Skip to content

Commit

Permalink
Merge pull request #41 from Lordfirespeed/1.20-shader-refactor
Browse files Browse the repository at this point in the history
1.20 Shader Refactor
  • Loading branch information
Buuz135 authored Jul 15, 2023
2 parents f2f2f55 + 496f7de commit a0f77b8
Show file tree
Hide file tree
Showing 19 changed files with 271 additions and 351 deletions.
112 changes: 71 additions & 41 deletions src/main/java/com/buuz135/darkmodeeverywhere/ClientProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@


import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import io.netty.util.concurrent.*;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
import java.util.Map;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.Tooltip;
Expand All @@ -24,52 +25,84 @@
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.*;
import java.util.function.Consumer;

public class ClientProxy {
private final EventExecutor eventExecutor;
public static Object2BooleanMap<String> BLACKLISTED_ELEMENTS = new Object2BooleanOpenHashMap<>();
public static List<String> MODDED_BLACKLIST = new ArrayList<>();

public static ShaderConfig CONFIG = new ShaderConfig();
public static Map<ResourceLocation, ShaderInstance> REGISTERED_SHADERS = new HashMap<>();
public static List<ResourceLocation> REGISTERED_SHADER_LOCATIONS = new ArrayList<>();
public static Map<ResourceLocation, ShaderConfig.ShaderValue> SHADER_VALUES = new HashMap<>();
public static ResourceLocation SELECTED_SHADER = null;
public static Map<ShaderConfig.ShaderValue, ShaderInstance> TEX_SHADERS = new HashMap<>();
public static Map<ShaderConfig.ShaderValue, ShaderInstance> TEX_COLOR_SHADERS = new HashMap<>();
private static HashMap<ResourceLocation, Promise<ShaderInstance>> ON_SHADERS_LOADED = new HashMap<>();
public static List<ShaderConfig.ShaderValue> SHADER_VALUES = new ArrayList<>();
public static ShaderConfig.ShaderValue SELECTED_SHADER_VALUE = null;

public ClientProxy() {
eventExecutor = new DefaultEventExecutor();
ShaderConfig.load();
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::shaderRegister);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::registerAllShaders);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onConfigReload);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::imcCallback);
MinecraftForge.EVENT_BUS.addListener(this::openGui);
}

private void registerShaderForLoading(RegisterShadersEvent event, ResourceLocation shaderResourceLocation, VertexFormat format) {
try {
DarkModeEverywhere.LOGGER.debug("Registering shader {} for loading", shaderResourceLocation);
ON_SHADERS_LOADED.put(shaderResourceLocation, eventExecutor.newPromise());
event.registerShader(new DarkShaderInstance(event.getResourceProvider(), shaderResourceLocation, format), (ShaderInstance shaderInstance) -> {
DarkModeEverywhere.LOGGER.debug("Shader {} has loaded, resolving promise", shaderResourceLocation);
ON_SHADERS_LOADED.get(shaderResourceLocation).setSuccess(shaderInstance);
});
} catch (IOException e) {
DarkModeEverywhere.LOGGER.trace("Failed to register shader", e);
}
}

public void listenForShaderLoaded(RegisterShadersEvent event, ResourceLocation shaderResourceLocation, VertexFormat format, Consumer<ShaderInstance> onLoaded) {
if (!(ON_SHADERS_LOADED.containsKey(shaderResourceLocation))) {
registerShaderForLoading(event, shaderResourceLocation, format);
}

Promise<ShaderInstance> onLoadedPromise = ON_SHADERS_LOADED.get(shaderResourceLocation);
FutureListener<ShaderInstance> listener = (Future<ShaderInstance> shaderInstance) -> onLoaded.accept(shaderInstance.get());
onLoadedPromise.addListener(listener);
}

