diff --git a/src/main/java/net/vulkanmod/Initializer.java b/src/main/java/net/vulkanmod/Initializer.java index 55638963a0..3d655e65d6 100644 --- a/src/main/java/net/vulkanmod/Initializer.java +++ b/src/main/java/net/vulkanmod/Initializer.java @@ -6,7 +6,6 @@ import net.vulkanmod.config.Config; import net.vulkanmod.config.Platform; import net.vulkanmod.config.UpdateChecker; -import net.vulkanmod.config.video.VideoModeManager; import net.vulkanmod.render.chunk.build.frapi.VulkanModRenderer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -44,14 +43,7 @@ public void onInitializeClient() { } private static Config loadConfig(Path path) { - Config config = Config.load(path); - - if(config == null) { - config = new Config(); - config.write(); - } - - return config; + return Config.load(path); } public static String getVersion() { diff --git a/src/main/java/net/vulkanmod/config/Platform.java b/src/main/java/net/vulkanmod/config/Platform.java index 9e55146420..6c7af3be04 100644 --- a/src/main/java/net/vulkanmod/config/Platform.java +++ b/src/main/java/net/vulkanmod/config/Platform.java @@ -13,7 +13,7 @@ public abstract class Platform { public static void init() { GLFW.glfwInitHint(GLFW_PLATFORM, activePlat); - LOGGER.info("Selecting Platform: {}", getStringFromPlat(activePlat)); + LOGGER.info("Selecting Platform: {}", getStringFromPlat()); LOGGER.info("GLFW: {}", GLFW.glfwGetVersionString()); GLFW.glfwInit(); } @@ -40,14 +40,14 @@ private static int getSupportedPlat() { return GLFW_ANY_PLATFORM; //Unknown platform } - private static String getStringFromPlat(int plat) { - return switch (plat) { + private static String getStringFromPlat() { + return switch (Platform.activePlat) { case GLFW_PLATFORM_WIN32 -> "WIN32"; case GLFW_PLATFORM_WAYLAND -> "WAYLAND"; case GLFW_PLATFORM_X11 -> "X11"; case GLFW_PLATFORM_COCOA -> "MACOS"; case GLFW_ANY_PLATFORM -> "ANDROID"; - default -> throw new IllegalStateException("Unexpected value: " + plat); + default -> throw new IllegalStateException("Unexpected value: " + Platform.activePlat); }; } diff --git a/src/main/java/net/vulkanmod/config/gui/GuiElement.java b/src/main/java/net/vulkanmod/config/gui/GuiElement.java index 04b85d2a1b..a50316cab9 100644 --- a/src/main/java/net/vulkanmod/config/gui/GuiElement.java +++ b/src/main/java/net/vulkanmod/config/gui/GuiElement.java @@ -7,7 +7,7 @@ import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.navigation.ScreenRectangle; -import net.minecraft.client.input.MouseButtonEvent; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class GuiElement implements GuiEventListener, NarratableEntry { @@ -22,6 +22,7 @@ public abstract class GuiElement implements GuiEventListener, NarratableEntry { protected int hoverTime; protected long hoverStopTime; + @SuppressWarnings("unused") // this will surely be used some day public void setPosition(int x, int y) { this.x = x; this.y = y; @@ -34,6 +35,7 @@ public void setPosition(int x, int y, int width, int height) { this.height = height; } + @SuppressWarnings("unused") // this will surely be used someday public void resize(int width, int height) { this.width = width; this.height = height; @@ -102,7 +104,7 @@ public ComponentPath getCurrentFocusPath() { } @Override - public ScreenRectangle getRectangle() { + public @NotNull ScreenRectangle getRectangle() { return GuiEventListener.super.getRectangle(); } @@ -117,7 +119,7 @@ public boolean isFocused() { } @Override - public NarrationPriority narrationPriority() { + public @NotNull NarrationPriority narrationPriority() { return NarrationPriority.NONE; } diff --git a/src/main/java/net/vulkanmod/config/gui/ModSettingsEntry.java b/src/main/java/net/vulkanmod/config/gui/ModSettingsEntry.java new file mode 100644 index 0000000000..bfe3e31e60 --- /dev/null +++ b/src/main/java/net/vulkanmod/config/gui/ModSettingsEntry.java @@ -0,0 +1,46 @@ +package net.vulkanmod.config.gui; + +import net.minecraft.network.chat.FormattedText; +import net.minecraft.resources.ResourceLocation; +import net.vulkanmod.config.option.OptionPage; + +import java.util.List; +import java.util.function.Supplier; + +public class ModSettingsEntry { + public final FormattedText modName; + public final Supplier iconSupplier; + private final Supplier> optionPageSupplier; + private final Runnable onApply; + + private ResourceLocation icon; + List pages; + + public ModSettingsEntry(FormattedText modName, Supplier iconSupplier, Supplier> optionPageSupplier, Runnable onApply) { + this.modName = modName; + this.iconSupplier = iconSupplier; + this.optionPageSupplier = optionPageSupplier; + this.onApply = onApply; + } + + public List initPages() { + this.pages = this.optionPageSupplier.get(); + return this.pages; + } + + public List getPages() { + return pages; + } + + public ResourceLocation getIcon() { + if (this.icon == null) { + this.icon = this.iconSupplier.get(); + } + + return icon; + } + + public void runOnApply() { + onApply.run(); + } +} diff --git a/src/main/java/net/vulkanmod/config/gui/ModSettingsRegistry.java b/src/main/java/net/vulkanmod/config/gui/ModSettingsRegistry.java new file mode 100644 index 0000000000..dd49e32920 --- /dev/null +++ b/src/main/java/net/vulkanmod/config/gui/ModSettingsRegistry.java @@ -0,0 +1,34 @@ +package net.vulkanmod.config.gui; + +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.vulkanmod.Initializer; +import net.vulkanmod.config.option.Options; + +import java.util.Set; + +public class ModSettingsRegistry { + + public static final ModSettingsRegistry INSTANCE = new ModSettingsRegistry(); + + private final Set modEntries = new ObjectArraySet<>(); + + ModSettingsRegistry() { + ModSettingsEntry vulkanModSettings = new ModSettingsEntry(Component.literal("VulkanMod").withStyle(ChatFormatting.DARK_RED), + () -> ResourceLocation.fromNamespaceAndPath("vulkanmod", "vlogo_transparent.png"), + Options::getOptionPages, + () -> Initializer.CONFIG.write()); + this.addModEntry(vulkanModSettings); + } + + public void addModEntry(ModSettingsEntry entry) { + this.modEntries.add(entry); + } + + public Set getModEntries() { + return modEntries; + } +} diff --git a/src/main/java/net/vulkanmod/config/gui/VOptionList.java b/src/main/java/net/vulkanmod/config/gui/VOptionList.java index c96ddce629..9b441c9e7d 100644 --- a/src/main/java/net/vulkanmod/config/gui/VOptionList.java +++ b/src/main/java/net/vulkanmod/config/gui/VOptionList.java @@ -2,8 +2,10 @@ import com.mojang.blaze3d.opengl.GlStateManager; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.vulkanmod.config.gui.render.GuiRenderer; import net.vulkanmod.config.gui.widget.OptionWidget; @@ -31,14 +33,15 @@ public VOptionList(int x, int y, int width, int height, int itemHeight) { this.width = width; this.height = height; - this.itemWidth = (int) (0.95f * this.width); + this.itemWidth = this.width - 7; this.itemHeight = itemHeight; this.itemMargin = 3; this.totalItemHeight = this.itemHeight + this.itemMargin; } + @SuppressWarnings("unused") public void addButton(OptionWidget widget) { - this.addEntry(new Entry(widget, this.itemMargin)); + this.addEntry(new Entry(widget, this.itemMargin, null)); } public void addAll(OptionBlock[] blocks) { @@ -47,26 +50,30 @@ public void addAll(OptionBlock[] blocks) { int width = this.itemWidth; int height = this.itemHeight; + // add a header (this is MOSTLY for the search) + String title = block.title(); + if (title != null && !title.isEmpty()) { + this.addEntry(new Entry(null, 8, title)); + } + var options = block.options(); for (Option option : options) { - int margin = this.itemMargin; - - final OptionWidget optionWidget = option.getWidget(); - optionWidget.setDimensions(x0, 0, width, height); - this.addEntry(new Entry(optionWidget, margin)); + OptionWidget widget = option.getWidget(); + widget.setDimensions(x0, 0, width, height); + this.addEntry(new Entry(widget, margin, null)); } - this.addEntry(new Entry(null, 12)); + this.addEntry(new Entry(null, 12, null)); } } private void addEntry(Entry entry) { this.children.add(entry); - this.listLength += entry.getTotalHeight(); } + @SuppressWarnings("unused") public void clearEntries() { this.listLength = 0; this.children.clear(); @@ -229,7 +236,7 @@ public void renderWidget(int mouseX, int mouseY) { } protected int getScrollbarPosition() { - return this.x + this.itemWidth + 5; + return this.x + this.width; } public VAbstractWidget getHoveredWidget(double mouseX, double mouseY) { @@ -254,13 +261,11 @@ protected void renderList(int mouseX, int mouseY) { int rowTop = this.y - (int) this.getScrollAmount(); for (int j = 0; j < itemCount; ++j) { - int rowBottom = rowTop + this.itemHeight; - VOptionList.Entry entry = this.getEntry(j); - if (rowBottom >= this.y && rowTop <= (this.y + this.height)) { - boolean updateState = this.focused == null; - entry.render(rowTop, mouseX, mouseY, updateState); + if (rowTop + entry.getTotalHeight() >= this.y && rowTop <= (this.y + this.height)) { + boolean updateState = this.focused == null; + entry.render(rowTop, mouseX, mouseY, updateState, this.x); } rowTop += entry.getTotalHeight(); @@ -278,13 +283,28 @@ protected boolean isValidClickButton(int i) { protected static class Entry implements GuiEventListener { final VAbstractWidget widget; final int margin; + final String headerTitle; - private Entry(OptionWidget widget, int margin) { + private Entry(OptionWidget widget, int margin, String headerTitle) { this.widget = widget; this.margin = margin; + this.headerTitle = headerTitle; } - public void render(int y, int mouseX, int mouseY, boolean updateState) { + public void render(int y, int mouseX, int mouseY, boolean updateState, int listX) { + // if there is a title, RENDER IT!!! + if (headerTitle != null && !headerTitle.isEmpty()) { + int headerY = y + 4; + GuiRenderer.drawString( + Minecraft.getInstance().font, + Component.literal(headerTitle), + listX + 8, + headerY, + 0xFFFFFFFF + ); + return; + } + if (widget == null) return; @@ -297,6 +317,9 @@ public void render(int y, int mouseX, int mouseY, boolean updateState) { } public int getTotalHeight() { + if (headerTitle != null && !headerTitle.isEmpty()) { + return Minecraft.getInstance().font.lineHeight + margin; + } if (widget != null) return widget.height + margin; else @@ -305,16 +328,19 @@ public int getTotalHeight() { @Override public boolean mouseClicked(MouseButtonEvent event, boolean bl) { + if (widget == null) return false; return widget.mouseClicked(event, bl); } @Override public boolean mouseReleased(MouseButtonEvent event) { + if (widget == null) return false; return widget.mouseReleased(event); } @Override public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) { + if (widget == null) return false; return widget.mouseDragged(event, deltaX, deltaY); } @@ -325,7 +351,8 @@ public boolean isFocused() { @Override public void setFocused(boolean bl) { - widget.setFocused(bl); + if (widget != null) + widget.setFocused(bl); } } -} +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/gui/VOptionScreen.java b/src/main/java/net/vulkanmod/config/gui/VOptionScreen.java index 718b9fa8c4..b2dc168b1d 100644 --- a/src/main/java/net/vulkanmod/config/gui/VOptionScreen.java +++ b/src/main/java/net/vulkanmod/config/gui/VOptionScreen.java @@ -3,117 +3,136 @@ import com.google.common.collect.Lists; import net.minecraft.ChatFormatting; import net.minecraft.Util; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.options.VideoSettingsScreen; +import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; -import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.FormattedCharSequence; import net.vulkanmod.Initializer; import net.vulkanmod.config.UpdateChecker; import net.vulkanmod.config.gui.render.GuiRenderer; -import net.vulkanmod.config.gui.widget.VAbstractWidget; -import net.vulkanmod.config.gui.widget.VButtonWidget; -import net.vulkanmod.config.option.OptionPage; -import net.vulkanmod.config.option.Options; +import net.vulkanmod.config.gui.util.SearchHelper; +import net.vulkanmod.config.gui.util.VGuiConstants; +import net.vulkanmod.config.gui.widget.*; +import net.vulkanmod.config.option.*; import net.vulkanmod.vulkan.VRenderSystem; import net.vulkanmod.vulkan.util.ColorUtil; +import org.lwjgl.glfw.GLFW; import java.util.ArrayList; import java.util.List; public class VOptionScreen extends Screen { - public final static int MARGIN = 20; - public final static int RED = ColorUtil.ARGB.pack(0.3f, 0.0f, 0.0f, 0.8f); - final ResourceLocation ICON = ResourceLocation.fromNamespaceAndPath("vulkanmod", "vlogo_transparent.png"); + public final static int MARGIN = 10; private final Screen parent; + private final List modSettingsEntries; + private final List optionPages; + private OptionPage searchResultsPage; private int currentListIdx = 0; + private boolean isSearchActive = false; private int tooltipX; private int tooltipY; private int tooltipWidth; - private VButtonWidget supportButton; - - private VButtonWidget doneButton; private VButtonWidget applyButton; + private VButtonWidget undoButton; + private VTextInputWidget searchField; + + private final List iconWidgets = Lists.newArrayList(); private final List pageButtons = Lists.newArrayList(); private final List buttons = Lists.newArrayList(); + public VOptionScreen(Component title, Screen parent) { super(title); this.parent = parent; this.optionPages = new ArrayList<>(); - } - - private void addPages() { - this.optionPages.clear(); - - OptionPage page = new OptionPage( - Component.translatable("vulkanmod.options.pages.video").getString(), - Options.getVideoOpts() - ); - this.optionPages.add(page); - - page = new OptionPage( - Component.translatable("vulkanmod.options.pages.graphics").getString(), - Options.getGraphicsOpts() - ); - this.optionPages.add(page); - - page = new OptionPage( - Component.translatable("vulkanmod.options.pages.optimizations").getString(), - Options.getOptimizationOpts() - ); - this.optionPages.add(page); - - page = new OptionPage( - Component.translatable("vulkanmod.options.pages.other").getString(), - Options.getOtherOpts() - ); - this.optionPages.add(page); + this.modSettingsEntries = new ArrayList<>(ModSettingsRegistry.INSTANCE.getModEntries()); } @Override protected void init() { - this.addPages(); + this.initOptionsPages(); + + if (this.optionPages.isEmpty()) { + throw new IllegalStateException("Default Options weren't added!"); + } - int top = 40; + int top = 32; int bottom = 60; int itemHeight = 20; - int leftMargin = MARGIN + 90; + int leftMargin = MARGIN + VGuiConstants.PAGE_BUTTON_WIDTH + 6; int listWidth = Math.min(this.width - leftMargin - MARGIN, 420); int listHeight = this.height - top - bottom; this.buildLists(leftMargin, top, listWidth, listHeight, itemHeight); - int x = leftMargin + listWidth + 10; - int width = this.width - x - 10; - int y = 50; + this.searchField = createSearchField(); + + int x = leftMargin + listWidth + 6; + int tooltipWidth = Math.min(this.width - x - 10, 420); + int y = top + itemHeight + 6; - if (width < 200) { - x = 100; - width = listWidth; + if (tooltipWidth < 200) { + x = leftMargin + 3; + tooltipWidth = listWidth; y = this.height - bottom + 10; } this.tooltipX = x; this.tooltipY = y; - this.tooltipWidth = width; + this.tooltipWidth = tooltipWidth; - buildPage(); + this.buildPage(); this.applyButton.active = false; + this.undoButton.visible = false; + } + + private void initOptionsPages() { + this.optionPages.clear(); + + for (var modPageSet : this.modSettingsEntries) { + modPageSet.initPages(); + + this.optionPages.addAll(modPageSet.getPages()); + } + } + + private VTextInputWidget createSearchField() { + int rightMargin = 10; + int padding = 10; + int kofiWidth = Minecraft.getInstance().font.width(Component.translatable("vulkanmod.options.buttons.kofi")) + padding; + int topBarRight = this.width - kofiWidth - rightMargin; + + if (UpdateChecker.isUpdateAvailable()) { + int updateWidth = minecraft.font.width(Component.translatable("vulkanmod.options.buttons.update_available")) + padding; + topBarRight -= updateWidth + VGuiConstants.WIDGET_MARGIN; + } + + + int leftMargin = VGuiConstants.PAGE_BUTTON_WIDTH + MARGIN + 6; + int width = Math.min(topBarRight - leftMargin - 4, 413); + + return new VTextInputWidget( + leftMargin, 4, + width, VGuiConstants.WIDGET_HEIGHT, + Component.translatable("vulkanmod.options.searchFieldPlaceholder"), + widget -> performSearch(widget.getInput()) + ); } private void buildLists(int left, int top, int listWidth, int listHeight, int itemHeight) { @@ -123,90 +142,176 @@ private void buildLists(int left, int top, int listWidth, int listHeight, int it } } - private void addPageButtons(int x0, int y0, int width, int height, boolean verticalLayout) { - int x = x0; - int y = y0; - for (int i = 0; i < this.optionPages.size(); ++i) { - var page = this.optionPages.get(i); - final int finalIdx = i; - VButtonWidget widget = new VButtonWidget(x, y, width, height, Component.nullToEmpty(page.name), button -> this.setOptionList(finalIdx)); - this.buttons.add(widget); - this.pageButtons.add(widget); - this.addWidget(widget); - - if (verticalLayout) - y += height + 1; - else - x += width + 1; + private void performSearch(String query) { + if (query == null || query.trim().isEmpty()) { + isSearchActive = false; + this.currentListIdx = 0; + buildPage(); + return; + } + + String searchTerm = query.toLowerCase().trim(); + List searchResults = new ArrayList<>(); + + for (OptionPage page : this.optionPages) { + List> matchingOptions = new ArrayList<>(); + + for (OptionBlock block : page.optionBlocks) { + for (Option option : block.options()) { + boolean matches = false; + + String optionName = option.getName().getString().toLowerCase(); + String optionTooltip = option.getTooltip() != null ? + option.getTooltip().getString().toLowerCase() : ""; + String displayedValue = option.getDisplayedValue().getString().toLowerCase(); + + if (optionName.contains(searchTerm) || + optionTooltip.contains(searchTerm) || + displayedValue.contains(searchTerm)) { + matches = true; + } + + else if (option instanceof CyclingOption cycling) { + if (SearchHelper.matchesAnyValue(cycling, searchTerm)) { + matches = true; + } + } + + if (matches) { + matchingOptions.add(option); + } + } + } + + if (!matchingOptions.isEmpty()) { + searchResults.add(new OptionBlock("§l" + page.name, + matchingOptions.toArray(new Option[0]))); + searchResults.add(new OptionBlock("", new Option[0])); + } } - this.pageButtons.get(this.currentListIdx).setSelected(true); + searchResultsPage = new OptionPage( + "Search Results", + searchResults.toArray(new OptionBlock[0]) + ); + + int top = 32; + int bottom = 60; + int itemHeight = 20; + int leftMargin = MARGIN + VGuiConstants.PAGE_BUTTON_WIDTH; + int listWidth = Math.min(this.width - leftMargin - MARGIN, 420); + int listHeight = this.height - top - bottom; + + searchResultsPage.createList(leftMargin, top, listWidth, listHeight, itemHeight); + + isSearchActive = true; + buildPage(); } private void buildPage() { this.buttons.clear(); this.pageButtons.clear(); + this.iconWidgets.clear(); + + String savedInput = this.searchField != null ? this.searchField.getInput() : ""; + boolean savedFocused = this.searchField != null && this.searchField.focused; + boolean savedSelected = this.searchField != null && this.searchField.selected; + this.clearWidgets(); - this.addPageButtons(MARGIN, 40, 80, 22, true); + int x = MARGIN; + int y = 4; + + int width = VGuiConstants.PAGE_BUTTON_WIDTH; + int j = 0; + for (var modEntry : this.modSettingsEntries) { + ModIconWidget iconWidget = new ModIconWidget(modEntry.modName, modEntry.getIcon(), x, y, width, 28); + this.iconWidgets.add(iconWidget); + this.addWidget(iconWidget); + y += 28; + + var pages = modEntry.getPages(); + for (OptionPage page : pages) { + final int finalIdx = j; + VButtonWidget widget = new VButtonWidget(x, y, width, VGuiConstants.WIDGET_HEIGHT, Component.nullToEmpty(page.name), button -> this.setOptionList(finalIdx)); + this.buttons.add(widget); + this.pageButtons.add(widget); + this.addWidget(widget); + + y += VGuiConstants.WIDGET_HEIGHT; + j++; + } + } + + if (!isSearchActive) { + this.pageButtons.get(this.currentListIdx).setSelected(true); + VOptionList currentList = this.optionPages.get(this.currentListIdx).getOptionList(); + this.addWidget(currentList); + } else { + if (searchResultsPage != null) { + VOptionList searchList = searchResultsPage.getOptionList(); + this.addWidget(searchList); + searchResultsPage.updateOptionStates(); + } + } - VOptionList currentList = this.optionPages.get(this.currentListIdx).getOptionList(); - this.addWidget(currentList); + this.addButtonsWithSearchBar(); - this.addButtons(); + this.searchField.setInput(savedInput); + if (savedFocused) { + this.searchField.setFocused(true); + this.searchField.setSelected(savedSelected); + } } - private void addButtons() { - int rightMargin = 20; - int buttonHeight = 20; + @SuppressWarnings("DuplicatedCode") + private void addButtonsWithSearchBar() { + int rightMargin = 10; int padding = 10; - int buttonMargin = 5; - int buttonWidth = minecraft.font.width(CommonComponents.GUI_DONE) + 2 * padding; + int buttonWidth = Minecraft.getInstance().font.width(CommonComponents.GUI_DONE) + 2 * padding; int x0 = (this.width - buttonWidth - rightMargin); - int y0 = this.height - buttonHeight - 7; + int y0 = this.height - VGuiConstants.WIDGET_HEIGHT - 7; - this.doneButton = new VButtonWidget( - x0, y0, - buttonWidth, buttonHeight, - CommonComponents.GUI_DONE, - button -> this.minecraft.setScreen(this.parent) - ); + VButtonWidget doneButton = new VButtonWidget(x0, y0, buttonWidth, VGuiConstants.WIDGET_HEIGHT, + CommonComponents.GUI_DONE, button -> Minecraft.getInstance().setScreen(this.parent)); - buttonWidth = minecraft.font.width(Component.translatable("vulkanmod.options.buttons.apply")) + 2 * padding; - x0 -= (buttonWidth + buttonMargin); - this.applyButton = new VButtonWidget( - x0, y0, - buttonWidth, buttonHeight, - Component.translatable("vulkanmod.options.buttons.apply"), - button -> this.applyOptions() - ); + buttonWidth = Minecraft.getInstance().font.width(Component.translatable("vulkanmod.options.buttons.apply")) + 2 * padding; + x0 -= (buttonWidth + VGuiConstants.WIDGET_MARGIN); + this.applyButton = new VButtonWidget(x0, y0, buttonWidth, VGuiConstants.WIDGET_HEIGHT, + Component.translatable("vulkanmod.options.buttons.apply"), button -> this.applyOptions()); - buttonWidth = minecraft.font.width(Component.translatable("vulkanmod.options.buttons.kofi")) + 10; - x0 = (this.width - buttonWidth - rightMargin); - this.supportButton = new VButtonWidget( - x0, 6, - buttonWidth, buttonHeight, + buttonWidth = Minecraft.getInstance().font.width(Component.translatable("vulkanmod.options.buttons.undo")) + 2 * padding; + x0 -= (buttonWidth + VGuiConstants.WIDGET_MARGIN); + this.undoButton = new VButtonWidget(x0, y0, buttonWidth, VGuiConstants.WIDGET_HEIGHT, + Component.translatable("vulkanmod.options.buttons.undo"), button -> undo()); + + int kofiWidth = Minecraft.getInstance().font.width(Component.translatable("vulkanmod.options.buttons.kofi")) + padding; + + int kofiX = this.width - kofiWidth - rightMargin; + VButtonWidget supportButton = new VButtonWidget(kofiX, 4, kofiWidth, VGuiConstants.WIDGET_HEIGHT, Component.translatable("vulkanmod.options.buttons.kofi"), - button -> Util.getPlatform().openUri("https://ko-fi.com/xcollateral") - ); + button -> Util.getPlatform().openUri("https://ko-fi.com/xcollateral")); this.buttons.add(this.applyButton); - this.buttons.add(this.doneButton); - this.buttons.add(this.supportButton); + this.buttons.add(doneButton); + this.buttons.add(supportButton); + this.buttons.add(this.undoButton); this.addWidget(this.applyButton); - this.addWidget(this.doneButton); - this.addWidget(this.supportButton); + this.addWidget(doneButton); + this.addWidget(supportButton); + this.addWidget(this.undoButton); + this.addWidget(this.searchField); if (UpdateChecker.isUpdateAvailable()) { - buttonWidth = minecraft.font.width(Component.translatable("vulkanmod.options.buttons.update_available")) + 10; + assert minecraft != null; + int updateWidth = minecraft.font.width(Component.translatable("vulkanmod.options.buttons.update_available")) + padding; var updateButton = new VButtonWidget( - x0 - buttonWidth - buttonMargin, 6, - buttonWidth, buttonHeight, + kofiX - updateWidth - VGuiConstants.WIDGET_MARGIN, 4, + updateWidth, VGuiConstants.WIDGET_HEIGHT, Component.translatable("vulkanmod.options.buttons.update_available").withStyle(ChatFormatting.UNDERLINE), button -> Util.getPlatform().openUri("https://modrinth.com/mod/vulkanmod") ); - this.buttons.add(updateButton); this.addWidget(updateButton); } @@ -240,7 +345,7 @@ public boolean mouseReleased(MouseButtonEvent event) { @Override public void onClose() { - this.minecraft.setScreen(this.parent); + Minecraft.getInstance().setScreen(this.parent); } @Override @@ -248,35 +353,62 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float delta) GuiRenderer.guiGraphics = guiGraphics; VRenderSystem.enableBlend(); - int size = 36; - guiGraphics.blit(RenderPipelines.GUI_TEXTURED, ICON, MARGIN + 40 - 18, 4, 0f, 0f, size, size, size, size); + VOptionList currentList; + if (isSearchActive && searchResultsPage != null) { + currentList = searchResultsPage.getOptionList(); + } else { + currentList = this.optionPages.get(this.currentListIdx).getOptionList(); + } - VOptionList currentList = this.optionPages.get(this.currentListIdx).getOptionList(); currentList.updateState(mouseX, mouseY); currentList.renderWidget(mouseX, mouseY); - renderButtons(mouseX, mouseY); - List list = getHoveredButtonTooltip(currentList, mouseX, mouseY); - if (list != null) { - this.renderTooltip(list, this.tooltipX, this.tooltipY); + for (var widget : iconWidgets) { + widget.render(mouseX, mouseY); } - } - public void renderButtons(int mouseX, int mouseY) { for (VButtonWidget button : buttons) { + button.updateState(mouseX, mouseY); button.render(mouseX, mouseY); } + searchField.updateState(mouseX, mouseY); + searchField.render(mouseX, mouseY); + + VAbstractWidget hoveredWidget = null; + + for (var b : buttons) { + if (b.isMouseOver(mouseX, mouseY)) { + hoveredWidget = b; + break; + } + } + + if (hoveredWidget == null) { + hoveredWidget = currentList.getHoveredWidget(mouseX, mouseY); + } + + if (hoveredWidget != null) { + this.renderTooltip(hoveredWidget, this.tooltipX, this.tooltipY); + } } - private void renderTooltip(List list, int x, int y) { + private void renderTooltip(VAbstractWidget widget, int x, int y) { + var list = this.getWidgetTooltip(widget); + + if (list.isEmpty()) { + return; + } + + int lines = list.size(); + int padding = 3; int width = GuiRenderer.getMaxTextWidth(this.font, list); - int height = list.size() * 10; + int height = lines * 10; float intensity = 0.05f; int color = ColorUtil.ARGB.pack(intensity, intensity, intensity, 0.6f); GuiRenderer.fill(x - padding, y - padding, x + width + padding, y + height + padding, color); - color = RED; + color = VGuiConstants.COLOR_RED; GuiRenderer.renderBorder(x - padding, y - padding, x + width + padding, y + height + padding, 1, color); int yOffset = 0; @@ -286,19 +418,24 @@ private void renderTooltip(List list, int x, int y) { } } - private List getHoveredButtonTooltip(VOptionList buttonList, int mouseX, int mouseY) { - VAbstractWidget widget = buttonList.getHoveredWidget(mouseX, mouseY); - if (widget != null) { - var tooltip = widget.getTooltip(); - if (tooltip == null) - return null; + private List getWidgetTooltip(VAbstractWidget widget) { + var tooltip = widget.getTooltip(); + var impact = widget.getImpact(); + + List textList = new ArrayList<>(); + if (tooltip != null) { + textList.addAll(this.font.split(tooltip, this.tooltipWidth)); + } - return this.font.split(tooltip, this.tooltipWidth); + if (impact != null) { + textList.addAll(this.font.split(Component.translatable("Performance Impact: %s", impact.component()), this.tooltipWidth)); } - return null; + + return textList; } private void updateState() { + if (this.applyButton == null | this.undoButton == null) return; boolean modified = false; for (var page : this.optionPages) { modified |= page.optionChanged(); @@ -311,16 +448,30 @@ private void updateState() { } this.applyButton.active = modified; + this.undoButton.visible = modified; } private void setOptionList(int i) { this.currentListIdx = i; + this.isSearchActive = false; + + this.searchField.setInput(""); + this.searchField.setFocused(false); this.buildPage(); this.pageButtons.get(i).setSelected(true); } + private void undo() { + for (OptionPage page : this.optionPages) { + page.resetToOriginalState(); + page.updateOptionStates(); + } + + buildPage(); + } + private void applyOptions() { List pages = List.copyOf(this.optionPages); for (var page : pages) { @@ -328,6 +479,39 @@ private void applyOptions() { page.updateOptionStates(); } - Initializer.CONFIG.write(); + for (var modEntry : this.modSettingsEntries) { + modEntry.runOnApply(); + } + } + + @Override + public boolean keyPressed(KeyEvent keyEvent) { + if (keyEvent.hasControlDown() && keyEvent.key() == GLFW.GLFW_KEY_L) { + this.setFocused(searchField); + searchField.setFocused(true); + searchField.setSelected(true); + + return true; + } + + if (keyEvent.key() == GLFW.GLFW_KEY_ESCAPE && this.isSearchActive) { + this.isSearchActive = false; + this.searchField.setInput(""); + this.searchField.setFocused(false); + this.buildPage(); + this.pageButtons.get(this.currentListIdx).setSelected(true); + return true; + } + + + if (!this.searchField.focused + && keyEvent.key() == GLFW.GLFW_KEY_P + && keyEvent.hasShiftDown()) { + Minecraft.getInstance().setScreen(new VideoSettingsScreen(this, Minecraft.getInstance(), Minecraft.getInstance().options)); + + return false; + } + + return super.keyPressed(keyEvent); } -} +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/gui/render/GuiRenderer.java b/src/main/java/net/vulkanmod/config/gui/render/GuiRenderer.java index e268dab921..3a502e3e13 100644 --- a/src/main/java/net/vulkanmod/config/gui/render/GuiRenderer.java +++ b/src/main/java/net/vulkanmod/config/gui/render/GuiRenderer.java @@ -2,12 +2,14 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.vertex.*; +import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; import org.joml.Matrix3x2f; import java.util.List; @@ -35,15 +37,16 @@ public static void fill(int x0, int y0, int x1, int y1, int color) { fill(x0, y0, x1, y1, 0, color); } - public static void fill(int x0, int y0, int x1, int y1, int z, int color) { + public static void fill(int x0, int y0, int x1, int y1, @SuppressWarnings("unused") int z, int color) { guiGraphics.fill(x0, y0, x1, y1, color); } + @SuppressWarnings("unused") public static void fillGradient(int x0, int y0, int x1, int y1, int color1, int color2) { fillGradient(x0, y0, x1, y1, 0, color1, color2); } - public static void fillGradient(int x0, int y0, int x1, int y1, int z, int color1, int color2) { + public static void fillGradient(int x0, int y0, int x1, int y1, @SuppressWarnings("unused") int z, int color1, int color2) { guiGraphics.fillGradient(x0, y0, x1, y1, color1, color2); } @@ -80,6 +83,24 @@ public static void drawCenteredString(Font font, Component component, int x, int guiGraphics.drawString(font, formattedCharSequence, x - font.width(formattedCharSequence) / 2, y, color); } + public static void drawScrollingString(Font font, Component component, int x, int y, int maxWidth, int color) { + int textWidth = font.width(component); + if (textWidth <= maxWidth) { + drawCenteredString(font, component, x, y, color); + } else { + int x0 = x - maxWidth / 2, x1 = x + maxWidth / 2; + int scrollAmount = textWidth - maxWidth; + double currentTimeInSeconds = (double) Util.getMillis() / 1000.0; + double scrollSpeed = Math.max(scrollAmount * 0.5, 3.0); + double scrollingOffset = Math.sin((Math.PI / 2) * Math.cos((Math.PI * 2) * currentTimeInSeconds / scrollSpeed)) / 2.0 + 0.5; + double horizontalScroll = Mth.lerp(scrollingOffset, 0.0, scrollAmount); + + enableScissor(x0 - 1, 0, x1, Minecraft.getInstance().getWindow().getScreenHeight()); + drawString(font, component, (int) (x0 - horizontalScroll), y, color); + disableScissor(); + } + } + public static int getMaxTextWidth(Font font, List list) { int maxWidth = 0; for (var text : list) { @@ -98,4 +119,4 @@ renderPipeline, textureSetup, new Matrix3x2f(), vertices, color, guiGraphics.sci ) ); } -} +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/gui/util/SearchHelper.java b/src/main/java/net/vulkanmod/config/gui/util/SearchHelper.java new file mode 100644 index 0000000000..4ec106685b --- /dev/null +++ b/src/main/java/net/vulkanmod/config/gui/util/SearchHelper.java @@ -0,0 +1,19 @@ +package net.vulkanmod.config.gui.util; + +import net.minecraft.network.chat.Component; +import net.vulkanmod.config.option.CyclingOption; + +import java.util.function.Function; + +public class SearchHelper { + public static boolean matchesAnyValue(CyclingOption cycling, String searchTerm) { + Function translator = cycling.getTranslator(); + for (T value : cycling.getValues()) { + String translated = translator.apply(value).getString().toLowerCase(); + if (translated.contains(searchTerm)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/net/vulkanmod/config/gui/util/VGuiConstants.java b/src/main/java/net/vulkanmod/config/gui/util/VGuiConstants.java new file mode 100644 index 0000000000..4e3187f9e1 --- /dev/null +++ b/src/main/java/net/vulkanmod/config/gui/util/VGuiConstants.java @@ -0,0 +1,15 @@ +package net.vulkanmod.config.gui.util; + +import net.vulkanmod.vulkan.util.ColorUtil; + +public class VGuiConstants { + public static final int COLOR_WHITE = ColorUtil.ARGB.pack(1f, 1f, 1f, 1f); + public static final int COLOR_BLACK = ColorUtil.ARGB.pack(0f, 0f, 0f, 1f); + public static final int COLOR_GRAY = ColorUtil.ARGB.pack(0.6f, 0.6f, 0.6f, 1f); + public static final int COLOR_RED = ColorUtil.ARGB.pack(0.4f, 0.05f, 0.05f, 0.8f); + + public static final int PAGE_BUTTON_WIDTH = 100; + public static final int WIDGET_HEIGHT = 20; + public static final int WIDGET_MARGIN = 5; + +} diff --git a/src/main/java/net/vulkanmod/config/gui/widget/CyclingOptionWidget.java b/src/main/java/net/vulkanmod/config/gui/widget/CyclingOptionWidget.java index 0537396ccf..5dc4801061 100644 --- a/src/main/java/net/vulkanmod/config/gui/widget/CyclingOptionWidget.java +++ b/src/main/java/net/vulkanmod/config/gui/widget/CyclingOptionWidget.java @@ -8,6 +8,7 @@ import net.vulkanmod.config.option.CyclingOption; import net.vulkanmod.render.shader.CustomRenderPipelines; import net.vulkanmod.vulkan.util.ColorUtil; +import org.jetbrains.annotations.NotNull; public class CyclingOptionWidget extends OptionWidget> { private final Button leftButton; @@ -29,11 +30,6 @@ public void setDimensions(int x, int y, int width, int height) { this.rightButton.setDimensions(this.controlX + this.controlWidth - 16, 16); } - @Override - protected int getYImage(boolean hovered) { - return 0; - } - public void renderControls(double mouseX, double mouseY) { this.renderBars(); @@ -44,7 +40,7 @@ public void renderControls(double mouseX, double mouseY) { Font textRenderer = Minecraft.getInstance().font; int x = this.controlX + this.controlWidth / 2; int y = this.y + (this.height - 9) / 2; - GuiRenderer.drawCenteredString(textRenderer, this.getDisplayedValue(), x, y, color); + GuiRenderer.drawScrollingString(textRenderer, this.getDisplayedValue(), x, y, (rightButton.x - (leftButton.x + leftButton.width) - 12), color); this.leftButton.renderButton(mouseX, mouseY); this.rightButton.renderButton(mouseX, mouseY); @@ -152,7 +148,13 @@ else if (this.active) { color = INACTIVE_COLOR; } - float h = f; + float[][] vertices = getVertices(f); + + + GuiRenderer.submitPolygon(CustomRenderPipelines.GUI_TRIANGLES, TextureSetup.noTexture(), vertices, color); + } + + private float[] @NotNull [] getVertices(float f) { float w = f - 1.0f; float yC = y + height * 0.5f; float xC = x + width * 0.5f; @@ -161,20 +163,18 @@ else if (this.active) { if (this.direction == Direction.LEFT) { vertices = new float[][]{ {xC - w, yC}, - {xC + w, yC + h}, - {xC + w, yC - h}, + {xC + w, yC + f}, + {xC + w, yC - f}, }; } else { vertices = new float[][]{ {xC + w, yC}, - {xC - w, yC - h}, - {xC - w, yC + h}, + {xC - w, yC - f}, + {xC - w, yC + f}, }; } - - - GuiRenderer.submitPolygon(CustomRenderPipelines.GUI_TRIANGLES, TextureSetup.noTexture(), vertices, color); + return vertices; } enum Direction { diff --git a/src/main/java/net/vulkanmod/config/gui/widget/ModIconWidget.java b/src/main/java/net/vulkanmod/config/gui/widget/ModIconWidget.java new file mode 100644 index 0000000000..a182c5d79f --- /dev/null +++ b/src/main/java/net/vulkanmod/config/gui/widget/ModIconWidget.java @@ -0,0 +1,39 @@ +package net.vulkanmod.config.gui.widget; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.resources.ResourceLocation; +import net.vulkanmod.config.gui.render.GuiRenderer; +import net.vulkanmod.config.gui.util.VGuiConstants; +import net.vulkanmod.vulkan.util.ColorUtil; + +public class ModIconWidget extends VAbstractWidget { + final FormattedText name; + final ResourceLocation icon; + + public ModIconWidget(FormattedText name, ResourceLocation icon, int x0, int y0, int width, int height) { + this.name = name; + this.icon = icon; + this.x = x0; + this.y = y0; + this.width = width; + this.height = height; + } + + public void render(double mX, double mY) { + int iconBackgroundColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_BLACK, 0.6f); + int iconBackgroundWidth = this.width; + int iconBackgroundHeight = this.height; + GuiRenderer.fill(this.x, this.y, this.x + iconBackgroundWidth, this.y + iconBackgroundHeight, iconBackgroundColor); + + + int size = this.height; + int iconX = this.x; + int iconY = this.y + (iconBackgroundHeight - size) / 2; + GuiRenderer.guiGraphics.blit(RenderPipelines.GUI_TEXTURED, icon, iconX, iconY, 0f, 0f, size, size, size, size); + + GuiRenderer.drawString(Minecraft.getInstance().font, (Component) this.name, this.x + size, iconY + this.height / 2 - 4, 0xffffffff); + } +} diff --git a/src/main/java/net/vulkanmod/config/gui/widget/OptionWidget.java b/src/main/java/net/vulkanmod/config/gui/widget/OptionWidget.java index e70d8e05fe..93db44cf05 100644 --- a/src/main/java/net/vulkanmod/config/gui/widget/OptionWidget.java +++ b/src/main/java/net/vulkanmod/config/gui/widget/OptionWidget.java @@ -5,13 +5,12 @@ import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.input.MouseButtonEvent; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.client.sounds.SoundManager; import net.minecraft.network.chat.Component; -import net.minecraft.sounds.SoundEvents; import net.vulkanmod.config.gui.render.GuiRenderer; import net.vulkanmod.config.option.Option; +import net.vulkanmod.config.option.PerformanceImpact; import net.vulkanmod.vulkan.util.ColorUtil; +import org.jetbrains.annotations.NotNull; public abstract class OptionWidget> extends VAbstractWidget implements NarratableEntry { public int controlX; @@ -48,15 +47,9 @@ public void render(double mouseX, double mouseY) { this.renderWidget(mouseX, mouseY); } - public void updateState() { - - } - public void renderWidget(double mouseX, double mouseY) { Minecraft minecraftClient = Minecraft.getInstance(); - int i = this.getYImage(this.isHovered()); - int xPadding = 0; int yPadding = 0; @@ -68,23 +61,22 @@ public void renderWidget(double mouseX, double mouseY) { color = this.active ? 0xFFFFFFFF : 0xFFA0A0A0; Font textRenderer = minecraftClient.font; - GuiRenderer.drawString(textRenderer, this.getName().getVisualOrderText(), this.x + 8, this.y + (this.height - 8) / 2, color); + Component nameComp = this.getName(); - this.renderControls(mouseX, mouseY); - } - - protected int getYImage(boolean hovered) { - int i = 1; - if (!this.active) { - i = 0; - } else if (hovered) { - i = 2; + if (this.option.isChanged()) { + nameComp = nameComp.copy().withStyle(style -> style.withItalic(true)); } - return i; - } - public boolean isHovered() { - return this.hovered || this.focused; + GuiRenderer.drawString( + textRenderer, + nameComp.getVisualOrderText(), + this.x + 8, + this.y + (this.height - 8) / 2, + color + ); + + + this.renderControls(mouseX, mouseY); } protected abstract void renderControls(double mouseX, double mouseY); @@ -95,10 +87,6 @@ public boolean isHovered() { protected abstract void onDrag(double mouseX, double mouseY, double deltaX, double deltaY); - protected boolean isValidClickButton(int button) { - return button == 0; - } - @Override public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) { if (this.isValidClickButton(event.button())) { @@ -166,8 +154,12 @@ public Component getTooltip() { return this.option.getTooltip(); } + public PerformanceImpact getImpact() { + return this.option.getImpact(); + } + @Override - public NarrationPriority narrationPriority() { + public @NotNull NarrationPriority narrationPriority() { if (this.focused) { return NarrationPriority.FOCUSED; } @@ -181,8 +173,4 @@ public NarrationPriority narrationPriority() { public final void updateNarration(NarrationElementOutput narrationElementOutput) { } - public void playDownSound(SoundManager soundManager) { - soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0f)); - } - } diff --git a/src/main/java/net/vulkanmod/config/gui/widget/RangeOptionWidget.java b/src/main/java/net/vulkanmod/config/gui/widget/RangeOptionWidget.java index 47ccb0dddf..a1168fb0a2 100644 --- a/src/main/java/net/vulkanmod/config/gui/widget/RangeOptionWidget.java +++ b/src/main/java/net/vulkanmod/config/gui/widget/RangeOptionWidget.java @@ -12,8 +12,6 @@ import org.lwjgl.glfw.GLFW; public class RangeOptionWidget extends OptionWidget { - protected double value; - private boolean focused; public RangeOptionWidget(RangeOption option, Component name) { @@ -21,14 +19,10 @@ public RangeOptionWidget(RangeOption option, Component name) { this.setValue(option.getScaledValue()); } - @Override - protected int getYImage(boolean hovered) { - return 0; - } - @Override protected void renderControls(double mouseX, double mouseY) { - int valueX = this.controlX + (int) (this.value * (this.controlWidth)); + float scaledValue = this.option.getScaledNewValue(); + int valueX = this.controlX + (int) (scaledValue * (this.controlWidth)); if (this.controlHovered && this.active) { int halfWidth = 2; @@ -72,7 +66,8 @@ public boolean keyPressed(KeyEvent event) { if (isLeft || isRight) { float direction = isLeft ? -1.0f : 1.0f; - this.setValue(this.value + (double) (direction / (float) (this.width - 8))); + double currentValue = this.option.getScaledValue(); + this.setValue(currentValue + (double) (direction / (float) (this.width - 8))); } return false; @@ -93,10 +88,10 @@ private void setValueFromMouse(double mouseX) { } private void setValue(double value) { - double d = this.value; - this.value = Mth.clamp(value, 0.0, 1.0); - if (d != this.value) { - this.applyValue(); + double currentValue = this.option.getScaledValue(); + value = Mth.clamp(value, 0.0, 1.0); + if (currentValue != value) { + this.applyNewValue((float) value); } this.updateDisplayedValue(); } @@ -106,9 +101,8 @@ protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY this.setValueFromMouse(mouseX); } - private void applyValue() { - option.setValue((float) this.value); - this.value = option.getScaledValue(); + private void applyNewValue(float value) { + option.setNewValueFromScaledFloat(value); } @Override diff --git a/src/main/java/net/vulkanmod/config/gui/widget/VAbstractWidget.java b/src/main/java/net/vulkanmod/config/gui/widget/VAbstractWidget.java index 43959f7a8a..c283eb0d86 100644 --- a/src/main/java/net/vulkanmod/config/gui/widget/VAbstractWidget.java +++ b/src/main/java/net/vulkanmod/config/gui/widget/VAbstractWidget.java @@ -7,7 +7,9 @@ import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvents; import net.vulkanmod.config.gui.GuiElement; +import net.vulkanmod.config.gui.util.VGuiConstants; import net.vulkanmod.config.gui.render.GuiRenderer; +import net.vulkanmod.config.option.PerformanceImpact; import net.vulkanmod.vulkan.util.ColorUtil; public abstract class VAbstractWidget extends GuiElement { @@ -46,16 +48,17 @@ public void setActive(boolean active) { } protected void renderHovering(int xPadding, int yPadding) { + if (this.isFocused() || !this.isActive() || !this.visible || this.focused) + return; + float hoverMultiplier = this.getHoverMultiplier(200); + int borderColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_RED, hoverMultiplier); + int backgroundColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_RED, 0.3f * hoverMultiplier); if (hoverMultiplier > 0.0f) { -// int color = ColorUtil.ARGB.pack(0.5f, 0.5f, 0.5f, hoverMultiplier * 0.2f); - int color = ColorUtil.ARGB.pack(0.3f, 0.0f, 0.0f, hoverMultiplier * 0.2f); -// int color = ColorUtil.ARGB.multiplyAlpha(VOptionScreen.RED, hoverMultiplier); - GuiRenderer.fill(this.x - xPadding, this.y - yPadding, this.x + this.width + xPadding, this.y + this.height + yPadding, color); - -// color = ColorUtil.ARGB.pack(1.0f, 1.0f, 1.0f, hoverMultiplier * 0.8f); - color = ColorUtil.ARGB.pack(0.3f, 0.0f, 0.0f, hoverMultiplier * 0.8f); + GuiRenderer.fill(this.x - xPadding, this.y - yPadding, + this.x + this.width + xPadding, this.y + this.height + yPadding, + backgroundColor); int x0 = this.x - xPadding; int x1 = this.x + this.width + xPadding; @@ -63,7 +66,7 @@ protected void renderHovering(int xPadding, int yPadding) { int y1 = this.y + height + yPadding; int border = 1; - GuiRenderer.renderBorder(x0, y0, x1, y1, border, color); + GuiRenderer.renderBorder(x0, y0, x1, y1, border, borderColor); } } @@ -116,6 +119,12 @@ public boolean mouseDragged(MouseButtonEvent event, double d, double e) { } } + @Override + public void updateState(double mX, double mY) { + super.updateState(mX, mY); + + } + public void playDownSound(SoundManager soundManager) { soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); } @@ -123,4 +132,8 @@ public void playDownSound(SoundManager soundManager) { public Component getTooltip() { return null; } + + public PerformanceImpact getImpact() { + return null; + } } diff --git a/src/main/java/net/vulkanmod/config/gui/widget/VButtonWidget.java b/src/main/java/net/vulkanmod/config/gui/widget/VButtonWidget.java index b1effb5edf..a9d7dffcd6 100644 --- a/src/main/java/net/vulkanmod/config/gui/widget/VButtonWidget.java +++ b/src/main/java/net/vulkanmod/config/gui/widget/VButtonWidget.java @@ -1,12 +1,14 @@ package net.vulkanmod.config.gui.widget; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.ComponentPath; +import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; +import net.vulkanmod.config.gui.util.VGuiConstants; import net.vulkanmod.config.gui.render.GuiRenderer; -import net.vulkanmod.vulkan.VRenderSystem; import net.vulkanmod.vulkan.util.ColorUtil; +import org.jetbrains.annotations.Nullable; import java.util.function.Consumer; @@ -24,37 +26,60 @@ public VButtonWidget(int x, int y, int width, int height, Component message, Con } public void renderWidget(double mouseX, double mouseY) { - Minecraft minecraftClient = Minecraft.getInstance(); - Font textRenderer = minecraftClient.font; + if (!this.isVisible()) return; - int xPadding = 0; - int yPadding = 0; + int backgroundColor = this.isActive() + ? ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_BLACK, 0.45f) + : ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_BLACK, 0.3f); + int textColor = this.isActive() + ? VGuiConstants.COLOR_WHITE + : VGuiConstants.COLOR_GRAY; + //noinspection DuplicatedCode + int selectionOutlineColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_RED, 0.8f); + int selectionFillColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_RED, 0.2f); - int color = ColorUtil.ARGB.pack(0.0f, 0.0f, 0.0f, this.active ? 0.45f : 0.3f); - GuiRenderer.fill(this.x - xPadding, this.y - yPadding, this.x + this.width + xPadding, this.y + this.height + yPadding, color); + GuiRenderer.fill(this.x, this.y, this.x + this.width, this.y + this.height, backgroundColor); - if (this.active) { - this.renderHovering(0, 0); + if (this.selected) { + GuiRenderer.fill(this.x, this.y, this.x + 2, this.y + this.height, selectionOutlineColor); + GuiRenderer.fill(this.x, this.y, this.x + this.width, this.y + this.height, selectionFillColor); } - if (this.selected) { - color = ColorUtil.ARGB.pack(0.3f, 0.0f, 0.0f, 1.0f); - GuiRenderer.fillBox(this.x, this.y, (int) 1.5f, this.height, color); + this.renderHovering(0, 0); - color = ColorUtil.ARGB.pack(0.3f, 0.0f, 0.0f, 0.2f); - GuiRenderer.fillBox(this.x, this.y, this.width, this.height, color); - } + // this is down here because of layering + GuiRenderer.drawString(Minecraft.getInstance().font, + this.message, + this.x + 8, (this.y + this.height / 2) - 4, + textColor | (Mth.ceil(this.alpha * 255.0f) << 24)); + } - int j = this.active ? 0xFFFFFF : 0xA0A0A0; - GuiRenderer.drawCenteredString(textRenderer, this.message, this.x + this.width / 2, this.y + (this.height - 8) / 2, j | Mth.ceil(this.alpha * 255.0f) << 24); + public void onClick(double mX, double mY) { + this.onPress.accept(this); } public void setSelected(boolean selected) { this.selected = selected; } - public void onClick(double mX, double mY) { - this.onPress.accept(this); + public boolean isVisible() { + return visible; + } + + @Override + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + @Override + public @Nullable ComponentPath nextFocusPath(FocusNavigationEvent event) { + if (!this.active || !this.visible) + return null; + return super.nextFocusPath(event); } } diff --git a/src/main/java/net/vulkanmod/config/gui/widget/VTextInputWidget.java b/src/main/java/net/vulkanmod/config/gui/widget/VTextInputWidget.java new file mode 100644 index 0000000000..ab0e07c8d2 --- /dev/null +++ b/src/main/java/net/vulkanmod/config/gui/widget/VTextInputWidget.java @@ -0,0 +1,242 @@ +package net.vulkanmod.config.gui.widget; + +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ComponentPath; +import net.minecraft.client.gui.navigation.FocusNavigationEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import net.vulkanmod.config.gui.render.GuiRenderer; +import net.vulkanmod.config.gui.util.VGuiConstants; +import net.vulkanmod.vulkan.util.ColorUtil; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.glfw.GLFW; + +import java.util.function.Consumer; + +public class VTextInputWidget extends VAbstractWidget { + public boolean selected = false; + Consumer onSearch; // when the search is "activated", like pressing enter + private String text; + private final Component placeholder; + + private int cursorPos = 0; + private int selectionEnd = 0; + private long lastBlinkTime = 0; + private boolean showCursor = true; + + private static final int CURSOR_BLINK_INTERVAL = 500; // ms + + public VTextInputWidget(int x, int y, int width, int height, Component placeholder, Consumer onSearch) { + this.setPosition(x, y, width, height); + + this.placeholder = placeholder; + this.onSearch = onSearch; + this.text = ""; + } + + @Override + public void renderWidget(double mouseX, double mouseY) { + if (!this.isVisible()) return; + + boolean hasText = !this.text.isEmpty(); + boolean isFocused = this.focused || this.selected; + + int backgroundColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_BLACK, 0.45f); + + int textColor = hasText ? VGuiConstants.COLOR_WHITE : VGuiConstants.COLOR_GRAY; + + GuiRenderer.fill(this.x, this.y, this.x + this.width, this.y + this.height, backgroundColor); + + this.renderHovering(0, 0); + + if (isFocused && cursorPos != selectionEnd) { + int start = Math.min(cursorPos, selectionEnd); + int end = Math.max(cursorPos, selectionEnd); + String before = text.substring(0, start); + String selected = text.substring(start, end); + + int xBefore = this.x + 8 + Minecraft.getInstance().font.width(before); + int xSelected = Minecraft.getInstance().font.width(selected); + + int selColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_RED, 0.55f); + GuiRenderer.fill(xBefore, this.y + 4, xBefore + xSelected, this.y + this.height - 4, selColor); + } + + Component displayText = hasText ? Component.literal(this.text) : this.placeholder; + GuiRenderer.drawString(Minecraft.getInstance().font, displayText, + this.x + 8, this.y + (this.height - 8) / 2, textColor | 0xFF000000); + + if (isFocused && showCursor) { + String beforeCursor = text.substring(0, cursorPos); + int cursorX = this.x + 8 + Minecraft.getInstance().font.width(beforeCursor); + + GuiRenderer.fill(cursorX, this.y + 6, cursorX + 1, this.y + this.height - 6, + VGuiConstants.COLOR_WHITE); + } + + if (isFocused) { + int borderColor = ColorUtil.ARGB.multiplyAlpha(VGuiConstants.COLOR_RED, 0.8f); + GuiRenderer.renderBorder(this.x, this.y, this.x + this.width, this.y + this.height, 1, borderColor); + } + + if (isFocused) { + long time = Util.getMillis(); + if (time - lastBlinkTime > CURSOR_BLINK_INTERVAL) { + showCursor = !showCursor; + lastBlinkTime = time; + } + } else { + showCursor = true; + } + } + + @Override + public boolean keyPressed(KeyEvent keyEvent) { + if (!this.focused && !this.selected) return false; + + boolean shift = keyEvent.hasShiftDown(); + boolean ctrl = keyEvent.hasControlDown(); + + if (keyEvent.key() == GLFW.GLFW_KEY_ENTER || keyEvent.key() == GLFW.GLFW_KEY_KP_ENTER) { + this.onSearch.accept(this); + return true; + } + + if (cursorPos != selectionEnd) { + int start = Math.min(cursorPos, selectionEnd); + int end = Math.max(cursorPos, selectionEnd); + + if (keyEvent.key() == GLFW.GLFW_KEY_BACKSPACE || keyEvent.key() == GLFW.GLFW_KEY_DELETE) { + this.text = text.substring(0, start) + text.substring(end); + cursorPos = start; + selectionEnd = start; + this.onSearch.accept(this); + return true; + } + } + + if (keyEvent.key() == GLFW.GLFW_KEY_BACKSPACE) { + if (cursorPos > 0) { + this.text = text.substring(0, cursorPos - 1) + text.substring(cursorPos); + cursorPos--; + selectionEnd = cursorPos; + this.onSearch.accept(this); + } + return true; + } + + if (keyEvent.key() == GLFW.GLFW_KEY_DELETE) { + if (cursorPos < text.length()) { + this.text = text.substring(0, cursorPos) + text.substring(cursorPos + 1); + this.onSearch.accept(this); + } + return true; + } + + if (ctrl && keyEvent.key() == GLFW.GLFW_KEY_A) { + cursorPos = text.length(); + selectionEnd = 0; + return true; + } + + if (keyEvent.key() == GLFW.GLFW_KEY_LEFT) { + if (cursorPos > 0) cursorPos--; + if (!shift) selectionEnd = cursorPos; + return true; + } + if (keyEvent.key() == GLFW.GLFW_KEY_RIGHT) { + if (cursorPos < text.length()) cursorPos++; + if (!shift) selectionEnd = cursorPos; + return true; + } + + String keyName = GLFW.glfwGetKeyName(keyEvent.key(), keyEvent.scancode()); + if (keyName != null && keyName.length() == 1) { + char c = keyEvent.hasShiftDown() ? keyName.toUpperCase().charAt(0) : keyName.charAt(0); + + if (cursorPos != selectionEnd) { + int start = Math.min(cursorPos, selectionEnd); + int end = Math.max(cursorPos, selectionEnd); + this.text = text.substring(0, start) + c + text.substring(end); + cursorPos = start + 1; + } else { + this.text = text.substring(0, cursorPos) + c + text.substring(cursorPos); + cursorPos++; + } + selectionEnd = cursorPos; + this.onSearch.accept(this); + return true; + } + + return false; + } + + public String getInput() { + return this.text; + } + + public void setInput(String input) { + this.text = input != null ? input : ""; + } + + @SuppressWarnings("unused") + public void setSelected(boolean selected) { + this.selected = selected; + } + + public boolean isVisible() { + return visible; + } + + @Override + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + @Override + public @Nullable ComponentPath nextFocusPath(FocusNavigationEvent event) { + if (!this.active || !this.visible) + return null; + return super.nextFocusPath(event); + } + + @Override + public boolean mouseClicked(MouseButtonEvent event, boolean bl) { + if (!this.active || !this.visible) return false; + + boolean clicked = this.clicked(event.x(), event.y()); + if (clicked) { + this.setFocused(true); + this.selected = true; + + int relX = (int) event.x() - (this.x + 8); + int pos = 0; + for (int i = 0; i < text.length(); i++) { + if (Minecraft.getInstance().font.width(text.substring(0, i + 1)) > relX) break; + pos = i + 1; + } + cursorPos = pos; + selectionEnd = pos; + + return true; + } else { + this.setFocused(false); + this.selected = false; + return false; + } + } + + @Override + public void setFocused(boolean focused) { + super.setFocused(focused); + if (!focused) { + this.selected = false; + } + } +} diff --git a/src/main/java/net/vulkanmod/config/option/CyclingOption.java b/src/main/java/net/vulkanmod/config/option/CyclingOption.java index 45487f278f..214b90d89f 100644 --- a/src/main/java/net/vulkanmod/config/option/CyclingOption.java +++ b/src/main/java/net/vulkanmod/config/option/CyclingOption.java @@ -20,10 +20,13 @@ public CyclingOption(Component name, E[] values, Consumer setter, Supplier } @Override - public OptionWidget createWidget() { - return new CyclingOptionWidget(this, this.name); + protected OptionWidget createWidget() { + var widget = new CyclingOptionWidget(this, this.name); + this.widget = widget; + return widget; } + @SuppressWarnings("unused") public void updateOption(E[] values, Consumer setter, Supplier getter) { this.onApply = setter; this.valueSupplier = getter; @@ -32,7 +35,9 @@ public void updateOption(E[] values, Consumer setter, Supplier getter) { this.index = ArrayUtils.indexOf(this.values, this.getNewValue()); } - public int index() { return this.index; } + public int index() { + return this.index; + } public void setValues(E[] values) { this.values = values; diff --git a/src/main/java/net/vulkanmod/config/option/Option.java b/src/main/java/net/vulkanmod/config/option/Option.java index 3d2e6e143c..1873520534 100644 --- a/src/main/java/net/vulkanmod/config/option/Option.java +++ b/src/main/java/net/vulkanmod/config/option/Option.java @@ -9,7 +9,9 @@ public abstract class Option { protected final Component name; + @SuppressWarnings("unused") protected Component tooltip; + protected PerformanceImpact impact; protected Consumer onApply; protected Supplier valueSupplier; @@ -18,6 +20,7 @@ public abstract class Option { protected T newValue; protected Function translator; + protected Function tooltipTranslator; OptionWidget widget; @@ -25,6 +28,19 @@ public abstract class Option { protected Runnable onChange; protected Supplier activationFn; + @SuppressWarnings("unused") + public Option(Component name, Consumer setter, Supplier getter, Function translator, Function tooltip) { + this.name = name; + + this.onApply = setter; + this.valueSupplier = getter; + + this.translator = translator; + this.tooltipTranslator = tooltip; + + this.newValue = this.value = this.valueSupplier.get(); + } + public Option(Component name, Consumer setter, Supplier getter, Function translator) { this.name = name; @@ -45,11 +61,13 @@ public Option(Component name, Consumer setter, Supplier getter) { this.newValue = this.value = this.valueSupplier.get(); } + @SuppressWarnings("unused") public Option setOnApply(Consumer onApply) { this.onApply = onApply; return this; } + @SuppressWarnings("unused") public Option setValueSupplier(Supplier supplier) { this.valueSupplier = supplier; return this; @@ -60,13 +78,31 @@ public Option setTranslator(Function translator) { return this; } + public Function getTranslator() { + return translator; + } + + public Option setTooltip(Function tooltipTranslator) { + this.tooltipTranslator = tooltipTranslator; + return this; + } + + public PerformanceImpact getImpact() { + return impact; + } + + public Option setImpact(PerformanceImpact impact) { + this.impact = impact; + return this; + } + public Option setActive(boolean active) { this.active = active; this.widget.active = active; return this; } - abstract OptionWidget createWidget(); + protected abstract OptionWidget createWidget(); public OptionWidget getWidget() { if (this.widget == null) { @@ -117,6 +153,10 @@ public void apply() { this.value = this.newValue; } + public void resetValue() { + this.setNewValue(this.value); + } + public T getNewValue() { return this.newValue; } @@ -125,12 +165,11 @@ public Component getDisplayedValue() { return this.translator.apply(this.newValue); } - public Option setTooltip(Component text) { - this.tooltip = text; - return this; - } - public Component getTooltip() { - return this.tooltip; + if (this.tooltipTranslator != null) { + return this.tooltipTranslator.apply(this.newValue); + } else { + return null; + } } -} +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/option/OptionPage.java b/src/main/java/net/vulkanmod/config/option/OptionPage.java index 7000e14682..22c957d025 100644 --- a/src/main/java/net/vulkanmod/config/option/OptionPage.java +++ b/src/main/java/net/vulkanmod/config/option/OptionPage.java @@ -5,8 +5,9 @@ public class OptionPage { public final String name; - OptionBlock[] optionBlocks; + public OptionBlock[] optionBlocks; private VOptionList optionList; + private int order; public OptionPage(String name, OptionBlock[] optionBlocks) { this.name = name; @@ -50,4 +51,20 @@ public void updateOptionStates() { } } } -} + + public void resetToOriginalState() { + for (var block : this.optionBlocks) { + for (var option : block.options()) { + option.resetValue(); + } + } + } + + public void setOrder(int order) { + this.order = order; + } + + public int getOrder() { + return order; + } +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/option/Options.java b/src/main/java/net/vulkanmod/config/option/Options.java index 9189490012..6da44f5706 100644 --- a/src/main/java/net/vulkanmod/config/option/Options.java +++ b/src/main/java/net/vulkanmod/config/option/Options.java @@ -6,24 +6,56 @@ import net.minecraft.server.level.ParticleStatus; import net.vulkanmod.Initializer; import net.vulkanmod.config.Config; -import net.vulkanmod.config.gui.OptionBlock; -import net.vulkanmod.config.video.VideoModeManager; -import net.vulkanmod.config.video.VideoModeSet; -import net.vulkanmod.config.video.WindowMode; +import net.vulkanmod.config.gui.*; +import net.vulkanmod.config.video.*; import net.vulkanmod.render.chunk.WorldRenderer; import net.vulkanmod.render.chunk.build.light.LightMode; import net.vulkanmod.render.vertex.TerrainRenderType; import net.vulkanmod.vulkan.Renderer; import net.vulkanmod.vulkan.device.DeviceManager; +import java.util.ArrayList; +import java.util.List; import java.util.stream.IntStream; public abstract class Options { + public static boolean fullscreenDirty = false; - static Config config = Initializer.CONFIG; - static Minecraft minecraft = Minecraft.getInstance(); - static Window window = minecraft.getWindow(); - static net.minecraft.client.Options minecraftOptions = minecraft.options; + + private static final Config config = Initializer.CONFIG; + private static final Minecraft minecraft = Minecraft.getInstance(); + private static final Window window = minecraft.getWindow(); + private static final net.minecraft.client.Options mcOptions = minecraft.options; + + public static List getOptionPages() { + List optionPages = new ArrayList<>(); + + OptionPage page = new OptionPage( + Component.translatable("vulkanmod.options.pages.video").getString(), + Options.getVideoOpts() + ); + optionPages.add(page); + + page = new OptionPage( + Component.translatable("vulkanmod.options.pages.graphics").getString(), + Options.getGraphicsOpts() + ); + optionPages.add(page); + + page = new OptionPage( + Component.translatable("vulkanmod.options.pages.optimizations").getString(), + Options.getOptimizationOpts() + ); + optionPages.add(page); + + page = new OptionPage( + Component.translatable("vulkanmod.options.pages.other").getString(), + Options.getOtherOpts() + ); + optionPages.add(page); + + return optionPages; + } public static OptionBlock[] getVideoOpts() { VideoModeManager.selectBestMonitor(window); @@ -44,7 +76,7 @@ public static OptionBlock[] getVideoOpts() { WindowMode.values(), value -> { boolean exclusiveFullscreen = value == WindowMode.EXCLUSIVE_FULLSCREEN; - minecraftOptions.fullscreen() + mcOptions.fullscreen() .set(exclusiveFullscreen); config.windowMode = value.mode; @@ -53,15 +85,16 @@ public static OptionBlock[] getVideoOpts() { () -> WindowMode.fromValue(config.windowMode)) .setTranslator(value -> Component.translatable(WindowMode.getComponentName(value))); - CyclingOption RefreshRate = (CyclingOption) new CyclingOption<>( + CyclingOption refreshRateOption = (CyclingOption) new CyclingOption<>( Component.translatable("vulkanmod.options.refreshRate"), refreshRates.toArray(new Integer[0]), (value) -> { VideoModeManager.selectedVideoMode.refreshRate = value; VideoModeManager.applySelectedVideoMode(); - if (minecraftOptions.fullscreen().get()) + if (mcOptions.fullscreen().get()) { fullscreenDirty = true; + } }, () -> VideoModeManager.selectedVideoMode.refreshRate) .setTranslator(refreshRate -> Component.nullToEmpty(refreshRate.toString())) @@ -71,11 +104,12 @@ public static OptionBlock[] getVideoOpts() { Component.translatable("options.fullscreen.resolution"), resolutions, (value) -> { - VideoModeManager.selectedVideoMode = value.getVideoMode(RefreshRate.getNewValue()); + VideoModeManager.selectedVideoMode = value.getVideoMode(refreshRateOption.getNewValue()); VideoModeManager.applySelectedVideoMode(); - if (minecraftOptions.fullscreen().get()) + if (mcOptions.fullscreen().get()) { fullscreenDirty = true; + } }, () -> { var selectedVideoMode = VideoModeManager.selectedVideoMode; @@ -87,81 +121,91 @@ public static OptionBlock[] getVideoOpts() { .setActivationFn(() -> windowModeOption.getNewValue() == WindowMode.EXCLUSIVE_FULLSCREEN); resolutionOption.setOnChange(() -> { - var newVideoMode = resolutionOption.getNewValue(); - var newRefreshRates = newVideoMode.getRefreshRates().toArray(new Integer[0]); - - RefreshRate.setValues(newRefreshRates); - RefreshRate.setNewValue(newRefreshRates[newRefreshRates.length - 1]); + VideoModeSet newSet = resolutionOption.getNewValue(); + Integer[] rates = newSet.getRefreshRates().toArray(new Integer[0]); + refreshRateOption.setValues(rates); + refreshRateOption.setNewValue(rates[rates.length - 1]); }); windowModeOption.setOnChange(() -> { resolutionOption.updateActiveState(); - RefreshRate.updateActiveState(); + refreshRateOption.updateActiveState(); }); return new OptionBlock[]{ new OptionBlock("", new Option[]{ windowModeOption, resolutionOption, - RefreshRate, + refreshRateOption, new RangeOption(Component.translatable("options.framerateLimit"), - 10, 260, 10, - value -> Component.nullToEmpty(value == 260 ? - Component.translatable( - "options.framerateLimit.max") - .getString() : - String.valueOf(value)), - value -> { - minecraftOptions.framerateLimit().set(value); - minecraft.getFramerateLimitTracker().setFramerateLimit(value); - }, - () -> minecraftOptions.framerateLimit().get()), + 10, 260, 10, + value -> Component.nullToEmpty(value == 260 + ? Component.translatable("options.framerateLimit.max").getString() + : String.valueOf(value)), + value -> { + mcOptions.framerateLimit().set(value); + minecraft.getFramerateLimitTracker().setFramerateLimit(value); + }, + () -> mcOptions.framerateLimit().get()), new SwitchOption(Component.translatable("options.vsync"), - value -> { - minecraftOptions.enableVsync().set(value); - window.updateVsync(value); - }, - () -> minecraftOptions.enableVsync().get()), + value -> { + mcOptions.enableVsync().set(value); + window.updateVsync(value); + }, + () -> mcOptions.enableVsync().get()), new CyclingOption<>(Component.translatable("options.inactivityFpsLimit"), - InactivityFpsLimit.values(), - value -> minecraftOptions.inactivityFpsLimit().set(value), - () -> minecraftOptions.inactivityFpsLimit().get()) - .setTranslator(inactivityFpsLimit -> Component.translatable(inactivityFpsLimit.getKey())) + InactivityFpsLimit.values(), + value -> mcOptions.inactivityFpsLimit().set(value), + () -> mcOptions.inactivityFpsLimit().get()) + .setTranslator(v -> Component.translatable(v.getKey())) }), new OptionBlock("", new Option[]{ new RangeOption(Component.translatable("options.guiScale"), - 0, window.calculateScale(0, minecraft.isEnforceUnicode()), 1, - value -> Component.translatable((value == 0) - ? "options.guiScale.auto" - : String.valueOf(value)), - value -> { - minecraftOptions.guiScale().set(value); - minecraft.resizeDisplay(); - }, - () -> (minecraftOptions.guiScale().get())), + 0, window.calculateScale(0, minecraft.isEnforceUnicode()), 1, + value -> Component.translatable(value == 0 ? "options.guiScale.auto" : String.valueOf(value)), + value -> { + mcOptions.guiScale().set(value); + minecraft.resizeDisplay(); + }, + () -> mcOptions.guiScale().get()), new RangeOption(Component.translatable("options.gamma"), - 0, 100, 1, - value -> Component.translatable(switch (value) { - case 0 -> "options.gamma.min"; - case 50 -> "options.gamma.default"; - case 100 -> "options.gamma.max"; - default -> String.valueOf(value); - }), - value -> minecraftOptions.gamma().set(value * 0.01), - () -> (int) (minecraftOptions.gamma().get() * 100.0)), + 0, 100, 1, + value -> Component.translatable(switch (value) { + case 0 -> "options.gamma.min"; + case 50 -> "options.gamma.default"; + case 100 -> "options.gamma.max"; + default -> String.valueOf(value); + }), + value -> mcOptions.gamma().set(value * 0.01), + () -> (int) (mcOptions.gamma().get() * 100.0)) }), new OptionBlock("", new Option[]{ new SwitchOption(Component.translatable("options.viewBobbing"), - (value) -> minecraftOptions.bobView().set(value), - () -> minecraftOptions.bobView().get()), + value -> mcOptions.bobView().set(value), + () -> mcOptions.bobView().get()), + new RangeOption(Component.translatable("options.fovEffectScale"), + 0, 100, 1, + value -> mcOptions.fovEffectScale().set(value / 100.0), + () -> (int) (mcOptions.fovEffectScale().get() * 100)) + .setTooltip(value -> Component.translatable("options.fovEffectScale.tooltip")), + new RangeOption(Component.translatable("options.glintSpeed"), + 0, 100, 1, + value -> mcOptions.glintSpeed().set(value / 100.0), + () -> (int) (mcOptions.glintSpeed().get() * 100)) + .setTooltip(value -> Component.translatable("options.glintSpeed.tooltip")), + new RangeOption(Component.translatable("options.glintStrength"), + 0, 100, 1, + value -> mcOptions.glintStrength().set(value / 100.0), + () -> (int) (mcOptions.glintStrength().get() * 100)) + .setTooltip(value -> Component.translatable("options.glintStrength.tooltip")), new CyclingOption<>(Component.translatable("options.attackIndicator"), - AttackIndicatorStatus.values(), - value -> minecraftOptions.attackIndicator().set(value), - () -> minecraftOptions.attackIndicator().get()) - .setTranslator(value -> Component.translatable(value.getKey())), + AttackIndicatorStatus.values(), + value -> mcOptions.attackIndicator().set(value), + () -> mcOptions.attackIndicator().get()) + .setTranslator(v -> Component.translatable(v.getKey())), new SwitchOption(Component.translatable("options.autosaveIndicator"), - value -> minecraftOptions.showAutosaveIndicator().set(value), - () -> minecraftOptions.showAutosaveIndicator().get()), + value -> mcOptions.showAutosaveIndicator().set(value), + () -> mcOptions.showAutosaveIndicator().get()) }) }; } @@ -170,180 +214,179 @@ public static OptionBlock[] getGraphicsOpts() { return new OptionBlock[]{ new OptionBlock("", new Option[]{ new RangeOption(Component.translatable("options.renderDistance"), - 2, 32, 1, - (value) -> minecraftOptions.renderDistance().set(value), - () -> minecraftOptions.renderDistance().get()), + 2, 32, 1, + value -> mcOptions.renderDistance().set(value), + () -> mcOptions.renderDistance().get()) + .setTooltip(v -> Component.literal("Chunk render distance")) + .setImpact(PerformanceImpact.HIGH), new RangeOption(Component.translatable("options.simulationDistance"), - 5, 32, 1, - (value) -> minecraftOptions.simulationDistance().set(value), - () -> minecraftOptions.simulationDistance().get()), + 5, 32, 1, + value -> mcOptions.simulationDistance().set(value), + () -> mcOptions.simulationDistance().get()), new CyclingOption<>(Component.translatable("options.prioritizeChunkUpdates"), - PrioritizeChunkUpdates.values(), - value -> minecraftOptions.prioritizeChunkUpdates().set(value), - () -> minecraftOptions.prioritizeChunkUpdates().get()) - .setTranslator(value -> Component.translatable(value.getKey())), + PrioritizeChunkUpdates.values(), + value -> mcOptions.prioritizeChunkUpdates().set(value), + () -> mcOptions.prioritizeChunkUpdates().get()) + .setTranslator(v -> Component.translatable(v.getKey())) }), new OptionBlock("", new Option[]{ new CyclingOption<>(Component.translatable("options.graphics"), - new GraphicsStatus[]{GraphicsStatus.FAST, GraphicsStatus.FANCY}, - value -> minecraftOptions.graphicsMode().set(value), - () -> minecraftOptions.graphicsMode().get()) - .setTranslator(graphicsMode -> Component.translatable(graphicsMode.getKey())), + new GraphicsStatus[]{GraphicsStatus.FAST, GraphicsStatus.FANCY}, + value -> mcOptions.graphicsMode().set(value), + () -> mcOptions.graphicsMode().get()) + .setTranslator(g -> Component.translatable(g.getKey())), new CyclingOption<>(Component.translatable("options.particles"), - new ParticleStatus[]{ParticleStatus.MINIMAL, ParticleStatus.DECREASED, ParticleStatus.ALL}, - value -> minecraftOptions.particles().set(value), - () -> minecraftOptions.particles().get()) - .setTranslator(particlesMode -> Component.translatable(particlesMode.getKey())), + new ParticleStatus[]{ParticleStatus.MINIMAL, ParticleStatus.DECREASED, ParticleStatus.ALL}, + value -> mcOptions.particles().set(value), + () -> mcOptions.particles().get()) + .setImpact(PerformanceImpact.MEDIUM) + .setTranslator(p -> Component.translatable(p.getKey())), new CyclingOption<>(Component.translatable("options.renderClouds"), - CloudStatus.values(), - value -> minecraftOptions.cloudStatus().set(value), - () -> minecraftOptions.cloudStatus().get()) - .setTranslator(value -> Component.translatable(value.getKey())), + CloudStatus.values(), + value -> mcOptions.cloudStatus().set(value), + () -> mcOptions.cloudStatus().get()) + .setTranslator(c -> Component.translatable(c.getKey())), new RangeOption(Component.translatable("options.renderCloudsDistance"), - 2, 128, 1, - (value) -> minecraftOptions.cloudRange().set(value), - () -> minecraftOptions.cloudRange().get()), + 2, 128, 1, + value -> mcOptions.cloudRange().set(value), + () -> mcOptions.cloudRange().get()), new CyclingOption<>(Component.translatable("options.ao"), - new Integer[]{LightMode.FLAT, LightMode.SMOOTH, LightMode.SUB_BLOCK}, - (value) -> { - if (value > LightMode.FLAT) - minecraftOptions.ambientOcclusion().set(true); - else - minecraftOptions.ambientOcclusion().set(false); - - config.ambientOcclusion = value; - - minecraft.levelRenderer.allChanged(); - }, - () -> config.ambientOcclusion) + new Integer[]{LightMode.FLAT, LightMode.SMOOTH, LightMode.SUB_BLOCK}, + value -> { + mcOptions.ambientOcclusion().set(value > LightMode.FLAT); + config.ambientOcclusion = value; + minecraft.levelRenderer.allChanged(); + }, + () -> config.ambientOcclusion) .setTranslator(value -> Component.translatable(switch (value) { case LightMode.FLAT -> "options.off"; case LightMode.SMOOTH -> "options.on"; case LightMode.SUB_BLOCK -> "vulkanmod.options.ao.subBlock"; default -> "vulkanmod.options.unknown"; })) - .setTooltip(Component.translatable("vulkanmod.options.ao.subBlock.tooltip")), + .setTooltip(value -> value == LightMode.SUB_BLOCK + ? Component.translatable("vulkanmod.options.ao.subBlock.tooltip") + : Component.empty()) + .setImpact(PerformanceImpact.LOW), new RangeOption(Component.translatable("options.biomeBlendRadius"), - 0, 7, 1, - value -> { - int v = value * 2 + 1; - return Component.nullToEmpty("%d x %d".formatted(v, v)); - }, - (value) -> { - minecraftOptions.biomeBlendRadius().set(value); - minecraft.levelRenderer.allChanged(); - }, - () -> minecraftOptions.biomeBlendRadius().get()), + 0, 7, 1, + value -> Component.nullToEmpty("%d x %d".formatted(value * 2 + 1, value * 2 + 1)), + value -> { + mcOptions.biomeBlendRadius().set(value); + minecraft.levelRenderer.allChanged(); + }, + () -> mcOptions.biomeBlendRadius().get()) }), new OptionBlock("", new Option[]{ new SwitchOption(Component.translatable("options.entityShadows"), - value -> minecraftOptions.entityShadows().set(value), - () -> minecraftOptions.entityShadows().get()), + value -> mcOptions.entityShadows().set(value), + () -> mcOptions.entityShadows().get()) + .setImpact(PerformanceImpact.LOW), new RangeOption(Component.translatable("options.entityDistanceScaling"), - 50, 500, 25, - value -> minecraftOptions.entityDistanceScaling().set(value * 0.01), - () -> minecraftOptions.entityDistanceScaling().get().intValue() * 100), + 50, 500, 25, + value -> mcOptions.entityDistanceScaling().set(value * 0.01), + () -> (int)(mcOptions.entityDistanceScaling().get() * 100)) + .setImpact(PerformanceImpact.HIGH), new CyclingOption<>(Component.translatable("options.mipmapLevels"), - new Integer[]{0, 1, 2, 3, 4}, - value -> { - minecraftOptions.mipmapLevels().set(value); - minecraft.updateMaxMipLevel(value); - minecraft.delayTextureReload(); - }, - () -> minecraftOptions.mipmapLevels().get()) - .setTranslator(value -> Component.nullToEmpty(value.toString())) + new Integer[]{0,1,2,3,4}, + value -> { + mcOptions.mipmapLevels().set(value); + minecraft.updateMaxMipLevel(value); + minecraft.delayTextureReload(); + }, + () -> mcOptions.mipmapLevels().get()) + .setTranslator(v -> Component.literal(String.valueOf(v))) + .setImpact(PerformanceImpact.LOW) }) }; } public static OptionBlock[] getOptimizationOpts() { return new OptionBlock[]{ - new OptionBlock("", new Option[]{ + new OptionBlock("", new Option[]{ new CyclingOption<>(Component.translatable("vulkanmod.options.advCulling"), - new Integer[]{1, 2, 3, 10}, - value -> config.advCulling = value, - () -> config.advCulling) - .setTranslator(value -> Component.translatable(switch (value) { + new Integer[]{1, 2, 3, 10}, + value -> config.advCulling = value, + () -> config.advCulling) + .setTranslator(v -> Component.translatable(switch (v) { case 1 -> "vulkanmod.options.advCulling.aggressive"; case 2 -> "vulkanmod.options.advCulling.normal"; case 3 -> "vulkanmod.options.advCulling.conservative"; case 10 -> "options.off"; default -> "vulkanmod.options.unknown"; })) - .setTooltip(Component.translatable("vulkanmod.options.advCulling.tooltip")), + .setTooltip(v -> v <= 3 ? Component.translatable("vulkanmod.options.advCulling.tooltip") : Component.empty()) + .setImpact(PerformanceImpact.HIGH), new SwitchOption(Component.translatable("vulkanmod.options.entityCulling"), - value -> config.entityCulling = value, - () -> config.entityCulling) - .setTooltip(Component.translatable("vulkanmod.options.entityCulling.tooltip")), + v -> config.entityCulling = v, + () -> config.entityCulling) + .setTooltip(v -> Component.translatable("vulkanmod.options.entityCulling.tooltip")) + .setImpact(PerformanceImpact.HIGH), new SwitchOption(Component.translatable("vulkanmod.options.uniqueOpaqueLayer"), - value -> { - config.uniqueOpaqueLayer = value; - TerrainRenderType.updateMapping(); - minecraft.levelRenderer.allChanged(); - }, - () -> config.uniqueOpaqueLayer) - .setTooltip(Component.translatable("vulkanmod.options.uniqueOpaqueLayer.tooltip")), + v -> { + config.uniqueOpaqueLayer = v; + TerrainRenderType.updateMapping(); + minecraft.levelRenderer.allChanged(); + }, + () -> config.uniqueOpaqueLayer) + .setTooltip(v -> Component.translatable("vulkanmod.options.uniqueOpaqueLayer.tooltip")) + .setImpact(PerformanceImpact.HIGH), new SwitchOption(Component.translatable("vulkanmod.options.backfaceCulling"), - value -> { - config.backFaceCulling = value; - Minecraft.getInstance().levelRenderer.allChanged(); - }, - () -> config.backFaceCulling) - .setTooltip(Component.translatable("vulkanmod.options.backfaceCulling.tooltip")), + v -> { + config.backFaceCulling = v; + minecraft.levelRenderer.allChanged(); + }, + () -> config.backFaceCulling) + .setTooltip(v -> Component.translatable("vulkanmod.options.backfaceCulling.tooltip")) + .setImpact(PerformanceImpact.HIGH), new SwitchOption(Component.translatable("vulkanmod.options.indirectDraw"), - value -> config.indirectDraw = value, - () -> config.indirectDraw) - .setTooltip(Component.translatable("vulkanmod.options.indirectDraw.tooltip")), + v -> config.indirectDraw = v, + () -> config.indirectDraw) + .setTooltip(v -> Component.translatable("vulkanmod.options.indirectDraw.tooltip")) + .setImpact(PerformanceImpact.HIGH) }) }; - } public static OptionBlock[] getOtherOpts() { return new OptionBlock[]{ - new OptionBlock("", new Option[]{ + new OptionBlock("", new Option[]{ new RangeOption(Component.translatable("vulkanmod.options.builderThreads"), - 0, (Runtime.getRuntime().availableProcessors() - 1), 1, - value -> { - config.builderThreads = value; - WorldRenderer.getInstance().getTaskDispatcher().createThreads(value); - }, - () -> config.builderThreads) - .setTranslator(value -> { - if (value == 0) - return Component.translatable("vulkanmod.options.builderThreads.auto"); - else - return Component.nullToEmpty(String.valueOf(value)); - }), + 0, Runtime.getRuntime().availableProcessors() - 1, 1, + value -> { + config.builderThreads = value; + WorldRenderer.getInstance().getTaskDispatcher().createThreads(value); + }, + () -> config.builderThreads) + .setTranslator(v -> v == 0 + ? Component.translatable("vulkanmod.options.builderThreads.auto") + : Component.literal(String.valueOf(v))), new RangeOption(Component.translatable("vulkanmod.options.frameQueue"), - 2, 5, 1, - value -> { - config.frameQueueSize = value; - Renderer.scheduleSwapChainUpdate(); - }, () -> config.frameQueueSize) - .setTooltip(Component.translatable("vulkanmod.options.frameQueue.tooltip")), + 2, 5, 1, + value -> { + config.frameQueueSize = value; + Renderer.scheduleSwapChainUpdate(); + }, + () -> config.frameQueueSize) + .setTooltip(v -> Component.translatable("vulkanmod.options.frameQueue.tooltip")), new SwitchOption(Component.translatable("vulkanmod.options.textureAnimations"), - value -> { - config.textureAnimations = value; - }, - () -> config.textureAnimations), + v -> config.textureAnimations = v, + () -> config.textureAnimations) }), - new OptionBlock("", new Option[]{ + new OptionBlock("", new Option[]{ new CyclingOption<>(Component.translatable("vulkanmod.options.deviceSelector"), - IntStream.range(-1, DeviceManager.suitableDevices.size()).boxed() - .toArray(Integer[]::new), - value -> config.device = value, - () -> config.device) - .setTranslator(value -> Component.translatable((value == -1) - ? "vulkanmod.options.deviceSelector.auto" - : DeviceManager.suitableDevices.get( - value).deviceName) - ) - .setTooltip(Component.nullToEmpty("%s: %s".formatted( - Component.translatable("vulkanmod.options.deviceSelector.tooltip").getString(), - DeviceManager.device.deviceName))) + IntStream.range(-1, DeviceManager.suitableDevices.size()) + .boxed() + .toArray(Integer[]::new), + value -> config.device = value, + () -> config.device) + .setTranslator(v -> Component.translatable( + v == -1 ? "vulkanmod.options.deviceSelector.auto" + : DeviceManager.suitableDevices.get(v).deviceName)) + .setTooltip(v -> Component.literal( + Component.translatable("vulkanmod.options.deviceSelector.tooltip").getString() + ": " + + DeviceManager.device.deviceName)) }) }; - } -} +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/option/Page.java b/src/main/java/net/vulkanmod/config/option/Page.java new file mode 100644 index 0000000000..188b88462e --- /dev/null +++ b/src/main/java/net/vulkanmod/config/option/Page.java @@ -0,0 +1,50 @@ +package net.vulkanmod.config.option; + +import net.minecraft.network.chat.Component; +import net.vulkanmod.config.gui.OptionBlock; + +import java.util.ArrayList; +import java.util.List; + +public class Page { + private final String name; + private final List blocks = new ArrayList<>(); + + private Page(String name) { + this.name = name; + } + + public static Page of(String name) { + return new Page(name); + } + + public Block block(String title) { + Block block = new Block(title, this); + blocks.add(block); + return block; + } + + public static class Block { + private final String title; + private final List> options = new ArrayList<>(); + private final Page parent; + + private Block(String title, Page parent) { + this.title = title; + this.parent = parent; + } + + public Block add(Option option) { + options.add(option); + return this; + } + + public Page done() { + return parent; + } + + private OptionBlock build() { + return new OptionBlock(title, options.toArray(new Option[0])); + } + } +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/option/PerformanceImpact.java b/src/main/java/net/vulkanmod/config/option/PerformanceImpact.java new file mode 100644 index 0000000000..72d7cc4e9b --- /dev/null +++ b/src/main/java/net/vulkanmod/config/option/PerformanceImpact.java @@ -0,0 +1,20 @@ +package net.vulkanmod.config.option; + +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; + +public enum PerformanceImpact { + LOW(Component.translatable("vulkanmod.options.performanceImpact.low").withStyle(ChatFormatting.DARK_GREEN)), + MEDIUM(Component.translatable("vulkanmod.options.performanceImpact.medium").withStyle(ChatFormatting.YELLOW)), + HIGH(Component.translatable("vulkanmod.options.performanceImpact.high").withStyle(ChatFormatting.RED)); + + private final Component component; + + PerformanceImpact(Component component) { + this.component = component; + } + + public Component component() { + return this.component; + } +} diff --git a/src/main/java/net/vulkanmod/config/option/RangeOption.java b/src/main/java/net/vulkanmod/config/option/RangeOption.java index 89d5f03557..7835d8d2f1 100644 --- a/src/main/java/net/vulkanmod/config/option/RangeOption.java +++ b/src/main/java/net/vulkanmod/config/option/RangeOption.java @@ -13,20 +13,24 @@ public class RangeOption extends Option { int min; int max; int step; + float scaledNewValue; public RangeOption(Component name, int min, int max, int step, Function translator, Consumer setter, Supplier getter) { super(name, setter, getter, translator); this.min = min; this.max = max; this.step = step; + this.scaledNewValue = computeScaledValue(this.newValue); } public RangeOption(Component name, int min, int max, int step, Consumer setter, Supplier getter) { this(name, min, max, step, (i) -> Component.literal(String.valueOf(i)), setter, getter); } - public OptionWidget createWidget() { - return new RangeOptionWidget(this, this.name); + protected OptionWidget createWidget() { + var widget = new RangeOptionWidget(this, this.name); + this.widget = widget; + return widget; } public Component getName() { @@ -34,16 +38,28 @@ public Component getName() { } public float getScaledValue() { - float value = this.getNewValue(); - - return (value - this.min) / (this.max - this.min); + return this.scaledNewValue; } - public void setValue(float f) { + public void setNewValueFromScaledFloat(float f) { double n = Mth.lerp(f, min, max); n = this.step * Math.round(n / this.step); this.setNewValue((int) n); } + + public void setNewValue(Integer newValue) { + super.setNewValue(newValue); + + this.scaledNewValue = computeScaledValue(this.newValue); + } + + public float getScaledNewValue() { + return scaledNewValue; + } + + private float computeScaledValue(float value) { + return (value - this.min) / (this.max - this.min); + } } diff --git a/src/main/java/net/vulkanmod/config/option/SwitchOption.java b/src/main/java/net/vulkanmod/config/option/SwitchOption.java index 455810d83b..f3ea2c1b32 100644 --- a/src/main/java/net/vulkanmod/config/option/SwitchOption.java +++ b/src/main/java/net/vulkanmod/config/option/SwitchOption.java @@ -13,8 +13,9 @@ public SwitchOption(Component name, Consumer setter, Supplier } @Override - public OptionWidget createWidget() { - return new SwitchOptionWidget(this, this.name); + protected OptionWidget createWidget() { + var widget = new SwitchOptionWidget(this, this.name); + this.widget = widget; + return widget; } - } diff --git a/src/main/java/net/vulkanmod/config/video/VideoMode.java b/src/main/java/net/vulkanmod/config/video/VideoMode.java new file mode 100644 index 0000000000..f31f38398c --- /dev/null +++ b/src/main/java/net/vulkanmod/config/video/VideoMode.java @@ -0,0 +1,15 @@ +package net.vulkanmod.config.video; + +import org.jetbrains.annotations.NotNull; + +public record VideoMode(int width, int height, int bitDepth, int refreshRate) { + + @Override + public @NotNull String toString() { + return width + "×" + height + (refreshRate > 0 ? " @ " + refreshRate + "Hz" : ""); + } + + public VideoMode withRefreshRate(int newRate) { + return new VideoMode(width, height, bitDepth, newRate); + } +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/config/video/VideoModeSet.java b/src/main/java/net/vulkanmod/config/video/VideoModeSet.java index e4fb34fac3..c0322295fb 100644 --- a/src/main/java/net/vulkanmod/config/video/VideoModeSet.java +++ b/src/main/java/net/vulkanmod/config/video/VideoModeSet.java @@ -84,12 +84,12 @@ public VideoMode(int width, int height, int bitDepth, int refreshRate) { @Override public String toString() { return "VideoMode[" + - "width=" + width + ", " + - "height=" + height + ", " + - "bitDepth=" + bitDepth + ", " + - "refreshRate=" + refreshRate + ']'; + "width=" + width + ", " + + "height=" + height + ", " + + "bitDepth=" + bitDepth + ", " + + "refreshRate=" + refreshRate + ']'; } - } + } } diff --git a/src/main/java/net/vulkanmod/mixin/render/GuiRendererMixin.java b/src/main/java/net/vulkanmod/mixin/render/GuiRendererMixin.java index 09e25216ef..6875677a5d 100644 --- a/src/main/java/net/vulkanmod/mixin/render/GuiRendererMixin.java +++ b/src/main/java/net/vulkanmod/mixin/render/GuiRendererMixin.java @@ -10,6 +10,7 @@ import net.minecraft.client.gui.render.state.GuiItemRenderState; import net.minecraft.client.gui.render.state.GuiRenderState; import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.client.renderer.item.TrackingItemStackRenderState; import net.vulkanmod.render.engine.VkRenderPass; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; @@ -25,6 +26,12 @@ public abstract class GuiRendererMixin { @Shadow @Final private GuiRenderState renderState; @Shadow private @Nullable GpuTextureView itemsAtlasView; + // Debug +// @Redirect(method = "method_71055", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/item/TrackingItemStackRenderState;isAnimated()Z")) +// private boolean forceRender(TrackingItemStackRenderState instance) { +// return true; +// } + @Overwrite private void submitBlitFromItemAtlas(GuiItemRenderState guiItemRenderState, float u, float v, int size, int atlasSize) { v = 1.0f - v; diff --git a/src/main/resources/assets/vulkanmod/lang/en_us.json b/src/main/resources/assets/vulkanmod/lang/en_us.json index ec9addfed0..fe308cbbde 100644 --- a/src/main/resources/assets/vulkanmod/lang/en_us.json +++ b/src/main/resources/assets/vulkanmod/lang/en_us.json @@ -6,7 +6,13 @@ "vulkanmod.options.pages.optimizations": "Optimizations", "vulkanmod.options.pages.other": "Other", + "vulkanmod.options.performanceImpact": "Performance impact: %s", + "vulkanmod.options.performanceImpact.low": "Low", + "vulkanmod.options.performanceImpact.medium": "Medium", + "vulkanmod.options.performanceImpact.high": "High", + "vulkanmod.options.buttons.apply": "Apply", + "vulkanmod.options.buttons.undo": "Undo", "vulkanmod.options.buttons.kofi": "Support me", "vulkanmod.options.buttons.update_available": "Update available!", @@ -16,8 +22,8 @@ "vulkanmod.options.advCulling.normal": "Normal", "vulkanmod.options.advCulling.tooltip": "Use a culling algorithm that might improve performance by reducing the number of non visible chunk sections rendered.", - "vulkanmod.options.ao.subBlock": "ON (Sub-block)", - "vulkanmod.options.ao.subBlock.tooltip": "ON (Sub-block): Enables smooth lighting for non full block (experimental).", + "vulkanmod.options.ao.subBlock": "Sub Block", + "vulkanmod.options.ao.subBlock.tooltip": "Enables smooth lighting for non full block (experimental).", "vulkanmod.options.deviceSelector": "Device selector", "vulkanmod.options.deviceSelector.auto": "Auto", @@ -35,7 +41,7 @@ "vulkanmod.options.indirectDraw": "Indirect Draw", "vulkanmod.options.indirectDraw.tooltip": "Reduces CPU overhead but might increases GPU overhead.", - "vulkanmod.options.refreshRate": "Refresh Rate", + "vulkanmod.options.refreshRate": "Fullscreen Refresh Rate", "vulkanmod.options.uniqueOpaqueLayer": "Unique opaque layer", "vulkanmod.options.uniqueOpaqueLayer.tooltip": "Use a unique render layer for opaque terrain to improve performance.", @@ -47,5 +53,7 @@ "vulkanmod.options.builderThreads": "Chunk Builder Threads", "vulkanmod.options.builderThreads.auto": "Auto", - "vulkanmod.options.textureAnimations": "Texture Animations" + "vulkanmod.options.textureAnimations": "Texture Animations", + + "vulkanmod.options.searchFieldPlaceholder": "Search Graphics Settings" } \ No newline at end of file diff --git a/src/main/resources/assets/vulkanmod/vlogo_transparent.png b/src/main/resources/assets/vulkanmod/vlogo_transparent.png index daef9f5f95..d0a662e406 100644 Binary files a/src/main/resources/assets/vulkanmod/vlogo_transparent.png and b/src/main/resources/assets/vulkanmod/vlogo_transparent.png differ