diff --git a/.gitignore b/.gitignore index 1573309b594..c1c44d92c86 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,6 @@ classes/ src/generated/resources/.cache/ *.patch +*.cap *.DS_Store diff --git a/dependencies.gradle b/dependencies.gradle index e908852c3e6..0f4d5ffdd70 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -42,8 +42,7 @@ dependencies { modCompileOnly(forge.architectury) modCompileOnly(forge.rhino) - // Shimmer - modCompileOnly(forge.shimmer) + // Performance modCompileOnly(forge.embeddium) modCompileOnly(forge.oculus) modCompileOnly(forge.modernfix) diff --git a/docs/content/Modpacks/Changes/v8.0.0.md b/docs/content/Modpacks/Changes/v8.0.0.md index fc7c33f8651..eca9b7b85d1 100644 --- a/docs/content/Modpacks/Changes/v8.0.0.md +++ b/docs/content/Modpacks/Changes/v8.0.0.md @@ -125,9 +125,22 @@ A large number of machine feature interfaces have been removed, and have had the - `IFluidRendererMulti` - Use `MultiblockFluidRendererTrait` +## Connected texture reimplementation +The mod's connected texture logic has been reimplemented in GTM proper. +Texture packs, addons, and modpacks will have to change their texture metadata files for connected texures slightly. +A few regexes for fixing all the MCMeta files is follows, run them in order: + +1. Match: `"ldlib":([\s\{]*)"connection"(:\s".*?")(?:,\s.*)?` + Replace with: `"gtceu":$1"connection_texture"$2` +2. Match: `\s*\},\s*"shimmer":\s*\{(\s*"bloom":.*)` + Replace with: `,$1` +3. Match: `(\{\s*)"shimmer":(\s*\{\s*"bloom":.*)` + Replace with: `$1"gtceu":$2` + + ## Other Changes - `BlastingRecipeBuilder`, `CampfireRecipeBuilder`, `SmeltingRecipeBuilder` and `SmokingRecipeBuilder` have been merged into `SimpleCookingRecipeBuilder` - Example usage: `SimpleCookingRecipeBuilder.campfireCooking("cooking_chicken").input(new ItemStack(Items.CHICKEN)).output(new ItemStacks(Items.COOKED_CHICKEN)).cookingTime(100).experience(100).save(provider);` - `GTFluidImpl` has been merged into `GTFluid`, use `GTFluid.Flowing` and `GTFluid.Source` instead of `GTFluidImpl.Flowing` and `GTFluidImpl.Source`. -- Item behaviors have been moved to `common/item/behavior`, and some items have been moved from `api/item` to `common/item`. \ No newline at end of file +- Item behaviors have been moved to `common/item/behavior`, and some items have been moved from `api/item` to `common/item`. diff --git a/docs/content/Modpacks/Other-Topics/Connected-Textures.md b/docs/content/Modpacks/Other-Topics/Connected-Textures.md new file mode 100644 index 00000000000..1b929e6aefe --- /dev/null +++ b/docs/content/Modpacks/Other-Topics/Connected-Textures.md @@ -0,0 +1,63 @@ +--- +title: Creating Connected Textures +--- + +**Connected textures** are, as the name would imply, textures that connect with neighboring blocks. + +The CTM renderer will draw the block faces by assembling 4 quadrants from the 5 available block textures. +The normal `texture.png` is the block's "unconnected" texture, and is used when CTM is disabled or the block +has nothing to connect to. +`texture.png` has the outside corner quadrants and `texture_ctm.png` contains the connections. +``` +┌─────────────────┐ ┌────────────────────────────────┐ +│ texture.png │ │ texture_ctm.png │ +│ ╔══════╤══════╗ │ │ ──────┼────── ║ ─────┼───── ║ │ +│ ║ │ ║ │ │ │ │ │║ │ ║ │ +│ ║ 4/4 │ 4/5 ║ │ │ │ 0/0 │ 0/1 │║ 0/2 │ 0/3 ║ │ +│ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │ +│ ║ │ ║ │ │ │ │ │║ │ ║ │ +│ ║ 5/4 │ 5/5 ║ │ │ │ 1/0 │ 1/1 │║ 1/2 │ 1/3 ║ │ +│ ╚══════╧══════╝ │ │ ──────┼────── ║ ─────┼───── ║ │ +└─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │ + │ │ │ ││ │ │ │ + │ │ 2/0 │ 2/1 ││ 2/2 │ 2/3 │ │ + │ ┼──────┼──────┼┼──────┼──────┼ │ + │ │ │ ││ │ │ │ + │ │ 3/0 │ 3/1 ││ 3/2 │ 3/3 │ │ + │ ═══════╧═══════╗ ─────┼───── ╔ │ + └────────────────────────────────┘ +``` + +For example, combining sections 4/4, 2/1, 5/4, and 3/1, we can generate a texture connected to the right! +``` +╔══════╤═══════ +║ │ │ +║ 4/4 │ 2/1 │ +╟──────┼──────┼ +║ │ │ +║ 5/4 │ 3/1 │ +╚══════╧═══════ +``` +Combining sections 0/2, 2/3, 5/4, and 3/1, we can generate a texture in the shape of an L (connected to the right and up): +``` +║ ─────┼───── ╚ +║ │ │ +║ 0/2 │ 2/3 │ +╟──────┼──────┼ +║ │ │ +║ 5/4 │ 3/1 │ +╚══════╧═══════ +``` + + +??? example "Example MCMeta file" + (For a texture `mypack/assets/textures/blocks/texture.png` with a ctm texture `mypack/assets/textures/blocks/texture_ctm.png`) + ```json title="mypack:blocks/texture.png.mcmeta" + { + "gtceu": { + "connection_texture": "mypack:blocks/texture_ctm" + } + } + ``` + The CTM texture layout is [here](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/resources/assets/gtceu/textures/block/ctm_test.png) for the unconnected texture and [here](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png) for its connections. + Its MCMeta metadata file is [this one](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/resources/assets/gtceu/textures/block/ctm_test.png.mcmeta). diff --git a/gradle/forge.versions.toml b/gradle/forge.versions.toml index 51f1f825a7a..662eadc6f0c 100644 --- a/gradle/forge.versions.toml +++ b/gradle/forge.versions.toml @@ -30,7 +30,7 @@ xaerosMinimap = "25.3.10" ## modrinth maven ## jade = "11.6.3" -embeddium = "0.3.31+mc1.20.1" +embeddium = "0.3.31-beta.53+mc1.20.1" oculus = "1.20.1-1.8.0" modernfix = "DdUByV9S" # 5.24.1+mc1.20.1 @@ -86,7 +86,7 @@ ftbteams = { module = "dev.ftb.mods:ftb-teams-forge", version.ref = " ftbquests = { module = "dev.ftb.mods:ftb-quests-forge", version.ref = "ftbquests" } ftbchunks = { module = "dev.ftb.mods:ftb-chunks-forge", version.ref = "ftbchunks" } jade = { module = "maven.modrinth:jade", version.ref = "jade" } -embeddium = { module = "maven.modrinth:embeddium", version.ref = "embeddium" } +embeddium = { module = "org.embeddedt:embeddium-1.20.1", version.ref = "embeddium" } oculus = { module = "maven.modrinth:oculus", version.ref = "oculus" } modernfix = { module = "maven.modrinth:modernfix", version.ref = "modernfix" } xaeroslib = { module = "xaero.lib:xaerolib-forge-1.20.1", version.ref = "xaerosLib" } diff --git a/gradle/scripts/moddevgradle.gradle b/gradle/scripts/moddevgradle.gradle index 3f857566965..f24fd0b5211 100644 --- a/gradle/scripts/moddevgradle.gradle +++ b/gradle/scripts/moddevgradle.gradle @@ -152,10 +152,16 @@ legacyForge { // Enable assertions for our classes in dev environment jvmArgument('-ea:com.gregtechceu.gtceu...') + // jvmArgument("-XX:+AllowEnhancedClassRedefinition") + jvmArgument("-XX:+AllowRedefinitionToAddDeleteMethods") + // Recommended logging level for the console // You can set various levels here. // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels logLevel = org.slf4j.event.Level.INFO + + // Disable JOML using scientific notation for its types' toString() outputs + systemProperty 'joml.format', 'false' } } } diff --git a/gradle/scripts/repositories.gradle b/gradle/scripts/repositories.gradle index 1b4d59ec81c..c3bceaabbe5 100644 --- a/gradle/scripts/repositories.gradle +++ b/gradle/scripts/repositories.gradle @@ -12,9 +12,12 @@ repositories { } } - maven { // JEI - name = "Jared's Maven" - url = "https://maven.blamejared.com/" + exclusiveContent { // Create, Ponder, Flywheel + forRepository { maven { url = "https://maven.blamejared.com" } } + filter { + includeGroup("mezz.jei") + includeGroup("org.embeddedt") + } } maven { // JEI mirror, AE2 @@ -37,7 +40,7 @@ repositories { } exclusiveContent { // KubeJS and Rhino forRepository { maven { url = "https://maven.latvian.dev/releases" } } - filter { includeGroup("dev.latvian.mods")} + filter { includeGroup("dev.latvian.mods") } } exclusiveContent { // FTB mods forRepository { maven { url = "https://maven.ftb.dev/releases" } } diff --git a/injected_interfaces/interfaces.json b/injected_interfaces/interfaces.json index 1ab154b3032..01ee4dec99d 100644 --- a/injected_interfaces/interfaces.json +++ b/injected_interfaces/interfaces.json @@ -1,6 +1,12 @@ { "net/minecraft/client/renderer/block/model/BakedQuad": [ - "com/gregtechceu/gtceu/core/IGTBakedQuad" + "com/gregtechceu/gtceu/core/util/extensions/BakedQuadExt" + ], + "com/mojang/blaze3d/vertex/VertexConsumer": [ + "com/gregtechceu/gtceu/core/util/extensions/VertexConsumerExt" + ], + "net/minecraftforge/client/model/lighting/QuadLighter": [ + "com/gregtechceu/gtceu/core/util/extensions/QuadLighterExt" ], "net/minecraft/world/entity/Entity": [ "com/gregtechceu/gtceu/core/IFireImmuneEntity", diff --git a/src/generated/resources/assets/gtceu/blockstates/ctm_test.json b/src/generated/resources/assets/gtceu/blockstates/ctm_test.json new file mode 100644 index 00000000000..9332a79dea2 --- /dev/null +++ b/src/generated/resources/assets/gtceu/blockstates/ctm_test.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "gtceu:block/ctm_test" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/lang/en_ud.json b/src/generated/resources/assets/gtceu/lang/en_ud.json index 53efcdcd9bf..0f4d96a813a 100644 --- a/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -187,6 +187,7 @@ "block.gtceu.creative_tank": "ʞuɐ⟘ ǝʌıʇɐǝɹƆ", "block.gtceu.creosote": "ǝʇosoǝɹƆ", "block.gtceu.crushing_wheels": "sןǝǝɥM buıɥsnɹƆ", + "block.gtceu.ctm_test": "ʞɔoןᗺ ʇsǝ⟘ ǝɹnʇxǝ⟘ pǝʇɔǝuuoƆ", "block.gtceu.cupronickel_coil_block": "ʞɔoןᗺ ןıoƆ ןǝʞɔıuoɹdnƆ", "block.gtceu.cyan_borderless_lamp": "dɯɐꞀ ssǝןɹǝpɹoᗺ uɐʎƆ", "block.gtceu.cyan_lamp": "dɯɐꞀ uɐʎƆ", @@ -1762,9 +1763,13 @@ "config.gtceu.option.arcRecyclingYield": "pןǝıʎbuıןɔʎɔǝᴚɔɹɐ", "config.gtceu.option.armorHud": "pnHɹoɯɹɐ", "config.gtceu.option.autoRebuildResources": "sǝɔɹnosǝᴚpןınqǝᴚoʇnɐ", + "config.gtceu.option.baseBrightness": "ssǝuʇɥbıɹᗺǝsɐq", "config.gtceu.option.batchDuration": "uoıʇɐɹnᗡɥɔʇɐq", "config.gtceu.option.bedrockOreDistance": "ǝɔuɐʇsıᗡǝɹOʞɔoɹpǝq", "config.gtceu.option.bedrockOreDropTagPrefix": "xıɟǝɹԀbɐ⟘doɹᗡǝɹOʞɔoɹpǝq", + "config.gtceu.option.bloom": "ɯooןq", + "config.gtceu.option.bloomType": "ǝdʎ⟘ɯooןq", + "config.gtceu.option.bloomType.load_error": "sןıɐʇǝp ɹoɟ %s ǝǝs 'ʇɔǝɟɟǝ ɯooןq ǝɥʇ ɹoɟ sɹǝpɐɥs pɐoן ʇou pןnoƆ", "config.gtceu.option.borderColor": "ɹoןoƆɹǝpɹoq", "config.gtceu.option.bronzeBoilerHeatSpeed": "pǝǝdSʇɐǝHɹǝןıoᗺǝzuoɹq", "config.gtceu.option.bronzeBoilerMaxTemperature": "ǝɹnʇɐɹǝdɯǝ⟘xɐWɹǝןıoᗺǝzuoɹq", @@ -1790,6 +1795,7 @@ "config.gtceu.option.drum": "ɯnɹp", "config.gtceu.option.dumpAssets": "sʇǝssⱯdɯnp", "config.gtceu.option.dumpRecipes": "sǝdıɔǝᴚdɯnp", + "config.gtceu.option.emissiveTexturesHaveBloom": "ɯooןᗺǝʌɐHsǝɹnʇxǝ⟘ǝʌıssıɯǝ", "config.gtceu.option.enableArcRecycling": "buıןɔʎɔǝᴚɔɹⱯǝןqɐuǝ", "config.gtceu.option.enableCleanroom": "ɯooɹuɐǝןƆǝןqɐuǝ", "config.gtceu.option.enableExtractorRecycling": "buıןɔʎɔǝᴚɹoʇɔɐɹʇxƎǝןqɐuǝ", @@ -1853,7 +1859,9 @@ "config.gtceu.option.machinesEmissiveTextures": "sǝɹnʇxǝ⟘ǝʌıssıɯƎsǝuıɥɔɐɯ", "config.gtceu.option.machinesHaveBERsByDefault": "ʇןnɐɟǝᗡʎᗺsᴚƎᗺǝʌɐHsǝuıɥɔɐɯ", "config.gtceu.option.maintenanceCheckRate": "ǝʇɐᴚʞɔǝɥƆǝɔuɐuǝʇuıɐɯ", + "config.gtceu.option.maxBrightness": "ssǝuʇɥbıɹᗺxɐɯ", "config.gtceu.option.meHatchEnergyUsage": "ǝbɐs∩ʎbɹǝuƎɥɔʇɐHǝɯ", + "config.gtceu.option.minBrightness": "ssǝuʇɥbıɹᗺuıɯ", "config.gtceu.option.minerSpeed": "pǝǝdSɹǝuıɯ", "config.gtceu.option.minimap": "dɐɯıuıɯ", "config.gtceu.option.nanoSaber": "ɹǝqɐSouɐu", @@ -1905,6 +1913,8 @@ "config.gtceu.option.steelBoilerHeatSpeed": "pǝǝdSʇɐǝHɹǝןıoᗺןǝǝʇs", "config.gtceu.option.steelBoilerMaxTemperature": "ǝɹnʇɐɹǝdɯǝ⟘xɐWɹǝןıoᗺןǝǝʇs", "config.gtceu.option.steelSteamMultiblocks": "sʞɔoןqıʇןnWɯɐǝʇSןǝǝʇs", + "config.gtceu.option.step": "dǝʇs", + "config.gtceu.option.strength": "ɥʇbuǝɹʇs", "config.gtceu.option.surfaceRockProspectRange": "ǝbuɐᴚʇɔǝdsoɹԀʞɔoᴚǝɔɐɟɹns", "config.gtceu.option.tankItemFluidPreview": "ʍǝıʌǝɹԀpınןℲɯǝʇIʞuɐʇ", "config.gtceu.option.temperaturesInCelsius": "snısןǝƆuIsǝɹnʇɐɹǝdɯǝʇ", diff --git a/src/generated/resources/assets/gtceu/lang/en_us.json b/src/generated/resources/assets/gtceu/lang/en_us.json index c9d6d18f758..63721612f3a 100644 --- a/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/src/generated/resources/assets/gtceu/lang/en_us.json @@ -187,6 +187,7 @@ "block.gtceu.creative_tank": "Creative Tank", "block.gtceu.creosote": "Creosote", "block.gtceu.crushing_wheels": "Crushing Wheels", + "block.gtceu.ctm_test": "Connected Texture Test Block", "block.gtceu.cupronickel_coil_block": "Cupronickel Coil Block", "block.gtceu.cyan_borderless_lamp": "Cyan Borderless Lamp", "block.gtceu.cyan_lamp": "Cyan Lamp", @@ -1762,9 +1763,13 @@ "config.gtceu.option.arcRecyclingYield": "arcRecyclingYield", "config.gtceu.option.armorHud": "armorHud", "config.gtceu.option.autoRebuildResources": "autoRebuildResources", + "config.gtceu.option.baseBrightness": "baseBrightness", "config.gtceu.option.batchDuration": "batchDuration", "config.gtceu.option.bedrockOreDistance": "bedrockOreDistance", "config.gtceu.option.bedrockOreDropTagPrefix": "bedrockOreDropTagPrefix", + "config.gtceu.option.bloom": "bloom", + "config.gtceu.option.bloomType": "bloomType", + "config.gtceu.option.bloomType.load_error": "Could not load shaders for the bloom effect, see %s for details", "config.gtceu.option.borderColor": "borderColor", "config.gtceu.option.bronzeBoilerHeatSpeed": "bronzeBoilerHeatSpeed", "config.gtceu.option.bronzeBoilerMaxTemperature": "bronzeBoilerMaxTemperature", @@ -1790,6 +1795,7 @@ "config.gtceu.option.drum": "drum", "config.gtceu.option.dumpAssets": "dumpAssets", "config.gtceu.option.dumpRecipes": "dumpRecipes", + "config.gtceu.option.emissiveTexturesHaveBloom": "emissiveTexturesHaveBloom", "config.gtceu.option.enableArcRecycling": "enableArcRecycling", "config.gtceu.option.enableCleanroom": "enableCleanroom", "config.gtceu.option.enableExtractorRecycling": "enableExtractorRecycling", @@ -1853,7 +1859,9 @@ "config.gtceu.option.machinesEmissiveTextures": "machinesEmissiveTextures", "config.gtceu.option.machinesHaveBERsByDefault": "machinesHaveBERsByDefault", "config.gtceu.option.maintenanceCheckRate": "maintenanceCheckRate", + "config.gtceu.option.maxBrightness": "maxBrightness", "config.gtceu.option.meHatchEnergyUsage": "meHatchEnergyUsage", + "config.gtceu.option.minBrightness": "minBrightness", "config.gtceu.option.minerSpeed": "minerSpeed", "config.gtceu.option.minimap": "minimap", "config.gtceu.option.nanoSaber": "nanoSaber", @@ -1905,6 +1913,8 @@ "config.gtceu.option.steelBoilerHeatSpeed": "steelBoilerHeatSpeed", "config.gtceu.option.steelBoilerMaxTemperature": "steelBoilerMaxTemperature", "config.gtceu.option.steelSteamMultiblocks": "steelSteamMultiblocks", + "config.gtceu.option.step": "step", + "config.gtceu.option.strength": "strength", "config.gtceu.option.surfaceRockProspectRange": "surfaceRockProspectRange", "config.gtceu.option.tankItemFluidPreview": "tankItemFluidPreview", "config.gtceu.option.temperaturesInCelsius": "temperaturesInCelsius", diff --git a/src/generated/resources/assets/gtceu/models/block/ctm_test.json b/src/generated/resources/assets/gtceu/models/block/ctm_test.json new file mode 100644 index 00000000000..47bfa0945dd --- /dev/null +++ b/src/generated/resources/assets/gtceu/models/block/ctm_test.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "gtceu:block/ctm_test" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/models/item/ctm_test.json b/src/generated/resources/assets/gtceu/models/item/ctm_test.json new file mode 100644 index 00000000000..1dec31234c8 --- /dev/null +++ b/src/generated/resources/assets/gtceu/models/item/ctm_test.json @@ -0,0 +1,3 @@ +{ + "parent": "gtceu:block/ctm_test" +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/GTCEu.java b/src/main/java/com/gregtechceu/gtceu/GTCEu.java index e7b1de43d39..b834dccf3b0 100644 --- a/src/main/java/com/gregtechceu/gtceu/GTCEu.java +++ b/src/main/java/com/gregtechceu/gtceu/GTCEu.java @@ -96,7 +96,7 @@ public static boolean isDataGen() { /** * A friendly reminder that the server instance is populated on the server side only, so null/side check it! - * + * * @return the current minecraft server instance */ public static MinecraftServer getMinecraftServer() { @@ -108,12 +108,14 @@ public static MinecraftServer getMinecraftServer() { * @return if the mod whose id is {@code modId} is loaded or not */ public static boolean isModLoaded(String modId) { - return ModList.get().isLoaded(modId); + ModList modList = ModList.get(); + if (modList != null) return modList.isLoaded(modId); + else return FMLLoader.getLoadingModList().getModFileById(modId) != null; } /** * For async stuff use this, otherwise use {@link GTCEu isClientSide} - * + * * @return if the current thread is the client thread */ public static boolean isClientThread() { @@ -132,7 +134,7 @@ public static boolean isClientSide() { /** * This check isn't the same for client and server! - * + * * @return if it's safe to access the current instance {@link net.minecraft.world.level.Level Level} on client or if * it's safe to access any level on server. */ @@ -175,9 +177,8 @@ public static boolean isIrisOculusLoaded() { return isModLoaded(GTValues.MODID_IRIS) || isModLoaded(GTValues.MODID_OCULUS); } - public static boolean isSodiumRubidiumEmbeddiumLoaded() { - return isModLoaded(GTValues.MODID_SODIUM) || isModLoaded(GTValues.MODID_RUBIDIUM) || - isModLoaded(GTValues.MODID_EMBEDDIUM); + public static boolean isSodiumEmbeddiumLoaded() { + return isModLoaded(GTValues.MODID_SODIUM) || isModLoaded(GTValues.MODID_EMBEDDIUM); } public static boolean isAE2Loaded() { @@ -188,10 +189,6 @@ public static boolean isCuriosLoaded() { return isModLoaded(GTValues.MODID_CURIOS); } - public static boolean isShimmerLoaded() { - return isModLoaded(GTValues.MODID_SHIMMER); - } - public static boolean isModernFixLoaded() { return isModLoaded(GTValues.MODID_MODERNFIX); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/GTValues.java b/src/main/java/com/gregtechceu/gtceu/api/GTValues.java index 7f2da34899c..ee1b821f8af 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/GTValues.java +++ b/src/main/java/com/gregtechceu/gtceu/api/GTValues.java @@ -36,7 +36,7 @@ public class GTValues { public static final int L = 144; public static final RandomSource RNG = RandomSource.createThreadSafe(); - // shortcut for various lengths of time in ticks + // shortcut for various lengths of time in ticks (with the default tickrate of 20) public static final long SECONDS = 20; public static final long MINUTES = 60 * SECONDS; public static final long HOURS = 60 * MINUTES; @@ -45,12 +45,6 @@ public class GTValues { public static final long MONTHS = 30 * DAYS; public static final long YEARS = 365 * DAYS; - /** - * The Item WildCard Tag. Even shorter than the "-1" of the past - */ - - // public static final short W = OreDictionary.WILDCARD_VALUE; - /** Current time on the Client. Will always be zero on the server. */ public static long CLIENT_TIME = 0; @@ -121,12 +115,11 @@ public static int[] tiersBetween(int minInclusive, int maxInclusive) { MODID_IRIS = "iris", MODID_OCULUS = "oculus", MODID_SODIUM = "sodium", - MODID_RUBIDIUM = "rubidium", MODID_EMBEDDIUM = "embeddium", + MODID_OPTIFINE = "optifine", MODID_CREATE = "create", MODID_CURIOS = "curios", MODID_AE2WTLIB = "ae2wtlib", - MODID_SHIMMER = "shimmer", MODID_MODERNFIX = "modernfix", MODID_JOURNEYMAP = "journeymap", MODID_XAEROS_MINIMAP = "xaerominimap", @@ -272,6 +265,7 @@ public static int[] tiersBetween(int minInclusive, int maxInclusive) { 0x7EC3C4, 0x7EB07E, 0xBF74C0, 0x0B5CFE, 0x914E91, 0x488748, 0x8C0000, 0x2828F5 }; // Main colour for each tier + @SuppressWarnings("DataFlowIssue") public static final int[] VCM = new int[] { DARK_GRAY.getColor(), GRAY.getColor(), diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java index 7a011bb3c71..d809950b750 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java @@ -38,7 +38,7 @@ import com.gregtechceu.gtceu.api.transfer.fluid.IFluidHandlerModifiable; import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.model.machine.MachineRenderState; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.cover.FluidFilterCover; import com.gregtechceu.gtceu.common.cover.ItemFilterCover; import com.gregtechceu.gtceu.common.cover.data.ManualIOMode; @@ -46,6 +46,7 @@ import com.gregtechceu.gtceu.common.machine.owner.PlayerOwner; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; import com.gregtechceu.gtceu.utils.ExtendedUseOnContext; +import com.gregtechceu.gtceu.utils.GTStringUtils; import com.gregtechceu.gtceu.utils.data.TagCompatibilityFixer; import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; @@ -53,8 +54,6 @@ import com.lowdragmc.lowdraglib.utils.DummyWorld; import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -661,7 +660,7 @@ public void addDebugOverlayText(Consumer lines) { // add render state info MachineRenderState renderState = this.getRenderState(); for (var property : renderState.getValues().entrySet()) { - lines.accept(ModelUtils.getPropertyValueString(property)); + lines.accept(GTStringUtils.getPropertyValueString(property)); } } @@ -1011,8 +1010,7 @@ public int getDefaultPaintingColor() { @OnlyIn(Dist.CLIENT) @Override public AABB getRenderBoundingBox() { - BlockRenderDispatcher blockRenderDispatcher = Minecraft.getInstance().getBlockRenderer(); - BakedModel model = blockRenderDispatcher.getBlockModel(this.getBlockState()); + BakedModel model = RenderUtil.getModelForState(this.getBlockState()); if (model instanceof IBlockEntityRendererBakedModel modelWithBER) { if (modelWithBER.getBlockEntityType() == this.getType()) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientEventListener.java b/src/main/java/com/gregtechceu/gtceu/client/ClientEventListener.java index fd7ab140609..572f098fa84 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientEventListener.java @@ -17,6 +17,7 @@ import com.gregtechceu.gtceu.integration.map.ClientCacheManager; import net.minecraft.ChatFormatting; +import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; @@ -41,6 +42,7 @@ import net.minecraftforge.fml.common.Mod; import com.mojang.authlib.minecraft.MinecraftProfileTexture; +import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.apache.commons.lang3.mutable.MutableInt; @@ -54,14 +56,22 @@ public class ClientEventListener { @SubscribeEvent public static void onRenderLevelStageEvent(RenderLevelStageEvent event) { + Camera camera = event.getCamera(); + PoseStack poseStack = event.getPoseStack(); + float partialTick = event.getPartialTick(); + if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_BLOCK_ENTITIES) { - // to render the preview after block entities, before the translucent. so it can be seen through the - // transparent blocks. - MultiblockInWorldPreviewRenderer.renderInWorldPreview(event.getPoseStack(), event.getCamera(), - event.getPartialTick()); + // to render the preview after block entities, before the translucent. + // so it can be seen through the transparent blocks. + MultiblockInWorldPreviewRenderer.renderInWorldPreview(poseStack, camera, partialTick); } } + @SubscribeEvent + public static void onLevelUnload(LevelEvent.Unload event) { + FacadeCoverRenderer.clearItemModelCache(); + } + private static final Map DEFAULT_CAPES = new Object2ObjectOpenHashMap<>(); @SubscribeEvent @@ -143,11 +153,6 @@ public static void onClientTickEvent(TickEvent.ClientTickEvent event) { } } - @SubscribeEvent - public static void onLevelUnloadEvent(LevelEvent.Unload event) { - FacadeCoverRenderer.clearItemModelCache(); - } - private static final String BLOCK_INFO_LINE_START = ChatFormatting.UNDERLINE + "Targeted Block: "; @SubscribeEvent diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index 668e0c8388f..7cec8289a4e 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -8,6 +8,7 @@ import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; import com.gregtechceu.gtceu.api.item.IComponentItem; import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.client.bloom.BloomHandler; import com.gregtechceu.gtceu.client.model.item.CustomItemRendererWrapperModel; import com.gregtechceu.gtceu.client.model.item.FacadeUnbakedModel; import com.gregtechceu.gtceu.client.model.machine.MachineModelLoader; @@ -30,6 +31,7 @@ import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderManager; import com.gregtechceu.gtceu.client.renderer.machine.impl.*; import com.gregtechceu.gtceu.client.renderer.machine.impl.BoilerMultiPartRender; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import com.gregtechceu.gtceu.common.CommonEventListener; import com.gregtechceu.gtceu.common.CommonProxy; import com.gregtechceu.gtceu.common.data.GTBlockEntities; @@ -45,6 +47,7 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.model.builder.PipeModelBuilder; import com.gregtechceu.gtceu.data.pack.event.RegisterDynamicResourcesEvent; +import com.gregtechceu.gtceu.integration.embeddium.GTEmbeddiumCompat; import com.gregtechceu.gtceu.integration.kjs.GregTechKubeJSPlugin; import com.gregtechceu.gtceu.integration.map.ClientCacheManager; import com.gregtechceu.gtceu.integration.map.cache.client.GTClientCache; @@ -62,7 +65,6 @@ import net.minecraft.client.renderer.entity.ThrownItemRenderer; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.event.*; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -89,8 +91,13 @@ public static void init() { Layers.registerLayer(OreRenderLayer::new, "ore_veins"); Layers.registerLayer(FluidRenderLayer::new, "bedrock_fluids"); CommonEventListener.registerCapes(new RegisterGTCapesEvent()); + + if (GTCEu.Mods.isSodiumEmbeddiumLoaded()) { + GTEmbeddiumCompat.init(); + } } initializeDynamicRenders(); + ModelEventHelper.initInternalAssetReloadListeners(); } @SubscribeEvent @@ -104,10 +111,13 @@ public void onRegisterEntityRenderers(EntityRenderersEvent.RegisterRenderers eve event.registerEntityRenderer(GTEntityTypes.BOAT.get(), c -> new GTBoatRenderer(c, false)); event.registerEntityRenderer(GTEntityTypes.CHEST_BOAT.get(), c -> new GTBoatRenderer(c, true)); + } + @SubscribeEvent + public void onRegisterEntityLayerDefinitions(EntityRenderersEvent.RegisterLayerDefinitions event) { for (var type : GTBoat.BoatType.values()) { - ForgeHooksClient.registerLayerDefinition(GTBoatRenderer.getBoatModelName(type), BoatModel::createBodyModel); - ForgeHooksClient.registerLayerDefinition(GTBoatRenderer.getChestBoatModelName(type), + event.registerLayerDefinition(GTBoatRenderer.getBoatModelName(type), BoatModel::createBodyModel); + event.registerLayerDefinition(GTBoatRenderer.getChestBoatModelName(type), ChestBoatModel::createBodyModel); } } @@ -158,7 +168,7 @@ public void onClientSetup(FMLClientSetupEvent event) { } } - public static void initializeDynamicRenders() { + private static void initializeDynamicRenders() { DynamicRenderManager.register(GTCEu.id("quantum_tank_fluid"), QuantumTankFluidRender.TYPE); DynamicRenderManager.register(GTCEu.id("quantum_chest_item"), QuantumChestItemRender.TYPE); diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomEventListeners.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomEventListeners.java new file mode 100644 index 00000000000..eaee5dfb982 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomEventListeners.java @@ -0,0 +1,97 @@ +package com.gregtechceu.gtceu.client.bloom; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; +import com.gregtechceu.gtceu.core.config.GTEarlyConfig; +import com.gregtechceu.gtceu.core.mixins.GTMixinPlugin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.ForgeRenderTypes; +import net.minecraftforge.client.event.RegisterNamedRenderTypesEvent; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.level.ChunkEvent; +import net.minecraftforge.event.level.LevelEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import lombok.experimental.UtilityClass; + +@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE) +@UtilityClass +public class BloomEventListeners { + + @SubscribeEvent + public static void afterParticlesRendered(RenderLevelStageEvent event) { + if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_PARTICLES) return; + + BloomRenderer.renderBloom(event.getCamera(), event.getPoseStack(), event.getFrustum(), event.getProjectionMatrix(), + event.getPartialTick(), event.getLevelRenderer(), Minecraft.getInstance().getProfiler()); + } + + @SubscribeEvent + public static void onRenderTick(TickEvent.RenderTickEvent event) { + if (event.phase != TickEvent.Phase.START || Minecraft.getInstance().level == null) return; + if (!BloomShaderManager.isBloomActive()) return; + + BloomShaderManager.BLOOM_TARGET.clear(Minecraft.ON_OSX); + Minecraft.getInstance().getMainRenderTarget().bindWrite(false); + } + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + BloomShaderManager.updateShaderAvailability(event); + } + + @SubscribeEvent + public static void onLevelUnload(LevelEvent.Unload event) { + BloomHandler.invalidateLevelData(event.getLevel()); + + if (BloomRenderer.SafeMode.enabled()) { + BloomRenderer.SafeMode.invalidateLevelData(); + } + } + + @SubscribeEvent + public static void onChunkUnload(ChunkEvent.Unload event) { + if (!BloomShaderManager.isBloomActive()) return; + + ChunkAccess chunk = event.getChunk(); + LevelAccessor level = chunk.getWorldForge(); + if (level == null) return; + + if (!BloomRenderer.SafeMode.enabled()) return; + + ChunkPos chunkPos = chunk.getPos(); + int minSection = level.getMinSection(), maxSection = level.getMaxSection(); + for (int y = minSection; y < maxSection; y++) { + BloomRenderer.SafeMode.invalidateSectionData(SectionPos.of(chunkPos.x, y, chunkPos.z)); + } + } + + // Merge into parent class in 1.21, event listener discovery is smarter there + @Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) + @UtilityClass + public static class ModBus { + + @SubscribeEvent + public static void registerNamedRenderTypes(RegisterNamedRenderTypesEvent event) { + RenderType block, entity; + if (!BloomRenderer.SafeMode.enabled() && BloomShaderManager.isBloomAvailable()) { + block = GTRenderTypes.bloom(); + entity = GTRenderTypes.entityBloomBlockSheet(); + } else { + // if safe mode is enabled, register the named render type as a copy of forge's 'cutout' + block = RenderType.cutoutMipped(); + entity = ForgeRenderTypes.ITEM_LAYERED_CUTOUT.get(); + } + event.register("bloom", block, entity); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomHandler.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomHandler.java new file mode 100644 index 00000000000..abc8688f4b8 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomHandler.java @@ -0,0 +1,257 @@ +package com.gregtechceu.gtceu.client.bloom; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.particle.GTParticle; +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; + +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import com.mojang.blaze3d.vertex.*; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.experimental.UtilityClass; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.*; +import java.util.function.*; + +import static com.gregtechceu.gtceu.client.bloom.BloomRenderer.BLOOM_RENDER_LOCK; + +@UtilityClass +public class BloomHandler { + + @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) + @UtilityClass + public static class RenderStage { + + public static RenderLevelStageEvent.@UnknownNullability Stage AFTER_BLOOM; + + @SubscribeEvent + public static void registerLevelRenderStages(RenderLevelStageEvent.RegisterStageEvent event) { + AFTER_BLOOM = event.register(GTCEu.id("after_bloom"), GTRenderTypes.bloom()); + } + } + + static final Map<@Nullable IRenderSetup, BloomRenderList> BLOOM_RENDERS = new Object2ObjectOpenHashMap<>(); + static final List SCHEDULED_BLOOM_RENDERS = new ArrayList<>(); + + /** + * Register a custom bloom render callback for subsequent world render. The render call persists until the + * {@code blockEntity} is invalidated, or the world associated with {@code blockEntity} or the ticket is + * manually freed by calling {@link BloomRenderTicket#invalidate()}. + * + *

+ * This method does not register bloom render ticket when Iris/Oculus is present, and an invalid ticket will be + * returned instead. + * + * @param setup Render setup, if exists + * @param render Rendering callback + * @param blockEntity Meta tile entity instance + * @return Ticket for the registered bloom render callback + * @throws NullPointerException if {@code bloomType == null || render == null || blockEntity == null} + */ + public static BloomRenderTicket registerBloomRender(@Nullable IRenderSetup setup, IBloomEffect render, + BlockEntity blockEntity) { + Objects.requireNonNull(blockEntity, "blockEntity == null"); + return registerBloomRender(setup, + new IBloomEffect() { + + @Override + public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, + EffectRenderContext context) { + render.renderBloomEffect(poseStack, buffer, context); + } + + @Override + public boolean shouldRenderBloomEffect(EffectRenderContext context) { + return blockEntity.getLevel() == context.getRenderViewEntity().level() && + render.shouldRenderBloomEffect(context); + } + }, + t -> !blockEntity.isRemoved(), + blockEntity::getLevel); + } + + /** + * Register a custom bloom render callback for subsequent world render. The render call persists until the + * {@code particle} is invalidated, or the ticket is manually freed by calling + * {@link BloomRenderTicket#invalidate()}. + * + *

+ * This method does not register bloom render ticket when Iris/Oculus is present, and an invalid ticket will be + * returned instead. + * + * @param setup Render setup, if exists + * @param render Rendering callback + * @param particle Particle instance + * @return Ticket for the registered bloom render callback + * @throws NullPointerException if {@code bloomType == null || render == null || metaTileEntity == null} + */ + public static BloomRenderTicket registerBloomRender(@Nullable IRenderSetup setup, IBloomEffect render, + GTParticle particle) { + Objects.requireNonNull(particle, "particle == null"); + return registerBloomRender(setup, render, t -> particle.isAlive()); + } + + /** + * Register a custom bloom render callback for subsequent world render. The render call persists until it is + * manually freed by calling {@link BloomRenderTicket#invalidate()}, or invalidated by validity checker. + * + *

+ * This method does not register bloom render ticket when Iris/Oculus is present, and an invalid ticket will be + * returned instead. + * + * @param setup Render setup, if exists + * @param render Rendering callback + * @param validityChecker Optional validity checker; returning {@code false} causes the ticket to be invalidated. + * Checked on both pre- / post-render each frame. + * @return Ticket for the registered bloom render callback + * @throws NullPointerException if {@code bloomType == null || render == null} + * @see #registerBloomRender(IRenderSetup, IBloomEffect, BlockEntity) + * @see #registerBloomRender(IRenderSetup, IBloomEffect, GTParticle) + * @see #registerBloomRender(IRenderSetup, IBloomEffect, Predicate, Supplier) + */ + public static BloomRenderTicket registerBloomRender(@Nullable IRenderSetup setup, IBloomEffect render, + @Nullable Predicate validityChecker) { + return registerBloomRender(setup, render, validityChecker, null); + } + + /** + * Register a custom bloom render callback for subsequent world render. The render call persists until it is + * manually freed by calling {@link BloomRenderTicket#invalidate()}, or invalidated by validity checker. + * + *

+ * This method does not register bloom render ticket when Iris/Oculus is present, and an invalid ticket will be + * returned instead. + * + * @param setup Render setup, if exists + * @param render Rendering callback + * @param validityChecker Optional validity checker; returning {@code false} causes the ticket to be invalidated. + * Checked on both pre- / post-render each frame. + * @param worldContext Optional world bound to the ticket. If the world returned is not null, the bloom ticket + * will be automatically invalidated on world unload. If world context returns {@code null}, + * it will not be affected by aforementioned automatic invalidation. + * @return Ticket for the registered bloom render callback + * @throws NullPointerException if {@code bloomType == null || render == null} + * @see #registerBloomRender(IRenderSetup, IBloomEffect, BlockEntity) + * @see #registerBloomRender(IRenderSetup, IBloomEffect, GTParticle) + */ + public static BloomRenderTicket registerBloomRender(@Nullable IRenderSetup setup, IBloomEffect render, + @Nullable Predicate validityChecker, + @Nullable Supplier<@Nullable Level> worldContext) { + if (!BloomShaderManager.isBloomActive()) return BloomRenderTicket.INVALID; + + BloomRenderTicket ticket = new BloomRenderTicket(setup, render, validityChecker, worldContext); + BLOOM_RENDER_LOCK.writeLock().lock(); + try { + SCHEDULED_BLOOM_RENDERS.add(ticket); + } finally { + BLOOM_RENDER_LOCK.writeLock().unlock(); + } + return ticket; + } + + /** + * Invalidate tickets associated with given level. + * + * @param level the level that was unloaded + */ + static void invalidateLevelData(LevelAccessor level) { + Objects.requireNonNull(level, "level == null"); + BLOOM_RENDER_LOCK.readLock().lock(); + try { + for (BloomRenderTicket ticket : BloomHandler.SCHEDULED_BLOOM_RENDERS) { + if (ticket.isValid() && ticket.worldContext != null && ticket.worldContext.get() == level) { + ticket.invalidate(); + } + } + + for (BloomRenderList list : BloomHandler.BLOOM_RENDERS.values()) { + for (BloomRenderTicket ticket : list) { + if (ticket.isValid() && ticket.worldContext != null && ticket.worldContext.get() == level) { + ticket.invalidate(); + } + } + } + } finally { + BLOOM_RENDER_LOCK.readLock().unlock(); + } + } + + // region internals + + static void initializeScheduledRenders() { + for (BloomRenderTicket ticket : SCHEDULED_BLOOM_RENDERS) { + if (!ticket.isValid()) continue; + BloomHandler.BLOOM_RENDERS.computeIfAbsent(ticket.renderSetup, BloomHandler.BloomRenderList::new).add(ticket); + } + SCHEDULED_BLOOM_RENDERS.clear(); + } + + static void removeInvalidatedRenders() { + BloomHandler.BLOOM_RENDERS.values().removeIf(BloomHandler.BloomRenderList::postDraw); + } + + static final class BloomRenderList extends ArrayList { + + private final @Nullable IRenderSetup renderSetup; + + BloomRenderList(@Nullable IRenderSetup renderSetup) { + super(2); + this.renderSetup = renderSetup; + } + + void draw(PoseStack poseStack, BufferBuilder buffer, EffectRenderContext context) { + boolean initialized = false; + + poseStack.pushPose(); + poseStack.translate(-context.camPos().x(), -context.camPos().y(), -context.camPos().z()); + + for (BloomRenderTicket ticket : this) { + ticket.checkValidity(); + if (!ticket.isValid() || !ticket.render.shouldRenderBloomEffect(context)) continue; + + if (!initialized) { + initialized = true; + if (this.renderSetup != null) { + this.renderSetup.preDraw(buffer); + } + } + + poseStack.pushPose(); + ticket.render.renderBloomEffect(poseStack, buffer, context); + poseStack.popPose(); + } + + poseStack.popPose(); + + if (initialized && this.renderSetup != null) { + this.renderSetup.postDraw(buffer); + } + } + + /** + * Do post-draw cleanup such as removing invalidated draw tickets. + * + * @return Whether this list should be removed from the tracking map. + */ + boolean postDraw() { + if (this.isEmpty()) return true; + + boolean removedAny = this.removeIf(ticket -> { + ticket.checkValidity(); + return !ticket.isValid(); + }); + if (!removedAny) return false; + + return this.isEmpty(); + } + } + + // endregion +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderTicket.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderTicket.java new file mode 100644 index 00000000000..8c6ef1cade9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderTicket.java @@ -0,0 +1,49 @@ +package com.gregtechceu.gtceu.client.bloom; + +import net.minecraft.world.level.Level; + +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public final class BloomRenderTicket { + + public static final BloomRenderTicket INVALID = new BloomRenderTicket(); + + final @Nullable IRenderSetup renderSetup; + final IBloomEffect render; + final @Nullable Predicate validityChecker; + final @Nullable Supplier<@Nullable Level> worldContext; + + private boolean invalidated; + + private BloomRenderTicket() { + this(null, (p, b, c) -> {}, null, null); + this.invalidated = true; + } + + BloomRenderTicket(@Nullable IRenderSetup renderSetup, IBloomEffect render, + @Nullable Predicate validityChecker, + @Nullable Supplier<@Nullable Level> worldContext) { + this.renderSetup = renderSetup; + this.render = Objects.requireNonNull(render, "render == null"); + this.validityChecker = validityChecker; + this.worldContext = worldContext; + } + + public boolean isValid() { + return !this.invalidated; + } + + public void invalidate() { + this.invalidated = true; + } + + void checkValidity() { + if (!this.invalidated && this.validityChecker != null && !this.validityChecker.test(this)) { + invalidate(); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java new file mode 100644 index 00000000000..35859132259 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java @@ -0,0 +1,383 @@ +package com.gregtechceu.gtceu.client.bloom; + +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; +import com.gregtechceu.gtceu.client.util.TextureMetadataHelper; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.core.config.GTEarlyConfig; +import com.gregtechceu.gtceu.core.mixins.GTMixinPlugin; +import com.gregtechceu.gtceu.core.mixins.client.bloom.PostChainAccessor; +import com.gregtechceu.gtceu.core.mixins.client.bloom.LevelRendererAccessor; +import com.gregtechceu.gtceu.utils.ScopedValue; +import com.gregtechceu.gtceu.utils.function.IntObjectConsumer; +import com.mojang.blaze3d.pipeline.RenderCall; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.shaders.Uniform; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.UtilityClass; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.core.SectionPos; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.ForgeHooksClient; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import static com.gregtechceu.gtceu.client.bloom.BloomShaderManager.BLOOM_TARGET; + +/** + * The actual rendering logic for bloom + */ +@ApiStatus.Internal +@UtilityClass +public class BloomRenderer { + + static final ReadWriteLock BLOOM_RENDER_LOCK = new ReentrantReadWriteLock(); + + @Accessors(fluent = true) + @Getter + @ApiStatus.Internal + static final ThreadLocal>> bloomChunkContext = ThreadLocal + .withInitial(ScopedValue.Object::new); + + @ApiStatus.Internal + static void renderBloom(Camera camera, PoseStack poseStack, Frustum frustum, Matrix4f projectionMatrix, + float partialTicks, LevelRenderer levelRenderer, ProfilerFiller profilerFiller) { + if (!BloomShaderManager.isBloomActive()) return; + + Vec3 camPos = camera.getPosition(); + + profilerFiller.popPush("gtceu:bloom"); + setupBloomShaderUniforms(); + + GTRenderTypes.bloom().setupRenderState(); + + renderSpecialBloom(camera, poseStack, frustum, partialTicks, profilerFiller); + + // safe mode disabled -> use deeper, faster hackery + if (!BloomRenderer.SafeMode.enabled()) { + ((LevelRendererAccessor) levelRenderer).invokeRenderChunkLayer(GTRenderTypes.bloom(), poseStack, + camPos.x, camPos.y, camPos.z, projectionMatrix); + + // have to re-setup here. so sad. very aw. + GTRenderTypes.bloom().setupRenderState(); + } + // safe mode enabled -> don't draw block bloom the 'normal' way; use BloomSafeMode.drawBlockBloom instead + else { + SafeMode.drawBlockBloom(camera, poseStack, frustum, projectionMatrix, levelRenderer, profilerFiller); + } + + processPostEffect(partialTicks, profilerFiller); + + // clear state. again. + GTRenderTypes.bloom().clearRenderState(); + + // profiler section is popped by popPush() in the calling function; don't pop it here + } + + static void renderSpecialBloom(Camera camera, PoseStack poseStack, Frustum frustum, float partialTicks, + ProfilerFiller profilerFiller) { + profilerFiller.push("special"); + + // render state is set up & cleared in calling function + + + BLOOM_RENDER_LOCK.writeLock().lock(); + try { + BloomHandler.initializeScheduledRenders(); + } finally { + BLOOM_RENDER_LOCK.writeLock().unlock(); + } + if (!BloomHandler.BLOOM_RENDERS.isEmpty()) { + EffectRenderContext context = EffectRenderContext.getInstance().update(camera, frustum, partialTicks); + + BLOOM_RENDER_LOCK.readLock().lock(); + try { + BloomHandler.BLOOM_RENDERS.forEach((renderSetup, list) -> { + BufferBuilder buffer = Tesselator.getInstance().getBuilder(); + list.draw(poseStack, buffer, context); + }); + } finally { + BLOOM_RENDER_LOCK.readLock().unlock(); + } + + BLOOM_RENDER_LOCK.writeLock().lock(); + try { + BloomHandler.removeInvalidatedRenders(); + } finally { + BLOOM_RENDER_LOCK.writeLock().unlock(); + } + } + + profilerFiller.pop(); + } + + static void processPostEffect(float partialTicks, ProfilerFiller profilerFiller) { + Minecraft minecraft = Minecraft.getInstance(); + RenderTarget mainTarget = minecraft.getMainRenderTarget(); + + profilerFiller.push("processPostEffect"); + + BloomShaderManager.BLOOM_CHAIN.process(partialTicks); + + mainTarget.bindWrite(false); + + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE); + + BLOOM_TARGET.blitToScreen(mainTarget.viewWidth, mainTarget.viewHeight, false); + BLOOM_TARGET.unbindRead(); + + RenderSystem.disableBlend(); + RenderSystem.defaultBlendFunc(); + + profilerFiller.pop(); + } + + @ApiStatus.Internal + static void setupBloomShaderUniforms() { + final var config = ConfigHolder.INSTANCE.client.bloom; + + // Forcefully insert config values to shader + modifyBloomPostShaders((index, shader) -> { + shader.safeGetUniform("DepthNear").set(GameRenderer.PROJECTION_Z_NEAR); + shader.safeGetUniform("DepthFar").set(Minecraft.getInstance().gameRenderer.getDepthFar()); + + // look for blur steps & change their blur strength to match the config + if (shader.getName().contains("blur")) { + if (index % 2 == 0) { + shader.safeGetUniform("BlurDir").set(0.0f, config.step); + } else { + shader.safeGetUniform("BlurDir").set(config.step, 0.0f); + } + } + + shader.safeGetUniform("BloomStrength").set(config.strength); + shader.safeGetUniform("BaseBrightness").set(config.baseBrightness); + shader.safeGetUniform("MinBrightness").set(config.minBrightness); + shader.safeGetUniform("MaxBrightness").set(config.maxBrightness); + }); + } + + static void modifyBloomPostShaders(IntObjectConsumer consumer) { + // Forcefully insert config values to shader + List passes = ((PostChainAccessor) BloomShaderManager.BLOOM_CHAIN).getPasses(); + for (int i = 0; i < passes.size(); i++) { + PostPass pass = passes.get(i); + consumer.accept(i, pass.getEffect()); + } + } + + /// Helper function for copying bloom-enabled quads drawn with non-bloom render types + public static void copyBloomQuad(BakedQuad quad, int[] packedLights, @Nullable RenderType renderType, + Consumer drawConsumer) { + if (renderType == GTRenderTypes.bloom() || renderType == GTRenderTypes.entityBloomBlockSheet()) { + return; + } + + if (TextureMetadataHelper.hasBloom(quad, packedLights)) { + Supplier currentVertexConsumer = bloomChunkContext().get().getValue(); + if (currentVertexConsumer == null) return; + + drawConsumer.accept(currentVertexConsumer.get()); + } + } + + /** + * A 'safe mode' for bloom rendering that's less intrusive but slower than the normal implementation. + */ + @ApiStatus.Internal + @UtilityClass + public static class SafeMode { + + // it's most likely better to use ConcurrentHashMaps rather than synchronized Long2ObjectMaps for this + // even with the boxing overhead + public static Map BLOOM_BUFFERS = new ConcurrentHashMap<>(); + public static Map BLOOM_BUFFER_BUILDERS = new ConcurrentHashMap<>(); + public static Map BLOOM_BUFFER_SORT_STATES = new ConcurrentHashMap<>(); + + public static boolean enabled() { + return GTMixinPlugin.isOptionEnabled(GTEarlyConfig.SAFE_MODE); + } + + private static void drawBlockBloom(Camera camera, PoseStack poseStack, Frustum frustum, Matrix4f projectionMatrix, + LevelRenderer levelRenderer, ProfilerFiller profilerFiller) { + Vec3 camPos = camera.getPosition(); + profilerFiller.push("safe_mode"); + + ShaderInstance shader = setupBlockShaderUniforms(poseStack, projectionMatrix); + Uniform chunkOffset = shader.CHUNK_OFFSET; + + BLOOM_RENDER_LOCK.readLock().lock(); + try { + for (var entry : BLOOM_BUFFERS.entrySet()) { + SectionPos sectionPos = entry.getKey(); + VertexBuffer buffer = entry.getValue(); + + // noinspection ConstantValue it just isn't annotated :)) + if (buffer.isInvalid() || buffer.getFormat() == null) { + // return early if buffer is invalid or has no vertex data bound + continue; + } + + if (chunkOffset != null) { + chunkOffset.set(sectionPos.minBlockX() - (float) camPos.x(), + sectionPos.minBlockY() - (float) camPos.y(), + sectionPos.minBlockZ() - (float) camPos.z()); + chunkOffset.upload(); + } + + buffer.bind(); + buffer.draw(); + } + } finally { + BLOOM_RENDER_LOCK.readLock().unlock(); + } + + if (chunkOffset != null) { + chunkOffset.set(0.0f, 0.0f, 0.0f); + } + shader.clear(); + VertexBuffer.unbind(); + + // pop the "safe_mode" profiler section before posting forge render stage event + profilerFiller.pop(); + + // noinspection UnstableApiUsage + ForgeHooksClient.dispatchRenderStage(BloomHandler.RenderStage.AFTER_BLOOM, levelRenderer, + poseStack, projectionMatrix, levelRenderer.getTicks(), camera, frustum); + } + + public static void finishBloomBuffer(SectionPos sectionPos, BufferBuilder builder) { + BufferBuilder.RenderedBuffer buffer = builder.endOrDiscardIfEmpty(); + if (buffer == null) { + return; + } + + BLOOM_RENDER_LOCK.writeLock().lock(); + try { + BLOOM_BUFFER_BUILDERS.remove(sectionPos, builder); + BLOOM_BUFFER_SORT_STATES.put(sectionPos, builder.getSortState()); + + RenderCall upload = () -> { + VertexBuffer vertexBuffer = BLOOM_BUFFERS.computeIfAbsent(sectionPos, + $ -> new VertexBuffer(VertexBuffer.Usage.STATIC)); + uploadBloomBuffer(buffer, vertexBuffer); + }; + if (RenderSystem.isOnRenderThread()) { + upload.execute(); + } else { + RenderSystem.recordRenderCall(upload); + } + } finally { + BLOOM_RENDER_LOCK.writeLock().unlock(); + } + } + + public static void uploadBloomBuffer(BufferBuilder.RenderedBuffer builder, VertexBuffer buffer) { + if (!buffer.isInvalid()) { + buffer.bind(); + buffer.upload(builder); + VertexBuffer.unbind(); + } + } + + public static BufferBuilder getOrStartBloomBuffer(SectionPos sectionPos) { + BufferBuilder builder = BLOOM_BUFFER_BUILDERS.computeIfAbsent(sectionPos, + $ -> new BufferBuilder(GTRenderTypes.bloom().bufferSize())); + if (!builder.building()) { + builder.begin(GTRenderTypes.bloom().mode(), GTRenderTypes.bloom().format()); + } + return builder; + } + + public static void bakeBloomChunkBuffers(SectionPos sectionPos, float camX, float camY, float camZ) { + if (!BloomShaderManager.isBloomActive()) return; + + BufferBuilder builder = BLOOM_BUFFER_BUILDERS.get(sectionPos); + if (builder == null || !builder.building()) { + return; + } + builder.setQuadSorting(VertexSorting.byDistance( + camX - sectionPos.minBlockX(), + camY - sectionPos.minBlockY(), + camZ - sectionPos.minBlockZ())); + + finishBloomBuffer(sectionPos, builder); + } + + /// @return the shader to use for drawing block bloom. + private static ShaderInstance setupBlockShaderUniforms(PoseStack poseStack, Matrix4f projectionMatrix) { + ShaderInstance shader = RenderSystem.getShader(); + assert shader != null; + + for (int i = 0; i < 12; ++i) { + int textureId = RenderSystem.getShaderTexture(i); + shader.setSampler("Sampler" + i, textureId); + } + if (shader.MODEL_VIEW_MATRIX != null) shader.MODEL_VIEW_MATRIX.set(poseStack.last().pose()); + if (shader.PROJECTION_MATRIX != null) shader.PROJECTION_MATRIX.set(projectionMatrix); + if (shader.COLOR_MODULATOR != null) shader.COLOR_MODULATOR.set(RenderSystem.getShaderColor()); + if (shader.GLINT_ALPHA != null) shader.GLINT_ALPHA.set(RenderSystem.getShaderGlintAlpha()); + if (shader.FOG_START != null) shader.FOG_START.set(RenderSystem.getShaderFogStart()); + if (shader.FOG_END != null) shader.FOG_END.set(RenderSystem.getShaderFogEnd()); + if (shader.FOG_COLOR != null) shader.FOG_COLOR.set(RenderSystem.getShaderFogColor()); + if (shader.FOG_SHAPE != null) shader.FOG_SHAPE.set(RenderSystem.getShaderFogShape().getIndex()); + if (shader.TEXTURE_MATRIX != null) shader.TEXTURE_MATRIX.set(RenderSystem.getTextureMatrix()); + if (shader.GAME_TIME != null) shader.GAME_TIME.set(RenderSystem.getShaderGameTime()); + + RenderSystem.setupShaderLights(shader); + shader.apply(); + + return shader; + } + + static void invalidateLevelData() { + BLOOM_RENDER_LOCK.writeLock().lock(); + try { + BLOOM_BUFFERS.clear(); + BLOOM_BUFFER_BUILDERS.clear(); + BLOOM_BUFFER_SORT_STATES.clear(); + } finally { + BLOOM_RENDER_LOCK.writeLock().unlock(); + } + } + + public static void invalidateSectionData(SectionPos sectionPos) { + BLOOM_RENDER_LOCK.writeLock().lock(); + + try { + BLOOM_BUFFER_BUILDERS.remove(sectionPos); + BLOOM_BUFFER_SORT_STATES.remove(sectionPos); + VertexBuffer buffer = BLOOM_BUFFERS.remove(sectionPos); + + if (buffer != null) { + if (!RenderSystem.isOnRenderThread()) { + RenderSystem.recordRenderCall(buffer::close); + } else { + buffer.close(); + } + } + } finally { + BLOOM_RENDER_LOCK.writeLock().unlock(); + } + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomShaderManager.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomShaderManager.java new file mode 100644 index 00000000000..f03c607fe71 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomShaderManager.java @@ -0,0 +1,133 @@ +package com.gregtechceu.gtceu.client.bloom; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.core.config.GTEarlyConfig; +import com.gregtechceu.gtceu.core.mixins.client.bloom.GameRendererAccessor; + +import lombok.experimental.UtilityClass; +import net.irisshaders.iris.api.v0.IrisApi; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.PostChain; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RegisterShadersEvent; +import net.minecraftforge.event.TickEvent; + +import com.google.gson.JsonSyntaxException; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import lombok.Getter; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.io.IOException; + +@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) +@UtilityClass +public class BloomShaderManager { + + public static @UnknownNullability PostChain BLOOM_CHAIN = null; + public static @UnknownNullability RenderTarget BLOOM_TARGET = null; + + @Getter + private static @Nullable ShaderInstance rendertypeBloomShader; + @Getter + private static @Nullable ShaderInstance rendertypeEntityBloomShader; + + @SubscribeEvent + public static void onRegisterShaders(RegisterShadersEvent event) throws IOException { + event.registerShader(new ShaderInstance(event.getResourceProvider(), + GTCEu.id("rendertype_bloom"), DefaultVertexFormat.BLOCK), + shader -> rendertypeBloomShader = shader); + event.registerShader(new ShaderInstance(event.getResourceProvider(), + GTCEu.id("rendertype_entity_bloom"), DefaultVertexFormat.NEW_ENTITY), + shader -> rendertypeEntityBloomShader = shader); + } + + /// @return whether the post effect was loaded successfully + @ApiStatus.Internal + public static boolean initPostShaders() { + deinitPostShaders(); + + // forcefully update availability on (re-)load + bloomAvailable = updateBloomShaderAvailability(); + + if (!isBloomAvailable()) return false; + + ResourceLocation id = null; + + switch (ConfigHolder.INSTANCE.client.bloom.type) { + case UNITY -> id = GTCEu.id("shaders/post/bloom_unity.json"); + case UNREAL -> id = GTCEu.id("shaders/post/bloom_unreal.json"); + case DISABLED -> { + return true; + } + // skip adding a default branch in favor of the if statement below + } + if (id == null) { + GTCEu.LOGGER.error("Invalid bloom style {}", ConfigHolder.INSTANCE.client.bloom.type); + ConfigHolder.INSTANCE.client.bloom.type = BloomType.DISABLED; + return false; + } + + try { + Minecraft mc = Minecraft.getInstance(); + + BLOOM_CHAIN = new PostChain(mc.getTextureManager(), mc.getResourceManager(), mc.getMainRenderTarget(), id); + BLOOM_CHAIN.resize(mc.getWindow().getWidth(), mc.getWindow().getHeight()); + BLOOM_TARGET = BLOOM_CHAIN.getTempTarget("final"); + return true; + } catch (Exception e) { + GTCEu.LOGGER.error("Failed to {} shader {}:", e instanceof JsonSyntaxException ? "parse" : "load", id, e); + BLOOM_CHAIN = null; + BLOOM_TARGET = null; + return false; + } + } + + private static void deinitPostShaders() { + if (BLOOM_CHAIN != null) { + BLOOM_CHAIN.close(); + BLOOM_TARGET.destroyBuffers(); + + BLOOM_CHAIN = null; + BLOOM_TARGET = null; + } + } + + public static boolean isBloomActive() { + return BLOOM_CHAIN != null && BLOOM_TARGET != null && + ConfigHolder.INSTANCE.client.bloom.type != BloomType.DISABLED && isBloomAvailable(); + } + + @Getter + private static boolean bloomAvailable = updateBloomShaderAvailability(); + + @ApiStatus.Internal + public static void updateShaderAvailability(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.START) return; + + int tick = ((GameRendererAccessor) Minecraft.getInstance().gameRenderer).getTick(); + // only update bloom availability once a second so every frame isn't bogged down with mod loaded checks + if (tick % 20 != 0) return; + + bloomAvailable = updateBloomShaderAvailability(); + } + + private static boolean updateBloomShaderAvailability() { + return !GTEarlyConfig.OPTIFINE_PRESENT && + !(GTCEu.Mods.isIrisOculusLoaded() && IrisCallWrapper.isShaderActive()); + } + + private static class IrisCallWrapper { + + private static boolean isShaderActive() { + return IrisApi.getInstance().isShaderPackInUse(); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomType.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomType.java new file mode 100644 index 00000000000..9ede642bcbb --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomType.java @@ -0,0 +1,17 @@ +package com.gregtechceu.gtceu.client.bloom; + +public enum BloomType { + + /** + * Unity Bloom (rescale) + */ + UNITY, + /** + * Unreal Bloom (gaussian blur) + */ + UNREAL, + /** + * No bloom at all + */ + DISABLED +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/EffectRenderContext.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/EffectRenderContext.java new file mode 100644 index 00000000000..0b8826acc20 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/EffectRenderContext.java @@ -0,0 +1,74 @@ +package com.gregtechceu.gtceu.client.bloom; + +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +import lombok.Getter; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.Objects; + +/** + * Collection of various information for rendering purposes. + */ +@Accessors(fluent = true) +public final class EffectRenderContext { + + private static final EffectRenderContext instance = new EffectRenderContext(); + + public static EffectRenderContext getInstance() { + return instance; + } + + @Getter + private Frustum frustum = new Frustum(Minecraft.getInstance().levelRenderer.getFrustum()); + + private @Nullable Entity renderViewEntity; + @Getter + private float partialTicks; + @Getter + private @UnknownNullability Vec3 camPos; + @Getter + private float rotationX; + @Getter + private float rotationZ; + @Getter + private float rotationYZ; + @Getter + private float rotationXY; + @Getter + private float rotationXZ; + + public EffectRenderContext update(Camera camera, Frustum frustum, float partialTicks) { + this.renderViewEntity = camera.getEntity(); + this.camPos = camera.getPosition(); + this.partialTicks = partialTicks; + + float i = Minecraft.getInstance().options.getCameraType().isFirstPerson() ? 1 : -1; + float pitch = camera.getYRot(); + float yaw = camera.getXRot(); + + this.rotationX = Mth.cos(yaw * Mth.DEG_TO_RAD) * i; + this.rotationZ = Mth.sin(yaw * Mth.DEG_TO_RAD) * i; + this.rotationYZ = -this.rotationX * Mth.sin(pitch * Mth.DEG_TO_RAD) * i; + this.rotationXY = this.rotationZ * Mth.sin(pitch * Mth.DEG_TO_RAD) * i; + this.rotationXZ = Mth.cos(pitch * Mth.DEG_TO_RAD); + + this.frustum = frustum; + + return this; + } + + /** + * @return render view entity + */ + public Entity getRenderViewEntity() { + return Objects.requireNonNull(renderViewEntity, "renderViewEntity not available yet"); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/IBloomEffect.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/IBloomEffect.java new file mode 100644 index 00000000000..40d2bbfe998 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/IBloomEffect.java @@ -0,0 +1,34 @@ +package com.gregtechceu.gtceu.client.bloom; + +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; + +/** + * Render callback interface for {@link BloomHandler#registerBloomRender(IRenderSetup, IBloomEffect, BlockEntity)}. + */ +@FunctionalInterface +public interface IBloomEffect { + + /** + * Render the bloom effect. + * + * @param buffer buffer builder + * @param context render context + */ + @OnlyIn(Dist.CLIENT) + void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectRenderContext context); + + /** + * @param context render context + * @return if this effect should be rendered; returning {@code false} skips calling + * {@link #renderBloomEffect(PoseStack, BufferBuilder, EffectRenderContext)}. + */ + @OnlyIn(Dist.CLIENT) + default boolean shouldRenderBloomEffect(EffectRenderContext context) { + return true; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/IRenderSetup.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/IRenderSetup.java new file mode 100644 index 00000000000..fcc79e5832e --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/IRenderSetup.java @@ -0,0 +1,25 @@ +package com.gregtechceu.gtceu.client.bloom; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import com.mojang.blaze3d.vertex.BufferBuilder; + +public interface IRenderSetup { + + /** + * Run any pre render gl code here. + * + * @param buffer Buffer builder + */ + @OnlyIn(Dist.CLIENT) + void preDraw(BufferBuilder buffer); + + /** + * Run any post render gl code here. + * + * @param buffer Buffer builder + */ + @OnlyIn(Dist.CLIENT) + void postDraw(BufferBuilder buffer); +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/package-info.java new file mode 100644 index 00000000000..70a443e69ae --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.bloom; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/particle/GTBloomParticle.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/particle/GTBloomParticle.java new file mode 100644 index 00000000000..bee4f2ddf46 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/particle/GTBloomParticle.java @@ -0,0 +1,18 @@ +package com.gregtechceu.gtceu.client.bloom.particle; + +import com.gregtechceu.gtceu.client.bloom.BloomHandler; +import com.gregtechceu.gtceu.client.bloom.IBloomEffect; +import com.gregtechceu.gtceu.client.bloom.IRenderSetup; +import com.gregtechceu.gtceu.client.particle.GTParticle; + +import org.jetbrains.annotations.Nullable; + +public abstract class GTBloomParticle extends GTParticle implements IBloomEffect { + + public GTBloomParticle(double posX, double posY, double posZ) { + super(posX, posY, posZ); + BloomHandler.registerBloomRender(getBloomRenderSetup(), this, this); + } + + protected abstract @Nullable IRenderSetup getBloomRenderSetup(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java b/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java index 24f641a3328..c33392c683c 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java @@ -13,6 +13,7 @@ public class GTModelProperties { public static final ModelProperty LEVEL = new ModelProperty<>(); public static final ModelProperty POS = new ModelProperty<>(); + public static final ModelProperty PARENT_MODEL_DATA = new ModelProperty<>(); public static final ModelProperty> COVER_MODEL_DATA = new ModelProperty<>(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java index 652d19bbba8..d554b30c13f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/TextureOverrideModel.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.client.model; -import com.gregtechceu.gtceu.client.util.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -14,7 +14,6 @@ import net.minecraftforge.client.model.data.ModelData; import lombok.Getter; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -23,7 +22,6 @@ public class TextureOverrideModel extends BakedModelWrappe public static final IQuadTransformer OVERLAY_OFFSET = GTQuadTransformers.offset(0.002f); - @NotNull @Getter protected final Map textureOverrides; @@ -37,10 +35,9 @@ public BakedModel getChild() { } @Override - public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction side, - @NotNull RandomSource rand, @NotNull ModelData extraData, - @Nullable RenderType renderType) { - return retextureQuads(super.getQuads(state, side, rand, extraData, renderType), textureOverrides); + public List getQuads(@Nullable BlockState state, @Nullable Direction side, + RandomSource rand, ModelData modelData, @Nullable RenderType renderType) { + return retextureQuads(super.getQuads(state, side, rand, modelData, renderType), textureOverrides); } public static List retextureQuads(List quads, Map overrides) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java new file mode 100644 index 00000000000..9cf0d70302a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMBakedModel.java @@ -0,0 +1,59 @@ +package com.gregtechceu.gtceu.client.model.ctm; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.BakedModelWrapper; +import net.minecraftforge.client.model.data.ModelData; + +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +import static com.gregtechceu.gtceu.client.model.GTModelProperties.*; + +public class CTMBakedModel extends BakedModelWrapper { + + public CTMBakedModel(T parent) { + super(parent); + } + + public BakedModel getParent() { + return this.originalModel; + } + + @SuppressWarnings("DataFlowIssue") + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, + RandomSource rand, ModelData data, @Nullable RenderType renderType) { + ModelData parentModelData = data.has(PARENT_MODEL_DATA) ? data.get(PARENT_MODEL_DATA) : data; + if (state == null || side == null) { + return super.getQuads(state, side, rand, parentModelData, renderType); + } + BlockAndTintGetter level = data.get(LEVEL); + BlockPos pos = data.get(POS); + if (level == null || pos == null) { + return super.getQuads(state, side, rand, parentModelData, renderType); + } + + TextureConnections connections = TextureConnections.getInstance(); + connections.fillSubmapCache(level, pos, state, side); + return CTMMeshBuilder.buildCTMQuads(connections, super.getQuads(state, side, rand, parentModelData, renderType), + side); + } + + @Override + public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { + ModelData parentModelData = super.getModelData(level, pos, state, modelData); + return ModelData.builder() + .with(LEVEL, level) + .with(POS, pos) + .with(PARENT_MODEL_DATA, parentModelData) + .build(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java new file mode 100644 index 00000000000..cf0f19c3656 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/CTMMeshBuilder.java @@ -0,0 +1,240 @@ +package com.gregtechceu.gtceu.client.model.ctm; + +import com.gregtechceu.gtceu.client.model.quad.MeshBuilder; +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import org.joml.Vector2f; +import org.joml.Vector3f; + +import java.util.LinkedList; +import java.util.List; + +import static com.gregtechceu.gtceu.client.model.quad.MutableQuadView.*; +import static com.gregtechceu.gtceu.client.util.ModelEventHelper.*; + +public class CTMMeshBuilder { + + public static List buildCTMQuads(BlockAndTintGetter level, BlockPos pos, BlockState state, + List quads, Direction cullFace) { + TextureConnections connections = TextureConnections.getInstance(); + connections.fillSubmapCache(level, pos, state, cullFace); + + return buildCTMQuads(connections, quads, cullFace); + } + + public static List buildCTMQuads(TextureConnections connections, List base, + Direction cullFace) { + List result = new LinkedList<>(); + MeshBuilder meshBuilder = MeshBuilder.getInstance(); + var emitter = meshBuilder.getEmitter(); + + for (BakedQuad originalQuad : base) { + TextureAtlasSprite originalSprite = originalQuad.getSprite(); + + TextureAtlasSprite connectionSprite = CTM_SPRITE_CACHE.get(originalSprite.contents().name()); + if (connectionSprite == null) { + result.add(originalQuad); + continue; + } + + for (int xQuadrant = 0; xQuadrant < 2; xQuadrant++) { + for (int yQuadrant = 0; yQuadrant < 2; yQuadrant++) { + boolean defaultTexture = connections.isDefaultTexture(xQuadrant, yQuadrant); + TextureAtlasSprite ctmSprite = defaultTexture ? originalSprite : connectionSprite; + + emitter.fromVanilla(originalQuad, cullFace); + emitter.spriteUnbake(originalSprite, BAKE_NORMALIZED | BAKE_DEROTATE_UV); + + // slice quad into the current quadrant + subsect(emitter, Submap.X2[xQuadrant][yQuadrant]); + remapUVs(emitter, connections.getSubmapFor(xQuadrant, yQuadrant)); + + emitter.spriteBake(ctmSprite, BAKE_NORMALIZED); + + emitter.computeGeometry(); + emitter.populateMissingNormals(); + + result.add(emitter.toBakedQuad(ctmSprite)); + emitter.emit(); + } + } + } + return result; + } + + // these are only used within the below methods, but are stored here as consts to reduce allocations + // because they can be reused infinitely. DO NOT USE OUTSIDE subsect()/transformUVs()!! + + // filled in first copyUv() calls + private static final ThreadLocal uvs = ThreadLocal.withInitial(() -> new Vector2f[4]); + private static final ThreadLocal uvExtremes = ThreadLocal.withInitial(() -> { + return new Vector2f[] { new Vector2f(), new Vector2f() }; + }); + // set in copyPos() calls + private static final ThreadLocal position = ThreadLocal.withInitial(Vector3f::new); + private static final ThreadLocal xy = ThreadLocal.withInitial(() -> { + return new Vector2f[] { new Vector2f(), new Vector2f(), new Vector2f(), new Vector2f() }; + }); + private static final ThreadLocal newXy = ThreadLocal.withInitial(() -> { + return new Vector2f[] { new Vector2f(), new Vector2f(), new Vector2f(), new Vector2f() }; + }); + + private static void remapUVs(MutableQuadView quad, ISubmap submap) { + submap = submap.unitScale(); + + Vector2f maxUV = CTMMeshBuilder.uvExtremes.get()[0]; + maxUV.set(Float.MIN_VALUE, Float.MIN_VALUE); + + // cache UVs + Vector2f[] uvs = CTMMeshBuilder.uvs.get(); + for (int i = 0; i < 4; i++) { + uvs[i] = quad.copyUv(i, uvs[i]); + maxUV.max(uvs[i]); + } + // scale the quadrants' UVs to the quadrant's area + scaleUVCoordinatesToQuadrant(uvs, maxUV); + + // recompute min & max UVs + Vector2f[] uvExtremes = getUVExtremes(uvs); + Vector2f minUV = uvExtremes[0]; + maxUV = uvExtremes[1]; + + float width = maxUV.x - minUV.x; + float height = maxUV.y - minUV.y; + + float minU = submap.getXOffset(); + float minV = submap.getYOffset(); + minU += minUV.x * submap.getWidth(); + minV += minUV.y * submap.getHeight(); + + float maxU = minU + (width * submap.getWidth()); + float maxV = minV + (height * submap.getHeight()); + + quad.uv(0, uvs[0].x <= minUV.x ? minU : maxU, uvs[0].y <= minUV.y ? minV : maxV); + quad.uv(1, uvs[1].x <= minUV.x ? minU : maxU, uvs[1].y <= minUV.y ? minV : maxV); + quad.uv(2, uvs[2].x <= minUV.x ? minU : maxU, uvs[2].y <= minUV.y ? minV : maxV); + quad.uv(3, uvs[3].x <= minUV.x ? minU : maxU, uvs[3].y <= minUV.y ? minV : maxV); + } + + // TODO simplify, this is quite long + public static MutableQuadView subsect(final MutableQuadView quad, ISubmap submap) { + Direction normal = quad.nominalFace(); + // nominalFace should never be null here; MutableQuadView.fromVanilla updates it + assert normal != null; + + Vector2f[] xy = CTMMeshBuilder.xy.get(); + Vector2f[] newXy = CTMMeshBuilder.newXy.get(); + Vector3f position = CTMMeshBuilder.position.get(); + for (int i = 0; i < 4; i++) { + // updates position + quad.copyPos(i, position); + + switch (normal.getAxis()) { + case X -> xy[i].set(position.z, position.y); + case Y -> xy[i].set(position.x, position.z); + case Z -> xy[i].set(position.x, position.y); + } + } + + if (normal != Direction.UP) { + submap = submap.flipY(); + } + if (normal == Direction.EAST || normal == Direction.NORTH) { + submap = submap.flipX(); + } + + submap = submap.unitScale(); + + if (normal.getAxis() == Direction.Axis.Y || normal == Direction.SOUTH || normal == Direction.WEST) { + // Relative X is the same sign for DOWN, UP, SOUTH, and WEST + newXy[0].x = Math.max(xy[0].x, submap.getXOffset()); // DUSW + newXy[1].x = Math.max(xy[1].x, submap.getXOffset()); // DUSW + newXy[2].x = Math.min(xy[2].x, submap.getXOffset() + submap.getWidth()); // DUSW + newXy[3].x = Math.min(xy[3].x, submap.getXOffset() + submap.getWidth()); // DUSW + } else { + // Flip relative X for NORTH and EAST + newXy[0].x = Math.min(xy[0].x, submap.getXOffset() + submap.getWidth()); // NE + newXy[1].x = Math.min(xy[1].x, submap.getXOffset() + submap.getWidth()); // NE + newXy[2].x = Math.max(xy[2].x, submap.getXOffset()); // NE + newXy[3].x = Math.max(xy[3].x, submap.getXOffset()); // NE + } + if (normal != Direction.UP) { + // Relative Y is the same sign for all but UP + newXy[0].y = Math.min(xy[0].y, submap.getYOffset() + submap.getHeight()); // DNSWE + newXy[1].y = Math.max(xy[1].y, submap.getYOffset()); // DNSWE + newXy[2].y = Math.max(xy[2].y, submap.getYOffset()); // DNSWE + newXy[3].y = Math.min(xy[3].y, submap.getYOffset() + submap.getHeight()); // DNSWE + } else { + // Flip relative Y for UP + newXy[0].y = Math.max(xy[0].y, submap.getYOffset()); // U + newXy[1].y = Math.min(xy[1].y, submap.getYOffset() + submap.getHeight()); // U + newXy[2].y = Math.min(xy[2].y, submap.getYOffset() + submap.getHeight()); // U + newXy[3].y = Math.max(xy[3].y, submap.getYOffset()); // U + } + + float u0 = normalize(newXy[0].x, xy[0].x, xy[3].x), + v0 = normalize(newXy[0].y, xy[0].y, xy[1].y); + float u1 = normalize(newXy[1].x, xy[1].x, xy[2].x), + v1 = normalize(newXy[1].y, xy[1].y, xy[0].y); + float u2 = normalize(newXy[2].x, xy[2].x, xy[1].x), + v2 = normalize(newXy[2].y, xy[2].y, xy[3].y); + float u3 = normalize(newXy[3].x, xy[3].x, xy[0].x), + v3 = normalize(newXy[3].y, xy[3].y, xy[2].y); + + quad.uv(0, Mth.lerp(u0, quad.u(0), quad.u(3)), Mth.lerp(v0, quad.v(0), quad.v(1))); + quad.uv(1, Mth.lerp(u1, quad.u(1), quad.u(2)), Mth.lerp(v1, quad.v(1), quad.v(0))); + quad.uv(2, Mth.lerp(u2, quad.u(2), quad.u(1)), Mth.lerp(v2, quad.v(2), quad.v(3))); + quad.uv(3, Mth.lerp(u3, quad.u(3), quad.u(0)), Mth.lerp(v3, quad.v(3), quad.v(2))); + + // spotless:off + for (int i = 0; i < 4; i++) { + switch (normal.getAxis()) { + case X -> quad.pos(i, quad.x(i), newXy[i].y, newXy[i].x); + case Y -> quad.pos(i, newXy[i].x, quad.y(i), newXy[i].y); + case Z -> quad.pos(i, newXy[i].x, newXy[i].y, quad.z(i)); + } + } + // spotless:on + + return quad; + } + + public static Vector2f[] getUVExtremes(Vector2f[] uvs) { + Vector2f[] uvExtremes = CTMMeshBuilder.uvExtremes.get(); + uvExtremes[0].set(Float.MAX_VALUE, Float.MAX_VALUE); + uvExtremes[1].set(Float.MIN_VALUE, Float.MIN_VALUE); + + for (int i = 0; i < 4; i++) { + Vector2f vertexUV = uvs[i]; + uvExtremes[0].min(vertexUV); + uvExtremes[1].max(vertexUV); + } + return uvExtremes; + } + + private static void scaleUVCoordinatesToQuadrant(Vector2f[] uvs, Vector2f maxUV) { + float minU = maxUV.x() - 0.5f > Mth.EPSILON ? 0.5f : 0.0f, + minV = maxUV.y() - 0.5f > Mth.EPSILON ? 0.5f : 0.0f; + float maxU = maxUV.x() - 0.5f > Mth.EPSILON ? 1.0f : 0.5f, + maxV = maxUV.y() - 0.5f > Mth.EPSILON ? 1.0f : 0.5f; + + for (int i = 0; i < 4; i++) { + // scale u,v to a 0-1 range + uvs[i].set(normalize(uvs[i].x, minU, maxU), normalize(uvs[i].y, minV, maxV)); + } + } + + /// scale {@code delta} to a 0-1 range based on {@code min} and {@code max} + public static float normalize(float delta, float min, float max) { + if (min == max) return 0.5f; + return Mth.clamp(Mth.inverseLerp(delta, min, max), 0.0f, 1.0f); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java new file mode 100644 index 00000000000..33724843038 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ConnectionCheck.java @@ -0,0 +1,86 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ +package com.gregtechceu.gtceu.client.model.ctm; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + +/** + * Sourced from ConnectedTexturesMod + * with considerable simplification. + */ +@UtilityClass +public class ConnectionCheck { + + /** + * A simple check for if the given block can connect to the given direction on the given side. + * + * @param level The level the positions are in. + * @param current The position of your block. + * @param currentState The current state of your block. + * @param connection The position of the block to check against. + * @param dir The {@link Direction side} of the block to check for connection status. + * This is not the direction to check in. + * @return True if the given block can connect to the given location on the given side. + */ + public static boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, + BlockPos connection, Direction dir) { + BlockState state = getConnectionState(level, current, currentState, + dir, connection, level.getBlockState(connection)); + return isConnected(level, current, currentState, connection, dir, state); + } + + /** + * A simple check for if the given block can connect to the given direction on the given side. + * + * @param level The level the positions are in. + * @param current The position of your block. + * @param connection The position of the block to check against. + * @param dir The {@link Direction side} of the block to check for connection status. + * This is not the direction to check in. + * @param state The state to check against for connection. + * @return True if the given block can connect to the given location on the given side. + */ + public static boolean isConnected(BlockAndTintGetter level, BlockPos current, BlockState currentState, + BlockPos connection, + Direction dir, BlockState state) { + BlockState connectionState = getConnectionState(level, connection, level.getBlockState(connection), dir, + current, currentState); + BlockPos obscuringPos = connection.relative(dir); + BlockState obscuring = getConnectionState(level, obscuringPos, level.getBlockState(obscuringPos), + dir, current, currentState); + + // check that we are connected AND aren't already connected outwards from this side + return state == connectionState && state != obscuring; + } + + public static BlockState getConnectionState(BlockAndTintGetter level, BlockPos pos, BlockState state, + @Nullable Direction side, BlockPos connection, + BlockState connectionState) { + if (side != null) { + return state.getAppearance(level, pos, side, connectionState, connection); + } + return state; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java new file mode 100644 index 00000000000..e7f733011e1 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/GTTextureMetadata.java @@ -0,0 +1,68 @@ +package com.gregtechceu.gtceu.client.model.ctm; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.utils.TriState; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.metadata.MetadataSectionSerializer; +import net.minecraft.server.packs.resources.Resource; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.SneakyThrows; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Optional; +import java.util.function.Function; + +public record GTTextureMetadata(@Nullable ResourceLocation connectionTexture, TriState bloom) { + + public static final String SECTION_NAME = GTCEu.MOD_ID; + public static final MetadataSectionSerializer SERIALIZER = new Serializer(); + + public static final GTTextureMetadata EMPTY = new GTTextureMetadata(null, TriState.DEFAULT); + + /** + * @apiNote This method throws {@link IOException} even though it isn't specified in the method definition. + */ + @SneakyThrows(IOException.class) + public static Optional getForResourceUnsafe(Resource resource) { + return resource.metadata().getSection(SERIALIZER); + } + + public GTTextureMetadata { + // Optional codec fields can't have null as the default value, so we do this instead. + // It's impossible to define an entirely empty ResourceLocation in a resource file, + // as even ":" is converted to "minecraft:". Thus, this should be entirely safe. + if (connectionTexture == Serializer.EMPTY_CONNECTION) connectionTexture = null; + } + + public static class Serializer implements MetadataSectionSerializer { + + protected static final ResourceLocation EMPTY_CONNECTION = new ResourceLocation("", ""); + + // spotless:off + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + ResourceLocation.CODEC.optionalFieldOf("connection_texture", EMPTY_CONNECTION).forGetter(GTTextureMetadata::connectionTexture), + TriState.CODEC.optionalFieldOf("bloom", TriState.DEFAULT).forGetter(GTTextureMetadata::bloom) + ).apply(instance, GTTextureMetadata::new)); + // spotless:on + + @Override + public GTTextureMetadata fromJson(@Nullable JsonObject json) throws JsonParseException { + return CODEC.parse(JsonOps.INSTANCE, json).get() + .map(Function.identity(), r -> { + throw new JsonParseException(r.message()); + }); + } + + @Override + public String getMetadataSectionName() { + return SECTION_NAME; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java new file mode 100644 index 00000000000..bfea41eb64a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/ISubmap.java @@ -0,0 +1,123 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ +package com.gregtechceu.gtceu.client.model.ctm; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +import lombok.RequiredArgsConstructor; + +/** + * Sourced from ConnectedTexturesMod. + */ +public interface ISubmap { + + float getYOffset(); + + float getXOffset(); + + float getWidth(); + + float getHeight(); + + default float getInterpolatedU(TextureAtlasSprite sprite, float u) { + return sprite.getU((getXOffset() + u / getWidth()) / 16F); + } + + default float getInterpolatedV(TextureAtlasSprite sprite, float v) { + return sprite.getV((getYOffset() + v / getHeight()) / 16F); + } + + default float[] toArray() { + return new float[] { getXOffset(), getYOffset(), getXOffset() + getWidth(), getYOffset() + getHeight() }; + } + + default ISubmap unitScale() { + return new SubmapRescaled(this, UNITS_PER_PIXEL, false); + } + + default ISubmap pixelScale() { + return this; + } + + float PIXELS_PER_UNIT = 16f; + float UNITS_PER_PIXEL = 1f / PIXELS_PER_UNIT; + + @RequiredArgsConstructor + class SubmapRescaled implements ISubmap { + + private final ISubmap parent; + private final float ratio; + private final boolean isPixelScale; + + @Override + public float getXOffset() { + return parent.getXOffset() * ratio; + } + + @Override + public float getYOffset() { + return parent.getYOffset() * ratio; + } + + @Override + public float getWidth() { + return parent.getWidth() * ratio; + } + + @Override + public float getHeight() { + return parent.getHeight() * ratio; + } + + @Override + public ISubmap pixelScale() { + return isPixelScale ? this : parent; + } + + @Override + public ISubmap unitScale() { + return isPixelScale ? parent : this; + } + + @Override + public float getInterpolatedU(TextureAtlasSprite sprite, float u) { + return parent.getInterpolatedU(sprite, u); + } + + @Override + public float getInterpolatedV(TextureAtlasSprite sprite, float v) { + return parent.getInterpolatedV(sprite, v); + } + + @Override + public float[] toArray() { + return parent.toArray(); + } + } + + default ISubmap flipX() { + return Submap.fromPixelScale(getWidth(), getHeight(), PIXELS_PER_UNIT - getXOffset() - getWidth(), + getYOffset()); + } + + default ISubmap flipY() { + return Submap.fromPixelScale(getWidth(), getHeight(), getXOffset(), + PIXELS_PER_UNIT - getYOffset() - getHeight()); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java new file mode 100644 index 00000000000..ca8c0b4d925 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/OctagonalOrientation.java @@ -0,0 +1,171 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ +package com.gregtechceu.gtceu.client.model.ctm; + +import com.gregtechceu.gtceu.utils.GTUtil; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.Locale; + +import static net.minecraft.core.Direction.*; + +/** + * Think of this class as an octagonal {@link net.minecraft.core.Direction}. + *

+ * It represents the eight different directions a face of a block can connect with CTM, + * and contains the logic for determining if a block is indeed connected in that direction. + *

+ * Note that, for example, {@link #TOP_RIGHT} does not mean connected to the {@link #TOP} and {@link #RIGHT}, + * but connected in the diagonal direction represented by {@link #TOP_RIGHT}. + * This is used for inner corner rendering. + *

+ * Sourced from ConnectedTexturesMod. + */ +public enum OctagonalOrientation implements StringRepresentable { + + // spotless:off + TOP(UP), + TOP_RIGHT(UP, EAST), + RIGHT(EAST), + BOTTOM_RIGHT(DOWN, EAST), + BOTTOM(DOWN), + BOTTOM_LEFT(DOWN, WEST), + LEFT(WEST), + TOP_LEFT(UP, WEST); + // spotless:on + + public static final OctagonalOrientation[] VALUES = values(); + private static final Direction NORMAL = SOUTH; + + static { + // Run after static init + for (OctagonalOrientation dir : OctagonalOrientation.VALUES) { + dir.buildCaches(); + } + } + + private final Direction[] dirs; + + private final BlockPos[] offsets = new BlockPos[6]; + + OctagonalOrientation(Direction... dirs) { + this.dirs = dirs; + } + + private void buildCaches() { + // Fill normalized dirs + for (Direction normal : GTUtil.DIRECTIONS) { + Direction[] normalized; + if (normal == NORMAL) { + normalized = dirs; + } else if (normal == NORMAL.getOpposite()) { + // If this is the opposite direction of the default normal, we need to mirror the dirs + // A mirror version does not affect y+ and y- so we ignore those + Direction[] ret = new Direction[dirs.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = dirs[i].getStepY() != 0 ? dirs[i] : dirs[i].getOpposite(); + } + normalized = ret; + } else { + Direction axis; + // Next, we need different a different rotation axis depending on if this is up/down or not + if (normal.getAxis() != Axis.Y) { + // If it is not up/down, pick either the left or right-hand rotation + axis = normal == NORMAL.getClockWise() ? UP : DOWN; + } else { + // If it is up/down, pick either the up or down rotation. + axis = normal == UP ? NORMAL.getCounterClockWise() : NORMAL.getClockWise(); + } + Direction[] ret = new Direction[dirs.length]; + // Finally apply all the rotations + for (int i = 0; i < ret.length; i++) { + ret[i] = rotate(dirs[i], axis); + } + normalized = ret; + } + BlockPos ret = BlockPos.ZERO; + for (Direction dir : normalized) { + ret = ret.relative(dir); + } + offsets[normal.ordinal()] = ret; + } + } + + /** + * Finds if this block is connected for the given side in this OctagonalOrientation. + * + * @param level The level the block is in. + * @param pos The position of your block. + * @param state The state of your block. + * @param side The side of the current face. + * @return True if the block is connected in the given OctagonalOrientation, false otherwise. + */ + public boolean isConnected(BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side) { + return ConnectionCheck.isConnected(level, pos, state, applyConnection(pos, side), side); + } + + /** + * Finds if this block is connected for the given side in this OctagonalOrientation. + * + * @param level The level the block is in. + * @param pos The position of your block. + * @param state The state of your block. + * @param side The side of the current face. + * @param connectionState The state to check for connection with. + * @return True if the block is connected in the given OctagonalOrientation, false otherwise. + */ + public boolean isConnected(BlockAndTintGetter level, BlockPos pos, BlockState state, + Direction side, BlockState connectionState) { + return ConnectionCheck.isConnected(level, pos, state, applyConnection(pos, side), side, connectionState); + } + + /** + * Apply this OctagonalOrientation to the given BlockPos for the given normal direction. + * + * @return The offset BlockPos + */ + public BlockPos applyConnection(BlockPos pos, Direction side) { + return pos.offset(getOffset(side)); + } + + public BlockPos getOffset(Direction normal) { + return offsets[normal.ordinal()]; + } + + private Direction rotate(Direction facing, Direction axisFacing) { + Direction.Axis axis = axisFacing.getAxis(); + AxisDirection axisDir = axisFacing.getAxisDirection(); + + if (axisDir == AxisDirection.POSITIVE) { + return facing.getClockWise(axis); + } else { + return facing.getCounterClockWise(axis); + } + } + + @Override + public String getSerializedName() { + return name().toLowerCase(Locale.ROOT); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java new file mode 100644 index 00000000000..3fbfba47392 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/Submap.java @@ -0,0 +1,95 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ +package com.gregtechceu.gtceu.client.model.ctm; + +import lombok.Getter; + +/** + * Sourced from ConnectedTexturesMod. + */ +public class Submap implements ISubmap { + + // spotless:off + public static final ISubmap X1 = fromPixelScale(16, 16, 0, 0); + + public static final ISubmap[][] X2 = { + { fromPixelScale(8, 8, 0, 0), fromPixelScale(8, 8, 8, 0) }, + { fromPixelScale(8, 8, 0, 8), fromPixelScale(8, 8, 8, 8) } + }; + + private static final float DIV3 = 16 / 3f; + public static final ISubmap[][] X3 = { + { fromPixelScale(DIV3, DIV3, 0, 0), fromPixelScale(DIV3, DIV3, DIV3, 0), fromPixelScale(DIV3, DIV3, DIV3 * 2, 0) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3), fromPixelScale(DIV3, DIV3, DIV3, DIV3), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3) }, + { fromPixelScale(DIV3, DIV3, 0, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3, DIV3 * 2), fromPixelScale(DIV3, DIV3, DIV3 * 2, DIV3 * 2) }, + }; + + public static final ISubmap[][] X4 = { + { fromPixelScale(4, 4, 0, 0), fromPixelScale(4, 4, 4, 0), fromPixelScale(4, 4, 8, 0), fromPixelScale(4, 4, 12, 0) }, + { fromPixelScale(4, 4, 0, 4), fromPixelScale(4, 4, 4, 4), fromPixelScale(4, 4, 8, 4), fromPixelScale(4, 4, 12, 4) }, + { fromPixelScale(4, 4, 0, 8), fromPixelScale(4, 4, 4, 8), fromPixelScale(4, 4, 8, 8), fromPixelScale(4, 4, 12, 8) }, + { fromPixelScale(4, 4, 0, 12), fromPixelScale(4, 4, 4, 12), fromPixelScale(4, 4, 8, 12), fromPixelScale(4, 4, 12, 12) }, + }; + // spotless:on + + public static ISubmap[][] grid(int w, int h) { + float xDiv = 16f / w; + float yDiv = 16f / h; + ISubmap[][] ret = new ISubmap[h][w]; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + ret[y][x] = fromPixelScale(xDiv, yDiv, xDiv * x, yDiv * y); + } + } + return ret; + } + + public static ISubmap raw(float width, float height, float xOffset, float yOffset) { + return new Submap(width, height, xOffset, yOffset, 1); + } + + public static ISubmap fromUnitScale(float width, float height, float xOffset, float yOffset) { + return fromPixelScale(width * PIXELS_PER_UNIT, height * PIXELS_PER_UNIT, xOffset * PIXELS_PER_UNIT, + yOffset * PIXELS_PER_UNIT); + } + + public static ISubmap fromPixelScale(float width, float height, float xOffset, float yOffset) { + return new Submap(width, height, xOffset, yOffset, UNITS_PER_PIXEL); + } + + @Getter + private final float width, height; + @Getter + private final float xOffset, yOffset; + + final SubmapRescaled rescaled; + + private Submap(float width, float height, float xOffset, float yOffset, float rescale) { + this.width = width; + this.height = height; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.rescaled = new SubmapRescaled(this, rescale, false); + } + + @Override + public SubmapRescaled pixelScale() { + return this.rescaled; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java new file mode 100644 index 00000000000..1e717a3bb3c --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/TextureConnections.java @@ -0,0 +1,279 @@ +/* + * This file is part of ConnectedTexturesMod (https://github.com/Chisel-Team/ConnectedTexturesMod). + * Copyright (c) 2023 Chisel Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ConnectedTexturesMod is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with ConnectedTexturesMod; if not, If not, see . + */ +package com.gregtechceu.gtceu.client.model.ctm; + +import com.gregtechceu.gtceu.utils.ArrayHelpers; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2i; +import org.joml.Vector2ic; + +import static com.gregtechceu.gtceu.client.model.ctm.OctagonalOrientation.*; + +// spotless:off +/** + * The CTM renderer will draw the block's FACE by assembling 4 quadrants from the 5 available block textures. + * The normal {@code texture.png} is the block's "unconnected" texture, and is used when CTM is disabled or the block + * has nothing to connect to. + * This texture has all the outside corner quadrants, and {@code texture_ctm.png} contains the rest of the quadrants. + *

+ * ┌─────────────────┐ ┌────────────────────────────────┐
+ * │ texture.png     │ │ texture_ctm.png                │
+ * │ ╔══════╤══════╗ │ │  ──────┼────── ║ ─────┼───── ║ │
+ * │ ║      │      ║ │ │ │      │      │║      │      ║ │
+ * │ ║ 4/4  │ 4/5  ║ │ │ │ 0/0  │ 0/1  │║ 0/2  │ 0/3  ║ │
+ * │ ╟──────┼──────╢ │ │ ┼──────┼──────┼╟──────┼──────╢ │
+ * │ ║      │      ║ │ │ │      │      │║      │      ║ │
+ * │ ║ 5/4  │ 5/5  ║ │ │ │ 1/0  │ 1/1  │║ 1/2  │ 1/3  ║ │
+ * │ ╚══════╧══════╝ │ │  ──────┼────── ║ ─────┼───── ║ │
+ * └─────────────────┘ │ ═══════╤═══════╝ ─────┼───── ╚ │
+ *                     │ │      │      ││      │      │ │
+ *                     │ │ 2/0  │ 2/1  ││ 2/2  │ 2/3  │ │
+ *                     │ ┼──────┼──────┼┼──────┼──────┼ │
+ *                     │ │      │      ││      │      │ │
+ *                     │ │ 3/0  │ 3/1  ││ 3/2  │ 3/3  │ │
+ *                     │ ═══════╧═══════╗ ─────┼───── ╔ │
+ *                     └────────────────────────────────┘
+ * 
+ * combining { { 5/4, 3/1 }, { 2/1, 4/4 } }, we can generate a texture connected to the right! + *
+ * ╔══════╤═══════
+ * ║      │      │
+ * ║ 4/4  │ 2/1  │
+ * ╟──────┼──────┼
+ * ║      │      │
+ * ║ 5/4  │ 3/1  │
+ * ╚══════╧═══════
+ * 
+ * + * combining { { 5/4, 3/1 }, { 0/2, 2/3 } }, we can generate a texture in the shape of an L + * (connected to the right and up) + *
+ * ║ ─────┼───── ╚
+ * ║      │      │
+ * ║ 0/2  │ 2/3  │
+ * ╟──────┼──────┼
+ * ║      │      │
+ * ║ 5/4  │ 3/1  │
+ * ╚══════╧═══════
+ * 
+ * + * HAVE FUN! + * -CptRageToaster- + *

+ * Sourced from ConnectedTexturesMod. + */ +// spotless:on +@Accessors(fluent = true, chain = true) +public class TextureConnections { + + /** Hardcoded offset values for the different submap indices */ + // store the full table(s) to reduce non-required allocations + protected static final Vector2ic[][] submapOffsets = { + { new Vector2i(0, 0), new Vector2i(0, 1), new Vector2i(0, 2), new Vector2i(0, 3), }, + { new Vector2i(1, 0), new Vector2i(1, 1), new Vector2i(1, 2), new Vector2i(1, 3), }, + { new Vector2i(2, 0), new Vector2i(2, 1), new Vector2i(2, 2), new Vector2i(2, 3), }, + { new Vector2i(3, 0), new Vector2i(3, 1), new Vector2i(3, 2), new Vector2i(3, 3), }, + }; + protected static final Vector2ic[][] defaultSubmapCache = { + { new Vector2i(4, 4), new Vector2i(4, 5), }, + { new Vector2i(5, 4), new Vector2i(5, 5), }, + }; + + // spotless:off + // Mapping the different corner indices to their respective dirs + protected static final OctagonalOrientation[][][] submapMap = { + { { LEFT, TOP, TOP_LEFT }, { RIGHT, TOP, TOP_RIGHT }, }, + { { LEFT, BOTTOM, BOTTOM_LEFT }, { RIGHT, BOTTOM, BOTTOM_RIGHT }, }, + }; + // spotless:on + + protected byte connectionMap; + protected Vector2ic[][] submapCache = ArrayHelpers.deepCopy(defaultSubmapCache); + + public static TextureConnections getInstance() { + return new TextureConnections(); + } + + /** + * Calculate the indices of the typical 4x4 submap to use for the given face at the given location. + * Indices are in counter-clockwise order starting at bottom left. + * + * @return The indices of the typical 4x4 submap to use for the given face at the given location. + */ + public Vector2ic[][] fillSubmapCache(@Nullable BlockAndTintGetter level, BlockPos pos, + BlockState state, Direction side) { + if (level == null) { + return this.submapCache; + } + + buildConnectionMap(level, pos, state, side); + // Map connections to submap indices + for (int x = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + fillSubmaps(x, y); + } + } + + return this.submapCache; + } + + public Vector2ic[][] getCachedSubmapIndices() { + return this.submapCache; + } + + public Vector2ic getSubmapCoordinatesFor(int quadrantX, int quadrantY) { + return this.submapCache[quadrantX][quadrantY]; + } + + public boolean isDefaultTexture(int quadrantX, int quadrantY) { + return isDefaultTexture(getSubmapCoordinatesFor(quadrantX, quadrantY)); + } + + public static boolean isDefaultTexture(Vector2ic id) { + return id.x() >= 4 && id.y() >= 4; + } + + public ISubmap getSubmapFor(int quadrantX, int quadrantY) { + return getSubmapFor(getSubmapCoordinatesFor(quadrantX, quadrantY)); + } + + public static ISubmap getSubmapFor(Vector2ic coordinates) { + if (isDefaultTexture(coordinates)) { + return Submap.X2[coordinates.x() % 4][coordinates.y() % 4]; + } else { + return Submap.X4[coordinates.x()][coordinates.y()]; + } + } + + protected void setConnectedState(OctagonalOrientation dir, boolean connected) { + this.connectionMap = setConnectedState(this.connectionMap, dir, connected); + } + + private static byte setConnectedState(byte map, OctagonalOrientation dir, boolean connected) { + if (connected) { + return (byte) (map | (1 << dir.ordinal())); + } else { + return (byte) (map & ~(1 << dir.ordinal())); + } + } + + /** + * Builds the connection map and stores it in this CTMLogic instance.
+ * The {@link #connected(OctagonalOrientation)}, {@link #connectedAnd(OctagonalOrientation...)}, + * and {@link #connectedOr(OctagonalOrientation...)} methods can be used to access it. + */ + public void buildConnectionMap(BlockAndTintGetter world, BlockPos pos, BlockState state, Direction side) { + // TODO this naive check doesn't work for models that have unculled faces. + // Perhaps a smarter optimization could be done eventually? + for (OctagonalOrientation dir : OctagonalOrientation.VALUES) { + // Note: We can't cache the state that we are checking about connection for as we want to ensure that + // we can take into account the side of the block we want to know the "state" of as if the block is + // a facade of some sort it might return different results based on where it is being queried from + setConnectedState(dir, dir.isConnected(world, pos, state, side)); + } + } + + @SuppressWarnings("null") + protected void fillSubmaps(int x, int y) { + // [0] is horizontal, [1] is vertical, [2] is diagonal + OctagonalOrientation[] dirs = submapMap[x][y]; + if (connectedOr(dirs[0], dirs[1])) { + if (connectedAnd(dirs)) { + // If all dirs are connected, we use the fully connected face, the base offset value. + this.submapCache[x][y] = submapOffsets[x][y]; + } else { + this.submapCache[x][y] = submapOffsets[x + (connected(dirs[0]) ? 2 : 0)][y + + (connected(dirs[1]) ? 2 : 0)]; + } + } + } + + /** + * @param dir The direction to check connection in. + * @return True if the cached connectionMap holds a connection in this {@link OctagonalOrientation direction}. + */ + public boolean connected(OctagonalOrientation dir) { + return ((this.connectionMap >> dir.ordinal()) & 1) == 1; + } + + /** + * @param dirs The directions to check connection in. + * @return True if the cached connectionMap holds a connection in all the given + * {@link OctagonalOrientation directions}. + */ + @SuppressWarnings("null") + public boolean connectedAnd(OctagonalOrientation... dirs) { + for (OctagonalOrientation dir : dirs) { + if (!connected(dir)) { + return false; + } + } + return true; + } + + /** + * @param dirs + * The directions to check connection in. + * @return True if the cached connectionMap holds a connection in one of the given + * {@link OctagonalOrientation directions}. + */ + @SuppressWarnings("null") + public boolean connectedOr(OctagonalOrientation... dirs) { + for (OctagonalOrientation dir : dirs) { + if (connected(dir)) { + return true; + } + } + return false; + } + + public boolean connectedNone(OctagonalOrientation... dirs) { + for (OctagonalOrientation dir : dirs) { + if (connected(dir)) { + return false; + } + } + return true; + } + + public boolean connectedOnly(OctagonalOrientation... dirs) { + byte map = 0; + for (OctagonalOrientation dir : dirs) { + map = setConnectedState(map, dir, true); + } + return map == this.connectionMap; + } + + @Override + public int hashCode() { + return this.connectionMap; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TextureConnections other)) return false; + return this.connectionMap == other.connectionMap; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/ctm/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/package-info.java new file mode 100644 index 00000000000..ca86d8adbbc --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/ctm/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.model.ctm; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java index ed631e969e4..e580ab23c2d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java @@ -10,16 +10,16 @@ import com.gregtechceu.gtceu.client.model.GTModelProperties; import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.model.TextureOverrideModel; +import com.gregtechceu.gtceu.client.model.ctm.CTMMeshBuilder; import com.gregtechceu.gtceu.client.model.machine.multipart.MultiPartBakedModel; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.machine.trait.AutoOutputTrait; import com.gregtechceu.gtceu.utils.GTUtil; -import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; - import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; @@ -319,8 +319,8 @@ public List renderMachine(@Nullable MetaMachine machine, @Nullable Bl // we have to recalculate CTM ourselves. // this is the slowest part by a long shot because the LDLib quad logic isn't very optimized. - if (level != null && pos != null && blockState != null) { - return CustomBakedModel.reBakeCustomQuads(quads, level, pos, blockState, side, 0.0f); + if (level != null && pos != null && blockState != null && side != null) { + return CTMMeshBuilder.buildCTMQuads(level, pos, blockState, quads, side); } return quads; } @@ -343,7 +343,7 @@ public List replacePartBaseModel(List originalQuads, IMult var controllers = part.getControllers(); for (MultiblockControllerMachine controller : controllers) { var state = controller.getBlockState(); - BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); + BakedModel model = RenderUtil.getModelForState(state); List newQuads = null; // spotless:off diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java index 756fd4d977e..9c694981ff8 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/package-info.java @@ -1,7 +1,4 @@ -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault +@NotNullByDefault package com.gregtechceu.gtceu.client.model; -import net.minecraft.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java index d529223d327..3e04a26c029 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java @@ -9,7 +9,8 @@ import com.gregtechceu.gtceu.client.model.GTModelProperties; import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel; import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; -import com.gregtechceu.gtceu.client.util.GTQuadTransformers; +import com.gregtechceu.gtceu.client.util.RenderUtil; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; import com.gregtechceu.gtceu.utils.GTUtil; @@ -102,7 +103,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction return quads; } BlockState frameState = frameBlockEntry.getDefaultState(); - BakedModel frameModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(frameState); + BakedModel frameModel = RenderUtil.getModelForState(frameState); modelData = frameModel.getModelData(level, pos, frameState, modelData); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java new file mode 100644 index 00000000000..85795309e0f --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/EncodingFormat.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.client.model.quad; + +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; + +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraftforge.client.model.IQuadTransformer; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +/** + * Holds all the array offsets and bit-wise encoders/decoders for packing/unpacking quad data in an array of integers. + * All of this is implementation-specific - that's why it isn't a "helper" class. + */ +@SuppressWarnings("PointlessArithmeticExpression") +@UtilityClass +public class EncodingFormat { + + static final int VERTEX_X = IQuadTransformer.POSITION + 0; + static final int VERTEX_Y = IQuadTransformer.POSITION + 1; + static final int VERTEX_Z = IQuadTransformer.POSITION + 2; + static final int VERTEX_COLOR = IQuadTransformer.COLOR; + static final int VERTEX_U = IQuadTransformer.UV0 + 0; + static final int VERTEX_V = IQuadTransformer.UV0 + 1; + static final int VERTEX_LIGHTMAP = IQuadTransformer.UV2; + static final int VERTEX_NORMAL = IQuadTransformer.NORMAL; + public static final int VERTEX_STRIDE = IQuadTransformer.STRIDE; + + public static final int QUAD_STRIDE = VERTEX_STRIDE * 4; + + /** used for quick clearing of quad buffers. */ + static final int[] EMPTY = new int[QUAD_STRIDE]; + + private static final int DIRECTION_MASK = Mth.smallestEncompassingPowerOfTwo(GeometryHelper.NULL_FACE_ID) - 1; + private static final int DIRECTION_BIT_COUNT = Integer.bitCount(DIRECTION_MASK); + private static final int CULL_SHIFT = 0; + private static final int CULL_INVERSE_MASK = ~(DIRECTION_MASK << CULL_SHIFT); + private static final int LIGHT_SHIFT = CULL_SHIFT + DIRECTION_BIT_COUNT; + private static final int LIGHT_INVERSE_MASK = ~(DIRECTION_MASK << LIGHT_SHIFT); + private static final int NORMALS_SHIFT = LIGHT_SHIFT + DIRECTION_BIT_COUNT; + private static final int NORMALS_COUNT = 4; + private static final int NORMALS_MASK = (1 << NORMALS_COUNT) - 1; + private static final int NORMALS_INVERSE_MASK = ~(NORMALS_MASK << NORMALS_SHIFT); + + static @Nullable Direction cullFace(long bits) { + return GeometryHelper.faceFromIndex((int) ((bits >> CULL_SHIFT) & DIRECTION_MASK)); + } + + static long cullFace(long bits, @Nullable Direction face) { + return (bits & CULL_INVERSE_MASK) | (GeometryHelper.toFaceIndex(face) << CULL_SHIFT); + } + + static Direction lightFace(long bits) { + return Objects.requireNonNull(GeometryHelper.faceFromIndex((int) ((bits >> LIGHT_SHIFT) & DIRECTION_MASK))); + } + + static long lightFace(long bits, Direction face) { + return (bits & LIGHT_INVERSE_MASK) | ((long) GeometryHelper.toFaceIndex(face) << LIGHT_SHIFT); + } + + /** indicate if vertex normal has been set - bits correspond to vertex ordinals. */ + static int normalFlags(long bits) { + return (int) ((bits >> NORMALS_SHIFT) & NORMALS_MASK); + } + + static long normalFlags(long bits, int normalFlags) { + return (bits & NORMALS_INVERSE_MASK) | ((long) (normalFlags & NORMALS_MASK) << NORMALS_SHIFT); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java new file mode 100644 index 00000000000..29403d1af8a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/Mesh.java @@ -0,0 +1,66 @@ +package com.gregtechceu.gtceu.client.model.quad; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlas; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * A bundle of one or more {@link QuadView} instances encoded by the renderer. + * + *

+ * Similar in purpose to the {@code List} instances returned by BakedModel, but affords the renderer the + * ability to optimize the format for performance and memory allocation. + * + *

+ * Only the renderer should implement or extend this interface. + * + * @implNote The way we encode meshes makes it very simple. + */ +public class Mesh { + + /** Used to satisfy external calls to {@link #forEach(Consumer)}. */ + private static final ThreadLocal POOL = ThreadLocal.withInitial(QuadView::new); + + final int[] data; + + Mesh(int[] data) { + this.data = data; + } + + public int[] data() { + return data; + } + + public void forEach(Consumer consumer) { + forEach(consumer, POOL.get()); + } + + /** + * The renderer will call this with its own cursor to avoid the performance hit of a thread-local lookup. Also + * means renderer can hold final references to quad buffers. + */ + void forEach(Consumer consumer, QuadView cursor) { + final int limit = data.length; + int index = 0; + + while (index < limit) { + cursor.load(data, index); + consumer.accept(cursor); + index += EncodingFormat.QUAD_STRIDE; + } + } + + @SuppressWarnings("deprecation") + public List toBlockBakedQuads() { + SpriteFinder finder = SpriteFinder.get(Minecraft.getInstance().getModelManager() + .getAtlas(TextureAtlas.LOCATION_BLOCKS)); + + List result = new ArrayList<>(); + forEach(qv -> result.add(qv.toBakedQuad(finder.find(qv)))); + return result; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java new file mode 100644 index 00000000000..bfebec00b2b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MeshBuilder.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.client.model.quad; + +/** + * Similar in purpose to {@link com.mojang.blaze3d.vertex.BufferBuilder} but simpler and not tied to NIO + * or any other specific implementation, plus designed to handle both static and dynamic building. + * + *

+ * Decouples models from the vertex format(s) used by ModelRenderer to allow compatibility across diverse + * implementations. + * + * @implNote Not much to it - mainly it just needs to grow the int[] array as quads are appended and + * maintain/provide a properly-configured {@link MutableQuadView} instance. + * All the encoding and other work is handled in the quad base classes. + * The one interesting bit is in {@link Maker#emit()}. + */ +public class MeshBuilder { + + private int[] data = new int[256]; + private final Maker maker = new Maker(); + private int index = 0; + private int limit = data.length; + + public static MeshBuilder getInstance() { + return new MeshBuilder(); + } + + protected void ensureCapacity() { + if (EncodingFormat.QUAD_STRIDE > limit - index) { + limit *= 2; + final int[] bigger = new int[limit]; + System.arraycopy(data, 0, bigger, 0, index); + data = bigger; + maker.data = bigger; + } + } + + public Mesh build() { + final int[] packed = new int[index]; + System.arraycopy(data, 0, packed, 0, index); + index = 0; + maker.begin(data, index); + return new Mesh(packed); + } + + public MutableQuadView getEmitter() { + ensureCapacity(); + maker.begin(data, index); + return maker; + } + + /** + * Our base classes are used differently so we define final encoding steps in subtypes. This will be a static mesh + * used at render time so we want to capture all geometry now and apply non-location-dependent lighting. + */ + private class Maker extends MutableQuadView { + + @Override + public Maker emit() { + computeGeometry(); + populateMissingNormals(); + index += EncodingFormat.QUAD_STRIDE; + ensureCapacity(); + baseIndex = index; + clear(); + return this; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java new file mode 100644 index 00000000000..828720357f5 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/MutableQuadView.java @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.client.model.quad; + +import com.gregtechceu.gtceu.client.util.TextureHelper; +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; + +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraftforge.client.model.QuadTransformers; + +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2fc; +import org.joml.Vector3f; + +import static com.gregtechceu.gtceu.client.model.quad.EncodingFormat.*; + +/** + * A mutable {@link QuadView} instance. + * + *

+ * Instances of {@link MutableQuadView} will practically always be thread local and/or reused - do not retain + * references. + * + *

+ * Only the renderer should implement or extend this interface. + * + * @implNote Almost-concrete implementation of a mutable quad. + */ +public abstract class MutableQuadView extends QuadView { + + /** + * Causes texture to appear with no rotation. + * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_NONE = 0b000000; + + /** + * Causes texture to appear rotated 90 deg. clockwise relative to nominal face. Pass in bakeFlags parameter to + * {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_90 = 0b000001; + + /** + * Causes texture to appear rotated 180 deg. relative to nominal face. Pass in bakeFlags parameter to + * {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_180 = 0b000010; + + /** + * Causes texture to appear rotated 270 deg. clockwise relative to nominal face. Pass in bakeFlags parameter to + * {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_ROTATE_270 = 0b000011; + + /** + * When enabled, texture coordinates are assigned based on vertex position. + * Any existing UV coordinates will be replaced. + * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * + *

+ * UV lock always derives texture coordinates based on nominal face, even when the quad is not co-planar + * with that face. The result is the same as if the quad were projected onto the nominal face, which is usually the + * desired result. + */ + public static final int BAKE_LOCK_UV = 0b000100; + + /** + * When enabled, texture coordinates are cycled so that vertex 0's UVs are the smallest. + * Pass in bakeFlags parameter to {@link TextureHelper#unbakeSprite(MutableQuadView, TextureAtlasSprite, int)}. + */ + public static final int BAKE_DEROTATE_UV = 0b000100; + + /** + * When set, U texture coordinates for the given sprite are flipped as part of baking. Can be useful for some + * randomization and texture mapping scenarios. Results are different from what can be obtained via rotation and + * both can be applied. Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_FLIP_U = 0b001000; + + /** + * Same as {@link #BAKE_FLIP_U} but for V coordinate. + */ + public static final int BAKE_FLIP_V = 0b010000; + + /** + * UV coordinates by default are assumed to be 0-16 scale for consistency with conventional Minecraft model format. + * This is scaled to 0-1 during baking before interpolation. Model loaders that already have 0-1 coordinates can + * avoid wasteful multiplication/division by passing 0-1 coordinates directly. + * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + */ + public static final int BAKE_NORMALIZED = 0b100000; + + public static MutableQuadView getInstance() { + return MutableQuadView.THREAD_LOCAL.get(); + } + + public static final ThreadLocal THREAD_LOCAL = ThreadLocal + .withInitial(() -> new MutableQuadView() { + + { + begin(new int[QUAD_STRIDE], 0); + } + + @Override + public MutableQuadView emit() { + throw new UnsupportedOperationException(); + } + }); + + public final void begin(int[] data, int baseIndex) { + this.data = data; + this.baseIndex = baseIndex; + clear(); + } + + public void clear() { + System.arraycopy(EMPTY, 0, data, baseIndex, QUAD_STRIDE); + isGeometryInvalid = true; + nominalFace = null; + tintIndex(-1); + cullFace(null); + } + + /** + * Sets the geometric vertex position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView pos(int vertexIndex, float x, float y, float z) { + final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; + data[index] = Float.floatToRawIntBits(x); + data[index + 1] = Float.floatToRawIntBits(y); + data[index + 2] = Float.floatToRawIntBits(z); + isGeometryInvalid = true; + return this; + } + + /** + * Same as {@link #pos(int, float, float, float)} but accepts a vector type. + */ + public MutableQuadView pos(int vertexIndex, Vector3f pos) { + return pos(vertexIndex, pos.x(), pos.y(), pos.z()); + } + + /** + * Sets the vertex X position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView x(int vertexIndex, float x) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X] = Float.floatToRawIntBits(x); + isGeometryInvalid = true; + return this; + } + + /** + * Sets the vertex Y position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView y(int vertexIndex, float y) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y] = Float.floatToRawIntBits(y); + isGeometryInvalid = true; + return this; + } + + /** + * Sets the vertex Z position for the given vertex, relative to block origin, (0,0,0). + * Minecraft rendering is designed for models that fit within a single block space and is recommended + * that coordinates remain in the 0-1 range, with multi-block meshes split into multiple per-block models. + */ + public MutableQuadView z(int vertexIndex, float z) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z] = Float.floatToRawIntBits(z); + isGeometryInvalid = true; + return this; + } + + /** + * Set vertex color. + */ + public MutableQuadView color(int vertexIndex, int color) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color; + return this; + } + + /** + * Convenience: set vertex color for all vertices at once. + */ + public MutableQuadView color(int c0, int c1, int c2, int c3) { + color(0, c0); + color(1, c1); + color(2, c2); + color(3, c3); + return this; + } + + /** + * Set texture coordinates. + */ + public MutableQuadView uv(int vertexIndex, float u, float v) { + final int i = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U; + data[i] = Float.floatToRawIntBits(u); + data[i + 1] = Float.floatToRawIntBits(v); + return this; + } + + /** + * Set texture coordinates. + * + *

+ * Only use this function if you already have a {@link Vector2fc}. + * Otherwise, see {@link MutableQuadView#uv(int, float, float)}. + * + * @see MutableQuadView#uv(int, float, float) + */ + public MutableQuadView uv(int vertexIndex, Vector2fc uv) { + return uv(vertexIndex, uv.x(), uv.y()); + } + + /** + * Assigns sprite atlas u,v coordinates to this quad for the given sprite. + * Can handle UV locking, rotation, interpolation, etc. + * Control this behavior by passing additive combinations of the BAKE_ flags defined in this interface. + */ + public MutableQuadView spriteBake(@Nullable TextureAtlasSprite sprite, int bakeFlags) { + TextureHelper.bakeSprite(this, sprite, bakeFlags); + return this; + } + + /** + * Normalizes this quad's u,v coordinates based on the given sprite. + * Can handle UV rotation, interpolation, etc. + * Control this behavior by passing additive combinations of the BAKE_ flags defined in this interface. + */ + public MutableQuadView spriteUnbake(@Nullable TextureAtlasSprite sprite, int bakeFlags) { + TextureHelper.unbakeSprite(this, sprite, bakeFlags); + return this; + } + + /** + * Accept vanilla lightmap values. + * Input values will override lightmap values computed from world state if input values are higher. + */ + public MutableQuadView lightmap(int vertexIndex, int lightmap) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap; + return this; + } + + /** + * Accept vanilla lightmap values. + * Input values will override lightmap values computed from world state if input values are higher. + */ + public MutableQuadView lightmap(int vertexIndex, int block, int sky) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = LightTexture.pack(block, sky); + return this; + } + + /** + * Convenience: set lightmap for all vertices at once. + * + * @see #lightmap(int, int) + */ + public MutableQuadView lightmap(int b0, int b1, int b2, int b3) { + lightmap(0, b0); + lightmap(1, b1); + lightmap(2, b2); + lightmap(3, b3); + return this; + } + + protected void normalFlags(int flags) { + headerFlags = EncodingFormat.normalFlags(headerFlags, flags); + } + + /** + * Adds a vertex normal. + * Models that have per-vertex normals should include them to get correct lighting when it matters. + * Computed face normal is used when no vertex normal is provided. + */ + public MutableQuadView normal(int vertexIndex, float x, float y, float z) { + normalFlags(normalFlags() | (1 << vertexIndex)); + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL] = GeometryHelper.packNormal(x, y, z, 0); + return this; + } + + /** + * Same as {@link #normal(int, float, float, float)} but accepts a vector type. + */ + public MutableQuadView normal(int vertexIndex, Vector3f normal) { + return normal(vertexIndex, normal.x(), normal.y(), normal.z()); + } + + /** + * Internal helper method. Copies face normals to vertex normals lacking one. + */ + public final void populateMissingNormals() { + final int normalFlags = this.normalFlags(); + if (normalFlags == 0b1111) + return; + + final int packedFaceNormal = GeometryHelper.packNormal(faceNormal(), 0); + + for (int v = 0; v < 4; v++) { + if ((normalFlags & (1 << v)) == 0) { + data[baseIndex + v * VERTEX_STRIDE + VERTEX_NORMAL] = packedFaceNormal; + } + } + + normalFlags(0b1111); + } + + /** + * If non-null, quad is coplanar with a block face which, if known, simplifies or shortcuts geometric analysis + * that might otherwise be needed. Set to null if quad is not coplanar or if this is not known. + * Also controls face culling during block rendering. + * + *

+ * Null by default. + * + *

+ * When called with a non-null value, also sets {@link #nominalFace(Direction)} to the same value. + * + *

+ * This is different from the value reported by {@link BakedQuad#getDirection()}. That value is computed based on + * face geometry and must be non-null in vanilla quads. That computed value is returned by {@link #lightFace()}. + */ + public final MutableQuadView cullFace(@Nullable Direction face) { + headerFlags = EncodingFormat.cullFace(headerFlags, face); + nominalFace(face); + return this; + } + + /** + * Provides a hint to renderer about the facing of this quad. + * Not required, but if provided can shortcut some geometric analysis if the quad is parallel to a block face. + * Should be the expected value of {@link #lightFace()}. + * Value will be confirmed and if invalid the correct light face will be calculated. + * + *

+ * Null by default, and set automatically by {@link #cullFace()}. + * + *

+ * Models may also find this useful as the face for texture UV locking and rotation semantics. + * + *

+ * Note: This value is not persisted independently when the quad is encoded. + * When reading encoded quads, this value will always be the same as {@link #lightFace()}. + */ + public final MutableQuadView nominalFace(@Nullable Direction face) { + this.nominalFace = face; + return this; + } + + /** + * Value functions identically to {@link BakedQuad#getTintIndex()} + * and is used by renderer / model builder in same way.
+ * Default value is -1. + */ + public final MutableQuadView tintIndex(int tintIndex) { + this.tintIndex = tintIndex; + return this; + } + + /** + * Value functions identically to {@link BakedQuad#isShade()} + * and is used by renderer / model builder in the same way.
+ * Default value is true. + */ + public final MutableQuadView shade(boolean shade) { + this.shade = shade; + return this; + } + + /** + * Value functions identically to {@link BakedQuad#hasAmbientOcclusion()} + * and is used by renderer / model builder in the same way.
+ * Default value is true. + */ + public final MutableQuadView ambientOcclusion(boolean ao) { + this.ambientOcclusion = ao; + return this; + } + + /** + * Enables bulk vertex data transfer using the standard Minecraft vertex formats. Only the + * {@link BakedQuad#getVertices() quad vertex data} is copied. This method should be performant whenever caller's + * vertex representation makes it feasible. + * + *

+ * Use {@link #fromVanilla(BakedQuad, Direction) the other overload} which has better encapsulation + * unless you have a specific reason to use this one. + * + *

+ * Calling this method does not emit the quad. + */ + public final MutableQuadView fromVanilla(int[] quadData, int startIndex) { + clear(); + System.arraycopy(quadData, startIndex, this.data, this.baseIndex, QUAD_STRIDE); + this.isGeometryInvalid = true; + + int colorIndex = baseIndex + VERTEX_COLOR; + + for (int i = 0; i < 4; i++) { + this.data[colorIndex] = QuadTransformers.toABGR(this.data[colorIndex]); + colorIndex += VERTEX_STRIDE; + } + + return this; + } + + /** + * Enables bulk vertex data transfer using the standard Minecraft quad format. + * + *

+ * Calling this method does not emit the quad. + */ + public final MutableQuadView fromVanilla(BakedQuad quad, @Nullable Direction cullFace) { + fromVanilla(quad.getVertices(), 0); + headerFlags = EncodingFormat.cullFace(0, cullFace); + + nominalFace(quad.getDirection()); + tintIndex(quad.getTintIndex()); + shade(quad.isShade()); + ambientOcclusion(quad.hasAmbientOcclusion()); + + return this; + } + + /** + * In static mesh building, causes quad to be appended to the mesh being built. In a dynamic render context, create + * a new quad to be output to rendering. In both cases, current instance is reset to default values. + */ + public abstract MutableQuadView emit(); + + /** + * Tolerance for determining if the depth parameter to {@link #square(Direction, float, float, float, float, float)} + * is effectively zero - meaning the face is a cull face. + */ + private static final float CULL_FACE_EPSILON = Mth.EPSILON; + + /** + * Helper method to assign vertex coordinates for a square aligned with the given face. + * Ensures that vertex order is consistent with vanilla convention. + * (Incorrect order can lead to bad AO lighting unless enhanced lighting logic is available/enabled.) + * + *

+ * Square will be parallel to the given face and coplanar with the face (and culled if the face is occluded) + * if the depth parameter is approximately zero. See {@link #CULL_FACE_EPSILON}. + * + *

+ * All coordinates should be normalized (0-1). + */ + public MutableQuadView square(Direction nominalFace, float left, float bottom, float right, float top, + float depth) { + if (Math.abs(depth) < CULL_FACE_EPSILON) { + cullFace(nominalFace); + depth = 0; // avoid any inconsistency for face quads + } else { + cullFace(null); + } + + nominalFace(nominalFace); + switch (nominalFace) { + case UP: + depth = 1 - depth; + top = 1 - top; + bottom = 1 - bottom; + // Fallthrough + + case DOWN: + pos(0, left, depth, top); + pos(1, left, depth, bottom); + pos(2, right, depth, bottom); + pos(3, right, depth, top); + break; + + case EAST: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + // Fallthrough + + case WEST: + pos(0, depth, top, left); + pos(1, depth, bottom, left); + pos(2, depth, bottom, right); + pos(3, depth, top, right); + break; + + case SOUTH: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + // Fallthrough + + case NORTH: + pos(0, 1 - left, top, depth); + pos(1, 1 - left, bottom, depth); + pos(2, 1 - right, bottom, depth); + pos(3, 1 - right, top, depth); + break; + } + + return this; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java new file mode 100644 index 00000000000..224930a8409 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/QuadView.java @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.client.model.quad; + +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraftforge.client.model.QuadTransformers; + +import lombok.Getter; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; +import org.joml.Vector2f; +import org.joml.Vector3f; + +import static com.gregtechceu.gtceu.client.model.quad.EncodingFormat.*; + +/** + * Interface for reading quad data encoded by {@link MeshBuilder}. + * Enables models to do analysis, re-texturing or translation + * without knowing the renderer's vertex formats and without retaining redundant information. + * + * @implNote Base class for all quads / quad makers. Handles the ugly bits of maintaining and encoding the quad state. + */ +@Accessors(fluent = true, chain = true) +public class QuadView { + + /** + * See {@link MutableQuadView#nominalFace(Direction)}. + */ + @Getter + protected @Nullable Direction nominalFace; + /** True when geometry flags or light face may not match geometry. */ + protected boolean isGeometryInvalid = true; + protected final Vector3f faceNormal = new Vector3f(); + /** + * Equivalent to {@link BakedQuad#isShade()}. If false, quad should not have shadows cast on it. + * + * @see MutableQuadView#shade(boolean) + */ + @Getter + protected boolean shade = true; + /** + * Equivalent to {@link BakedQuad#hasAmbientOcclusion()}. If false, quad should not have AO. + * + * @see MutableQuadView#ambientOcclusion(boolean) + */ + @Getter + protected boolean ambientOcclusion = true; + /** + * The quad color index serialized with the quad. + */ + @Getter + protected int tintIndex; + + protected long headerFlags = 0; + /** + * Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. + * + * -- GETTER -- + * Reference to underlying array. Use with caution. Meant for fast renderer access + */ + @Getter + protected int @UnknownNullability [] data; + + /** Beginning of the quad. Also the header index. */ + protected int baseIndex = 0; + + /** + * Use when subtype is "attached" to a pre-existing array. Sets data reference and index and decodes state from + * array. + */ + final void load(int[] data, int baseIndex) { + this.data = data; + this.baseIndex = baseIndex; + load(); + } + + /** + * Like {@link #load(int[], int)} but assumes array and index already set. Only does the decoding part. + */ + public final void load() { + isGeometryInvalid = false; + nominalFace = lightFace(); + + // face normal isn't encoded + GeometryHelper.computeFaceNormal(faceNormal, this); + } + + public int normalFlags() { + return EncodingFormat.normalFlags(headerFlags); + } + + /** True if any vertex normal has been set. */ + public boolean hasVertexNormals() { + return normalFlags() != 0; + } + + @ApiStatus.Internal + public void computeGeometry() { + if (isGeometryInvalid) { + isGeometryInvalid = false; + + GeometryHelper.computeFaceNormal(faceNormal, this); + + // depends on face normal + headerFlags = EncodingFormat.lightFace(headerFlags, GeometryHelper.lightFace(this)); + } + } + + /** + * Equivalent to {@link BakedQuad#getDirection()}. This is the face used for vanilla lighting calculations and will + * be the block face to which the quad is most closely aligned. + * Always the same as cull face for quads that are on a block face, but never null. + */ + public final Direction lightFace() { + computeGeometry(); + return EncodingFormat.lightFace(headerFlags); + } + + /** + * If non-null, quad should not be rendered in-world if the opposite face of a neighbor block occludes it. + * + * @see MutableQuadView#cullFace(Direction) + */ + public final @Nullable Direction cullFace() { + computeGeometry(); + return EncodingFormat.cullFace(headerFlags); + } + + /** + * Normal of the quad as implied by geometry. Will be invalid if quad vertices are not co-planar. Typically computed + * lazily on demand and not encoded. + * + *

+ * Not typically needed by models. Exposed to enable standard lighting utility functions for use by renderers. + */ + public final Vector3f faceNormal() { + computeGeometry(); + return faceNormal; + } + + /** + * Extracts all quad properties except material to the given {@link MutableQuadView} instance. Must be used before + * calling {link QuadEmitter#emit()} on the target instance. Meant for re-texturing, analysis and static + * transformation use cases. + */ + @Contract(mutates = "param") + public void copyTo(MutableQuadView quad) { + computeGeometry(); + + // copy everything except the material + System.arraycopy(data, baseIndex, quad.data, quad.baseIndex, QUAD_STRIDE); + quad.faceNormal.set(faceNormal.x(), faceNormal.y(), faceNormal.z()); + quad.nominalFace = this.nominalFace; + quad.isGeometryInvalid = false; + quad.shade(this.shade); + quad.headerFlags = this.headerFlags; + } + + /** + * Returns the specified vertex's geometric position. + * + *

+ * Pass a non-null target to avoid allocation - will be returned with values. Otherwise, returns a new instance. + */ + @Contract(value = "_, !null -> param2; _, null -> new", mutates = "param2") + public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) { + if (target == null) { + target = new Vector3f(); + } + + final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; + target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]), + Float.intBitsToFloat(data[index + 2])); + return target; + } + + /** + * Returns the specified vertex's geometric position. + */ + @Contract(value = "_ -> new", pure = true) + public Vector3f copyPos(int vertexIndex) { + return copyPos(vertexIndex, null); + } + + /** + * Returns the specified vertex's normal vector. + * + *

+ * Pass a non-null target to avoid allocation - will be returned with values. Otherwise, returns a new instance. + * + *

+ * Returns null if normal not present. + */ + @Contract(value = "_, !null -> param2; _, null -> new", mutates = "param2") + public @Nullable Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target) { + if (hasNormal(vertexIndex)) { + if (target == null) { + target = new Vector3f(); + } + + final int normal = data[normalIndex(vertexIndex)]; + target.set(GeometryHelper.getPackedNormalComponent(normal, 0), + GeometryHelper.getPackedNormalComponent(normal, 1), + GeometryHelper.getPackedNormalComponent(normal, 2)); + return target; + } else { + return null; + } + } + + /** + * Returns the specified vertex's normal vector. + * + *

+ * Returns null if normal not present. + */ + @Contract(value = "_ -> new", pure = true) + public @Nullable Vector3f copyNormal(int vertexIndex) { + return copyNormal(vertexIndex, null); + } + + /** + * Returns the specified vertex's UV coordinates. + * + *

+ * Pass a non-null target to avoid allocation - will be returned with values. Otherwise, returns a new instance. + */ + @Contract(value = "_, !null -> param2; _, null -> new", mutates = "param2") + public Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) { + if (target == null) { + target = new Vector2f(); + } + + target.set(u(vertexIndex), v(vertexIndex)); + return target; + } + + /** + * Returns the specified vertex's UV coordinates. + */ + @Contract(value = "_ -> new", pure = true) + public Vector2f copyUv(int vertexIndex) { + return copyUv(vertexIndex, null); + } + + /** + * Retrieve geometric position, x coordinate. + */ + public float x(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X]); + } + + /** + * Retrieve geometric position, y coordinate. + */ + public float y(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y]); + } + + /** + * Retrieve geometric position, z coordinate. + */ + public float z(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z]); + } + + /** + * Retrieve vertex color. + */ + public int color(int vertexIndex) { + return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR]; + } + + /** + * Convenience: access x, y, z by index 0-2. + */ + public float posByIndex(int vertexIndex, int coordinateIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X + coordinateIndex]); + } + + /** + * If false, no vertex normal was provided. Lighting should use face normal in that case. + */ + public boolean hasNormal(int vertexIndex) { + return (normalFlags() & (1 << vertexIndex)) != 0; + } + + protected final int normalIndex(int vertexIndex) { + return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL; + } + + /** + * Will return {@link Float#NaN} if normal not present. + */ + public float normalX(int vertexIndex) { + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 0) : + Float.NaN; + } + + /** + * Will return {@link Float#NaN} if normal not present. + */ + public float normalY(int vertexIndex) { + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 1) : + Float.NaN; + } + + /** + * Will return {@link Float#NaN} if normal not present. + */ + public float normalZ(int vertexIndex) { + return hasNormal(vertexIndex) ? GeometryHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 2) : + Float.NaN; + } + + /** + * Minimum block brightness. Zero if not set. + */ + public int lightmap(int vertexIndex) { + return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP]; + } + + /** + * Retrieve horizontal texture coordinates. + */ + public float u(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U]); + } + + /** + * Retrieve vertical texture coordinates. + */ + public float v(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_V]); + } + + /** + * Reads baked vertex data and outputs standard {@link BakedQuad#getVertices() baked quad vertex data} in the given + * array and location. + * + * @param target Target array for the baked quad data. + * + * @param targetIndex Starting position in target array - array must have at least 28 elements available at this + * index. + */ + public final void toVanilla(int[] target, int targetIndex) { + System.arraycopy(data, baseIndex, target, targetIndex, QUAD_STRIDE); + + int colorIndex = EncodingFormat.VERTEX_COLOR; + for (int i = 0; i < 4; i++) { + target[colorIndex] = QuadTransformers.toABGR(target[colorIndex]); + colorIndex += VERTEX_STRIDE; + } + } + + /** + * Generates a new BakedQuad instance with texture coordinates and colors from the given sprite. + * + * @param sprite {@link MutableQuadView} does not serialize sprites so the sprite must be provided by the caller. + * + * @return A new baked quad instance with the closest-available appearance supported by vanilla features. Will + * retain emissive light maps, for example, but the standard Minecraft renderer will not use them. + */ + public BakedQuad toBakedQuad(TextureAtlasSprite sprite) { + int[] vertexData = new int[QUAD_STRIDE]; + toVanilla(vertexData, 0); + return new BakedQuad(vertexData, tintIndex(), lightFace(), sprite, shade()); + } + + @SuppressWarnings("deprecation") + public BakedQuad toBlockBakedQuad() { + var finder = SpriteFinder.get(Minecraft.getInstance().getModelManager() + .getAtlas(TextureAtlas.LOCATION_BLOCKS)); + return toBakedQuad(finder.find(this)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java new file mode 100644 index 00000000000..b77c1b59d64 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/SpriteFinder.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.client.model.quad; + +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; + +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.function.Consumer; + +/** + * Indexes a texture atlas to allow fast lookup of Sprites from baked vertex coordinates. + * Main use is for {@link Mesh}-based models to generate vanilla quads on demand + * without tracking and retaining the sprites that were baked into the mesh. + * In other words, this class supplies the sprite parameter for + * {@link QuadView#toBakedQuad(TextureAtlasSprite)}. + * + * @implNote Implementation is a straightforward quad tree. + * Other options that were considered were linear search (slow) and direct indexing of fixed-size cells. + * Direct indexing would be fastest but would be memory-intensive for large atlases + * and unsuitable for any atlas that isn't consistently aligned to a fixed cell size. + */ +public class SpriteFinder { + + /** + * Retrieves or creates the finder for the given atlas. Instances should not be retained as fields or they must be + * refreshed whenever there is a resource reload or other event that causes atlas textures to be re-stitched. + */ + public static SpriteFinder get(TextureAtlas atlas) { + return ((SpriteFinderAccess) atlas).gtceu$spriteFinder(); + } + + private final Node root; + private final TextureAtlas textureAtlas; + + public SpriteFinder(Map sprites, TextureAtlas textureAtlas) { + root = new Node(0.5f, 0.5f, 0.25f); + this.textureAtlas = textureAtlas; + sprites.values().forEach(root::add); + } + + /** + * Finds the atlas sprite containing the vertex centroid of the quad. Vertex centroid is essentially the mean u,v + * coordinate - the intent being to find a point that is unambiguously inside the sprite (vs on an edge.) + * + *

+ * Should be reliable for any convex quad or triangle. May fail for non-convex quads. Note that all the above refers + * to u,v coordinates. Geometric vertex does not matter, except to the extent it was used to determine u,v. + */ + public TextureAtlasSprite find(QuadView quad) { + float u = 0; + float v = 0; + + for (int i = 0; i < 4; i++) { + u += quad.u(i); + v += quad.v(i); + } + + return find(u * 0.25f, v * 0.25f); + } + + /** + * Alternative to {@link #find(QuadView)} when vertex centroid is already known or unsuitable. + * Expects normalized (0-1) coordinates on the atlas texture, which should already be the case for u,v values + * in vanilla baked quads and in {@link QuadView} after calling + * {@link MutableQuadView#spriteBake(TextureAtlasSprite, int)}. + * + *

+ * Coordinates must be in the sprite interior for reliable results. + * Generally it'll be easier to use {@link #find(QuadView)} unless you know + * the vertex centroid will somehow not be in the quad interior. + * This method will be slightly faster if you already have the centroid or another appropriate value. + */ + public TextureAtlasSprite find(float u, float v) { + return root.find(u, v); + } + + private class Node { + + private final float midU; + private final float midV; + private final float cellRadius; + + private @Nullable Object lowLow = null; + private @Nullable Object lowHigh = null; + private @Nullable Object highLow = null; + private @Nullable Object highHigh = null; + + Node(float midU, float midV, float radius) { + this.midU = midU; + this.midV = midV; + cellRadius = radius; + } + + static final float EPS = Mth.EPSILON; + + void add(TextureAtlasSprite sprite) { + final boolean lowU = sprite.getU0() < midU - EPS; + final boolean highU = sprite.getU1() > midU + EPS; + final boolean lowV = sprite.getV0() < midV - EPS; + final boolean highV = sprite.getV1() > midV + EPS; + + if (lowU && lowV) { + addInner(sprite, lowLow, -1, -1, q -> lowLow = q); + } + + if (lowU && highV) { + addInner(sprite, lowHigh, -1, 1, q -> lowHigh = q); + } + + if (highU && lowV) { + addInner(sprite, highLow, 1, -1, q -> highLow = q); + } + + if (highU && highV) { + addInner(sprite, highHigh, 1, 1, q -> highHigh = q); + } + } + + private void addInner(TextureAtlasSprite sprite, @Nullable Object quadrant, int uStep, int vStep, + Consumer setter) { + if (quadrant == null) { + setter.accept(sprite); + } else if (quadrant instanceof Node node) { + node.add(sprite); + } else { + Node n = new Node(midU + cellRadius * uStep, midV + cellRadius * vStep, cellRadius * 0.5f); + + if (quadrant instanceof TextureAtlasSprite quadrantSprite) { + n.add(quadrantSprite); + } + + n.add(sprite); + setter.accept(n); + } + } + + private TextureAtlasSprite find(float u, float v) { + if (u < midU) { + return v < midV ? findInner(lowLow, u, v) : findInner(lowHigh, u, v); + } else { + return v < midV ? findInner(highLow, u, v) : findInner(highHigh, u, v); + } + } + + private TextureAtlasSprite findInner(@Nullable Object quadrant, float u, float v) { + if (quadrant instanceof TextureAtlasSprite sprite) { + return sprite; + } else if (quadrant instanceof Node node) { + return node.find(u, v); + } else { + return textureAtlas.getSprite(MissingTextureAtlasSprite.getLocation()); + } + } + } + + public interface SpriteFinderAccess { + + SpriteFinder gtceu$spriteFinder(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/StaticFaceBakery.java similarity index 95% rename from src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java rename to src/main/java/com/gregtechceu/gtceu/client/model/quad/StaticFaceBakery.java index 7b963ba6b52..8b3c0203236 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/StaticFaceBakery.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util; +package com.gregtechceu.gtceu.client.model.quad; import net.minecraft.client.renderer.FaceInfo; import net.minecraft.client.renderer.block.model.*; @@ -73,8 +73,8 @@ public static BakedQuad bakeFace(Direction face, TextureAtlasSprite sprite, Mode return bakeFace(BLOCK, face, sprite, rotation, tintIndex, emissivity, cull, shade); } - public static BakedQuad bakeFace(Direction face, TextureAtlasSprite sprite, ModelState rotation, int tintIndex, - int emissivity) { + public static BakedQuad bakeFace(Direction face, TextureAtlasSprite sprite, ModelState rotation, + int tintIndex, int emissivity) { return bakeFace(face, sprite, rotation, tintIndex, emissivity, true, true); } @@ -94,15 +94,10 @@ public static BakedQuad bakeFace(AABB cube, Direction face, TextureAtlasSprite s return bakeFace(cube, face, sprite, BlockModelRotation.X0_Y0, -1, 0, true, true); } - public static BakedQuad bakeQuad(Vector3f posFrom, - Vector3f posTo, - BlockElementFace face, - TextureAtlasSprite sprite, - Direction facing, - ModelState transform, - @Nullable BlockElementRotation partRotation, - boolean shade, - int emissivity) { + public static BakedQuad bakeQuad(Vector3f posFrom, Vector3f posTo, + BlockElementFace face, TextureAtlasSprite sprite, Direction facing, + ModelState transform, @Nullable BlockElementRotation partRotation, + boolean shade, int emissivity) { BlockFaceUV uvs = face.uv; if (transform.isUvLocked()) { uvs = recomputeUVs(face.uv, facing, transform.getRotation()); diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/package-info.java new file mode 100644 index 00000000000..04eef27d2b2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.model.quad; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java b/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java new file mode 100644 index 00000000000..b604160adf5 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/model/quad/transform/QuadTransform.java @@ -0,0 +1,23 @@ +package com.gregtechceu.gtceu.client.model.quad.transform; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraftforge.client.model.IQuadTransformer; + +@FunctionalInterface +public interface QuadTransform extends IQuadTransformer { + + /** + * Return false to filter out quads from rendering. When more than one transform is in effect, returning false + * means unapplied transforms will not receive the quad. + */ + boolean transform(MutableQuadView quad); + + @Override + default void processInPlace(BakedQuad quad) { + MutableQuadView quadView = MutableQuadView.getInstance().fromVanilla(quad.getVertices(), 0); + this.transform(quadView); + quadView.toVanilla(quad.getVertices(), 0); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java new file mode 100644 index 00000000000..b3e77131720 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -0,0 +1,289 @@ +package com.gregtechceu.gtceu.client.particle; + +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.client.bloom.EffectRenderContext; +import com.gregtechceu.gtceu.client.bloom.IRenderSetup; +import com.gregtechceu.gtceu.client.bloom.particle.GTBloomParticle; +import com.gregtechceu.gtceu.client.util.RenderBufferHelper; +import com.gregtechceu.gtceu.client.util.RenderUtil; +import com.gregtechceu.gtceu.common.blockentity.CableBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author brachy84 + */ +public class GTOverheatParticle extends GTBloomParticle { + + public static final int TEMPERATURE_CUTOFF = 400; + + /** + * Source + */ + private static final int[] blackBodyColors = { + 0xFF3300, // 1000 K + 0xFF5300, // 1200 K + 0xFF6500, // 1400 K + 0xFF7300, // 1600 K + 0xFF7E00, // 1800 K + 0xFF8912, // 2000 K + 0xFF932C, // 2200 K + 0xFF9D3F, // 2400 K + 0xffa54f, // 2600 K + 0xffad5e, // 2800 K + 0xffb46b, // 3000 K + 0xffbb78, // 3200 K + 0xffc184, // 3400 K + 0xffc78f, // 3600 K + 0xffcc99, // 3800 K + 0xffd1a3, // 4000 K + 0xffd5ad, // 4200 K + 0xffd9b6, // 4400 K + 0xffddbe, // 4600 K + 0xffe1c6, // 4800 K + 0xffe4ce, // 5000 K + 0xffe8d5, // 5200 K + 0xffebdc, // 5400 K + 0xffeee3, // 5600 K + 0xfff0e9, // 5800 K + 0xfff3ef, // 6000 K + 0xfff5f5, // 6200 K + 0xfff8fb, // 6400 K + 0xfef9ff, // 6600 K + 0xf9f6ff, // 6800 K + 0xf5f3ff, // 7000 K + 0xf0f1ff, // 7200 K + 0xedefff, // 7400 K + 0xe9edff, // 7600 K + 0xe6ebff, // 7800 K + 0xe3e9ff, // 8000 K + 0xe0e7ff, // 8200 K + 0xdde6ff, // 8400 K + 0xdae4ff, // 8600 K + 0xd8e3ff, // 8800 K + 0xd6e1ff, // 9000 K + 0xd3e0ff, // 9200 K + 0xd1dfff, // 9400 K + 0xcfddff, // 9600 K + 0xcedcff, // 9800 K + 0xccdbff, // 10000 K + 0xcadaff, // 10200 K + 0xc9d9ff, // 10400 K + 0xc7d8ff, // 10600 K + 0xc6d8ff, // 10800 K + 0xc4d7ff, // 11000 K + 0xc3d6ff, // 11200 K + 0xc2d5ff, // 11400 K + 0xc1d4ff, // 11600 K + 0xc0d4ff, // 11800 K + 0xbfd3ff, // 12000 K + 0xbed2ff, // 12200 K + 0xbdd2ff, // 12400 K + 0xbcd1ff, // 12600 K + 0xbbd1ff, // 12800 K + 0xbad0ff, // 13000 K + 0xb9d0ff, // 13200 K + 0xb8cfff, // 13400 K + 0xb7cfff, // 13600 K + 0xb7ceff, // 13800 K + 0xb6ceff, // 14000 K + 0xb5cdff, // 14200 K + 0xb5cdff, // 14400 K + 0xb4ccff, // 14600 K + 0xb3ccff, // 14800 K + 0xb3ccff, // 15000 K + 0xb2cbff, // 15200 K + 0xb2cbff, // 15400 K + 0xb1caff, // 15600 K + 0xb1caff, // 15800 K + 0xb0caff, // 16000 K + 0xafc9ff, // 16200 K + 0xafc9ff, // 16400 K + 0xafc9ff, // 16600 K + 0xaec9ff, // 16800 K + 0xaec8ff, // 17000 K + 0xadc8ff, // 17200 K + 0xadc8ff, // 17400 K + 0xacc7ff, // 17600 K + 0xacc7ff, // 17800 K + 0xacc7ff, // 18000 K + 0xabc7ff, // 18200 K + 0xabc6ff, // 18400 K + 0xaac6ff, // 18600 K + 0xaac6ff, // 18800 K + 0xaac6ff, // 19000 K + 0xa9c6ff, // 19200 K + 0xa9c5ff, // 19400 K + 0xa9c5ff, // 19600 K + 0xa9c5ff, // 19800 K + 0xa8c5ff, // 20000 K + // color doesn't really change onwards + }; + + public static int getBlackBodyColor(int temperature) { + if (temperature < 1000) + return blackBodyColors[0]; + int index = (temperature - 1000) / 200; + if (index >= blackBodyColors.length - 1) + return blackBodyColors[blackBodyColors.length - 1]; + int color = blackBodyColors[index]; + return RenderUtil.interpolateColor(color, blackBodyColors[index + 1], temperature % 200 / 200f); + } + + private final CableBlockEntity blockEntity; + + protected final int meltTemp; + protected int temperature = 293; + protected VoxelShape pipeBoxes; + protected boolean insulated; + + protected float alpha = 0; + protected int color = blackBodyColors[0]; + + public GTOverheatParticle(CableBlockEntity blockEntity, int meltTemp, VoxelShape pipeBoxes, boolean insulated) { + super(blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ()); + this.blockEntity = blockEntity; + this.meltTemp = meltTemp; + this.pipeBoxes = pipeBoxes; + updatePipeBoxes(pipeBoxes); + this.insulated = insulated; + } + + public void setTemperature(int temperature) { + this.temperature = temperature; + if (temperature <= 293 || temperature > meltTemp) { + setExpired(); + return; + } + if (temperature < 500) { + alpha = 0f; + } else if (temperature < 1000) { + alpha = (temperature - 500f) / 500f; + alpha *= 0.8f; + } else { + alpha = 0.8f; + } + color = getBlackBodyColor(temperature); + } + + public void updatePipeBoxes(VoxelShape pipeBoxes) { + List boxes = pipeBoxes.toAabbs(); + this.pipeBoxes = boxes.stream() + .map(aabb -> aabb.inflate(0.001)) + .map(Shapes::create) + .reduce(Shapes.empty(), Shapes::or) + .optimize(); + } + + @Override + public void onUpdate() { + if (blockEntity.isRemoved() || !blockEntity.isParticleAlive()) { + setExpired(); + blockEntity.killParticle(); + return; + } + + if (temperature <= TEMPERATURE_CUTOFF || temperature > meltTemp) { + setExpired(); + return; + } + if (temperature < 500) { + alpha = 0f; + } else if (temperature < 1000) { + alpha = (temperature - 500f) / 500f; + alpha *= 0.8f; + } else { + alpha = 0.8f; + } + color = getBlackBodyColor(temperature); + + if (GTValues.RNG.nextFloat() < 0.04) { + spawnSmoke(); + } + } + + private void spawnSmoke() { + BlockPos pos = blockEntity.getBlockPos(); + float xPos = pos.getX() + 0.5F; + float yPos = pos.getY() + 0.9F; + float zPos = pos.getZ() + 0.5F; + + float ySpd = 0.3F + 0.1F * blockEntity.getLevel().random.nextFloat(); + blockEntity.getLevel().addParticle(ParticleTypes.LARGE_SMOKE, xPos, yPos, zPos, 0, ySpd, 0); + } + + @Override + public String toString() { + return "GTOverheatParticle{" + + "tileEntity=" + blockEntity + + ", pipeBoxes=" + pipeBoxes + + ", insulated=" + insulated + + ", alpha=" + alpha + + ", color=" + color + + '}'; + } + + @Override + public @Nullable IRenderSetup getRenderSetup() { + return SETUP; + } + + @Override + public boolean shouldRender(EffectRenderContext context) { + if (this.insulated) return false; + for (AABB cuboid : pipeBoxes.toAabbs()) { + if (!context.frustum().isVisible(cuboid.move(posX, posY, posZ))) { + return false; + } + } + return true; + } + + @Override + protected @Nullable IRenderSetup getBloomRenderSetup() { + return SETUP; + } + + public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectRenderContext context) { + float red = ((color >> 16) & 0xFF) / 255f; + float green = ((color >> 8) & 0xFF) / 255f; + float blue = (color & 0xFF) / 255f; + + poseStack.pushPose(); + poseStack.translate(posX, posY, posZ); + for (AABB cuboid : pipeBoxes.toAabbs()) { + RenderBufferHelper.renderColorCube(poseStack, buffer, cuboid, red, green, blue, alpha, true); + } + poseStack.popPose(); + } + + private static final IRenderSetup SETUP = new IRenderSetup() { + + @Override + @OnlyIn(Dist.CLIENT) + public void preDraw(BufferBuilder buffer) { + RenderSystem.setShaderColor(1, 1, 1, 1); + RenderSystem.enableBlend(); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void postDraw(BufferBuilder buffer) { + BufferUploader.drawWithShader(buffer.end()); + RenderSystem.disableBlend(); + } + }; +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticle.java new file mode 100644 index 00000000000..b7162675b95 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticle.java @@ -0,0 +1,115 @@ +package com.gregtechceu.gtceu.client.particle; + +import com.gregtechceu.gtceu.client.bloom.EffectRenderContext; +import com.gregtechceu.gtceu.client.bloom.IRenderSetup; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import lombok.Getter; +import org.jetbrains.annotations.Nullable; + +/** + * A custom particle implementation with framework for more advanced rendering capabilities. + *

+ * GTParticle instances are managed by {@link GTParticleManager}. GTParticle instances with same {@link IRenderSetup}s + * will be drawn together as a batch. + */ +public abstract class GTParticle { + + public double posX; + public double posY; + public double posZ; + + /** + * render range. If the distance between particle and render view entity exceeds this value, the particle + * will not be rendered. If render range is negative value or {@code NaN}, then the check is disabled and + * the + * particle will be rendered regardless of the distance. + */ + @Getter + private double renderRange = -1; + /** + * squared render range, or negative value if render distance check is disabled. + */ + @Getter + private double squaredRenderRange = -1; + + @Getter + private boolean expired; + + protected GTParticle(double posX, double posY, double posZ) { + this.posX = posX; + this.posY = posY; + this.posZ = posZ; + } + + public boolean shouldRender(EffectRenderContext context) { + if (squaredRenderRange < 0) return true; + return context.getRenderViewEntity().getEyePosition(context.partialTicks()) + .distanceToSqr(posX, posY, posZ) <= squaredRenderRange; + } + + public final boolean isAlive() { + return !expired; + } + + public final void setExpired() { + if (this.expired) return; + this.expired = true; + onExpired(); + } + + /** + * @return {@code true} to render the particle with + * {@link com.mojang.blaze3d.systems.RenderSystem#depthMask(boolean) depth mask} feature disabled; in + * other words, render the particle without modifying depth buffer. + */ + public boolean shouldDisableDepth() { + return false; + } + + /** + * Sets the render range. If the distance between particle and render view entity exceeds this value, the particle + * will not be rendered. If render range is negative value or {@code NaN}, then the check is disabled and the + * particle will be rendered regardless of the distance. + * + * @param renderRange Render range + */ + public final void setRenderRange(double renderRange) { + this.renderRange = renderRange; + if (renderRange >= 0) this.squaredRenderRange = renderRange * renderRange; + else this.squaredRenderRange = -1; + } + + /** + * Update the particle. This method is called each tick. + */ + public void onUpdate() {} + + /** + * Called once on expiration. + */ + protected void onExpired() {} + + /** + * Render the particle. If this particle has non-null {@link #getRenderSetup()} associated, this method will be + * called between a {@link IRenderSetup#preDraw(BufferBuilder)} call and a + * {@link IRenderSetup#postDraw(BufferBuilder)} call. + * + * @param poseStack pose stack + * @param buffer buffer builder + * @param context render context + */ + @OnlyIn(Dist.CLIENT) + public void renderParticle(PoseStack poseStack, BufferBuilder buffer, EffectRenderContext context) {} + + /** + * @return Render setup for this particle, if exists + */ + public @Nullable IRenderSetup getRenderSetup() { + return null; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java new file mode 100644 index 00000000000..cf2c5ae5380 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java @@ -0,0 +1,230 @@ +package com.gregtechceu.gtceu.client.particle; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.bloom.EffectRenderContext; +import com.gregtechceu.gtceu.client.bloom.IRenderSetup; + +import net.minecraft.ChatFormatting; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent; +import net.minecraftforge.client.event.CustomizeGuiOverlayEvent; +import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.event.level.LevelEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * Singleton class responsible for managing, updating and rendering {@link GTParticle} instances. + */ +@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, value = Dist.CLIENT) +public class GTParticleManager { + + public static final GTParticleManager INSTANCE = new GTParticleManager(); + + private final Map<@Nullable IRenderSetup, ArrayDeque> depthEnabledParticles = new Object2ObjectLinkedOpenHashMap<>(); + private final Map<@Nullable IRenderSetup, ArrayDeque> depthDisabledParticles = new Object2ObjectLinkedOpenHashMap<>(); + + private final List newParticleQueue = new ArrayList<>(); + + public void addEffect(GTParticle particles) { + newParticleQueue.add(particles); + } + + public void updateEffects() { + if (!this.depthEnabledParticles.isEmpty()) { + updateQueue(this.depthEnabledParticles); + } + if (!this.depthDisabledParticles.isEmpty()) { + updateQueue(this.depthDisabledParticles); + } + + if (!newParticleQueue.isEmpty()) { + for (GTParticle particle : newParticleQueue) { + var queue = particle.shouldDisableDepth() ? this.depthDisabledParticles : this.depthEnabledParticles; + + ArrayDeque particles = queue.computeIfAbsent(particle.getRenderSetup(), + setup -> new ArrayDeque<>()); + + if (particles.size() > 6000) { + particles.removeFirst().setExpired(); + } + particles.add(particle); + } + + newParticleQueue.clear(); + } + } + + private void updateQueue(Map<@Nullable IRenderSetup, ArrayDeque> renderQueue) { + Iterator> it = renderQueue.values().iterator(); + while (it.hasNext()) { + ArrayDeque particlesForSetup = it.next(); + + Iterator particles = particlesForSetup.iterator(); + while (particles.hasNext()) { + GTParticle particle = particles.next(); + + if (particle.isAlive()) { + try { + particle.onUpdate(); + } catch (RuntimeException exception) { + GTCEu.LOGGER.error("Particle update error: {}", particle, exception); + particle.setExpired(); + } + if (particle.isAlive()) continue; + } + + particles.remove(); + } + + if (particlesForSetup.isEmpty()) { + it.remove(); + } + } + } + + public void clearAllEffects(boolean cleanNewQueue) { + if (cleanNewQueue) { + for (GTParticle particle : this.newParticleQueue) { + particle.setExpired(); + } + this.newParticleQueue.clear(); + } + for (ArrayDeque particles : this.depthEnabledParticles.values()) { + for (GTParticle particle : particles) { + particle.setExpired(); + } + } + for (ArrayDeque particles : this.depthDisabledParticles.values()) { + for (GTParticle particle : particles) { + particle.setExpired(); + } + } + this.depthEnabledParticles.clear(); + this.depthDisabledParticles.clear(); + } + + public void renderParticles(PoseStack poseStack, Camera camera, Frustum frustum, float partialTicks) { + if (this.depthEnabledParticles.isEmpty() && this.depthDisabledParticles.isEmpty()) return; + + EffectRenderContext instance = EffectRenderContext.getInstance() + .update(camera, frustum, partialTicks); + + RenderSystem.enableBlend(); + RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + + if (!this.depthDisabledParticles.isEmpty()) { + RenderSystem.depthMask(false); + renderParticlesInLayer(poseStack, this.depthDisabledParticles, instance); + RenderSystem.depthMask(true); + } + renderParticlesInLayer(poseStack, this.depthEnabledParticles, instance); + + RenderSystem.disableBlend(); + } + + private static void renderParticlesInLayer(PoseStack poseStack, + Map<@Nullable IRenderSetup, ArrayDeque> renderQueue, + EffectRenderContext context) { + for (var entry : renderQueue.entrySet()) { + ArrayDeque particles = entry.getValue(); + if (particles.isEmpty()) continue; + + IRenderSetup handler = entry.getKey(); + boolean initialized = false; + + BufferBuilder buffer = Tesselator.getInstance().getBuilder(); + for (GTParticle particle : particles) { + if (!particle.shouldRender(context)) { + continue; + } + try { + if (!initialized) { + initialized = true; + if (handler != null) { + handler.preDraw(buffer); + } + } + particle.renderParticle(poseStack, buffer, context); + + } catch (Throwable throwable) { + GTCEu.LOGGER.error("Particle render error: {}", particle, throwable); + particle.setExpired(); + } + } + if (initialized && handler != null) { + handler.postDraw(buffer); + } + } + } + + @SubscribeEvent + public static void onClientLevelLoad(LevelEvent.Load event) { + if (!(event.getLevel() instanceof ClientLevel newLevel)) { + return; + } + ClientLevel oldLevel = Minecraft.getInstance().level; + if (oldLevel != newLevel) { + INSTANCE.clearAllEffects(oldLevel != null); + } + + if (oldLevel != null) { + INSTANCE.updateEffects(); + } + } + + @SubscribeEvent + public static void onClientLevelUnload(ClientPlayerNetworkEvent.LoggingOut event) { + if (event.getPlayer() != null) { + INSTANCE.clearAllEffects(true); + } + } + + @SubscribeEvent + public static void renderWorld(RenderLevelStageEvent event) { + if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_CUTOUT_BLOCKS) { + Entity entity = Minecraft.getInstance().getCameraEntity(); + if (entity == null) { + entity = Minecraft.getInstance().player; + } + if (entity != null) { + INSTANCE.renderParticles(event.getPoseStack(), event.getCamera(), event.getFrustum(), + event.getPartialTick()); + } + } + } + + @SubscribeEvent + public static void debugOverlay(CustomizeGuiOverlayEvent.DebugText event) { + if (event.getLeft().size() >= 5) { + String particleTxt = event.getLeft().get(4); + particleTxt += "." + ChatFormatting.GOLD + + " PARTICLE-BACK: " + count(INSTANCE.depthEnabledParticles) + + "PARTICLE-FRONT: " + count(INSTANCE.depthDisabledParticles); + event.getLeft().set(4, particleTxt); + } + } + + private static int count(Map<@Nullable IRenderSetup, ArrayDeque> renderQueue) { + int total = 0; + for (Deque queue : renderQueue.values()) { + total += queue.size(); + } + return total; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/particle/package-info.java new file mode 100644 index 00000000000..4f3e9248862 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.particle; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighlightRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighlightRenderer.java index d0a7a3849ec..b48b4d541c4 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighlightRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighlightRenderer.java @@ -10,7 +10,6 @@ import com.gregtechceu.gtceu.api.item.tool.ToolHelper; import com.gregtechceu.gtceu.api.pattern.util.RelativeDirection; import com.gregtechceu.gtceu.api.pipenet.IPipeType; -import com.gregtechceu.gtceu.client.util.PoseStackExtensions; import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.item.behavior.CoverPlaceBehavior; import com.gregtechceu.gtceu.common.item.tool.rotation.CustomBlockRotations; @@ -36,7 +35,6 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; -import lombok.experimental.ExtensionMethod; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionfc; import org.joml.Vector3f; @@ -48,7 +46,6 @@ import static com.gregtechceu.gtceu.utils.GTMatrixUtils.*; @OnlyIn(Dist.CLIENT) -@ExtensionMethod(PoseStackExtensions.class) public class BlockHighlightRenderer { public static void renderBlockHighlight(PoseStack poseStack, Camera camera, BlockHitResult target, diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java index ce3fea89a5d..d71227d9f0a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java @@ -1,8 +1,12 @@ package com.gregtechceu.gtceu.client.renderer; +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; + import net.minecraft.Util; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -15,20 +19,58 @@ @OnlyIn(Dist.CLIENT) public class GTRenderTypes extends RenderType { - private static final RenderType LIGHT_RING = RenderType.create("light_ring", - DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_STRIP, 256, false, false, + public static final RenderStateShard.OutputStateShard BLOOM_TARGET = new RenderStateShard.OutputStateShard( + "bloom_target", + () -> { + if (BloomShaderManager.isBloomActive()) { + BloomShaderManager.BLOOM_TARGET.bindWrite(false); + } + }, + () -> { + if (BloomShaderManager.isBloomActive()) { + Minecraft.getInstance().getMainRenderTarget().bindWrite(false); + } + }); + protected static final RenderStateShard.ShaderStateShard RENDERTYPE_BLOOM_SHADER = new RenderStateShard.ShaderStateShard( + BloomShaderManager::getRendertypeBloomShader); + protected static final RenderStateShard.ShaderStateShard RENDERTYPE_ENTITY_BLOOM_SHADER = new RenderStateShard.ShaderStateShard( + BloomShaderManager::getRendertypeEntityBloomShader); + + private static final RenderType LIGHT_RING = RenderType.create("light_ring", DefaultVertexFormat.POSITION_COLOR, + VertexFormat.Mode.TRIANGLE_STRIP, RenderType.SMALL_BUFFER_SIZE, false, false, RenderType.CompositeState.builder() .setCullState(NO_CULL) - .setShaderState(RenderStateShard.POSITION_COLOR_SHADER) - .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setShaderState(POSITION_COLOR_SHADER) .createCompositeState(false)); + + private static final RenderType BLOOM = RenderType.create("gtceu:bloom", DefaultVertexFormat.BLOCK, + VertexFormat.Mode.QUADS, RenderType.BIG_BUFFER_SIZE, true, false, + RenderType.CompositeState.builder() + .setShaderState(RENDERTYPE_BLOOM_SHADER) + .setOutputState(BLOOM_TARGET) + .setLightmapState(LIGHTMAP) + .setTextureState(BLOCK_SHEET_MIPPED) + .createCompositeState(true)); + private static final Function ENTITY_BLOOM = Util.memoize((texture) -> { + return create("gtceu:entity_bloom", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, + RenderType.TRANSIENT_BUFFER_SIZE, true, false, + RenderType.CompositeState.builder() + .setShaderState(RENDERTYPE_ENTITY_BLOOM_SHADER) + .setOutputState(BLOOM_TARGET) + .setLightmapState(LIGHTMAP) + .setOverlayState(OVERLAY) + .setTextureState(new RenderStateShard.TextureStateShard(texture, false, false)) + .createCompositeState(true)); + }); + private static final RenderType MONITOR = RenderType.create("central_monitor", - DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, 256, false, false, + DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE, false, false, RenderType.CompositeState.builder() .setCullState(NO_CULL) .setShaderState(POSITION_COLOR_SHADER) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .createCompositeState(false)); + private static final Function GUI_TEXTURE = Util.memoize((texture) -> { return create("gui_texture", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, VertexFormat.Mode.QUADS, RenderType.TRANSIENT_BUFFER_SIZE, false, true, @@ -45,10 +87,23 @@ private GTRenderTypes(String name, VertexFormat format, VertexFormat.Mode mode, super(name, format, mode, bufferSize, affectsCrumbling, sortOnUpload, setupState, clearState); } - public static RenderType getLightRing() { + public static RenderType lightRing() { return LIGHT_RING; } + public static RenderType bloom() { + return BLOOM; + } + + public static RenderType entityBloom(ResourceLocation location) { + return ENTITY_BLOOM.apply(location); + } + + @SuppressWarnings("deprecation") + public static RenderType entityBloomBlockSheet() { + return entityBloom(TextureAtlas.LOCATION_BLOCKS); + } + public static RenderType getMonitor() { return MONITOR; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/FluidBlockRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/FluidBlockRenderer.java index e8a9e820e37..c5a378d2518 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/FluidBlockRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/FluidBlockRenderer.java @@ -1,28 +1,30 @@ package com.gregtechceu.gtceu.client.renderer.block; import com.gregtechceu.gtceu.client.util.RenderUtil; +import com.gregtechceu.gtceu.utils.GTUtil; import net.minecraft.client.renderer.LightTexture; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.lighting.LightEngine; import net.minecraft.world.level.material.Fluid; import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; +import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import lombok.Data; import lombok.Getter; -import org.joml.Matrix4f; +import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.joml.Vector3fc; import java.util.*; import static com.gregtechceu.gtceu.client.util.RenderUtil.*; -import static net.minecraft.util.FastColor.ARGB32.*; public class FluidBlockRenderer { @@ -45,128 +47,109 @@ public Vector3f[] transformVertices(Vector3fc[] vertices, Direction face) { case Z -> offsetZ += properties.offsetFace; } - var newVertices = new Vector3f[4]; - for (int i = 0; i < 4; i++) { + var newVertices = new Vector3f[vertices.length]; + for (int i = 0; i < vertices.length; i++) { newVertices[i] = RenderUtil.transformVertex(vertices[i], face, offsetX, offsetY, offsetZ); } return newVertices; } - public void drawBlocks(Set offsets, Matrix4f pose, VertexConsumer consumer, - Fluid fluid, - RenderUtil.FluidTextureType texture, int combinedOverlay, int combinedLight) { + public void drawBlocks(Set offsets, PoseStack poseStack, VertexConsumer consumer, + Fluid fluid, RenderUtil.FluidTextureType texture, + int combinedOverlay, int combinedLight) { var fluidClientInfo = IClientFluidTypeExtensions.of(fluid); var sprite = texture.map(fluidClientInfo); float u0 = sprite.getU0(), v0 = sprite.getV0(), u1 = sprite.getU1(), v1 = sprite.getV1(); int color = fluidClientInfo.getTintColor(); - int r = red(color), g = green(color), b = blue(color), a = alpha(color); for (var pos : offsets) { - pose.translate(pos.getX(), pos.getY(), pos.getZ()); - for (var direction : Direction.values()) { + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + + for (var direction : GTUtil.DIRECTIONS) { if (offsets.contains(pos.relative(direction))) continue; - if (direction != Direction.UP && direction != Direction.DOWN) direction = direction.getOpposite(); - drawFace(pose, consumer, - transformVertices(getVertices(direction), direction), - getNormal(direction), - u0, u1, v0, v1, - r, g, b, a, - combinedOverlay, combinedLight); + if (direction.getAxis() != Direction.Axis.Y) direction = direction.getOpposite(); + + drawFace(poseStack.last(), consumer, + transformVertices(getVertices(direction), direction), getNormal(direction), + u0, u1, v0, v1, color, combinedOverlay, combinedLight); } - pose.translate(-pos.getX(), -pos.getY(), -pos.getZ()); + poseStack.popPose(); } } - public void drawPlanes(Direction[] faces, Map> directionalOffsets, Matrix4f pose, - VertexConsumer consumer, Fluid fluid, RenderUtil.FluidTextureType texture, - int combinedOverlay, int combinedLight) { - for (var face : faces) { + public void drawPlanes(Direction[] faces, Map> directionalOffsets, + PoseStack poseStack, VertexConsumer consumer, Fluid fluid, + RenderUtil.FluidTextureType texture, int combinedOverlay, int combinedLight) { + for (Direction face : faces) { if (!directionalOffsets.containsKey(face)) continue; - drawPlane(face, directionalOffsets.get(face), pose, consumer, fluid, texture, combinedOverlay, - combinedLight); + + drawPlane(face, directionalOffsets.get(face), poseStack, consumer, + fluid, texture, combinedOverlay, combinedLight); } } - public void drawPlane(Direction face, Collection offsets, Matrix4f pose, VertexConsumer consumer, - Fluid fluid, RenderUtil.FluidTextureType texture, int combinedOverlay, BlockPos origin) { + public void drawPlane(Direction face, Collection offsets, + PoseStack poseStack, VertexConsumer consumer, + Fluid fluid, RenderUtil.FluidTextureType texture, + int combinedOverlay, BlockPos origin, @Nullable BlockAndTintGetter level) { var fluidClientInfo = IClientFluidTypeExtensions.of(fluid); var sprite = texture.map(fluidClientInfo); float u0 = sprite.getU0(), v0 = sprite.getV0(), u1 = sprite.getU1(), v1 = sprite.getV1(); int color = fluidClientInfo.getTintColor(); - int r = red(color), g = green(color), b = blue(color), a = alpha(color); - var normal = getNormal(face); - var vertices = transformVertices(getVertices(face), face); + Vector3fc normal = getNormal(face); + Vector3f[] vertices = transformVertices(getVertices(face), face); - BlockPos prevOffset = null; - for (var offset : offsets) { - BlockPos currOffset = prevOffset == null ? offset : offset.subtract(prevOffset); - pose.translate(currOffset.getX(), currOffset.getY(), currOffset.getZ()); - drawFace(pose, consumer, vertices, normal, u0, u1, v0, v1, r, g, b, a, combinedOverlay, - RenderUtil.getFluidLight(fluid, origin.offset(currOffset))); - prevOffset = offset; + for (BlockPos offset : offsets) { + poseStack.pushPose(); + poseStack.translate(offset.getX(), offset.getY(), offset.getZ()); + drawFace(poseStack.last(), consumer, vertices, normal, + u0, u1, v0, v1, color, + combinedOverlay, RenderUtil.getFluidLight(fluid, origin.offset(offset), level)); + poseStack.popPose(); } } - public void drawPlane(Direction face, Collection offsets, Matrix4f pose, VertexConsumer consumer, + public void drawPlane(Direction face, Collection offsets, PoseStack poseStack, VertexConsumer consumer, Fluid fluid, RenderUtil.FluidTextureType texture, int combinedOverlay, int combinedLight) { var fluidClientInfo = IClientFluidTypeExtensions.of(fluid); var sprite = texture.map(fluidClientInfo); float u0 = sprite.getU0(), v0 = sprite.getV0(), u1 = sprite.getU1(), v1 = sprite.getV1(); int color = fluidClientInfo.getTintColor(); - int r = red(color), g = green(color), b = blue(color), a = alpha(color); - var normal = getNormal(face); - var vertices = transformVertices(getVertices(face), face); + Vector3fc normal = getNormal(face); + Vector3f[] vertices = transformVertices(getVertices(face), face); - BlockPos prevOffset = null; for (var offset : offsets) { - BlockPos currOffset = prevOffset == null ? offset : offset.subtract(prevOffset); - pose.translate(currOffset.getX(), currOffset.getY(), currOffset.getZ()); - drawFace(pose, consumer, vertices, normal, u0, u1, v0, v1, r, g, b, a, combinedOverlay, combinedLight); - prevOffset = offset; + poseStack.pushPose(); + poseStack.translate(offset.getX(), offset.getY(), offset.getZ()); + drawFace(poseStack.last(), consumer, vertices, normal, + u0, u1, v0, v1, color, combinedOverlay, combinedLight); + poseStack.popPose(); } } - public void drawFace(Direction face, Matrix4f pose, VertexConsumer consumer, Fluid fluid, - RenderUtil.FluidTextureType texture, int combinedOverlay, int combinedLight) { + public void drawFace(Direction face, PoseStack.Pose pose, VertexConsumer consumer, + Fluid fluid, RenderUtil.FluidTextureType texture, + int combinedOverlay, int combinedLight) { var fluidClientInfo = IClientFluidTypeExtensions.of(fluid); var sprite = texture.map(fluidClientInfo); float u0 = sprite.getU0(), v0 = sprite.getV0(), u1 = sprite.getU1(), v1 = sprite.getV1(); int color = fluidClientInfo.getTintColor(); - int r = red(color), g = green(color), b = blue(color), a = alpha(color); - var normal = getNormal(face); - var vertices = transformVertices(getVertices(face), face); - drawFace(pose, consumer, vertices, normal, u0, u1, v0, v1, r, g, b, a, combinedOverlay, combinedLight); + Vector3fc normal = getNormal(face); + Vector3f[] vertices = transformVertices(getVertices(face), face); + + drawFace(pose, consumer, vertices, normal, u0, u1, v0, v1, color, combinedOverlay, combinedLight); } - public void drawFace(Matrix4f pose, VertexConsumer consumer, Vector3f[] vertices, Vector3fc normal, + public void drawFace(PoseStack.Pose pose, VertexConsumer consumer, Vector3f[] vertices, Vector3fc normal, float u0, float u1, float v0, float v1, - int r, int g, int b, int a, - int combinedOverlay, int combinedLight) { + int argb, int combinedOverlay, int combinedLight) { if (properties.isOverwriteLight()) combinedLight = properties.getLight(); - var vert = vertices[0]; - RenderUtil.vertex(pose, consumer, vert.x, vert.y, vert.z, - r, g, b, a, - u0, v1, - combinedOverlay, combinedLight, normal.x(), normal.y(), normal.z()); - - vert = vertices[1]; - RenderUtil.vertex(pose, consumer, vert.x, vert.y, vert.z, - r, g, b, a, - u0, v0, - combinedOverlay, combinedLight, normal.x(), normal.y(), normal.z()); - - vert = vertices[2]; - RenderUtil.vertex(pose, consumer, vert.x, vert.y, vert.z, - r, g, b, a, - u1, v0, - combinedOverlay, combinedLight, normal.x(), normal.y(), normal.z()); - - vert = vertices[3]; - RenderUtil.vertex(pose, consumer, vert.x, vert.y, vert.z, - r, g, b, a, - u1, v1, - combinedOverlay, combinedLight, normal.x(), normal.y(), normal.z()); + RenderUtil.vertex(pose, consumer, vertices[0], normal, u0, v1, argb, combinedOverlay, combinedLight); + RenderUtil.vertex(pose, consumer, vertices[1], normal, u0, v0, argb, combinedOverlay, combinedLight); + RenderUtil.vertex(pose, consumer, vertices[2], normal, u1, v0, argb, combinedOverlay, combinedLight); + RenderUtil.vertex(pose, consumer, vertices[3], normal, u1, v1, argb, combinedOverlay, combinedLight); } @Data diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java index 2d88b38e102..799fb61a06f 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/FacadeCoverRenderer.java @@ -3,9 +3,9 @@ import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.client.model.BaseBakedModel; import com.gregtechceu.gtceu.client.model.GTModelProperties; -import com.gregtechceu.gtceu.client.util.GTQuadTransformers; -import com.gregtechceu.gtceu.client.util.ModelUtils; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.RenderUtil; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; import com.gregtechceu.gtceu.common.cover.FacadeCover; import com.gregtechceu.gtceu.common.item.behavior.FacadeItemBehaviour; import com.gregtechceu.gtceu.utils.GTUtil; @@ -127,7 +127,7 @@ public void renderCover(List quads, @Nullable Direction side, RandomS return; } - BakedModel facadeModel = ModelUtils.getModelForState(facadeState); + BakedModel facadeModel = RenderUtil.getModelForState(facadeState); if (facadeModel.isCustomRenderer()) { return; } @@ -187,7 +187,7 @@ public ModelData getModelData(CoverBehavior coverBehavior, BlockPos pos, BlockAn return ModelData.EMPTY; } - BakedModel facadeModel = ModelUtils.getModelForState(facadeState); + BakedModel facadeModel = RenderUtil.getModelForState(facadeState); return facadeModel.getModelData(level, pos, facadeState, holderModelData); } @@ -202,7 +202,7 @@ public ChunkRenderTypeSet getRenderTypes(CoverBehavior coverBehavior, BlockPos p return ChunkRenderTypeSet.none(); } - BakedModel facadeModel = ModelUtils.getModelForState(facadeState); + BakedModel facadeModel = RenderUtil.getModelForState(facadeState); return facadeModel.getRenderTypes(facadeState, rand, modelData); } @@ -285,7 +285,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction if (facadeState.getRenderShape() != RenderShape.MODEL) { return quads; } - BakedModel facadeModel = ModelUtils.getModelForState(facadeState); + BakedModel facadeModel = RenderUtil.getModelForState(facadeState); if (facadeModel.isCustomRenderer()) { return quads; } @@ -340,7 +340,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) { return super.getModelData(level, pos, state, modelData).derive() .with(GTModelProperties.CHILD_MODEL_DATA, - ModelUtils.getModelForState(facadeState).getModelData(level, pos, state, modelData)) + RenderUtil.getModelForState(facadeState).getModelData(level, pos, state, modelData)) .build(); } @@ -348,7 +348,7 @@ public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState public List getRenderTypes(ItemStack stack, boolean fabulous) { List renderTypes = new ArrayList<>(); - BakedModel facadeModel = ModelUtils.getModelForState(this.facadeState); + BakedModel facadeModel = RenderUtil.getModelForState(this.facadeState); for (var model : facadeModel.getRenderPasses(stack, fabulous)) { renderTypes.addAll(model.getRenderTypes(this.facadeStack, fabulous)); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/ICoverableRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/ICoverableRenderer.java index 489f4e43e0c..2469b6ab994 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/ICoverableRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/ICoverableRenderer.java @@ -5,8 +5,8 @@ import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.client.model.GTModelProperties; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; import com.gregtechceu.gtceu.client.util.RenderUtil; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; import com.gregtechceu.gtceu.utils.GTUtil; import net.minecraft.client.renderer.MultiBufferSource; diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java index 28f0c8d5cc9..5c8fd4da25d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/IOCoverRenderer.java @@ -4,8 +4,8 @@ import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.cover.CoverBehavior; import com.gregtechceu.gtceu.api.cover.IIOCover; -import com.gregtechceu.gtceu.client.util.ModelUtils; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -46,7 +46,7 @@ public IOCoverRenderer(@Nullable ResourceLocation overlay, @Nullable ResourceLocation invertedOverlay, @Nullable ResourceLocation emissiveOverlay, @Nullable ResourceLocation invertedEmissiveOverlay) { - ModelUtils.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { + ModelEventHelper.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { var atlas = event.getAtlas(); if (overlay != null) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java index 472597cafcd..c9acfcd6477 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/cover/SimpleCoverRenderer.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.client.renderer.cover; import com.gregtechceu.gtceu.api.cover.CoverBehavior; -import com.gregtechceu.gtceu.client.util.ModelUtils; -import com.gregtechceu.gtceu.client.util.StaticFaceBakery; +import com.gregtechceu.gtceu.client.model.quad.StaticFaceBakery; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -34,7 +34,7 @@ public SimpleCoverRenderer(ResourceLocation texture) { } public SimpleCoverRenderer(ResourceLocation texture, ResourceLocation emissiveTexture) { - ModelUtils.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { + ModelEventHelper.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> { var atlas = event.getAtlas(); sprite = atlas.getSprite(texture); diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/item/ToolChargeBarRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/item/ToolChargeBarRenderer.java index 5e6074bf9ca..b1154fed005 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/item/ToolChargeBarRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/item/ToolChargeBarRenderer.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.item.IGTTool; import com.gregtechceu.gtceu.api.item.component.IDurabilityBar; import com.gregtechceu.gtceu.api.item.tool.ToolHelper; -import com.gregtechceu.gtceu.client.util.DrawUtil; +import com.gregtechceu.gtceu.client.util.RenderUtil; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.RenderType; @@ -39,7 +39,7 @@ public static void render(GuiGraphics graphics, int level, int xPosition, int yP int x = xPosition + 2; int y = yPosition + 13 - offset; graphics.fill(RenderType.gui(), x, y, x + 13, y + (shadow ? 2 : 1), 190, colorShadow); - DrawUtil.fillHorizontalGradient(graphics, RenderType.gui(), x, y, x + level, y + 1, left, right, 190); + RenderUtil.fillHorizontalGradient(graphics, RenderType.gui(), x, y, x + level, y + 1, left, right, 190); // graphics.fill(RenderType.guiOverlay(), x + BAR_W, y, x + BAR_W - level, y - 1, colorBG); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java index dc4dcd9b5c4..f450e986b41 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/BoilerMultiPartRender.java @@ -8,7 +8,7 @@ import com.gregtechceu.gtceu.client.model.machine.IControllerModelRenderer; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderType; -import com.gregtechceu.gtceu.client.util.ModelUtils; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.block.BoilerFireboxType; import com.gregtechceu.gtceu.common.data.GTBlocks; @@ -96,13 +96,13 @@ public void renderPartModel(List quads, MultiblockControllerMachine c Direction frontFacing, @Nullable Direction side, RandomSource rand, @NotNull ModelData modelData, @Nullable RenderType renderType) { if (this.fireboxIdleModel == null) { - this.fireboxIdleModel = ModelUtils.getModelForState(fireboxIdle); + this.fireboxIdleModel = RenderUtil.getModelForState(fireboxIdle); } if (this.fireboxActiveModel == null) { - this.fireboxActiveModel = ModelUtils.getModelForState(fireboxActive); + this.fireboxActiveModel = RenderUtil.getModelForState(fireboxActive); } if (this.casingModel == null) { - this.casingModel = ModelUtils.getModelForState(casing); + this.casingModel = RenderUtil.getModelForState(casing); } BlockPos partPos = part.self().getBlockPos(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java index b585d9f14a8..d39980e2eb3 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FluidAreaRender.java @@ -11,6 +11,7 @@ import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; @@ -20,6 +21,7 @@ import net.minecraftforge.client.RenderTypeHelper; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import lombok.Getter; @@ -94,7 +96,7 @@ public void render(WorkableMultiblockMachine machine, float partialTick, if (lastRecipe == null) { cachedRecipe = null; cachedFluid = null; - } else if (machine.self().getOffsetTimer() % 20 == 0 || lastRecipe.id != cachedRecipe) { + } else if (machine.getOffsetTimer() % 20 == 0 || lastRecipe.id != cachedRecipe) { cachedRecipe = lastRecipe.id; if (machine.isActive()) { cachedFluid = RenderUtil.getRecipeFluidToRender(lastRecipe); @@ -107,19 +109,18 @@ public void render(WorkableMultiblockMachine machine, float partialTick, return; } - var fluidRenderType = ItemBlockRenderTypes.getRenderLayer(cachedFluid.defaultFluidState()); - var consumer = buffer.getBuffer(RenderTypeHelper.getEntityRenderType(fluidRenderType, false)); + RenderType fluidRenderType = ItemBlockRenderTypes.getRenderLayer(cachedFluid.defaultFluidState()); + VertexConsumer consumer = buffer.getBuffer(RenderTypeHelper.getEntityRenderType(fluidRenderType, false)); for (RelativeDirection face : this.drawFaces) { poseStack.pushPose(); - var pose = poseStack.last().pose(); - var dir = face.getRelative(machine.self().getFrontFacing(), machine.self().getUpwardsFacing(), - machine.self().isFlipped()); + Direction dir = face.getRelative(machine.getFrontFacing(), machine.getUpwardsFacing(), + machine.isFlipped()); if (dir.getAxis() != Direction.Axis.Y) dir = dir.getOpposite(); - fluidBlockRenderer.drawPlane(dir, trait.getFluidOffsets(), pose, consumer, cachedFluid, - RenderUtil.FluidTextureType.STILL, packedOverlay, machine.self().getBlockPos()); + fluidBlockRenderer.drawPlane(dir, trait.getFluidOffsets(), poseStack, consumer, cachedFluid, + RenderUtil.FluidTextureType.STILL, packedOverlay, machine.getBlockPos(), machine.getLevel()); poseStack.popPose(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java index c23337bbb61..fce8e332633 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java @@ -1,27 +1,30 @@ package com.gregtechceu.gtceu.client.renderer.machine.impl; -import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.pattern.util.RelativeDirection; +import com.gregtechceu.gtceu.client.bloom.*; import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderType; -import com.gregtechceu.gtceu.client.util.BloomUtils; import com.gregtechceu.gtceu.client.util.RenderBufferHelper; import com.gregtechceu.gtceu.common.machine.multiblock.electric.FusionReactorMachine; -import com.lowdragmc.shimmer.client.shader.RenderUtils; - import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.util.Mth; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; import com.mojang.serialization.Codec; +import lombok.RequiredArgsConstructor; +import org.lwjgl.opengl.GL11; import static net.minecraft.util.FastColor.ARGB32.*; @@ -50,28 +53,35 @@ public boolean shouldRender(FusionReactorMachine machine, Vec3 cameraPos) { } @Override - public void render(FusionReactorMachine machine, float partialTick, - PoseStack poseStack, MultiBufferSource buffer, + public void render(FusionReactorMachine machine, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) { if (!machine.recipeLogic.isWorking() && delta <= 0) { return; } - if (GTCEu.Mods.isShimmerLoaded()) { - PoseStack finalStack = RenderUtils.copyPoseStack(poseStack); - BloomUtils.entityBloom(source -> renderLightRing(machine, partialTick, finalStack, - source.getBuffer(GTRenderTypes.getLightRing()))); - } else { - renderLightRing(machine, partialTick, poseStack, buffer.getBuffer(GTRenderTypes.getLightRing())); + + if (machine.getRegisteredBloomTicket().isValid() && !machine.isFormed()) { + machine.getRegisteredBloomTicket().invalidate(); + } + if (!machine.getRegisteredBloomTicket().isValid() && BloomShaderManager.isBloomActive()) { + BloomRenderTicket ticket = BloomHandler.registerBloomRender(FusionBloomEffect.SETUP, + new FusionBloomEffect(machine), machine); + + machine.setRegisteredBloomTicket(ticket); } + + renderLightRing(machine, partialTick, poseStack, buffer.getBuffer(GTRenderTypes.lightRing())); } @OnlyIn(Dist.CLIENT) - private void renderLightRing(FusionReactorMachine machine, float partialTicks, PoseStack stack, - VertexConsumer buffer) { - var color = machine.getColor(); - var alpha = 1f; + private void renderLightRing(FusionReactorMachine machine, float partialTicks, + PoseStack stack, VertexConsumer buffer) { + RenderSystem.disableCull(); + RenderSystem.disableDepthTest(); + RenderSystem.depthFunc(GL11.GL_ALWAYS); + + float alpha = 1f; if (machine.recipeLogic.isWorking()) { - lastColor = color; + lastColor = machine.getColor(); delta = FADEOUT; } else { alpha = delta / FADEOUT; @@ -79,21 +89,27 @@ private void renderLightRing(FusionReactorMachine machine, float partialTicks, P delta -= Minecraft.getInstance().getDeltaFrameTime(); } - final var lerpFactor = Math.abs((Math.abs(machine.getOffsetTimer() % 50) + partialTicks) - 25) / 25; - var front = machine.getFrontFacing(); - var upwards = machine.getUpwardsFacing(); - var flipped = machine.isFlipped(); - var back = RelativeDirection.BACK.getRelative(front, upwards, flipped); - var axis = RelativeDirection.UP.getRelative(front, upwards, flipped).getAxis(); - var r = Mth.lerp(lerpFactor, red(lastColor), 255) / 255f; - var g = Mth.lerp(lerpFactor, green(lastColor), 255) / 255f; - var b = Mth.lerp(lerpFactor, blue(lastColor), 255) / 255f; + Direction front = machine.getFrontFacing(); + Direction upwards = machine.getUpwardsFacing(); + boolean flipped = machine.isFlipped(); + Direction back = RelativeDirection.BACK.getRelative(front, upwards, flipped); + Direction.Axis axis = RelativeDirection.UP.getRelative(front, upwards, flipped).getAxis(); + + float lerpFactor = Math.abs((Math.abs(machine.getOffsetTimer() % 50) + partialTicks) - 25) / 25; + float r = Mth.lerp(lerpFactor, red(lastColor), 255) / 255f; + float g = Mth.lerp(lerpFactor, green(lastColor), 255) / 255f; + float b = Mth.lerp(lerpFactor, blue(lastColor), 255) / 255f; + RenderBufferHelper.renderRing(stack, buffer, back.getStepX() * 7 + 0.5F, back.getStepY() * 7 + 0.5F, back.getStepZ() * 7 + 0.5F, 6, 0.2F, 10, 20, r, g, b, alpha, axis); + + RenderSystem.enableCull(); + RenderSystem.enableDepthTest(); + RenderSystem.depthFunc(GL11.GL_LEQUAL); } @Override @@ -101,13 +117,54 @@ public boolean shouldRenderOffScreen(FusionReactorMachine machine) { return machine.recipeLogic.isWorking() || delta > 0; } - @Override - public int getViewDistance() { - return 32; - } - @Override public AABB getRenderBoundingBox(FusionReactorMachine machine) { return new AABB(machine.getBlockPos()).inflate(getViewDistance() / 2.0D); } + + @RequiredArgsConstructor + private final class FusionBloomEffect implements IBloomEffect { + + private final FusionReactorMachine machine; + + private static final BufferBuilder lightRingBuffer = new BufferBuilder(GTRenderTypes.lightRing().bufferSize()); + + private static final IRenderSetup SETUP = new IRenderSetup() { + + @Override + @OnlyIn(Dist.CLIENT) + public void preDraw(BufferBuilder buffer) { + lightRingBuffer.begin(GTRenderTypes.lightRing().mode(), GTRenderTypes.lightRing().format()); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void postDraw(BufferBuilder buffer) { + ShaderInstance lastShader = RenderSystem.getShader(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + + BufferUploader.drawWithShader(lightRingBuffer.end()); + + RenderSystem.setShader(() -> lastShader); + } + }; + + @Override + public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectRenderContext context) { + BlockPos pos = machine.getBlockPos(); + + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + + FusionRingRender.this.renderLightRing(machine, context.partialTicks(), poseStack, lightRingBuffer); + + poseStack.popPose(); + } + + @Override + public boolean shouldRenderBloomEffect(EffectRenderContext context) { + return (machine.recipeLogic.isWorking() || delta > 0) && + context.frustum().isVisible(FusionRingRender.this.getRenderBoundingBox(machine)); + } + } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumChestItemRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumChestItemRender.java index 6be72025874..5d9fe4b06f6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumChestItemRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumChestItemRender.java @@ -3,7 +3,6 @@ import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRender; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderType; -import com.gregtechceu.gtceu.client.util.PoseStackExtensions; import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.data.GTMachines; import com.gregtechceu.gtceu.common.machine.storage.CreativeChestMachine; @@ -26,13 +25,11 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.serialization.Codec; -import lombok.experimental.ExtensionMethod; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import static com.gregtechceu.gtceu.utils.GTMatrixUtils.*; -@ExtensionMethod(PoseStackExtensions.class) public class QuantumChestItemRender extends DynamicRender { // spotless:off diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumTankFluidRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumTankFluidRender.java index 1489b8dc126..901deec6652 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumTankFluidRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/QuantumTankFluidRender.java @@ -101,11 +101,11 @@ public void renderTank(PoseStack poseStack, MultiBufferSource buffer, Direction EnumSet sidesToRender = EnumSet.of(frontFacing); VertexConsumer builder = buffer.getBuffer(Sheets.translucentCullBlockSheet()); - var gas = fluid.getFluid().getFluidType().isLighterThanAir(); - var percentFull = isCreative || maxAmount <= storedAmount ? 1f : (float) storedAmount / maxAmount; + boolean gas = fluid.getFluid().getFluidType().isLighterThanAir(); + float percentFull = isCreative || maxAmount <= storedAmount ? 1f : (float) storedAmount / maxAmount; - var maxTop = gas ? MAX : MIN + percentFull * (MAX - MIN); - var minBot = gas ? MIN + (1 - percentFull) * (MAX - MIN) : MIN; + float maxTop = gas ? MAX : MIN + percentFull * (MAX - MIN); + float minBot = gas ? MIN + (1 - percentFull) * (MAX - MIN) : MIN; float minY, maxY, minZ, maxZ; if (frontFacing.getAxis() == Direction.Axis.Y) { minY = MIN; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java index eb035bf4ed0..ffdc9caed12 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/AssetEventListener.java @@ -1,5 +1,9 @@ package com.gregtechceu.gtceu.client.util; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.eventbus.api.Event; @@ -15,6 +19,7 @@ public interface AssetEventListener { return null; } + @FunctionalInterface interface AtlasStitched extends AssetEventListener { @Override @@ -24,15 +29,14 @@ default Class eventClass() { } } - interface ModifyBakingResult extends AssetEventListener { + @FunctionalInterface + interface BakedModelReplacement { - @Override - @Nullable - default Class eventClass() { - return ModelEvent.ModifyBakingResult.class; - } + BakedModel modifyBakedModel(ResourceLocation modelLocation, BakedModel model, + @Nullable UnbakedModel rootModel, ModelBakery modelBakery); } + @FunctionalInterface interface RegisterAdditional extends AssetEventListener { @Override diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/BloomUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/BloomUtils.java deleted file mode 100644 index 6325e1f7086..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/client/util/BloomUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gregtechceu.gtceu.client.util; - -import com.lowdragmc.shimmer.client.postprocessing.PostProcessing; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -import java.util.function.Consumer; - -@OnlyIn(Dist.CLIENT) -public class BloomUtils { - - public static void entityBloom(Consumer sourceConsumer) { - // Shimmer will call PostProcessing.BLOOM_UNREAL.renderEntityPost in LevelRenderer#renderLevel - // We probably don't need to call it ourselves - PostProcessing.BLOOM_UNREAL.postEntity(sourceConsumer); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/DrawUtil.java b/src/main/java/com/gregtechceu/gtceu/client/util/DrawUtil.java deleted file mode 100644 index 03b1958a156..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/client/util/DrawUtil.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.gregtechceu.gtceu.client.util; - -import com.gregtechceu.gtceu.core.mixins.client.GuiGraphicsAccessor; - -import com.lowdragmc.lowdraglib.utils.ColorUtils; - -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.RenderType; - -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.joml.Matrix4f; - -public class DrawUtil { - - /** - * Fills a rectangle with a gradient color from colorFrom to colorTo at the specified z-level using the given render - * type and coordinates as the boundaries. - * - * @param y2 the y-coordinate of the second corner of the rectangle. - * @param x2 the x-coordinate of the second corner of the rectangle. - * @param y1 the y-coordinate of the first corner of the rectangle. - * @param x1 the x-coordinate of the first corner of the rectangle. - * @param renderType the render type to use. - * @param z the z-level of the rectangle. - * @param colorTo the ending color of the gradient. - * @param colorFrom the starting color of the gradient. - */ - public static void fillHorizontalGradient(GuiGraphics graphics, RenderType renderType, int x1, int y1, int x2, - int y2, int colorFrom, int colorTo, int z) { - VertexConsumer vertexconsumer = graphics.bufferSource().getBuffer(renderType); - fillHorizontalGradient(graphics, vertexconsumer, x1, y1, x2, y2, z, colorFrom, colorTo); - ((GuiGraphicsAccessor) graphics).callFlushIfUnmanaged(); - } - - /** - * The core `fillGradient` method. - *

- * Fills a rectangle with a gradient color from colorFrom to colorTo at the specified z-level using the given render - * type and coordinates as the boundaries. - * - * @param consumer the {@linkplain VertexConsumer} object for drawing the vertices on screen. - * @param x1 the x-coordinate of the first corner of the rectangle. - * @param y1 the y-coordinate of the first corner of the rectangle. - * @param x2 the x-coordinate of the second corner of the rectangle. - * @param y2 the y-coordinate of the second corner of the rectangle. - * @param z the z-level of the rectangle. - * @param colorFrom the starting color of the gradient. - * @param colorTo the ending color of the gradient. - */ - private static void fillHorizontalGradient(GuiGraphics graphics, VertexConsumer consumer, int x1, int y1, int x2, - int y2, int z, int colorFrom, int colorTo) { - float a1 = ColorUtils.alpha(colorFrom); - float r1 = ColorUtils.red(colorFrom); - float g1 = ColorUtils.green(colorFrom); - float b1 = ColorUtils.blue(colorFrom); - float a2 = ColorUtils.alpha(colorTo); - float r2 = ColorUtils.red(colorTo); - float g2 = ColorUtils.green(colorTo); - float b2 = ColorUtils.blue(colorTo); - Matrix4f matrix4f = graphics.pose().last().pose(); - consumer.vertex(matrix4f, (float) x1, (float) y1, (float) z).color(r1, g1, b1, a1).endVertex(); - consumer.vertex(matrix4f, (float) x1, (float) y2, (float) z).color(r1, g1, b1, a1).endVertex(); - consumer.vertex(matrix4f, (float) x2, (float) y2, (float) z).color(r2, g2, b2, a2).endVertex(); - consumer.vertex(matrix4f, (float) x2, (float) y1, (float) z).color(r2, g2, b2, a2).endVertex(); - } - - /** - * Converts an (A)RGB integer color into an array of floats, for use in GL calls - * - * @return float[]{R, G, B, A} - */ - public static float[] floats(int argb) { - return new float[] { - (float) (argb >> 16 & 255) / 255.0F, - (float) (argb >> 8 & 255) / 255.0F, - (float) (argb & 255) / 255.0F, - (float) (argb >> 24 & 255) / 255.0F - }; - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java new file mode 100644 index 00000000000..bb616bf300c --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/ModelEventHelper.java @@ -0,0 +1,229 @@ +package com.gregtechceu.gtceu.client.util; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.model.ctm.CTMBakedModel; +import com.gregtechceu.gtceu.client.model.machine.MachineModel; +import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; +import com.gregtechceu.gtceu.core.mixins.ReloadableResourceManagerAccessor; +import com.gregtechceu.gtceu.integration.modernfix.GTModernFixIntegration; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManagerReloadListener; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.ApiStatus; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +@SuppressWarnings("deprecation") +@UtilityClass +@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ModelEventHelper { + + @ApiStatus.Internal + public record EventListenerHolder(T listener, boolean removeOnReload) {} + + @ApiStatus.Internal + public static final List> EVENT_LISTENERS = new ArrayList<>(); + @ApiStatus.Internal + public static final Map CTM_SPRITE_CACHE = new ConcurrentHashMap<>(); + + private static final Multimap SCRAPED_TEXTURES = HashMultimap.create(); + private static final Object2BooleanMap WRAPPED_MODELS = new Object2BooleanOpenHashMap<>(); + + @ApiStatus.Internal + public static void markTextureUsedForModel(ResourceLocation modelLocation, Material material) { + SCRAPED_TEXTURES.put(modelLocation, material); + } + + public static void registerAtlasStitchedEventListener(boolean removeOnReload, + AssetEventListener.AtlasStitched listener) { + EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); + } + + public static void registerAtlasStitchedEventListener(boolean removeOnReload, final ResourceLocation atlasLocation, + final AssetEventListener.AtlasStitched listener) { + registerAtlasStitchedEventListener(removeOnReload, event -> { + if (event.getAtlas().location().equals(atlasLocation)) { + listener.accept(event); + } + }); + } + + public static void registerBakeEventListener(boolean removeOnReload, + AssetEventListener.BakedModelReplacement listener) { + EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); + } + + public static void registerAddModelsEventListener(boolean removeOnReload, + AssetEventListener.RegisterAdditional listener) { + EVENT_LISTENERS.add(new EventListenerHolder<>(listener, removeOnReload)); + } + + private static final AtomicInteger reloadCounter = new AtomicInteger(0); + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void registerReloadListener(RegisterClientReloadListenersEvent event) { + ((ReloadableResourceManagerAccessor) Minecraft.getInstance().getResourceManager()).getListeners() + .add(0, (ResourceManagerReloadListener) resourceManager -> { + if (reloadCounter.addAndGet(1) > 1) { + EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); + } + + CTM_SPRITE_CACHE.clear(); + WRAPPED_MODELS.clear(); + SCRAPED_TEXTURES.clear(); + TextureMetadataHelper.invalidateCaches(); + }); + } + + @SuppressWarnings("unchecked") + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onAtlasStitched(TextureStitchEvent.Post event) { + for (var listener : EVENT_LISTENERS) { + if (!(listener.listener instanceof AssetEventListener assetEventListener)) continue; + + Class eventClass = assetEventListener.eventClass(); + if (eventClass != null && eventClass.isInstance(event)) { + ((AssetEventListener) listener.listener).accept(event); + } + } + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onModifyBakingResult(ModelEvent.ModifyBakingResult event) { + // don't process baked model replacement here if ModernFix is loaded & dynamic resources is enabled + if (GTCEu.Mods.isModernFixLoaded() && GTModernFixIntegration.isDynamicResourcesEnabled()) return; + + for (var entry : event.getModels().entrySet()) { + BakedModel model = entry.getValue(); + + // process all model replacers + for (var listener : EVENT_LISTENERS) { + if (!(listener.listener instanceof AssetEventListener.BakedModelReplacement modelReplacement)) continue; + model = modelReplacement.modifyBakedModel(entry.getKey(), model, + event.getModelBakery().getModel(entry.getKey()), event.getModelBakery()); + } + entry.setValue(model); + } + } + + @SuppressWarnings("unchecked") + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onRegisterAdditional(ModelEvent.RegisterAdditional event) { + for (var listener : EVENT_LISTENERS) { + if (!(listener.listener instanceof AssetEventListener assetEventListener)) continue; + + Class eventClass = assetEventListener.eventClass(); + if (eventClass != null && eventClass.isInstance(event)) { + ((AssetEventListener) listener.listener).accept(event); + } + } + } + + // INTERNAL ASSET RELOAD LISTENER REGISTRATION + + @ApiStatus.Internal + public static void initInternalAssetReloadListeners() { + registerAtlasStitchedEventListener(false, TextureAtlas.LOCATION_BLOCKS, event -> { + TextureAtlas atlas = event.getAtlas(); + // Cache all textures' CTM metadata + // TODO lazy + for (ResourceLocation location : atlas.getTextureLocations()) { + var sec = TextureMetadataHelper.getMetadataFromRelativeLocation(location); + sec.ifPresent(section -> { + if (section.connectionTexture() != null) { + TextureAtlasSprite ctmSprite = atlas.getSprite(section.connectionTexture()); + CTM_SPRITE_CACHE.put(location, ctmSprite); + } + }); + } + + MachineModel.initSprites(atlas); + ICoverableRenderer.initSprites(atlas); + }); + + // register CTM model wrapper + ModelEventHelper.registerBakeEventListener(false, (rl, baked, rootModel, modelBakery) -> { + if (baked.isCustomRenderer()) { + // Nothing we can add to builtin models + return baked; + } + // do not register automatic CTM for machine models, they handle it themselves + if (baked instanceof MachineModel) { + return baked; + } + + if (!(rl instanceof ModelResourceLocation) || rootModel == null || baked instanceof CTMBakedModel) { + return baked; + } + Deque dependencies = new ArrayDeque<>(); + Set seenModels = new HashSet<>(); + dependencies.push(rl); + seenModels.add(rl); + + boolean shouldWrap = WRAPPED_MODELS.getOrDefault(rl, false); + if (WRAPPED_MODELS.containsKey(rl)) { + // shortcut if the model's already been checked + if (shouldWrap) return new CTMBakedModel<>(baked); + else return baked; + } + // Breadth-first loop through dependencies + // exiting as soon as a CTM texture is found, and skipping duplicates/cycles + PARENT_LOOP: + while (!shouldWrap && !dependencies.isEmpty()) { + ResourceLocation dependencyName = dependencies.pop(); + UnbakedModel unbaked; + try { + unbaked = dependencyName == rl ? rootModel : modelBakery.getModel(dependencyName); + } catch (Exception e) { + continue; + } + try { + // have to copy because the set is updated during this loop + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + Set textures = new HashSet<>(SCRAPED_TEXTURES.get(dependencyName)); + for (Material tex : textures) { + if (TextureMetadataHelper.getMetadata(tex).isPresent()) { + // At least one texture has CTM metadata, so we should wrap this model + shouldWrap = true; + break PARENT_LOOP; + } + } + // shouldWrap is always false here because of the `break` above + for (ResourceLocation newDep : unbaked.getDependencies()) { + if (seenModels.add(newDep)) { + dependencies.push(newDep); + } + } + } catch (Exception e) { + GTCEu.LOGGER.error("Error loading dependency {} for model {}. Skipping...", + dependencyName, rl, e); + } + } + ModelEventHelper.WRAPPED_MODELS.put(rl, shouldWrap); + if (shouldWrap) { + return new CTMBakedModel<>(baked); + } + + return baked; + }); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java b/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java deleted file mode 100644 index 8568412da98..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/client/util/ModelUtils.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.gregtechceu.gtceu.client.util; - -import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.client.model.machine.MachineModel; -import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer; -import com.gregtechceu.gtceu.integration.modernfix.GTModernFixIntegration; - -import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; - -import net.minecraft.ChatFormatting; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.resources.model.*; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.server.packs.resources.ResourceManagerReloadListener; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.ModelEvent; -import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; -import net.minecraftforge.client.event.TextureStitchEvent; -import net.minecraftforge.client.model.data.ModelData; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; - -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class ModelUtils { - - private ModelUtils() {} - - private static final List EVENT_LISTENERS = new ArrayList<>(); - - public static List getBakedModelQuads(BakedModel model, BlockAndTintGetter level, BlockPos pos, - BlockState state, Direction side, RandomSource rand) { - return model.getQuads(state, side, rand, model.getModelData(level, pos, state, ModelData.EMPTY), null); - } - - public static BakedModel getModelForState(BlockState state) { - return Minecraft.getInstance().getBlockRenderer().getBlockModel(state); - } - - public static String getPropertyValueString(Map.Entry, Comparable> entry) { - Property property = entry.getKey(); - Comparable value = entry.getValue(); - - String valueString = Util.getPropertyName(property, value); - if (Boolean.TRUE.equals(value)) { - valueString = ChatFormatting.GREEN + valueString; - } else if (Boolean.FALSE.equals(value)) { - valueString = ChatFormatting.RED + valueString; - } - - return property.getName() + ": " + valueString; - } - - public static void registerAtlasStitchedEventListener(boolean removeOnReload, - AssetEventListener.AtlasStitched listener) { - EVENT_LISTENERS.add(new EventListenerHolder(listener, removeOnReload)); - } - - public static void registerAtlasStitchedEventListener(boolean removeOnReload, final ResourceLocation atlasLocation, - final AssetEventListener.AtlasStitched listener) { - registerAtlasStitchedEventListener(removeOnReload, event -> { - if (event.getAtlas().location().equals(atlasLocation)) { - listener.accept(event); - } - }); - } - - public static void registerBakeEventListener(boolean removeOnReload, - AssetEventListener.ModifyBakingResult listener) { - EVENT_LISTENERS.add(new EventListenerHolder(listener, removeOnReload)); - } - - public static void registerAddModelsEventListener(boolean removeOnReload, - AssetEventListener.RegisterAdditional listener) { - EVENT_LISTENERS.add(new EventListenerHolder(listener, removeOnReload)); - } - - @SubscribeEvent(priority = EventPriority.HIGH) - public static void registerReloadListener(RegisterClientReloadListenersEvent event) { - event.registerReloadListener(new ResourceManagerReloadListener() { - - @Override - public void onResourceManagerReload(@NotNull ResourceManager resourceManager) { - EVENT_LISTENERS.removeIf(EventListenerHolder::removeOnReload); - } - }); - } - - @SuppressWarnings({ "unchecked", "deprecation" }) - @SubscribeEvent(priority = EventPriority.LOWEST) - public static void onAtlasStitched(TextureStitchEvent.Post event) { - TextureAtlas atlas = event.getAtlas(); - if (atlas.location() == TextureAtlas.LOCATION_BLOCKS) { - MachineModel.initSprites(atlas); - ICoverableRenderer.initSprites(atlas); - } - - for (var listener : EVENT_LISTENERS) { - Class eventClass = listener.listener.eventClass(); - if (eventClass != null && eventClass.isInstance(event)) { - ((AssetEventListener) listener.listener).accept(event); - } - } - } - - @SuppressWarnings("unchecked") - @SubscribeEvent(priority = EventPriority.LOWEST) - public static void onModifyBakingResult(ModelEvent.ModifyBakingResult event) { - for (var listener : EVENT_LISTENERS) { - Class eventClass = listener.listener.eventClass(); - if (eventClass != null && eventClass.isInstance(event)) { - ((AssetEventListener) listener.listener).accept(event); - } - } - - // don't process the CTM model unwrapping here if modernfix dynamic resources is enabled - if (GTCEu.Mods.isModernFixLoaded() && GTModernFixIntegration.isDynamicResourcesEnabled()) return; - - // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins - // Also, the caching they have stops our models from updating properly - for (var entry : event.getModels().entrySet()) { - BakedModel model = entry.getValue(); - if (!(model instanceof CustomBakedModel ctmModel)) { - continue; - } - if (ctmModel.getParent() instanceof MachineModel machine) { - entry.setValue(machine); - } - } - } - - @SuppressWarnings("unchecked") - @SubscribeEvent(priority = EventPriority.LOWEST) - public static void onRegisterAdditional(ModelEvent.RegisterAdditional event) { - for (var listener : EVENT_LISTENERS) { - Class eventClass = listener.listener.eventClass(); - if (eventClass != null && eventClass.isInstance(event)) { - ((AssetEventListener) listener.listener).accept(event); - } - } - } - - private record EventListenerHolder(AssetEventListener listener, boolean removeOnReload) {} -} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/PoseStackExtensions.java b/src/main/java/com/gregtechceu/gtceu/client/util/PoseStackExtensions.java deleted file mode 100644 index ac411d26ada..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/client/util/PoseStackExtensions.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.gregtechceu.gtceu.client.util; - -import com.mojang.blaze3d.vertex.PoseStack; -import org.joml.Matrix4fc; - -public class PoseStackExtensions { - - public static void mulPoseMatrix(PoseStack self, Matrix4fc matrix) { - self.last().pose().mul(matrix); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/RenderBufferHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/RenderBufferHelper.java index 6a739a35182..8792fc7af27 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/RenderBufferHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/RenderBufferHelper.java @@ -6,11 +6,13 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import com.mojang.blaze3d.vertex.*; import org.joml.Matrix4f; +import org.joml.Vector3f; import org.joml.Vector3fc; import java.util.EnumSet; @@ -39,8 +41,8 @@ public class RenderBufferHelper { * @param alpha transparency * @param axis The axial direction of the "ring pipe" determines which axis the "ring pipe" rotates around. */ - public static void renderRing(PoseStack poseStack, VertexConsumer buffer, float x, float y, float z, float r, - float tubeRadius, + public static void renderRing(PoseStack poseStack, VertexConsumer buffer, float x, float y, float z, + float r, float tubeRadius, int sides, int segments, float red, float green, float blue, float alpha, Direction.Axis axis) { Matrix4f mat = poseStack.last().pose(); @@ -152,6 +154,80 @@ public static void renderCube(VertexConsumer buffer, PoseStack.Pose pose, Set + * Fills a rectangle with a gradient color from colorFrom to colorTo at the specified z-level using the given render + * type and coordinates as the boundaries. + * + * @param consumer the {@linkplain VertexConsumer} object for drawing the vertices on screen. + * @param x1 the x-coordinate of the first corner of the rectangle. + * @param y1 the y-coordinate of the first corner of the rectangle. + * @param x2 the x-coordinate of the second corner of the rectangle. + * @param y2 the y-coordinate of the second corner of the rectangle. + * @param z the z-level of the rectangle. + * @param colorFrom the starting color of the gradient. + * @param colorTo the ending color of the gradient. + */ + private static void fillHorizontalGradient(GuiGraphics graphics, VertexConsumer consumer, + float x1, float y1, float x2, float y2, float z, + int colorFrom, int colorTo) { + int a1 = alpha(colorFrom), r1 = red(colorFrom), g1 = green(colorFrom), b1 = blue(colorFrom); + int a2 = alpha(colorTo), r2 = red(colorTo), g2 = green(colorTo), b2 = blue(colorTo); + + Matrix4f pose = graphics.pose().last().pose(); + consumer.vertex(pose, x1, y1, z).color(r1, g1, b1, a1).endVertex(); + consumer.vertex(pose, x1, y2, z).color(r1, g1, b1, a1).endVertex(); + consumer.vertex(pose, x2, y2, z).color(r2, g2, b2, a2).endVertex(); + consumer.vertex(pose, x2, y1, z).color(r2, g2, b2, a2).endVertex(); + } + + /** + * Converts an (A)RGB integer color into an array of floats, for use in GL calls + * + * @return float[]{R, G, B, A} + */ + public static float[] floats(int argb) { + return new float[] { + (float) (argb >> 16 & 255) / 255.0F, + (float) (argb >> 8 & 255) / 255.0F, + (float) (argb & 255) / 255.0F, + (float) (argb >> 24 & 255) / 255.0F + }; + } + + public static int interpolateColor(int color1, int color2, float blend) { + int a1 = color1 >> 24 & 255; + int r1 = color1 >> 16 & 255; + int g1 = color1 >> 8 & 255; + int b1 = color1 & 255; + + int a2 = color2 >> 24 & 255; + int r2 = color2 >> 16 & 255; + int g2 = color2 >> 8 & 255; + int b2 = color2 & 255; + + int a = (int) (a1 * (1 - blend) + a2 * blend); + int r = (int) (r1 * (1 - blend) + r2 * blend); + int g = (int) (g1 * (1 - blend) + g2 * blend); + int b = (int) (b1 * (1 - blend) + b2 * blend); + return a << 24 | r << 16 | g << 8 | b; + } + public static void moveToFace(PoseStack poseStack, Vector3fc pos, Direction face) { moveToFace(poseStack, pos.x(), pos.y(), pos.z(), face); } @@ -216,6 +316,10 @@ public static void moveToFace(PoseStack poseStack, float x, float y, float z, Di Math.fma(face.getStepZ(), 0.5f, z)); } + public static BakedModel getModelForState(BlockState state) { + return Minecraft.getInstance().getBlockRenderer().getBlockModel(state); + } + public static void drawBlock(BlockAndTintGetter level, BlockPos pos, BlockState state, MultiBufferSource bufferSource, PoseStack poseStack) { int packedLight = LevelRenderer.getLightColor(level, state, pos); diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java new file mode 100644 index 00000000000..452b46b9540 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/SpriteFunctionWrapper.java @@ -0,0 +1,28 @@ +package com.gregtechceu.gtceu.client.util; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; + +import java.util.function.Function; + +public class SpriteFunctionWrapper implements Function { + + private final Function internal; + private final ResourceLocation modelLocation; + + public SpriteFunctionWrapper(Function internal, ResourceLocation modelLocation) { + if (internal instanceof SpriteFunctionWrapper wrapper) { + this.internal = wrapper.internal; + } else { + this.internal = internal; + } + this.modelLocation = modelLocation; + } + + @Override + public TextureAtlasSprite apply(Material material) { + ModelEventHelper.markTextureUsedForModel(this.modelLocation, material); + return internal.apply(material); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java new file mode 100644 index 00000000000..facecba1cfb --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureHelper.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.client.util; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Nullable; + +import static com.gregtechceu.gtceu.client.model.quad.MutableQuadView.*; + +/** + * Handles most texture-baking use cases for model loaders and model libraries via + * {@link #bakeSprite(MutableQuadView, TextureAtlasSprite, int)}. + */ +@UtilityClass +public class TextureHelper { + + public static final float NORMALIZER = 1f / 16f; + public static final float DENORMALIZER = 16f; + + private static final int BAKE_ROTATE_ANY = BAKE_ROTATE_270 | BAKE_ROTATE_180 | BAKE_ROTATE_90; + + /** + * Bakes textures in the provided vertex data, handling UV locking, rotation, interpolation, etc. + * Textures must not be already baked. + * + *

+ * If {@code sprite == null}, only the UV modifiers will be applied, + * but they won't be translated to the sprite's atlas coordinates. + * + * @see #unbakeSprite(MutableQuadView, TextureAtlasSprite, int) + * @see MutableQuadView#BAKE_ROTATE_NONE bake flags + */ + public static void bakeSprite(MutableQuadView quad, @Nullable TextureAtlasSprite sprite, int bakeFlags) { + if (quad.nominalFace() != null && (BAKE_LOCK_UV & bakeFlags) != 0) { + // Assigns normalized UV coordinates based on vertex positions + applyModifier(quad, UV_LOCKERS[quad.nominalFace().get3DDataValue()]); + } else if ((BAKE_NORMALIZED & bakeFlags) == 0) { + // flag is NOT set, UVs are assumed to not be normalized yet as is the default. + // normalize through dividing by 16 + + // Scales from 0-16 to 0-1 + applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * NORMALIZER, q.v(i) * NORMALIZER)); + } + + final int rotation = bakeFlags & BAKE_ROTATE_ANY; + + if (rotation != 0) { + // Rotates texture around the center of sprite. + // Assumes normalized coordinates. + applyModifier(quad, ROTATIONS[rotation]); + } + + if ((BAKE_FLIP_U & bakeFlags) != 0) { + // Inverts U coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i))); + } + + if ((BAKE_FLIP_V & bakeFlags) != 0) { + // Inverts V coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i))); + } + + if (sprite != null) { + interpolate(quad, sprite); + } + } + + /** + * Faster than sprite method. Sprite computes span and normalizes inputs each call, so we'd have to denormalize + * before we called, only to have the sprite renormalize immediately. + */ + public static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) { + final float uMin = sprite.getU0(); + final float uSpan = sprite.getU1() - uMin; + final float vMin = sprite.getV0(); + final float vSpan = sprite.getV1() - vMin; + + for (int i = 0; i < 4; i++) { + q.uv(i, uMin + q.u(i) * uSpan, vMin + q.v(i) * vSpan); + } + } + + /** + * The reverse operation of {@link #bakeSprite}. Undoes the same operations except UV locking. + * Textures must be already baked. + * + *

+ * Note this the function's order of operations is reversed in relation to {@link #bakeSprite}.
+ * The {@link MutableQuadView#BAKE_NORMALIZED BAKE_NORMALIZED} flag also works inversely + * to the one in {@link #bakeSprite}. + * + *

+ * If {@code sprite == null}, only the UV modifiers will be applied, + * but they won't be translated from the sprite's atlas coordinates to a 0-16 range. + * + * @see #bakeSprite(MutableQuadView, TextureAtlasSprite, int) + * @see MutableQuadView#BAKE_ROTATE_NONE bake flags + */ + public static void unbakeSprite(MutableQuadView quad, @Nullable TextureAtlasSprite sprite, int bakeFlags) { + if (sprite != null) { + deInterpolate(quad, sprite); + } + + if ((BAKE_FLIP_V & bakeFlags) != 0) { + // Inverts V coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i))); + } + + if ((BAKE_FLIP_U & bakeFlags) != 0) { + // Inverts U coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i))); + } + + final int rotation = bakeFlags & BAKE_ROTATE_ANY; + + if (rotation != 0) { + // Rotates texture around the center of sprite. + // Assumes normalized coordinates. + applyModifier(quad, ROTATIONS[rotation]); + } + + if ((BAKE_NORMALIZED & bakeFlags) == 0) { + // flag is NOT set, UVs are assumed to be normalized as is the default. + // denormalize through multiplying by 16 + + // Scales from 0-1 to 0-16 + applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * DENORMALIZER, q.v(i) * DENORMALIZER)); + } + if ((BAKE_DEROTATE_UV & bakeFlags) != 0) { + // Cycles texture coordinates so that vertex 0's UVs are the smallest + derotateUV(quad); + } + } + + /** + * Faster than sprite method. Sprite computes span and normalizes inputs each call, so we'd have to denormalize + * before we called, only to have the sprite renormalize immediately. + */ + public static void deInterpolate(MutableQuadView q, TextureAtlasSprite sprite) { + final float uMin = sprite.getU0(); + final float uSpan = sprite.getU1() - uMin; + final float vMin = sprite.getV0(); + final float vSpan = sprite.getV1() - vMin; + + for (int i = 0; i < 4; i++) { + q.uv(i, (q.u(i) - uMin) / uSpan, (q.v(i) - vMin) / vSpan); + } + } + + private static void derotateUV(MutableQuadView quad) { + int minIndex = 0; + float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE; + + for (int i = 0; i < 4; i++) { + if (quad.u(i) <= minU && quad.v(i) <= minV) { + minIndex = i; + minU = quad.u(i); + minV = quad.v(i); + } + } + applyModifier(quad, ROTATIONS[minIndex]); + } + + @FunctionalInterface + public interface VertexModifier { + + void apply(MutableQuadView quad, int vertexIndex); + } + + private static void applyModifier(MutableQuadView quad, VertexModifier modifier) { + for (int i = 0; i < 4; i++) { + modifier.apply(quad, i); + } + } + + private static final VertexModifier[] ROTATIONS = new VertexModifier[] { + (q, i) -> {}, // 0 + (q, i) -> q.uv(i, q.v(i), 1 - q.u(i)), // 90 + (q, i) -> q.uv(i, 1 - q.u(i), 1 - q.v(i)), // 180 + (q, i) -> q.uv(i, 1 - q.v(i), q.u(i)) // 270 + }; + + private static final VertexModifier[] UV_LOCKERS = new VertexModifier[6]; + + static { + UV_LOCKERS[Direction.EAST.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i)); + UV_LOCKERS[Direction.WEST.get3DDataValue()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i)); + UV_LOCKERS[Direction.NORTH.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i)); + UV_LOCKERS[Direction.SOUTH.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i)); + UV_LOCKERS[Direction.DOWN.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.z(i)); + UV_LOCKERS[Direction.UP.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), q.z(i)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java new file mode 100644 index 00000000000..e9e4ba4130f --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/TextureMetadataHelper.java @@ -0,0 +1,102 @@ +package com.gregtechceu.gtceu.client.util; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.client.model.ctm.GTTextureMetadata; +import com.gregtechceu.gtceu.client.util.quad.transformers.GTQuadTransformers; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.utils.TriState; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; + +import lombok.experimental.UtilityClass; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +@UtilityClass +public class TextureMetadataHelper { + + private static final Map> metadataCache = new ConcurrentHashMap<>(); + + public static Optional getMetadata(ResourceLocation res) { + return metadataCache.computeIfAbsent(res, loc -> { + try { + return Minecraft.getInstance().getResourceManager().getResource(res) + .flatMap(GTTextureMetadata::getForResourceUnsafe); + } catch (Exception e) { + // the real exception that's caught should always be an IOException, + // but @SneakyThrows hides that from us so we catch all exceptions instead. + GTCEu.LOGGER.error("Error loading metadata for location {}", res, e); + + return Optional.empty(); + } + }); + } + + public static Optional getMetadata(TextureAtlasSprite sprite) { + return getMetadata(spriteToAbsolute(sprite.contents().name())); + } + + public static Optional getMetadata(Material material) { + return getMetadata(spriteToAbsolute(material.texture())); + } + + public static Optional getMetadataFromRelativeLocation(ResourceLocation relativeLocation) { + return getMetadata(spriteToAbsolute(relativeLocation)); + } + + public static ResourceLocation spriteToAbsolute(ResourceLocation sprite) { + if (!sprite.getPath().startsWith("textures/")) { + sprite = sprite.withPrefix("textures/"); + } + if (!sprite.getPath().endsWith(".png")) { + sprite = sprite.withSuffix(".png"); + } + return sprite; + } + + public static boolean hasBloom(BakedQuad quad, int[] ambientPackedLights) { + var metadata = getMetadata(quad.getSprite()); + if (metadata.isPresent()) { + TriState bloomValue = metadata.get().bloom(); + if (bloomValue == TriState.TRUE) return true; + // Explicitly disable bloom if it's set to FALSE in the metadata + else if (bloomValue == TriState.FALSE) return false; + + // fall through to emissivity config check if default + } + + if (ConfigHolder.INSTANCE.client.bloom.emissiveTexturesHaveBloom) { + return isEmissive(quad, ambientPackedLights); + } + + return false; + } + + public static boolean isEmissive(BakedQuad quad, int[] ambientPackedLights) { + int[] quadPackedLights = GTQuadTransformers.getPackedLights(quad); + + for (int i = 0; i < 4; i++) { + int quadLight = quadPackedLights[i]; + int qBlock = LightTexture.block(quadLight), qSky = LightTexture.sky(quadLight); + + int ambientLight = ambientPackedLights[i]; + int aBlock = LightTexture.block(ambientLight), aSky = LightTexture.sky(ambientLight); + + if (qBlock > aBlock || qSky > aSky) { + return true; + } + } + return false; + } + + static void invalidateCaches() { + metadataCache.clear(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/util/package-info.java new file mode 100644 index 00000000000..1bc08b04b82 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.client.util; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java new file mode 100644 index 00000000000..01fc65ccd43 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/GeometryHelper.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.client.util.quad; + +import com.gregtechceu.gtceu.client.model.quad.QuadView; +import com.gregtechceu.gtceu.utils.GTUtil; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Vec3i; +import net.minecraft.util.Mth; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +/** + * Static routines of general utility for renderer implementations. + * Renderers are not required to use these helpers, but they were designed to be usable without the default renderer. + */ +@UtilityClass +public class GeometryHelper { + + /** Result from {@link #toFaceIndex(Direction)} for null values. */ + public static final int NULL_FACE_ID = 6; + + /** + * Convenient way to encode faces that may be null. Null is returned as {@link #NULL_FACE_ID}. + * Use {@link #faceFromIndex(int)} to retrieve encoded face. + */ + public static int toFaceIndex(@Nullable Direction face) { + return face == null ? NULL_FACE_ID : face.get3DDataValue(); + } + + /** + * Use to decode a result from {@link #toFaceIndex(Direction)}. Return value will be null if encoded value was null. + */ + @Contract("null -> null") + public static @Nullable Direction faceFromIndex(int faceIndex) { + return GTUtil.DIRECTIONS_WITH_NULL[faceIndex]; + } + + /** + * Identifies the face to which the quad is most closely aligned. This mimics the value that + * {@link BakedQuad#getDirection()} returns, and is used in the vanilla renderer for all diffuse lighting. + * + *

+ * Derived from the quad face normal and expects convex quads with all points co-planar. + */ + public static Direction lightFace(QuadView quad) { + final Vector3f normal = quad.faceNormal(); + return switch (GeometryHelper.longestAxis(normal)) { + case X -> normal.x() > 0 ? Direction.EAST : Direction.WEST; + case Y -> normal.y() > 0 ? Direction.UP : Direction.DOWN; + case Z -> normal.z() > 0 ? Direction.SOUTH : Direction.NORTH; + }; + } + + /** + * @see #longestAxis(float, float, float) + */ + public static Axis longestAxis(Vector3f vec) { + return longestAxis(vec.x(), vec.y(), vec.z()); + } + + /** + * Identifies the largest (max absolute magnitude) component (X, Y, Z) in the given vector. + */ + public static Axis longestAxis(float normalX, float normalY, float normalZ) { + Axis result = Axis.Y; + float longest = Math.abs(normalY); + float a = Math.abs(normalX); + + if (a > longest) { + result = Axis.X; + longest = a; + } + + return Math.abs(normalZ) > longest ? Axis.Z : result; + } + + /** + * 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 = Mth.clamp(x, -1, 1); + y = Mth.clamp(y, -1, 1); + z = Mth.clamp(z, -1, 1); + w = Mth.clamp(w, -1, 1); + + return ((int) (x * 127) & 255) | (((int) (y * 127) & 255) << 8) | (((int) (z * 127) & 255) << 16) | + (((int) (w * 127) & 255) << 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. + * If {@link QuadView#nominalFace()} is set will optimize by confirming quad is parallel to that face and, + * if so, use the standard normal for that face direction. + * + *

+ * Will work with triangles also. Assumes counter-clockwise winding order, which is the norm. Expects convex quads + * with all points co-planar. + */ + public static void computeFaceNormal(Vector3f saveTo, QuadView q) { + final Direction nominalFace = q.nominalFace(); + + if (isQuadParallelToFace(nominalFace, q)) { + Vec3i vec = nominalFace.getNormal(); + 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); + } + + /** + * Returns true if quad is parallel to the given face. Does not validate quad winding order. Expects convex quads + * with all points co-planar. + */ + public static boolean isQuadParallelToFace(@Nullable Direction face, QuadView quad) { + if (face == null) { + return false; + } + + int i = face.getAxis().ordinal(); + final float val = quad.posByIndex(0, i); + return Mth.equal(val, quad.posByIndex(1, i)) && Mth.equal(val, quad.posByIndex(2, i)) && + Mth.equal(val, quad.posByIndex(3, i)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/GTQuadTransformers.java similarity index 74% rename from src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java rename to src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/GTQuadTransformers.java index 42e0bb9b62b..8a240d1645b 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/GTQuadTransformers.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/GTQuadTransformers.java @@ -1,4 +1,4 @@ -package com.gregtechceu.gtceu.client.util; +package com.gregtechceu.gtceu.client.util.quad.transformers; import net.minecraft.client.renderer.FaceInfo; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -9,6 +9,8 @@ import net.minecraftforge.client.model.IQuadTransformer; import net.minecraftforge.client.model.QuadTransformers; +import java.lang.reflect.Array; + public final class GTQuadTransformers { public static IQuadTransformer offset(float by) { @@ -79,9 +81,9 @@ public static BakedQuad setSprite(BakedQuad quad, TextureAtlasSprite sprite) { vertices[offset] = Float.floatToRawIntBits(u); vertices[offset + 1] = Float.floatToRawIntBits(v); } - BakedQuad newQuad = new BakedQuad(vertices, quad.getTintIndex(), quad.getDirection(), - sprite, quad.isShade(), quad.hasAmbientOcclusion()); - return newQuad.gtceu$setTextureKey(quad.gtceu$getTextureKey()); + return new BakedQuad(vertices, quad.getTintIndex(), quad.getDirection(), + sprite, quad.isShade(), quad.hasAmbientOcclusion()) + .gtceu$setTextureKey(quad.gtceu$getTextureKey()); } public static BakedQuad setColor(BakedQuad quad, int argbColor, boolean clearTintIndex) { @@ -94,11 +96,48 @@ public static BakedQuad setColor(BakedQuad quad, int argbColor, boolean clearTin return copy; } + public static IQuadTransformer derotate() { + return quad -> { + int[] vertices = quad.getVertices(); + + int start = 0; + float minU = Float.MAX_VALUE, minV = Float.MAX_VALUE; + int[][] uvs = (int[][]) Array.newInstance(int.class, 4, 2); + + for (int i = 0; i < 4; i++) { + int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.UV0; + System.arraycopy(vertices, offset, uvs[i], 0, 2); + + float u = Float.intBitsToFloat(uvs[i][0]); + float v = Float.intBitsToFloat(uvs[i][1]); + if (u <= minU && v <= minV) { + minU = Math.min(minU, u); + minV = Math.min(minV, v); + start = i; + } + } + for (int i = 0; i < 4; i++) { + int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.UV0; + System.arraycopy(uvs[(i + start) % 4], 0, vertices, offset, 2); + } + }; + } + public static BakedQuad copy(BakedQuad quad) { return new BakedQuad(quad.getVertices().clone(), quad.getTintIndex(), quad.getDirection(), quad.getSprite(), quad.isShade(), quad.hasAmbientOcclusion()) .gtceu$setTextureKey(quad.gtceu$getTextureKey()); } + public static int[] getPackedLights(BakedQuad quad) { + int[] vertices = quad.getVertices(); + + int[] lights = new int[4]; + for (int i = 0; i < 4; i++) { + lights[i] = vertices[i * IQuadTransformer.STRIDE + IQuadTransformer.UV2]; + } + return lights; + } + private GTQuadTransformers() {} } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java new file mode 100644 index 00000000000..f1b1d5404fa --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/InterpolationHelper.java @@ -0,0 +1,120 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import net.minecraft.util.Mth; + +/** + * @author covers1624 + */ +public class InterpolationHelper { + + private final float[][] posCache = new float[4][2]; + private final float[] valCache = new float[4]; + + private float x0; + private float x1; + private float y0; + private float y1; + + private float rX; + private float rY; + + private int p00; + private int p10; + private int p11; + private int p01; + + /** + * Resets the interpolation helper with the given quad. Does not care what order the vertices are in. + */ + public void reset(float dx0, float dy0, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) { + float[] vec0 = this.posCache[0]; + float[] vec1 = this.posCache[1]; + float[] vec2 = this.posCache[2]; + float[] vec3 = this.posCache[3]; + + vec0[0] = dx0; + vec1[0] = dx1; + vec2[0] = dx2; + vec3[0] = dx3; + + vec0[1] = dy0; + vec1[1] = dy1; + vec2[1] = dy2; + vec3[1] = dy3; + } + + /** + * Call when you are ready to use the interpolation helper. + */ + public void setup() { + this.p00 = 0; // Bottom Left is always first. + this.x0 = this.posCache[this.p00][0]; + this.y0 = this.posCache[this.p00][1]; + + for (int i = 1; i < 4; i++) { + float x = this.posCache[i][0]; + float y = this.posCache[i][1]; + + if (this.y0 == y) { + // Bottom right. + this.p10 = i; + this.x1 = x; + } else if (this.x0 == x) { + // Top left. + this.p01 = i; + this.y1 = y; + } else { + // Top right. + this.p11 = i; + } + } + } + + /** + * Computes the coefficients for the interpolation. + * + * @param x X interpolation location. + * @param y Y interpolation location. + */ + public void locate(float x, float y) { + this.rX = Mth.inverseLerp(x, this.x0, this.x1); + this.rY = Mth.inverseLerp(y, this.y0, this.y1); + } + + /** + * Interpolates using the already computed coefficients. + * + * @param q0 Value at dx0 dy0 + * @param q1 Value at dx1 dy1 + * @param q2 Value at dx2 dy2 + * @param q3 Value at dx3 dy3 + * @return The result. + */ + public float interpolate(float q0, float q1, float q2, float q3) { + this.valCache[0] = q0; + this.valCache[1] = q1; + this.valCache[2] = q2; + this.valCache[3] = q3; + float f0 = Mth.lerp(this.rX, this.valCache[this.p00], this.valCache[this.p10]); + float f1 = Mth.lerp(this.rX, this.valCache[this.p01], this.valCache[this.p11]); + + return Mth.lerp(this.rY, f0, f1); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java new file mode 100644 index 00000000000..9ca6980a74d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadClamper.java @@ -0,0 +1,106 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; + +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; + +import org.joml.Vector3f; + +/** + * This transformer simply clamps the vertices inside the provided box.
+ * You probably want to Re-Interpolate the UV's, Color, and Lightmap. For that, see {@link QuadReInterpolator}. + * + * @see QuadReInterpolator + * @author covers1624 + */ +public class QuadClamper implements QuadTransform { + + private final AABB clampBounds; + + private final Vector3f pos = new Vector3f(); + + public QuadClamper(AABB clampBounds) { + this.clampBounds = clampBounds; + } + + @Override + public boolean transform(MutableQuadView quad) { + Direction.Axis axis = quad.nominalFace().getAxis(); + + clamp(quad, this.clampBounds); + + // Check if the quad would be invisible and cull it. + float x1 = quad.posByIndex(0, xCoord(axis)); + float x2 = quad.posByIndex(1, xCoord(axis)); + float x3 = quad.posByIndex(2, xCoord(axis)); + float x4 = quad.posByIndex(3, xCoord(axis)); + + float y1 = quad.posByIndex(0, yCoord(axis)); + float y2 = quad.posByIndex(1, yCoord(axis)); + float y3 = quad.posByIndex(2, yCoord(axis)); + float y4 = quad.posByIndex(3, yCoord(axis)); + + // These comparisons are safe as we are comparing clamped values. + boolean flag1 = x1 == x2 && x2 == x3 && x3 == x4; + boolean flag2 = y1 == y2 && y2 == y3 && y3 == y4; + return !flag1 && !flag2; + } + + private void clamp(MutableQuadView quad, AABB bb) { + for (int i = 0; i < 4; i++) { + quad.copyPos(i, pos); + pos.set((float) Mth.clamp(pos.x(), bb.minX, bb.maxX), + (float) Mth.clamp(pos.y(), bb.minY, bb.maxY), + (float) Mth.clamp(pos.z(), bb.minZ, bb.maxZ)); + quad.pos(i, pos); + } + } + + /** + * Gets the 2d X coordinate for the given axis. + * + * @param axis The axis. side >> 1 + * @return The x coordinate. + */ + private static int xCoord(Direction.Axis axis) { + if (axis == Direction.Axis.Y) { + return 0; + } else { + return 2; + } + } + + /** + * Gets the 2d Y coordinate for the given axis. + * + * @param axis The axis. + * @return The y coordinate. + */ + private static int yCoord(Direction.Axis axis) { + if (axis != Direction.Axis.Y) { + return 1; + } else { + return 2; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java new file mode 100644 index 00000000000..fe849c4d525 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadCornerKicker.java @@ -0,0 +1,205 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; +import com.gregtechceu.gtceu.client.util.quad.GeometryHelper; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.Vec3i; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; + +import org.jetbrains.annotations.Nullable; + +import static net.minecraft.core.Direction.*; +import static net.minecraft.core.Direction.AxisDirection.*; + +/** + * This transformer is a little complicated. + * Basically, a Facade / Cover can use this to 'kick' the edges of quads in to fix Z-fighting in the corners. + *

+ * Use it by specifying + *

    + *
  • the side of the block you are on,
  • + *
  • the bitmask for where the other Facades / Covers are,
  • + *
  • the bounding box of the facade (NOT the hole piece),
  • + *
  • and the thickness of your Facade / Cover (which is used as the kick amount).
  • + *
+ * + * @author covers1624 + */ +public class QuadCornerKicker implements QuadTransform { + + public static final QuadCornerKicker INSTANCE = new QuadCornerKicker(); + + // Simple horizonal lookups. + public static Direction[][] horizonals = new Direction[][] { + // Around Y axis, NSWE. + { NORTH, SOUTH, WEST, EAST }, + { NORTH, SOUTH, WEST, EAST }, + + // Around Z axis, DUWE. + { DOWN, UP, WEST, EAST }, + { DOWN, UP, WEST, EAST }, + + // Around X axis, DUNS. + { DOWN, UP, NORTH, SOUTH }, + { DOWN, UP, NORTH, SOUTH } }; + + private Direction mySide; + private int facadeMask; + private AABB bounds; + private double thickness; + + public QuadCornerKicker() { + super(); + } + + /** + * Set's the side this Facade / Cover is attached to. + * + * @param side The side. + */ + public void setSide(Direction side) { + this.mySide = side; + } + + /** + * Sets the bitmask of Facades / Covers in the block space. + * This is as simple as {@code mask = (1 << side)}. + * + * @param mask The mask. + */ + public void setFacadeMask(int mask) { + this.facadeMask = mask; + } + + /** + * Sets the bounding box of the Facade / Cover, this should be the full box, not just a piece of the hole's 'ring'. + * + * @param bounds The bounding box. + */ + public void setBounds(AABB bounds) { + this.bounds = bounds; + } + + /** + * Sets the amount to kick the vertex in by, this is your facades thickness. + * + * @param thickness The thickness. + */ + public void setThickness(double thickness) { + this.thickness = thickness; + } + + @Override + public boolean transform(MutableQuadView quad) { + Direction side = quad.nominalFace(); + if (side == this.mySide || side == this.mySide.getOpposite()) { + return true; + } + for (Direction hoz : horizonals[this.mySide.get3DDataValue()]) { + if (side == hoz || side == hoz.getOpposite() || (this.facadeMask & (1 << hoz.ordinal())) == 0) { + continue; + } + Corner corner = Corner.fromSides(this.mySide.getOpposite(), side, hoz); + for (int i = 0; i < 4; i++) { + float x = quad.posByIndex(i, 0); + float y = quad.posByIndex(i, 1); + float z = quad.posByIndex(i, 2); + if (Mth.equal(x, corner.pX(this.bounds)) && Mth.equal(y, corner.pY(this.bounds)) && + Mth.equal(z, corner.pZ(this.bounds))) { + Vec3i normal = hoz.getNormal(); + x -= normal.getX() * this.thickness; + y -= normal.getY() * this.thickness; + z -= normal.getZ() * this.thickness; + quad.pos(i, x, y, z); + } + } + } + + return true; + } + + @Override + public void processInPlace(BakedQuad quad) {} + + public enum Corner { + + MIN_X_MIN_Y_MIN_Z(NEGATIVE, NEGATIVE, NEGATIVE), + MIN_X_MIN_Y_MAX_Z(NEGATIVE, NEGATIVE, POSITIVE), + MIN_X_MAX_Y_MIN_Z(NEGATIVE, POSITIVE, NEGATIVE), + MIN_X_MAX_Y_MAX_Z(NEGATIVE, POSITIVE, POSITIVE), + + MAX_X_MIN_Y_MIN_Z(POSITIVE, NEGATIVE, NEGATIVE), + MAX_X_MIN_Y_MAX_Z(POSITIVE, NEGATIVE, POSITIVE), + MAX_X_MAX_Y_MIN_Z(POSITIVE, POSITIVE, NEGATIVE), + MAX_X_MAX_Y_MAX_Z(POSITIVE, POSITIVE, POSITIVE); + + private final AxisDirection xAxis; + private final AxisDirection yAxis; + private final AxisDirection zAxis; + + public static final Corner[] VALUES = values(); + private static final int[] sideMask = { 0, 2, 0, 1, 0, 4 }; + + Corner(AxisDirection xAxis, AxisDirection yAxis, AxisDirection zAxis) { + this.xAxis = xAxis; + this.yAxis = yAxis; + this.zAxis = zAxis; + } + + /** + * Used to find what corner is at the 3 sides. + * This method assumes you pass in the X axis side, Y axis side, and Z axis side, + * it will NOT complain about an invalid side, you will just get garbage data. + * This method also does not care what order the 3 axes are in. + * + * @param sideA Side one. + * @param sideB Side two. + * @param sideC Side three. + * @return The corner at the 3 sides. + */ + public static Corner fromSides(@Nullable Direction sideA, + @Nullable Direction sideB, + @Nullable Direction sideC) { + int aIndex = GeometryHelper.toFaceIndex(sideA); + int bIndex = GeometryHelper.toFaceIndex(sideB); + int cIndex = GeometryHelper.toFaceIndex(sideC); + + // <3 Chicken-Bones. + return Corner.VALUES[sideMask[aIndex] | sideMask[bIndex] | sideMask[cIndex]]; + } + + public float pX(AABB box) { + return (float) (this.xAxis == NEGATIVE ? box.minX : box.maxX); + } + + public float pY(AABB box) { + return (float) (this.yAxis == NEGATIVE ? box.minY : box.maxY); + } + + public float pZ(AABB box) { + return (float) (this.zAxis == NEGATIVE ? box.minZ : box.maxZ); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java new file mode 100644 index 00000000000..bc3cf275201 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadReInterpolator.java @@ -0,0 +1,189 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.QuadView; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; + +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.core.Direction; + +/** + * This transformer Re-Interpolates the Color, UV's and LightMaps. Use this after all transformations that translate + * vertices in the pipeline. + *

+ * This Transformation can only be used in the BakedPipeline. + * + * @author covers1624 + */ +public class QuadReInterpolator implements QuadTransform { + + private final InterpolationHelper interpolationHelper = new InterpolationHelper(); + + private final int[] originalSpriteColor = new int[4]; + private final float[] originalSpriteU = new float[4]; + private final float[] originalSpriteV = new float[4]; + private final int[] originalSpriteLightmap = new int[4]; + + public QuadReInterpolator() { + super(); + } + + public void setInputQuad(QuadView quad) { + Direction.Axis axis = quad.nominalFace().getAxis(); + int xIndex = xCoord(axis); + int yIndex = yCoord(axis); + + interpolationHelper.reset( + quad.posByIndex(0, xIndex), quad.posByIndex(0, yIndex), + quad.posByIndex(1, xIndex), quad.posByIndex(1, yIndex), + quad.posByIndex(2, xIndex), quad.posByIndex(2, yIndex), + quad.posByIndex(3, xIndex), quad.posByIndex(3, yIndex)); + + // Save the original properties of the quad's vertices + for (int v = 0; v < 4; v++) { + originalSpriteColor[v] = quad.color(v); + originalSpriteU[v] = quad.u(v); + originalSpriteV[v] = quad.v(v); + originalSpriteLightmap[v] = quad.lightmap(v); + } + } + + @Override + public boolean transform(MutableQuadView quad) { + Direction.Axis axis = quad.nominalFace().getAxis(); + int xIndex = xCoord(axis); + int yIndex = yCoord(axis); + + this.interpolationHelper.setup(); + for (int i = 0; i < 4; i++) { + float x = quad.posByIndex(i, xIndex); + float y = quad.posByIndex(i, yIndex); + this.interpolationHelper.locate(x, y); + interpolateColorFrom(quad, i); + interpolateUVFrom(quad, i); + interpolateLightmapFrom(quad, i); + } + return true; + } + + /** + * Interpolates the new color values for this Vertex using the others as a reference. + */ + public void interpolateColorFrom(MutableQuadView quad, int vertexIndex) { + int p1 = this.originalSpriteColor[0]; + int p2 = this.originalSpriteColor[1]; + int p3 = this.originalSpriteColor[2]; + int p4 = this.originalSpriteColor[3]; + if (p1 == p2 && p2 == p3 && p3 == p4) { + return; // Don't bother for uniformly colored quads + } + + // Interpolate each color component separately + int color = 0; + int mask = 0xFF; + for (int i = 0; i < 4; i++) { + int p1c = p1 & mask; + int p2c = p2 & mask; + int p3c = p3 & mask; + int p4c = p4 & mask; + int interpolated = (int) interpolationHelper.interpolate(p1c, p2c, p3c, p4c); + color |= interpolated & mask; + mask <<= 8; + } + + quad.color(vertexIndex, color); + } + + /** + * Interpolates the new UV values for this Vertex using the others as a reference. + */ + public void interpolateUVFrom(MutableQuadView quad, int vertexIndex) { + float p1 = originalSpriteU[0]; + float p2 = originalSpriteU[1]; + float p3 = originalSpriteU[2]; + float p4 = originalSpriteU[3]; + float u = interpolationHelper.interpolate(p1, p2, p3, p4); + + p1 = originalSpriteV[0]; + p2 = originalSpriteV[1]; + p3 = originalSpriteV[2]; + p4 = originalSpriteV[3]; + float v = interpolationHelper.interpolate(p1, p2, p3, p4); + quad.uv(vertexIndex, u, v); + } + + /** + * Interpolates the new LightMap values for this Vertex using the others as a reference. + * + * @return The same Vertex. + */ + public void interpolateLightmapFrom(MutableQuadView quad, int vertexIndex) { + int p1 = originalSpriteLightmap[0]; + int p2 = originalSpriteLightmap[1]; + int p3 = originalSpriteLightmap[2]; + int p4 = originalSpriteLightmap[3]; + if (p1 == p2 && p2 == p3 && p3 == p4) { + return; // Don't bother for uniformly lit quads + } + + // Interpolate both lightmap components separately + int p1l = LightTexture.block(p1); + int p2l = LightTexture.block(p2); + int p3l = LightTexture.block(p3); + int p4l = LightTexture.block(p4); + int block = (int) interpolationHelper.interpolate(p1l, p2l, p3l, p4l); + + p1l = LightTexture.sky(p1); + p2l = LightTexture.sky(p2); + p3l = LightTexture.sky(p3); + p4l = LightTexture.sky(p4); + int sky = (int) interpolationHelper.interpolate(p1l, p2l, p3l, p4l); + + quad.lightmap(vertexIndex, block, sky); + } + + /** + * Gets the 2d X coordinate for the given axis. + * + * @param axis The axis. side >> 1 + * @return The x coordinate. + */ + private static int xCoord(Direction.Axis axis) { + if (axis == Direction.Axis.Y) { + return 0; + } else { + return 2; + } + } + + /** + * Gets the 2d Y coordinate for the given axis. + * + * @param axis The axis. + * @return The y coordinate. + */ + private static int yCoord(Direction.Axis axis) { + if (axis != Direction.Axis.Y) { + return 1; + } else { + return 2; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java new file mode 100644 index 00000000000..06a50545782 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/util/quad/transformers/QuadTinter.java @@ -0,0 +1,60 @@ +/* + * This file is part of CodeChickenLib. + * Copyright (c) 2018, covers1624, All rights reserved. + * + * CodeChickenLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * CodeChickenLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CodeChickenLib. If not, see . + */ +package com.gregtechceu.gtceu.client.util.quad.transformers; + +import com.gregtechceu.gtceu.client.model.quad.MutableQuadView; +import com.gregtechceu.gtceu.client.model.quad.transform.QuadTransform; + +/** + * This transformer tints quads. + */ +public class QuadTinter implements QuadTransform { + + private final int argb; + + public QuadTinter(int rgb) { + this.argb = 0xFF000000 | rgb; + } + + @Override + public boolean transform(MutableQuadView quad) { + // Nuke tintIndex. + quad.tintIndex(-1); + for (int i = 0; i < 4; i++) { + int color = quad.color(i); + color = multiplyColor(color, argb); + quad.color(i, color); + } + return true; + } + + private static int multiplyColor(int color1, int color2) { + if (color1 == -1) { + return color2; + } else if (color2 == -1) { + return color1; + } + + final int alpha = ((color1 >> 24) & 0xFF) * ((color2 >> 24) & 0xFF) / 0xFF; + final int red = ((color1 >> 16) & 0xFF) * ((color2 >> 16) & 0xFF) / 0xFF; + final int green = ((color1 >> 8) & 0xFF) * ((color2 >> 8) & 0xFF) / 0xFF; + final int blue = (color1 & 0xFF) * (color2 & 0xFF) / 0xFF; + + return (alpha << 24) | (red << 16) | (green << 8) | blue; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java index be3caf82361..ba3c179a040 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -12,6 +12,8 @@ import com.gregtechceu.gtceu.api.machine.feature.IDataInfoProvider; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; import com.gregtechceu.gtceu.api.sync_system.annotations.SyncToClient; +import com.gregtechceu.gtceu.client.particle.GTOverheatParticle; +import com.gregtechceu.gtceu.client.particle.GTParticleManager; import com.gregtechceu.gtceu.common.block.CableBlock; import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; import com.gregtechceu.gtceu.common.item.behavior.PortableScannerBehavior; @@ -32,8 +34,13 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import lombok.Getter; import org.jetbrains.annotations.NotNull; @@ -52,6 +59,8 @@ public class CableBlockEntity extends PipeBlockEntity currentEnergyNet = new WeakReference<>(null); + @SideOnly(Side.CLIENT) + private GTOverheatParticle particle; private static final int meltTemp = 3000; private final EnumMap handlers = new EnumMap<>(Direction.class); @@ -227,6 +236,27 @@ public boolean incrementAmperage(long amps, long voltage) { return false; } + @OnlyIn(Dist.CLIENT) + public boolean isParticleAlive() { + return particle != null && particle.isAlive(); + } + + @OnlyIn(Dist.CLIENT) + public void createParticle() { + particle = new GTOverheatParticle(this, meltTemp, + getPipeBlock().getShape(getBlockState(), level, getBlockPos(), CollisionContext.empty()), + getPipeType().insulationLevel >= 0); + GTParticleManager.INSTANCE.addEffect(particle); + } + + @OnlyIn(Dist.CLIENT) + public void killParticle() { + if (isParticleAlive()) { + particle.setExpired(); + particle = null; + } + } + public void applyHeat(int amount) { heatQueue += amount; if (!level.isClientSide && heatSubs == null && temperature + heatQueue > getDefaultTemp()) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java index 0fb295c79ce..92698e130bd 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java @@ -19,6 +19,7 @@ import com.gregtechceu.gtceu.common.block.*; import com.gregtechceu.gtceu.common.block.explosive.IndustrialTNTBlock; import com.gregtechceu.gtceu.common.block.explosive.PowderbarrelBlock; +import com.gregtechceu.gtceu.common.data.blocks.GTDevBlocks; import com.gregtechceu.gtceu.common.data.models.GTModels; import com.gregtechceu.gtceu.common.item.LampBlockItem; import com.gregtechceu.gtceu.common.item.LaserPipeBlockItem; @@ -1425,6 +1426,11 @@ public static void init() { // GCYM GCYMBlocks.init(); + + // Dev-only test blocks + if (GTCEu.isDev()) { + GTDevBlocks.init(); + } } private static void initializeCobbleReplacements() { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java new file mode 100644 index 00000000000..e0cca005d91 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/data/blocks/GTDevBlocks.java @@ -0,0 +1,19 @@ +package com.gregtechceu.gtceu.common.data.blocks; + +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; + +import com.tterrag.registrate.util.entry.BlockEntry; + +import static com.gregtechceu.gtceu.common.registry.GTRegistration.REGISTRATE; + +public class GTDevBlocks { + + public static final BlockEntry CTM_TEST = REGISTRATE.block("ctm_test", Block::new) + .lang("Connected Texture Test Block") + .properties(p -> p.noLootTable().sound(SoundType.SCULK)) + .simpleItem() + .register(); + + public static void init() {} +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java index d4cdf600f2c..6ba47cd12d2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTMachineModels.java @@ -598,7 +598,8 @@ public static MachineBuilder.ModelInitializer createHPCAPartModel(boolean advanc } public static final ResourceLocation OVERLAY_SCREEN_TEXTURE = GTCEu.id("block/overlay/machine/overlay_screen"); - public static final ResourceLocation OVERLAY_QTANK_EMISSIVE_TEXTURE = GTCEu.id("block/overlay/machine/overlay_qtank_emissive"); + public static final ResourceLocation OVERLAY_QTANK_EMISSIVE_TEXTURE = GTCEu + .id("block/overlay/machine/overlay_qtank_emissive"); public static MachineBuilder.ModelInitializer createFisherModel() { return (ctx, prov, builder) -> { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java index b0538ef1158..91fa2986d45 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java @@ -21,6 +21,7 @@ import com.gregtechceu.gtceu.api.recipe.modifier.RecipeModifier; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; import com.gregtechceu.gtceu.api.sync_system.annotations.SyncToClient; +import com.gregtechceu.gtceu.client.bloom.BloomRenderTicket; import com.gregtechceu.gtceu.common.block.FusionCasingBlock; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.gregtechceu.gtceu.utils.GTUtil; @@ -40,6 +41,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import lombok.Getter; +import lombok.Setter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,10 +79,14 @@ public class FusionReactorMachine extends WorkableElectricMultiblockMachine impl protected final NotifiableEnergyContainer energyContainer; @Getter @SyncToClient - private Integer color = -1; + private int color = 0xFFFFFFFF; @Nullable protected TickableSubscription preHeatSubs; + @Getter + @Setter + protected BloomRenderTicket registeredBloomTicket = BloomRenderTicket.INVALID; + public FusionReactorMachine(BlockEntityCreationInfo info, int tier) { super(info); this.tier = tier; diff --git a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java index 3248f0c11be..865638cacdb 100644 --- a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java +++ b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java @@ -2,13 +2,23 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.GTCEuAPI; +import com.gregtechceu.gtceu.client.bloom.BloomType; +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; import net.minecraft.commands.Commands; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraftforge.fml.loading.FMLPaths; import dev.toma.configuration.Configuration; +import dev.toma.configuration.client.IValidationHandler; import dev.toma.configuration.config.Config; import dev.toma.configuration.config.Configurable; import dev.toma.configuration.config.format.ConfigFormats; +import dev.toma.configuration.config.validate.ValidationResult; +import org.jetbrains.annotations.ApiStatus; + +import java.nio.file.Path; @Config(id = GTCEu.MOD_ID) public class ConfigHolder { @@ -16,14 +26,23 @@ public class ConfigHolder { public static ConfigHolder INSTANCE; private static final Object LOCK = new Object(); + @ApiStatus.Internal + public static dev.toma.configuration.config.ConfigHolder INTERNAL_INSTANCE; + public static void init() { synchronized (LOCK) { if (INSTANCE == null) { - INSTANCE = Configuration.registerConfig(ConfigHolder.class, ConfigFormats.yaml()).getConfigInstance(); + INTERNAL_INSTANCE = Configuration.registerConfig(ConfigHolder.class, ConfigFormats.yaml()); + INSTANCE = INTERNAL_INSTANCE.getConfigInstance(); } } } + public static ConfigHolder getInstance() { + init(); + return INSTANCE; + } + @Configurable public RecipeConfigs recipes = new RecipeConfigs(); @Configurable @@ -277,11 +296,11 @@ public static class MinimapCompatConfig { public String borderColor = "#00000000"; @Configurable - @Configurable.Comment({ "Which part of the screen to anchor buttons to", "Default: \"BOTTOM_LEFT\"" }) + @Configurable.Comment({ "Which part of the screen to anchor buttons to", "Default: BOTTOM_LEFT" }) public Anchor buttonAnchor = Anchor.BOTTOM_LEFT; @Configurable - @Configurable.Comment({ "Which direction the buttons will go", "Default: \"VERTICAL\"" }) + @Configurable.Comment({ "Which direction the buttons will go", "Default: VERTICAL" }) public Direction direction = Direction.VERTICAL; @Configurable @@ -789,8 +808,13 @@ public static class ClientConfigs { public int animationTime = 300; @Configurable public ArmorHud armorHud = new ArmorHud(); + + @Configurable + public RendererOptions renderer = new RendererOptions(); @Configurable - public RendererConfigs renderer = new RendererConfigs(); + @Configurable.Comment("Config options for bloom and other post-processing effects") + public BloomOptions bloom = new BloomOptions(); + @Configurable public TankItemFluidPreview tankItemFluidPreview = new TankItemFluidPreview(); @@ -816,6 +840,109 @@ public static class ArmorHud { public int hudOffsetY = 0; } + public static class BloomOptions { + + @Configurable + @Configurable.Comment({ "Bloom Algorithm", + "Requires reloading all chunks ", + "UNITY - Unity-like Bloom (rescale)", + "UNREAL - Unreal-like Bloom (gaussian blur)", + "DISABLED - No bloom", + "Default: UNREAL" }) + @Configurable.ValueUpdateCallback(method = "typeOptionChanged") + // @Configurable.Validator(BloomEventListeners.BloomTypeUpdateCallback.class) // for Configuration 3.x + public BloomType type = BloomType.UNREAL; + + @Configurable + @Configurable.Comment({ "Whether or not to add bloom to emissive textures", "Default: true" }) + public boolean emissiveTexturesHaveBloom = true; + + @Configurable + @Configurable.Comment({ + "The brightness after bloom should not exceed this value. It can be used to limit the brightness of highlights (e.g., daytime)", + "This value should be greater than minBrightness.", + "OUTPUT = BACKGROUND + BLOOM * strength * (base + min + (1 - BACKGROUND_BRIGHTNESS) * ({max} - min)))", + "Default: 0.5" }) + @Configurable.DecimalRange(min = 0) + public float maxBrightness = 0.5f; + + @Configurable + @Configurable.Comment({ + "The brightness after bloom should not smaller than this value. It can be used to limit the brightness of dusky parts (e.g., night/caves)", + "This value should be lower than maxBrightness.", + "OUTPUT = BACKGROUND + BLOOM * strength * (base + {min} + (1 - BACKGROUND_BRIGHTNESS) * (max - {min})))", + "Default: 0.2" }) + @Configurable.DecimalRange(min = 0) + public float minBrightness = 0.2f; + + @Configurable + @Configurable.Comment({ "The base brightness of the bloom.", "It is similar to strength", + "This value should be lower than maxBrightness.", + "OUTPUT = BACKGROUND + BLOOM * strength * ({base} + min + (1 - BACKGROUND_BRIGHTNESS) * (max - min)))", + "Default: 0.1" }) + @Configurable.DecimalRange(min = 0) + public float baseBrightness = 0.1f; + + @Configurable + @Configurable.Comment({ "Bloom Strength", + "OUTPUT = BACKGROUND + BLOOM * {strength} * (base + min + (1 - BACKGROUND_BRIGHTNESS) * (max - min)))", + "Default: 1.5" }) + @Configurable.DecimalRange(min = 0) + public float strength = 1.5f; + + @Configurable + @Configurable.Comment({ "Blur Step (bloom range)", "Default: 1" }) + @Configurable.DecimalRange(min = 0) + public float step = 1.0f; + + // used by bloomType field's value update callback + @SuppressWarnings("unused") + private void typeOptionChanged(BloomType newType, IValidationHandler validationHandler) { + if (!BloomShaderManager.initPostShaders()) { + // failed to load post shaders + + Path gameDir = FMLPaths.GAMEDIR.get().toAbsolutePath(); + Path logFile = gameDir.resolve(Path.of("logs", "latest.log")); + Component latestLogClickable = Component.literal(gameDir.relativize(logFile).toString()) + .withStyle((style) -> style.withUnderlined(true) + .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, + logFile.toFile().toString()))); + + validationHandler.setValidationResult(ValidationResult.warn(Component.translatable( + "config.gtceu.option.bloomType.load_error", latestLogClickable))); + } else { + // post shader loaded successfully + validationHandler.setOkStatus(); + } + } + } + + public static class RendererOptions { + + @Configurable + @Configurable.Comment({ "Render fluids in multiblocks that support them?", "Default: true" }) + public boolean renderFluids = true; + + @Configurable + @Configurable.Comment({ "Render growing plants in multiblocks that support them?", "Default: true" }) + public boolean renderGrowingPlants = true; + + @Configurable + @Configurable.Comment({ "Whether or not to color material/ore block highlights in the material color", + "Default: true" }) + public boolean coloredMaterialBlockOutline = true; + + @Configurable + @Configurable.Comment({ "Whether or not to color tiered machine highlights in the tier color", + "Default: true" }) + public boolean coloredTieredMachineOutline = true; + + @Configurable + @Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier", + "Default: true" }) + public boolean coloredWireOutline = true; + } + public static class TankItemFluidPreview { @Configurable @@ -851,30 +978,4 @@ public static class DeveloperConfigs { "Only works in a development environment", "Default: false" }) public boolean autoRebuildResources = false; } - - public static class RendererConfigs { - - @Configurable - @Configurable.Comment({ "Render fluids in multiblocks that support them?", "Default: true" }) - public boolean renderFluids = true; - - @Configurable - @Configurable.Comment({ "Render growing plants in multiblocks that support them?", "Default: true" }) - public boolean renderGrowingPlants = true; - - @Configurable - @Configurable.Comment({ "Whether or not to color material/ore block highlights in the material color", - "Default: true" }) - public boolean coloredMaterialBlockOutline = true; - - @Configurable - @Configurable.Comment({ "Whether or not to color tiered machine highlights in the tier color", - "Default: true" }) - public boolean coloredTieredMachineOutline = true; - - @Configurable - @Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier or material color", - "Default: true" }) - public boolean coloredWireOutline = true; - } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/config/GTEarlyConfig.java b/src/main/java/com/gregtechceu/gtceu/core/config/GTEarlyConfig.java new file mode 100644 index 00000000000..bbf13645eac --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/config/GTEarlyConfig.java @@ -0,0 +1,349 @@ +package com.gregtechceu.gtceu.core.config; + +import net.minecraftforge.fml.loading.FMLLoader; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.util.*; + +/** + * An early (e.g. mixin) config handler based on the one from ModernFix + */ +public class GTEarlyConfig { + + public static final String SAFE_MODE = "client.bloom.safe_mode."; + + private static final Logger LOGGER = LogManager.getLogger("GTEarlyConfig"); + + private final Map options = new HashMap<>(); + private final File configFile; + + private GTEarlyConfig(File file) { + this.configFile = file; + + // 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. + + Option option = addMixinRule(SAFE_MODE, false); + option.addComment( + "Whether to use a 'safe mode' for bloom rendering", + "NOTE: considerably slower than the normal logic, but likely fixes compatibility issues with other mods.", + "Requires restarting the client to take effect."); + + addDelegateRule("client.bloom.safemode", SAFE_MODE, false); + addDelegateRule("client.bloom.normal", SAFE_MODE, true); + + // hidden rules for dev-only mixins + addHiddenRule("dev", !FMLLoader.isProduction()); + addHiddenRule("dev.datagen", FMLLoader.getLaunchHandler().isData()); + + // hidden rules for mod dependencies + enableIfModPresent("emi", "emi"); + enableIfModPresent("jei", "jei"); + enableIfModPresent("rei", "roughlyenoughitems"); + + final String[] EMBEDDIUM_MOD_IDS = { "embeddium", "sodium" }; + final String[] OCULUS_MOD_IDS = { "oculus", "iris" }; + enableIfModPresent("embeddium", EMBEDDIUM_MOD_IDS); + enableIfModPresent("oculus", OCULUS_MOD_IDS); + enableIfModPresent("client.bloom.normal.embeddium", EMBEDDIUM_MOD_IDS); + enableIfModPresent("client.bloom.normal.oculus", OCULUS_MOD_IDS); + enableIfModPresent("client.bloom.safemode.embeddium", EMBEDDIUM_MOD_IDS); + + enableIfModPresent("top", "top"); + + enableIfModPresent("ftbchunks", "ftbchunks"); + enableIfModPresent("xaerominimap", "xaerominimap"); + enableIfModPresent("xaeroworldmap", "xaeroworldmap"); + + // bind non-empty parents + for (Map.Entry entry : this.options.entrySet()) { + if (entry.getValue().getParent() != null) continue; + + int idx = entry.getKey().lastIndexOf('.'); + if (idx <= 0) continue; + + String potentialParentKey = entry.getKey().substring(0, idx); + Option potentialParent = this.options.get(potentialParentKey); + if (potentialParent != null) { + entry.getValue().setParent(potentialParent); + } + } + } + + private void disableIfModPresent(String configName, String... ids) { + Option option = this.options.get(configName); + if (option == null) { + option = addMixinRule(configName, true); + } + + for (String id : ids) { + if (isModLoaded(id)) { + option.addModOverride(false, id); + } + } + } + + // opposite of disableIfModPresent + private void enableIfModPresent(String configName, String... ids) { + Option option = this.options.get(configName); + if (option == null) { + option = addMixinRule(configName, false); + } + option.setHidden(true); + + for (String id : ids) { + if (isModLoaded(id)) { + option.addModOverride(true, id); + } + } + } + + /** + * Defines a Mixin rule which can be configured by users and other mods. + * + * @param configName 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 + * + * @throws IllegalStateException If a rule with that name already exists + */ + private Option addMixinRule(String configName, boolean enabled) { + if (configName.endsWith(".")) configName = configName.substring(0, configName.length() - 1); + + Option option = new Option(configName, enabled, false); + if (this.options.putIfAbsent(configName, option) != null) { + throw new IllegalStateException("Mixin rule already defined: " + configName); + } + return option; + } + + /** + * Defines a Mixin rule which can be configured by users and other mods. + * + * @param configName 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 + * + * @throws IllegalStateException If a rule with that name already exists + */ + private Option addHiddenRule(String configName, boolean enabled) { + Option option = addMixinRule(configName, enabled); + option.setHidden(true); + return option; + } + + /** + * Defines a Mixin rule which directly relegates to another (existing) mixin rule. + * + * @param configName The name of the mixin package which will be controlled by this rule + * @param delegateName The name of the (existing) rule which this rule delegates to + * @param invert Whether to invert {@code delegateName}'s enabled state + * + * @throws IllegalStateException If a rule with that name already exists + * @throws IllegalArgumentException If a rule named {@code delegateName} doesn't already exist + */ + private Option addDelegateRule(String configName, String delegateName, boolean invert) { + if (delegateName.endsWith(".")) delegateName = delegateName.substring(0, delegateName.length() - 1); + + Option delegateOption = this.options.get(delegateName); + if (delegateOption == null) { + throw new IllegalArgumentException("Delegate rule not defined: " + delegateName); + } + + Option option = addHiddenRule(configName, delegateOption.isEnabled() != invert); + option.setParent(delegateOption); + option.setParentValueInverted(invert); + + return option; + } + + 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; + } + if (option.isHidden()) { + 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 (!option.isModDefined()) { + option.setEnabled(enabled, true); + } else { + LOGGER.warn("Option '{}' already disabled by a mod. Ignoring user configuration", key); + } + } + } + + /** + * 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 + * an 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 @Nullable Option getEffectiveOptionForMixin(String mixinClassName) { + int lastSplit = 0; + int nextSplit; + + Option rule = null; + + while ((nextSplit = mixinClassName.indexOf('.', lastSplit)) != -1) { + String key = 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 GTEarlyConfig load(File file) { + GTEarlyConfig config = new GTEarlyConfig(file); + Properties props = new Properties(); + if (file.exists()) { + try (FileInputStream fin = new FileInputStream(file)) { + props.load(fin); + } catch (IOException e) { + throw new RuntimeException("Could not load config file", e); + } + config.readProperties(props); + } + + try { + config.save(); + } catch (IOException e) { + LOGGER.warn("Could not write configuration file", e); + } + + return config; + } + + public void save() throws IOException { + File dir = configFile.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(configFile)) { + writer.write("# This is the early configuration file for GregTech CEu Modern.\n"); + writer.write("# The following options can be enabled or disabled if there is a compatibility issue.\n"); + writer.write( + "# Add a line with your option name and =true or =false at the bottom of the file to enable\n"); + writer.write("# or disable a rule. For example:\n"); + writer.write("# client.bloom.safe_mode=true\n"); + writer.write("# Do not include the #. You may reset to defaults by deleting this file.\n"); + writer.write("#\n"); + writer.write("# Available options:\n"); + var entries = this.options.entrySet().stream() + .filter(entry -> !entry.getValue().isHidden()) + .sorted() + .toList(); + + for (var entry : entries) { + String line = entry.getKey(); + Option option = entry.getValue(); + + String extraContext; + if (!option.isUserDefined()) { + extraContext = "=" + option.isEnabled() + " # " + + (option.isModDefined() ? "(overridden for mod compat)" : "(default)"); + } else { + extraContext = "=" + option.isDefaultEnabled() + " # (default)"; + } + + writer.write("#\n"); + if (option.getComment() != null) { + for (String commentLine : option.getComment()) { + writer.write("# # " + commentLine + "\n"); + } + } + writer.write("# " + line + extraContext + "\n"); + } + + writer.write("#\n"); + writer.write("#\n"); + writer.write("# User overrides go here.\n"); + + for (var entry : entries) { + Option option = entry.getValue(); + if (option.isUserDefined()) { + writer.write(entry.getKey() + "=" + option.isEnabled() + "\n"); + } + } + } + } + + public int getOptionCount() { + return this.options.size(); + } + + public int getOptionOverrideCount() { + return (int) this.options.values() + .stream() + .filter(option -> !option.isHidden()) + .filter(Option::isOverridden) + .count(); + } + + public Map getOptionMap() { + return Collections.unmodifiableMap(this.options); + } + + public static boolean isModLoaded(String modId) { + if (modId.equals("optifine")) { + return OPTIFINE_PRESENT; + } else { + return FMLLoader.getLoadingModList().getModFileById(modId) != null; + } + } + + public static final boolean OPTIFINE_PRESENT; + + static { + boolean hasOfClass = false; + try { + Class.forName("optifine.OptiFineTransformationService"); + hasOfClass = true; + } catch (Throwable ignored) {} + + OPTIFINE_PRESENT = hasOfClass; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/config/Option.java b/src/main/java/com/gregtechceu/gtceu/core/config/Option.java new file mode 100644 index 00000000000..5d701c1e9ec --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/config/Option.java @@ -0,0 +1,110 @@ +package com.gregtechceu.gtceu.core.config; + +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class Option { + + @Getter + private final String name; + @Getter + private final boolean defaultEnabled; + @Getter + private @Nullable List comment = null; + + private @Nullable Set modDefined = null; + private boolean enabled; + @Getter + private boolean userDefined; + @Getter + @Setter + private @Nullable Option parent = null; + @Getter + @Setter + private boolean hidden; + @Setter + private boolean parentValueInverted; + + public Option(String name, boolean enabled, boolean userDefined) { + this.name = name; + this.defaultEnabled = enabled; + + this.enabled = enabled; + this.userDefined = userDefined; + } + + public void setEnabled(boolean enabled, boolean userDefined) { + if (this.enabled == enabled) return; + + this.enabled = enabled; + this.userDefined = userDefined; + } + + public void addModOverride(boolean enabled, String modId) { + if (this.enabled == enabled) return; + + this.enabled = enabled; + + if (this.modDefined == null) { + this.modDefined = new LinkedHashSet<>(); + } + + this.modDefined.add(modId); + } + + public void addComment(String... comment) { + if (this.comment == null) { + this.comment = new ArrayList<>(); + } + Collections.addAll(this.comment, comment); + } + + public int getDepth() { + if (this.parent == null) return 0; + else return this.parent.getDepth() + 1; + } + + public boolean isEnabled() { + if (this.hidden && this.parent != null) { + return this.parent.isEnabled() != parentValueInverted; + } + return this.enabled; + } + + /** + * Checks if this option will effectively be disabled (regardless of its own status) + * by the parent rule being disabled. + */ + public boolean isEffectivelyDisabledByParent() { + return this.parent != null && + (!this.parent.enabled || this.parent.isEffectivelyDisabledByParent()) != parentValueInverted; + } + + public boolean isOverridden() { + return this.isUserDefined() || this.isModDefined() || (this.hidden && this.parent != null); + } + + public boolean isModDefined() { + return this.modDefined != null; + } + + public String getSelfName() { + if (this.parent == null) return this.name; + else return this.name.substring(this.parent.getName().length() + 1); + } + + public void clearModsDefiningValue() { + this.modDefined = null; + } + + public void clearUserDefined() { + this.userDefined = false; + } + + public Collection getDefiningMods() { + return this.modDefined != null ? Collections.unmodifiableCollection(this.modDefined) : Collections.emptyList(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/config/package-info.java b/src/main/java/com/gregtechceu/gtceu/core/config/package-info.java new file mode 100644 index 00000000000..a6db9225c91 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/config/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.core.config; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/GTMixinPlugin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/GTMixinPlugin.java index a6a55a1d653..db567a4aa79 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/GTMixinPlugin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/GTMixinPlugin.java @@ -1,73 +1,81 @@ package com.gregtechceu.gtceu.core.mixins; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.loading.FMLLoader; -import net.minecraftforge.fml.loading.LoadingModList; +import com.gregtechceu.gtceu.core.config.GTEarlyConfig; +import com.gregtechceu.gtceu.core.config.Option; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.UnknownNullability; import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.io.File; +import java.util.*; + +import static com.gregtechceu.gtceu.core.config.GTEarlyConfig.OPTIFINE_PRESENT; public class GTMixinPlugin implements IMixinConfigPlugin { - @Override - public void onLoad(String mixinPackage) {} + public static final Logger LOGGER = LogManager.getLogger("GregTechCEu"); - @Override - public String getRefMapperConfig() { - return null; - } + public static final String MIXIN_PACKAGE_ROOT = "com.gregtechceu.gtceu.core.mixins."; - private static final String MIXIN_PACKAGE = "com.gregtechceu.gtceu.core.mixins."; - private static final Map MOD_COMPAT_MIXINS = new HashMap<>(); + public static @UnknownNullability GTEarlyConfig CONFIG = null; + + public GTMixinPlugin() { + if (CONFIG != null) { + return; + } - private static final String DEV_PACKAGE = "dev."; - private static final String DATAGEN_PACKAGE = "datagen."; + try { + CONFIG = GTEarlyConfig.load(new File("./config/gtceu-early.properties")); + } catch (Exception e) { + throw new RuntimeException("Could not load mixin configuration file for GTCEu", e); + } - static { - MOD_COMPAT_MIXINS.put("roughlyenoughitems", "rei."); - addModCompatMixin("emi"); - addModCompatMixin("jei"); - addModCompatMixin("top"); - addModCompatMixin("ftbchunks"); - addModCompatMixin("xaerominimap"); - addModCompatMixin("xaeroworldmap"); + if (OPTIFINE_PRESENT) { + LOGGER.fatal( + "OptiFine detected. Use of GTCEu with OptiFine is not supported due to its breakage of Forge features."); + } } @Override public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - if (!mixinClassName.startsWith(MIXIN_PACKAGE)) { - // skip checking mixins that aren't in our package - // this should never happen, but better safe than sorry - return true; - } - mixinClassName = mixinClassName.substring(MIXIN_PACKAGE.length()); - - if (mixinClassName.startsWith(DEV_PACKAGE)) { - if (FMLLoader.isProduction()) { - // don't load dev-only mixins in prod - return false; - } - mixinClassName = mixinClassName.substring(DEV_PACKAGE.length()); - if (mixinClassName.startsWith(DATAGEN_PACKAGE)) { - // only load datagen mixins in datagen - return FMLLoader.getLaunchHandler().isData(); - } - return true; + if (!mixinClassName.startsWith(MIXIN_PACKAGE_ROOT)) { + LOGGER.error("Expected mixin '{}' to start with package root '{}', treating as foreign and disabling!", + mixinClassName, MIXIN_PACKAGE_ROOT); + + return false; } - for (var compatMod : MOD_COMPAT_MIXINS.entrySet()) { - if (mixinClassName.startsWith(compatMod.getValue())) { - return isModLoaded(compatMod.getKey()); - } + + String mixin = mixinClassName.substring(MIXIN_PACKAGE_ROOT.length()); + + if (!isOptionEnabled(mixin)) { + return false; } + return true; } + public static boolean isOptionEnabled(String mixin) { + Option option = CONFIG.getEffectiveOptionForMixin(mixin); + if (option == null) { + // if the mixin doesn't have an option, it's always enabled + return true; + } + + return option.isEnabled(); + } + + @Override + public void onLoad(String mixinPackage) {} + + @Override + public String getRefMapperConfig() { + return null; + } + @Override public void acceptTargets(Set myTargets, Set otherTargets) {} @@ -81,15 +89,4 @@ public void preApply(String targetClassName, ClassNode targetClass, String mixin @Override public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} - - private static void addModCompatMixin(String modId) { - MOD_COMPAT_MIXINS.put(modId, modId + "."); - } - - private static boolean isModLoaded(String modId) { - if (ModList.get() == null) { - return LoadingModList.get().getModFileById(modId) != null; - } - return ModList.get().isLoaded(modId); - } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableResourceManagerAccessor.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableResourceManagerAccessor.java new file mode 100644 index 00000000000..1aae111b199 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableResourceManagerAccessor.java @@ -0,0 +1,16 @@ +package com.gregtechceu.gtceu.core.mixins; + +import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.ReloadableResourceManager; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(ReloadableResourceManager.class) +public interface ReloadableResourceManagerAccessor { + + @Accessor + List getListeners(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/BakedQuadMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/BakedQuadMixin.java index ea2fadc9922..9b137439356 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/BakedQuadMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/BakedQuadMixin.java @@ -1,15 +1,16 @@ package com.gregtechceu.gtceu.core.mixins.client; -import com.gregtechceu.gtceu.core.IGTBakedQuad; +import com.gregtechceu.gtceu.core.util.extensions.BakedQuadExt; import net.minecraft.client.renderer.block.model.BakedQuad; import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.*; + +import java.util.Arrays; @Mixin(BakedQuad.class) -public class BakedQuadMixin implements IGTBakedQuad { +public class BakedQuadMixin implements BakedQuadExt { @Unique private String gtceu$textureKey = null; @@ -24,4 +25,34 @@ public class BakedQuadMixin implements IGTBakedQuad { public String gtceu$getTextureKey() { return gtceu$textureKey; } + + // @Intrinsic means this'll be skipped if someone else does it too + @Intrinsic + public boolean equals(Object o) { + if (!(o instanceof BakedQuad that)) return false; + + return self().isShade() == that.isShade() && + self().hasAmbientOcclusion() == that.hasAmbientOcclusion() && + self().getTintIndex() == that.getTintIndex() && + self().getDirection() == that.getDirection() && + self().getSprite() == that.getSprite() && + Arrays.equals(self().getVertices(), that.getVertices()); + } + + @Intrinsic + public int hashCode() { + int result = Boolean.hashCode(self().isShade()); + result = 31 * result + Boolean.hashCode(self().hasAmbientOcclusion()); + result = 31 * result + self().getTintIndex(); + result = 31 * result + self().getDirection().hashCode(); + result = 31 * result + self().getSprite().hashCode(); + result = 31 * result + Arrays.hashCode(self().getVertices()); + + return result; + } + + @Intrinsic + private BakedQuad self() { + return (BakedQuad) (Object) this; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java index fe2adab665c..55d69972b59 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java @@ -22,7 +22,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.BlockDestructionProgress; import net.minecraft.util.FastColor; -import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; @@ -32,8 +31,6 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.model.data.ModelData; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; @@ -55,7 +52,6 @@ import java.util.*; @Mixin(value = LevelRenderer.class, priority = 500) -@OnlyIn(Dist.CLIENT) public abstract class LevelRendererMixin { @Shadow @@ -73,9 +69,6 @@ public abstract class LevelRendererMixin { @Shadow private @Nullable ClientLevel level; - @Unique - private final RandomSource gtceu$modelRandom = RandomSource.create(); - @Inject(method = "renderLevel", at = @At("HEAD")) private void renderLevel(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java new file mode 100644 index 00000000000..bd8aef34c66 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelBakerImplMixin.java @@ -0,0 +1,31 @@ +package com.gregtechceu.gtceu.core.mixins.client; + +import com.gregtechceu.gtceu.client.util.SpriteFunctionWrapper; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.resources.ResourceLocation; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.function.Function; + +@Mixin(targets = { "net.minecraft.client.resources.model.ModelBakery$ModelBakerImpl" }) +public abstract class ModelBakerImplMixin { + + // the parameters aren't remapped because Parchment can't remap Forge's patches + @SuppressWarnings("NameDoesntMatchTargetClass") + // Note: We don't remap this method as it's added by forge + @ModifyVariable(at = @At("HEAD"), + method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", + argsOnly = true, + remap = false) + private Function gtceu$injectTextureScraper(Function spriteGetter, + ResourceLocation modelLocation, + ModelState transform) { + return new SpriteFunctionWrapper(spriteGetter, modelLocation); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/RenderStateShardAccessor.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/RenderStateShardAccessor.java new file mode 100644 index 00000000000..52d2cd2d926 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/RenderStateShardAccessor.java @@ -0,0 +1,13 @@ +package com.gregtechceu.gtceu.core.mixins.client; + +import net.minecraft.client.renderer.RenderStateShard; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(RenderStateShard.class) +public interface RenderStateShardAccessor { + + @Accessor("name") + String getName(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java new file mode 100644 index 00000000000..e06a756efb9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/TextureAtlasMixin.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 com.gregtechceu.gtceu.core.mixins.client; + +import com.gregtechceu.gtceu.client.model.quad.SpriteFinder; + +import net.minecraft.client.renderer.texture.SpriteLoader; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; + +import org.jetbrains.annotations.NotNull; +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.Map; + +@Mixin(TextureAtlas.class) +public class TextureAtlasMixin implements SpriteFinder.SpriteFinderAccess { + + @Shadow + private Map texturesByName; + + @Unique + private SpriteFinder gtceu$spriteFinder = null; + + @Inject(at = @At("TAIL"), method = "upload") + private void uploadHook(SpriteLoader.Preparations preparations, CallbackInfo info) { + gtceu$spriteFinder = null; + } + + @Override + public @NotNull SpriteFinder gtceu$spriteFinder() { + if (this.gtceu$spriteFinder == null) { + this.gtceu$spriteFinder = new SpriteFinder(texturesByName, (TextureAtlas) (Object) this); + } + return this.gtceu$spriteFinder; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/VertexConsumerMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/VertexConsumerMixin.java new file mode 100644 index 00000000000..d89a7c203ba --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/VertexConsumerMixin.java @@ -0,0 +1,9 @@ +package com.gregtechceu.gtceu.core.mixins.client; + +import com.gregtechceu.gtceu.core.util.extensions.VertexConsumerExt; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(VertexConsumer.class) +public interface VertexConsumerMixin extends VertexConsumerExt {} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/ForgeModelBlockRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/ForgeModelBlockRendererMixin.java new file mode 100644 index 00000000000..e0995818396 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/ForgeModelBlockRendererMixin.java @@ -0,0 +1,33 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.lighting.ForgeModelBlockRenderer; +import net.minecraftforge.client.model.lighting.QuadLighter; + +import com.llamalad7.mixinextras.expression.Definition; +import com.llamalad7.mixinextras.expression.Expression; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(value = ForgeModelBlockRenderer.class, remap = false) +public class ForgeModelBlockRendererMixin { + + @Definition(id = "setup", + method = "Lnet/minecraftforge/client/model/lighting/QuadLighter;setup(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V") + // we don't really care about the args, but it's better to define them than not; less likely to break this way + @Definition(id = "level", local = @Local(type = BlockAndTintGetter.class, argsOnly = true)) + @Definition(id = "pos", local = @Local(type = BlockPos.class, argsOnly = true)) + @Definition(id = "state", local = @Local(type = BlockState.class, argsOnly = true)) + @Expression("@(?).setup(level, pos, state)") + @ModifyExpressionValue(method = "render", at = @At(value = "MIXINEXTRAS:EXPRESSION")) + private static QuadLighter gtceu$setQuadLighterRenderType(QuadLighter lighter, + @Local(argsOnly = true) RenderType renderType) { + lighter.gtceu$setRenderType(renderType); + return lighter; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/GameRendererAccessor.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/GameRendererAccessor.java new file mode 100644 index 00000000000..50d9a1a0bef --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/GameRendererAccessor.java @@ -0,0 +1,13 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import net.minecraft.client.renderer.GameRenderer; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GameRenderer.class) +public interface GameRendererAccessor { + + @Accessor + int getTick(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/LevelRendererAccessor.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/LevelRendererAccessor.java new file mode 100644 index 00000000000..04ffcfad5ac --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/LevelRendererAccessor.java @@ -0,0 +1,17 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.RenderType; + +import com.mojang.blaze3d.vertex.PoseStack; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(LevelRenderer.class) +public interface LevelRendererAccessor { + + @Invoker + void invokeRenderChunkLayer(RenderType renderType, PoseStack poseStack, double camX, double camY, double camZ, + Matrix4f projectionMatrix); +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/LevelRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/LevelRendererMixin.java new file mode 100644 index 00000000000..2eda3f3cf2d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/LevelRendererMixin.java @@ -0,0 +1,26 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; + +import net.minecraft.client.renderer.LevelRenderer; + +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 = LevelRenderer.class) +public abstract class LevelRendererMixin { + + @Inject(method = "resize", at = @At("TAIL")) + private void gtceu$resizeBloomChain(int width, int height, CallbackInfo ci) { + if (BloomShaderManager.BLOOM_CHAIN != null) { + BloomShaderManager.BLOOM_CHAIN.resize(width, height); + } + } + + @Inject(method = "graphicsChanged", at = @At(value = "HEAD")) + private void gtceu$reinitBloomEffect(CallbackInfo ci) { + BloomShaderManager.initPostShaders(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/ModelBlockRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/ModelBlockRendererMixin.java new file mode 100644 index 00000000000..2e1e2c3df07 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/ModelBlockRendererMixin.java @@ -0,0 +1,65 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import com.gregtechceu.gtceu.client.bloom.BloomRenderer; +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.utils.ScopedValue; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.ModelData; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.blaze3d.vertex.*; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ModelBlockRenderer.class) +public class ModelBlockRendererMixin { + + @Unique + private static final ThreadLocal> gtceu$currentRenderType = ThreadLocal + .withInitial(ScopedValue.Object::new); + + @WrapMethod(method = { + "tesselateWithAO(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V", + "tesselateWithoutAO(Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;ZLnet/minecraft/util/RandomSource;JILnet/minecraftforge/client/model/data/ModelData;Lnet/minecraft/client/renderer/RenderType;)V" + }, remap = false) + private void gtceu$copyBloomQuads$1(BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, + PoseStack poseStack, VertexConsumer consumer, boolean checkSides, + RandomSource random, long seed, int packedOverlay, + ModelData modelData, RenderType renderType, + Operation original) { + try (var $ = gtceu$currentRenderType.get().with(renderType)) { + original.call(level, model, state, pos, poseStack, consumer, checkSides, random, seed, packedOverlay, + modelData, renderType); + } + } + + // The arguments don't have locals, so there's no good way to capture them except a @WarpWith(Condition) injector + @WrapOperation(method = "putQuadData", + at = @At(value = "INVOKE", + target = "Lcom/mojang/blaze3d/vertex/VertexConsumer;putBulkData(Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lnet/minecraft/client/renderer/block/model/BakedQuad;[FFFF[IIZ)V")) + private void gtceu$copyBloomQuads(VertexConsumer consumer, PoseStack.Pose pose, BakedQuad quad, + float[] colorMuls, float red, float green, float blue, + int[] combinedLights, int combinedOverlay, boolean mulColor, + Operation original) { + original.call(consumer, pose, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); + + if (!BloomShaderManager.isBloomActive()) return; + + RenderType renderType = gtceu$currentRenderType.get().getValue(); + BloomRenderer.copyBloomQuad(quad, combinedLights, renderType, bloomVertexConsumer -> { + original.call(bloomVertexConsumer, pose, quad, colorMuls, red, green, blue, + combinedLights, combinedOverlay, mulColor); + }); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/PostChainAccessor.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/PostChainAccessor.java new file mode 100644 index 00000000000..044f5afc58d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/PostChainAccessor.java @@ -0,0 +1,16 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import net.minecraft.client.renderer.PostChain; +import net.minecraft.client.renderer.PostPass; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(PostChain.class) +public interface PostChainAccessor { + + @Accessor + List getPasses(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/QuadLighterMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/QuadLighterMixin.java new file mode 100644 index 00000000000..d634eb5a5df --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/QuadLighterMixin.java @@ -0,0 +1,50 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import com.gregtechceu.gtceu.client.bloom.BloomRenderer; +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.core.util.extensions.QuadLighterExt; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraftforge.client.model.lighting.QuadLighter; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; + +@SuppressWarnings("SameReturnValue") +@Mixin(value = QuadLighter.class, remap = false) +public class QuadLighterMixin implements QuadLighterExt { + + @Unique + private @Nullable RenderType gtceu$renderType; + + @WrapOperation(method = "process", + at = @At(value = "INVOKE", + target = "Lcom/mojang/blaze3d/vertex/VertexConsumer;putBulkData(Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lnet/minecraft/client/renderer/block/model/BakedQuad;[FFFF[IIZ)V", + remap = true)) + private void gtceu$copyBloomQuads(VertexConsumer consumer, PoseStack.Pose pose, BakedQuad quad, + float[] colorMuls, float red, float green, float blue, + int[] combinedLights, int combinedOverlay, boolean mulColor, + Operation original) { + original.call(consumer, pose, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); + + if (this.gtceu$renderType == null) return; + if (!BloomShaderManager.isBloomActive()) return; + + BloomRenderer.copyBloomQuad(quad, combinedLights, this.gtceu$renderType, bloomVertexConsumer -> { + original.call(bloomVertexConsumer, pose, quad, colorMuls, red, green, blue, + combinedLights, combinedOverlay, mulColor); + }); + } + + @Override + public void gtceu$setRenderType(RenderType currentRenderType) { + this.gtceu$renderType = currentRenderType; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/RebuildTaskMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/RebuildTaskMixin.java new file mode 100644 index 00000000000..c56c2c1ff5d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/RebuildTaskMixin.java @@ -0,0 +1,72 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom; + +import com.gregtechceu.gtceu.client.bloom.BloomRenderer; +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; + +import com.gregtechceu.gtceu.core.config.GTEarlyConfig; +import com.gregtechceu.gtceu.core.mixins.GTMixinPlugin; +import net.minecraft.client.renderer.ChunkBufferBuilderPack; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +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.Set; +import java.util.function.Supplier; + +@Mixin(targets = "net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$RenderChunk$RebuildTask") +public abstract class RebuildTaskMixin { + + @Shadow(aliases = { "this$1", "f_290687_", "f" }) + @Final + ChunkRenderDispatcher.RenderChunk this$1; + + @Inject(method = "compile", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/Minecraft;getBlockRenderer()Lnet/minecraft/client/renderer/block/BlockRenderDispatcher;")) + private void gtceu$initBloomContextData(float camX, float camY, float camZ, ChunkBufferBuilderPack builders, + CallbackInfoReturnable cir, + @Local(ordinal = 0) BlockPos sectionOrigin, + @Local Set usedRenderTypes) { + if (!BloomShaderManager.isBloomActive()) return; + + Supplier provider = () -> { + if (!BloomRenderer.SafeMode.enabled()) { + BufferBuilder buffer = builders.builder(GTRenderTypes.bloom()); + // no existing geometry on this layer + if (usedRenderTypes.add(GTRenderTypes.bloom())) this$1.beginLayer(buffer); + return buffer; + } else { + // safe mode path + return BloomRenderer.SafeMode.getOrStartBloomBuffer(SectionPos.of(sectionOrigin)); + } + }; + // intentionally no try-with-resource statement; closed in 'gtceu$clearBloomContextData' + BloomRenderer.bloomChunkContext().get().with(provider); + } + + @Inject(method = "compile", + at = @At(value = "INVOKE", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", remap = false)) + private void gtceu$clearBloomContextData(float camX, float camY, float camZ, ChunkBufferBuilderPack builders, + CallbackInfoReturnable cir, + @Local(ordinal = 0) BlockPos sectionOrigin) { + if (!BloomShaderManager.isBloomActive()) return; + + if (BloomRenderer.SafeMode.enabled()) { + BloomRenderer.SafeMode.bakeBloomChunkBuffers(SectionPos.of(sectionOrigin), camX, camY, camZ); + } + + BloomRenderer.bloomChunkContext().get().close(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/RenderTypeMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/RenderTypeMixin.java new file mode 100644 index 00000000000..369cd1304e6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/RenderTypeMixin.java @@ -0,0 +1,30 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom.normal; + +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; +import com.gregtechceu.gtceu.core.config.GTEarlyConfig; + +import net.minecraft.client.renderer.RenderType; + +import com.google.common.collect.ImmutableList; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(RenderType.class) +public class RenderTypeMixin { + + @ModifyExpressionValue(method = "", + at = @At(value = "INVOKE", + target = "Lcom/google/common/collect/ImmutableList;of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/google/common/collect/ImmutableList;", + remap = false)) + private static ImmutableList gtceu$forceAddBloomToChunkBufferLayers(ImmutableList original) { + // don't bother checking if bloom can be loaded here; Bloom can't be used with OptiFine installed and shaders + // aren't loaded when this class is loaded. + // This mixin is also only applied if bloom safe mode is disabled. + if (GTEarlyConfig.OPTIFINE_PRESENT) return original; + + return ImmutableList.builder() + .addAll(original).add(GTRenderTypes.bloom()) + .build(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/BlockRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/BlockRendererMixin.java new file mode 100644 index 00000000000..a8234daa9ae --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/BlockRendererMixin.java @@ -0,0 +1,82 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom.normal.embeddium; + +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.client.util.TextureMetadataHelper; +import com.gregtechceu.gtceu.integration.embeddium.GTEmbeddiumCompat; + +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import me.jellysquid.mods.sodium.client.model.color.ColorProvider; +import me.jellysquid.mods.sodium.client.model.light.LightPipeline; +import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; +import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; +import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; +import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; +import org.embeddedt.embeddium.impl.render.chunk.compile.GlobalChunkBuildContext; +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(value = BlockRenderer.class, remap = false) +public abstract class BlockRendererMixin { + + @Shadow + protected abstract void writeGeometry(BlockRenderContext ctx, ChunkModelBuilder builder, Vec3 offset, Material material, BakedQuadView quad, int[] colors, QuadLightData light); + + @Inject(method = "renderQuadList", + at = @At(value = "INVOKE", + target = "Lme/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer;writeGeometry(Lme/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext;Lme/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder;Lnet/minecraft/world/phys/Vec3;Lme/jellysquid/mods/sodium/client/render/chunk/terrain/material/Material;Lme/jellysquid/mods/sodium/client/model/quad/BakedQuadView;[ILme/jellysquid/mods/sodium/client/model/light/data/QuadLightData;)V", + shift = At.Shift.AFTER)) + private void gtceu$copyBloomQuads(BlockRenderContext ctx, Material material, LightPipeline lighter, + ColorProvider colorizer, Vec3 offset, ChunkModelBuilder builder, + List quads, Direction cullFace, + CallbackInfo ci, + @Local(name = "quad") BakedQuadView quad, + @Local(name = "vertexColors") int[] vertexColors, + @Local(name = "lightData") QuadLightData lightData, + @Share("bloomBuilder") LocalRef bloomBuilderRef) { + ChunkBuildContext chunkContext = GlobalChunkBuildContext.get(); + if (BloomShaderManager.isBloomActive() && chunkContext != null && + TextureMetadataHelper.hasBloom((BakedQuad) quad, lightData.lm)) { + var bloomBuilder = chunkContext.buffers.get(GTEmbeddiumCompat.BLOOM_RENDER_PASS); + bloomBuilderRef.set(bloomBuilder); + + // call the same method again, this time with the bloom chunk model builder + this.writeGeometry(ctx, bloomBuilder, offset, GTEmbeddiumCompat.BLOOM_MATERIAL, quad, vertexColors, lightData); + } else { + bloomBuilderRef.set(null); + } + } + + @Inject(method = "renderQuadList", + at = @At(value = "INVOKE", + target = "Lme/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder;addSprite(Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;)V", + shift = At.Shift.AFTER)) + private void gtceu$copyBloomSpriteAdds(BlockRenderContext ctx, Material material, LightPipeline lighter, + ColorProvider colorizer, Vec3 offset, ChunkModelBuilder builder, + List quads, Direction cullFace, + CallbackInfo ci, + @Local(name = "sprite") TextureAtlasSprite sprite, + @Share("bloomBuilder") LocalRef bloomBuilderRef) { + // set by the above inject; value is only non-null when all appropriate conditions/requirements apply. + // thus no need to check them here. + var bloomBuilder = bloomBuilderRef.get(); + if (bloomBuilder != null) { + bloomBuilder.addSprite(sprite); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/DefaultMaterialsMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/DefaultMaterialsMixin.java new file mode 100644 index 00000000000..4d1f80c5e5e --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/DefaultMaterialsMixin.java @@ -0,0 +1,28 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom.normal.embeddium; + +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; +import com.gregtechceu.gtceu.integration.embeddium.GTEmbeddiumCompat; + +import net.minecraft.client.renderer.RenderType; + +import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.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.CallbackInfoReturnable; + +@Mixin(value = DefaultMaterials.class, remap = false) +public class DefaultMaterialsMixin { + + @Inject(method = "forRenderLayer", at = @At(value = "HEAD"), cancellable = true) + private static void gtceu$fixBloomLayerError(RenderType renderType, + CallbackInfoReturnable cir) { + if (!BloomShaderManager.isBloomAvailable()) return; + + if (renderType == GTRenderTypes.bloom()) { + cir.setReturnValue(GTEmbeddiumCompat.BLOOM_MATERIAL); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/DefaultTerrainRenderPassesMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/DefaultTerrainRenderPassesMixin.java new file mode 100644 index 00000000000..f763198b2b3 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/DefaultTerrainRenderPassesMixin.java @@ -0,0 +1,27 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom.normal.embeddium; + +import com.gregtechceu.gtceu.integration.embeddium.GTEmbeddiumCompat; + +import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import org.apache.commons.lang3.ArrayUtils; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = DefaultTerrainRenderPasses.class, remap = false) +public class DefaultTerrainRenderPassesMixin { + + @Shadow + @Final + @Mutable + public static TerrainRenderPass[] ALL; + + static { + // don't bother checking if bloom can be loaded here; Embeddium won't load with OptiFine installed and shaders + // aren't loaded when this class is loaded. + // This mixin is also only applied if bloom safe mode is disabled. + ALL = ArrayUtils.add(ALL, GTEmbeddiumCompat.BLOOM_RENDER_PASS); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/SodiumWorldRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/SodiumWorldRendererMixin.java new file mode 100644 index 00000000000..c650f6284cd --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/embeddium/SodiumWorldRendererMixin.java @@ -0,0 +1,36 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom.normal.embeddium; + +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; +import com.gregtechceu.gtceu.integration.embeddium.GTEmbeddiumCompat; + +import net.minecraft.client.renderer.RenderType; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.vertex.PoseStack; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices; +import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; +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(value = SodiumWorldRenderer.class, remap = false) +public class SodiumWorldRendererMixin { + + @Shadow + private RenderSectionManager renderSectionManager; + + @Inject(method = "drawChunkLayer", at = @At("RETURN")) + private void gtceu$drawBloomChunkLayer(RenderType renderLayer, PoseStack matrixStack, double x, double y, double z, + CallbackInfo ci, + @Local(name = "matrices") ChunkRenderMatrices matrices) { + if (!BloomShaderManager.isBloomActive()) return; + + if (renderLayer == GTRenderTypes.bloom()) { + this.renderSectionManager.renderLayer(matrices, GTEmbeddiumCompat.BLOOM_RENDER_PASS, x, y, z); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/oculus/WorldRenderingPhaseMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/oculus/WorldRenderingPhaseMixin.java new file mode 100644 index 00000000000..f994caa731f --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/normal/oculus/WorldRenderingPhaseMixin.java @@ -0,0 +1,49 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom.normal.oculus; + +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; + +import net.irisshaders.iris.pipeline.WorldRenderingPhase; +import net.minecraft.client.renderer.RenderType; + +import org.apache.commons.lang3.ArrayUtils; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.gen.Invoker; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = WorldRenderingPhase.class, remap = false) +public class WorldRenderingPhaseMixin { + + @Shadow + @Final + @Mutable + private static WorldRenderingPhase[] $VALUES; + + @Unique + private static final WorldRenderingPhase GTCEU$BLOOM; + + @Invoker("") + private static WorldRenderingPhase gtceu$callInit(String name, int ordinal) { + throw new AssertionError(); + } + + static { + // don't bother checking if bloom can be loaded here; Oculus won't load with OptiFine installed and shaders + // aren't loaded when this class is loaded. + // This mixin is also only applied if bloom safe mode is disabled. + GTCEU$BLOOM = gtceu$callInit("GTCEU$BLOOM", $VALUES.length); + $VALUES = ArrayUtils.add($VALUES, GTCEU$BLOOM); + } + + @Inject(method = "fromTerrainRenderType", at = @At(value = "HEAD"), cancellable = true) + private static void gtceu$fixBloomLayerError(RenderType renderType, + CallbackInfoReturnable cir) { + if (!BloomShaderManager.isBloomAvailable()) return; + + if (renderType == GTRenderTypes.bloom()) { + cir.setReturnValue(GTCEU$BLOOM); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/safemode/embeddium/BlockRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/safemode/embeddium/BlockRendererMixin.java new file mode 100644 index 00000000000..e16054d4669 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/bloom/safemode/embeddium/BlockRendererMixin.java @@ -0,0 +1,82 @@ +package com.gregtechceu.gtceu.core.mixins.client.bloom.safemode.embeddium; + +import com.gregtechceu.gtceu.client.bloom.BloomRenderer; +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.client.util.TextureMetadataHelper; + +import com.gregtechceu.gtceu.integration.embeddium.GTEmbeddiumCompat; +import com.mojang.blaze3d.vertex.VertexConsumer; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildContext; +import net.caffeinemc.mods.sodium.api.util.ColorARGB; +import net.caffeinemc.mods.sodium.api.util.NormI8; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.core.SectionPos; +import net.minecraft.world.phys.Vec3; + +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import com.mojang.blaze3d.vertex.BufferBuilder; +import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; +import me.jellysquid.mods.sodium.client.model.quad.BakedQuadView; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; +import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; +import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; +import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder; +import org.embeddedt.embeddium.impl.render.chunk.compile.GlobalChunkBuildContext; +import org.objectweb.asm.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.callback.CallbackInfo; + +/** + * Safe mode version of {@link com.gregtechceu.gtceu.core.mixins.client.bloom.normal.embeddium.BlockRendererMixin} + * + * @see com.gregtechceu.gtceu.core.mixins.client.bloom.normal.embeddium.BlockRendererMixin + */ +@Mixin(value = BlockRenderer.class, remap = false) +public class BlockRendererMixin { + + @Inject(method = "writeGeometry", at = @At(value = "HEAD")) + private void gtceu$copyBloomQuads$initLocals(BlockRenderContext ctx, ChunkModelBuilder builder, + Vec3 offset, Material material, BakedQuadView quad, + int[] colors, QuadLightData lightData, + CallbackInfo ci, + @Share("bloomBuffer") LocalRef bloomBufferRef) { + // Check if quad is full brightness OR we have bloom enabled for the quad + if (BloomShaderManager.isBloomActive() && TextureMetadataHelper.hasBloom((BakedQuad) quad, lightData.lm)) { + SectionPos sectionPos = SectionPos.of(ctx.pos()); + bloomBufferRef.set(BloomRenderer.SafeMode.getOrStartBloomBuffer(sectionPos)); + } else { + bloomBufferRef.set(null); + } + + } + + @Inject(method = "writeGeometry", + at = @At(value = "FIELD", + target = "Lme/jellysquid/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder$Vertex;light:I", + opcode = Opcodes.PUTFIELD, + shift = At.Shift.AFTER)) + private void gtceu$copyBloomQuads(BlockRenderContext ctx, ChunkModelBuilder builder, Vec3 offset, + Material material, BakedQuadView quad, int[] colors, QuadLightData light, + CallbackInfo ci, + @Local(name = "srcIndex") int srcIndex, + @Local(name = "out") ChunkVertexEncoder.Vertex v, + @Share("bloomBuffer") LocalRef bloomBufferRef) { + VertexConsumer bloomBuffer = bloomBufferRef.get(); + // bloomBuffer is null if bloom isn't available or the quad's texture doesn't have bloom + if (bloomBuffer == null) return; + + int normal = quad.getForgeNormal(srcIndex); + if (normal == 0) normal = quad.getComputedFaceNormal(); + + bloomBuffer.vertex(v.x, v.y, v.z) + .color(ColorARGB.toABGR(v.color)) + .uv(v.u, v.v) + .uv2(v.light) + .normal(NormI8.unpackX(normal), NormI8.unpackY(normal), NormI8.unpackZ(normal)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/IGTBakedQuad.java b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/BakedQuadExt.java similarity index 61% rename from src/main/java/com/gregtechceu/gtceu/core/IGTBakedQuad.java rename to src/main/java/com/gregtechceu/gtceu/core/util/extensions/BakedQuadExt.java index 8cb853a080a..2e0db8ca1be 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/IGTBakedQuad.java +++ b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/BakedQuadExt.java @@ -1,18 +1,18 @@ -package com.gregtechceu.gtceu.core; +package com.gregtechceu.gtceu.core.util.extensions; import net.minecraft.client.renderer.block.model.BakedQuad; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -public interface IGTBakedQuad { +public interface BakedQuadExt { @ApiStatus.Internal default BakedQuad gtceu$setTextureKey(@Nullable String key) { - return (BakedQuad) this; + throw new AssertionError("Mixin didn't apply"); } default @Nullable String gtceu$getTextureKey() { - return null; + throw new AssertionError("Mixin didn't apply"); } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/util/extensions/ExtensionHelpers.java b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/ExtensionHelpers.java new file mode 100644 index 00000000000..92a9fad317a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/ExtensionHelpers.java @@ -0,0 +1,14 @@ +package com.gregtechceu.gtceu.core.util.extensions; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.ApiStatus; +import org.joml.Vector3f; + +// package-private so only things in this package can use it +@UtilityClass +class ExtensionHelpers { + + /// Avoid allocations in hot code by using thread-local temporary vectors in {@link VertexConsumerExt} + @ApiStatus.Internal + static final ThreadLocal scratch = ThreadLocal.withInitial(Vector3f::new); +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/util/extensions/QuadLighterExt.java b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/QuadLighterExt.java new file mode 100644 index 00000000000..e97dbe19cbc --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/QuadLighterExt.java @@ -0,0 +1,10 @@ +package com.gregtechceu.gtceu.core.util.extensions; + +import net.minecraft.client.renderer.RenderType; + +public interface QuadLighterExt { + + default void gtceu$setRenderType(RenderType currentRenderType) { + throw new AssertionError("Mixin didn't apply"); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/util/extensions/VertexConsumerExt.java b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/VertexConsumerExt.java new file mode 100644 index 00000000000..3d64d602e86 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/util/extensions/VertexConsumerExt.java @@ -0,0 +1,22 @@ +package com.gregtechceu.gtceu.core.util.extensions; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import org.joml.*; + +@SuppressWarnings("unused") +public interface VertexConsumerExt { + + private VertexConsumer self() { + return (VertexConsumer) this; + } + + default VertexConsumer gtceu$vertex(Matrix4f poseMatrix, Vector3fc pos) { + pos = poseMatrix.transformPosition(pos, ExtensionHelpers.scratch.get()); + return self().vertex(pos.x(), pos.y(), pos.z()); + } + + default VertexConsumer gtceu$normal(Matrix3f normalMatrix, Vector3fc normal) { + normal = normalMatrix.transform(normal, ExtensionHelpers.scratch.get()); + return self().normal(normal.x(), normal.y(), normal.z()); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/data/lang/ConfigurationLang.java b/src/main/java/com/gregtechceu/gtceu/data/lang/ConfigurationLang.java index d24677602c5..42ffac29a46 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/lang/ConfigurationLang.java +++ b/src/main/java/com/gregtechceu/gtceu/data/lang/ConfigurationLang.java @@ -16,6 +16,9 @@ public class ConfigurationLang { public static void init(RegistrateLangProvider provider) { + provider.add("config.gtceu.option.bloomType.load_error", + "Could not load shaders for the bloom effect, see %s for details"); + dfs(provider, new HashSet<>(), Configuration.registerConfig(ConfigHolder.class, ConfigFormats.yaml()).getValueMap()); } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/embeddium/GTEmbeddiumCompat.java b/src/main/java/com/gregtechceu/gtceu/integration/embeddium/GTEmbeddiumCompat.java new file mode 100644 index 00000000000..c02092d4f46 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/embeddium/GTEmbeddiumCompat.java @@ -0,0 +1,46 @@ +package com.gregtechceu.gtceu.integration.embeddium; + +import com.gregtechceu.gtceu.client.bloom.BloomRenderer; +import com.gregtechceu.gtceu.client.bloom.BloomShaderManager; +import com.gregtechceu.gtceu.client.renderer.GTRenderTypes; +import com.gregtechceu.gtceu.core.config.GTEarlyConfig; +import com.gregtechceu.gtceu.core.mixins.GTMixinPlugin; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.SectionPos; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material; +import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.parameters.AlphaCutoffParameter; +import org.embeddedt.embeddium.api.ChunkMeshEvent; + +public class GTEmbeddiumCompat { + + public static final TerrainRenderPass BLOOM_RENDER_PASS = new TerrainRenderPass(GTRenderTypes.bloom(), false, true); + public static final Material BLOOM_MATERIAL = new Material(BLOOM_RENDER_PASS, + AlphaCutoffParameter.ONE_TENTH, true); + + public static void init() { + MinecraftForge.EVENT_BUS.register(GTEmbeddiumCompat.class); + } + + @SubscribeEvent + public static void registerSafeModeChunkMeshAppender(ChunkMeshEvent event) { + if (!BloomRenderer.SafeMode.enabled()) return; + if (!BloomShaderManager.isBloomActive()) return; + + event.addMeshAppender(context -> { + SectionPos sectionOrigin = context.sectionOrigin(); + if (!BloomRenderer.SafeMode.BLOOM_BUFFER_BUILDERS.containsKey(sectionOrigin)) { + return; + } + + Vec3 camPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition(); + BloomRenderer.SafeMode.bakeBloomChunkBuffers(sectionOrigin, + (float) camPos.x, (float) camPos.y, (float) camPos.z); + }); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/integration/embeddium/package-info.java b/src/main/java/com/gregtechceu/gtceu/integration/embeddium/package-info.java new file mode 100644 index 00000000000..e7e62efcfd2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/integration/embeddium/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.integration.embeddium; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/map/ftbchunks/veins/ore/OreVeinIcon.java b/src/main/java/com/gregtechceu/gtceu/integration/map/ftbchunks/veins/ore/OreVeinIcon.java index c6cd4331c23..4fc31c7643c 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/map/ftbchunks/veins/ore/OreVeinIcon.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/map/ftbchunks/veins/ore/OreVeinIcon.java @@ -4,7 +4,7 @@ import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconSet; import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType; import com.gregtechceu.gtceu.api.data.worldgen.ores.GeneratedVeinMetadata; -import com.gregtechceu.gtceu.client.util.DrawUtil; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.integration.map.ftbchunks.FTBChunksOptions; import com.gregtechceu.gtceu.integration.map.layer.builtin.OreRenderLayer; @@ -157,7 +157,7 @@ public void draw(MapType mapType, GuiGraphics graphics, int x, int y, int w, int var iconSize = ConfigHolder.INSTANCE.compat.minimap.oreIconSize; var material = getMaterial(); var color = material.isNull() ? 0xFFFFFFFF : material.getMaterialARGB(); - var colors = DrawUtil.floats(color); + var colors = RenderUtil.floats(color); RenderSystem.setShaderColor(1, 1, 1, 1); var iconSet = material.isNull() ? MaterialIconSet.METALLIC : material.getMaterialIconSet(); @@ -172,7 +172,7 @@ public void draw(MapType mapType, GuiGraphics graphics, int x, int y, int w, int oreTexture = MaterialIconType.rawOre.getItemTexturePath(iconSet, "secondary", true); if (oreTexture != null) { var materialSecondaryARGB = material.isNull() ? 0xFFFFFFFF : material.getMaterialSecondaryARGB(); - colors = DrawUtil.floats(materialSecondaryARGB); + colors = RenderUtil.floats(materialSecondaryARGB); var oreSprite = Minecraft.getInstance() .getTextureAtlas(InventoryMenu.BLOCK_ATLAS) .apply(oreTexture); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/minimap/ore/OreVeinElementRenderer.java b/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/minimap/ore/OreVeinElementRenderer.java index 6539ed5ffad..3fb592d1e79 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/minimap/ore/OreVeinElementRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/minimap/ore/OreVeinElementRenderer.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType; import com.gregtechceu.gtceu.api.data.worldgen.ores.GeneratedVeinMetadata; -import com.gregtechceu.gtceu.client.util.DrawUtil; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.integration.map.GroupingMapRenderer; @@ -45,7 +45,7 @@ public boolean renderElement(OreVeinElement element, Material firstMaterial = vein.definition().veinGenerator().getAllMaterials().get(0); int materialARGB = firstMaterial.getMaterialARGB(); - float[] colors = DrawUtil.floats(materialARGB); + float[] colors = RenderUtil.floats(materialARGB); RenderSystem.setShaderColor(1, 1, 1, 1); ResourceLocation oreTexture = MaterialIconType.rawOre.getItemTexturePath(firstMaterial.getMaterialIconSet(), diff --git a/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/worldmap/ore/OreVeinElementRenderer.java b/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/worldmap/ore/OreVeinElementRenderer.java index 653e9667f00..bc70aae18aa 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/worldmap/ore/OreVeinElementRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/map/xaeros/worldmap/ore/OreVeinElementRenderer.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType; import com.gregtechceu.gtceu.api.data.worldgen.ores.GeneratedVeinMetadata; -import com.gregtechceu.gtceu.client.util.DrawUtil; +import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.integration.map.GroupingMapRenderer; @@ -84,7 +84,7 @@ public boolean renderElement(int location, OreVeinElement element, Material firstMaterial = vein.definition().veinGenerator().getAllMaterials().get(0); int materialARGB = firstMaterial.getMaterialARGB(); - float[] colors = DrawUtil.floats(materialARGB); + float[] colors = RenderUtil.floats(materialARGB); RenderSystem.setShaderColor(1, 1, 1, 1); ResourceLocation oreTexture = MaterialIconType.rawOre.getItemTexturePath(firstMaterial.getMaterialIconSet(), @@ -99,7 +99,7 @@ public boolean renderElement(int location, OreVeinElement element, oreTexture = MaterialIconType.rawOre.getItemTexturePath(firstMaterial.getMaterialIconSet(), "secondary", true); if (oreTexture != null) { int materialSecondaryARGB = firstMaterial.getMaterialSecondaryARGB(); - colors = DrawUtil.floats(materialSecondaryARGB); + colors = RenderUtil.floats(materialSecondaryARGB); var oreSprite = Minecraft.getInstance() .getTextureAtlas(InventoryMenu.BLOCK_ATLAS) .apply(oreTexture); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java index a36f05bde92..6946e0c45b5 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/modernfix/GTModernFixIntegration.java @@ -1,8 +1,7 @@ package com.gregtechceu.gtceu.integration.modernfix; -import com.gregtechceu.gtceu.client.model.machine.MachineModel; - -import com.lowdragmc.lowdraglib.client.model.custommodel.CustomBakedModel; +import com.gregtechceu.gtceu.client.util.AssetEventListener; +import com.gregtechceu.gtceu.client.util.ModelEventHelper; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; @@ -41,15 +40,14 @@ public void onDynamicResourcesStatusChange(boolean enabled) { } @Override - public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, - BakedModel originalModel, ModelState state, ModelBakery bakery, + public BakedModel onBakedModelLoad(ResourceLocation modelLocation, UnbakedModel baseModel, + BakedModel model, ModelState state, ModelBakery bakery, Function textureGetter) { - if (originalModel instanceof CustomBakedModel ctmModel) { - // Unwrap all machine models from LDLib CTM models so we don't need to be as aggressive with mixins - if (ctmModel.getParent() instanceof MachineModel machineModel) { - return machineModel; - } + // process all model replacers + for (var listener : ModelEventHelper.EVENT_LISTENERS) { + if (!(listener.listener() instanceof AssetEventListener.BakedModelReplacement modelReplacement)) continue; + model = modelReplacement.modifyBakedModel(modelLocation, model, baseModel, bakery); } - return originalModel; + return model; } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java new file mode 100644 index 00000000000..ce09f7754b9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/ArrayHelpers.java @@ -0,0 +1,237 @@ +package com.gregtechceu.gtceu.utils; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Array; +import java.util.Objects; + +import static org.apache.commons.lang3.ArrayUtils.*; + +@SuppressWarnings("ForLoopReplaceableByForEach") +public class ArrayHelpers { + + /** + * Returns a copy of the specified array object, deeply copying multidimensional arrays. + * If the specified object is null, the return value is null. + * + *

+ * Note: if the array object has an element type which is a reference type that is not an array type, + * the elements themselves are not deeply copied. This method only copies array objects. + * + * @param array the array object to deep copy + * @param the type of the array to deep copy + * @return a copy of the specified array object, deeply copying multidimensional arrays, or null if the object is + * null + */ + @Contract(value = "!null -> !null; _ -> null", pure = true) + public static T @Nullable [] deepCopy(T @Nullable [] array) { + if (array == null) { + return null; + } + + Class componentType = array.getClass().getComponentType(); + + @SuppressWarnings("unchecked") + T[] copy = (T[]) Array.newInstance(componentType, array.length); + + if (componentType.isArray()) { + for (int i = 0; i < array.length; ++i) { + // noinspection unchecked + Array.set(copy, i, deepCopy((T[]) array[i])); + } + } else { + System.arraycopy(array, 0, copy, 0, array.length); + } + + return copy; + } + + public static boolean allMatch(boolean[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + boolean firstElement = array[0]; + if (array.length == 2) return firstElement == array[1]; + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement) { + return false; + } + } + return true; + } + + public static boolean allMatch(byte[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + byte firstElement = array[0]; + if (array.length == 2) return firstElement == array[1]; + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement) { + return false; + } + } + return true; + } + + public static boolean allMatch(char[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + char firstElement = array[0]; + if (array.length == 2) return firstElement == array[1]; + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement) { + return false; + } + } + return true; + } + + public static boolean allMatch(double[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + double firstElement = array[0]; + boolean searchNaN = Double.isNaN(firstElement); + + if (array.length == 2) return array[1] == firstElement || searchNaN && Double.isNaN(array[1]); + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement && !(searchNaN && Double.isNaN(array[i]))) { + return false; + } + } + + return false; + } + + public static boolean allMatch(double[] array, double tolerance) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + double firstElement = array[0]; + double min = firstElement - tolerance; + double max = firstElement + tolerance; + + if (array.length == 2) return array[1] >= min && array[1] <= max; + + for (int i = 0; i < array.length; ++i) { + if (array[i] < min || array[i] > max) { + return false; + } + } + return true; + } + + public static boolean allMatch(float[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + float firstElement = array[0]; + boolean searchNaN = Float.isNaN(firstElement); + + if (array.length == 2) return array[1] == firstElement || searchNaN && Float.isNaN(array[1]); + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement && !(searchNaN && Float.isNaN(array[i]))) { + return false; + } + } + + return false; + } + + public static boolean allMatch(float[] array, float tolerance) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + float firstElement = array[0]; + float min = firstElement - tolerance; + float max = firstElement + tolerance; + + if (array.length == 2) return array[1] >= min && array[1] <= max; + + for (int i = 0; i < array.length; ++i) { + if (array[i] < min && array[i] > max) { + return false; + } + } + return true; + } + + public static boolean allMatch(int[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + int firstElement = array[0]; + if (array.length == 2) return firstElement == array[1]; + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement) { + return false; + } + } + return true; + } + + public static boolean allMatch(long[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + long firstElement = array[0]; + if (array.length == 2) return firstElement == array[1]; + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement) { + return false; + } + } + return true; + } + + public static boolean allMatch(Object[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + Object firstElement = array[0]; + if (array.length == 2) return Objects.equals(array[1], firstElement); + + for (int i = 0; i < array.length; ++i) { + if (!Objects.equals(array[i], firstElement)) { + return false; + } + } + return true; + } + + public static boolean allMatch(short[] array) { + if (isEmpty(array) || array.length == 1) { + return true; + } + + short firstElement = array[0]; + if (array.length == 2) return firstElement == array[1]; + + for (int i = 0; i < array.length; ++i) { + if (array[i] != firstElement) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java b/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java index caeaf139aed..dc51630821a 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java @@ -10,6 +10,9 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4fc; +import org.joml.Options; +import org.joml.Runtime; import java.math.BigInteger; import java.text.DecimalFormat; @@ -79,7 +82,7 @@ private static String checkNumbers(String string, int startIndex) { * * @param string Any string with ASCII characters. * @return A string that is all lowercase, with underscores inserted before word/number boundaries: - * + * *

      *         
{@code "maragingSteel300" -> "maraging_steel_300"} *
{@code "gtceu:maraging_steel_300" -> "gtceu:maraging_steel_300"} @@ -287,4 +290,46 @@ public static String formatTemperature(int temperature) { return formatNumbers(temperature - 273) + " °C"; else return formatNumbers(temperature) + " K"; } + + /** + * Return a single-line string representation of {@code matrix} using JOML's number formatting. + * + * @return the string representation + */ + public static String matrixToSingleLineString(Matrix4fc matrix) { + String str = matrixToSingleLineString(matrix, Options.NUMBER_FORMAT); + StringBuilder res = new StringBuilder(); + int eIndex = Integer.MIN_VALUE; + + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == 'E') { + eIndex = i; + } else if (c == ' ' && eIndex == i - 1) { + // workaround Java 1.4 DecimalFormat bug + res.append('+'); + continue; + } else if (Character.isDigit(c) && eIndex == i - 1) { + res.append('+'); + } + res.append(c); + } + return res.toString(); + } + + /** + * Return a single-line string representation of this matrix by formatting the matrix + * elements with the given {@link NumberFormat}. + * + * @param formatter the {@link NumberFormat} used to format the matrix values with + * @return the string representation + */ + // spotless:off + public static String matrixToSingleLineString(Matrix4fc matrix, NumberFormat formatter) { + return "{ [" + Runtime.format(matrix.m00(), formatter) + " " + Runtime.format(matrix.m10(), formatter) + " " + Runtime.format(matrix.m20(), formatter) + " " + Runtime.format(matrix.m30(), formatter) + "]. " + + "[" + Runtime.format(matrix.m01(), formatter) + " " + Runtime.format(matrix.m11(), formatter) + " " + Runtime.format(matrix.m21(), formatter) + " " + Runtime.format(matrix.m31(), formatter) + "], " + + "[" + Runtime.format(matrix.m02(), formatter) + " " + Runtime.format(matrix.m12(), formatter) + " " + Runtime.format(matrix.m22(), formatter) + " " + Runtime.format(matrix.m32(), formatter) + "]. " + + "[" + Runtime.format(matrix.m03(), formatter) + " " + Runtime.format(matrix.m13(), formatter) + " " + Runtime.format(matrix.m23(), formatter) + " " + Runtime.format(matrix.m33(), formatter) + "] }"; + } + // spotless:on } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java b/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java index 44f6ad29e34..b5b9d31a626 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/GTMatrixUtils.java @@ -6,7 +6,6 @@ import net.minecraft.util.Mth; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Table; import com.google.common.collect.Tables; import org.jetbrains.annotations.Contract; @@ -14,7 +13,8 @@ import java.lang.Math; import java.security.InvalidParameterException; -import java.util.Objects; +import java.util.EnumMap; +import java.util.Map; import javax.annotation.ParametersAreNonnullByDefault; @@ -22,13 +22,10 @@ @MethodsReturnNonnullByDefault public class GTMatrixUtils { - @SuppressWarnings("UnstableApiUsage") - private static final ImmutableMap directionAxises = Util.make(() -> { - ImmutableMap.Builder map = ImmutableMap.builderWithExpectedSize(6); + private static final Map directionAxes = Util.make(new EnumMap<>(Direction.class), map -> { for (Direction dir : GTUtil.DIRECTIONS) { map.put(dir, dir.step()); } - return map.build(); }); private static final Table rotations = Tables .synchronizedTable(HashBasedTable.create()); @@ -160,6 +157,6 @@ public static Matrix4fc createRotationState(Direction frontFace, Direction upwar } public static Vector3fc getDirectionAxis(Direction dir) { - return Objects.requireNonNull(directionAxises.get(dir)); + return directionAxes.get(dir); } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java b/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java index 70912110719..32d503a7f57 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/GTStringUtils.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.utils; import net.minecraft.ChatFormatting; +import net.minecraft.Util; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; @@ -8,6 +9,7 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.NotNull; @@ -15,6 +17,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; public class GTStringUtils { @@ -222,4 +225,18 @@ public static Component toComponent(ListTag arr) { component.append("]"); return component; } + + public static String getPropertyValueString(Map.Entry, Comparable> entry) { + Property property = entry.getKey(); + Comparable value = entry.getValue(); + + String valueString = Util.getPropertyName(property, value); + if (Boolean.TRUE.equals(value)) { + valueString = ChatFormatting.GREEN + valueString; + } else if (Boolean.FALSE.equals(value)) { + valueString = ChatFormatting.RED + valueString; + } + + return property.getName() + ": " + valueString; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/utils/ScopedValue.java b/src/main/java/com/gregtechceu/gtceu/utils/ScopedValue.java new file mode 100644 index 00000000000..9758bd3288f --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/ScopedValue.java @@ -0,0 +1,84 @@ +package com.gregtechceu.gtceu.utils; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.Nullable; + +/** + * "recreations" of Java 25 scoped values using {@link AutoCloseable AutoCloseables}. + */ +public abstract class ScopedValue implements AutoCloseable { + + /** + * Scoped object value. Resets to {@code null} when exiting scope. + * @param The type of the object. + */ + @RequiredArgsConstructor + public static final class Object extends ScopedValue { + + private final @Nullable T initialValue; + + /** + * Current value in this scope + */ + @Getter + private @Nullable T value; + + public Object() { + this(null); + } + + /** + * Set {@code current} to {@code value} within this scope. + * @return this + */ + public Object with(T value) { + this.value = value; + return this; + } + + @Override + public void close() { + this.value = this.initialValue; + } + } + + /** + * Scoped boolean value. Resets to {@link #initialValue} when exiting scope. + */ + @RequiredArgsConstructor + public static final class Boolean extends ScopedValue { + + private final boolean initialValue; + + /** + * Current value in this scope + */ + @Getter + private boolean active; + + /** + * Set {@code current} to {@code value} within this scope. + * @return this + */ + public Boolean with(boolean value) { + this.active = value; + return this; + } + + /** + * Shortcut method that sets {@code current} to {@code !initial} + * @return this + */ + public Boolean active() { + return with(!this.initialValue); + } + + @Override + public void close() { + this.active = this.initialValue; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/TriState.java b/src/main/java/com/gregtechceu/gtceu/utils/TriState.java new file mode 100644 index 00000000000..e58e68e5cc9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/TriState.java @@ -0,0 +1,102 @@ +package com.gregtechceu.gtceu.utils; + +import net.minecraft.util.StringRepresentable; + +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Lifecycle; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Locale; +import java.util.function.BooleanSupplier; +import java.util.function.Function; + +/** + * Represents a boolean value that can be {@code true}, {@code false} or refer to a default value. + */ +public enum TriState implements StringRepresentable { + + /** + * Represents the boolean value {@code true}. + */ + TRUE, + /** + * Represents a "default" value, often used as a fallback. + */ + DEFAULT, + /** + * Represents the boolean value {@code false}. + */ + FALSE; + + public static final Codec CODEC = Codec.either(Codec.BOOL, StringRepresentable.fromEnum(TriState::values)) + .xmap(either -> either.map(TriState::of, Function.identity()), + triState -> triState != DEFAULT ? Either.left(triState.isTrue()) : Either.right(DEFAULT)); + + // Helper methods + + public boolean isTrue() { + return this == TRUE; + } + + public boolean isDefault() { + return this == DEFAULT; + } + + public boolean isFalse() { + return this == FALSE; + } + + public static TriState of(boolean value) { + return value ? TRUE : FALSE; + } + + public static TriState of(@Nullable Boolean value) { + return value == null ? DEFAULT : of((boolean) value); + } + + public static TriState of(DataResult value) { + if (value.result().isPresent()) return of(value.result().get()); + // throw out parsing errors and return default + else return DEFAULT; + } + + public @Nullable Boolean toBoolean() { + return switch (this) { + case TRUE -> Boolean.TRUE; + case FALSE -> Boolean.FALSE; + default -> null; + }; + } + + public DataResult toBooleanOrError() { + return switch (this) { + case TRUE -> DataResult.success(Boolean.TRUE); + case FALSE -> DataResult.success(Boolean.FALSE); + default -> DataResult.error(() -> "Default does not have a value", Lifecycle.stable()); + }; + } + + public boolean toBooleanOrElse(final boolean other) { + return switch (this) { + case TRUE -> true; + case FALSE -> false; + default -> other; + }; + } + + public boolean toBooleanOrElseGet(final @NotNull BooleanSupplier supplier) { + return switch (this) { + case TRUE -> true; + case FALSE -> false; + default -> supplier.getAsBoolean(); + }; + } + + @Override + public @NotNull String getSerializedName() { + return this.name().toLowerCase(Locale.ROOT); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/function/IntObjectConsumer.java b/src/main/java/com/gregtechceu/gtceu/utils/function/IntObjectConsumer.java new file mode 100644 index 00000000000..567c5d6e07b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/function/IntObjectConsumer.java @@ -0,0 +1,35 @@ +package com.gregtechceu.gtceu.utils.function; + +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; + +/** + * A type-specific {@link BinaryOperator}; provides methods operating both on objects and on + * primitives. + * + * @see BinaryOperator + * @since 8.5.0 + */ +@FunctionalInterface +public interface IntObjectConsumer extends BiConsumer { + + /** + * Computes the operator on the given inputs. + * + * @param t the first input. + * @param u the second input. + * @return the output of the operator on the given inputs. + */ + void accept(int t, T u); + + /** + * {@inheritDoc} + * + * @deprecated Please use the corresponding type-specific method instead. + */ + @Deprecated + @Override + default void accept(Integer integer, T u) { + accept((int) integer, u); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 4f4d6041e1c..cb04f0d6f61 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -24,6 +24,9 @@ public net.minecraft.world.entity.Entity m_20115_(IZ)V # setSharedFlag public net.minecraft.world.entity.vehicle.Boat f_38285_ # DATA_ID_TYPE +# for bloom +public net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$RenderChunk m_112805_(Lcom/mojang/blaze3d/vertex/BufferBuilder;)V # beginLayer + # for AE2 to be able to load (idk why but it needs these?) public net.minecraft.world.level.block.Blocks m_50774_(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z # always public net.minecraft.world.level.block.Blocks m_50805_(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z # never diff --git a/src/main/resources/assets/gtceu/shaders/core/black_hole.fsh b/src/main/resources/assets/gtceu/shaders/core/black_hole.fsh new file mode 100644 index 00000000000..52f8332eb78 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/core/black_hole.fsh @@ -0,0 +1,217 @@ +#version 140 + +#define AA 2 //change to 1 to increase performance +#define _Speed 3.0 //disk rotation speed +#define _Steps 12. //disk texture layers +#define _Size 0.3 //size of BH + +uniform float u_time; +uniform vec2 u_resolution; +uniform vec3 eye; +uniform vec3 target; +uniform sampler2D Sampler0; + +float hash(float x){ return fract(sin(x)*152754.742);} +float hash(vec2 x){ return hash(x.x + hash(x.y));} + +float value(vec2 p, float f) //value noise +{ + float bl = hash(floor(p*f + vec2(0.,0.))); + float br = hash(floor(p*f + vec2(1.,0.))); + float tl = hash(floor(p*f + vec2(0.,1.))); + float tr = hash(floor(p*f + vec2(1.,1.))); + + vec2 fr = fract(p*f); + fr = (3. - 2.*fr)*fr*fr; + float b = mix(bl, br, fr.x); + float t = mix(tl, tr, fr.x); + return mix(b,t, fr.y); +} + +vec3 background(vec2 fragCoord, float r) +{ + vec2 uv = fragCoord.xy / u_resolution.xy; + vec2 lpos = u_resolution.xy / 2. / u_resolution.x; + vec2 texC2 = fragCoord.xy / u_resolution.x; + vec2 texC = mix(uv, lpos, (20. * r / (distance((texC2 * 2.0 - lpos * 2.0) * 5. + lpos, lpos) - r))); //Black hole shader + vec3 getColor = texture2D(Sampler0,texC).rgb; + return getColor; +} + +vec4 raymarchDisk(vec3 ray, vec3 zeroPos) +{ + //return vec4(1.,1.,1.,0.); //no disk + + vec3 position = zeroPos; + float lengthPos = length(position.xz); + float dist = min(1., lengthPos*(1./_Size) *0.5) * _Size * 0.4 *(1./_Steps) /( abs(ray.y) ); + + position += dist*_Steps*ray*0.5; + + vec2 deltaPos; + deltaPos.x = -zeroPos.z*0.01 + zeroPos.x; + deltaPos.y = zeroPos.x*0.01 + zeroPos.z; + deltaPos = normalize(deltaPos - zeroPos.xz); + + float parallel = dot(ray.xz, deltaPos); + parallel /= sqrt(lengthPos); + parallel *= 0.5; + float redShift = parallel +0.3; + redShift *= redShift; + + redShift = clamp(redShift, 0., 1.); + + float disMix = clamp((lengthPos - _Size * 2.)*(1./_Size)*0.24, 0., 1.); + vec3 insideCol = mix(vec3(1.0,0.8,0.0), vec3(0.5,0.13,0.02)*0.2, disMix); + + insideCol *= mix(vec3(0.4, 0.2, 0.1), vec3(1.6, 2.4, 4.0), redShift); + insideCol *= 1.25; + redShift += 0.12; + redShift *= redShift; + + vec4 o = vec4(0.); + + for(float i = 0. ; i < _Steps; i++) + { + position -= dist * ray ; + + float intensity =clamp( 1. - abs((i - 0.8) * (1./_Steps) * 2.), 0., 1.); + float lengthPos = length(position.xz); + float distMult = 1.; + + distMult *= clamp((lengthPos - _Size * 0.75) * (1./_Size) * 1.5, 0., 1.); + distMult *= clamp(( _Size * 10. -lengthPos) * (1./_Size) * 0.20, 0., 1.); + distMult *= distMult; + + float u = lengthPos + u_time* _Size*0.3 + intensity * _Size * 0.2; + + vec2 xy ; + float rot = mod(u_time*_Speed, 8192.); + xy.x = -position.z*sin(rot) + position.x*cos(rot); + xy.y = position.x*sin(rot) + position.z*cos(rot); + + float x = abs( xy.x/(xy.y)); + float angle = 0.02*atan(x); + + const float f = 70.; + float noise = value( vec2( angle, u * (1./_Size) * 0.05), f); + noise = noise*0.66 + 0.33*value( vec2( angle, u * (1./_Size) * 0.05), f*2.); + + float extraWidth = noise * 1. * (1. - clamp(i * (1./_Steps)*2. - 1., 0., 1.)); + + float alpha = clamp(noise*(intensity + extraWidth)*( (1./_Size) * 10. + 0.01 ) * dist * distMult , 0., 1.); + + vec3 col = 2.*mix(vec3(0.3,0.2,0.15)*insideCol, insideCol, min(1.,intensity*2.)); + o = clamp(vec4(col*alpha + o.rgb*(1.-alpha), o.a*(1.-alpha) + alpha), vec4(0.), vec4(1.)); + + lengthPos *= (1./_Size); + + o.rgb+= redShift*(intensity*1. + 0.5)* (1./_Steps) * 100.*distMult/(lengthPos*lengthPos); + } + + o.rgb = clamp(o.rgb - 0.005, 0., 1.); + return o ; +} + + +mat4 viewMatrix(vec3 eye, vec3 center, vec3 up) { + // Based on gluLookAt man page + vec3 f = normalize(center - eye); + vec3 s = normalize(cross(f, up)); + vec3 u = cross(s, f); + return mat4( + vec4(s, 0.0), + vec4(u, 0.0), + vec4(-f, 0.0), + vec4(0.0, 0.0, 0.0, 1) + ); +} + +vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) { + vec2 xy = fragCoord - size / 2.0; + float z = size.y / tan(radians(fieldOfView) / 2.0); + return normalize(vec3(xy, -z)); +} + +out vec4 fragColor; + +void main() +{ + fragColor = vec4(0.); + + vec2 fragCoordRot; + fragCoordRot.x = gl_FragCoord.x*1.0; + fragCoordRot.y = gl_FragCoord.y*1.0; + + for( int j=0; j _Size * 1000.) //ray escaped BH + { + vec3 bg = background (gl_FragCoord.xy, 1./r); + outCol = vec4(col.rgb*col.a + bg.rgb*(1.-col.a) + glow.rgb *(1.-col.a), 1.); + break; + } + + else if (abs(pos.y) <= _Size * 0.002 ) //ray hit accretion disk + { + vec4 diskCol = raymarchDisk(ray, pos); //render disk + pos.y = 0.; + pos += abs(_Size * 0.001 /ray.y) * ray; + col = vec4(diskCol.rgb*(1.-col.a) + col.rgb, col.a + diskCol.a*(1.-col.a)); + } + } + + //if the ray never escaped or got sucked in + if(outCol.r == 100.) + outCol = vec4(col.rgb + glow.rgb *(col.a + glow.a) , 1.); + + col = outCol; + col.rgb = pow( col.rgb, vec3(0.6) ); + + fragColor += col/float(AA*AA); + } +} diff --git a/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.fsh b/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.fsh new file mode 100644 index 00000000000..758edb55dae --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.fsh @@ -0,0 +1,26 @@ +#version 150 + +#moj_import + +uniform sampler2D Sampler0; + +uniform vec4 ColorModulator; +uniform float FogStart; +uniform float FogEnd; +uniform vec4 FogColor; + +in float vertexDistance; +in vec4 vertexColor; +in vec2 texCoord0; +in vec4 normal; + +out vec4 fragColor; + +void main() { + vec4 color = texture(Sampler0, texCoord0); + if (color.a < 0.1) { + discard; + } + color *= vertexColor * ColorModulator; + fragColor = linear_fog(color, vertexDistance, FogStart, FogEnd, FogColor); +} diff --git a/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.json b/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.json new file mode 100644 index 00000000000..4550883d022 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.json @@ -0,0 +1,30 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "gtceu:rendertype_bloom", + "fragment": "gtceu:rendertype_bloom", + "attributes": [ + "Position", + "Color", + "UV0", + "UV2", + "Normal" + ], + "samplers": [ + { "name": "Sampler0" }, + { "name": "Sampler2" } + ], + "uniforms": [ + { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ChunkOffset", "type": "float", "count": 3, "values": [ 0.0, 0.0, 0.0 ] }, + { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }, + { "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] }, + { "name": "FogShape", "type": "int", "count": 1, "values": [ 0 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.vsh b/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.vsh new file mode 100644 index 00000000000..39cfe866331 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/core/rendertype_bloom.vsh @@ -0,0 +1,32 @@ +#version 150 + +#moj_import +#moj_import + +in vec3 Position; +in vec4 Color; +in vec2 UV0; +in ivec2 UV2; +in vec3 Normal; + +uniform sampler2D Sampler2; + +uniform mat4 ModelViewMat; +uniform mat4 ProjMat; +uniform vec3 ChunkOffset; +uniform int FogShape; + +out float vertexDistance; +out vec4 vertexColor; +out vec2 texCoord0; +out vec4 normal; + +void main() { + vec3 pos = Position + ChunkOffset; + gl_Position = ProjMat * ModelViewMat * vec4(pos, 1.0); + + vertexDistance = fog_distance(ModelViewMat, pos, FogShape); + vertexColor = Color * minecraft_sample_lightmap(Sampler2, UV2); + texCoord0 = UV0; + normal = ProjMat * ModelViewMat * vec4(Normal, 0.0); +} diff --git a/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.fsh b/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.fsh new file mode 100644 index 00000000000..9f35ffb944d --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.fsh @@ -0,0 +1,30 @@ +#version 150 + +#moj_import + +uniform sampler2D Sampler0; + +uniform vec4 ColorModulator; +uniform float FogStart; +uniform float FogEnd; +uniform vec4 FogColor; + +in float vertexDistance; +in vec4 vertexColor; +in vec4 lightMapColor; +in vec4 overlayColor; +in vec2 texCoord0; +in vec4 normal; + +out vec4 fragColor; + +void main() { + vec4 color = texture(Sampler0, texCoord0); + if (color.a < 0.1) { + discard; + } + color *= vertexColor * ColorModulator; + color.rgb = mix(overlayColor.rgb, color.rgb, overlayColor.a); + color *= lightMapColor; + fragColor = linear_fog(color, vertexDistance, FogStart, FogEnd, FogColor); +} diff --git a/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.json b/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.json new file mode 100644 index 00000000000..8d2c550e87f --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.json @@ -0,0 +1,34 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "gtceu:rendertype_entity_bloom", + "fragment": "gtceu:rendertype_entity_bloom", + "attributes": [ + "Position", + "Color", + "UV0", + "UV1", + "UV2", + "Normal" + ], + "samplers": [ + { "name": "Sampler0" }, + { "name": "Sampler1" }, + { "name": "Sampler2" } + ], + "uniforms": [ + { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "IViewRotMat", "type": "matrix3x3", "count": 9, "values": [ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }, + { "name": "Light0_Direction", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0] }, + { "name": "Light1_Direction", "type": "float", "count": 3, "values": [0.0, 0.0, 0.0] }, + { "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] }, + { "name": "FogShape", "type": "int", "count": 1, "values": [ 0 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.vsh b/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.vsh new file mode 100644 index 00000000000..955095d9366 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/core/rendertype_entity_bloom.vsh @@ -0,0 +1,40 @@ +#version 150 + +#moj_import +#moj_import + +in vec3 Position; +in vec4 Color; +in vec2 UV0; +in ivec2 UV1; +in ivec2 UV2; +in vec3 Normal; + +uniform sampler2D Sampler1; +uniform sampler2D Sampler2; + +uniform mat4 ModelViewMat; +uniform mat4 ProjMat; +uniform mat3 IViewRotMat; +uniform int FogShape; + +uniform vec3 Light0_Direction; +uniform vec3 Light1_Direction; + +out float vertexDistance; +out vec4 vertexColor; +out vec4 lightMapColor; +out vec4 overlayColor; +out vec2 texCoord0; +out vec4 normal; + +void main() { + gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); + + vertexDistance = fog_distance(ModelViewMat, IViewRotMat * Position, FogShape); + vertexColor = minecraft_mix_light(Light0_Direction, Light1_Direction, Normal, Color); + lightMapColor = texelFetch(Sampler2, UV2 / 16, 0); + overlayColor = texelFetch(Sampler1, UV1, 0); + texCoord0 = UV0; + normal = ProjMat * ModelViewMat * vec4(Normal, 0.0); +} diff --git a/src/main/resources/assets/gtceu/shaders/post/bloom_unity.json b/src/main/resources/assets/gtceu/shaders/post/bloom_unity.json new file mode 100644 index 00000000000..1120226e8f3 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/post/bloom_unity.json @@ -0,0 +1,74 @@ +{ + "targets": [ + "final", + "filter", + { "name": "swap_a2", "bilinear": true }, + { "name": "swap_a4", "bilinear": true }, + { "name": "swap_1", "bilinear": true }, + { "name": "swap_2", "bilinear": true } + ], + "passes": [ + { + "name": "gtceu:filter_bloom_color", + "intarget": "final", + "outtarget": "filter", + "auxtargets": [ + { "id": "final:depth", "name": "DiffuseDepthSampler" }, + { "id": "minecraft:main:depth", "name": "MainDepthSampler" } + ] + }, + { + "name": "blit", + "intarget": "filter", + "outtarget": "swap_a2" + }, + { + "name": "gtceu:down_sampling", + "intarget": "swap_a2", + "outtarget": "swap_a4" + }, + { + "name": "gtceu:down_sampling", + "intarget": "swap_a4", + "outtarget": "swap_1" + }, + { + "name": "gtceu:down_sampling", + "intarget": "swap_1", + "outtarget": "swap_2" + }, + { + "name": "gtceu:up_sampling", + "intarget": "swap_2", + "outtarget": "swap_1", + "auxtargets": [ + { "id": "swap_a4", "name": "DownTexture" } + ] + }, + { + "name": "gtceu:up_sampling", + "intarget": "swap_1", + "outtarget": "swap_2", + "auxtargets": [ + { "id": "swap_a2", "name": "DownTexture" } + ] + }, + { + "name": "gtceu:up_sampling", + "intarget": "swap_2", + "outtarget": "swap_1", + "auxtargets": [ + { "id": "filter", "name": "DownTexture" } + ] + }, + { + "name": "gtceu:unity_composite", + "intarget": "swap_1", + "outtarget": "final", + "auxtargets": [ + { "id": "filter", "name": "HighlightSampler" }, + { "id": "minecraft:main", "name": "MainSampler" } + ] + } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/post/bloom_unreal.json b/src/main/resources/assets/gtceu/shaders/post/bloom_unreal.json new file mode 100644 index 00000000000..b383aad0e33 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/post/bloom_unreal.json @@ -0,0 +1,157 @@ +{ + "targets": [ + "final", + "filter", + { "name": "swap_b0", "bilinear": true }, + { "name": "swap_b1", "bilinear": true }, + { "name": "swap_b2", "bilinear": true }, + { "name": "swap_b3", "bilinear": true }, + { "name": "swap_b4", "bilinear": true } + ], + "passes": [ + { + "name": "gtceu:filter_bloom_color", + "intarget": "final", + "outtarget": "filter", + "auxtargets": [ + { "id": "final:depth", "name": "DiffuseDepthSampler" }, + { "id": "minecraft:main:depth", "name": "MainDepthSampler" } + ] + }, + { + "name": "gtceu:blur", + "intarget": "filter", + "outtarget": "swap_b0", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 1.0, 0.0 ] + }, + { + "name": "Radius", + "values": [3] + } + ] + }, + { + "name": "gtceu:blur", + "intarget": "swap_b0", + "outtarget": "swap_b1", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 0.0, 1.0 ] + }, + { + "name": "Radius", + "values": [3] + } + ] + }, + { + "name": "gtceu:blur", + "intarget": "swap_b1", + "outtarget": "swap_b0", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 1.0, 0.0 ] + }, + { + "name": "Radius", + "values": [5] + } + ] + }, + { + "name": "gtceu:blur", + "intarget": "swap_b0", + "outtarget": "swap_b2", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 0.0, 1.0 ] + }, + { + "name": "Radius", + "values": [5] + } + ] + }, + { + "name": "gtceu:blur", + "intarget": "swap_b2", + "outtarget": "swap_b0", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 1.0, 0.0 ] + }, + { + "name": "Radius", + "values": [7] + } + ] + }, + { + "name": "gtceu:blur", + "intarget": "swap_b0", + "outtarget": "swap_b3", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 0.0, 1.0 ] + }, + { + "name": "Radius", + "values": [7] + } + ] + }, + { + "name": "gtceu:blur", + "intarget": "swap_b3", + "outtarget": "swap_b0", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 1.0, 0.0 ] + }, + { + "name": "Radius", + "values": [9] + } + ] + }, + { + "name": "gtceu:blur", + "intarget": "swap_b0", + "outtarget": "swap_b4", + "uniforms": [ + { + "name": "BlurDir", + "values": [ 0.0, 1.0 ] + }, + { + "name": "Radius", + "values": [9] + } + ] + }, + { + "name": "gtceu:unreal_composite", + "intarget": "minecraft:main", + "outtarget": "final", + "auxtargets": [ + { "id": "filter", "name": "HighlightSampler" }, + { "id": "swap_b1", "name": "BlurTexture1" }, + { "id": "swap_b2", "name": "BlurTexture2" }, + { "id": "swap_b3", "name": "BlurTexture3" }, + { "id": "swap_b4", "name": "BlurTexture4" } + ], + "uniforms": [ + { "name": "BloomRadius", "values": [1.0] } + ] + } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/program/blur.fsh b/src/main/resources/assets/gtceu/shaders/program/blur.fsh new file mode 100644 index 00000000000..6ab6c8ae16e --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/blur.fsh @@ -0,0 +1,43 @@ +#version 150 + +#define PI 3.141592653 + +uniform sampler2D DiffuseSampler; +uniform vec2 BlurDir; +uniform float Radius; +uniform vec2 OutSize; + +in vec2 texCoord; + +out vec4 fragColor; + +const float INV_SQRT_2PI = 1 / sqrt(2 * PI); + +// gaussian probability density function +float gaussianPdf(float x, float sigma) { + // this is the same as (1 / sqrt(2 * PI * sigma)) * exp(-(x^2) / (2 * sigma * sigma)) + // but it's technically more efficient, since it only uses division once + // and the inverse square root is stored as a constant + float invSigma = 1 / sigma; + return (INV_SQRT_2PI * invSigma) * exp(-(x * x) * (0.5 * invSigma * invSigma)); +} + +void main() { + vec2 invSize = 1.0 / OutSize; + + float weightSum = gaussianPdf(0.0, Radius); + vec4 diffuseSum = texture(DiffuseSampler, texCoord) * weightSum; + + for(float x = 1; x < Radius; x += 1.0) { + float w = gaussianPdf(x, Radius); + vec2 uvOffset = BlurDir * invSize * x; + + // sample both +x and -x offsets + vec4 sample1 = texture(DiffuseSampler, texCoord + uvOffset); + vec4 sample2 = texture(DiffuseSampler, texCoord - uvOffset); + + diffuseSum += (sample1 + sample2) * w; + weightSum += 2.0 * w; + } + fragColor = diffuseSum / weightSum; +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/shaders/program/blur.json b/src/main/resources/assets/gtceu/shaders/program/blur.json new file mode 100644 index 00000000000..8a1ed353426 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/blur.json @@ -0,0 +1,21 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha", + "srcalpha": "zero", + "dstalpha": "one" + }, + "vertex": "blit", + "fragment": "gtceu:blur", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "BlurDir", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "Radius", "type": "float", "count": 1, "values": [ 5 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/program/down_sampling.fsh b/src/main/resources/assets/gtceu/shaders/program/down_sampling.fsh new file mode 100644 index 00000000000..c025a3ee686 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/down_sampling.fsh @@ -0,0 +1,76 @@ +#version 150 + +uniform sampler2D DiffuseSampler; +uniform vec2 OutSize; +uniform vec2 InSize; + +in vec2 texCoord; + +out vec4 fragColor; + +#define OUTPUT_SCALE_FACTOR (0.25 * 0.25 * 0.125) + +vec2 inTexel = 1.0 / InSize; +vec2 inTexelInv = vec2(-inTexel.x, inTexel.y); + +vec2 outTexel = 1.0 / OutSize; +vec2 outTexelX = vec2(outTexel.x, 0.0); +vec2 outTexelY = vec2(0.0, outTexel.y); +vec2 outTexelInv = vec2(-outTexel.x, outTexel.y); + +vec4 average(vec4 center, vec4 left, vec4 right, vec4 up, vec4 down, bool accountCenterColor) { + float totalAlpha = abs(center.a - left.a) + abs(center.a - right.a) + abs(center.a - up.a) + abs(center.a - down.a); + vec3 totalColor = (left.rgb * left.a) + + (right.rgb * right.a) + + (up.rgb * up.a) + + (down.rgb * down.a) + + (center.rgb * center.a * float(accountCenterColor)); + + return vec4(totalColor, totalAlpha); +} + +vec4 four_k(vec2 uv) { + vec4 center = texture(DiffuseSampler, uv); // 1 1 + vec4 tl = texture(DiffuseSampler, uv + inTexel); // 1 1 + vec4 tr = texture(DiffuseSampler, uv + inTexelInv); // -1 1 + vec4 bl = texture(DiffuseSampler, uv - inTexel); // -1 -1 + vec4 br = texture(DiffuseSampler, uv - inTexelInv); // 1 -1 + + return average(center, tl, tr, bl, br, false); +} + +// I really hope GPU drivers are smart enough to optimize most of the repeated lookups away +// - screret + +void main() { + vec4 center = four_k(texCoord + outTexel) // 1 1 + + four_k(texCoord + outTexelInv) // -1 1 + + four_k(texCoord - outTexelInv) // 1 -1 + + four_k(texCoord - outTexel); // -1 -1 + + vec4 tl = four_k(texCoord + outTexelInv) // -1 1 + + four_k(texCoord - outTexelX) // -1 0 + + four_k(texCoord + outTexelY) // 0 1 + + four_k(texCoord); // 0 0 + + vec4 tr = four_k(texCoord + outTexel) // 1 1 + + four_k(texCoord + outTexelX) // 1 0 + + four_k(texCoord + outTexelY) // 0 1 + + four_k(texCoord); // 0 0 + + vec4 bl = four_k(texCoord - outTexel) // -1 -1 + + four_k(texCoord - outTexelX) // -1 0 + + four_k(texCoord - outTexelY) // 0 -1 + + four_k(texCoord); // 0 0 + + vec4 br = four_k(texCoord - outTexelInv) // 1 -1 + + four_k(texCoord - outTexelY) // 0 -1 + + four_k(texCoord + outTexelX) // 1 0 + + four_k(texCoord); // 0 0 + + fragColor = average(center, tl, tr, bl, br, true); + + // Optimization: do multiplication in one step at the end + // They used to be done separately on each addition to fragColor and in four_k +// fragColor.rgb *= OUTPUT_SCALE_FACTOR; +} diff --git a/src/main/resources/assets/gtceu/shaders/program/down_sampling.json b/src/main/resources/assets/gtceu/shaders/program/down_sampling.json new file mode 100644 index 00000000000..244807fae30 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/down_sampling.json @@ -0,0 +1,19 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha", + "srcalpha": "zero", + "dstalpha": "one" + }, + "vertex": "blit", + "fragment": "gtceu:down_sampling", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" } + ], + "uniforms": [ + { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/program/filter_bloom_color.fsh b/src/main/resources/assets/gtceu/shaders/program/filter_bloom_color.fsh new file mode 100644 index 00000000000..78b9350554f --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/filter_bloom_color.fsh @@ -0,0 +1,33 @@ +#version 150 + +uniform sampler2D DiffuseSampler; +uniform sampler2D DiffuseDepthSampler; +uniform sampler2D MainDepthSampler; + +// these should be #defines, but adding those dynamically doesn't exist in vanilla MC until 26.1. +// GameRenderer.PROJECTION_Z_NEAR +uniform float DepthNear = 0.05; +// GameRenderer#getDepthFar; 8 chunk render distance -> 8 * 16 * 4 +uniform float DepthFar = 512.0; + +in vec2 texCoord; + +out vec4 fragColor; + +float linearizeDepth(float depth) { + float z = depth * 2.0 - 1.0; // back to NDC + return (2.0 * DepthNear * DepthFar) / (DepthFar + DepthNear - z * (DepthFar - DepthNear)); +} + +void main() { + + // calculate linear depth + float mainDepth = linearizeDepth(texture(MainDepthSampler, texCoord).r); + float diffuseDepth = linearizeDepth(texture(DiffuseDepthSampler, texCoord).r); + // clear bloom color fragment if the main sampler's depth isn't the same as the bloom sampler's depth + if (abs(mainDepth - diffuseDepth) > 1.0e-5) { + fragColor = vec4(0.0); + } else { + fragColor = texture(DiffuseSampler, texCoord); + } +} diff --git a/src/main/resources/assets/gtceu/shaders/program/filter_bloom_color.json b/src/main/resources/assets/gtceu/shaders/program/filter_bloom_color.json new file mode 100644 index 00000000000..120f270d7ab --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/filter_bloom_color.json @@ -0,0 +1,23 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha", + "srcalpha": "zero", + "dstalpha": "one" + }, + "vertex": "blit", + "fragment": "gtceu:filter_bloom_color", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" }, + { "name": "DiffuseDepthSampler" }, + { "name": "MainDepthSampler" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "DepthNear", "type": "float", "count": 1, "values": [ 0.05 ] }, + { "name": "DepthFar", "type": "float", "count": 1, "values": [ 512.0 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/program/unity_composite.fsh b/src/main/resources/assets/gtceu/shaders/program/unity_composite.fsh new file mode 100644 index 00000000000..93c5c8d2a18 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/unity_composite.fsh @@ -0,0 +1,26 @@ +#version 150 + +uniform sampler2D DiffuseSampler; +uniform sampler2D HighlightSampler; +uniform sampler2D MainSampler; +uniform float BloomStrength; +uniform float BaseBrightness; +uniform float MaxBrightness; +uniform float MinBrightness; + +in vec2 texCoord; +out vec4 fragColor; + +void main() { + vec4 bloom = BloomStrength * texture(DiffuseSampler, texCoord); + + vec4 highlight = texture(HighlightSampler, texCoord); + vec4 background = texture(MainSampler, texCoord); + background.rgb = background.rgb * (1 - highlight.a) + highlight.a * highlight.rgb; + + float min = min(background.r, min(background.g, background.b)); + float max = max(background.r, max(background.g, background.b)); + float backgroundBrightness = (max + min) / 2.0; + + fragColor = vec4(background.rgb + bloom.rgb * (MinBrightness + BaseBrightness + (1.0 - backgroundBrightness) * (MaxBrightness - MinBrightness)), bloom.a); +} diff --git a/src/main/resources/assets/gtceu/shaders/program/unity_composite.json b/src/main/resources/assets/gtceu/shaders/program/unity_composite.json new file mode 100644 index 00000000000..411ff0180fa --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/unity_composite.json @@ -0,0 +1,25 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha", + "srcalpha": "zero", + "dstalpha": "one" + }, + "vertex": "blit", + "fragment": "gtceu:unity_composite", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" }, + { "name": "HighlightSampler" }, + { "name": "MainSampler" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "BloomStrength", "type": "float", "count": 1, "values": [ 1.7 ] }, + { "name": "BaseBrightness", "type": "float", "count": 1, "values": [ 0.1 ] }, + { "name": "MaxBrightness", "type": "float", "count": 1, "values": [ 0.5 ] }, + { "name": "MinBrightness", "type": "float", "count": 1, "values": [ 0.2 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/program/unreal_composite.fsh b/src/main/resources/assets/gtceu/shaders/program/unreal_composite.fsh new file mode 100644 index 00000000000..be8b8279839 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/unreal_composite.fsh @@ -0,0 +1,66 @@ +#version 150 + +uniform sampler2D DiffuseSampler; +uniform sampler2D HighlightSampler; +uniform sampler2D BlurTexture1; +uniform sampler2D BlurTexture2; +uniform sampler2D BlurTexture3; +uniform sampler2D BlurTexture4; +uniform float BloomRadius; +uniform float BloomStrength; +uniform float BaseBrightness; +uniform float MaxBrightness; +uniform float MinBrightness; + +in vec2 texCoord; +out vec4 fragColor; + +float lerpBloomFactor(float factor) { + float mirrorFactor = 1.2 - factor; + return mix(factor, mirrorFactor, BloomRadius); +} + +// from https://www.shadertoy.com/view/4dBcD1, explanation(s) there +vec3 jodieReinhardTonemap(vec3 color) { + float luma = dot(color, vec3(0.2126, 0.7152, 0.0722)); + vec3 tc = color / (color + 1.0); + + return mix(color / (luma + 1.0), tc, tc); +} +vec3 jodieReinhard2Tonemap(const vec3 color) { + float luma = dot(color, vec3(.2126, .7152, .0722)); + + // tonemap curve goes on this line + // (I used reinhard here) + vec4 rgbl = vec4(color, luma) / (luma + 1.); + + vec3 mappedColor = rgbl.rgb; + float mappedLuma = rgbl.a; + + float channelMax = max(max(max(mappedColor.r, mappedColor.g), mappedColor.b), 1.0); + + // this is just the simplified/optimised math of the more human readable version linked above + return ( + (mappedLuma * mappedColor - mappedColor) - + (channelMax * mappedLuma - mappedLuma) + ) / (mappedLuma - channelMax); +} + +void main() { + vec4 bloom = BloomStrength * ( + lerpBloomFactor(1.0) * texture(BlurTexture1, texCoord) + + lerpBloomFactor(0.8) * texture(BlurTexture2, texCoord) + + lerpBloomFactor(0.6) * texture(BlurTexture3, texCoord) + + lerpBloomFactor(0.4) * texture(BlurTexture4, texCoord)); + bloom.rgb = jodieReinhardTonemap(bloom.rgb); + + vec4 background = texture(DiffuseSampler, texCoord); + vec4 highlight = texture(HighlightSampler, texCoord); + background.rgb = background.rgb * (1 - highlight.a) + highlight.rgb * highlight.a; + + float min = min(background.r, min(background.g, background.b)); + float max = max(background.r, max(background.g, background.b)); + float backgroundBrightness = (max + min) / 2.0; + + fragColor = vec4(background.rgb + bloom.rgb * (MinBrightness + BaseBrightness + (1.0 - backgroundBrightness) * (MaxBrightness - MinBrightness)), bloom.a); +} diff --git a/src/main/resources/assets/gtceu/shaders/program/unreal_composite.json b/src/main/resources/assets/gtceu/shaders/program/unreal_composite.json new file mode 100644 index 00000000000..011e688ca50 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/unreal_composite.json @@ -0,0 +1,29 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha", + "srcalpha": "zero", + "dstalpha": "one" + }, + "vertex": "blit", + "fragment": "gtceu:unreal_composite", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" }, + { "name": "HighlightSampler" }, + { "name": "BlurTexture1" }, + { "name": "BlurTexture2" }, + { "name": "BlurTexture3" }, + { "name": "BlurTexture4" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "BloomRadius", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "BloomStrength", "type": "float", "count": 1, "values": [ 1.7 ] }, + { "name": "BaseBrightness", "type": "float", "count": 1, "values": [ 0.1 ] }, + { "name": "MaxBrightness", "type": "float", "count": 1, "values": [ 0.5 ] }, + { "name": "MinBrightness", "type": "float", "count": 1, "values": [ 0.2 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/shaders/program/up_sampling.fsh b/src/main/resources/assets/gtceu/shaders/program/up_sampling.fsh new file mode 100644 index 00000000000..5a8df90ad0e --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/up_sampling.fsh @@ -0,0 +1,46 @@ +#version 150 + +uniform sampler2D DiffuseSampler; +uniform sampler2D DownTexture; +uniform vec2 OutSize; + +in vec2 texCoord; + +out vec4 fragColor; + +vec2 outTexel = 1.0 / OutSize; +vec2 outTexelX = vec2(outTexel.x, 0.0); +vec2 outTexelY = vec2(0.0, outTexel.y); +vec2 outTexelInv = vec2(-outTexel.x, outTexel.y); + +vec4 average(vec4 center, vec4 left, vec4 right, vec4 up, vec4 down, bool accountCenterColor) { + float totalAlpha = abs(center.a - left.a) + abs(center.a - right.a) + abs(center.a - up.a) + abs(center.a - down.a); + vec3 totalColor = (left.rgb * left.a) + + (right.rgb * right.a) + + (up.rgb * up.a) + + (down.rgb * down.a) + + (center.rgb * center.a * float(accountCenterColor)); + + return vec4(totalColor, totalAlpha); +} + +void main() { + vec4 center = texture(DiffuseSampler, texCoord) * 4.0; // 0 0 + + vec4 tr = texture(DiffuseSampler, texCoord + outTexel); // 1 1 + vec4 tl = texture(DiffuseSampler, texCoord - outTexelInv); // 1 -1 + vec4 br = texture(DiffuseSampler, texCoord + outTexelInv); // -1 1 + vec4 bl = texture(DiffuseSampler, texCoord - outTexel); // -1 -1 + + vec4 right = texture(DiffuseSampler, texCoord + outTexelX) * 2.0; // 1 0 + vec4 left = texture(DiffuseSampler, texCoord - outTexelX) * 2.0; // -1 0 + vec4 up = texture(DiffuseSampler, texCoord + outTexelY) * 2.0; // 0 1 + vec4 down = texture(DiffuseSampler, texCoord - outTexelY) * 2.0; // 0 -1 + + vec4 colorSum = average(center, left, right, up, down, true); + colorSum += average(center, tl, tr, bl, br, false); + + colorSum = (colorSum / 16.0 + texture(DownTexture, texCoord)) * 0.8; + + fragColor = clamp(colorSum, 0.0, 1.0); +} diff --git a/src/main/resources/assets/gtceu/shaders/program/up_sampling.json b/src/main/resources/assets/gtceu/shaders/program/up_sampling.json new file mode 100644 index 00000000000..1ada000f1e3 --- /dev/null +++ b/src/main/resources/assets/gtceu/shaders/program/up_sampling.json @@ -0,0 +1,20 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha", + "srcalpha": "zero", + "dstalpha": "one" + }, + "vertex": "blit", + "fragment": "gtceu:up_sampling", + "attributes": [ "Position" ], + "samplers": [ + { "name": "DiffuseSampler" }, + { "name": "DownTexture" } + ], + "uniforms": [ + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] } + ] +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta index 679654e7450..197e174c743 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/filter_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/cleanroom/filter_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/cleanroom/filter_casing_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta index 0b6135d2c98..bcfe132b2ef 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/plascrete.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/cleanroom/plascrete_ctm" - } + "gtceu": { + "connection_texture": "gtceu:block/casings/cleanroom/plascrete_ctm" + } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta index 0e1b3e83e63..bb26602ecf7 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/cleanroom/sterilizing_filter_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/cleanroom/sterilizing_filter_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/cleanroom/sterilizing_filter_casing_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta index d611cacb4ef..78607c6ca08 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_cupronickel_ctm" - } + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_cupronickel_ctm" + } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta index b1e5096ccb5..419344f2357 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_cupronickel_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_cupronickel_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_cupronickel_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta index d0eb5a1b4e0..2f8b0f3c606 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_hssg_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_hssg_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta index a3d39d70b26..7007fd7d399 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_hssg_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_hssg_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_hssg_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta index a543d938427..7323ad0e179 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_kanthal_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_kanthal_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta index 5f77e5af023..369076e1f9d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_kanthal_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_kanthal_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_kanthal_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta index cdf115622d5..ee713eaaf40 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta index e5d9efbf204..15eded51a94 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_molybdenum_disilicide_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta index 2e4b0f7663e..8d778222e5f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_naquadah_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_naquadah_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta index 89be208adcf..4e7c10b2cff 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_naquadah_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_naquadah_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_naquadah_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta index 4ea55aec150..b769004afbd 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_nichrome_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_nichrome_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta index d454af3ff67..8afaa449311 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_nichrome_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_nichrome_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_nichrome_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta index 746da5c90c5..6b2870c83a6 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_rtm_alloy_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_rtm_alloy_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta index 527eb9bb051..6d09c673e6f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_rtm_alloy_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_rtm_alloy_bloom_ctm", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_rtm_alloy_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta index 5e76601ac3e..a604c36f15e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_superconductor_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_superconductor_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta index 2f5edd2ed74..824306dde04 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_superconductor_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta index 6ae83eb0551..17e24d0d0f3 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_trinium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_trinium_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta index 0d93c95e458..75e5e226e1f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_trinium_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_trinium_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_trinium_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta index 49409f48da5..76d31028072 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tritanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tritanium_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta index 1aa566dca58..5153271f7ba 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tritanium_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tritanium_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tritanium_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta index 274e5147e1d..66a136186c5 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tungstensteel_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta index 11a9a3bcd34..df8fd23d60c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_tungstensteel_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_tungstensteel_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/coils/machine_coil_tungstensteel_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta index 618e068e4dd..653afb29006 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_bronze.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_bronze_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_bronze_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta index f07082f52f5..f120eaf9032 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_steel_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta index 06e9796abed..afe2869054b 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_titanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_titanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_titanium_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta index fdd57cb4a7a..6ee0e5eb3d5 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/firebox/machine_casing_firebox_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/firebox/machine_casing_firebox_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/firebox/machine_casing_firebox_tungstensteel_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta index 60ef8c970be..42c81b1632c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta index d63d26a280c..72d1a0104b4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_bloom_ctm", "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta index 266021414e4..f8063da866f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk2.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_mk2_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_mk2_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta index 8b45a91c06a..4fd16130b5c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/fusion_casing_mk3.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/fusion_casing_mk3_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/fusion_casing_mk3_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta index 0efbe8cd43c..e8fd0abfc97 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/fusion/superconducting_coil_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/fusion/superconducting_coil_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta index 2f5edd2ed74..824306dde04 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", - "emissive": true - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/casings/coils/machine_coil_superconductor_bloom_ctm", "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta index e333118814e..5f4d1c8fd47 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/fusion/superconducting_coil_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta index ec7ee024889..4e544655bb0 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/atomic_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/atomic_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/atomic_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta index c5ad2294e42..34dd301c21d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/corrosion_proof_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/corrosion_proof_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/corrosion_proof_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta index 2457291b40f..c5fa362c0f9 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/high_temperature_smelting_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/high_temperature_smelting_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/high_temperature_smelting_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta index 0f942a68354..cebb04f9e44 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/industrial_steam_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/industrial_steam_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/industrial_steam_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta index 306854983f3..67a616a6316 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/large_scale_assembling_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/large_scale_assembling_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/large_scale_assembling_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta index df8cb84ff6f..24476332093 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/laser_safe_engraving_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/laser_safe_engraving_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/laser_safe_engraving_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta index eafb895c281..1e3827124a1 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/nonconducting_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/nonconducting_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/nonconducting_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta index ae09e8eb280..5b62e5ce35d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/reaction_safe_mixing_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/reaction_safe_mixing_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/reaction_safe_mixing_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta index 3768093e52a..f6ec7e514b4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/secure_maceration_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/secure_maceration_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/secure_maceration_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta index cf058736156..b13d57a26f7 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/shock_proof_cutting_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/shock_proof_cutting_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/shock_proof_cutting_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta index 58804a3f988..f3cd3b2d23c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/sifter_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/sifter_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/sifter_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta index 19fb6ad2f8f..bf95820d5b5 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/stress_proof_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/stress_proof_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/stress_proof_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta index 20efcbc319f..1e13a18a0da 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/vibration_safe_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/vibration_safe_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/vibration_safe_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta index 4a3033b0362..01c2c216764 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/gcym/watertight_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/gcym/watertight_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/gcym/watertight_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta index 42e07d2dea7..184b499a8ba 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/back.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/back_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/back_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta index 8c187a0684a..8cd3c5a5935 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/bottom.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/bottom_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/bottom_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta index c57c972dc1c..5f54ab8dbe8 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/front.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/front_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/front_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta index 961092b3f9e..7435e5af674 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta index 7e23f5cded5..693c691f8d1 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/advanced_computer_casing/top.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/advanced_computer_casing/top_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/advanced_computer_casing/top_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta index 5878953ae0d..6e6e8c6bb63 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/back.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/back_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/back_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta index 9fb2a643fdb..eddb4850067 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/bottom.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/bottom_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/bottom_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta index 303678ceb2d..ab496cd7ff0 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/front.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/front_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/front_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta index cc1c5d48c57..7ad5ef7f1ea 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta index d4805c14851..e5d8d808ff4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_casing/top.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_casing/top_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_casing/top_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta index c50ce958d8a..714dd86272f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_heat_vent_side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_heat_vent_side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta index f41eea02b1d..a5dbe2bc9c0 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/computer_heat_vent_top_bot.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/computer_heat_vent_top_bot_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/computer_heat_vent_top_bot_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta index 787770c3abd..07dec6c8212 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/hpca/high_power_casing.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/hpca/high_power_casing_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/hpca/high_power_casing_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta index f2e939b3527..a3edcb551d9 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_assembly_line_bloom.png.mcmeta @@ -2,10 +2,7 @@ "animation":{ "frametime":2 }, - "ldlib": { - "emissive": true - }, - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta index aa9b988334d..5e2dd444e27 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_stainless_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_stainless_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_stainless_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta index a7fd421b3b3..72c1a53ba16 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta index 728b371f290..a79cc793f76 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_titanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_titanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_titanium_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta index 4a128ac164e..d23695359ad 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/mechanic/machine_casing_turbine_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/mechanic/machine_casing_turbine_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/mechanic/machine_casing_turbine_tungstensteel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta index 7e7c3fcc388..edb2af3afa7 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_a.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_a_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_a_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta index 41f9c4fca66..1e4a835fdfd 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_b.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_b_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_b_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta index 24ae068cdf3..58c74e507cf 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_c.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_c_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_c_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta index be0c3b09523..31d57035871 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/signs/machine_casing_stripes_d.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/signs/machine_casing_stripes_d_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/signs/machine_casing_stripes_d_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta index 752d89be69b..27d8682d91a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/bottom.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/slicing_blades/bottom_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/slicing_blades/bottom_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta index 2e013feb3a1..92fe24d573a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/side.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/slicing_blades/side_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/slicing_blades/side_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta index fe5e643f07c..7716663f87c 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/slicing_blades/top.png.mcmeta @@ -1,6 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/slicing_blades/top_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/slicing_blades/top_ctm" }, "animation": { "interpolate": false, diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta index 84d6ac55955..f7bc18370f4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_bronze_plated_bricks.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_bronze_plated_bricks_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_bronze_plated_bricks_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta index 87b382c8442..37fdc7ef59f 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_clean_stainless_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_clean_stainless_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_clean_stainless_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta index 06e68458b87..063daa7f6df 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_frost_proof.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_frost_proof_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_frost_proof_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta index 46a7987cfed..6a69dafbaed 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_heatproof.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_heatproof_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_heatproof_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta index df90ab84c03..af024fa07e3 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_inert_ptfe.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_inert_ptfe_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_inert_ptfe_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta index 7cdf09342f4..6960d04e965 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_palladium_substation.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_palladium_substation_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_palladium_substation_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta index 854f8df3dbe..1a2b15bb41b 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_robust_tungstensteel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_robust_tungstensteel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_robust_tungstensteel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta index 12cc1053c71..ad374a7d98d 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_solid_steel.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_solid_steel_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_solid_steel_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta index 97014a06a14..bb8fdf80156 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stable_titanium.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_stable_titanium_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_stable_titanium_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta index 53b118fbefe..e5b5ae4c3e4 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_stainless_evaporation.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_stainless_evaporation_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_stainless_evaporation_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta index 225285146b7..6299e80252e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta index 225285146b7..6299e80252e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/solid/machine_casing_sturdy_hsse_green.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/solid/machine_casing_sturdy_hsse_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta index 4e88ec7cc0c..26a4910f29a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/cleanroom_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/cleanroom_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/cleanroom_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta index d193e57fef1..6264f382525 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/fusion_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/fusion_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/fusion_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta index 0a0ee21c685..b4319b49730 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/laminated_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/laminated_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/laminated_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta index 502bb849399..ff94fb81b10 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/transparent/tempered_glass.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/transparent/tempered_glass_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/transparent/tempered_glass_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta index 17b629c309c..71c9206ffbd 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/crushing_wheels_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/crushing_wheels_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta index cbe1abf13b7..b4a2ed95093 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/crushing_wheels_active.png.mcmeta @@ -1,6 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/crushing_wheels_active_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/crushing_wheels_active_ctm" }, "animation": { "interpolate": false, diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta index 89d89e9d079..8d624c1275a 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/heat_vent_bloom.png.mcmeta @@ -2,7 +2,7 @@ "animation": { "frametime": 1 }, - "shimmer": { + "gtceu": { "bloom": true } } diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta index 39765a1c5d6..60a0eb8b058 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/slicing_blades_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/slicing_blades_ctm" } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta index 1440c3a3821..721f4cb651e 100644 --- a/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/casings/unique/slicing_blades_active.png.mcmeta @@ -1,6 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/casings/unique/slicing_blades_active_ctm" + "gtceu": { + "connection_texture": "gtceu:block/casings/unique/slicing_blades_active_ctm" }, "animation": { "interpolate": false, diff --git a/src/main/resources/assets/gtceu/textures/block/ctm_test.png b/src/main/resources/assets/gtceu/textures/block/ctm_test.png new file mode 100644 index 00000000000..88ea914d2f3 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/ctm_test.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/ctm_test.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/ctm_test.png.mcmeta new file mode 100644 index 00000000000..34afddbda20 --- /dev/null +++ b/src/main/resources/assets/gtceu/textures/block/ctm_test.png.mcmeta @@ -0,0 +1,5 @@ +{ + "gtceu": { + "connection_texture": "gtceu:block/ctm_test_ctm" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png b/src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png new file mode 100644 index 00000000000..7e4b5d08300 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/ctm_test_ctm.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom.png.mcmeta index ff453012c57..c301a7a8f5a 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom.png.mcmeta @@ -1,9 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/black_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/black_bloom_ctm", "bloom": true } -} - +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta index 28943d615fd..d540f92e9d4 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/black_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/black_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_on.png.mcmeta index 5c13fcde49a..12347ec4d5f 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/black_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/black_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/black_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/black_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/black_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/black_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom.png.mcmeta index 313de4456f9..c889309fb30 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/blue_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/blue_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta index e6c3f4b96e9..623d823821b 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/blue_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/blue_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_on.png.mcmeta index 116a33b1c75..ec7799a58b0 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/blue_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/blue_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/blue_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/blue_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/blue_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/blue_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom.png.mcmeta index 5db8b403bd9..1e23d5f8fb0 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/brown_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/brown_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta index 8115cf5c3cb..1eff63925b0 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/brown_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/brown_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_on.png.mcmeta index 16ca1f1305f..2d910f7b266 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/brown_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/brown_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/brown_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/brown_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/brown_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/brown_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom.png.mcmeta index 65522bdc8fb..9eab8949a7c 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/cyan_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/cyan_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta index edcb44542fe..251dd85873d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/cyan_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/cyan_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on.png.mcmeta index 1e35d272972..d04fd0d6097 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/cyan_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/cyan_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/cyan_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom.png.mcmeta index ce76a054ea7..0299bf9dc14 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/gray_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/gray_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta index 3ec9391d805..5196d6cddbb 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/gray_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/gray_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_on.png.mcmeta index cbc26838129..9943bf7c836 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/gray_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/gray_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/gray_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/gray_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/gray_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/gray_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom.png.mcmeta index 38fe7740e76..2a60822bd60 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/green_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/green_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_ctm_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta index 34ae9f7ae18..3ee9471d4cf 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/green_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/green_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/green_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/green_on.png.mcmeta index 6074941a516..85469151a79 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/green_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/green_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/green_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/green_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom.png.mcmeta index 00958024c4a..cf7408e3bdb 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_blue_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_blue_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta index 4bcde263e5f..ebc03338d1d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_blue_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_blue_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on.png.mcmeta index dafb5e4a108..dbfc460f870 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_blue_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_blue_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_blue_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta index 3b30d57e8c1..52d15b67196 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_gray_ctm_emissive" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_gray_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta index 5cfccb7226f..32ae60ef967 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_gray_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_gray_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta index 3761d1c9e64..f8cdf3acb09 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/light_gray_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/light_gray_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/light_gray_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom.png.mcmeta index 4b238ac69c1..3cdad29c52f 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/lime_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/lime_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta index 52dfcbae47c..6bb707d9745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/lime_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/lime_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_on.png.mcmeta index 41bab1624eb..761e6e27029 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/lime_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/lime_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/lime_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/lime_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/lime_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/lime_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom.png.mcmeta index b4e1d4d53b6..8f0f1bde4df 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/magenta_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/magenta_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta index 5809d1c23a4..eb754db1014 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/magenta_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/magenta_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_on.png.mcmeta index 0278b6ccc48..a485f4942bd 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/magenta_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/magenta_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/magenta_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/magenta_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom.png.mcmeta index eb9d61c06c6..b163cbbcb96 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/orange_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/orange_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_ctm_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta index eabf6bb2656..c790daf2e7d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/orange_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/orange_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/orange_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/orange_on.png.mcmeta index 17eea4ce1ed..d0e1825998f 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/orange_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/orange_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/orange_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/orange_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom.png.mcmeta index 29c10bfe24d..1a5c77f6d2b 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/pink_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/pink_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta index ce444d36c89..df209795670 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/pink_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/pink_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_on.png.mcmeta index cf9b95eb37d..0bc33c2b6e5 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/pink_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/pink_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/pink_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/pink_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/pink_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/pink_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom.png.mcmeta index 942e844eaa7..a99d5e93fd9 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/purple_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/purple_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta index 067da7a4996..c23cbdc43e8 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/purple_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/purple_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_on.png.mcmeta index e2f7fcfda8a..d9a7215ea62 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/purple_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/purple_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/purple_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/purple_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/purple_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/purple_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom.png.mcmeta index 70de0198151..e7bc790288d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/red_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/red_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta index be15cc2a979..a8f33bceb6d 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/red_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/red_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_on.png.mcmeta index bb34744e74d..b0d0d50508e 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/red_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/red_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/red_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/red_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/red_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/red_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom.png.mcmeta index 8a579d67dd6..19bf97f06f1 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/white_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/white_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta index 2c90d5cde00..5d2e3d36601 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/white_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/white_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_on.png.mcmeta index 9c7a3a147a8..a3c0b0de9d9 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/white_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/white_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/white_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/white_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/white_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/white_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom.png.mcmeta index 99638cdc659..93d4e56f77c 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/yellow_bloom_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/yellow_bloom_ctm", "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom_ctm.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_bloom_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_bloom.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_bloom.png.mcmeta index 4da3f5f1299..c29eace5074 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_bloom.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_bloom.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": true } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_on.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_borderless_on.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta index d582a53eb12..09f1c035f6b 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_off.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/yellow_off_ctm" + "gtceu": { + "connection_texture": "gtceu:block/lamps/yellow_off_ctm" } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on.png.mcmeta index ebf371f8d42..57f5d1f2f42 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on.png.mcmeta @@ -1,8 +1,6 @@ { - "ldlib": { - "connection": "gtceu:block/lamps/yellow_on_ctm" - }, - "shimmer": { + "gtceu": { + "connection_texture": "gtceu:block/lamps/yellow_on_ctm", "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on_ctm.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on_ctm.png.mcmeta index 4662e246aa1..7eef7f8b745 100644 --- a/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on_ctm.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/lamps/yellow_on_ctm.png.mcmeta @@ -1,5 +1,5 @@ { - "shimmer": { + "gtceu": { "bloom": false } -} +} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front.png b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front.png deleted file mode 100644 index 729e656da01..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active.png b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active.png deleted file mode 100644 index cad1bcaa2bb..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active.png.mcmeta deleted file mode 100644 index cfcef74876f..00000000000 --- a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active.png.mcmeta +++ /dev/null @@ -1,10 +0,0 @@ -{ - "animation": { - "frametime": 16, - "frames": [ - 0, - 1, - 2 - ] - } -} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active_emissive.png b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active_emissive.png deleted file mode 100644 index 76c223417d8..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active_emissive.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active_emissive.png.mcmeta deleted file mode 100644 index cfcef74876f..00000000000 --- a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_active_emissive.png.mcmeta +++ /dev/null @@ -1,10 +0,0 @@ -{ - "animation": { - "frametime": 16, - "frames": [ - 0, - 1, - 2 - ] - } -} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_emissive.png b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_emissive.png deleted file mode 100644 index 0486a073200..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_emissive.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_paused.png b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_paused.png deleted file mode 100644 index 901e9e1e126..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_paused.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_paused_emissive.png b/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_paused_emissive.png deleted file mode 100644 index f18b9aa3899..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/advanced_processing_array/overlay_front_paused_emissive.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front.png b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front.png deleted file mode 100644 index 729e656da01..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active.png b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active.png deleted file mode 100644 index cad1bcaa2bb..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active.png.mcmeta deleted file mode 100644 index cfcef74876f..00000000000 --- a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active.png.mcmeta +++ /dev/null @@ -1,10 +0,0 @@ -{ - "animation": { - "frametime": 16, - "frames": [ - 0, - 1, - 2 - ] - } -} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active_emissive.png b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active_emissive.png deleted file mode 100644 index 76c223417d8..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active_emissive.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active_emissive.png.mcmeta deleted file mode 100644 index cfcef74876f..00000000000 --- a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_active_emissive.png.mcmeta +++ /dev/null @@ -1,10 +0,0 @@ -{ - "animation": { - "frametime": 16, - "frames": [ - 0, - 1, - 2 - ] - } -} \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_emissive.png b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_emissive.png deleted file mode 100644 index 0486a073200..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_emissive.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_paused.png b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_paused.png deleted file mode 100644 index 901e9e1e126..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_paused.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_paused_emissive.png b/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_paused_emissive.png deleted file mode 100644 index f18b9aa3899..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/block/multiblock/processing_array/overlay_front_paused_emissive.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta index 38c2c75c408..deb8a6cb565 100644 --- a/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/overlay/machine/overlay_monitor.png.mcmeta @@ -1,5 +1,5 @@ { - "ldlib": { - "connection": "gtceu:block/overlay/machine/overlay_monitor_ctm" + "gtceu": { + "connection_texture": "gtceu:block/overlay/machine/overlay_monitor_ctm" } } diff --git a/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta index 53a9815890b..352db4d3be4 100644 --- a/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/pipe/ld_fluid_pipe/overlay_emissive.png.mcmeta @@ -1,8 +1,5 @@ { - "ldlib": { - "emissive": true - }, - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta b/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta index 53a9815890b..352db4d3be4 100644 --- a/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta +++ b/src/main/resources/assets/gtceu/textures/block/pipe/ld_item_pipe/overlay_emissive.png.mcmeta @@ -1,8 +1,5 @@ { - "ldlib": { - "emissive": true - }, - "shimmer": { + "gtceu": { "bloom": true } } \ No newline at end of file diff --git a/src/main/resources/gtceu.mixins.json b/src/main/resources/gtceu.mixins.json index 84336bfed86..1389ff4c42c 100644 --- a/src/main/resources/gtceu.mixins.json +++ b/src/main/resources/gtceu.mixins.json @@ -1,6 +1,9 @@ { "required": true, "minVersion": "0.8", + "mixinextras": { + "minVersion": "0.5.0-rc.3" + }, "refmap": "gtceu.refmap.json", "package": "com.gregtechceu.gtceu.core.mixins", "compatibilityLevel": "JAVA_17", @@ -17,10 +20,28 @@ "client.GuiHeartTypeMixin", "client.HumanoidArmorLayerMixin", "client.LevelRendererMixin", + "client.ModelBakerImplMixin", "client.ModelManagerMixin", "client.MultiPlayerGameModeMixin", "client.PlayerInfoAccessor", + "client.RenderStateShardAccessor", + "client.TextureAtlasMixin", "client.VariantDeserializerMixin", + "client.VertexConsumerMixin", + "client.bloom.GameRendererAccessor", + "client.bloom.LevelRendererMixin", + "client.bloom.PostChainAccessor", + "client.bloom.ForgeModelBlockRendererMixin", + "client.bloom.LevelRendererAccessor", + "client.bloom.ModelBlockRendererMixin", + "client.bloom.QuadLighterMixin", + "client.bloom.RebuildTaskMixin", + "client.bloom.normal.RenderTypeMixin", + "client.bloom.normal.embeddium.BlockRendererMixin", + "client.bloom.normal.embeddium.DefaultMaterialsMixin", + "client.bloom.normal.embeddium.DefaultTerrainRenderPassesMixin", + "client.bloom.normal.oculus.WorldRenderingPhaseMixin", + "client.bloom.safemode.embeddium.BlockRendererMixin", "dev.client.KeyboardHandlerMixin", "ftbchunks.FTBChunksClientMixin", "ftbchunks.LargeMapScreenMixin", @@ -54,6 +75,7 @@ "PotionBrewingAccessor", "PrimedTntAccessor", "RecipeManagerMixin", + "ReloadableResourceManagerAccessor", "RepairItemRecipeMixin", "ServerChunkProviderMixin", "ServerGamePacketListenerImplAccessor", @@ -64,6 +86,7 @@ "TagManagerMixin", "TagValueAccessor", "client.ItemEntityMixin", + "client.bloom.normal.embeddium.SodiumWorldRendererMixin", "dev.datagen.FixParallelKeyMappingRegistrationMixin", "dev.test.GameTestRegistryMixin", "emi.EmiRecipeFillerMixin",