@SubscribeEvent
public void shaderRegister(RegisterShadersEvent event){
REGISTERED_SHADERS = new HashMap<>();
REGISTERED_SHADER_LOCATIONS = new ArrayList<>();
SHADER_VALUES = new HashMap<>();
public void registerAllShaders(RegisterShadersEvent event){
TEX_SHADERS = new HashMap<>();
TEX_COLOR_SHADERS = new HashMap<>();
ON_SHADERS_LOADED = new HashMap<>();
SHADER_VALUES = new ArrayList<>();
for (ShaderConfig.ShaderValue shaderValue : CONFIG.getShaders()) {
if (SHADER_VALUES.put(shaderValue.resourceLocation, shaderValue) == null) {
try {
event.registerShader(new ShaderInstance(event.getResourceProvider(), shaderValue.resourceLocation, DefaultVertexFormat.POSITION_TEX), shaderInstance -> {
DarkModeEverywhere.LOGGER.debug("Registered shader {}", shaderValue.resourceLocation);
REGISTERED_SHADERS.put(shaderValue.resourceLocation, shaderInstance);
REGISTERED_SHADER_LOCATIONS.add(shaderValue.resourceLocation);
});
} catch (IOException e) {
DarkModeEverywhere.LOGGER.trace("Failed to register shader", e);
}
}
}
if (CONFIG.getSelectedShader() != null){
SELECTED_SHADER = new ResourceLocation(CONFIG.getSelectedShader());
SHADER_VALUES.add(shaderValue);
if (shaderValue == null) continue;
listenForShaderLoaded(event, shaderValue.texShaderLocation, DefaultVertexFormat.POSITION_TEX, (shaderInstance -> {
TEX_SHADERS.put(shaderValue, shaderInstance);
}));
listenForShaderLoaded(event, shaderValue.texColorShaderLocation, DefaultVertexFormat.POSITION_TEX_COLOR, (shaderInstance -> {
TEX_COLOR_SHADERS.put(shaderValue, shaderInstance);
}));
}
SELECTED_SHADER_VALUE = SHADER_VALUES.get(CONFIG.getSelectedShaderIndex());
RenderedClassesTracker.start();
}

public static ShaderInstance getSelectedTexShader() {
return TEX_SHADERS.get(SELECTED_SHADER_VALUE);
}

public static ShaderInstance getSelectedTexColorShader() {
return TEX_COLOR_SHADERS.get(SELECTED_SHADER_VALUE);
}

public static ShaderConfig.ShaderValue getSelectedShaderValue() {
return SELECTED_SHADER_VALUE;
}

@SubscribeEvent
public void onConfigReload(ModConfigEvent.Reloading reloading){ BLACKLISTED_ELEMENTS.clear(); }

Expand All @@ -95,25 +128,21 @@ public void imcCallback(InterModProcessEvent event) {
});
}

private ResourceLocation getNextShaderResourceLocation() {
private int getNextShaderValueIndex() {
if (Screen.hasShiftDown()) {
return null;
}

if (SELECTED_SHADER == null){
return REGISTERED_SHADER_LOCATIONS.get(0);
return 0;
}

int nextShaderIndex = REGISTERED_SHADER_LOCATIONS.indexOf(SELECTED_SHADER) + 1;
if (nextShaderIndex >= REGISTERED_SHADERS.size()){
return null;
int nextShaderIndex = SHADER_VALUES.indexOf(SELECTED_SHADER_VALUE) + 1;
if (nextShaderIndex >= SHADER_VALUES.size()){
return 0;
}

return REGISTERED_SHADER_LOCATIONS.get(nextShaderIndex);
return nextShaderIndex;
}

private Tooltip getShaderSwitchButtonTooltip() {
MutableComponent tooltipComponent = SELECTED_SHADER == null ? Component.translatable("gui." + DarkModeEverywhere.MODID + ".light_mode") : Component.translatable(SHADER_VALUES.get(SELECTED_SHADER).displayName);
MutableComponent tooltipComponent = (SELECTED_SHADER_VALUE == null ? Component.translatable("gui." + DarkModeEverywhere.MODID + ".light_mode") : SELECTED_SHADER_VALUE.displayName).plainCopy();
tooltipComponent.append(Component.literal("\n"));
tooltipComponent.append(Component.translatable("gui.tooltip." + DarkModeEverywhere.MODID + ".shader_switch_tooltip").withStyle(ChatFormatting.GRAY));

Expand All @@ -133,8 +162,9 @@ public void openGui(ScreenEvent.Init event){
Button.Builder buttonBuilder = Button.builder(
Component.translatable("gui." + DarkModeEverywhere.MODID + ".dark_mode"),
button -> {
SELECTED_SHADER = getNextShaderResourceLocation();
CONFIG.setSelectedShader(SELECTED_SHADER);
int selectedShaderIndex = getNextShaderValueIndex();
CONFIG.setSelectedShaderIndex(selectedShaderIndex);
SELECTED_SHADER_VALUE = SHADER_VALUES.get(selectedShaderIndex);
button.setTooltip(getShaderSwitchButtonTooltip());
});

Expand Down
8 changes: 7 additions & 1 deletion src/main/java/com/buuz135/darkmodeeverywhere/DarkConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ public Client() {
"renderExperienceBar", "m_93071_",
"renderLogo", "m_280037_", "m_280118_",
"net.minecraft.client.gui.Gui", "net.minecraft.src.C_3431_",
"renderDirtBackground", "m_280039_", "m_280039_"
"renderDirtBackground", "m_280039_", "m_280039_",
"configured.client.screen.ListMenuScreen", // Configured background
"OnlineServerEntry:drawIcon", "OnlineServerEntry:m_99889_", // Multiplayer Server icons
"WorldSelectionList$WorldListEntry:render", "WorldSelectionList$WorldListEntry:m_6311_", // Single player world icons
"CubeMap:render", "CubeMap:m_108849_", //1.20+ title screen panorama
"squeek.appleskin.client.HUDOverlayHandler", //AppleSkin overlay
"shadows.packmenu.ExtendedMenuScreen" //Custom PackMenu backgrounds
));

String TRANSLATION_KEY_BASE = "config." + DarkModeEverywhere.MODID + ".";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.buuz135.darkmodeeverywhere;

import com.mojang.blaze3d.shaders.Uniform;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceProvider;

import java.io.IOException;

public class DarkShaderInstance extends ShaderInstance {

public final Uniform DivideFactor;
public final Uniform PerceptionScale;

public DarkShaderInstance(ResourceProvider p_173336_, ResourceLocation shaderLocation, VertexFormat p_173338_) throws IOException {
super(p_173336_, shaderLocation, p_173338_);
this.DivideFactor = this.getUniform("DivideFactor");
this.PerceptionScale = this.getUniform("PerceptionScale");
}
}
52 changes: 31 additions & 21 deletions src/main/java/com/buuz135/darkmodeeverywhere/ShaderConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,40 @@ public class ShaderConfig {

private List<ShaderValue> shaders;
private int version;
private String selectedShader;
private int selectedShaderIndex;
private static final File configFilePath = new File("config" + File.separator + "darkmodeeverywhereshaders.json");

public ShaderConfig() {
this.shaders = new ArrayList<>();
this.version = 1;
this.shaders.add(new ShaderValue(new ResourceLocation("darkmodeeverywhere", "perfect_dark"), "gui.darkmodeeverywhere.perfect_dark", 16777215));
this.shaders.add(new ShaderValue(new ResourceLocation("darkmodeeverywhere", "less_perfect_dark"), "gui.darkmodeeverywhere.less_perfect_dark", 16777215));
this.shaders.add(new ShaderValue(new ResourceLocation("darkmodeeverywhere", "toasted_light"), "gui.darkmodeeverywhere.toasted_light", 16777215));
this.selectedShader = null;
this.version = 2;
ResourceLocation tex_shader_location = new ResourceLocation("darkmodeeverywhere", "dark_position_tex");
ResourceLocation tex_color_shader_location = new ResourceLocation("darkmodeeverywhere", "dark_position_tex_color");
this.shaders.add(null);
this.shaders.add(new ShaderValue(tex_shader_location, tex_color_shader_location, Component.translatable("gui.darkmodeeverywhere.perfect_dark"), (float)5.5, 16777215));
this.shaders.add(new ShaderValue(tex_shader_location, tex_color_shader_location, Component.translatable("gui.darkmodeeverywhere.less_perfect_dark"), (float)3.5, 16777215));
this.shaders.add(new ShaderValue(tex_shader_location, tex_color_shader_location, Component.translatable("gui.darkmodeeverywhere.toasted_light"), (float)2, 16777215));
this.selectedShaderIndex = 0;
}

public List<ShaderValue> getShaders() {
return shaders;
}

public void setSelectedShader(ResourceLocation resourceLocation){
if (resourceLocation == null){
selectedShader = null;
} else {
selectedShader = resourceLocation.toString();
}
DarkModeEverywhere.LOGGER.debug("Selected shader updated to {}", selectedShader);
public void setSelectedShaderIndex(int index) {
selectedShaderIndex = index;
DarkModeEverywhere.LOGGER.debug("Selected shader index updated to {}", selectedShaderIndex);
new Thread(ShaderConfig::createDefaultConfigFile).start();
}

public String getSelectedShader() {
return selectedShader;
public int getSelectedShaderIndex() {
return selectedShaderIndex;
}

private static Gson createGson() {
return new GsonBuilder().setPrettyPrinting().create();
return new GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(MutableComponent.class, new Component.Serializer())
.create();
}

public static void load(){
Expand All @@ -59,8 +61,12 @@ public static void load(){
Gson gson = createGson();
try (FileReader reader = new FileReader(configFilePath)) {
ClientProxy.CONFIG = gson.fromJson(reader, ShaderConfig.class);
if (ClientProxy.CONFIG.version != new ShaderConfig().version) {
throw new Exception("Invalid config version.");
}
} catch (Exception e) {
e.printStackTrace();
ClientProxy.CONFIG = new ShaderConfig();
createDefaultConfigFile();
}
}
Expand All @@ -75,13 +81,17 @@ private static void createDefaultConfigFile(){
}

public static class ShaderValue {
public ResourceLocation resourceLocation;
public String displayName;
public ResourceLocation texShaderLocation;
public ResourceLocation texColorShaderLocation;
public MutableComponent displayName;
public float divideFactor;
public int darkColorReplacement;

public ShaderValue(ResourceLocation resourceLocation, String displayName, int darkColorReplacement) {
this.resourceLocation = resourceLocation;
public ShaderValue(ResourceLocation texShaderLocation, ResourceLocation texColorShaderLocation, MutableComponent displayName, float divideFactor, int darkColorReplacement) {
this.texShaderLocation = texShaderLocation;
this.texColorShaderLocation = texColorShaderLocation;
this.displayName = displayName;
this.divideFactor = divideFactor;
this.darkColorReplacement = darkColorReplacement;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ public int drawInternalA(int color) {

private int modifyColor(int color){
if (color == 0) return color;
if (ClientProxy.SELECTED_SHADER != null && Minecraft.getInstance().screen != null) {
int thre = 65;
ShaderConfig.ShaderValue shaderValue = ClientProxy.SHADER_VALUES.get(ClientProxy.SELECTED_SHADER);
if (ClientProxy.SELECTED_SHADER_VALUE != null && Minecraft.getInstance().screen != null) {
int threshold = 65;
ShaderConfig.ShaderValue shaderValue = ClientProxy.SELECTED_SHADER_VALUE;
if (shaderValue.darkColorReplacement == -1) return color;
if (FastColor.ARGB32.red(color) < thre && FastColor.ARGB32.green(color) < thre && FastColor.ARGB32.blue(color) < thre){
if (FastColor.ARGB32.red(color) < threshold && FastColor.ARGB32.green(color) < threshold && FastColor.ARGB32.blue(color) < threshold){
return shaderValue.darkColorReplacement;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,50 @@

import com.buuz135.darkmodeeverywhere.ClassUtil;
import com.buuz135.darkmodeeverywhere.ClientProxy;
import com.mojang.blaze3d.systems.RenderSystem;
import cpw.mods.modlauncher.api.INameMappingService;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.function.Supplier;

@Mixin(GameRenderer.class)
public class GameRenderMixin {
public abstract class GameRenderMixin {

@Unique
private static void darkModeEverywhere$replaceDefaultShader(CallbackInfoReturnable<ShaderInstance> cir, Supplier<ShaderInstance> replacer) {
ShaderInstance replacement = replacer.get();
if (replacement == null) return;
cir.setReturnValue(replacer.get());
}

@Unique
private static void darkModeEverywhere$replaceDefaultShaderWhenAppropriate(CallbackInfoReturnable<ShaderInstance> cir, Supplier<ShaderInstance> replacer) {
if (ClientProxy.SELECTED_SHADER_VALUE == null) return;

var callerClassName = ClassUtil.getCallerClassName();
if (callerClassName == null) {
darkModeEverywhere$replaceDefaultShader(cir, replacer);
return;
}

boolean elementNameIsBlacklisted = ClientProxy.isElementNameBlacklisted(callerClassName);

private static void replaceDefaultShaderWithSelectedShader(CallbackInfoReturnable<ShaderInstance> cir) {
cir.setReturnValue(ClientProxy.REGISTERED_SHADERS.get(ClientProxy.SELECTED_SHADER));
if (!elementNameIsBlacklisted) {
darkModeEverywhere$replaceDefaultShader(cir, replacer);
}
}

@Inject(method = "getPositionTexShader", at = @At("HEAD"), cancellable = true)
private static void getPositionTexShader(CallbackInfoReturnable<ShaderInstance> cir) {
if (ClientProxy.SELECTED_SHADER != null){
var callerClassName = ClassUtil.getCallerClassName();
if (callerClassName == null) {
replaceDefaultShaderWithSelectedShader(cir);
return;
}

boolean elementNameIsBlacklisted = ClientProxy.isElementNameBlacklisted(callerClassName);

if (!elementNameIsBlacklisted) {
replaceDefaultShaderWithSelectedShader(cir);
}
}
darkModeEverywhere$replaceDefaultShaderWhenAppropriate(cir, ClientProxy::getSelectedTexShader);
}


@Inject(method = "getPositionTexColorShader", at = @At("HEAD"), cancellable = true)
private static void getPositionTexColorShader(CallbackInfoReturnable<ShaderInstance> cir) {
darkModeEverywhere$replaceDefaultShaderWhenAppropriate(cir, ClientProxy::getSelectedTexColorShader);
}
}
Loading

0 comments on commit a0f77b8

Please sign in to comment.