From 0357e1c8b9c5f0553011bfc22689c17d42cd3836 Mon Sep 17 00:00:00 2001 From: xTracr Date: Sat, 17 Feb 2024 20:37:46 +0800 Subject: [PATCH] Changed to bind based on UV coordinates and Improved ModelViewScreen --- build.gradle | 2 +- .../com/xtracr/realcamera/RealCameraCore.java | 19 +- .../realcamera/command/ClientCommand.java | 4 +- .../xtracr/realcamera/config/ModConfig.java | 5 +- .../realcamera/gui/DoubleValueSlider.java | 10 +- .../realcamera/gui/FloatFieldWidget.java | 38 ++++ .../xtracr/realcamera/gui/IntFieldWidget.java | 39 ---- .../xtracr/realcamera/gui/ModelAnalyser.java | 78 ++++--- .../realcamera/gui/ModelViewScreen.java | 190 +++++++++++------- .../realcamera/util/VertexRecorder.java | 84 +++++--- .../assets/realcamera/lang/en_us.json | 15 +- .../assets/realcamera/lang/zh_cn.json | 17 +- gradle.properties | 6 +- 13 files changed, 295 insertions(+), 212 deletions(-) create mode 100644 common/src/main/java/com/xtracr/realcamera/gui/FloatFieldWidget.java delete mode 100644 common/src/main/java/com/xtracr/realcamera/gui/IntFieldWidget.java diff --git a/build.gradle b/build.gradle index aae640d..15d86fe 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.4-SNAPSHOT" apply false + id "dev.architectury.loom" version "1.5-SNAPSHOT" apply false } architectury { diff --git a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java index 15442c4..3f996cb 100644 --- a/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java +++ b/common/src/main/java/com/xtracr/realcamera/RealCameraCore.java @@ -11,6 +11,7 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.render.entity.PlayerEntityRenderer; @@ -27,6 +28,7 @@ import org.joml.Vector4f; import java.util.Collection; +import java.util.function.BiPredicate; public class RealCameraCore { private static final ModConfig config = ConfigFile.modConfig; @@ -90,16 +92,15 @@ public static void renderPlayer(Vec3d offset, MatrixStack matrices, VertexConsum Matrix4f positionMatrix = matrices.peek().getPositionMatrix().transpose().invertAffine() .translate((float) -offset.getX(), (float) -offset.getY(), (float) -offset.getZ()); Matrix3f normalMatrix = matrices.peek().getNormalMatrix().transpose().invert(); - VertexRecorder.VertexPredicate predicate = (renderLayer, vertices, index) -> { - Vec3d center = Vec3d.ZERO; - double depth = config.disable.depth; + BiPredicate biPredicate = (renderLayer, vertices) -> { + double depth = config.disable.depth, centerZ = 0; for (VertexRecorder.Vertex vertex : vertices) { - center = center.add(vertex.pos()); if (vertex.z() < -depth) return true; + centerZ += vertex.z(); } - return center.getZ() < -depth * vertices.length; + return centerZ < -depth * vertices.length; }; - recorder.drawByAnother(vertex -> vertex.transform(positionMatrix, normalMatrix), vertexConsumers, renderLayer -> true, predicate); + recorder.drawByAnother(vertex -> vertex.transform(positionMatrix, normalMatrix), vertexConsumers, renderLayer -> true, biPredicate); matrices.pop(); } @@ -133,9 +134,9 @@ public static void computeCamera(MinecraftClient client, float tickDelta) { } recorder.setCurrent(renderLayer -> renderLayer.toString().contains(target.textureId()), 0); if (recorder.quadCount() <= 0) throw new NullPointerException("Vertices not found"); - Vec3d front = recorder.getNormal(target.frontIndex()); - Vec3d up = recorder.getNormal(target.upIndex()); - Vec3d center = recorder.getCenter(target.posIndex()); + Vec3d front = recorder.getNormal(target.forwardU(), target.forwardV()); + Vec3d up = recorder.getNormal(target.upwardU(), target.upwardV()); + Vec3d center = recorder.getPos(target.posU(), target.posV()); if (!MathUtil.isFinite(front) || !MathUtil.isFinite(up) || !MathUtil.isFinite(center)) throw new ArithmeticException(); normal.set(up.crossProduct(front).toVector3f(), up.toVector3f(), front.toVector3f()); Vector3f vec3f = normal.transform(new Vector3f((float) (config.getBindingZ() * config.getScale()), diff --git a/common/src/main/java/com/xtracr/realcamera/command/ClientCommand.java b/common/src/main/java/com/xtracr/realcamera/command/ClientCommand.java index f14faf1..756f065 100644 --- a/common/src/main/java/com/xtracr/realcamera/command/ClientCommand.java +++ b/common/src/main/java/com/xtracr/realcamera/command/ClientCommand.java @@ -42,9 +42,7 @@ private int deleteList(CommandContext context) { private int listAll(CommandContext context) { StringBuffer buffer = new StringBuffer(); - config.binding.targetMap.forEach((name, target) -> buffer.append("\n'").append(name).append("' -> [ ") - .append(target.textureId()).append(" ").append(target.frontIndex()).append(" ") - .append(target.upIndex()).append(" ").append(target.posIndex()).append(" ]")); + config.binding.targetMap.forEach((name, target) -> buffer.append("\n'").append(name).append("' -> ").append(target)); printGameMessage(Text.translatable(KEY_COMMAND + "listAll", config.binding.targetMap.size(), buffer.toString())); return 1; } diff --git a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java index aedaa15..8afef7e 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java +++ b/common/src/main/java/com/xtracr/realcamera/config/ModConfig.java @@ -295,7 +295,8 @@ private void clamp() { public static class Binding { protected static final Map defaultTargetMap = Map.of("minecraft_head", - new Target("minecraft:textures/entity/player/", 3, 0, 3)); + new Target("minecraft:textures/entity/player/", + 0.1875f, 0.2f, 0.1875f, 0.075f, 0.1875f, 0.2f)); public VanillaModelPart vanillaModelPart = VanillaModelPart.head; public boolean experimental = false; public boolean adjustOffset = true; @@ -324,7 +325,7 @@ private void clamp() { roll = MathHelper.wrapDegrees(roll); } - public record Target(String textureId, int frontIndex, int upIndex, int posIndex) {} + public record Target(String textureId, float forwardU, float forwardV, float upwardU, float upwardV, float posU, float posV) {} } public static class Classic { diff --git a/common/src/main/java/com/xtracr/realcamera/gui/DoubleValueSlider.java b/common/src/main/java/com/xtracr/realcamera/gui/DoubleValueSlider.java index 738da7c..b01d443 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/DoubleValueSlider.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/DoubleValueSlider.java @@ -10,15 +10,15 @@ public class DoubleValueSlider extends SliderWidget { private final double min, max; private final Function textFunction; - private final DoubleConsumer consumer; + private final DoubleConsumer setter; - public DoubleValueSlider(int width, int height, double value, double min, double max, Function textFunction, DoubleConsumer consumer) { + public DoubleValueSlider(int width, int height, double value, double min, double max, Function textFunction, DoubleConsumer setter) { super(0, 0, width, height, textFunction.apply(min + (max - min) * value), value); this.min = min; this.max = max; this.textFunction = textFunction; - this.consumer = consumer; - this.consumer.accept(min + (max - min) * value); + this.setter = setter; + this.setter.accept(min + (max - min) * value); } protected void setValue(double value) { @@ -34,6 +34,6 @@ protected void updateMessage() { @Override protected void applyValue() { - consumer.accept(min + (max - min) * value); + setter.accept(min + (max - min) * value); } } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/FloatFieldWidget.java b/common/src/main/java/com/xtracr/realcamera/gui/FloatFieldWidget.java new file mode 100644 index 0000000..abb8089 --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/gui/FloatFieldWidget.java @@ -0,0 +1,38 @@ +package com.xtracr.realcamera.gui; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; + + +public class FloatFieldWidget extends TextFieldWidget { + + public FloatFieldWidget(TextRenderer textRenderer, int x, int y, int width, int height, @Nullable FloatFieldWidget copyFrom, Text text) { + super(textRenderer, x, y, width, height, text); + setMaxLength(8); + setValue(0); + if (copyFrom != null) setValue(copyFrom.getValue()); + } + + protected float getValue() { + try { + String text = getText(); + if (text.startsWith(".")) setText("0" + text); + return Float.parseFloat(getText()); + } catch (Exception exception) { + return 0f; + } + } + + protected void setValue(float value) { + setText(String.valueOf(value)); + } + + @Override + public boolean charTyped(char chr, int modifiers) { + if (chr != '.' && (chr < '0' || chr > '9')) return false; + if (chr == '.' && getText().contains(".")) return false; + return super.charTyped(chr, modifiers); + } +} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/IntFieldWidget.java b/common/src/main/java/com/xtracr/realcamera/gui/IntFieldWidget.java deleted file mode 100644 index 3e5dd90..0000000 --- a/common/src/main/java/com/xtracr/realcamera/gui/IntFieldWidget.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.xtracr.realcamera.gui; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.text.Text; - -import java.util.function.IntConsumer; - -public class IntFieldWidget extends TextFieldWidget { - IntConsumer consumer; - - public IntFieldWidget(TextRenderer textRenderer, int x, int y, int width, int height, Text text, int value, IntConsumer consumer) { - super(textRenderer, x, y, width, height, text); - this.consumer = consumer; - setMaxLength(9); - setValue(value); - } - - protected int getValue() { - return Integer.parseInt(getText()); - } - - protected void setValue(int value) { - setText(String.valueOf(value)); - consumer.accept(value); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - if (chr < '0' || chr > '9') { - return false; - } - boolean ret = super.charTyped(chr, modifiers); - int value = getValue(); - setValue(value); - consumer.accept(value); - return ret; - } -} diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java index 14c657f..5b55c81 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelAnalyser.java @@ -5,11 +5,11 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.VertexConsumer; -import org.joml.Vector3f; +import net.minecraft.util.Pair; +import net.minecraft.util.math.Vec3d; import java.awt.*; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -21,29 +21,46 @@ public String focusedTextureId() { return getTextureId(focusedRecord); } - public int getFocusedIndex(int mouseX, int mouseY, int layers) { - List> sortByDepth = new ArrayList<>(); - for (BuiltRecord record : records) for (int i = 0; i < record.quadCount(); i++) { - Vertex[] quad = record.vertices()[i]; - Polygon polygon = new Polygon(); - for (Vertex vertex : quad) polygon.addPoint((int) vertex.x(), (int) vertex.y()); - Vertex point = quad[0]; - Vector3f normal = new Vector3f(point.normalX(), point.normalY(), point.normalZ()); - Vector3f mousePos = new Vector3f((float) point.x(), (float) point.y(), (float) point.z()); - float deltaZ = 0; - if (normal.z() != 0) deltaZ = (normal.x() * (mouseX - mousePos.x()) + normal.y() * (mouseY - mousePos.y())) / normal.z(); - if (polygon.contains(mouseX, mouseY)) sortByDepth.add(new Triple<>(mousePos.z() + deltaZ, record, i)); + public Pair getCenterUV(int quadIndex) { + if (quadIndex == -1 || focusedRecord == null || quadIndex >= focusedRecord.quadCount()) return null; + float u = 0, v = 0; + Vertex[] quad = focusedRecord.vertices()[quadIndex]; + for (Vertex vertex : quad) { + u += vertex.u(); + v += vertex.v(); } + return new Pair<>(u / quad.length, v / quad.length); + } + + public int getFocusedIndex(int mouseX, int mouseY, int layers) { + List> sortByDepth = new ArrayList<>(); + records.forEach(record -> { + Vertex[][] vertices = record.vertices(); + for (int i = 0, size = vertices.length; i < size; i++) { + Polygon polygon = new Polygon(); + Vertex[] quad = vertices[i]; + for (Vertex vertex : quad) polygon.addPoint((int) vertex.x(), (int) vertex.y()); + Vertex point = quad[0]; + double deltaZ = 0; + if (point.normalZ() != 0) deltaZ = (point.normalX() * (mouseX - point.x()) + point.normalY() * (mouseY - point.y())) / point.normalZ(); + if (polygon.contains(mouseX, mouseY)) sortByDepth.add(new Triple<>(point.z() + deltaZ, record, i)); + } + }); if (sortByDepth.isEmpty()) return -1; sortByDepth.sort(Comparator.comparingDouble(triple -> -triple.getLeft())); - Triple result = sortByDepth.get(Math.min(sortByDepth.size() - 1, layers)); + Triple result = sortByDepth.get(Math.min(sortByDepth.size() - 1, layers)); focusedRecord = result.getMiddle(); return result.getRight(); } + public void drawQuad(DrawContext context, float u, float v, int argb) { + if (currentRecord == null) return; + drawQuad(context, getQuadIndex(currentRecord, u, v), argb, false); + } + public void drawQuad(DrawContext context, int quadIndex, int argb, boolean drawFocused) { BuiltRecord record = drawFocused ? focusedRecord : currentRecord; - if (record == null || quadIndex >= record.quadCount()) return; + if (quadIndex == -1 || record == null || quadIndex >= record.quadCount()) return; drawQuad(context, record.vertices()[quadIndex], argb, 1000); if (drawFocused) { Vertex[] highlight = record.vertices()[quadIndex]; @@ -90,30 +107,31 @@ public void drawPolyhedron(DrawContext context, int quadIndex, int argb) { drawQuad(context, reversed, argb, 1100); } - public void drawNormal(DrawContext context, int quadIndex, int length, int argb) { - if (quadIndex >= quadCount()) return; + public void drawNormal(DrawContext context, float u, float v, int length, int argb) { + if (currentRecord == null) return; + int quadIndex = getQuadIndex(currentRecord, u, v); + if (quadIndex == -1) return; + Vertex vertex = currentRecord.vertices()[quadIndex][0]; + Vec3d start = getPos(u, v); + Vec3d end = vertex.normal().multiply(length).add(start); VertexConsumer vertexConsumer = context.getVertexConsumers().getBuffer(RenderLayer.getLineStrip()); - Vector3f normal = getNormal(quadIndex).toVector3f(); - Vector3f start = getCenter(quadIndex).toVector3f(); - Vector3f end = new Vector3f(normal).mul(length).add(start); - vertexConsumer.vertex(start.x(), start.y(), start.z() + 1200f).color(argb).normal(normal.x(), normal.y(), normal.z()).next(); - vertexConsumer.vertex(end.x(), end.y(), end.z() + 1200f).color(argb).normal(normal.x(), normal.y(), normal.z()).next(); + vertexConsumer.vertex(start.getX(), start.getY(), start.getZ() + 1200f).color(argb) + .normal(vertex.normalX(), vertex.normalY(), vertex.normalZ()).next(); + vertexConsumer.vertex(end.getX(), end.getY(), end.getZ() + 1200f).color(argb) + .normal(vertex.normalX(), vertex.normalY(), vertex.normalZ()).next(); context.draw(); } private static boolean intersects(Vertex[] quad, List quads) { final float precision = 0.00001f; - boolean ret = false; - for (Vertex[] p : quads) for (Vertex v1 : quad) - if (Arrays.stream(p).anyMatch(v2 -> v1.pos().squaredDistanceTo(v2.pos()) < precision)) ret = true; - return ret; + for (Vertex[] q : quads) for (Vertex v1 : quad) + for (Vertex v2 : q) if (v1.pos().squaredDistanceTo(v2.pos()) < precision) return true; + return false; } private static void drawQuad(DrawContext context, Vertex[] quad, int argb, int offset) { VertexConsumer vertexConsumer = context.getVertexConsumers().getBuffer(RenderLayer.getGui()); - for (Vertex vertex : quad) { - vertexConsumer.vertex(vertex.x(), vertex.y(), vertex.z() + offset).color(argb).next(); - } + for (Vertex vertex : quad) vertexConsumer.vertex(vertex.x(), vertex.y(), vertex.z() + offset).color(argb).next(); if (quad.length == 3) vertexConsumer.vertex(quad[2].x(), quad[2].y(), quad[2].z() + offset).color(argb).next(); context.draw(); } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index 211ace9..eb4777d 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -9,6 +9,8 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.GridWidget; +import net.minecraft.client.gui.widget.SimplePositioningWidget; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.render.DiffuseLighting; import net.minecraft.client.render.entity.EntityRenderDispatcher; @@ -16,39 +18,34 @@ import net.minecraft.entity.LivingEntity; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import net.minecraft.util.Pair; import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; import org.lwjgl.glfw.GLFW; +import java.util.Map; + public class ModelViewScreen extends Screen { private static final String KEY_SCREEN = "screen.xtracr_" + RealCamera.MODID + "_modelView_"; private static final String KEY_WIDGET = "screen.widget.xtracr_" + RealCamera.MODID + "_modelView_"; private static final String KEY_TOOLTIP = "screen.tooltip.xtracr_" + RealCamera.MODID + "_modelView_"; - protected int xSize = 400, ySize = 220; + private static final Map selectingText = Map.of("forward", Text.translatable(KEY_WIDGET + "forwardMode").styled(s -> s.withColor(Formatting.GREEN)), + "upward", Text.translatable(KEY_WIDGET + "upwardMode").styled(s -> s.withColor(Formatting.RED)), + "pos", Text.translatable(KEY_WIDGET + "posMode").styled(s -> s.withColor(Formatting.BLUE))); + protected int xSize = 420, ySize = 220, widgetWidth = (xSize - ySize) / 4 - 10, widgetHeight = 17; protected int x, y; - protected boolean shouldPause = false, showCube = false; - private int entitySize = 80; + private boolean shouldPause = false, showCube = false; + private int entitySize = 80, layers = 0; private double entityX, entityY; private float yaw, pitch, xRot, yRot; - private int select; - private String focusedTextureId; - private int layers, frontIndex, upIndex, posIndex, focusedIndex = -1; - private IntFieldWidget frontIndexWidget, upIndexWidget, posIndexWidget; - private TextFieldWidget textureIdWidget, nameWidget; - private final ButtonWidget selectFrontButton = ButtonWidget.builder(Text.literal("OFF"), button -> changeSelectionTarget(0, button)).size(25, 18).build(); - private final ButtonWidget selectUpButton = ButtonWidget.builder(Text.literal("OFF"), button -> changeSelectionTarget(1, button)).size(25, 18).build(); - private final ButtonWidget selectPosButton = ButtonWidget.builder(Text.literal("OFF"), button -> changeSelectionTarget(2, button)).size(25, 18).build(); - private final ButtonWidget saveButton = ButtonWidget.builder(Text.translatable(KEY_WIDGET + "save"), button -> saveCurrent()).size((xSize - ySize)/4 - 10, 18).build(); - private final ButtonWidget loadButton = ButtonWidget.builder(Text.translatable(KEY_WIDGET + "load"), button -> loadToCurrent()).size((xSize - ySize)/4 - 10, 18).build(); - private final DoubleValueSlider yawWidget = new DoubleValueSlider((xSize - ySize)/2 - 15, 18, 0.5D, - -60.0D, 60.0D, d -> Text.translatable(KEY_WIDGET + "yaw", MathUtil.round(d, 2)), d -> yaw = (float) d); - private final DoubleValueSlider pitchWidget = new DoubleValueSlider((xSize - ySize)/2 - 15, 18, 0.5D, - -90.0D, 90.0D, d -> Text.translatable(KEY_WIDGET + "pitch", MathUtil.round(d, 2)), d -> pitch = (float) d); - private final ButtonWidget resetWidget = ButtonWidget.builder(Text.translatable(KEY_WIDGET + "reset"), button -> reset()).size((xSize - ySize)/2 - 15, 18).build(); - private final ButtonWidget pauseWidget = ButtonWidget.builder(Text.translatable(KEY_WIDGET + "pause"), button -> shouldPause = !shouldPause).size((xSize - ySize)/2 - 15, 18).build(); - private final ButtonWidget showCubeWidget = ButtonWidget.builder(Text.translatable(KEY_WIDGET + "showCube"), button -> showCube = !showCube).size((xSize - ySize)/2 - 15, 18).build(); + private String focusedTextureId, selecting = "forward"; + private Pair focusedUV; + private FloatFieldWidget forwardUField, forwardVField, upwardUField, upwardVField, posUField, posVField; + private TextFieldWidget textureIdField, nameField; + private DoubleValueSlider yawSlider, pitchSlider; public ModelViewScreen() { super(Text.translatable(KEY_SCREEN + "title")); @@ -59,33 +56,51 @@ protected void init() { super.init(); x = (width - xSize) / 2; y = (height - ySize) / 2; - frontIndexWidget = new IntFieldWidget(textRenderer, x + 5, y + 70, (xSize - ySize)/2 - 45, 18, Text.translatable(KEY_WIDGET + "frontIndex"), frontIndex, i -> frontIndex = i); - upIndexWidget = new IntFieldWidget(textRenderer, x + 5, y + 92, (xSize - ySize)/2 - 45, 18, Text.translatable(KEY_WIDGET + "upIndex"), upIndex, i -> upIndex = i); - posIndexWidget = new IntFieldWidget(textRenderer, x + 5, y + 114, (xSize - ySize)/2 - 45, 18, Text.translatable(KEY_WIDGET + "posIndex"), posIndex, i -> posIndex = i); - textureIdWidget = new TextFieldWidget(textRenderer, x + 5, y + 136, (xSize - ySize)/2 - 15, 18, Text.translatable(KEY_WIDGET + "textureId")); - nameWidget = new TextFieldWidget(textRenderer, x + 5, y + 180, (xSize - ySize)/2 - 15, 18, Text.translatable(KEY_WIDGET + "listName")); - textureIdWidget.setMaxLength(1024); - nameWidget.setMaxLength(20); - selectFrontButton.setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "selectFront"))); - selectUpButton.setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "selectUp"))); - selectPosButton.setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "selectPos"))); - pauseWidget.setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "pause"))); - showCubeWidget.setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "showCube"))); - addDrawableChild(resetWidget).setPosition(x + 5, y + 4); - addDrawableChild(yawWidget).setPosition(x + 5, y + 26); - addDrawableChild(pitchWidget).setPosition(x + 5, y + 48); - addDrawableChild(frontIndexWidget).setTooltip(Tooltip.of(Text.translatable(KEY_WIDGET + "frontIndex"))); - addDrawableChild(selectFrontButton).setPosition(x + (xSize - ySize)/2 - 35, y + 70); - addDrawableChild(upIndexWidget).setTooltip(Tooltip.of(Text.translatable(KEY_WIDGET + "upIndex"))); - addDrawableChild(selectUpButton).setPosition(x + (xSize - ySize)/2 - 35, y + 92); - addDrawableChild(posIndexWidget).setTooltip(Tooltip.of(Text.translatable(KEY_WIDGET + "posIndex"))); - addDrawableChild(selectPosButton).setPosition(x + (xSize - ySize)/2 - 35, y + 114); - addDrawableChild(saveButton).setPosition(x + 5, y + 158); - addDrawableChild(loadButton).setPosition(x + (xSize - ySize)/4, y + 158); - addDrawableChild(textureIdWidget).setTooltip(Tooltip.of(Text.translatable(KEY_WIDGET + "textureId"))); - addDrawableChild(nameWidget).setTooltip(Tooltip.of(Text.translatable(KEY_WIDGET + "listName"))); - addDrawableChild(pauseWidget).setPosition(x + (xSize + ySize) / 2 + 10, y + 4); - addDrawableChild(showCubeWidget).setPosition(x + (xSize + ySize) / 2 + 10, y + 26); + initLeftWidgets(); + initRightWidgets(); + } + + private void initLeftWidgets() { + GridWidget gridWidget = new GridWidget(); + gridWidget.getMainPositioner().margin(5, 4, 0, 0); + GridWidget.Adder adder = gridWidget.createAdder(2); + adder.add(createButton("reset",widgetWidth * 2 + 5, button -> reset()), 2); + adder.add(yawSlider = new DoubleValueSlider(widgetWidth * 2 + 5, widgetHeight, 0.5D, + -60.0D, 60.0D, d -> Text.translatable(KEY_WIDGET + "yaw", MathUtil.round(d, 2)), d -> yaw = (float) d), 2); + adder.add(pitchSlider = new DoubleValueSlider(widgetWidth * 2 + 5, widgetHeight, 0.5D, + -90.0D, 90.0D, d -> Text.translatable(KEY_WIDGET + "pitch", MathUtil.round(d, 2)), d -> pitch = (float) d), 2); + adder.add(createButton(Text.translatable(KEY_WIDGET + "selectMode", selectingText.get(selecting)), widgetWidth * 2 + 5, button -> { + if (selecting.equals("forward")) selecting = "upward"; + else if (selecting.equals("upward")) selecting = "pos"; + else selecting = "forward"; + button.setMessage(Text.translatable(KEY_WIDGET + "selectMode", selectingText.get(selecting))); + }), 2).setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "selectMode"))); + adder.add(forwardUField = createFloatField(widgetWidth, forwardUField)); + adder.add(forwardVField = createFloatField(widgetWidth, forwardVField)); + adder.add(upwardUField = createFloatField(widgetWidth, upwardUField)); + adder.add(upwardVField = createFloatField(widgetWidth, upwardVField)); + adder.add(posUField = createFloatField(widgetWidth, posUField)); + adder.add(posVField = createFloatField(widgetWidth, posVField)); + adder.add(textureIdField = createTextField(widgetWidth * 2 + 5, textureIdField),2).setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "textureId"))); + adder.add(createButton("save", widgetWidth, button -> saveConfig())); + adder.add(createButton("load", widgetWidth, button -> loadConfig())); + adder.add(nameField = createTextField(widgetWidth * 2 + 5, nameField),2).setTooltip(Tooltip.of(Text.translatable(KEY_TOOLTIP + "listName"))); + textureIdField.setMaxLength(1024); + nameField.setMaxLength(20); + gridWidget.refreshPositions(); + SimplePositioningWidget.setPos(gridWidget, x, y, x + (xSize - ySize) / 2 - 5, y + ySize, 0, 0); + gridWidget.forEachChild(this::addDrawableChild); + } + + private void initRightWidgets() { + GridWidget gridWidget = new GridWidget(); + gridWidget.getMainPositioner().margin(5, 4, 0, 0); + GridWidget.Adder adder = gridWidget.createAdder(2); + adder.add(createButton("pause", widgetWidth * 2 + 5, button -> shouldPause = !shouldPause), 2); + adder.add(createButton("showCube", widgetWidth * 2 + 5, button -> showCube = !showCube), 2); + gridWidget.refreshPositions(); + SimplePositioningWidget.setPos(gridWidget, x + (xSize + ySize) / 2 + 5, y, x + xSize, y +ySize, 0, 0); + gridWidget.forEachChild(this::addDrawableChild); } @Override @@ -140,18 +155,19 @@ protected void drawEntity(DrawContext context, float x, float y, int mouseX, int ModelAnalyser analyser = new ModelAnalyser(); entityRenderDispatcher.render(entity, 0, -entity.getHeight() / 2.0f, 0, 0.0f, 1.0f, context.getMatrices(), analyser, 0xF000F0); analyser.buildLastRecord(); - analyser.drawByAnother(context.getVertexConsumers(), renderLayer -> true, (renderLayer, vertices, index) -> true); // TODO + analyser.drawByAnother(context.getVertexConsumers(), renderLayer -> true, (renderLayer, vertices) -> true); // TODO context.draw(); - analyser.setCurrent(renderLayer -> renderLayer.toString().contains(textureIdWidget.getText()), 0); - focusedIndex = analyser.getFocusedIndex(mouseX, mouseY, layers); + analyser.setCurrent(renderLayer -> renderLayer.toString().contains(textureIdField.getText()), 0); + int focusedIndex = analyser.getFocusedIndex(mouseX, mouseY, layers); + focusedUV = analyser.getCenterUV(focusedIndex); focusedTextureId = analyser.focusedTextureId(); - analyser.drawQuad(context, posIndex, 0x6F3333CC, false); - if (focusedIndex > -1) { + analyser.drawQuad(context, posUField.getValue(), posVField.getValue(), 0x6F3333CC); + if (focusedIndex != -1) { if (showCube) analyser.drawPolyhedron(context, focusedIndex, 0x5FFFFFFF); else analyser.drawQuad(context, focusedIndex, 0x7FFFFFFF, true); } - analyser.drawNormal(context, frontIndex, entitySize / 2, 0xFF00CC00); - analyser.drawNormal(context, upIndex, entitySize / 2, 0xFFCC0000); + analyser.drawNormal(context, forwardUField.getValue(), forwardVField.getValue(), entitySize / 2, 0xFF00CC00); + analyser.drawNormal(context, upwardUField.getValue(), upwardVField.getValue(), entitySize / 2, 0xFFCC0000); entityRenderDispatcher.setRenderShadows(true); context.getMatrices().pop(); DiffuseLighting.enableGuiDepthLighting(); @@ -159,37 +175,52 @@ protected void drawEntity(DrawContext context, float x, float y, int mouseX, int private void reset() { entitySize = 80; - yawWidget.setValue(0); - pitchWidget.setValue(0); + yawSlider.setValue(0); + pitchSlider.setValue(0); entityX = entityY = 0; xRot = yRot = 0; layers = 0; } - private void saveCurrent() { - String name = nameWidget.getText(); + private void saveConfig() { + String name = nameField.getText(); if (name == null) return; - ConfigFile.modConfig.binding.targetMap.put(name, - new ModConfig.Binding.Target(textureIdWidget.getText(), frontIndex, upIndex, posIndex)); + ConfigFile.modConfig.binding.targetMap.put(name, new ModConfig.Binding.Target(textureIdField.getText(), + forwardUField.getValue(), forwardVField.getValue(), upwardUField.getValue(), upwardVField.getValue(), + posUField.getValue(), posVField.getValue())); ConfigFile.save(); } - private void loadToCurrent() { - String name = nameWidget.getText(); + private void loadConfig() { + String name = nameField.getText(); ModConfig.Binding.Target target = ConfigFile.modConfig.binding.targetMap.get(name); + if (target == null) return; try { - textureIdWidget.setText(target.textureId()); - frontIndexWidget.setValue(target.frontIndex()); - upIndexWidget.setValue(target.upIndex()); - posIndexWidget.setValue(target.posIndex()); + textureIdField.setText(target.textureId()); + forwardUField.setValue(target.forwardU()); + forwardVField.setValue(target.forwardV()); + upwardUField.setValue(target.upwardU()); + upwardVField.setValue(target.upwardV()); + posUField.setValue(target.posU()); + posVField.setValue(target.posV()); } catch (Exception ignored) { } } - private void changeSelectionTarget(int target, ButtonWidget button) { - select ^= 1 << target; - if ((select >> target & 1) != 0) button.setMessage(Text.literal("ON").styled(style -> style.withColor(Formatting.GREEN))); - else button.setMessage(Text.literal("OFF")); + private ButtonWidget createButton(String name, int width, ButtonWidget.PressAction onPress) { + return createButton(Text.translatable(KEY_WIDGET + name), width, onPress); + } + + private ButtonWidget createButton(Text message, int width, ButtonWidget.PressAction onPress) { + return ButtonWidget.builder(message, onPress).size(width, widgetHeight).build(); + } + + private FloatFieldWidget createFloatField(int width, @Nullable FloatFieldWidget copyFrom) { + return new FloatFieldWidget(textRenderer, 0, 0, width, widgetHeight, copyFrom, null); + } + + private TextFieldWidget createTextField(int width, @Nullable TextFieldWidget copyFrom) { + return new TextFieldWidget(textRenderer, 0, 0, width, widgetHeight, copyFrom, null); } protected boolean mouseInViewArea(double mouseX, double mouseY) { @@ -198,15 +229,20 @@ protected boolean mouseInViewArea(double mouseX, double mouseY) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (mouseInViewArea(mouseX, mouseY) && focusedIndex > -1 && button == GLFW.GLFW_MOUSE_BUTTON_LEFT && + if (mouseInViewArea(mouseX, mouseY) && focusedUV != null && button == GLFW.GLFW_MOUSE_BUTTON_LEFT && InputUtil.isKeyPressed(this.client.getWindow().getHandle(), GLFW.GLFW_KEY_LEFT_ALT)) { - if ((select & 1) != 0) frontIndexWidget.setValue(focusedIndex); - if ((select >> 1 & 1) != 0) upIndexWidget.setValue(focusedIndex); - if ((select >> 2 & 1) != 0) posIndexWidget.setValue(focusedIndex); - if (select != 0) { - textureIdWidget.setText(focusedTextureId); - return true; + if (selecting.equals("forward")) { + forwardUField.setValue(focusedUV.getLeft()); + forwardVField.setValue(focusedUV.getRight()); + } else if (selecting.equals("upward")) { + upwardUField.setValue(focusedUV.getLeft()); + upwardVField.setValue(focusedUV.getRight()); + } else { + posUField.setValue(focusedUV.getLeft()); + posVField.setValue(focusedUV.getRight()); } + textureIdField.setText(focusedTextureId); + return true; } return super.mouseClicked(mouseX, mouseY, button); } diff --git a/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java b/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java index bbd5aea..dcc634c 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java +++ b/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java @@ -9,9 +9,10 @@ import org.joml.Vector3f; import org.joml.Vector4f; -import java.util.ArrayList; -import java.util.Comparator; +import java.awt.*; import java.util.List; +import java.util.*; +import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Matcher; @@ -32,21 +33,31 @@ public String currentTextureId() { return getTextureId(currentRecord); } - public Vec3d getCenter(int index) { + public Vec3d getPos(float u, float v) { if (currentRecord == null) return null; - Vec3d center = Vec3d.ZERO; - for (Vertex vertex : currentRecord.vertices[index]) center = center.add(vertex.pos()); - return center.multiply(1 / (double) currentRecord.additionalVertexCount); + return getPos(getQuadIndex(currentRecord, u, v), u, v); } - public Vec3d getNormal(int index) { + public Vec3d getPos(int quadIndex, float u, float v) { + if (currentRecord == null || quadIndex >= currentRecord.quadCount) return null; + Vertex[] quad = currentRecord.vertices[quadIndex]; + if (quad.length < 3) return null; + float u0 = quad[0].u, v0 = quad[0].v, u1 = quad[1].u, v1 = quad[1].v, u2 = quad[2].u, v2 = quad[2].v; + float alpha = ((u - u1) * (v1 - v2) - (v - v1) * (u1 - u2)) / ((u0 - u1) * (v1 - v2) - (v0 - v1) * (u1 - u2)), + beta = ((u - u2) * (v2 - v0) - (v - v2) * (u2 - u0)) / ((u1 - u2) * (v2 - v0) - (v1 - v2) * (u2 - u0)); + return quad[0].pos().multiply(alpha).add(quad[1].pos().multiply(beta)).add(quad[2].pos().multiply(1 - alpha - beta)); + } + + public Vec3d getNormal(float u, float v) { if (currentRecord == null) return null; - return currentRecord.vertices[index][0].normal(); + Vertex[] quad = getQuad(currentRecord, u, v); + if (quad == null || quad.length < 1) return null; + return quad[0].normal(); } public void buildLastRecord() { if (lastRecord == null) return; - records.add(lastRecord.build()); + if (!lastRecord.vertices.isEmpty()) records.add(lastRecord.build()); lastRecord = null; } @@ -55,21 +66,20 @@ public void setCurrent(Predicate predicate, int index) { .sorted(Comparator.comparingInt(record -> -record.quadCount())).toList().get(index); } - public void drawByAnother(VertexConsumerProvider anotherProvider, Predicate layerPredicate, VertexPredicate vertexPredicate) { - drawByAnother(vertex -> vertex, anotherProvider, layerPredicate, vertexPredicate); + public void drawByAnother(VertexConsumerProvider anotherProvider, Predicate layerPredicate, BiPredicate biPredicate) { + drawByAnother(vertex -> vertex, anotherProvider, layerPredicate, biPredicate); } - public void drawByAnother(Function function, VertexConsumerProvider anotherProvider, Predicate layerPredicate, VertexPredicate vertexPredicate) { + public void drawByAnother(Function function, VertexConsumerProvider anotherProvider, Predicate layerPredicate, BiPredicate biPredicate) { records.forEach(record -> { RenderLayer renderLayer = record.renderLayer; if (!layerPredicate.test(renderLayer)) return; - Vertex[][] vertices = record.vertices; + int argb; + Vertex[] newQuad; VertexConsumer buffer = anotherProvider.getBuffer(renderLayer); - int quadCount = record.quadCount, vertexCount = record.additionalVertexCount, argb; - for (int i = 0; i < quadCount; i++) { - Vertex[] quad = new Vertex[vertexCount]; - for (int j = 0; j < vertexCount; j++) quad[j] = function.apply(vertices[i][j]); - if (vertexPredicate.test(renderLayer, quad, i)) for (Vertex vertex : quad) { + for (Vertex[] quad : record.vertices) { + newQuad = Arrays.stream(quad).map(function).toArray(Vertex[]::new); + if (biPredicate.test(renderLayer, newQuad)) for (Vertex vertex : newQuad) { argb = vertex.argb; buffer.vertex((float) vertex.x, (float) vertex.y, (float) vertex.z, (float) (argb >> 16 & 0xFF) / 255, (float) (argb >> 8 & 0xFF) / 255, (float) (argb & 0xFF) / 255, (float) (argb >> 24) / 255, @@ -79,18 +89,38 @@ public void drawByAnother(Function function, VertexConsumerProvi }); } + protected static Vertex[] getQuad(BuiltRecord record, float u, float v) { + int i = getQuadIndex(record, u, v); + if (i >= 0) return record.vertices[i]; + return null; + } + + protected static int getQuadIndex(BuiltRecord record, float u, float v) { + final int resolution = 10000000; + for (int i = 0, size = record.vertices.length; i < size; i++) { + Vertex[] quad = record.vertices[i]; + Polygon polygon = new Polygon(); + for (Vertex vertex : quad) polygon.addPoint((int) (resolution * vertex.u), (int) (resolution * vertex.v)); + if (polygon.contains(resolution * u, resolution * v)) return i; + } + return -1; + } + protected static String getTextureId(BuiltRecord record) { String name = record.renderLayer.toString(); Pattern pattern = Pattern.compile("texture\\[Optional\\[(.*?)]"); Matcher matcher = pattern.matcher(name); if (matcher.find()) return matcher.group(1); - return null; + return name; } @Override - public VertexConsumer getBuffer(RenderLayer layer) { - buildLastRecord(); - return lastRecord = new VertexRecord(layer); + public VertexConsumer getBuffer(RenderLayer renderLayer) { + if (lastRecord == null || !Objects.equals(lastRecord.renderLayer, renderLayer) || !renderLayer.areVerticesNotShared()) { + buildLastRecord(); + lastRecord = new VertexRecord(renderLayer); + } + return lastRecord; } private static class VertexRecord implements VertexConsumer { @@ -162,6 +192,12 @@ public void next() { u = v = overlay = light = argb = 0; } + @Override + public void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) { + int argb = (int) (alpha * 255.0f) << 24 | (int) (red * 255.0f) << 16 | (int) (green * 255.0f) << 8 | (int) (blue * 255.0f); + vertices.add(new Vertex(x, y, z, argb, u, v, overlay, light, normalX, normalY, normalZ)); + } + @Override public void fixedColor(int red, int green, int blue, int alpha) { } @@ -188,8 +224,4 @@ public Vertex transform(Matrix4f positionMatrix, Matrix3f normalMatrix) { return new Vertex(pos.x(), pos.y(), pos.z(), argb, u, v, overlay, light, normal.x(), normal.y(), normal.z()); } } - - public interface VertexPredicate { - boolean test(RenderLayer renderLayer, Vertex[] vertices, int index); - } } diff --git a/common/src/main/resources/assets/realcamera/lang/en_us.json b/common/src/main/resources/assets/realcamera/lang/en_us.json index ce8751f..b3f8de3 100644 --- a/common/src/main/resources/assets/realcamera/lang/en_us.json +++ b/common/src/main/resources/assets/realcamera/lang/en_us.json @@ -107,17 +107,16 @@ "screen.widget.xtracr_realcamera_modelView_yaw": "Yaw = %s", "screen.widget.xtracr_realcamera_modelView_pitch": "Pitch = %s", "screen.widget.xtracr_realcamera_modelView_reset": "Reset Model State", - "screen.widget.xtracr_realcamera_modelView_frontIndex": "Index of the forward vector", - "screen.widget.xtracr_realcamera_modelView_upIndex": "Index of the upward vector", - "screen.widget.xtracr_realcamera_modelView_posIndex": "Index of the plane", - "screen.widget.xtracr_realcamera_modelView_textureId": "The texture id of the selected model (not necessary to be the full id), can be shortened when saving to make it easier to recognize.\nFor example, shorten minecraft:textures/entity/player/slim/alex.png to minecraft:textures/entity/player/.", - "screen.widget.xtracr_realcamera_modelView_listName": "Name of the list of the indexes, can be selected and bound in the 'Experimental' screen of config screen if saved", + "screen.widget.xtracr_realcamera_modelView_selectMode": "Selecting: %s", + "screen.widget.xtracr_realcamera_modelView_forwardMode": "Forward Vector", + "screen.widget.xtracr_realcamera_modelView_upwardMode": "Upward Vector", + "screen.widget.xtracr_realcamera_modelView_posMode": "Plane", "screen.widget.xtracr_realcamera_modelView_save": "Save", "screen.widget.xtracr_realcamera_modelView_load": "Load", "screen.widget.xtracr_realcamera_modelView_pause": "Start/End Pause", "screen.widget.xtracr_realcamera_modelView_showCube": "Show/Hide Cube", - "screen.tooltip.xtracr_realcamera_modelView_selectFront": "When turned on, hold Alt and left click to select forward vector\nNote: scroll with left Alt held to toggle between the different layers of model", - "screen.tooltip.xtracr_realcamera_modelView_selectUp": "When turned on, hold Alt and left click to select upward vector\nNote: scroll with left Alt held to toggle between the different layers of model", - "screen.tooltip.xtracr_realcamera_modelView_selectPos": "When turned on, hold Alt and left click to select plane, to which camera can be bound to its center\nNote: scroll with left Alt held to toggle between the different layers of model" + "screen.tooltip.xtracr_realcamera_modelView_selectMode": "Hold left Alt and left click to get the UV coordinates at the mouse pointer\nThe three sets of UV coordinates below are, from top to bottom, the forward vector, the upward vector, and the UV coordinates of the plane's center\nNote: Scroll with left Alt held to switch between the different layers of model. Manually inputting UV coordinates allows you to bind more accurately to the target position", + "screen.tooltip.xtracr_realcamera_modelView_textureId": "The texture id of the selected model (not necessary to be the full id), can be shortened when saving to make it easier to recognize.\nFor example, shorten minecraft:textures/entity/player/slim/alex.png to minecraft:textures/entity/player/.", + "screen.tooltip.xtracr_realcamera_modelView_listName": "Name of the config, can be selected and bound in the 'Experimental' screen of config screen if saved" } \ No newline at end of file diff --git a/common/src/main/resources/assets/realcamera/lang/zh_cn.json b/common/src/main/resources/assets/realcamera/lang/zh_cn.json index 6e1f22c..67249f3 100644 --- a/common/src/main/resources/assets/realcamera/lang/zh_cn.json +++ b/common/src/main/resources/assets/realcamera/lang/zh_cn.json @@ -103,21 +103,20 @@ "message.xtracr_realcamera_command_delete_success": "成功删除'%s'", "message.xtracr_realcamera_command_listAll": "找到了%d个结果: %s", - "screen.xtracr_realcamera_modelView_title": "模型试图", + "screen.xtracr_realcamera_modelView_title": "模型视图", "screen.widget.xtracr_realcamera_modelView_yaw": "俯仰 = %s", "screen.widget.xtracr_realcamera_modelView_pitch": "偏航 = %s", "screen.widget.xtracr_realcamera_modelView_reset": "重置模型状态", - "screen.widget.xtracr_realcamera_modelView_frontIndex": "向前矢量的索引", - "screen.widget.xtracr_realcamera_modelView_upIndex": "向上矢量的索引", - "screen.widget.xtracr_realcamera_modelView_posIndex": "平面的索引", - "screen.widget.xtracr_realcamera_modelView_textureId": "被选中的模型的纹理的id(不是完整的id也可以识别),保存时可以缩短一部分以便于程序识别\n比如将minecraft:textures/entity/player/slim/alex.png缩短为minecraft:textures/entity/player/", - "screen.widget.xtracr_realcamera_modelView_listName": "索引组的名称,保存后可在配置屏幕的'Experimental'界面选择并绑定", + "screen.widget.xtracr_realcamera_modelView_selectMode": "选择: %s", + "screen.widget.xtracr_realcamera_modelView_forwardMode": "向前矢量", + "screen.widget.xtracr_realcamera_modelView_upwardMode": "向上矢量", + "screen.widget.xtracr_realcamera_modelView_posMode": "平面", "screen.widget.xtracr_realcamera_modelView_save": "保存", "screen.widget.xtracr_realcamera_modelView_load": "加载", "screen.widget.xtracr_realcamera_modelView_pause": "开始/结束 暂停", "screen.widget.xtracr_realcamera_modelView_showCube": "显示/隐藏 立方体", - "screen.tooltip.xtracr_realcamera_modelView_selectFront": "打开后,按住Alt并左键可选择向前矢量\n注:按住左Alt键滚动可在模型的不同层间切换", - "screen.tooltip.xtracr_realcamera_modelView_selectUp": "打开后,按住Alt并左键可选择向上矢量\n注:按住左Alt键滚动可在模型的不同层间切换", - "screen.tooltip.xtracr_realcamera_modelView_selectPos": "打开后,按住Alt并左键可选择平面,摄像头可以绑定到该平面的中心点上\n注:按住左Alt键滚动可在模型的不同层间切换" + "screen.tooltip.xtracr_realcamera_modelView_selectMode": "按住左Alt并左键可获取鼠标指针处的UV坐标\n下方三组UV坐标由上到下依次为向前矢量、向上矢量和平面中心的UV坐标\n注:按住左Alt键滚动可在模型的不同层间切换,手动输入UV坐标可以更加精确地绑定到目标位置", + "screen.tooltip.xtracr_realcamera_modelView_textureId": "被选中的模型的纹理的id(不是完整的id也可以识别),保存时可以缩短一部分以便于程序识别\n比如将minecraft:textures/entity/player/slim/alex.png缩短为minecraft:textures/entity/player/", + "screen.tooltip.xtracr_realcamera_modelView_listName": "配置的名称,保存后可在配置屏幕的'Experimental'界面选择并绑定" } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index e0ab236..c2cd03b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,13 +5,13 @@ org.gradle.parallel=true minecraft_version=1.20.1 enabled_platforms=fabric,forge forge_version=1.20.1-47.2.20 -fabric_loader_version=0.15.6 +fabric_loader_version=0.15.7 yarn_mappings=1.20.1+build.10 # Mod Properties -mod_version=0.6.0-alpha.2 +mod_version=0.6.0-alpha.3 maven_group=com.xtracr.realcamera archives_base_name=realcamera # Dependencies -fabric_api_version=0.91.0+1.20.1 +fabric_api_version=0.92.0+1.20.1 cloth_config_version=11.1.118 modmenu_version=7.1.0