Improved Cursors

- Cursor position is now float instead of integer, making movement way smoother
- Added a fallback cursor to use in Wayland sessions
This commit is contained in:
Martin Prokoph
2024-07-17 23:23:05 +02:00
parent bdb3c36518
commit 45149af859
16 changed files with 69 additions and 38 deletions

View File

@@ -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.

View File

@@ -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");
}
/**

View File

@@ -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";
};
}
}

View File

@@ -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) {

View File

@@ -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")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB