diff --git a/README.md b/README.md
index 4cb8b3a..db46e55 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,32 @@
-
# DynamicHUD for Minecraft Fabric
DynamicHUD is a special tool for Minecraft mod creators who use Fabric. It works with Minecraft 1.19.1 and newer versions. With DynamicHUD, you can make your own HUD parts that players can change and interact with, making their game look and feel better.
> _It may be ported back upto 1.16 fabric on demand._
+# Examples
+- [_DynamicHUDtest.java_](src/main/java/com/tanishisherewith/dynamichud/DynamicHUDtest.java)
+-
+## Demo
+
+*May vary from version to version*
+
+### Developed stage
+> In progress
+---
+
+### Mid stage (1.2.0)
+
+ View Demo video
+
+ [!Mid stage demo video](https://github.com/V-Fast/DynamicHUD/assets/120117618/2abfcdf5-d786-4e58-acae-aefe51b77b4a)
+
+
+### Early stages
+
+ View Demo video
+
+ [!Early stage demo video](https://github.com/V-Fast/DynamicHUD/assets/120117618/04de9319-69cd-4456-a555-c026c7e053a2)
+
## Features
@@ -66,29 +89,3 @@ DynamicHUD is released under the MIT License. Feel free to use and modify it in
## Support
Need assistance or have suggestions? Join our [Discord](https://discord.com/invite/Rqpn3C7yR5) community or submit an issue on our GitHub [repository](https://github.com/V-Fast/DynamicHUD).
-# Examples
-- [_DynamicHUDtest.java_](src/main/java/com/tanishisherewith/dynamichud/DynamicHUDtest.java)
-
-# [Modrinth](https://modrinth.com/mod/dynamichud)
-
-## A LIBRARY SIMILAR TO THIS WHICH SUPPORTS OLDER MINECRAFT VERSIONS: https://github.com/LaconicLizard/HudElements
-
-# Demo:
-### *May vary from version to version*
-## New Version 1.2.0
-https://github.com/V-Fast/DynamicHUD/assets/120117618/2abfcdf5-d786-4e58-acae-aefe51b77b4a
-
-
-## Old Version
-https://github.com/V-Fast/DynamicHUD/assets/120117618/04de9319-69cd-4456-a555-c026c7e053a2
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build.gradle b/build.gradle
index 8511df6..904421d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id 'fabric-loom' version '1.2-SNAPSHOT'
+ id 'fabric-loom' version '1.3-SNAPSHOT'
id 'maven-publish'
}
@@ -18,7 +18,13 @@ repositories {
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
+ mavenCentral()
+ jcenter()
maven { url "https://maven.terraformersmc.com/releases/" }
+ maven {
+ name 'Xander Maven'
+ url 'https://maven.isxander.dev/releases'
+ }
}
dependencies {
@@ -28,7 +34,9 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
- modApi "com.terraformersmc:modmenu:7.1.0"
+ modImplementation "dev.isxander.yacl:yet-another-config-lib-fabric:${project.yacl_version}"
+
+ modApi "com.terraformersmc:modmenu:9.0.0"
}
processResources {
diff --git a/gradle.properties b/gradle.properties
index 3a255cd..6f22580 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,16 +1,17 @@
-# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx3G
+org.gradle.parallel=true
# Fabric Properties
- minecraft_version=1.20.1
- yarn_mappings=1.20.1+build.1
- loader_version=0.14.21
+# check these on https://fabricmc.net/develop
+ minecraft_version=1.20.4
+ yarn_mappings=1.20.4+build.1
+ loader_version=0.15.0
# Mod Properties
- mod_version = 1.2.0
+ mod_version = 2.0.0
maven_group = com.tanishisherewith
archives_base_name = dynamichud
# Dependencies
- # check this on https://modmuss50.me/fabric.html
- fabric_version=0.83.1+1.20.1
+ fabric_version=0.91.1+1.20.4
+ yacl_version=3.3.2+1.20.4
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 37aef8d..3499ded 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java
index 6f43839..84166ea 100644
--- a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java
+++ b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java
@@ -1,109 +1,48 @@
package com.tanishisherewith.dynamichud;
-import com.tanishisherewith.dynamichud.huds.AbstractMoveableScreen;
-import com.tanishisherewith.dynamichud.interfaces.IWigdets;
-import com.tanishisherewith.dynamichud.util.DynamicUtil;
-import net.fabricmc.api.ModInitializer;
+import com.tanishisherewith.dynamichud.config.GlobalConfig;
+import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen;
+import com.tanishisherewith.dynamichud.widget.Widget;
+import com.tanishisherewith.dynamichud.widget.WidgetManager;
+import com.tanishisherewith.dynamichud.widget.WidgetRenderer;
+import com.tanishisherewith.dynamichud.widgets.TextWidget;
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
-import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.FabricLoader;
+import net.fabricmc.loader.api.metadata.ModMetadata;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.KeyBinding;
-import net.minecraft.client.util.InputUtil;
-import net.minecraft.resource.LifecycledResourceManager;
-import net.minecraft.server.MinecraftServer;
-import org.lwjgl.glfw.GLFW;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
-public class DynamicHUD implements ModInitializer {
-
- private static final Logger logger = LoggerFactory.getLogger("DynamicHud");
- static AbstractMoveableScreen Screen;
- private static String keybingCategory = "DynamicHud";
- private static String TranslationKey = "DynamicHud Editor Screen";
- private static InputUtil.Type inputType = InputUtil.Type.KEYSYM;
- private static int key = GLFW.GLFW_KEY_RIGHT_SHIFT;
- public static final KeyBinding EditorScreenKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
- TranslationKey,
- inputType,
- key,
- keybingCategory
- ));
- private static String filename = "widgets.nbt";
- private static File fileDirectory = FabricLoader.getInstance().getConfigDir().toFile();
- public static final File WIDGETS_FILE = new File(fileDirectory, filename);
- private static DynamicUtil dynamicutil;
- private static IWigdets iWigdets;
- MinecraftClient mc = MinecraftClient.getInstance();
-
- public static File getFileDirectory() {
- return fileDirectory;
- }
-
- public static String getFilename() {
- return filename;
- }
-
- public static String getTranslationKey() {
- return TranslationKey;
- }
-
- public static String getKeybingCategory() {
- return keybingCategory;
- }
-
- public static InputUtil.Type getInputType() {
- return inputType;
- }
-
- public static void setInputType(InputUtil.Type inputType) {
- DynamicHUD.inputType = inputType;
- }
-
- public static void setKeyBindKey(int key) {
- DynamicHUD.key = key;
- }
-
- public static void setKeybingCategory(String keybingCategory) {
- DynamicHUD.keybingCategory = keybingCategory;
- }
-
- public static void setTranslationKey(String translationKey) {
- TranslationKey = translationKey;
- }
+public class DynamicHUD implements ClientModInitializer {
+ /**
+ * This is a map to store the list of widgets for each widget file to be saved.
+ *
+ * Allows saving widgets across different mods with same save file name.
+ */
+ public static final HashMap> FILE_MAP = new HashMap<>();
+ public static final Logger logger = LoggerFactory.getLogger("DynamicHud");
+ private static final List widgetRenderers = new ArrayList<>();
+ public static MinecraftClient MC = MinecraftClient.getInstance();
+ public static String MOD_ID = "dynamichud";
- public static void setFilename(String filename) {
- DynamicHUD.filename = filename;
+ public static void addWidgetRenderer(WidgetRenderer widgetRenderer) {
+ widgetRenderers.add(widgetRenderer);
}
- public static void setFileDirectory(File fileDirectory) {
- DynamicHUD.fileDirectory = fileDirectory;
- }
-
- public static void setAbstractScreen(AbstractMoveableScreen screen) {
- Screen = screen;
- }
-
- public static AbstractMoveableScreen getScreen() {
- return Screen;
- }
-
- public static DynamicUtil getDynamicUtil() {
- return dynamicutil;
- }
-
- public static IWigdets getIWigdets() {
- return iWigdets;
- }
-
- public static void setIWigdets(IWigdets iWigdets) {
- DynamicHUD.iWigdets = iWigdets;
+ public static List getWidgetRenderers() {
+ return widgetRenderers;
}
public static void printInfo(String msg) {
@@ -114,48 +53,125 @@ public static void printWarn(String msg) {
logger.warn(msg);
}
+ /**
+ * Opens the MovableScreen when the specified key is pressed.
+ *
+ * @param key The key to listen for
+ * @param screen The AbstractMoveableScreen instance to use to set the screen
+ */
+ public static void openDynamicScreen(KeyBinding key, AbstractMoveableScreen screen) {
+ if (key.wasPressed()) {
+ MC.setScreen(screen);
+ }
+ }
+
@Override
- public void onInitialize() {
- dynamicutil = new DynamicUtil(mc);
- printInfo("DynamicHud Initialised");
-
- //Save and Load
- ClientTickEvents.START_CLIENT_TICK.register(server -> {
- if (iWigdets != null) {
- if (!WIDGETS_FILE.exists()) {
- if (!dynamicutil.WidgetAdded) {
- iWigdets.addWigdets(dynamicutil);
- }
- if (!dynamicutil.MainMenuWidgetAdded) {
- iWigdets.addMainMenuWigdets(dynamicutil);
+ public void onInitializeClient() {
+ printInfo("Initialising DynamicHud");
+
+ // Add WidgetData of included widgets
+ WidgetManager.registerCustomWidgets(
+ TextWidget.DATA
+ );
+
+ //YACL load
+ GlobalConfig.HANDLER.load();
+
+ printInfo("Integrating mods...");
+ FabricLoader.getInstance()
+ .getEntrypointContainers("dynamicHud", DynamicHudIntegration.class)
+ .forEach(entrypoint -> {
+ ModMetadata metadata = entrypoint.getProvider().getMetadata();
+ String modId = metadata.getId();
+ printInfo(String.format("Supported mod with id %s was found!", modId));
+ AbstractMoveableScreen screen;
+ KeyBinding binding;
+ WidgetRenderer widgetRenderer;
+ File widgetsFile;
+ try {
+ DynamicHudIntegration DHIntegration = entrypoint.getEntrypoint();
+
+ //Calls the init method
+ DHIntegration.init();
+
+ //Gets the widget file to save and load the widgets from
+ widgetsFile = DHIntegration.getWidgetsFile();
+
+ // Adds / loads widgets from file
+ if (widgetsFile.exists()) {
+ WidgetManager.loadWidgets(widgetsFile);
+ } else {
+ DHIntegration.addWidgets();
+ }
+
+ //Calls the second init method
+ DHIntegration.initAfter();
+
+ // Get the instance of AbstractMoveableScreen
+ screen = DHIntegration.getMovableScreen();
+
+ // Get the keybind to open the screen instance
+ binding = DHIntegration.getKeyBind();
+
+ //Register custom widget datas by WidgetManager.registerCustomWidgets();
+ DHIntegration.registerCustomWidgets();
+
+ //WidgetRenderer with widgets instance
+ widgetRenderer = DHIntegration.getWidgetRenderer();
+ addWidgetRenderer(widgetRenderer);
+
+ List widgets = FILE_MAP.get(widgetsFile.getName());
+
+ if (widgets == null || widgets.isEmpty()) {
+ FILE_MAP.put(widgetsFile.getName(), widgetRenderer.getWidgets());
+ } else {
+ widgets.addAll(widgetRenderer.getWidgets());
+ FILE_MAP.put(widgetsFile.getName(), widgets);
+ }
+
+ //Register events for rendering, saving, loading, and opening the hudEditor
+ ClientTickEvents.START_CLIENT_TICK.register((client) -> openDynamicScreen(binding, screen));
+
+ /* === Saving === */
+
+ //When a player exits a world (SinglePlayer worlds) or a server stops
+ ServerLifecycleEvents.SERVER_STOPPING.register(server -> saveWidgetsSafely(widgetsFile, FILE_MAP.get(widgetsFile.getName())));
+
+ // When a resource pack is reloaded.
+ ServerLifecycleEvents.END_DATA_PACK_RELOAD.register((server, resourceManager, s) -> saveWidgetsSafely(widgetsFile, FILE_MAP.get(widgetsFile.getName())));
+
+ //When player disconnects
+ ServerPlayConnectionEvents.DISCONNECT.register((handler, packetSender) -> saveWidgetsSafely(widgetsFile, FILE_MAP.get(widgetsFile.getName())));
+
+ //When minecraft closes
+ ClientLifecycleEvents.CLIENT_STOPPING.register((minecraftClient) -> saveWidgetsSafely(widgetsFile, FILE_MAP.get(widgetsFile.getName())));
+
+ printInfo(String.format("Integration of mod %s was successful", modId));
+ } catch (Throwable e) {
+ if (e instanceof IOException) {
+ logger.warn("An error has occurred while loading widgets of mod {}", modId, e);
+ } else {
+ logger.warn("Mod {} has incorrect implementation of DynamicHUD", modId, e);
+ }
}
- }
-
- if (WIDGETS_FILE.exists() && !dynamicutil.WidgetLoaded) {
- iWigdets.loadWigdets(dynamicutil);
- printInfo("Widgets loaded");
- File FileDirectory = new File(fileDirectory, filename);
- printInfo("Load file Directory: " + FileDirectory);
- }
- }
- DynamicUtil.openDynamicScreen(EditorScreenKeyBinding, Screen);
- });
-
- //RenderCallBack
- HudRenderCallback.EVENT.register((drawContext, tickDelta) -> dynamicutil.render(drawContext, tickDelta));
-
- // Save during exiting a world, server or Minecraft itself
- ServerLifecycleEvents.SERVER_STOPPING.register(this::onServerStopping);
- ServerLifecycleEvents.END_DATA_PACK_RELOAD.register(this::onEndDataPackReload);
- ServerPlayConnectionEvents.DISCONNECT.register((handler, packetSender) -> dynamicutil.getWidgetManager().saveWidgets(WIDGETS_FILE));
- Runtime.getRuntime().addShutdownHook(new Thread(() -> dynamicutil.getWidgetManager().saveWidgets(WIDGETS_FILE)));
- }
+ });
+
+ ServerLifecycleEvents.SERVER_STOPPING.register(server -> GlobalConfig.HANDLER.save());
+ ServerLifecycleEvents.END_DATA_PACK_RELOAD.register((server, resourceManager, s) -> GlobalConfig.HANDLER.save());
+ ServerPlayConnectionEvents.DISCONNECT.register((handler, packetSender) -> GlobalConfig.HANDLER.save());
+ ClientLifecycleEvents.CLIENT_STOPPING.register((minecraftClient) -> GlobalConfig.HANDLER.save());
- private void onEndDataPackReload(MinecraftServer server, LifecycledResourceManager lifecycledResourceManager, boolean b) {
- dynamicutil.getWidgetManager().saveWidgets(WIDGETS_FILE);
+
+ HudRenderCallback.EVENT.register(new HudRender());
}
- private void onServerStopping(MinecraftServer server) {
- dynamicutil.getWidgetManager().saveWidgets(WIDGETS_FILE);
+ private void saveWidgetsSafely(File widgetsFile, List widgets) {
+ try {
+ WidgetManager.saveWidgets(widgetsFile, widgets);
+ } catch (IOException e) {
+ logger.error("Failed to save widgets. Widgets passed: {}", widgets);
+ throw new RuntimeException(e);
+ }
}
+
}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUDtest.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUDtest.java
deleted file mode 100644
index d606440..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUDtest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package com.tanishisherewith.dynamichud;
-
-import com.tanishisherewith.dynamichud.helpers.TextureHelper;
-import com.tanishisherewith.dynamichud.huds.MoveableScreen;
-import com.tanishisherewith.dynamichud.interfaces.IWigdets;
-import com.tanishisherewith.dynamichud.interfaces.WidgetLoading;
-import com.tanishisherewith.dynamichud.util.DynamicUtil;
-import com.tanishisherewith.dynamichud.widget.Widget;
-import com.tanishisherewith.dynamichud.widget.armor.ArmorWidget;
-import com.tanishisherewith.dynamichud.widget.item.ItemWidget;
-import com.tanishisherewith.dynamichud.widget.text.TextWidget;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.entity.EquipmentSlot;
-import net.minecraft.item.Items;
-import net.fabricmc.api.ClientModInitializer;
-import net.minecraft.nbt.NbtCompound;
-import net.minecraft.text.Text;
-
-import java.awt.*;
-import java.util.HashSet;
-import java.util.Set;
-
-import static com.tanishisherewith.dynamichud.DynamicHUD.WIDGETS_FILE;
-import static com.tanishisherewith.dynamichud.DynamicHUD.printInfo;
-
-public class DynamicHUDtest implements ClientModInitializer, IWigdets, WidgetLoading {
- protected Set widgets = new HashSet<>();
- protected Set MainMenuwidgets = new HashSet<>();
- MinecraftClient mc = MinecraftClient.getInstance();
- private DynamicUtil dynamicutil;
-
-
- @Override
- public void onInitializeClient() {
- dynamicutil = DynamicHUD.getDynamicUtil();
- widgets.clear();
- MainMenuwidgets.clear();
-
- DynamicHUD.setAbstractScreen(new MoveableScreen(Text.of("Editor Screen"), dynamicutil));
- DynamicHUD.setIWigdets(new DynamicHUDtest());
- dynamicutil.getWidgetManager().setWidgetLoading(new DynamicHUDtest());
- }
-
- @Override
- public void addWigdets(DynamicUtil dynamicUtil) {
- if (mc.player != null) {
- printInfo("Widgets added");
- addTextWidgets(dynamicUtil);
- addArmorWidgets(dynamicUtil);
- addItemWidgets(dynamicUtil);
- dynamicUtil.WidgetAdded = true;
- }
- }
-
- private void addTextWidgets(DynamicUtil dynamicUtil) {
- widgets.add(new TextWidget(mc, "Non Draggable FPS: ", () -> mc.fpsDebugString.split(" ")[0], 0.5f, 0.5f, true, true, -1, -1, true));
- widgets.add(new TextWidget(mc, "Dynamic", () -> "HUD", 0.7f, 0.3f, false, false, -1, -1, true));
- widgets.add(new TextWidget(mc, "Test", () -> "", 0.08f, 0.5f, false, false, -1, -1, true));
- widgets.add(new TextWidget(mc, "", () -> "Data Test", 0.4f, 0.8f, false, false, -1, -1, true));
- widgets.add(new TextWidget(mc, "HUD Test ", () -> "", 0.83f, 0.8f, false, false, -1, -1, true));
-
- for (Widget widget : widgets) {
- if (widget instanceof TextWidget textWidget) {
- if (textWidget.getText().equalsIgnoreCase("Non Draggable FPS: ")) {
- textWidget.setDraggable(false);
- }
- }
- dynamicUtil.getWidgetManager().addWidget(widget);
- }
- }
-
- private void addArmorWidgets(DynamicUtil dynamicUtil) {
- String text = "Text";
- widgets.add(new ArmorWidget(mc, EquipmentSlot.CHEST, 0.01f, 0.01f, true,
- TextureHelper.Position.ABOVE,
- () -> text,
- () -> Color.RED,
- true,
- "Text"));
- widgets.add(new ArmorWidget(mc,
- EquipmentSlot.LEGS,
- 0.05f,
- 0.01f,
- true,
- TextureHelper.Position.LEFT,
- () -> String.valueOf(MinecraftClient.getInstance().getCurrentFps()),
- () -> Color.WHITE,
- true,
- "FPS"));
-
- for (Widget widget : widgets) {
- if (widget instanceof ArmorWidget armorWidget) {
- dynamicUtil.getWidgetManager().addWidget(armorWidget);
- }
- }
- }
-
- private void addItemWidgets(DynamicUtil dynamicUtil) {
- widgets.add(new ItemWidget(mc,
- Items.DIAMOND_AXE::getDefaultStack,
- 0.15f,
- 0.15f,
- true,
- TextureHelper.Position.ABOVE,
- () -> "Label",
- () -> Color.RED,
- true,
- "Label"));
-
- for (Widget widgetItem : widgets) {
- if (widgetItem instanceof ItemWidget itemWidgetItem) {
- dynamicUtil.getWidgetManager().addWidget(itemWidgetItem);
- }
- }
- }
-
-
- @Override
- public void addMainMenuWigdets(DynamicUtil dynamicUtil) {
- printInfo("MainMenu Widgets added");
-
- MainMenuwidgets.add(new TextWidget(mc, "Test ", () -> "", 0.83f, 0.8f, false, false, -1, -1, true));
- MainMenuwidgets.add(new TextWidget(mc, "E Test ", () -> "", 0.85f, 0.3f, false, false, -1, -1, true));
- MainMenuwidgets.add(new TextWidget(mc, "Non Draggable FPS: ", () -> String.valueOf(mc.getCurrentFps()), 0.67f, 0.5f, false, false, -1, -1, true));
- for (Widget mmwigdet : MainMenuwidgets) {
- if (mmwigdet instanceof TextWidget textWidget) {
- if (textWidget.getText().equalsIgnoreCase("Non Draggable FPS: ")) {
- textWidget.setDraggable(false);
- }
- }
- dynamicUtil.getWidgetManager().addMainMenuWidget(mmwigdet);
- }
- dynamicUtil.MainMenuWidgetAdded = true;
- }
-
- @Override
- public void loadWigdets(DynamicUtil dynamicUtil) {
- Set widgets = dynamicUtil.getWidgetManager().loadWigdets(WIDGETS_FILE);
- Set MainMenuWidget = dynamicUtil.getWidgetManager().loadMainMenuWigdets(WIDGETS_FILE);
-
- Widget.addTextGenerator("Non Draggable FPS: ", () -> String.valueOf(mc.getCurrentFps()));
- Widget.addTextGenerator("Dynamic", () -> "HUD");
- Widget.addTextGenerator("Test", () -> "");
- Widget.addTextGenerator("", () -> "Data Test");
- Widget.addTextGenerator("HUD Test ", () -> "");
- Widget.addTextGenerator("Text", () -> "Text");
- Widget.addTextGenerator("Test ", () -> String.valueOf(mc.getCurrentFps()));
- Widget.addTextGenerator("Non Draggable FPS: ", () -> String.valueOf(mc.getCurrentFps()));
- Widget.addTextGenerator("Label", () -> "Label");
-
- for (Widget widget : widgets) {
- dynamicUtil.getWidgetManager().addWidget(widget);
- }
-
- for (Widget widgetItem : MainMenuWidget) {
- dynamicUtil.getWidgetManager().addMainMenuWidget(widgetItem);
- }
-
- dynamicUtil.WidgetLoaded = true;
- }
-
-
- @Override
- public Widget loadWidgetsFromTag(String className, NbtCompound widgetTag) {
- //SAMPLE CODE EXAMPLE :
- /*if (className.equals(ItemWidget.class.getName())) {
- ItemWidget widget = new ItemWidget(MinecraftClient.getInstance(), ItemStack.EMPTY, 0, 0, true, TextureHelper.Position.ABOVE, () -> "", Color.BLUE);
- widget.readFromTag(widgetTag);
- return widget;
- }*/
- System.out.println("widget tag loaded");
- return WidgetLoading.super.loadWidgetsFromTag(className, widgetTag);
- }
-}
-
-
-
diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHudIntegration.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHudIntegration.java
new file mode 100644
index 0000000..d8959f7
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/DynamicHudIntegration.java
@@ -0,0 +1,134 @@
+package com.tanishisherewith.dynamichud;
+
+import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen;
+import com.tanishisherewith.dynamichud.widget.WidgetData;
+import com.tanishisherewith.dynamichud.widget.WidgetManager;
+import com.tanishisherewith.dynamichud.widget.WidgetRenderer;
+import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
+import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.client.option.KeyBinding;
+import net.minecraft.client.util.InputUtil;
+import org.lwjgl.glfw.GLFW;
+
+import java.io.File;
+
+/**
+ * This interface provides methods for integrating DynamicHud into a mod.
+ */
+public interface DynamicHudIntegration {
+ /**
+ * The category for the key binding.
+ */
+ String KEYBIND_CATEGORY = "DynamicHud";
+
+ /**
+ * The translation key for the editor screen.
+ */
+ String TRANSLATION_KEY = "DynamicHud Editor Screen";
+
+ /**
+ * The input type for the key binding.
+ */
+ InputUtil.Type INPUT_TYPE = InputUtil.Type.KEYSYM;
+
+ /**
+ * The key code for the key binding.
+ */
+ int KEY = GLFW.GLFW_KEY_RIGHT_SHIFT;
+
+ /**
+ * The key binding for opening the editor screen.
+ */
+ KeyBinding EDITOR_SCREEN_KEY_BINDING = KeyBindingHelper.registerKeyBinding(new KeyBinding(
+ "DynamicHud Editor Screen",
+ InputUtil.Type.KEYSYM,
+ GLFW.GLFW_KEY_RIGHT_SHIFT,
+ "DynamicHud"
+ ));
+
+ /**
+ * The filename for the widgets file.
+ */
+ String FILENAME = "widgets.nbt";
+
+ /**
+ * The directory for the widgets file.
+ */
+ File FILE_DIRECTORY = FabricLoader.getInstance().getConfigDir().toFile();
+
+ /**
+ * The file where widgets are saved.
+ */
+ File WIDGETS_FILE = new File(FILE_DIRECTORY, FILENAME);
+
+ /**
+ * Initializes the DynamicHud integration.
+ *
+ * Suggested to be used to initialize {@link com.tanishisherewith.dynamichud.utils.DynamicValueRegistry} and widgets with their respective values
+ *
+ */
+ void init();
+
+ /**
+ * To be used to add widgets using {@link WidgetManager}.
+ */
+ void addWidgets();
+
+ /**
+ * To register custom widgets. This method can be overridden by implementations.
+ *
+ * Use {@link WidgetManager#registerCustomWidget(WidgetData)} to register custom widgets.
+ *
+ */
+ default void registerCustomWidgets() {
+ }
+
+ /**
+ * Performs any necessary initialization after the widgets have been added. This method can be overridden by implementations.
+ *
+ * Suggested to be used to initialize a {@link WidgetRenderer} object with the added widgets.
+ *
+ */
+ default void initAfter() {
+ }
+
+ /**
+ * Returns the file where widgets are to be saved and loaded from.
+ *
+ * @return The widgets file.
+ */
+ default File getWidgetsFile() {
+ return WIDGETS_FILE;
+ }
+
+ /**
+ * Returns the keybind to open the {@link AbstractMoveableScreen} instance.
+ *
+ * @return The keybind.
+ */
+ default KeyBinding getKeyBind() {
+ return EDITOR_SCREEN_KEY_BINDING;
+ }
+
+ /**
+ * Returns the movable screen for the DynamicHud.
+ *
+ * @return The movable screen.
+ */
+ AbstractMoveableScreen getMovableScreen();
+
+ /**
+ * To return a {@link WidgetRenderer} object.
+ * By default, it returns a widget renderer consisting of all widgets in the {@link WidgetManager}
+ *
+ * @return The widget renderer.
+ */
+ default WidgetRenderer getWidgetRenderer() {
+ return new WidgetRenderer(WidgetManager.getWidgets());
+ }
+}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHudTest.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHudTest.java
new file mode 100644
index 0000000..6f1b2f4
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/DynamicHudTest.java
@@ -0,0 +1,98 @@
+package com.tanishisherewith.dynamichud;
+
+import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen;
+import com.tanishisherewith.dynamichud.utils.DynamicValueRegistry;
+import com.tanishisherewith.dynamichud.widget.Widget;
+import com.tanishisherewith.dynamichud.widget.WidgetManager;
+import com.tanishisherewith.dynamichud.widget.WidgetRenderer;
+import com.tanishisherewith.dynamichud.widgets.TextWidget;
+import net.minecraft.client.gui.screen.TitleScreen;
+import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
+import net.minecraft.text.Text;
+
+import java.util.List;
+
+public class DynamicHudTest implements DynamicHudIntegration {
+ TextWidget FPSWidget;
+ TextWidget HelloWidget;
+ TextWidget DynamicHUDWidget;
+ DynamicValueRegistry registry;
+ WidgetRenderer renderer;
+
+ @Override
+ public void init() {
+ //Global registry
+ DynamicValueRegistry.registerGlobal("FPS", () -> "FPS: " + DynamicHUD.MC.getCurrentFps());
+
+ //Local registry
+ registry = new DynamicValueRegistry(DynamicHUD.MOD_ID);
+ registry.registerLocal("Hello", () -> "Hello!");
+ registry.registerLocal("DynamicHUD", () -> "DynamicHUD");
+
+
+ FPSWidget = new TextWidget.Builder()
+ .setX(250)
+ .setY(100)
+ .setDraggable(true)
+ .rainbow(false)
+ .setDRKey("FPS")
+ .setModID(DynamicHUD.MOD_ID)
+ .shouldScale(false)
+ .build();
+
+ HelloWidget = new TextWidget.Builder()
+ .setX(200)
+ .setY(100)
+ .setDraggable(true)
+ .rainbow(false)
+ .setDRKey("Hello")
+ .setDVR(registry)
+ .setModID(DynamicHUD.MOD_ID)
+ .shouldScale(true)
+ .build();
+
+ DynamicHUDWidget = new TextWidget.Builder()
+ .setX(5)
+ .setY(5)
+ .setDraggable(false)
+ .rainbow(true)
+ .setDRKey("DynamicHUD")
+ .setDVR(registry)
+ .setModID(DynamicHUD.MOD_ID)
+ .shouldScale(true)
+ .build();
+
+ }
+
+ @Override
+ public void addWidgets() {
+ WidgetManager.addWidget(FPSWidget);
+ WidgetManager.addWidget(HelloWidget);
+ WidgetManager.addWidget(DynamicHUDWidget);
+ }
+
+ @Override
+ public void registerCustomWidgets() {
+ //WidgetManager.addWidgetData(MyWidget.DATA);
+ }
+
+ public void initAfter() {
+ List widgets = WidgetManager.getWidgetsForMod(DynamicHUD.MOD_ID);
+
+ renderer = new WidgetRenderer(widgets);
+ renderer.shouldRenderInGameHud(true);
+ renderer.addScreen(TitleScreen.class);
+ }
+
+ @Override
+ public AbstractMoveableScreen getMovableScreen() {
+ return new AbstractMoveableScreen(Text.literal("Editor Screen"), renderer) {
+ };
+ }
+
+ @Override
+ public WidgetRenderer getWidgetRenderer() {
+ return renderer;
+ }
+
+}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/HudRender.java b/src/main/java/com/tanishisherewith/dynamichud/HudRender.java
new file mode 100644
index 0000000..b4e301e
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/HudRender.java
@@ -0,0 +1,18 @@
+package com.tanishisherewith.dynamichud;
+
+import com.tanishisherewith.dynamichud.widget.WidgetRenderer;
+import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
+import net.minecraft.client.gui.DrawContext;
+
+/**
+ * Using the fabric event {@link HudRenderCallback} to render widgets in the game HUD.
+ * Mouse positions are passed in the negatives even though theoretically it's in the centre of the screen.
+ */
+public class HudRender implements HudRenderCallback {
+ @Override
+ public void onHudRender(DrawContext drawContext, float tickDelta) {
+ for (WidgetRenderer widgetRenderer : DynamicHUD.getWidgetRenderers()) {
+ widgetRenderer.renderWidgets(drawContext, -120, -120);
+ }
+ }
+}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java b/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java
index 07cb3aa..30fffb4 100644
--- a/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java
+++ b/src/main/java/com/tanishisherewith/dynamichud/ModMenuIntegration.java
@@ -1,11 +1,16 @@
package com.tanishisherewith.dynamichud;
+import com.tanishisherewith.dynamichud.config.GlobalConfig;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
+import net.minecraft.client.gui.screen.Screen;
+
public class ModMenuIntegration implements ModMenuApi {
+ public static Screen YACL_CONFIG_SCREEN = GlobalConfig.get().createYACLGUI();
+
@Override
public ConfigScreenFactory> getModConfigScreenFactory() {
- return parent -> DynamicHUD.getScreen();
+ return parent -> YACL_CONFIG_SCREEN;
}
}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java
new file mode 100644
index 0000000..7c34869
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java
@@ -0,0 +1,55 @@
+package com.tanishisherewith.dynamichud.config;
+
+import dev.isxander.yacl3.api.*;
+import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder;
+import dev.isxander.yacl3.config.v2.api.ConfigClassHandler;
+import dev.isxander.yacl3.config.v2.api.SerialEntry;
+import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder;
+import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+
+public class GlobalConfig {
+ public static final ConfigClassHandler HANDLER = ConfigClassHandler.createBuilder(GlobalConfig.class)
+ .id(new Identifier("dynamichud", "dynamichud_config"))
+ .serializer(config -> GsonConfigSerializerBuilder.create(config)
+ .setPath(FabricLoader.getInstance().getConfigDir().resolve("dynamichud.json5"))
+ .setJson5(true)
+ .build())
+ .build();
+ private static final GlobalConfig INSTANCE = new GlobalConfig();
+ /**
+ * Common scale for all widgets. Set by the user using YACL.
+ */
+ @SerialEntry
+ private float scale = 1.0f;
+
+ public static GlobalConfig get() {
+ return INSTANCE;
+ }
+
+ public final Screen createYACLGUI() {
+ return YetAnotherConfigLib.createBuilder()
+ .title(Text.literal("DynamicHUD config screen."))
+ .category(ConfigCategory.createBuilder()
+ .name(Text.literal("General"))
+ .tooltip(Text.literal("Set the general settings for all widgets."))
+ .group(OptionGroup.createBuilder()
+ .name(Text.literal("Global"))
+ .description(OptionDescription.of(Text.literal("Global settings for all widgets.")))
+ .option(Option.createBuilder()
+ .name(Text.literal("Scale"))
+ .description(OptionDescription.of(Text.literal("Set scale for all widgets.")))
+ .binding(1.0f, () -> this.scale, newVal -> this.scale = newVal)
+ .controller(floatOption -> FloatSliderControllerBuilder.create(floatOption).range(0.1f, 2.5f).step(0.1f))
+ .build())
+ .build())
+ .build())
+ .build()
+ .generateScreen(null);
+ }
+ public float getScale(){
+ return scale;
+ }
+}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/handlers/DefaultDragHandler.java b/src/main/java/com/tanishisherewith/dynamichud/handlers/DefaultDragHandler.java
deleted file mode 100644
index 02e77db..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/handlers/DefaultDragHandler.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.tanishisherewith.dynamichud.handlers;
-
-import com.tanishisherewith.dynamichud.widget.Widget;
-
-public class DefaultDragHandler implements DragHandler {
- private int dragStartX = 0;
- private int dragStartY = 0;
-
- @Override
- public boolean startDragging(Widget widget, double mouseX, double mouseY) {
- if (widget.getWidgetBox().contains(widget, mouseX, mouseY, Widget.getScale())) {
- dragStartX = (int) (mouseX - widget.getX());
- dragStartY = (int) (mouseY - widget.getY());
- return true;
- }
- return false;
- }
-
- @Override
- public void updateDragging(Widget widget, double mouseX, double mouseY) {
- int newX = (int) (dragStartX + mouseX);
- int newY = (int) (dragStartY + mouseY);
- widget.setX(newX + (newX / 2));
- widget.setY(newY + (newY / 2));
- }
-
- @Override
- public void stopDragging(Widget widget) {
- // Nothing to do here in the default implementation
- }
-}
-
diff --git a/src/main/java/com/tanishisherewith/dynamichud/handlers/DefaultMouseHandler.java b/src/main/java/com/tanishisherewith/dynamichud/handlers/DefaultMouseHandler.java
deleted file mode 100644
index 5a9c03f..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/handlers/DefaultMouseHandler.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.tanishisherewith.dynamichud.handlers;
-
-import com.tanishisherewith.dynamichud.util.colorpicker.ColorGradientPicker;
-import com.tanishisherewith.dynamichud.util.contextmenu.ContextMenu;
-import com.tanishisherewith.dynamichud.widget.slider.SliderWidget;
-import com.tanishisherewith.dynamichud.widget.text.TextWidget;
-
-import java.util.List;
-
-public class DefaultMouseHandler implements MouseHandler {
- private final ColorGradientPicker colorPicker;
- private final List contextMenu;
- private final List sliderWidget;
-
- public DefaultMouseHandler(ColorGradientPicker colorPicker, List contextMenu, List sliderWidget) {
- this.colorPicker = colorPicker;
- this.contextMenu = contextMenu;
- this.sliderWidget = sliderWidget;
- }
-
- @Override
- public boolean mouseClicked(double mouseX, double mouseY, int button) {
- if (contextMenu != null && sliderWidget != null) {
- for (ContextMenu contextMenu : contextMenu) {
- if (contextMenuClicked(mouseX, mouseY, button, contextMenu)) {
- return true;
- }
- }
- for (SliderWidget sliderWidget : sliderWidget) {
- if (sliderClicked(mouseX, mouseY, button, sliderWidget)) {
- return true;
- }
- }
- }
- return colorPickerClicked(mouseX, mouseY, button);
- }
-
- @Override
- public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
- if (sliderWidget != null) {
- for (SliderWidget sliderWidget : sliderWidget) {
- if (sliderWidget != null && sliderWidget.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) {
- return true;
- }
- }
- }
- if (this.colorPicker != null) {
- colorPicker.mouseDragged(mouseX, mouseY, button);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean mouseReleased(double mouseX, double mouseY, int button) {
- if (this.colorPicker != null) {
- colorPicker.mouseReleased(mouseX, mouseY, button);
- return true;
- }
- return false;
- }
-
-
- @Override
- public boolean contextMenuClicked(double mouseX, double mouseY, int button, ContextMenu contextMenu) {
- return contextMenu != null && contextMenu.mouseClicked(mouseX, mouseY, button);
- }
-
- @Override
- public boolean colorPickerClicked(double mouseX, double mouseY, int button) {
- return colorPicker != null && colorPicker.mouseClicked(mouseX, mouseY, button);
- }
-
- @Override
- public boolean sliderClicked(double mouseX, double mouseY, int button, SliderWidget sliderWidget) {
- return sliderWidget != null && sliderWidget.mouseClicked(mouseX, mouseY, button);
- }
-}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/handlers/DragHandler.java b/src/main/java/com/tanishisherewith/dynamichud/handlers/DragHandler.java
deleted file mode 100644
index 8c2c090..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/handlers/DragHandler.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.tanishisherewith.dynamichud.handlers;
-
-import com.tanishisherewith.dynamichud.widget.Widget;
-
-public interface DragHandler {
- boolean startDragging(Widget widget, double mouseX, double mouseY);
-
- void updateDragging(Widget widget, double mouseX, double mouseY);
-
- void stopDragging(Widget widget);
-}
-
diff --git a/src/main/java/com/tanishisherewith/dynamichud/handlers/MouseHandler.java b/src/main/java/com/tanishisherewith/dynamichud/handlers/MouseHandler.java
deleted file mode 100644
index bb587f3..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/handlers/MouseHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.tanishisherewith.dynamichud.handlers;
-
-import com.tanishisherewith.dynamichud.util.contextmenu.ContextMenu;
-import com.tanishisherewith.dynamichud.widget.slider.SliderWidget;
-
-public interface MouseHandler {
- boolean mouseClicked(double mouseX, double mouseY, int button);
-
- boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY);
-
- boolean mouseReleased(double mouseX, double mouseY, int button);
-
- boolean contextMenuClicked(double mouseX, double mouseY, int button, ContextMenu contextMenu);
-
- boolean colorPickerClicked(double mouseX, double mouseY, int button);
-
- boolean sliderClicked(double mouseX, double mouseY, int button, SliderWidget sliderWidget);
-
-
-}
-
diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java
index 2194e4b..b119142 100644
--- a/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java
+++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java
@@ -1,6 +1,5 @@
package com.tanishisherewith.dynamichud.helpers;
-import net.minecraft.network.packet.Packet;
import net.minecraft.util.math.MathHelper;
import java.awt.*;
@@ -10,28 +9,18 @@
*/
public class ColorHelper {
public static int r, g, b, a;
+
public ColorHelper(int r, int g, int b) {
- this.r = r;
- this.g = g;
- this.b = b;
- this.a = 255;
+ ColorHelper.r = r;
+ ColorHelper.g = g;
+ ColorHelper.b = b;
+ a = 255;
validate();
}
+
public ColorHelper() {
}
- public void validate() {
- if (r < 0) r = 0;
- else if (r > 255) r = 255;
-
- if (g < 0) g = 0;
- else if (g > 255) g = 255;
-
- if (b < 0) b = 0;
- else if (b > 255) b = 255;
- if (a < 0) a = 0;
- else if (a > 255) a = 255;
- }
/**
* Returns a color as an integer value given its red, green and blue components.
*
@@ -83,10 +72,10 @@ public static int getColorFromHue(float hue) {
public static int ColorToInt(Color color) {
return color.getRGB();
}
- public static float[] getRainbowColor()
- {
+
+ public static float[] getRainbowColor() {
float x = System.currentTimeMillis() % 2000 / 1000F;
- float pi = (float)Math.PI;
+ float pi = (float) Math.PI;
float[] rainbow = new float[3];
rainbow[0] = 0.5F + 0.5F * MathHelper.sin(x * pi);
@@ -94,6 +83,32 @@ public static float[] getRainbowColor()
rainbow[2] = 0.5F + 0.5F * MathHelper.sin((x + 8F / 3F) * pi);
return rainbow;
}
+
+ /**
+ * Rainbow color with custom speed.
+ *
+ * @param speed
+ * @return Current rainbow color.
+ */
+ public static Color getRainbowColor(int speed) {
+ float hue = (System.currentTimeMillis() % (speed * 100)) / (speed * 100.0f);
+ return Color.getHSBColor(hue, 1.0f, 1.0f);
+ }
+
+ /**
+ * Changes alpha on color.
+ *
+ * @param color Target color.
+ * @param alpha Target alpha.
+ * @return Color with changed alpha.
+ */
+ public static Color changeAlpha(Color color, int alpha) {
+ if (color != null)
+ return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
+ else
+ return new Color(0);
+ }
+
public static int fromRGBA(int r, int g, int b, int a) {
return (r << 16) + (g << 8) + (b) + (a << 24);
}
@@ -113,8 +128,22 @@ public static int toRGBAB(int color) {
public static int toRGBAA(int color) {
return (color >> 24) & 0x000000FF;
}
- public int toInt()
- {
- return new Color(r,b,g,a).getRGB();
+
+ public void validate() {
+ if (r < 0) r = 0;
+ else if (r > 255) r = 255;
+
+ if (g < 0) g = 0;
+ else if (g > 255) g = 255;
+
+ if (b < 0) b = 0;
+ else if (b > 255) b = 255;
+
+ if (a < 0) a = 0;
+ else if (a > 255) a = 255;
+ }
+
+ public int toInt() {
+ return new Color(r, b, g, a).getRGB();
}
}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java
index 34f9115..3794f06 100644
--- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java
+++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java
@@ -1,195 +1,787 @@
package com.tanishisherewith.dynamichud.helpers;
+import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
-import com.tanishisherewith.dynamichud.util.CustomTextRenderer;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.font.TextRenderer;
+import com.tanishisherewith.dynamichud.DynamicHUD;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.render.*;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.util.math.MathHelper;
import org.joml.Matrix4f;
+import org.lwjgl.opengl.GL40C;
-public class DrawHelper extends DrawContext {
- public static CustomTextRenderer customTextRenderer;
+import java.awt.*;
- public DrawHelper(MinecraftClient client, VertexConsumerProvider.Immediate vertexConsumers) {
- super(client, vertexConsumers);
- }
+/**
+ * Credits: HeliosClient
+ */
+public class DrawHelper {
/**
- * Fills a box on the screen with a specified color.
+ * Draws a singular gradient rectangle on screen with the given parameters
*
- * @param drawContext The matrix stack used for rendering
- * @param x The x position of the rectangle
- * @param y The y position of the rectangle
- * @param width The width of the rectangle
- * @param height The height of the rectangle
- * @param color The color to fill the rectangle with
+ * @param matrix4f Matrix4f object to draw the gradient
+ * @param x X position of the gradient
+ * @param y Y position of the gradient
+ * @param width Width of the gradient
+ * @param height Height of the gradient
+ * @param startColor start color of the gradient
+ * @param endColor end color of the gradient
+ * @param direction Draws the gradient in the given direction
*/
- public static void drawBox(DrawContext drawContext, int x, int y, int width, int height, int color) {
- int x1 = x - width / 2 - 2;
- int y1 = y - height / 2 - 2;
- int x2 = x + width / 2 + 2;
- int y2 = y + height / 2 + 2;
- drawContext.fill(x1, y1, x2, y2, color);
+ public static void drawGradient(Matrix4f matrix4f, float x, float y, float width, float height, int startColor, int endColor, Direction direction) {
+ float startRed = (float) (startColor >> 16 & 255) / 255.0F;
+ float startGreen = (float) (startColor >> 8 & 255) / 255.0F;
+ float startBlue = (float) (startColor & 255) / 255.0F;
+ float startAlpha = (float) (startColor >> 24 & 255) / 255.0F;
+
+ float endRed = (float) (endColor >> 16 & 255) / 255.0F;
+ float endGreen = (float) (endColor >> 8 & 255) / 255.0F;
+ float endBlue = (float) (endColor & 255) / 255.0F;
+ float endAlpha = (float) (endColor >> 24 & 255) / 255.0F;
+
+ Tessellator tessellator = Tessellator.getInstance();
+ BufferBuilder bufferBuilder = tessellator.getBuffer();
+
+ RenderSystem.enableBlend();
+ RenderSystem.defaultBlendFunc();
+ RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+
+ bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
+
+ switch (direction) {
+ case LEFT_RIGHT:
+ bufferBuilder.vertex(matrix4f, x, y + height, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y + height, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ bufferBuilder.vertex(matrix4f, x, y, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ break;
+ case TOP_BOTTOM:
+ bufferBuilder.vertex(matrix4f, x, y + height, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y + height, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ bufferBuilder.vertex(matrix4f, x, y, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ break;
+ case RIGHT_LEFT:
+ bufferBuilder.vertex(matrix4f, x, y + height, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y + height, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ bufferBuilder.vertex(matrix4f, x, y, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ break;
+ case BOTTOM_TOP:
+ bufferBuilder.vertex(matrix4f, x, y + height, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y + height, 0.0F).color(startRed, startGreen, startBlue, startAlpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ bufferBuilder.vertex(matrix4f, x, y, 0.0F).color(endRed, endGreen, endBlue, endAlpha).next();
+ break;
+ }
+
+ tessellator.draw();
+
+ RenderSystem.disableBlend();
+ }
+
+ public static void enableScissor(int x, int y, int width, int height) {
+ double scaleFactor = DynamicHUD.MC.getWindow().getScaleFactor();
+
+ int scissorX = (int) (x * scaleFactor);
+ int scissorY = (int) (DynamicHUD.MC.getWindow().getHeight() - ((y + height) * scaleFactor));
+ int scissorWidth = (int) (width * scaleFactor);
+ int scissorHeight = (int) (height * scaleFactor);
+
+ RenderSystem.enableScissor(scissorX, scissorY, scissorWidth, scissorHeight);
+ }
+
+ public static void disableScissor() {
+ RenderSystem.disableScissor();
}
/**
- * Fills a rectangle on the screen with a specified color.
+ * Draws a singular rectangle on screen with the given parameters
*
- * @param x1 The x position of the top left corner of the rectangle
- * @param y1 The y position of the top left corner of the rectangle
- * @param x2 The x position of the bottom right corner of the rectangle
- * @param y2 The y position of the bottom right corner of the rectangle
- * @param color The color to fill the rectangle with
+ * @param matrix4f Matrix4f object to draw the rectangle
+ * @param x X position of the rectangle
+ * @param y Y position of the rectangle
+ * @param width Width of the rectangle
+ * @param height Height of the rectangle
+ * @param color Color of the rectangle
*/
- public static void fill(DrawContext drawContext, int x1, int y1, int x2, int y2, int color) {
- drawContext.fill(x1, y1, x2, y2, color);
+ public static void drawRectangle(Matrix4f matrix4f, float x, float y, float width, float height, int color) {
+ float red = (float) (color >> 16 & 255) / 255.0F;
+ float green = (float) (color >> 8 & 255) / 255.0F;
+ float blue = (float) (color & 255) / 255.0F;
+ float alpha = (float) (color >> 24 & 255) / 255.0F;
+
+ Tessellator tessellator = Tessellator.getInstance();
+ BufferBuilder bufferBuilder = tessellator.getBuffer();
+
+ RenderSystem.enableBlend();
+ RenderSystem.defaultBlendFunc();
+ RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+
+ bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
+
+ bufferBuilder.vertex(matrix4f, x, y + height, 0.0F).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y + height, 0.0F).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x + width, y, 0.0F).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x, y, 0.0F).color(red, green, blue, alpha).next();
+
+ tessellator.draw();
+
+ RenderSystem.disableBlend();
}
+ /* ==== Drawing Rectangles ==== */
+
/**
- * Draws text on screen.
+ * Draws a singular outline rectangle on screen with the given parameters
*
- * @param textRenderer - TextRenderer instance used for rendering.
- * @param text - Text to be drawn.
- * @param x - X position to draw at.
- * @param y - Y position to draw at.
- * @param color - Color to draw with.
+ * @param matrix4f Matrix4f object to draw the rectangle
+ * @param x X position of the rectangle
+ * @param y Y position of the rectangle
+ * @param width Width of the rectangle
+ * @param height Height of the rectangle
+ * @param color Color of the rectangle
*/
- public static void drawText(DrawContext drawContext,
- TextRenderer textRenderer,
- String text,
- int x,
- int y,
- int color,
- boolean shadow) {
- drawContext.drawText(textRenderer, text, x, y, color, shadow);
+ public static void drawOutlineBox(Matrix4f matrix4f, float x, float y, float width, float height, float thickness, int color) {
+ drawRectangle(matrix4f, x, y, width, thickness, color);
+ drawRectangle(matrix4f, x, y + height - thickness, width, thickness, color);
+ drawRectangle(matrix4f, x, y + thickness, thickness, height - thickness * 2, color);
+ drawRectangle(matrix4f, x + width - thickness, y + thickness, thickness, height - thickness * 2, color);
}
+ /**
+ * Draws a singular rectangle with a dark shadow on screen with the given parameters
+ * Bad way because there is a better way
+ *
+ * @param matrix4f Matrix4f object to draw the rectangle and shadow
+ * @param x X position of the rectangle
+ * @param y Y position of the rectangle
+ * @param width Width of the rectangle
+ * @param height Height of the rectangle
+ * @param color Color of the rectangle
+ * @param shadowOpacity Opacity of the shadow (Dark --> Lighter)
+ * @param shadowOffsetX X position Offset of the shadow from the main rectangle X pos
+ * @param shadowOffsetY Y position Offset of the shadow from the main rectangle Y pos
+ */
+ public static void drawRectangleWithShadowBadWay(Matrix4f matrix4f, float x, float y, float width, float height, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) {
+ // First, render the shadow
+ drawRectangle(matrix4f, x + shadowOffsetX, y + shadowOffsetY, width, height, ColorHelper.getColor(0, 0, 0, shadowOpacity));
+
+ // Then, render the rectangle
+ drawRectangle(matrix4f, x, y, width, height, color);
+ }
/**
- * Draws text on screen.
+ * Draws an outline rounded rectangle by drawing 4 side rectangles, and 4 arcs
*
- * @param drawContext - drawContext used for rendering.
- * @param text - Text to be drawn.
- * @param x - X position to draw at.
- * @param y - Y position to draw at.
- * @param color - Color to draw with.
+ * @param matrix4f Matrix4f object to draw the rounded rectangle
+ * @param x X pos
+ * @param y Y pos
+ * @param width Width of rounded rectangle
+ * @param height Height of rounded rectangle
+ * @param radius Radius of the quadrants / the rounded rectangle
+ * @param color Color of the rounded rectangle
+ * @param thickness thickness of the outline
*/
- public static void drawTextWithScale(DrawContext drawContext,
- String text,
- int x,
- int y,
- int color,
- boolean shadow,
- float scale) {
- customTextRenderer = new CustomTextRenderer(MinecraftClient.getInstance(), scale);
- customTextRenderer.draw(drawContext, text, x, y, color, shadow);
+ public static void drawOutlineRoundedBox(Matrix4f matrix4f, float x, float y, float width, float height, float radius, float thickness, int color) {
+ // Draw the rectangles for the outline
+ drawRectangle(matrix4f, x + radius, y, width - radius * 2, thickness, color); // Top rectangle
+ drawRectangle(matrix4f, x + radius, y + height - thickness, width - radius * 2, thickness, color); // Bottom rectangle
+ drawRectangle(matrix4f, x, y + radius, thickness, height - radius * 2, color); // Left rectangle
+ drawRectangle(matrix4f, x + width - thickness, y + radius, thickness, height - radius * 2, color); // Right rectangle
+
+ // Draw the arcs at the corners for the outline
+ drawArc(matrix4f, x + radius, y + radius, radius, thickness, color, 180, 270); // Top-left arc
+ drawArc(matrix4f, x + width - radius, y + radius, radius, thickness, color, 90, 180); // Top-right arc
+ drawArc(matrix4f, x + width - radius, y + height - radius, radius, thickness, color, 0, 90); // Bottom-right arc
+ drawArc(matrix4f, x + radius, y + height - radius, radius, thickness, color, 270, 360); // Bottom-left arc
}
+ public static void drawRainbowGradientRectangle(Matrix4f matrix4f, float x, float y, float width, float height, float alpha) {
+ BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer();
- public static void drawCutRectangle(DrawContext drawContext, int x1, int y1, int x2, int y2, int z, int color, int cornerRadius) {
- // Draw the rectangles
- drawContext.fill(x1 + cornerRadius, y1, x2 - cornerRadius, y1 + cornerRadius, z, color);
- drawContext.fill(x1 + cornerRadius, y2 - cornerRadius, x2 - cornerRadius, y2, z, color);
- drawContext.fill(x1, y1 + cornerRadius, x2, y2 - cornerRadius, z, color);
+ RenderSystem.enableBlend();
+ RenderSystem.defaultBlendFunc();
+ RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+
+ bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
+
+ for (int i = 0; i <= width; i++) {
+ float hue = (float) i / width;
+ int color = Color.HSBtoRGB(hue, 1.0f, 1.0f);
+ color = (color & 0x00FFFFFF) | ((int) (alpha * 255) << 24);
+
+ float red = (color >> 16 & 255) / 255.0F;
+ float green = (color >> 8 & 255) / 255.0F;
+ float blue = (color & 255) / 255.0F;
+ float alphaVal = (color >> 24 & 255) / 255.0F;
+
+ bufferBuilder.vertex(matrix4f, x + i, y, 0.0f).color(red, green, blue, alphaVal).next();
+ bufferBuilder.vertex(matrix4f, x + i, y + height, 0.0f).color(red, green, blue, alphaVal).next();
+ }
+
+ for (int i = (int) width; i >= 0; i--) {
+ float hue = (float) i / width;
+ int color = Color.HSBtoRGB(hue, 1.0f, 1.0f);
+ color = (color & 0x00FFFFFF) | ((int) (alpha * 255) << 24);
+
+ float red = (color >> 16 & 255) / 255.0F;
+ float green = (color >> 8 & 255) / 255.0F;
+ float blue = (color & 255) / 255.0F;
+ float alphaVal = (color >> 24 & 255) / 255.0F;
+
+ bufferBuilder.vertex(matrix4f, x + i, y + height, 0.0f).color(red, green, blue, alphaVal).next();
+ bufferBuilder.vertex(matrix4f, x + i, y, 0.0f).color(red, green, blue, alphaVal).next();
+ }
+
+ Tessellator.getInstance().draw();
+
+ RenderSystem.disableBlend();
}
+ public static void drawRainbowGradient(Matrix4f matrix, float x, float y, float width, float height) {
+ Matrix4f matrix4f = RenderSystem.getModelViewMatrix();
+
+ RenderSystem.enableBlend();
+ RenderSystem.colorMask(false, false, false, true);
+ RenderSystem.clearColor(0.0F, 0.0F, 0.0F, 0.0F);
+ RenderSystem.clear(GL40C.GL_COLOR_BUFFER_BIT, false);
+ RenderSystem.colorMask(true, true, true, true);
+
+ drawRectangle(matrix4f, x, y, width, height, Color.BLACK.getRGB());
+
+ RenderSystem.blendFunc(GL40C.GL_DST_ALPHA, GL40C.GL_ONE_MINUS_DST_ALPHA);
+
+ RenderSystem.enableBlend();
+ RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
+
+ BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer();
+ bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
+ for (float i = 0; i < width; i += 1.0f) {
+ float hue = (i / width); // Multiply by 1 to go through the whole color spectrum once (red to red)
+ Color color = Color.getHSBColor(hue, 1.0f, 1.0f); // Full saturation and brightness
+
+ bufferBuilder.vertex(matrix4f, x + i, y, 0.0F).color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()).next();
+ bufferBuilder.vertex(matrix4f, x + i + 1.0f, y, 0.0F).color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()).next();
+ bufferBuilder.vertex(matrix4f, x + i + 1.0f, y + height, 0.0F).color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()).next();
+ bufferBuilder.vertex(matrix4f, x + i, y + height, 0.0F).color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()).next();
+ }
+
+ BufferRenderer.drawWithGlobalProgram(bufferBuilder.end());
+ RenderSystem.disableBlend();
+
+ RenderSystem.defaultBlendFunc();
+ }
+
+
+ /* ==== Drawing filled and outline circles ==== */
+
/**
- * Fills a rounded rectangle on screen with specified color.
- * This causes a lot of problems and for some reason does not work for ArmorWidget when used for contextMenu
+ * Draws an outline of a circle
*
- * @param matrix4f - Matrix4f used for rendering.
- * @param x1 - X position of top left corner of rectangle.
- * @param y1 - Y position of top left corner of rectangle.
- * @param x2 - X position of bottom right corner of rectangle.
- * @param y2 - Y position of bottom right corner of rectangle.
- * @param cornerRadius - Radius of rounded corners.
- * @param color - Color to fill rectangle with.
+ * @param matrix4f Matrix4f object to draw the circle outline
+ * @param xCenter X position of the circle outline
+ * @param yCenter Y position of the circle outline
+ * @param radius radius of the circle outline
+ * @param color color of the circle outline
*/
- public static void fillRoundedRect(Matrix4f matrix4f, int x1, int y1, int x2, int y2, int cornerRadius, int color) {
+ public static void drawOutlineCircle(Matrix4f matrix4f, float xCenter, float yCenter, float radius, float lineWidth, int color) {
+ float red = (float) (color >> 16 & 255) / 255.0F;
+ float green = (float) (color >> 8 & 255) / 255.0F;
+ float blue = (float) (color & 255) / 255.0F;
float alpha = (float) (color >> 24 & 255) / 255.0F;
+
+ Tessellator tessellator = Tessellator.getInstance();
+ BufferBuilder bufferBuilder = tessellator.getBuffer();
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+ bufferBuilder.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR);
+
+ for (int i = 0; i <= 360; i++) {
+ double x = xCenter + Math.sin(Math.toRadians(i)) * radius;
+ double y = yCenter + Math.cos(Math.toRadians(i)) * radius;
+ double x2 = xCenter + Math.sin(Math.toRadians(i)) * (radius + lineWidth);
+ double y2 = yCenter + Math.cos(Math.toRadians(i)) * (radius + lineWidth);
+ bufferBuilder.vertex(matrix4f, (float) x, (float) y, 0).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, (float) x2, (float) y2, 0).color(red, green, blue, alpha).next();
+ }
+
+
+ tessellator.draw();
+ }
+
+ /**
+ * Draws a filled circle
+ *
+ * @param matrix4f Matrix4f object to draw the circle outline
+ * @param xCenter X position of the circle outline
+ * @param yCenter Y position of the circle outline
+ * @param radius radius of the circle outline
+ * @param color color of the circle outline
+ */
+ public static void drawFilledCircle(Matrix4f matrix4f, float xCenter, float yCenter, float radius, int color) {
float red = (float) (color >> 16 & 255) / 255.0F;
float green = (float) (color >> 8 & 255) / 255.0F;
float blue = (float) (color & 255) / 255.0F;
+ float alpha = (float) (color >> 24 & 255) / 255.0F;
+
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
+
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+ bufferBuilder.begin(VertexFormat.DrawMode.TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
- bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
+ RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
- // Draw the center rectangle
- bufferBuilder.vertex(matrix4f, x1 + cornerRadius, y2 - cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x2 - cornerRadius, y2 - cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x2 - cornerRadius, y1 + cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x1 + cornerRadius, y1 + cornerRadius, 0).color(red, green, blue, alpha).next();
-
- // Draw the side rectangles
- bufferBuilder.vertex(matrix4f, x1, y1 + cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x1 + cornerRadius, y1 + cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x1 + cornerRadius, y2 - cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x1, y2 - cornerRadius, 0).color(red, green, blue, alpha).next();
-
- bufferBuilder.vertex(matrix4f, x2, y1 + cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x2 - cornerRadius, y1 + cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x2 - cornerRadius, y2 - cornerRadius, 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, x2, y2 - cornerRadius, 0).color(red, green, blue, alpha).next();
-
-
- // Draw the rounded corners
- for (int i = 0; i <= 90; i += 5) {
- double angle = Math.toRadians(i);
- double sin = Math.sin(angle);
- double cos = Math.cos(angle);
- bufferBuilder.vertex(matrix4f, (float) (x1 + cornerRadius * (1 - cos)), (float) (y1 + cornerRadius * (1 - sin)), 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, (float) (x1 + cornerRadius * (1 - cos)), (float) (y2 - cornerRadius * (1 - sin)), 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, (float) (x2 - cornerRadius * (1 - cos)), (float) (y2 - cornerRadius * (1 - sin)), 0).color(red, green, blue, alpha).next();
- bufferBuilder.vertex(matrix4f, (float) (x2 - cornerRadius * (1 - cos)), (float) (y1 + cornerRadius * (1 - sin)), 0).color(red, green, blue, alpha).next();
+
+ bufferBuilder.vertex(matrix4f, xCenter, yCenter, 0).color(red, green, blue, alpha).next();
+
+ for (int i = 0; i <= 360; i++) {
+ double x = xCenter + Math.sin(Math.toRadians(i)) * radius;
+ double y = yCenter + Math.cos(Math.toRadians(i)) * radius;
+ bufferBuilder.vertex(matrix4f, (float) x, (float) y, 0).color(red, green, blue, alpha).next();
}
+
tessellator.draw();
RenderSystem.disableBlend();
}
- public static void fillRoundedRect(DrawContext drawContext, int left, int top, int right, int bottom, int color) {
- drawContext.fill(left + 1, top, right - 1, top + 1, color);
- drawContext.fill(left + 1, bottom - 1, right - 1, bottom, color);
- drawContext.fill(left, top + 1, left + 1, bottom - 1, color);
- drawContext.fill(right - 1, top + 1, right, bottom - 1, color);
- drawContext.fill(left + 1, top + 1, right - 1, bottom - 1, color);
+ /**
+ * Draws a filled circle with a shadow bad way
+ *
+ * @param matrix4f Matrix4f object to draw the circle
+ * @param xCenter X position of the circle
+ * @param yCenter Y position of the circle
+ * @param radius Radius of the circle
+ * @param color Color of the circle
+ * @param shadowOffsetX X position of the circle shadow offset from main circle
+ * @param shadowOffsetY X position of the circle shadow offset from main circle
+ * @param shadowOpacity Opacity of the circle shadow offset from main circle
+ */
+ public static void drawCircleWithShadow(Matrix4f matrix4f, float xCenter, float yCenter, float radius, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) {
+ // First, render the shadow
+ drawFilledCircle(matrix4f, xCenter + shadowOffsetX, yCenter + shadowOffsetY, radius, ColorHelper.getColor(0, 0, 0, shadowOpacity));
+
+ // Then, render the circle
+ drawFilledCircle(matrix4f, xCenter, yCenter, radius, color);
}
/**
- * Fills a rectangle on screen with a gradient.
+ * Not Tested
*
- * @param matrix4f - Matrix4f used for rendering.
- * @param x1 - X position of top left corner of rectangle.
- * @param y1 - Y position of top left corner of rectangle.
- * @param x2 - X position of bottom right corner of rectangle.
- * @param y2 - Y position of bottom right corner of rectangle.
- * @param topColor - Color at top of gradient.
- * @param bottomColor - Color at bottom of gradient.
+ * @param matrix4f
+ * @param x
+ * @param y
+ * @param radius
+ * @param startAngle
+ * @param endAngle
+ * @param color
*/
- public static void fillGradient(Matrix4f matrix4f, int x1, int y1, int x2, int y2, int topColor, int bottomColor) {
- float topAlpha = (float) (topColor >> 24 & 255) / 255.0F;
- float topRed = (float) (topColor >> 16 & 255) / 255.0F;
- float topGreen = (float) (topColor >> 8 & 255) / 255.0F;
- float topBlue = (float) (topColor & 255) / 255.0F;
- float bottomAlpha = (float) (bottomColor >> 24 & 255) / 255.0F;
- float bottomRed = (float) (bottomColor >> 16 & 255) / 255.0F;
- float bottomGreen = (float) (bottomColor >> 8 & 255) / 255.0F;
- float bottomBlue = (float) (bottomColor & 255) / 255.0F;
+ @Deprecated
+ public static void drawFilledArc(Matrix4f matrix4f, float x, float y, float radius, float startAngle, float endAngle, int color) {
+ float red = (float) (color >> 16 & 255) / 255.0F;
+ float green = (float) (color >> 8 & 255) / 255.0F;
+ float blue = (float) (color & 255) / 255.0F;
+ float alpha = (float) (color >> 24 & 255) / 255.0F;
+
+
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+ bufferBuilder.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR);
RenderSystem.enableBlend();
- RenderSystem.defaultBlendFunc();
- bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
- bufferBuilder.vertex(matrix4f, x1, y2, 0).color(topRed, topGreen, topBlue, topAlpha).next();
- bufferBuilder.vertex(matrix4f, x2, y2, 0).color(topRed, topGreen, topBlue, topAlpha).next();
- bufferBuilder.vertex(matrix4f, x2, y1, 0).color(bottomRed, bottomGreen, bottomBlue, bottomAlpha).next();
- bufferBuilder.vertex(matrix4f, x1, y1, 0).color(bottomRed, bottomGreen, bottomBlue, bottomAlpha).next();
+
+ for (float angle = startAngle; angle <= endAngle; angle += 1.0F) {
+ float x1 = x + MathHelper.cos(angle * 0.017453292F) * radius;
+ float y1 = y + MathHelper.sin(angle * 0.017453292F) * radius;
+ float x2 = x + MathHelper.cos((angle + 1.0F) * 0.017453292F) * radius;
+ float y2 = y + MathHelper.sin((angle + 1.0F) * 0.017453292F) * radius;
+
+ bufferBuilder.vertex(matrix4f, x, y, 0).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x1, y1, 0).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x2, y2, 0).color(red, green, blue, alpha).next();
+ }
tessellator.draw();
RenderSystem.disableBlend();
}
+ /* ==== Drawing Quadrants, Arcs, and Triangles ==== */
+
+ /**
+ * Draws a filled Gradient quadrant
+ *
+ * @param matrix4f Matrix4f object to draw the quadrant
+ * @param xCenter X position of the quadrant
+ * @param yCenter Y position of the quadrant
+ * @param radius Radius of the quadrant
+ * @param startColor start color of the gradient
+ * @param endColor end color of the gradient
+ * @param quadrant Integer value of the quadrant of the circle. 1 == Top Right, 2 == Top Left, 3 == Bottom Right, 4 == Bottom Left
+ */
+ public static void drawFilledGradientQuadrant(Matrix4f matrix4f, float xCenter, float yCenter, float radius, int startColor, int endColor, int quadrant) {
+ float startRed = (float) (startColor >> 16 & 255) / 255.0F;
+ float startGreen = (float) (startColor >> 8 & 255) / 255.0F;
+ float startBlue = (float) (startColor & 255) / 255.0F;
+ float startAlpha = (float) (startColor >> 24 & 255) / 255.0F;
+
+ float endRed = (float) (endColor >> 16 & 255) / 255.0F;
+ float endGreen = (float) (endColor >> 8 & 255) / 255.0F;
+ float endBlue = (float) (endColor & 255) / 255.0F;
+ float endAlpha = (float) (endColor >> 24 & 255) / 255.0F;
+
+ Tessellator tessellator = Tessellator.getInstance();
+ BufferBuilder bufferBuilder = tessellator.getBuffer();
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+ bufferBuilder.begin(VertexFormat.DrawMode.TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
+ RenderSystem.enableBlend();
+
+ bufferBuilder.vertex(matrix4f, xCenter, yCenter, 0).color(startRed, startGreen, startBlue, startAlpha).next();
+
+ for (int i = quadrant * 90; i <= quadrant * 90 + 90; i++) {
+ double x = xCenter + Math.sin(Math.toRadians(i)) * radius;
+ double y = yCenter + Math.cos(Math.toRadians(i)) * radius;
+
+ // Interpolate the color based on the angle
+ float t = (float) (i - quadrant * 90) / 90.0f;
+ float red = startRed * (1 - t) + endRed * t;
+ float green = startGreen * (1 - t) + endGreen * t;
+ float blue = startBlue * (1 - t) + endBlue * t;
+ float alpha = startAlpha * (1 - t) + endAlpha * t;
+
+ bufferBuilder.vertex(matrix4f, (float) x, (float) y, 0).color(red, green, blue, alpha).next();
+ }
+
+ tessellator.draw();
+ RenderSystem.disableBlend();
+ }
+
+ /**
+ * Draws an arc
+ *
+ * @param matrix4f Matrix4f object to draw the arc
+ * @param xCenter X position of the arc's center
+ * @param yCenter Y position of the arc's center
+ * @param radius Radius of the arc's center circle
+ * @param startAngle start Angle of the arc
+ * @param endAngle end Angle of the arc
+ * @param thickness Thickness of the arc (width of the arc)
+ */
+ public static void drawArc(Matrix4f matrix4f, float xCenter, float yCenter, float radius, float thickness, int color, int startAngle, int endAngle) {
+ float red = (float) (color >> 16 & 255) / 255.0F;
+ float green = (float) (color >> 8 & 255) / 255.0F;
+ float blue = (float) (color & 255) / 255.0F;
+ float alpha = (float) (color >> 24 & 255) / 255.0F;
+
+ Tessellator tessellator = Tessellator.getInstance();
+ BufferBuilder bufferBuilder = tessellator.getBuffer();
+
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+ bufferBuilder.begin(VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR);
+ RenderSystem.enableBlend();
+
+ for (int i = startAngle; i <= endAngle; i++) {
+ double innerX = xCenter + Math.sin(Math.toRadians(i)) * (radius - thickness);
+ double innerY = yCenter + Math.cos(Math.toRadians(i)) * (radius - thickness);
+ double outerX = xCenter + Math.sin(Math.toRadians(i)) * radius;
+ double outerY = yCenter + Math.cos(Math.toRadians(i)) * radius;
+
+ bufferBuilder.vertex(matrix4f, (float) innerX, (float) innerY, 0).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, (float) outerX, (float) outerY, 0).color(red, green, blue, alpha).next();
+ }
+
+ tessellator.draw();
+
+ RenderSystem.disableBlend();
+ }
+
+ /**
+ * Draws a filled quadrant
+ *
+ * @param matrix4f Matrix4f object to draw the quadrant
+ * @param xCenter X position of the quadrant
+ * @param yCenter Y position of the quadrant
+ * @param radius Radius of the quadrant
+ * @param color color of the quadrant
+ * @param quadrant Integer value of the quadrant of the circle. 1 == Top Right, 2 == Top Left, 3 == Bottom Right, 4 == Bottom Left
+ */
+ public static void drawFilledQuadrant(Matrix4f matrix4f, float xCenter, float yCenter, float radius, int color, int quadrant) {
+ float red = (float) (color >> 16 & 255) / 255.0F;
+ float green = (float) (color >> 8 & 255) / 255.0F;
+ float blue = (float) (color & 255) / 255.0F;
+ float alpha = (float) (color >> 24 & 255) / 255.0F;
+
+ Tessellator tessellator = Tessellator.getInstance();
+ BufferBuilder bufferBuilder = tessellator.getBuffer();
+ RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+ bufferBuilder.begin(VertexFormat.DrawMode.TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
+ RenderSystem.enableBlend();
+
+ bufferBuilder.vertex(matrix4f, xCenter, yCenter, 0).color(red, green, blue, alpha).next();
+
+ for (int i = quadrant * 90; i <= quadrant * 90 + 90; i++) {
+ double x = xCenter + Math.sin(Math.toRadians(i)) * radius;
+ double y = yCenter + Math.cos(Math.toRadians(i)) * radius;
+ bufferBuilder.vertex(matrix4f, (float) x, (float) y, 0).color(red, green, blue, alpha).next();
+ }
+
+ tessellator.draw();
+ RenderSystem.disableBlend();
+
+ }
+
+ /**
+ * Draws a Triangle with the given coordinates
+ *
+ * @param matrix4f
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ * @param x3
+ * @param y3
+ * @param color
+ */
+ public static void drawOutlineTriangle(Matrix4f matrix4f, int x1, int y1, int x2, int y2, int x3, int y3, int color) {
+ float red = (float) (color >> 16 & 255) / 255.0F;
+ float green = (float) (color >> 8 & 255) / 255.0F;
+ float blue = (float) (color & 255) / 255.0F;
+ float alpha = (float) (color >> 24 & 255) / 255.0F;
+
+ Tessellator tessellator = Tessellator.getInstance();
+ BufferBuilder bufferBuilder = tessellator.getBuffer();
+ bufferBuilder.begin(VertexFormat.DrawMode.DEBUG_LINES, VertexFormats.POSITION_COLOR);
+
+ bufferBuilder.vertex(matrix4f, x1, y1, 0).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x2, y2, 0).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x3, y3, 0).color(red, green, blue, alpha).next();
+ bufferBuilder.vertex(matrix4f, x1, y1, 0).color(red, green, blue, alpha).next();
+
+ tessellator.draw();
+ }
+
+ /**
+ * Draws a outline quadrant
+ *
+ * @param matrix4f Matrix4f object to draw the quadrant
+ * @param xCenter X position of the quadrant
+ * @param yCenter Y position of the quadrant
+ * @param radius Radius of the quadrant
+ * @param color color of the quadrant
+ * @param quadrant Integer value of the quadrant of the circle. 1 == Top Right, 2 == Top Left, 3 == Bottom Right, 4 == Bottom Left
+ */
+ public static void drawOutlineQuadrant(Matrix4f matrix4f, float xCenter, float yCenter, float radius, int quadrant, int color) {
+ int startAngle = 0;
+ int endAngle = 0;
+
+ if (quadrant == 1) {
+ startAngle = 270;
+ endAngle = 360;
+ } else if (quadrant == 2) {
+ startAngle = 180;
+ endAngle = 270;
+ } else if (quadrant == 3) {
+ startAngle = 90;
+ endAngle = 180;
+ } else if (quadrant == 4) {
+ endAngle = 90;
+ }
+
+ drawArc(matrix4f, xCenter, yCenter, radius, 1f, color, startAngle, endAngle);
+ }
+
+ /**
+ * Draws a filled rounded rectangle by drawing 1 main rectangle, 4 side rectangles, and 4 filled quadrants
+ *
+ * @param matrix4f Matrix4f object to draw the rounded rectangle
+ * @param x X pos
+ * @param y Y pos
+ * @param width Width of rounded rectangle
+ * @param height Height of rounded rectangle
+ * @param radius Radius of the quadrants / the rounded rectangle
+ * @param color Color of the rounded rectangle
+ */
+ public static void drawRoundedRectangle(Matrix4f matrix4f, float x, float y, float width, float height, float radius, int color) {
+ drawRoundedRectangle(matrix4f, x, y, true, true, true, true, width, height, radius, color);
+ }
+
+ /* ==== Drawing Rounded Rectangles ==== */
+
+ /**
+ * Draws a filled rounded rectangle by drawing 1 main rectangle, 4 side rectangles, and specified filled quadrants
+ *
+ * @param matrix4f Matrix4f object to draw the rounded rectangle
+ * @param x X pos
+ * @param y Y pos
+ * @param TL Whether to draw the top left quadrant
+ * @param TR Whether to draw the top right quadrant
+ * @param BL Whether to draw the bottom left quadrant
+ * @param BR Whether to draw the bottom right quadrant
+ * @param width Width of rounded rectangle
+ * @param height Height of rounded rectangle
+ * @param radius Radius of the quadrants / the rounded rectangle
+ * @param color Color of the rounded rectangle
+ */
+ public static void drawRoundedRectangle(Matrix4f matrix4f, float x, float y, boolean TL, boolean TR, boolean BL, boolean BR, float width, float height, float radius, int color) {
+ // Draw the main rectangle
+ drawRectangle(matrix4f, x + radius, y + radius, width - 2 * radius, height - 2 * radius, color);
+
+ // Draw rectangles at the sides
+ drawRectangle(matrix4f, x + radius, y, width - 2 * radius, radius, color); // top
+ drawRectangle(matrix4f, x + radius, y + height - radius, width - 2 * radius, radius, color); // bottom
+ drawRectangle(matrix4f, x, y + radius, radius, height - 2 * radius, color); // left
+ drawRectangle(matrix4f, x + width - radius, y + radius, radius, height - 2 * radius, color); // right
+
+ if (TL) {
+ drawFilledQuadrant(matrix4f, x + radius, y + radius, radius, color, 2);
+ } else {
+ drawRectangle(matrix4f, x, y, radius, radius, color);
+ }
+ if (TR) {
+ drawFilledQuadrant(matrix4f, x + width - radius, y + radius, radius, color, 1);
+ } else {
+ drawRectangle(matrix4f, x + width - radius, y, radius, radius, color);
+ }
+ if (BL) {
+ drawFilledQuadrant(matrix4f, x + radius, y + height - radius, radius, color, 3);
+ } else {
+ drawRectangle(matrix4f, x, y + height - radius, radius, radius, color);
+ }
+ if (BR) {
+ drawFilledQuadrant(matrix4f, x + width - radius, y + height - radius, radius, color, 4);
+ } else {
+ drawRectangle(matrix4f, x + width - radius, y + height - radius, radius, radius, color);
+ }
+ }
+
+ /**
+ * Draws an outline rounded gradient rectangle
+ *
+ * @param matrix4f Matrix4f object to draw the rounded gradient rectangle
+ * @param color1 is applied to the bottom-left vertex (x, y + height).
+ * @param color2 is applied to the bottom-right vertex (x + width, y + height).
+ * @param color3 is applied to the top-right vertex (x + width, y).
+ * @param color4 is applied to the top-left vertex (x, y).
+ * @param x X pos
+ * @param y Y pos
+ * @param width Width of rounded gradient rectangle
+ * @param height Height of rounded gradient rectangle
+ * @param radius Radius of the quadrants / the rounded gradient rectangle
+ */
+ public static void drawOutlineGradientRoundedBox(Matrix4f matrix4f, float x, float y, float width, float height, float radius, float thickness, Color color1, Color color2, Color color3, Color color4) {
+ // Draw the rectangles for the outline with gradient
+ drawGradient(matrix4f, x + radius, y, width - radius * 2, thickness, color1.getRGB(), color2.getRGB(), Direction.LEFT_RIGHT); // Top rectangle
+ drawGradient(matrix4f, x + radius, y + height - thickness, width - radius * 2, thickness, color3.getRGB(), color4.getRGB(), Direction.RIGHT_LEFT); // Bottom rectangle
+
+ drawGradient(matrix4f, x, y + radius, thickness, height - radius * 2, color4.getRGB(), color1.getRGB(), Direction.BOTTOM_TOP); // Left rectangle
+ drawGradient(matrix4f, x + width - thickness, y + radius, thickness, height - radius * 2, color2.getRGB(), color3.getRGB(), Direction.TOP_BOTTOM); // Right rectangle
+
+ // Draw the arcs at the corners for the outline with gradient
+ drawArc(matrix4f, x + radius, y + radius, radius, thickness, color1.getRGB(), 180, 270); // Top-left arc
+ drawArc(matrix4f, x + width - radius, y + radius, radius, thickness, color2.getRGB(), 90, 180); // Top-right arc
+ drawArc(matrix4f, x + width - radius, y + height - radius, radius, thickness, color3.getRGB(), 0, 90); // Bottom-right arc
+ drawArc(matrix4f, x + radius, y + height - radius, radius, thickness, color4.getRGB(), 270, 360); // Bottom-left arc
+ }
+
+ public static void drawCutRectangle(DrawContext drawContext, int x1, int y1, int x2, int y2, int z, int color, int cornerRadius) {
+ // Draw the rectangles
+ drawContext.fill(x1 + cornerRadius, y1, x2 - cornerRadius, y1 + cornerRadius, z, color);
+ drawContext.fill(x1 + cornerRadius, y2 - cornerRadius, x2 - cornerRadius, y2, z, color);
+ drawContext.fill(x1, y1 + cornerRadius, x2, y2 - cornerRadius, z, color);
+ }
+
+ /**
+ * Draws a rounded rectangle with a shadow in a bad way
+ *
+ * @param matrix4f Matrix4f object to draw the rounded rectangle
+ * @param x X pos
+ * @param y Y pos
+ * @param width Width of rounded rectangle
+ * @param height Height of rounded rectangle
+ * @param radius Radius of the quadrants / the rounded rectangle
+ * @param color Color of the rounded rectangle
+ * @param shadowOpacity opacity of the shadow
+ * @param shadowOffsetX X offset of the shadow
+ * @param shadowOffsetY Y offset of the shadow
+ */
+ public static void drawRoundedRectangleWithShadowBadWay(Matrix4f matrix4f, float x, float y, float width, float height, float radius, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) {
+ // First, render the shadow
+ drawRoundedRectangle(matrix4f, x + shadowOffsetX, y + shadowOffsetY, width, height, radius, ColorHelper.getColor(0, 0, 0, shadowOpacity));
+
+ // Then, render the rounded rectangle
+ drawRoundedRectangle(matrix4f, x, y, width, height, radius, color);
+ }
+
+ /**
+ * Draws a rounded gradient rectangle
+ *
+ * @param matrix Matrix4f object to draw the rounded gradient rectangle
+ * @param color1 is applied to the bottom-left vertex (x, y + height).
+ * @param color2 is applied to the bottom-right vertex (x + width, y + height).
+ * @param color3 is applied to the top-right vertex (x + width, y).
+ * @param color4 is applied to the top-left vertex (x, y).
+ * @param x X pos
+ * @param y Y pos
+ * @param width Width of rounded gradient rectangle
+ * @param height Height of rounded gradient rectangle
+ * @param radius Radius of the quadrants / the rounded gradient rectangle
+ */
+ public static void drawRoundedGradientRectangle(Matrix4f matrix, Color color1, Color color2, Color color3, Color color4, float x, float y, float width, float height, float radius) {
+ drawRoundedGradientRectangle(matrix, color1, color2, color3, color4, x, y, width, height, radius, true, true, true, true);
+ }
+
+ /**
+ * Draws a rounded gradient rectangle
+ *
+ * @param matrix Matrix4f object to draw the rounded gradient rectangle
+ * @param color1 is applied to the bottom-left vertex (x, y + height).
+ * @param color2 is applied to the bottom-right vertex (x + width, y + height).
+ * @param color3 is applied to the top-right vertex (x + width, y).
+ * @param color4 is applied to the top-left vertex (x, y).
+ * @param x X pos
+ * @param y Y pos
+ * @param width Width of rounded gradient rectangle
+ * @param height Height of rounded gradient rectangle
+ * @param radius Radius of the quadrants / the rounded gradient rectangle
+ */
+ public static void drawRoundedGradientRectangle(Matrix4f matrix, Color color1, Color color2, Color color3, Color color4, float x, float y, float width, float height, float radius, boolean TL, boolean TR, boolean BL, boolean BR) {
+ RenderSystem.enableBlend();
+ RenderSystem.colorMask(false, false, false, true);
+ RenderSystem.clearColor(0.0F, 0.0F, 0.0F, 0.0F);
+ RenderSystem.clear(GL40C.GL_COLOR_BUFFER_BIT, false);
+ RenderSystem.colorMask(true, true, true, true);
+
+ drawRoundedRectangle(matrix, x, y, TL, TR, BL, BR, width, height, (int) radius, color1.getRGB());
+
+ RenderSystem.blendFunc(GL40C.GL_DST_ALPHA, GL40C.GL_ONE_MINUS_DST_ALPHA);
+
+ RenderSystem.enableBlend();
+ RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
+
+ BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer();
+ bufferBuilder.begin(VertexFormat.DrawMode.TRIANGLE_FAN, VertexFormats.POSITION_COLOR);
+
+ bufferBuilder.vertex(matrix, x, y + height, 0.0F).color(color1.getRGB()).next();
+ bufferBuilder.vertex(matrix, x + width, y + height, 0.0F).color(color2.getRGB()).next();
+ bufferBuilder.vertex(matrix, x + width, y, 0.0F).color(color3.getRGB()).next();
+ bufferBuilder.vertex(matrix, x, y, 0.0F).color(color4.getRGB()).next();
+ BufferRenderer.drawWithGlobalProgram(bufferBuilder.end());
+ RenderSystem.disableBlend();
+
+ RenderSystem.defaultBlendFunc();
+ }
+
+ /* ==== Drawing Lines ==== */
+ public static void drawVerticalLine(Matrix4f matrix4f, float x, float y1, float height, float thickness, int color) {
+ drawRectangle(matrix4f, x, y1, thickness, height, color);
+ }
+
+ public static void drawHorizontalLine(Matrix4f matrix4f, float x1, float width, float y, float thickness, int color) {
+ drawRectangle(matrix4f, x1, y, width, thickness, color);
+ }
/**
* Draws an outlined box on the screen.
@@ -207,4 +799,53 @@ public static void drawOutlinedBox(DrawContext drawContext, int x1, int y1, int
drawContext.fill(x2 - 1, y1 + 1, x2, y2 - 1, color);
}
-}
+ /**
+ * This method assumes that the x, y coords are the origin of a widget.
+ *
+ * @param x X position of widget
+ * @param y Y position of widget
+ * @param scale Scale the matrices
+ */
+ public static void scaleAndPosition(MatrixStack matrices, float x, float y, float scale) {
+ matrices.push(); // Save the current transformation state
+
+ // Translate the origin back to the desired position
+ matrices.translate(x, y, 0);
+
+ // Scale the matrix
+ matrices.scale(scale, scale, 1.0F);
+
+ matrices.translate(-x, -y, 0);
+ }
+
+ /**
+ * This method scales the matrices by the centre of the widget
+ *
+ * @param x X position of widget
+ * @param y Y position of widget
+ * @param height height of widget
+ * @param width width of widget
+ * @param scale Scale the matrices
+ */
+ public static void scaleAndPosition(MatrixStack matrices, float x, float y, float width, float height, float scale) {
+ matrices.push(); // Save the current transformation state
+
+ // Translate the origin back to the desired position
+ matrices.translate(x + width / 2.0f, y + height / 2.0f, 0);
+
+ // Scale the matrix
+ matrices.scale(scale, scale, 1.0F);
+
+ matrices.translate(-(x + width / 2.0f), -(y + height / 2.0f), 0);
+ }
+
+ public static void stopScaling(MatrixStack matrices) {
+ matrices.pop(); // Restore the previous transformation state
+ }
+
+ public enum Direction {
+ /* LEFT_RIGHT means from left to right. Same for others */
+ LEFT_RIGHT, TOP_BOTTOM, RIGHT_LEFT, BOTTOM_TOP
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java
index 0fade01..5301aaa 100644
--- a/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java
+++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java
@@ -1,232 +1,269 @@
package com.tanishisherewith.dynamichud.helpers;
-import com.mojang.blaze3d.systems.RenderSystem;
-import com.tanishisherewith.dynamichud.util.CustomItemRenderer;
-import com.tanishisherewith.dynamichud.util.CustomTextRenderer;
import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.font.TextRenderer;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.render.VertexConsumerProvider;
-import net.minecraft.item.ItemStack;
+import net.minecraft.client.texture.NativeImage;
import net.minecraft.util.Identifier;
-/**
- * This class provides helper methods for drawing textures on the screen.
- */
-public class TextureHelper extends DrawContext {
- public static CustomTextRenderer customTextRenderer;
- public static CustomItemRenderer customItemRenderer;
+import java.io.IOException;
+import java.io.InputStream;
+public class TextureHelper {
+ static MinecraftClient mc = MinecraftClient.getInstance();
- public TextureHelper(MinecraftClient client, VertexConsumerProvider.Immediate vertexConsumers) {
- super(client, vertexConsumers);
+ public static NativeImage loadTexture(Identifier textureId) {
+ if(mc.getResourceManager().getResource(textureId).isPresent()) {
+ try (InputStream inputStream = mc.getResourceManager().getResource(textureId).get().getInputStream()) {
+ return NativeImage.read(inputStream);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load texture " + textureId, e);
+ }
+ }
+ return null;
}
+ public static NativeImage resizeTexture(NativeImage image, int newWidth, int newHeight) {
+ NativeImage result = new NativeImage(newWidth, newHeight, false);
- /**
- * Draws an item texture on the screen.
- *
- * @param itemStack The item stack to render the texture for
- * @param x The x position to draw the texture at
- * @param y The y position to draw the texture at
- */
- public static void drawItemTexture(DrawContext drawContext,
- ItemStack itemStack,
- int x,
- int y) {
- drawContext.drawItem(itemStack, x, y);
- }
+ int oldWidth = image.getWidth();
+ int oldHeight = image.getHeight();
- /**
- * Draws the texture of the item in the player's main hand on the screen.
- *
- * @param client The Minecraft client instance
- * @param x The x position to draw the texture at
- * @param y The y position to draw the texture at
- */
- public static void drawMainHandTexture(DrawContext drawContext,
- MinecraftClient client,
- int x,
- int y) {
- assert client.player != null;
- ItemStack mainHandItem = client.player.getMainHandStack();
- drawItemTexture(drawContext, mainHandItem, x, y);
- }
+ for (int y = 0; y < newHeight; y++) {
+ for (int x = 0; x < newWidth; x++) {
+ int srcX = x * oldWidth / newWidth;
+ int srcY = y * oldHeight / newHeight;
- /**
- * Draws a textured rectangle on the screen.
- *
- * @param x The x position of the top left corner of the rectangle
- * @param y The y position of the top left corner of the rectangle
- * @param u The x position of the texture within the texture image
- * @param v The y position of the texture within the texture image
- * @param width The width of the rectangle
- * @param height The height of the rectangle
- * @param textureWidth The width of the texture image
- * @param textureHeight The height of the texture image
- */
- public static void drawTexture(DrawContext drawContext, Identifier texture, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight) {
- drawContext.drawTexture(texture, x, y, u, v, width, height, textureWidth, textureHeight);
- }
+ result.setColor(x, y, image.getColor(srcX, srcY));
+ }
+ }
- /**
- * Draws a textured rectangle on the screen with a specified color.
- *
- * @param x The x position of the top left corner of the rectangle
- * @param y The y position of the top left corner of the rectangle
- * @param u The x position of the texture within the texture image
- * @param v The y position of the texture within the texture image
- * @param width The width of the rectangle
- * @param height The height of the rectangle
- * @param color The color to draw the rectangle with
- */
- public static void drawTexturedRect(DrawContext drawContext, Identifier texture, int x, int y, int u, int v, int width, int height, int color) {
- RenderSystem.setShaderColor((color >> 16 & 255) / 255.0F,
- (color >> 8 & 255) / 255.0F,
- (color & 255) / 255.0F,
- (color >> 24 & 255) / 255.0F);
- drawContext.drawTexture(texture, x, y, u, v, width, height);
+ return result;
}
+ public static NativeImage resizeTextureUsingBilinearInterpolation(NativeImage image, int newWidth, int newHeight) {
+ NativeImage result = new NativeImage(newWidth, newHeight, false);
+
+ float x_ratio = ((float)(image.getWidth()-1))/newWidth;
+ float y_ratio = ((float)(image.getHeight()-1))/newHeight;
+ float x_diff, y_diff, blue, red, green;
+ int offset, a, b, c, d, index;
+
+ for (int i=0;i {
- textX = x + (16 - textWidth) / 2;
- textY = y - textHeight;
+ // Indexes of the 4 surrounding pixels
+ a = image.getColor(x, y);
+ b = image.getColor(x+1, y);
+ c = image.getColor(x, y+1);
+ d = image.getColor(x+1, y+1);
+
+ // Blue element
+ blue = (a&0xff)*(1-x_diff)*(1-y_diff) + (b&0xff)*(x_diff)*(1-y_diff) +
+ (c&0xff)*(y_diff)*(1-x_diff) + (d&0xff)*(x_diff*y_diff);
+
+ // Green element
+ green = ((a>>8)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>8)&0xff)*(x_diff)*(1-y_diff) +
+ ((c>>8)&0xff)*(y_diff)*(1-x_diff) + ((d>>8)&0xff)*(x_diff*y_diff);
+
+ // Red element
+ red = ((a>>16)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>16)&0xff)*(x_diff)*(1-y_diff) +
+ ((c>>16)&0xff)*(y_diff)*(1-x_diff) + ((d>>16)&0xff)*(x_diff*y_diff);
+
+ result.setColor(j, i,
+ ((((int)red)<<16)&0xff0000) |
+ ((((int)green)<<8)&0xff00) |
+ ((int)blue)&0xff);
}
- case BELOW -> {
- textX = x + (17 - textWidth) / 2;
- textY = y + 16;
+ }
+
+ return result;
+ }
+ public static NativeImage invertTexture(NativeImage image) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ NativeImage result = new NativeImage(width, height, false);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int argb = image.getColor(x, y);
+
+ int alpha = (argb >> 24) & 0xFF;
+ int red = 255 - ((argb >> 16) & 0xFF);
+ int green = 255 - ((argb >> 8) & 0xFF);
+ int blue = 255 - (argb & 0xFF);
+
+ int newArgb = (alpha << 24) | (red << 16) | (green << 8) | blue;
+
+ result.setColor(x, y, newArgb);
}
- case LEFT -> {
- textX = x - textWidth - 2;
- textY = y + (16 - textHeight) / 2;
+ }
+
+ return result;
+ }
+
+ public static NativeImage rotateTexture(NativeImage image, int degrees) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ NativeImage result = new NativeImage(height, width, false);
+
+ double centerX = width / 2.0;
+ double centerY = height / 2.0;
+ double angle = Math.toRadians(degrees);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int newX = (int)((x - centerX) * Math.cos(angle) - (y - centerY) * Math.sin(angle) + centerX);
+ int newY = (int)((x - centerX) * Math.sin(angle) + (y - centerY) * Math.cos(angle) + centerY);
+
+ if (newX >= 0 && newX < width && newY >= 0 && newY < height) {
+ result.setColor(newY, newX, image.getColor(x, y));
+ }
}
- case RIGHT -> {
- textX = x + 18;
- textY = y + (16 - textHeight) / 2;
+ }
+
+ return result;
+ }
+
+ private static NativeImage flipTextureHorizontally(NativeImage image) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ NativeImage result = new NativeImage(width, height, false);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ result.setColor(width - x - 1, y, image.getColor(x, y));
}
}
- // Draw semi-opaque black rectangle
- if (text != null) {
- if (textBackground && !text.trim().isEmpty()) {
- int backgroundColor = 0x40000000; // ARGB format: 50% opaque black
- drawContext.fill(textX - 1, textY - 1, textX + textWidth + 1, textY + textHeight + 1, backgroundColor);
+ return result;
+ }
+
+ private static NativeImage flipTextureVertically(NativeImage image) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ NativeImage result = new NativeImage(width, height, false);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ result.setColor(x, height - y - 1, image.getColor(x, y));
}
- // Draw the scaled text at the calculated position
- drawContext.getMatrices().push();
- drawContext.getMatrices().scale(scale, scale, 1.0f);
- float scaledX = textX / scale;
- float scaledY = textY / scale;
- drawContext.drawText(textRenderer, text, (int) scaledX, (int) scaledY, color, false);
- drawContext.getMatrices().pop();
}
- // Draw the item texture
- drawContext.drawItem(itemStack, x, y);
+
+ return result;
}
- /**
- * Draws an item texture on the screen with text at a specified position relative to it.
- *
- * @param itemScale The scale for the item to be rendered at
- * @param textRenderer The text renderer instance used for rendering the text
- * @param itemStack The item stack to render the texture for
- * @param x The x position to draw the texture at
- * @param y The y position to draw the texture at
- * @param text The text to draw relative to the texture
- * @param color The color to draw the text with
- * @param position The position of the text relative to the texture (ABOVE, BELOW, LEFT, or RIGHT)
- * @param textScale The scale factor to apply to the text (1.0 is normal size)
- */
- public static void drawItemTextureWithTextAndScale(DrawContext drawContext,
- float itemScale,
- TextRenderer textRenderer,
- ItemStack itemStack,
- int x,
- int y,
- String text,
- int color,
- Position position,
- float textScale,
- boolean textBackground) {
- if (text != null && !text.trim().isEmpty()) {
- // Calculate the position of the text based on its size and the specified position
- int textWidth = (int) (textRenderer.getWidth(text) * textScale);
- int textHeight = (int) (textRenderer.fontHeight * textScale);
- int textX = switch (position) {
- case ABOVE, BELOW -> x + (int) ((16 * itemScale - textWidth) / 2);
- case LEFT -> x - textWidth - 2;
- case RIGHT -> x + (int) (16 * itemScale + 2);
- };
- int textY = switch (position) {
- case ABOVE -> y - textHeight - 2;
- case BELOW -> y + (int) (16 * itemScale + 2);
- case LEFT, RIGHT -> y + (int) ((16 * itemScale - textHeight) / 2);
- };
-
- // Draw semi-opaque black rectangle
- if (textBackground) {
- int backgroundColor = 0x40000000; // ARGB format: 50% opaque black
- drawContext.fill(textX, textY - 1, textX + textWidth + 1, textY + textHeight + 1, backgroundColor);
+ public static NativeImage flipTexture(NativeImage image, boolean flipVertically) {
+ if (flipVertically) {
+ return flipTextureVertically(image);
+ } else {
+ return flipTextureHorizontally(image);
+ }
+ }
+
+ public static NativeImage applyGrayScaleFilter(NativeImage image) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ NativeImage result = new NativeImage(width, height, false);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int argb = image.getColor(x, y);
+
+ int alpha = (argb >> 24) & 0xFF;
+ int red = (argb >> 16) & 0xFF;
+ int green = (argb >> 8) & 0xFF;
+ int blue = argb & 0xFF;
+
+ int gray = (red + green + blue) / 3;
+ int newArgb = (alpha << 24) | (gray << 16) | (gray << 8) | gray;
+
+ result.setColor(x, y, newArgb);
}
+ }
+
+ return result;
+ }
+ public static NativeImage cropTexture(NativeImage image, int x, int y, int width, int height) {
+ NativeImage result = new NativeImage(width, height, false);
- // Draw the scaled text at the calculated position
- drawContext.getMatrices().push();
- drawContext.getMatrices().scale(textScale, textScale, 11.0f);
- float scaledX = textX / textScale;
- float scaledY = textY / textScale;
- drawContext.drawText(textRenderer, text, (int) scaledX + 1, (int) scaledY +1, color, false);
- drawContext.getMatrices().pop();
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ result.setColor(j, i, image.getColor(x + j, y + i));
+ }
}
- customItemRenderer = new CustomItemRenderer(itemStack, itemScale);
- customItemRenderer.draw(drawContext, x, y, color);
+
+ return result;
}
- public enum Position {
- ABOVE("Above"),
- RIGHT("Right"),
- BELOW("Below"),
- LEFT("Left");
- private final String name;
+ public static NativeImage tintTexture(NativeImage image, int color) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ NativeImage result = new NativeImage(width, height, false);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int argb = image.getColor(x, y);
+
+ int alpha = (argb >> 24) & 0xFF;
+ int red = ((argb >> 16) & 0xFF) * ((color >> 16) & 0xFF) / 255;
+ int green = ((argb >> 8) & 0xFF) * ((color >> 8) & 0xFF) / 255;
+ int blue = (argb & 0xFF) * (color & 0xFF) / 255;
- Position(String name) {
- this.name = name;
+ int newArgb = (alpha << 24) | (red << 16) | (green << 8) | blue;
+
+ result.setColor(x, y, newArgb);
+ }
}
- public static Position getByUpperCaseName(String name) {
- if (name == null || name.isEmpty()) {
- return null;
+ return result;
+ }
+
+ public static NativeImage overlayTexture(NativeImage image, NativeImage overlay) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+ NativeImage result = new NativeImage(width, height, false);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int argb1 = image.getColor(x, y);
+ int argb2 = overlay.getColor(x, y);
+
+ int alpha = Math.max((argb1 >> 24) & 0xFF, (argb2 >> 24) & 0xFF);
+ int red = Math.min(255, ((argb1 >> 16) & 0xFF) + ((argb2 >> 16) & 0xFF));
+ int green = Math.min(255, ((argb1 >> 8) & 0xFF) + ((argb2 >> 8) & 0xFF));
+ int blue = Math.min(255, (argb1 & 0xFF) + (argb2 & 0xFF));
+
+ int newArgb = (alpha << 24) | (red << 16) | (green << 8) | blue;
+
+ result.setColor(x, y, newArgb);
}
+ }
+
+ return result;
+ }
+
+ public static int getAverageColor(NativeImage image) {
+ long redTotal = 0;
+ long greenTotal = 0;
+ long blueTotal = 0;
+ int pixelCount = image.getWidth() * image.getHeight();
- return Position.valueOf(name.toUpperCase());
+ for (int y = 0; y < image.getHeight(); y++) {
+ for (int x = 0; x < image.getWidth(); x++) {
+ int argb = image.getColor(x, y);
+
+ redTotal += (argb >> 16) & 0xFF;
+ greenTotal += (argb >> 8) & 0xFF;
+ blueTotal += argb & 0xFF;
+ }
}
+
+ int redAverage = (int)(redTotal / pixelCount);
+ int greenAverage = (int)(greenTotal / pixelCount);
+ int blueAverage = (int)(blueTotal / pixelCount);
+
+ return (redAverage << 16) | (greenAverage << 8) | blueAverage;
}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/huds/AbstractMoveableScreen.java b/src/main/java/com/tanishisherewith/dynamichud/huds/AbstractMoveableScreen.java
deleted file mode 100644
index 5d33fb5..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/huds/AbstractMoveableScreen.java
+++ /dev/null
@@ -1,214 +0,0 @@
-package com.tanishisherewith.dynamichud.huds;
-
-import com.tanishisherewith.dynamichud.handlers.DefaultDragHandler;
-import com.tanishisherewith.dynamichud.handlers.DefaultMouseHandler;
-import com.tanishisherewith.dynamichud.handlers.DragHandler;
-import com.tanishisherewith.dynamichud.handlers.MouseHandler;
-import com.tanishisherewith.dynamichud.util.DynamicUtil;
-import com.tanishisherewith.dynamichud.util.colorpicker.ColorGradientPicker;
-import com.tanishisherewith.dynamichud.util.contextmenu.ContextMenu;
-import com.tanishisherewith.dynamichud.widget.Widget;
-import com.tanishisherewith.dynamichud.widget.slider.SliderWidget;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.text.Text;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-public abstract class AbstractMoveableScreen extends Screen {
- protected final DynamicUtil dynamicutil; // The DynamicUtil instance used by this screen
- protected MinecraftClient mc = MinecraftClient.getInstance();
- protected Widget selectedWidget = null; // The currently selected widget
- protected int dragStartX = 0, dragStartY = 0; // The starting position of a drag operation
- protected List contextMenus = new ArrayList<>(); // The context menu that is currently displayed
- protected ColorGradientPicker colorPicker = null; // The color picker that is currently displayed
- protected Widget sliderWigdet = null; // The widget that is currently being edited by the slider
- protected List Sliders = new ArrayList<>(); // The List of sliders
- protected MouseHandler mouseHandler;
- protected DragHandler dragHandler;
- protected int gridSize = 3; // The size of each grid cell in pixels
- protected boolean ShouldPause = false; // To pause if the screen is opened or not
- protected boolean ShouldBeAffectedByResize = false; // If the stuff drawn on screen to be affected by screen resize or not
- protected int widgetX;
- protected int widgetY;
-
-
- /**
- * Constructs a AbstractMoveableScreen object.
- *
- * @param dynamicutil The DynamicUtil instance used by this screen
- */
- public AbstractMoveableScreen(Text title, DynamicUtil dynamicutil) {
- super(title);
- this.dynamicutil = dynamicutil;
- updateMouseHandler(this.colorPicker, contextMenus, Sliders);
- dragHandler = new DefaultDragHandler();
- }
-
- /**
- * Handles mouse dragging on this screen.
- *
- * @param mouseX - Current X position of mouse cursor.
- * @param mouseY - Current Y position of mouse cursor.
- * @param button - Mouse button being dragged.
- * @param deltaX - Change in X position since last call to this method.
- * @param deltaY - Change in Y position since last call to this method.
- * @return true if mouse dragging was handled by this screen.
- */
- @Override
- public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
- if (mouseHandler.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) {
- return true;
- }
- if (selectedWidget != null && selectedWidget.isDraggable) {
- // Update the position of the widget while dragging
- int newX = (int) (mouseX - dragStartX);
- int newY = (int) (mouseY - dragStartY);
-
- // Snap the widget to the grid
- newX = (newX / gridSize) * gridSize;
- newY = (newY / gridSize) * gridSize;
-
- selectedWidget.setX(newX);
- selectedWidget.setY(newY);
- return true;
- }
- return false;
- }
-
- /**
- * Handles mouse clicks on this screen.
- *
- * @param mouseX - X position of mouse cursor.
- * @param mouseY - Y position of mouse cursor.
- * @param button - Mouse button that was clicked.
- * @return true if mouse click was handled by this screen, false otherwise.
- */
- @Override
- public boolean mouseClicked(double mouseX, double mouseY, int button) {
- if (mouseHandler.mouseClicked(mouseX, mouseY, button)) {
- return true;
- }
-
- for (Widget widget : dynamicutil.getWidgetManager().getWidgets()) {
- if (widget.getWidgetBox().contains(widget, mouseX, mouseY, Widget.getScale())) {
- // Start dragging the widget
- colorPicker = null;
- contextMenus.clear();
- Sliders.clear();
- if (button == 1) { // Right-click
- handleRightClickOnWidget(widget);
- } else if (button == 0) {
- widget.enabled = !widget.enabled;
- }
- if (dragHandler.startDragging(widget, mouseX, mouseY) && button == 0 && widget.isDraggable) {
- selectedWidget = widget;
- for (ContextMenu contextmenu : contextMenus) {
- contextmenu.updatePosition();
- }
- for (SliderWidget sliderWidget : Sliders) {
- sliderWidget.updatePosition();
- }
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Handles mouse release events on this screen.
- *
- * @param mouseX The current x position of the mouse cursor
- * @param mouseY The current y position of the mouse cursor
- * @param button The mouse button that was released
- * @return True if the mouse release event was handled by this screen, false otherwise
- */
- @Override
- public boolean mouseReleased(double mouseX, double mouseY, int button) {
- // Stop dragging or scaling the widget
- if (mouseHandler.mouseReleased(mouseX, mouseY, button)) {
- return true;
- }
- if (selectedWidget != null) {
- selectedWidget = null;
- return true;
- }
- return contextMenus != null;
- }
-
- /**
- * Renders this screen and its widgets on the screen.
- *
- * @param drawContext The matrix stack used for rendering
- * @param mouseX The current x position of the mouse cursor
- * @param mouseY The current y position of the mouse cursor
- * @param delta The time elapsed since the last frame in seconds
- */
- @Override
- public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) {
- super.render(drawContext, mouseX, mouseY, delta);
-
- // Draw each widget
- for (Widget widget : dynamicutil.getWidgetManager().getWidgets()) {
- widget.render(drawContext);
- }
-
- // Draw the slider and other stuff
- for (SliderWidget sliderWidget : Sliders) {
- sliderWidget.render(drawContext);
- }
- for (ContextMenu contextMenu : contextMenus) {
- contextMenu.render(drawContext);
- }
-
- if (colorPicker != null) {
- colorPicker.render(drawContext);
- }
-
- if (selectedWidget != null) {
- widgetX = selectedWidget.getX();
- widgetY = selectedWidget.getY();
- }
-
- updateMouseHandler(colorPicker, contextMenus, Sliders);
- }
-
- private void updateMouseHandler(ColorGradientPicker colorPicker, List contextMenus, List Sliders) {
- this.colorPicker = colorPicker;
- this.contextMenus = contextMenus;
- this.Sliders = Sliders;
- mouseHandler = new DefaultMouseHandler(colorPicker, contextMenus, Sliders);
- }
-
- public void setGridSize(int gridSize) {
- this.gridSize = gridSize;
- }
-
- public void setShouldPause(boolean shouldpause) {
- this.ShouldPause = shouldpause;
- }
-
- public void setShouldBeAffectedByResize(boolean shouldBeAffectedByResize) {
- this.ShouldBeAffectedByResize = shouldBeAffectedByResize;
- }
-
- @Override
- public void resize(MinecraftClient client, int width, int height) {
- if (ShouldBeAffectedByResize)
- super.resize(client, width, height);
- }
-
- @Override
- public boolean shouldPause() {
- return ShouldPause;
- }
-
- protected abstract boolean handleRightClickOnWidget(Widget widget);
-
- protected abstract void menu(Widget widget, int x, int y);
-}
-
diff --git a/src/main/java/com/tanishisherewith/dynamichud/huds/MoveableScreen.java b/src/main/java/com/tanishisherewith/dynamichud/huds/MoveableScreen.java
deleted file mode 100644
index 58c7a07..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/huds/MoveableScreen.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package com.tanishisherewith.dynamichud.huds;
-
-import com.tanishisherewith.dynamichud.helpers.ColorHelper;
-import com.tanishisherewith.dynamichud.helpers.TextureHelper;
-import com.tanishisherewith.dynamichud.util.DynamicUtil;
-import com.tanishisherewith.dynamichud.util.colorpicker.ColorGradientPicker;
-import com.tanishisherewith.dynamichud.util.contextmenu.ContextMenu;
-import com.tanishisherewith.dynamichud.widget.Widget;
-import com.tanishisherewith.dynamichud.widget.armor.ArmorWidget;
-import com.tanishisherewith.dynamichud.widget.item.ItemWidget;
-import com.tanishisherewith.dynamichud.widget.slider.SliderWidget;
-import com.tanishisherewith.dynamichud.widget.slider.SliderWidgetBuilder;
-import com.tanishisherewith.dynamichud.widget.text.TextWidget;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.text.Text;
-
-import java.awt.*;
-
-public class MoveableScreen extends AbstractMoveableScreen {
- SliderWidget SliderWidget;
- /**
- * Constructs a AbstractMoveableScreen object.
- *
- * @param title
- * @param dynamicutil The DynamicUtil instance used by this screen
- */
- public MoveableScreen(Text title, DynamicUtil dynamicutil) {
- super(title, dynamicutil);
- setGridSize(1);
- setShouldPause(false);
- setShouldBeAffectedByResize(false);
- }
-
- @Override
- public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) {
- super.render(drawContext, mouseX, mouseY, delta);
- assert client != null;
- /*SliderWidget = new SliderWidgetBuilder(client)
- .setX(client.getWindow().getScaledWidth() - 120)
- .setY(client.getWindow().getScaledHeight() - 20)
- .setWidth(105)
- .setHeight(10)
- .setLabel("Scale")
- .setValue(Widget.getScale())
- .getValue(Widget::setScale)
- .setMinValue(0.5f)
- .setMaxValue(4f)
- .setSelectedWidget(null)
- .build();*/
- drawContext.drawTextWithShadow(textRenderer, "Editors Screen", (int) (MinecraftClient.getInstance().getWindow().getScaledWidth() / 2f - textRenderer.getWidth("Editor Screen") / 2f), 5, ColorHelper.ColorToInt(Color.WHITE));
- // SliderWidget.render(drawContext);
- }
-
- @Override
- protected boolean handleRightClickOnWidget(Widget widget) {
- selectedWidget = widget;
- sliderWigdet = widget;
- // Show context menu
- menu(widget, widgetX, widgetY);
- return true;
- }
-
- @Override
- protected void menu(Widget widget, int x, int y) {
- contextMenus.clear();
- contextMenus.add(new ContextMenu(mc, x, y + widget.getHeight() + 5, selectedWidget, this));
- if (widget instanceof ArmorWidget armorWidget) {
- ArmorWidgetMenu(armorWidget, x, y);
- }
- if (widget instanceof ItemWidget itemWidget) {
- ItemWidgetMenu(itemWidget, x, y);
- }
- if (widget instanceof TextWidget textWidget) {
- TextWidgetMenu(textWidget, x, y);
- }
- }
-
- protected void ItemWidgetMenu(ItemWidget itemWidget, int x, int y) {
- Sliders.clear();
- colorPicker = null;
- contextMenus.clear();
- }
-
- protected void ArmorWidgetMenu(ArmorWidget armorWidget, int x, int y) {
- Sliders.clear();
- contextMenus.get(0).setHeightFromWidget(14);
- contextMenus.get(0).setPadding(5);
- contextMenus.get(0).addEnumCycleOption("", TextureHelper.Position.values(), () -> armorWidget.currentTextPosition[0], newPosition -> {
- armorWidget.currentTextPosition[0] = newPosition;
- });
- }
-
- protected void TextWidgetMenu(TextWidget textWidget, int x, int y) {
- contextMenus.get(0).setHeightFromWidget(2);
- contextMenus.get(0).setPadding(5);
-
- contextMenus.get(0).addOption("Shadow", () -> {
- textWidget.setShadow(!textWidget.hasShadow());
- });
- contextMenus.get(0).addOption("Rainbow", () -> {
- textWidget.setRainbow(!textWidget.hasRainbow());
- });
- if (!textWidget.getText().isEmpty()) {
- contextMenus.get(0).addOption("TextColor", () -> {
- textWidget.toggleTextColorOption();
-
- if (textWidget.isTextcolorOptionEnabled())
- colorPicker = new ColorGradientPicker(mc, widgetX + 110, widgetY + textWidget.getHeight() + 5, textWidget.getTextcolor(), textWidget::setTextColor, 50, 100, selectedWidget);
- else
- colorPicker = null;
- });
- }
- if (!textWidget.getDataText().trim().isEmpty()) {
- contextMenus.get(0).addOption("DataColor", () -> {
- textWidget.toggleDataColorOption();
-
- if (textWidget.isDatacolorOptionEnabled())
- colorPicker = new ColorGradientPicker(mc, widgetX + 110, widgetY + textWidget.getHeight() + 5, textWidget.getDatacolor(), textWidget::setDataColor, 50, 100, selectedWidget);
- else
- colorPicker = null;
- });
- }
- /* contextMenus.get(0).addOption("SubMenu: ",()->
- {
- if (contextMenus.size()>1) contextMenus.remove(1);
- contextMenus.add(new ContextMenu(mc, contextMenus.get(0).getX() + 40, contextMenus.get(0).getOptionY(6), selectedWidget,this));
- contextMenus.get(1).addOption("Option: 1",()->System.out.println("Pressed 1 "));
- contextMenus.get(1).addOption("Option: 2",()->System.out.println("Pressed 2 "));
- contextMenus.get(1).addOption("Option: 3",()->System.out.println("Pressed 3 "));
- });
- contextMenus.get(0).addDataTextOption(("Enter data"), data -> {
- System.out.println("Entered data: " + data);
- },widgetX,widgetY);
- contextMenus.get(0).addDoubleTextOption(("Enter double"), data -> {
- System.out.println("Entered data: " + data);
- },widgetX,widgetY);*/
-
- SliderWidget sliderWidget =new SliderWidgetBuilder(client)
- .setX(x)
- .setY(y)
- .setWidth(105)
- .setHeight(contextMenus.get(0).getHeight() + 7)
- .setLabel("Rainbow Speed")
- .setValue(textWidget.getRainbowSpeed())
- .setMinValue(5f)
- .setMaxValue(25.0f)
- .getValue(TextWidget::setRainbowSpeed)
- .setSelectedWidget(selectedWidget)
- .build();
- Sliders.add(sliderWidget);
- }
-
-
- @Override
- public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
- // if(SliderWidget.mouseDragged(mouseX,mouseY,button,deltaX,deltaY))
- //{
- // return true;
- //}
- return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
- }
-
- @Override
- public boolean mouseClicked(double mouseX, double mouseY, int button) {
- // if(SliderWidget.mouseClicked(mouseX,mouseY,button))
- // {
- // SliderWidget.updatePosition();
- // return true;
- // }
- return super.mouseClicked(mouseX, mouseY, button);
- }
-}
-
-
diff --git a/src/main/java/com/tanishisherewith/dynamichud/interfaces/IWigdets.java b/src/main/java/com/tanishisherewith/dynamichud/interfaces/IWigdets.java
deleted file mode 100644
index d27675e..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/interfaces/IWigdets.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.tanishisherewith.dynamichud.interfaces;
-
-import com.tanishisherewith.dynamichud.util.DynamicUtil;
-
-public interface IWigdets {
-
- void addWigdets(DynamicUtil dynamicUtil);
-
- void addMainMenuWigdets(DynamicUtil dynamicUtil);
-
- void loadWigdets(DynamicUtil dynamicUtil);
-}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/interfaces/TextGenerator.java b/src/main/java/com/tanishisherewith/dynamichud/interfaces/TextGenerator.java
deleted file mode 100644
index 009f0dc..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/interfaces/TextGenerator.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.tanishisherewith.dynamichud.interfaces;
-
-@FunctionalInterface
-public interface TextGenerator {
- String generateText();
-}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/interfaces/WidgetLoading.java b/src/main/java/com/tanishisherewith/dynamichud/interfaces/WidgetLoading.java
deleted file mode 100644
index fe7a7be..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/interfaces/WidgetLoading.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.tanishisherewith.dynamichud.interfaces;
-
-import com.tanishisherewith.dynamichud.helpers.TextureHelper;
-import com.tanishisherewith.dynamichud.widget.Widget;
-import com.tanishisherewith.dynamichud.widget.armor.ArmorWidget;
-import com.tanishisherewith.dynamichud.widget.item.ItemWidget;
-import com.tanishisherewith.dynamichud.widget.text.TextWidget;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.entity.EquipmentSlot;
-import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.NbtCompound;
-
-import java.awt.*;
-
-public interface WidgetLoading {
- default Widget loadWidgetsFromTag(String className, NbtCompound widgetTag) {
- if (className.equals(TextWidget.class.getName())) {
- TextWidget widget = new TextWidget(MinecraftClient.getInstance(), "", () -> "", 0, 0, false, false, -1, -1, true);
- widget.readFromTag(widgetTag);
- return widget;
- }
- if (className.equals(ArmorWidget.class.getName())) {
- ArmorWidget widget = new ArmorWidget(MinecraftClient.getInstance(), EquipmentSlot.CHEST, 0, 0, false, TextureHelper.Position.ABOVE, () -> "", () -> Color.RED, true, "");
- widget.readFromTag(widgetTag);
- return widget;
- }
- if (className.equals(ItemWidget.class.getName())) {
- ItemWidget widget = new ItemWidget(MinecraftClient.getInstance(), () -> ItemStack.EMPTY, 0, 0, true, TextureHelper.Position.ABOVE, () -> "", () -> Color.WHITE, true, "");
- widget.readFromTag(widgetTag);
- return widget;
- }
- return null;
- }
-}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java
deleted file mode 100644
index 345e818..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.tanishisherewith.dynamichud.mixins;
-
-
-import com.tanishisherewith.dynamichud.widget.Widget;
-import com.tanishisherewith.dynamichud.widget.slider.ScaleSliderWidget;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.gui.screen.option.OptionsScreen;
-import net.minecraft.client.gui.widget.EmptyWidget;
-import net.minecraft.client.gui.widget.GridWidget;
-import net.minecraft.client.gui.widget.SimplePositioningWidget;
-import net.minecraft.client.option.GameOptions;
-import net.minecraft.text.Text;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import java.text.DecimalFormat;
-@Mixin(OptionsScreen.class)
-public class OptionsScreenMixin extends Screen {
- private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##");
- private final GameOptions settings = MinecraftClient.getInstance().options;
-
-
- protected OptionsScreenMixin(Text title) {
- super(title);
- }
-
- @Inject(at = @At("TAIL"), method = "init")
- public void addButtons(CallbackInfo ci) {
- int width = 100;
- int height = 20;
- int x = this.width - width - 10;
- int y = this.height - height- 5;
- String formattedValue = DECIMAL_FORMAT.format(Widget.getScale());
- ScaleSliderWidget scaleSlider = new ScaleSliderWidget(x, y, width, height, Text.of("Widgets Scale: " + formattedValue), Widget.getScale(), 0.5f, 3f);
- this.addDrawableChild(scaleSlider);
- }
-}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java
new file mode 100644
index 0000000..1ce36e5
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java
@@ -0,0 +1,41 @@
+package com.tanishisherewith.dynamichud.mixins;
+
+import com.tanishisherewith.dynamichud.DynamicHUD;
+import com.tanishisherewith.dynamichud.widget.WidgetManager;
+import com.tanishisherewith.dynamichud.widget.WidgetRenderer;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.Screen;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(Screen.class)
+public abstract class ScreenMixin {
+ @Shadow
+ public int width;
+
+ @Shadow
+ public int height;
+
+ @Inject(at = @At("TAIL"), method = "render")
+ private void render(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
+ for (WidgetRenderer widgetRenderer : DynamicHUD.getWidgetRenderers()) {
+ widgetRenderer.renderWidgets(context, mouseX, mouseY);
+ }
+ }
+
+ @Inject(at = @At("HEAD"), method = "resize")
+ private void onScreenResize(MinecraftClient client, int width, int height, CallbackInfo ci) {
+ WidgetManager.onScreenResized(width, height, this.width, this.height);
+ }
+
+ @Inject(at = @At("HEAD"), method = "close")
+ private void onClose(CallbackInfo ci) {
+ for (WidgetRenderer widgetRenderer : DynamicHUD.getWidgetRenderers()) {
+ widgetRenderer.onCloseScreen();
+ }
+ }
+}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/TitleScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/TitleScreenMixin.java
deleted file mode 100644
index 6abfe5e..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/mixins/TitleScreenMixin.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package com.tanishisherewith.dynamichud.mixins;
-
-import com.tanishisherewith.dynamichud.DynamicHUD;
-import com.tanishisherewith.dynamichud.handlers.DefaultDragHandler;
-import com.tanishisherewith.dynamichud.handlers.DefaultMouseHandler;
-import com.tanishisherewith.dynamichud.handlers.DragHandler;
-import com.tanishisherewith.dynamichud.handlers.MouseHandler;
-import com.tanishisherewith.dynamichud.util.DynamicUtil;
-import com.tanishisherewith.dynamichud.widget.Widget;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.gui.screen.TitleScreen;
-import net.minecraft.text.Text;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-@Mixin(TitleScreen.class)
-public abstract class TitleScreenMixin extends Screen {
- protected MouseHandler mouseHandler = new DefaultMouseHandler(null, null, null);
- protected DragHandler dragHandler = new DefaultDragHandler();
- protected Widget selectedWidget;
- protected int dragStartX = 0, dragStartY = 0; // The starting position of a drag operation
- protected int gridSize = 1; // The size of each grid cell in pixels
- DynamicUtil dynamicUtil = DynamicHUD.getDynamicUtil();
-
- protected TitleScreenMixin(Text title) {
- super(title);
- }
-
- public void setGridSize(int gridSize) {
- this.gridSize = gridSize;
- }
-
- @Inject(at = @At("TAIL"), method = "render")
- private void render(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
- // Draw custom text on the title screen
- if (dynamicUtil != null && (dynamicUtil.MainMenuWidgetAdded || dynamicUtil.WidgetLoaded)) {
- dynamicUtil.render(context, delta);
- }
- }
-
- @Override
- public boolean mouseClicked(double mouseX, double mouseY, int button) {
- if (mouseHandler.mouseClicked(mouseX, mouseY, button)) {
- return true;
- }
-
- for (Widget widget : dynamicUtil.getWidgetManager().getMainMenuWidgets()) {
- if (widget.getWidgetBox().contains(widget, mouseX, mouseY,widget.getScale())) {
- if (button == 1) { // Right-click
- handleRightClickOnWidget(widget);
- } else if (button == 0) {
- widget.enabled = !widget.enabled;
- }
- if (dragHandler.startDragging(widget, mouseX, mouseY) && button == 0 && widget.isDraggable) {
- selectedWidget = widget;
- return true;
- }
- }
- }
- return super.mouseClicked(mouseX, mouseY, button);
- }
-
-
- @Override
- public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
- if (mouseHandler.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) {
- return true;
- }
- if (selectedWidget != null && selectedWidget.isDraggable) {
- // Update the position of the widget while dragging
- int newX = (int) (mouseX - dragStartX);
- int newY = (int) (mouseY - dragStartY);
-
- // Snap the widget to the grid
- newX = (newX / gridSize) * gridSize;
- newY = (newY / gridSize) * gridSize;
-
- selectedWidget.setX(newX);
- selectedWidget.setY(newY);
- return true;
- }
- return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
- }
-
- @Override
- public boolean mouseReleased(double mouseX, double mouseY, int button) {
- if (mouseHandler.mouseReleased(mouseX, mouseY, button)) {
- return true;
- }
- if (selectedWidget != null) {
- selectedWidget = null;
- return true;
- }
- return super.mouseReleased(mouseX, mouseY, button);
- }
-
- protected void handleRightClickOnWidget(Widget widget) {
-
- }
-
-}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java b/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java
new file mode 100644
index 0000000..9c3bc60
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java
@@ -0,0 +1,103 @@
+package com.tanishisherewith.dynamichud.screens;
+
+import com.tanishisherewith.dynamichud.widget.WidgetRenderer;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.text.Text;
+
+public abstract class AbstractMoveableScreen extends Screen {
+ public final WidgetRenderer widgetRenderer;
+ public int snapSize = 100;
+ protected boolean shouldPause = false; // To pause if the screen is opened or not
+
+ /**
+ * Constructs a AbstractMoveableScreen object.
+ */
+ public AbstractMoveableScreen(Text title, WidgetRenderer renderer) {
+ super(title);
+ this.widgetRenderer = renderer;
+ }
+
+ @Override
+ public void onDisplayed() {
+ super.onDisplayed();
+ widgetRenderer.isInEditor = true;
+ }
+
+ @Override
+ public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
+ widgetRenderer.mouseDragged(mouseX, mouseY, button, snapSize);
+ return false;
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ widgetRenderer.mouseClicked(mouseX, mouseY, button);
+ return false;
+ }
+
+ @Override
+ public boolean mouseReleased(double mouseX, double mouseY, int button) {
+ widgetRenderer.mouseReleased(mouseX, mouseY, button);
+ return false;
+ }
+
+ @Override
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ widgetRenderer.keyPressed(keyCode);
+ return super.keyPressed(keyCode, scanCode, modifiers);
+ }
+
+ @Override
+ public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
+ widgetRenderer.keyReleased(keyCode);
+ return super.keyReleased(keyCode, scanCode, modifiers);
+ }
+
+ @Override
+ public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
+ widgetRenderer.mouseScrolled(mouseX, mouseY, verticalAmount, horizontalAmount);
+ return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
+ }
+
+ /**
+ * Renders this screen and its widgets on the screen.
+ *
+ * @param drawContext The matrix stack used for rendering
+ * @param mouseX The current x position of the mouse cursor
+ * @param mouseY The current y position of the mouse cursor
+ * @param delta The time elapsed since the last frame in seconds
+ */
+ @Override
+ public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) {
+ assert this.client != null;
+ if (this.client.world == null) {
+ this.renderBackgroundTexture(drawContext);
+ }
+ drawContext.drawText(client.textRenderer,title,client.getWindow().getScaledWidth()/2 - client.textRenderer.getWidth(title.getString())/2,textRenderer.fontHeight/2,-1,true);
+
+ // Draw each widget
+ widgetRenderer.renderWidgets(drawContext, mouseX, mouseY);
+ }
+
+ @Override
+ public void close() {
+ widgetRenderer.isInEditor = false;
+ widgetRenderer.onCloseScreen();
+ super.close();
+ }
+
+ public void setShouldPause(boolean shouldPause) {
+ this.shouldPause = shouldPause;
+ }
+
+ @Override
+ public boolean shouldPause() {
+ return shouldPause;
+ }
+
+ public void setSnapSize(int size) {
+ this.snapSize = size;
+ }
+}
+
diff --git a/src/main/java/com/tanishisherewith/dynamichud/util/CustomItemRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/util/CustomItemRenderer.java
deleted file mode 100644
index d5beee6..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/util/CustomItemRenderer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.tanishisherewith.dynamichud.util;
-
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.font.TextRenderer;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.render.item.ItemRenderer;
-import net.minecraft.item.ItemStack;
-
-public class CustomItemRenderer {
- private final ItemStack itemStack; // The text renderer instance
- private final float scale; // The scaling factor of the text
-
- /**
- * Constructs a CustomTextRenderer object.
- *
- * @param stack The stack to render
- * @param scale The scaling factor of the text
- */
- public CustomItemRenderer(ItemStack stack, float scale) {
- // The Minecraft client instance
- this.itemStack = stack;
- this.scale = scale;
- }
-
- /**
- * Draws a text with shadow on the screen with the given parameters.
- *
- * @param context The drawContext to use for rendering
- * @param x The x position of the text in pixels
- * @param y The y position of the text in pixels
- * @param color The color of the text in ARGB format
- */
- public void draw(DrawContext context, int x, int y, int color) {
- context.getMatrices().push(); // Pushes the current matrix onto the stack
- context.getMatrices().scale(scale, scale, scale); // Scales the matrix by the scaling factor
- context.drawItem(itemStack,(int) (x/scale), (int) (y/scale),color);
- context.getMatrices().pop(); // Pops the current matrix from the stack and restores the previous one
- }
-}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/util/CustomTextRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/util/CustomTextRenderer.java
deleted file mode 100644
index 0bb0621..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/util/CustomTextRenderer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.tanishisherewith.dynamichud.util;
-
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.font.TextRenderer;
-import net.minecraft.client.gui.DrawContext;
-
-public class CustomTextRenderer {
- private final TextRenderer textRenderer; // The text renderer instance
- private final float scale; // The scaling factor of the text
-
- /**
- * Constructs a CustomTextRenderer object.
- *
- * @param client The Minecraft client instance
- * @param scale The scaling factor of the text
- */
- public CustomTextRenderer(MinecraftClient client, float scale) {
- // The Minecraft client instance
- this.textRenderer = client.textRenderer;
- this.scale = scale;
- }
-
- /**
- * Draws a text with shadow on the screen with the given parameters.
- *
- * @param context The drawContext to use for rendering
- * @param text The text to draw
- * @param x The x position of the text in pixels
- * @param y The y position of the text in pixels
- * @param color The color of the text in ARGB format
- */
- public void draw(DrawContext context, String text, int x, int y, int color, boolean shadow) {
- context.getMatrices().push(); // Pushes the current matrix onto the stack
- context.getMatrices().scale(scale, scale, scale); // Scales the matrix by the scaling factor
- context.drawText(textRenderer,text, (int) (x/scale), (int) (y/scale),color,shadow);
- context.getMatrices().pop(); // Pops the current matrix from the stack and restores the previous one
- }
-}
-
diff --git a/src/main/java/com/tanishisherewith/dynamichud/util/DynamicUtil.java b/src/main/java/com/tanishisherewith/dynamichud/util/DynamicUtil.java
deleted file mode 100644
index 742792b..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/util/DynamicUtil.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package com.tanishisherewith.dynamichud.util;
-
-
-import com.tanishisherewith.dynamichud.helpers.ColorHelper;
-import com.tanishisherewith.dynamichud.helpers.DrawHelper;
-import com.tanishisherewith.dynamichud.huds.AbstractMoveableScreen;
-import com.tanishisherewith.dynamichud.widget.Widget;
-import com.tanishisherewith.dynamichud.widget.WidgetBox;
-import com.tanishisherewith.dynamichud.widget.WidgetManager;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.gui.screen.TitleScreen;
-import net.minecraft.client.option.KeyBinding;
-import net.minecraft.client.render.BufferBuilder;
-import net.minecraft.client.render.VertexConsumerProvider;
-
-import java.util.Set;
-
-
-/**
- * This class provides utility methods for working with the DynamicHUD mod.
- */
-public class DynamicUtil extends DrawContext {
- static MinecraftClient client = MinecraftClient.getInstance();
- private final WidgetManager widgetManager; // The WidgetManager instance used by this class
- public boolean WidgetAdded = false;
- public boolean MainMenuWidgetAdded = false;
- public boolean WidgetLoaded = false;
-
-
- /**
- * Constructs a DynamicUtil object.
- *
- * @param client The Minecraft client instance
- */
- public DynamicUtil(MinecraftClient client) {
- super(client, VertexConsumerProvider.immediate(new BufferBuilder(3)));
- this.widgetManager = new WidgetManager();
- }
-
- /**
- * Opens the MoveScreen when the specified key is pressed.
- *
- * @param key The key to listen for
- * @param screen The AbstractMoveableScreen instance to use to set the screen
- */
- public static void openDynamicScreen(KeyBinding key, AbstractMoveableScreen screen) {
- if (key.wasPressed()) {
- client.setScreen(screen);
- }
- }
-
- /**
- * Renders widgets on screen.
- *
- * @param context - MatrixStack used for rendering.
- * @param delta - Time elapsed since last frame in seconds.
- */
- public void render(DrawContext context, float delta) {
- Set mainMenuWidgets = widgetManager.getMainMenuWidgets();
- Set widgets = widgetManager.getWidgets();
-
- if (client.currentScreen instanceof TitleScreen) {
- // Draw each Menu widget
- for (Widget widget : mainMenuWidgets) {
- widget.render(context);
- widget.updatePosition();
- int backgroundColor = widget.isEnabled() ? ColorHelper.getColor(0, 0, 0, 128) : ColorHelper.getColor(255, 0, 0, 128);
- WidgetBox box = widget.getWidgetBox();
- DrawHelper.fill(context, (int) (box.x1 - 2), (int) (box.y1 - 2), (int) (box.x2 + 2), (int) (box.y2 + 2), backgroundColor);
- }
- return;
- }
-
- // Draw each widget
- if (!client.options.debugEnabled || client.currentScreen instanceof AbstractMoveableScreen) {
- for (Widget widget : widgets) {
- if (client.currentScreen instanceof AbstractMoveableScreen) {
- widget.render(context);
- } else if (widget.isEnabled()) {
- widget.render(context);
- }
- // Draw a red box around the widget if the HUD is disabled
- if (client.currentScreen instanceof AbstractMoveableScreen) {
- int backgroundColor = widget.isEnabled() ? ColorHelper.getColor(0, 0, 0, 128) : ColorHelper.getColor(255, 0, 0, 128);
- WidgetBox box = widget.getWidgetBox();
- DrawHelper.fill(context, (int) (box.x1 - 2), (int) (box.y1 - 2), (int) (box.x2 + 2), (int) (box.y2 + 2), backgroundColor);
- }
- widget.updatePosition();
- }
- }
- }
-
-
- /**
- * Returns WidgetManager instance used by this class.
- *
- * @return WidgetManager instance used by this class.
- */
- public WidgetManager getWidgetManager() {
- return widgetManager;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/tanishisherewith/dynamichud/util/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/util/contextmenu/ContextMenu.java
deleted file mode 100644
index e76e540..0000000
--- a/src/main/java/com/tanishisherewith/dynamichud/util/contextmenu/ContextMenu.java
+++ /dev/null
@@ -1,442 +0,0 @@
-package com.tanishisherewith.dynamichud.util.contextmenu;
-
-import com.tanishisherewith.dynamichud.helpers.ColorHelper;
-import com.tanishisherewith.dynamichud.helpers.DrawHelper;
-import com.tanishisherewith.dynamichud.widget.Widget;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.font.TextRenderer;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.gui.screen.Screen;
-
-import java.awt.*;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-
-public class ContextMenu {
- private static int optionY;
- private final MinecraftClient client; // The Minecraft client instance
- private final List options = new ArrayList<>(); // The list of options in the context menu
- private final Widget selectedWidget; // The widget that this context menu is associated with
- private final Screen parentScreen;
- private int width = 0; // The width of the context menu
- private int x; // The x position of the context menu
- private int y; // The y position of the context menu
- private int backgroundColor = 0x90C0C0C0;// Semi-transparent light grey color
- private int padding = 5; // The amount of padding around the rectangle
- private int HeightFromWidget = 5; // The amount of padding around the rectangle
- private float scale = 0.0f;
- private int height = 0;
- private String dataInputValue = "";
- private String doubleInputValue = "";
-
-
- /**
- * Constructs a ContextMenu object.
- *
- * @param client The Minecraft client instance
- * @param x The x position of the context menu
- * @param y The y position of the context menu
- * @param selectedWidget The widget that this context menu is associated with
- */
- public ContextMenu(MinecraftClient client, int x, int y, Widget selectedWidget, Screen parentScreen) {
- this.client = client;
- this.selectedWidget = selectedWidget;
- this.parentScreen = parentScreen;
- this.x = x;
- this.y = Math.round(y + selectedWidget.getWidgetBox().getHeight());
- }
-
- public static int getOptionY() {
- return optionY;
- }
-
- /**
- * Sets the options to enable or disable based on values
- *
- * @param label The label of the option
- * @param option Context Menu options
- */
- public void setOptions(String label, ContextMenuOption option) {
- if (selectedWidget instanceof ContextMenuOptionsProvider optionsProvider) {
- option.enabled = optionsProvider.isOptionEnabled(label);
- }
- }
-
- /**
- * Adds an option to the context menu.
- *
- * @param label The label of the option
- * @param action The action to perform when the option is clicked
- */
- public void addOption(String label, Runnable action) {
- ContextMenuOption option = new ContextMenuOption(label, action);
- if (selectedWidget != null) {
- setOptions(label, option);
- }
- options.add(option);
- }
-
- public void addDataTextOption(String label, Consumer action, int WidgetX, int WidgetY) {
- int OptionY = WidgetY + HeightFromWidget + 2;
- WidgetX += client.textRenderer.getWidth(label + dataInputValue);
- OptionY += options.size() * (client.textRenderer.fontHeight + 2);
- DataInputOption option = new DataInputOption(label + dataInputValue, text -> {
- action.accept(text);
- dataInputValue = text;
- }, WidgetX, OptionY);
- if (selectedWidget != null) {
- setOptions(label, option);
- }
- options.add(option);
- }
-
- public void addDoubleTextOption(String label, Consumer action, int WidgetX, int WidgetY) {
- int OptionY = WidgetY + HeightFromWidget + 2;
- WidgetX += client.textRenderer.getWidth(label + dataInputValue);
- OptionY += options.size() * (client.textRenderer.fontHeight + 2);
- DoubleInputOption option = new DoubleInputOption(label + doubleInputValue, text -> {
- action.accept(text);
- doubleInputValue = String.valueOf(text);
- }, WidgetX, OptionY);
- if (selectedWidget != null) {
- setOptions(label, option);
- }
- options.add(option);
- }
-
- public void setBackgroundColor(int backgroundColor) {
- this.backgroundColor = backgroundColor;
- }
-
- /**
- * Returns whether the given point is within the bounds of this context menu.
- *
- * @param x - X position of the point.
- * @param y - Y position of the point.
- * @return true if the point is within the bounds of this context menu, false otherwise.
- */
- public boolean contains(double x, double y) {
- return x >= this.x - 3 && x <= this.x + width + 13 && y >= this.y + HeightFromWidget - 3 && y <= this.y + height + HeightFromWidget + 3;
- }
-
- public int getX() {
- return x;
- }
-
- public int getY() {
- return y;
- }
-
- public int getWidth() {
- return width;
- }
-
- public Screen getParentScreen() {
- return parentScreen;
- }
-
- public Widget getSelectedWidget() {
- return selectedWidget;
- }
-
- public float getScale() {
- return scale;
- }
-
- public int getHeight() {
- return height;
- }
-
- public int getOptionY(int optionIndex) {
- int OptionY = y + HeightFromWidget + 2;
- OptionY += optionIndex * (client.textRenderer.fontHeight + 2);
- return OptionY;
- }
-
- /**
- * Adds an option to the context menu that cycles through the values of an enum.
- *
+ */
+public class DynamicValueRegistry extends System {
+ /**
+ * A map that holds the global registry of suppliers.
+ *
+ * @see #localRegistry
+ */
+ private static final Map> globalRegistry = new HashMap<>();
+
+ /**
+ * A map that holds the local registry of suppliers.
+ *
+ * @see #globalRegistry
+ */
+ private final Map> localRegistry = new HashMap<>();
+
+ /**
+ * Constructor for the DynamicValueRegistry class.
+ *
+ * @param modId The ID of the mod for which this registry is being created. Doesn't need to be modId, it can simply be used as a standard unique identifier string.
+ */
+ public DynamicValueRegistry(String modId) {
+ super(modId);
+ instances.computeIfAbsent(modId, k -> new ArrayList<>()).add(this);
+ }
+
+ /**
+ * Registers a supplier in the global registry.
+ *
+ * @param key The key under which the supplier is to be registered.
+ * @param supplier The supplier to be registered.
+ */
+ public static void registerGlobal(String key, Supplier> supplier) {
+ globalRegistry.put(key, supplier);
+ }
+
+ /**
+ * Retrieves a supplier from the global registry.
+ *
+ * @param key The key of the supplier to be retrieved.
+ * @return The supplier registered under the given key, or null if no such supplier exists.
+ */
+ public static Supplier> getGlobal(String key) {
+ return globalRegistry.get(key);
+ }
+
+ /**
+ * Registers a supplier in the local registry.
+ *
+ * @param key The key under which the supplier is to be registered.
+ * @param supplier The supplier to be registered.
+ */
+ public void registerLocal(String key, Supplier> supplier) {
+ localRegistry.put(key, supplier);
+ }
+
+ /**
+ * Retrieves a supplier from the local registry, falling back to the global registry if necessary.
+ *
+ * @param key The key of the supplier to be retrieved.
+ * @return The supplier registered under the given key, or null if no such supplier exists.
+ */
+ public Supplier> get(String key) {
+ // First, try to get the supplier from the local registry
+ Supplier> supplier = localRegistry.get(key);
+
+ // If the supplier is not in the local registry, try the global registry
+ if (supplier == null) {
+ supplier = globalRegistry.get(key);
+ }
+
+ return supplier;
+ }
+
+ /**
+ * Sets the local registry to the given map.
+ *
+ * @param map The map to be set as the local registry.
+ */
+ public void setLocalRegistry(Map> map) {
+ localRegistry.putAll(map);
+ }
+}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/System.java b/src/main/java/com/tanishisherewith/dynamichud/utils/System.java
new file mode 100644
index 0000000..3cbc6a0
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/utils/System.java
@@ -0,0 +1,23 @@
+package com.tanishisherewith.dynamichud.utils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class System {
+ // A map to store all instances of DynamicValueRegistry by modId
+ protected static final Map> instances = new ConcurrentHashMap<>();
+ protected final String modId;
+
+ public System(String modId) {
+ this.modId = modId;
+ }
+
+ public static List getInstances(String modId) {
+ return instances.get(modId);
+ }
+
+ public String getModId() {
+ return modId;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/UID.java b/src/main/java/com/tanishisherewith/dynamichud/utils/UID.java
new file mode 100644
index 0000000..6a1735f
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/utils/UID.java
@@ -0,0 +1,30 @@
+package com.tanishisherewith.dynamichud.utils;
+
+import java.util.Random;
+
+public class UID {
+ private static final String ALPHANUMERIC = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
+ private static final int LENGTH = 6;
+ private static final Random RANDOM = new Random();
+ public String uniqueID;
+
+ public UID(String id) {
+ this.uniqueID = id;
+ }
+
+ public static UID generate() {
+ StringBuilder sb = new StringBuilder(LENGTH);
+ for (int i = 0; i < LENGTH; i++) {
+ sb.append(ALPHANUMERIC.charAt(RANDOM.nextInt(ALPHANUMERIC.length())));
+ }
+ return new UID(sb.toString());
+ }
+
+ public String getUniqueID() {
+ return uniqueID;
+ }
+
+ public void setUniqueID(String uniqueID) {
+ this.uniqueID = uniqueID;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java
new file mode 100644
index 0000000..b7f2ccc
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java
@@ -0,0 +1,29 @@
+package com.tanishisherewith.dynamichud.utils;
+
+import com.tanishisherewith.dynamichud.DynamicHUD;
+
+public class Util {
+ public static Quadrant getQuadrant(int x, int y) {
+ int screenWidth = DynamicHUD.MC.getWindow().getScaledWidth();
+ int screenHeight = DynamicHUD.MC.getWindow().getScaledHeight();
+
+ if (x < screenWidth / 2) {
+ if (y < screenHeight / 2) {
+ return Quadrant.UPPER_LEFT;
+ } else {
+ return Quadrant.BOTTOM_LEFT;
+ }
+ } else {
+ if (y < screenHeight / 2) {
+ return Quadrant.UPPER_RIGHT;
+ } else {
+ return Quadrant.BOTTOM_RIGHT;
+ }
+ }
+ }
+
+ public enum Quadrant {
+ UPPER_LEFT, UPPER_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT
+ }
+
+}
diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java
new file mode 100644
index 0000000..17d58e4
--- /dev/null
+++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java
@@ -0,0 +1,149 @@
+package com.tanishisherewith.dynamichud.utils.contextmenu;
+
+import com.tanishisherewith.dynamichud.helpers.DrawHelper;
+import net.minecraft.client.gui.DrawContext;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ContextMenu {
+ private final List