Improved Cursors
- Cursor position is now float instead of integer, making movement way smoother - Added a fallback cursor to use in Wayland sessions
@@ -10,6 +10,7 @@
|
||||
package eu.midnightdust.midnightcontrols;
|
||||
|
||||
import eu.midnightdust.lib.util.PlatformFunctions;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -29,6 +30,9 @@ public class MidnightControls {
|
||||
isExtrasLoaded = PlatformFunctions.isModLoaded("midnightcontrols-extra");
|
||||
log("Initializing MidnightControls...");
|
||||
}
|
||||
public static Identifier id(String path) {
|
||||
return Identifier.of(MidnightControlsConstants.NAMESPACE, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message to the terminal.
|
||||
|
||||
@@ -12,7 +12,6 @@ package eu.midnightdust.midnightcontrols.client;
|
||||
import eu.midnightdust.lib.util.PlatformFunctions;
|
||||
import eu.midnightdust.midnightcontrols.ControlsMode;
|
||||
import eu.midnightdust.midnightcontrols.MidnightControls;
|
||||
import eu.midnightdust.midnightcontrols.MidnightControlsConstants;
|
||||
import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
|
||||
import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
|
||||
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
|
||||
@@ -51,25 +50,27 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
*/
|
||||
public class MidnightControlsClient extends MidnightControls {
|
||||
public static boolean lateInitDone = false;
|
||||
public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_up"),
|
||||
public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(id("look_up"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement");
|
||||
public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_right"),
|
||||
public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(id("look_right"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement");
|
||||
public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_down"),
|
||||
public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(id("look_down"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement");
|
||||
public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_left"),
|
||||
public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(id("look_left"),
|
||||
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement");
|
||||
public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "ring"),
|
||||
public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(id("ring"),
|
||||
InputUtil.Type.KEYSYM, InputUtil.UNKNOWN_KEY.getCode(), "key.categories.misc");
|
||||
public static final Identifier CONTROLLER_BUTTONS = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png");
|
||||
public static final Identifier CONTROLLER_EXPANDED = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_expanded.png");
|
||||
public static final Identifier CONTROLLER_AXIS = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_axis.png");
|
||||
public static final Identifier CURSOR_TEXTURE = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/cursor.png");
|
||||
public static final Identifier CONTROLLER_BUTTONS = id("textures/gui/controller_buttons.png");
|
||||
public static final Identifier CONTROLLER_EXPANDED = id("textures/gui/controller_expanded.png");
|
||||
public static final Identifier CONTROLLER_AXIS = id("textures/gui/controller_axis.png");
|
||||
public static final Identifier WAYLAND_CURSOR_TEXTURE_LIGHT = id("cursor/light/mouse_pointer");
|
||||
public static final Identifier WAYLAND_CURSOR_TEXTURE_DARK = id("cursor/dark/mouse_pointer");
|
||||
public static final File MAPPINGS_FILE = new File("config/gamecontrollercustommappings.txt");
|
||||
public static final MinecraftClient client = MinecraftClient.getInstance();
|
||||
public static final MidnightInput input = new MidnightInput();
|
||||
public static final MidnightRing ring = new MidnightRing();
|
||||
public static final MidnightReacharound reacharound = new MidnightReacharound();
|
||||
public static boolean isWayland;
|
||||
private static MidnightControlsHud hud;
|
||||
private static ControlsMode previousControlsMode;
|
||||
|
||||
@@ -87,6 +88,7 @@ public class MidnightControlsClient extends MidnightControls {
|
||||
}, delay, period);
|
||||
|
||||
HudManager.register(hud = new MidnightControlsHud());
|
||||
isWayland = GLFW.glfwGetVersionString().contains("Wayland");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,4 +81,12 @@ public enum VirtualMouseSkin implements Nameable {
|
||||
public static @NotNull Optional<VirtualMouseSkin> byId(@NotNull String id) {
|
||||
return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst();
|
||||
}
|
||||
public String getSpritePath() {
|
||||
return switch (this) {
|
||||
case DEFAULT_LIGHT -> "cursor/light/default";
|
||||
case DEFAULT_DARK -> "cursor/dark/default";
|
||||
case SECOND_LIGHT -> "cursor/light/secondary";
|
||||
case SECOND_DARK -> "cursor/dark/secondary";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,21 +10,34 @@
|
||||
package eu.midnightdust.midnightcontrols.client.gui;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import eu.midnightdust.midnightcontrols.ControlsMode;
|
||||
import eu.midnightdust.midnightcontrols.client.enums.ControllerType;
|
||||
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
|
||||
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
|
||||
import eu.midnightdust.midnightcontrols.client.MidnightInput;
|
||||
import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
|
||||
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
|
||||
import eu.midnightdust.midnightcontrols.client.enums.VirtualMouseSkin;
|
||||
import eu.midnightdust.midnightcontrols.client.util.HandledScreenAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.BufferRenderer;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.render.Tessellator;
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import static eu.midnightdust.midnightcontrols.MidnightControls.id;
|
||||
|
||||
/**
|
||||
* Represents the midnightcontrols renderer.
|
||||
*
|
||||
@@ -192,14 +205,28 @@ public class MidnightControlsRenderer {
|
||||
private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer) {
|
||||
return 15 + 5 + textRenderer.getWidth(action);
|
||||
}
|
||||
public static void renderWaylandCursor(@NotNull DrawContext context, @NotNull MinecraftClient client) {
|
||||
if (MidnightControlsConfig.virtualMouse || client.currentScreen == null || MidnightControlsConfig.controlsMode != ControlsMode.CONTROLLER) return;
|
||||
|
||||
float mouseX = (float) client.mouse.getX() * client.getWindow().getScaledWidth() / client.getWindow().getWidth();
|
||||
float mouseY = (float) client.mouse.getY() * client.getWindow().getScaledHeight() / client.getWindow().getHeight();
|
||||
|
||||
try {
|
||||
Identifier spritePath = MidnightControlsClient.WAYLAND_CURSOR_TEXTURE_LIGHT;
|
||||
if (MidnightControlsConfig.virtualMouseSkin == VirtualMouseSkin.DEFAULT_DARK || MidnightControlsConfig.virtualMouseSkin == VirtualMouseSkin.SECOND_DARK)
|
||||
spritePath = MidnightControlsClient.WAYLAND_CURSOR_TEXTURE_DARK;
|
||||
Sprite sprite = client.getGuiAtlasManager().getSprite(spritePath);
|
||||
drawUnalignedTexturedQuad(sprite.getAtlasId(), context, mouseX, mouseX + 8, mouseY, mouseY + 8, 999, sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV());
|
||||
} catch (IllegalStateException ignored) {}
|
||||
}
|
||||
|
||||
public static void renderVirtualCursor(@NotNull DrawContext context, @NotNull MinecraftClient client) {
|
||||
if (!MidnightControlsConfig.virtualMouse || (client.currentScreen == null
|
||||
|| MidnightInput.isScreenInteractive(client.currentScreen)))
|
||||
return;
|
||||
|
||||
int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth());
|
||||
int mouseY = (int) (client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight());
|
||||
float mouseX = (float) client.mouse.getX() * client.getWindow().getScaledWidth() / client.getWindow().getWidth();
|
||||
float mouseY = (float) client.mouse.getY() * client.getWindow().getScaledHeight() / client.getWindow().getHeight();
|
||||
|
||||
boolean hoverSlot = false;
|
||||
|
||||
@@ -217,7 +244,7 @@ public class MidnightControlsRenderer {
|
||||
}
|
||||
|
||||
if (!hoverSlot && client.currentScreen != null) {
|
||||
var slot = MidnightControlsCompat.getSlotAt(client.currentScreen, mouseX, mouseY);
|
||||
var slot = MidnightControlsCompat.getSlotAt(client.currentScreen, (int) mouseX, (int) mouseY);
|
||||
|
||||
if (slot != null) {
|
||||
mouseX = slot.x();
|
||||
@@ -231,32 +258,21 @@ public class MidnightControlsRenderer {
|
||||
mouseY -= 8;
|
||||
}
|
||||
|
||||
//context.getMatrices().push();
|
||||
context.getMatrices().translate(0f, 0f, 999f);
|
||||
drawCursor(context, mouseX, mouseY, hoverSlot, client);
|
||||
//context.getMatrices().pop();
|
||||
try {
|
||||
Sprite sprite = client.getGuiAtlasManager().getSprite(id(MidnightControlsConfig.virtualMouseSkin.getSpritePath() + (hoverSlot ? "_slot" : "")));
|
||||
drawUnalignedTexturedQuad(sprite.getAtlasId(), context, mouseX, mouseX + 16, mouseY, mouseY + 16, 999, sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV());
|
||||
} catch (IllegalStateException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the virtual cursor.
|
||||
*
|
||||
* @param context the context
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param hoverSlot true if hovering a slot, else false
|
||||
* @param client the client instance
|
||||
*/
|
||||
public static void drawCursor(@NotNull DrawContext context, int x, int y, boolean hoverSlot, @NotNull MinecraftClient client) {
|
||||
//RenderSystem.disableDepthTest();
|
||||
//RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
|
||||
//RenderSystem.disableBlend();
|
||||
//RenderSystem.setShaderTexture(0, MidnightControlsClient.CURSOR_TEXTURE);
|
||||
context.drawTexture(MidnightControlsClient.CURSOR_TEXTURE, x, y,
|
||||
hoverSlot ? 16.f : 0.f, MidnightControlsConfig.virtualMouseSkin.ordinal() * 16.f,
|
||||
16, 16, 32, 64);
|
||||
context.fill(1, 1, x, y, 0xFFFFFF);
|
||||
context.draw();
|
||||
//RenderSystem.enableDepthTest();
|
||||
private static void drawUnalignedTexturedQuad(Identifier texture, DrawContext context, float x1, float x2, float y1, float y2, float z, float u1, float u2, float v1, float v2) {
|
||||
RenderSystem.setShaderTexture(0, texture);
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
|
||||
Matrix4f matrix4f = context.getMatrices().peek().getPositionMatrix();
|
||||
BufferBuilder bufferBuilder = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
|
||||
bufferBuilder.vertex(matrix4f, x1, y1, z).texture(u1, v1);
|
||||
bufferBuilder.vertex(matrix4f, x1, y2, z).texture(u1, v2);
|
||||
bufferBuilder.vertex(matrix4f, x2, y2, z).texture(u2, v2);
|
||||
bufferBuilder.vertex(matrix4f, x2, y1, z).texture(u2, v1);
|
||||
BufferRenderer.drawWithGlobalProgram(bufferBuilder.end());
|
||||
}
|
||||
|
||||
public record ButtonSize(int length, int height) {
|
||||
|
||||
@@ -42,6 +42,7 @@ public abstract class GameRendererMixin {
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;draw()V", shift = At.Shift.BEFORE))
|
||||
private void renderVirtualCursor(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci, @Local DrawContext drawContext) {
|
||||
MidnightControlsRenderer.renderVirtualCursor(drawContext, client);
|
||||
if (MidnightControlsClient.isWayland) MidnightControlsRenderer.renderWaylandCursor(drawContext, client);
|
||||
drawContext.draw();
|
||||
}
|
||||
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/GameRenderer;renderHand:Z"), method = "renderWorld")
|
||||
|
||||
|
Before Width: | Height: | Size: 327 B |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |