From a9c2d202d3bae5c299d17b30bbbc2d0418c3cc65 Mon Sep 17 00:00:00 2001 From: tzdwindows 7 <3076584115@qq.com> Date: Sat, 25 Oct 2025 17:11:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor(animation):=E4=BC=98=E5=8C=96=E5=8A=A8?= =?UTF-8?q?=E7=94=BB=E7=B3=BB=E7=BB=9F=E5=AD=97=E6=AE=B5=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E5=8F=98=E6=80=A7=E4=B8=8Egetter=E6=96=B9=E6=B3=95=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F-=20=E5=B0=86AnimationClip=E4=B8=AD=E7=9A=84creationTi?= =?UTF-8?q?me=E5=AD=97=E6=AE=B5=E8=AE=BE=E4=B8=BAfinal=20-=20=E5=B0=86Anim?= =?UTF-8?q?ationLayer=E4=B8=AD=E7=9A=84parameterOverrides=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E8=AE=BE=E4=B8=BAfinal=20-=20=E5=B0=86AnimationParame?= =?UTF-8?q?ter=E4=B8=AD=E7=9A=84id=E3=80=81defaultValue=E3=80=81minValue?= =?UTF-8?q?=E3=80=81maxValue=E5=AD=97=E6=AE=B5=E8=AE=BE=E4=B8=BAfinal=20-?= =?UTF-8?q?=20=E5=B0=86LightSource=E4=B8=AD=E7=9A=84position=E3=80=81color?= =?UTF-8?q?=E3=80=81intensity=E5=AD=97=E6=AE=B5=E8=AE=BE=E4=B8=BAfinal=20-?= =?UTF-8?q?=20=E7=BB=9F=E4=B8=80=E6=89=80=E6=9C=89getter=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=8D=A2=E8=A1=8C=E4=B8=8E=E5=A4=A7=E6=8B=AC=E5=8F=B7?= =?UTF-8?q?=20-=20=E4=BC=98=E5=8C=96Mesh2D=E4=B8=AD=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91=E4=B8=8E?= =?UTF-8?q?=E5=AD=97=E6=AE=B5final=E5=A3=B0=E6=98=8E-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E9=83=A8=E5=88=86JavaDoc=E6=B3=A8=E9=87=8A=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=B8=8E=E7=A9=BA=E8=A1=8C=E4=BD=8D=E7=BD=AE=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E5=8F=AF=E8=AF=BB=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vivid2D/render/ModelRender.java | 94 ++++++--- .../render/MultiSelectionBoxRenderer.java | 10 +- .../render/awt/ModelClickListener.java | 37 ++-- .../vivid2D/render/awt/ModelLayerPanel.java | 125 ++++++----- .../vivid2D/render/awt/ModelRenderPanel.java | 62 +++--- .../vivid2D/render/awt/TransformPanel.java | 14 +- .../awt/util/OperationHistoryGlobal.java | 93 ++++----- .../awt/util/OperationHistoryManager.java | 33 ++- .../render/awt/util/OperationListener.java | 5 +- .../render/awt/util/OperationRecorder.java | 4 + .../render/awt/util/PSD_Structure_Dumper.java | 2 +- .../render/model/AnimationParameter.java | 37 +++- .../vivid2D/render/model/Model2D.java | 74 +++++-- .../vivid2D/render/model/ModelPart.java | 75 ++++--- .../render/model/data/AnimationLayerData.java | 4 +- .../vivid2D/render/model/data/MeshData.java | 3 +- .../vivid2D/render/model/data/ModelData.java | 184 ++++++++++++----- .../render/model/data/ModelMetadata.java | 2 +- .../render/model/data/PartPoseData.java | 4 +- .../vivid2D/render/model/data/PoseData.java | 1 + .../model/transform/RotationDeformer.java | 23 ++- .../model/transform/VertexDeformer.java | 16 +- .../render/model/transform/WaveDeformer.java | 62 ++++-- .../render/model/util/AnimationLayer.java | 171 +++++++++++---- .../vivid2D/render/model/util/Deformer.java | 46 ++++- .../render/model/util/LightSource.java | 81 ++++++-- .../vivid2D/render/model/util/ModelPose.java | 87 ++++++-- .../vivid2D/render/model/util/PuppetPin.java | 67 ++++-- .../render/model/util/SaveVector2f.java | 10 +- .../render/model/util/SecondaryVertex.java | 24 ++- .../vivid2D/render/systems/Camera.java | 4 +- .../render/systems/buffer/BufferBuilder.java | 43 ++-- .../render/systems/buffer/BufferUploader.java | 5 +- .../render/systems/buffer/Tesselator.java | 2 +- .../systems/sources/CompleteShader.java | 8 +- .../render/systems/sources/Shader.java | 2 + .../systems/sources/def/FragmentShaders.java | 195 +++++++++--------- .../sources/def/SolidColorFragmentShader.java | 35 ++-- .../systems/sources/def/SolidColorShader.java | 1 + .../sources/def/SolidColorVertexShader.java | 29 +-- .../systems/sources/def/VertexShaders.java | 38 ++-- .../vivid2D/test/ModelLayerPanelTest.java | 9 +- .../vivid2D/test/ModelLoadTest.java | 90 ++++---- .../vivid2D/test/ModelRenderLightingTest.java | 62 +++--- .../vivid2D/test/ModelRenderTest.java | 3 +- .../vivid2D/test/ModelRenderTest2.java | 6 +- .../vivid2D/test/ModelRenderTextureTest.java | 33 +-- .../chuangzhou/vivid2D/test/ModelTest.java | 3 +- .../chuangzhou/vivid2D/test/ModelTest2.java | 26 ++- .../vivid2D/test/TestModelGLPanel.java | 1 + 50 files changed, 1342 insertions(+), 703 deletions(-) diff --git a/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java b/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java index 25888ad..999040b 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java @@ -2,25 +2,30 @@ package com.chuangzhou.vivid2D.render; import com.chuangzhou.vivid2D.render.model.Model2D; import com.chuangzhou.vivid2D.render.model.ModelPart; -import com.chuangzhou.vivid2D.render.systems.Camera; -import com.chuangzhou.vivid2D.render.systems.buffer.BufferBuilder; -import com.chuangzhou.vivid2D.render.systems.buffer.Tesselator; import com.chuangzhou.vivid2D.render.model.util.LightSource; import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem; +import com.chuangzhou.vivid2D.render.systems.Camera; import com.chuangzhou.vivid2D.render.systems.RenderSystem; +import com.chuangzhou.vivid2D.render.systems.buffer.BufferBuilder; +import com.chuangzhou.vivid2D.render.systems.buffer.Tesselator; import com.chuangzhou.vivid2D.render.systems.sources.CompleteShader; -import com.chuangzhou.vivid2D.render.systems.sources.ShaderProgram; import com.chuangzhou.vivid2D.render.systems.sources.ShaderManagement; +import com.chuangzhou.vivid2D.render.systems.sources.ShaderProgram; import org.joml.Matrix3f; import org.joml.Vector2f; import org.joml.Vector4f; -import org.lwjgl.opengl.*; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** @@ -65,6 +70,7 @@ public final class ModelRender { /** * 渲染系统初始化状态标志,确保系统只初始化一次 + * * @see #initialize() * @see #isInitialized() */ @@ -73,6 +79,7 @@ public final class ModelRender { /** * 视口宽度(像素),定义渲染区域的大小 * 默认值:800像素 + * * @see #setViewport(int, int) */ static int viewportWidth = 800; @@ -80,6 +87,7 @@ public final class ModelRender { /** * 视口高度(像素),定义渲染区域的大小 * 默认值:600像素 + * * @see #setViewport(int, int) */ static int viewportHeight = 600; @@ -87,6 +95,7 @@ public final class ModelRender { /** * 清除颜色(RGBA),用于在每帧开始时清空颜色缓冲区 * 默认值:黑色不透明 (0.0f, 0.0f, 0.0f, 1.0f) + * * @see RenderSystem#clearColor(float, float, float, float) */ private static final Vector4f CLEAR_COLOR = new Vector4f(0.0f, 0.0f, 0.0f, 1.0f); @@ -95,6 +104,7 @@ public final class ModelRender { * 深度测试启用标志,控制是否进行深度缓冲测试 * 在2D渲染中通常禁用以提高性能 * 默认值:false(禁用) + * * @see RenderSystem#enableDepthTest() * @see RenderSystem#disableDepthTest() */ @@ -103,6 +113,7 @@ public final class ModelRender { /** * 混合功能启用标志,控制透明度和颜色混合 * 默认值:true(启用) + * * @see RenderSystem#enableBlend() * @see RenderSystem#disableBlend() */ @@ -119,6 +130,7 @@ public final class ModelRender { /** * 默认着色器程序,用于大多数模型的渲染 * 包含基础的光照、纹理和变换功能 + * * @see #compileDefaultShader() */ private static ShaderProgram defaultProgram = null; @@ -127,6 +139,7 @@ public final class ModelRender { * 网格GPU资源缓存,管理已上传到GPU的网格数据 * 键:Mesh2D对象 * 值:对应的OpenGL资源(VAO、VBO、EBO) + * * @see MeshGLResources */ private static final Map meshResources = new HashMap<>(); @@ -141,6 +154,7 @@ public final class ModelRender { /** * 默认白色纹理ID,当模型没有指定纹理时使用 * 这是一个1x1的纯白色纹理,确保模型有基本的颜色显示 + * * @see #createDefaultTexture() */ private static int defaultTextureId = 0; @@ -189,7 +203,7 @@ public final class ModelRender { */ private static final Camera camera = new Camera(); -// ================== 字体管理 ================== + // ================== 字体管理 ================== private static TextRenderer defaultTextRenderer = null; private static final int FONT_BITMAP_WIDTH = 512; private static final int FONT_BITMAP_HEIGHT = 512; @@ -290,9 +304,18 @@ public final class ModelRender { boolean initialized = false; void dispose() { - if (ebo != 0) { GL15.glDeleteBuffers(ebo); ebo = 0; } - if (vbo != 0) { GL15.glDeleteBuffers(vbo); vbo = 0; } - if (vao != 0) { GL30.glDeleteVertexArrays(vao); vao = 0; } + if (ebo != 0) { + GL15.glDeleteBuffers(ebo); + ebo = 0; + } + if (vbo != 0) { + GL15.glDeleteBuffers(vbo); + vbo = 0; + } + if (vao != 0) { + GL30.glDeleteVertexArrays(vao); + vao = 0; + } initialized = false; } } @@ -722,12 +745,13 @@ public final class ModelRender { } } // 恢复原始颜色 - setUniformVec4Internal(defaultProgram, "uColor", new Vector4f(1,1,1,1)); + setUniformVec4Internal(defaultProgram, "uColor", new Vector4f(1, 1, 1, 1)); } /** * 绘制简洁的灯泡形状 - * @param position 灯泡位置 + * + * @param position 灯泡位置 * @param intensity 光源强度,用于控制灯泡大小 */ private static void drawLightBulb(Vector2f position, float intensity) { @@ -868,16 +892,14 @@ public final class ModelRender { RenderSystem.checkGLError("before_render_collider_" + enabledColliders); - if (collider instanceof PhysicsSystem.CircleCollider) { - PhysicsSystem.CircleCollider c = (PhysicsSystem.CircleCollider) collider; + if (collider instanceof PhysicsSystem.CircleCollider c) { if (c.getCenter() != null && c.getRadius() > 0) { drawCircleColliderWire(c.getCenter(), c.getRadius()); enabledColliders++; } else { logger.warn("Invalid CircleCollider: center={}, radius={}", c.getCenter(), c.getRadius()); } - } else if (collider instanceof PhysicsSystem.RectangleCollider) { - PhysicsSystem.RectangleCollider r = (PhysicsSystem.RectangleCollider) collider; + } else if (collider instanceof PhysicsSystem.RectangleCollider r) { if (r.getCenter() != null && r.getWidth() > 0 && r.getHeight() > 0) { drawRectangleColliderWire(r.getCenter(), r.getWidth(), r.getHeight()); enabledColliders++; @@ -977,17 +999,25 @@ public final class ModelRender { ModelPart.BlendMode bm = part.getBlendMode(); if (bm != null) { switch (bm) { - case ADDITIVE: blend = 1; break; - case MULTIPLY: blend = 2; break; - case SCREEN: blend = 3; break; - case NORMAL: default: blend = 0; + case ADDITIVE: + blend = 1; + break; + case MULTIPLY: + blend = 2; + break; + case SCREEN: + blend = 3; + break; + case NORMAL: + default: + blend = 0; } } else { blend = 0; } setUniformIntInternal(sp, "uBlendMode", blend); // 这里保留为白色,若需要部件 tint 请替换为 part 的 color 属性 - setUniformVec4Internal(sp, "uColor", new Vector4f(1,1,1,1)); + setUniformVec4Internal(sp, "uColor", new Vector4f(1, 1, 1, 1)); } public static TextRenderer getTextRenderer() { @@ -1009,9 +1039,10 @@ public final class ModelRender { /** * 渲染文字 - * @param text 文字内容 - * @param x 世界坐标 X - * @param y 世界坐标 Y ,反转的 + * + * @param text 文字内容 + * @param x 世界坐标 X + * @param y 世界坐标 Y ,反转的 * @param color RGBA 颜色 */ public static void renderText(String text, float x, float y, Vector4f color) { @@ -1025,6 +1056,7 @@ public final class ModelRender { /** * 获取默认摄像机与当前摄像机之间的偏移量 + * * @return Vector2f 偏移向量 (dx, dy) */ public static Vector2f getCameraOffset() { @@ -1033,15 +1065,16 @@ public final class ModelRender { float zoom = camera.getZoom(); Vector2f pos = camera.getPosition(); float tx = -1.0f - (2.0f * zoom * pos.x / width); - float ty = 1.0f + (2.0f * zoom * pos.y / height); + float ty = 1.0f + (2.0f * zoom * pos.y / height); float tx0 = -1.0f; - float ty0 = 1.0f; + float ty0 = 1.0f; float offsetX = tx - tx0; float offsetY = ty - ty0; offsetX = -offsetX * width / 2.0f / zoom; offsetY = offsetY * height / 2.0f / zoom; return new Vector2f(offsetX, offsetY); } + public static void setViewport(int width, int height) { viewportWidth = Math.max(1, width); viewportHeight = Math.max(1, height); @@ -1049,7 +1082,12 @@ public final class ModelRender { } // ================== 辅助:外部获取状态 ================== - public static boolean isInitialized() { return initialized; } - public static int getLoadedMeshCount() { return meshResources.size(); } + public static boolean isInitialized() { + return initialized; + } + + public static int getLoadedMeshCount() { + return meshResources.size(); + } } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java b/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java index b8ca1d8..4288303 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java @@ -11,11 +11,11 @@ import org.lwjgl.opengl.GL11; /** * 现代化选择框渲染器(性能优化版) * 主要优化点: - * 1) 复用 Tesselator 单例 BufferBuilder,减少频繁的 GPU 资源创建/销毁 - * 2) 批量提交顶点:把同一 primitive(LINES / TRIANGLES / LINE_LOOP)与同一颜色的顶点尽量合并到一次 begin/end - * 3) 手柄使用实心矩形(两三角形)批量绘制,保持美观且高效 - * 4) 增加轻微外发光(透明大边框)和阴影感以达到“现代”外观 - * + * 1) 复用 Tesselator 单例 BufferBuilder,减少频繁的 GPU 资源创建/销毁 + * 2) 批量提交顶点:把同一 primitive(LINES / TRIANGLES / LINE_LOOP)与同一颜色的顶点尽量合并到一次 begin/end + * 3) 手柄使用实心矩形(两三角形)批量绘制,保持美观且高效 + * 4) 增加轻微外发光(透明大边框)和阴影感以达到“现代”外观 + *

* 注意:本类依赖你工程中已有的 RenderSystem/Tesselator/BufferBuilder/BufferUploader 实现。 */ public class MultiSelectionBoxRenderer { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelClickListener.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelClickListener.java index 495e249..3b85cf1 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelClickListener.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelClickListener.java @@ -11,9 +11,10 @@ import com.chuangzhou.vivid2D.render.model.util.Mesh2D; public interface ModelClickListener { /** * 当点击模型时触发 - * @param mesh 被点击的网格,如果点击在空白处则为 null - * @param modelX 模型坐标系中的 X 坐标 - * @param modelY 模型坐标系中的 Y 坐标 + * + * @param mesh 被点击的网格,如果点击在空白处则为 null + * @param modelX 模型坐标系中的 X 坐标 + * @param modelY 模型坐标系中的 Y 坐标 * @param screenX 屏幕坐标系中的 X 坐标 * @param screenY 屏幕坐标系中的 Y 坐标 */ @@ -21,22 +22,32 @@ public interface ModelClickListener { /** * 当鼠标在模型上移动时触发 - * @param mesh 鼠标下方的网格,如果不在任何网格上则为 null - * @param modelX 模型坐标系中的 X 坐标 - * @param modelY 模型坐标系中的 Y 坐标 + * + * @param mesh 鼠标下方的网格,如果不在任何网格上则为 null + * @param modelX 模型坐标系中的 X 坐标 + * @param modelY 模型坐标系中的 Y 坐标 * @param screenX 屏幕坐标系中的 X 坐标 * @param screenY 屏幕坐标系中的 Y 坐标 */ - default void onModelHover(Mesh2D mesh, float modelX, float modelY, int screenX, int screenY) {} - default void onLiquifyModeExited(){}; + default void onModelHover(Mesh2D mesh, float modelX, float modelY, int screenX, int screenY) { + } - default void onLiquifyModeEntered(Mesh2D targetMesh, ModelPart liquifyTargetPart){}; + default void onLiquifyModeExited() { + } - default void onSecondaryVertexModeEntered(Mesh2D secondaryVertexTargetMesh){}; + default void onLiquifyModeEntered(Mesh2D targetMesh, ModelPart liquifyTargetPart) { + } - default void onSecondaryVertexModeExited(){}; + default void onSecondaryVertexModeEntered(Mesh2D secondaryVertexTargetMesh) { + } - default void onPuppetModeEntered(Mesh2D puppetTargetMesh){}; + default void onSecondaryVertexModeExited() { + } + + default void onPuppetModeEntered(Mesh2D puppetTargetMesh) { + } + + default void onPuppetModeExited() { + } - default void onPuppetModeExited(){}; } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelLayerPanel.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelLayerPanel.java index a74c75d..2143bb9 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelLayerPanel.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelLayerPanel.java @@ -16,11 +16,15 @@ import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; -import java.awt.event.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.lang.reflect.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; @@ -30,13 +34,13 @@ import java.util.concurrent.Callable; /** * ModelLayerPanel(完整实现) - * + *

* - 列表显示“从上到下”的图层(listModel[0] 为最上层) * - 在任何修改后都会把 model.parts 同步为列表的反序(保证渲染顺序与 UI 一致) * - 支持添加空层 / 从文件创建带贴图的层(在有 renderPanel 时在 GL 线程使用 Texture.createFromFile) * - 支持为选中部件绑定贴图、创建透明图层 * - 支持拖拽重排、上下按钮移动,并在重排后正确恢复选中与不触发滑块事件 - * + *

* 使用: * new ModelLayerPanel(model, optionalModelRenderPanel) */ @@ -242,7 +246,8 @@ public class ModelLayerPanel extends JPanel { if (partMap != null) { partMap.put(uniqueName, part); } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } part.setVisible(layerInfo.visible); @@ -293,7 +298,8 @@ public class ModelLayerPanel extends JPanel { // 强制尝试上传/初始化(若纹理对象需要) try { tryCallTextureUpload(texture); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } // 标记模型需要更新 model.markNeedsUpdate(); @@ -306,10 +312,12 @@ public class ModelLayerPanel extends JPanel { SwingUtilities.invokeLater(() -> { try { reloadFromModel(); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } try { if (renderPanel != null) renderPanel.repaint(); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } }); } else { System.err.println("创建纹理失败: " + uniqueName); @@ -505,7 +513,8 @@ public class ModelLayerPanel extends JPanel { f.setAccessible(true); Object v = f.get(sel); if (v instanceof Float) op = (Float) v; - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } int val = Math.round(op * 100); @@ -604,7 +613,8 @@ public class ModelLayerPanel extends JPanel { Field f = sel.getClass().getDeclaredField("opacity"); f.setAccessible(true); f.setFloat(sel, val / 100.0f); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } if (model != null) model.markNeedsUpdate(); layerList.repaint(); @@ -711,7 +721,8 @@ public class ModelLayerPanel extends JPanel { w = Math.max(1, Integer.parseInt(sp[0].trim())); h = Math.max(1, Integer.parseInt(sp[1].trim())); } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); ModelPart part = model.createPart(name); @@ -753,20 +764,23 @@ public class ModelLayerPanel extends JPanel { File f = chooser.getSelectedFile(); try { BufferedImage img = null; - try { img = ImageIO.read(f); } catch (Exception ignored) {} + try { + img = ImageIO.read(f); + } catch (Exception ignored) { + } // 获取第一个 mesh Mesh2D targetMesh = null; try { Method getMeshes = sel.getClass().getMethod("getMeshes"); Object list = getMeshes.invoke(sel); - if (list instanceof List) { - List meshes = (List) list; + if (list instanceof List meshes) { if (!meshes.isEmpty() && meshes.get(0) instanceof Mesh2D) { targetMesh = (Mesh2D) meshes.get(0); } } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } if (targetMesh == null) { if (img == null) { @@ -828,12 +842,12 @@ public class ModelLayerPanel extends JPanel { try { Method m = Mesh2D.class.getMethod("createQuad", String.class, float.class, float.class); Object o = m.invoke(null, meshName, w, h); - if (o instanceof Mesh2D) { - Mesh2D mesh = (Mesh2D) o; + if (o instanceof Mesh2D mesh) { // 对基础四边形进行细分以增加顶点密度 return subdivideMeshForLiquify(mesh, 3); // 3级细分 } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } try { // 创建高密度网格(细分网格) @@ -914,8 +928,7 @@ public class ModelLayerPanel extends JPanel { if (cons != null) { cons.setAccessible(true); Object meshObj = cons.newInstance(name, vertices, uvs, indices); - if (meshObj instanceof Mesh2D) { - Mesh2D mesh = (Mesh2D) meshObj; + if (meshObj instanceof Mesh2D mesh) { // 设置合适的pivot(中心点) mesh.setPivot(0, 0); @@ -1074,11 +1087,12 @@ public class ModelLayerPanel extends JPanel { if (renderPanel == null) throw new IllegalStateException("需要 renderPanel 才能在 GL 上下文创建纹理"); try { - return renderPanel.executeInGLContext((Callable) () -> { + return renderPanel.executeInGLContext(() -> { // 静态工厂尝试 try { Method factory = findStaticMethod(Texture.class, "createFromBufferedImage", BufferedImage.class); - if (factory == null) factory = findStaticMethod(Texture.class, "createFromImage", BufferedImage.class); + if (factory == null) + factory = findStaticMethod(Texture.class, "createFromImage", BufferedImage.class); if (factory != null) { Object texObj = factory.invoke(null, img); if (texObj instanceof Texture) { @@ -1086,7 +1100,8 @@ public class ModelLayerPanel extends JPanel { return (Texture) texObj; } } - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } // 构造 ByteBuffer 并尝试构造器 try { @@ -1123,15 +1138,20 @@ public class ModelLayerPanel extends JPanel { } } } - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } if (formatEnum != null) { try { texObj = suit.newInstance(texName, w, h, formatEnum, buf); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } } if (texObj == null) { - try { texObj = suit.newInstance(texName, img.getWidth(), img.getHeight(), buf); } catch (Exception ignored) {} + try { + texObj = suit.newInstance(texName, img.getWidth(), img.getHeight(), buf); + } catch (Exception ignored) { + } } if (texObj instanceof Texture) { tryCallTextureUpload((Texture) texObj); @@ -1185,13 +1205,20 @@ public class ModelLayerPanel extends JPanel { } } } - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } if (formatEnum != null) { - try { texObj = suit.newInstance(texName, w, h, formatEnum, buf); } catch (Throwable ignored) {} + try { + texObj = suit.newInstance(texName, w, h, formatEnum, buf); + } catch (Throwable ignored) { + } } } if (texObj == null) { - try { texObj = suit.newInstance(texName, w, h, buf); } catch (Throwable ignored) {} + try { + texObj = suit.newInstance(texName, w, h, buf); + } catch (Throwable ignored) { + } } if (texObj instanceof Texture) return (Texture) texObj; } @@ -1245,12 +1272,14 @@ public class ModelLayerPanel extends JPanel { try { Method m = cls.getMethod(name, param); if (Modifier.isStatic(m.getModifiers())) return m; - } catch (Exception ignored) {} + } catch (Exception ignored) { + } try { Method m = cls.getDeclaredMethod(name, param); m.setAccessible(true); if (Modifier.isStatic(m.getModifiers())) return m; - } catch (Exception ignored) {} + } catch (Exception ignored) { + } return null; } @@ -1277,7 +1306,8 @@ public class ModelLayerPanel extends JPanel { model.setRootPart(null); } } - } catch (Exception ignored) {} + } catch (Exception ignored) { + } model.markNeedsUpdate(); reloadFromModel(); } catch (Exception ex) { @@ -1449,9 +1479,7 @@ public class ModelLayerPanel extends JPanel { Field partsField = model.getClass().getDeclaredField("parts"); partsField.setAccessible(true); Object old = partsField.get(model); - if (old instanceof java.util.List) { - @SuppressWarnings("rawtypes") - java.util.List rawList = (java.util.List) old; + if (old instanceof @SuppressWarnings("rawtypes")List rawList) { rawList.clear(); rawList.addAll(newParts); } else { @@ -1465,9 +1493,9 @@ public class ModelLayerPanel extends JPanel { // ============== 列表渲染/拖拽辅助 ============== private class LayerCellRenderer extends JPanel implements ListCellRenderer { - private JCheckBox visibleBox = new JCheckBox(); - private JLabel nameLabel = new JLabel(); - private JLabel opacityLabel = new JLabel(); + private final JCheckBox visibleBox = new JCheckBox(); + private final JLabel nameLabel = new JLabel(); + private final JLabel opacityLabel = new JLabel(); LayerCellRenderer() { setLayout(new BorderLayout(6, 6)); @@ -1543,7 +1571,9 @@ public class ModelLayerPanel extends JPanel { } @Override - public int getSourceActions(JComponent c) { return MOVE; } + public int getSourceActions(JComponent c) { + return MOVE; + } @Override public boolean canImport(TransferSupport support) { @@ -1638,23 +1668,25 @@ public class ModelLayerPanel extends JPanel { try { Field fx = p.getClass().getDeclaredField("pivotX"); Field fy = p.getClass().getDeclaredField("pivotY"); - fx.setAccessible(true); fy.setAccessible(true); + fx.setAccessible(true); + fy.setAccessible(true); px = ((Number) fx.get(p)).floatValue(); py = ((Number) fy.get(p)).floatValue(); - } catch (Exception ignored2) {} + } catch (Exception ignored2) { + } } try { Method vm = p.getClass().getMethod("isVisible"); visible = (Boolean) vm.invoke(p); - } catch (Exception ignored) {} - System.out.println(String.format("Part[%d] name=%s visible=%s pivot=(%.1f, %.1f)", i, name, visible, px, py)); + } catch (Exception ignored) { + } + System.out.printf("Part[%d] name=%s visible=%s pivot=(%.1f, %.1f)%n", i, name, visible, px, py); // meshes try { Method gmsh = p.getClass().getMethod("getMeshes"); Object list = gmsh.invoke(p); - if (list instanceof List) { - List meshes = (List) list; + if (list instanceof List meshes) { System.out.println(" meshes count = " + meshes.size()); for (int m = 0; m < meshes.size(); m++) { Object mesh = meshes.get(m); @@ -1667,7 +1699,8 @@ public class ModelLayerPanel extends JPanel { Field f = mesh.getClass().getDeclaredField("texture"); f.setAccessible(true); tex = f.get(mesh); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } System.out.println(" mesh[" + m + "] texture = " + (tex == null ? "null" : tex.getClass().getSimpleName())); } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelRenderPanel.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelRenderPanel.java index 9c80653..94c5a9a 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelRenderPanel.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/ModelRenderPanel.java @@ -14,28 +14,27 @@ import com.chuangzhou.vivid2D.render.systems.RenderSystem; import com.chuangzhou.vivid2D.test.TestModelGLPanel; import org.joml.Matrix3f; import org.joml.Vector2f; -import org.lwjgl.glfw.*; +import org.lwjgl.glfw.GLFW; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL11; import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.awt.event.*; -import java.lang.reflect.Method; -import java.nio.IntBuffer; -import java.nio.ByteOrder; -import java.util.concurrent.locks.LockSupport; - -import javax.swing.*; import javax.swing.Timer; +import javax.swing.*; import java.awt.*; +import java.awt.event.*; import java.awt.image.BufferedImage; +import java.lang.reflect.Method; import java.nio.ByteBuffer; -import java.util.*; +import java.nio.ByteOrder; +import java.nio.IntBuffer; import java.util.List; +import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; /** * vivid2D 模型的 Java 渲染面板 @@ -43,11 +42,10 @@ import java.util.concurrent.atomic.AtomicReference; *

该类提供了 vivid2D 模型在 Java 环境下的图形渲染功能, * 包含基本的 2D 图形绘制、模型显示和交互操作。

* - * * @author tzdwindows 7 * @version 1.1 - * @since 2025-10-13 * @see TestModelGLPanel + * @since 2025-10-13 */ public class ModelRenderPanel extends JPanel { private static final Logger logger = LoggerFactory.getLogger(ModelRenderPanel.class); @@ -82,6 +80,7 @@ public class ModelRenderPanel extends JPanel { private volatile float dragStartX, dragStartY; private volatile float partStartX, partStartY; private volatile boolean isDragging = false; + private enum DragMode { NONE, // 无拖拽 MOVE, // 移动部件 @@ -110,8 +109,8 @@ public class ModelRenderPanel extends JPanel { public static final float BORDER_THICKNESS = 6.0f; public static final float CORNER_SIZE = 12.0f; - private volatile float partInitialScaleX = 1.0f; - private volatile float partInitialScaleY = 1.0f; + private final float partInitialScaleX = 1.0f; + private final float partInitialScaleY = 1.0f; private volatile float displayScale = 1.0f; // 当前可视缩放(用于检测阈值/角点等) private volatile float targetScale = 1.0f; // 目标缩放(鼠标滚轮/程序改变时设置) @@ -121,23 +120,23 @@ public class ModelRenderPanel extends JPanel { private static final float ZOOM_MAX = 8.0f; private volatile boolean shiftDuringDrag = false; private volatile float rotationStartAngle = 0.0f; - private volatile float partInitialRotation = 0.0f; - private volatile Vector2f rotationCenter = new Vector2f(); + private final float partInitialRotation = 0.0f; + private final Vector2f rotationCenter = new Vector2f(); private static final float ROTATION_HANDLE_DISTANCE = 30.0f; private OperationHistoryManager historyManager; // 新增:操作历史管理器 - private OperationHistoryGlobal operationHistory; + private final OperationHistoryGlobal operationHistory; // 新增:拖拽操作的状态记录字段 - private Map dragStartPositions = new HashMap<>(); - private Map dragStartScales = new HashMap<>(); - private Map dragStartRotations = new HashMap<>(); - private Map dragStartPivots = new HashMap<>(); + private final Map dragStartPositions = new HashMap<>(); + private final Map dragStartScales = new HashMap<>(); + private final Map dragStartRotations = new HashMap<>(); + private final Map dragStartPivots = new HashMap<>(); // 新增:鼠标手势相关字段 private volatile Cursor currentCursor = Cursor.getDefaultCursor(); - private volatile DragMode hoverDragMode = DragMode.NONE; + private final DragMode hoverDragMode = DragMode.NONE; private volatile boolean isOverSelection = false; // ================== 摄像机控制相关字段 ================== @@ -1036,7 +1035,7 @@ public class ModelRenderPanel extends JPanel { * 退出液化模式 */ private void exitLiquifyMode() { - executeInGLContext(()->{ + executeInGLContext(() -> { liquifyMode = false; if (liquifyTargetPart != null) { liquifyTargetPart.setStartLiquefy(false); @@ -1112,7 +1111,7 @@ public class ModelRenderPanel extends JPanel { // 绘制圆圈 int center = size / 2; - int radius = (int)(liquifyBrushSize * 0.1f); // 根据画笔大小缩放光标 + int radius = (int) (liquifyBrushSize * 0.1f); // 根据画笔大小缩放光标 // 外圈 g2d.setColor(Color.RED); @@ -3342,7 +3341,10 @@ public class ModelRenderPanel extends JPanel { // 确保缓冲区大小匹配(可能在 resize 后需要重建) if (pixelBuffer == null || pixelInts == null || pixelInts.length != pixelCount) { if (pixelBuffer != null) { - try { MemoryUtil.memFree(pixelBuffer); } catch (Throwable ignored) {} + try { + MemoryUtil.memFree(pixelBuffer); + } catch (Throwable ignored) { + } } pixelBuffer = MemoryUtil.memAlloc(pixelCount * 4); pixelBuffer.order(ByteOrder.nativeOrder()); @@ -3431,6 +3433,7 @@ public class ModelRenderPanel extends JPanel { /** * 在 GL 上下文线程上异步执行任务 + * * @param task 要在 GL 上下文线程中执行的任务 * @return CompletableFuture 用于获取任务执行结果 */ @@ -3464,6 +3467,7 @@ public class ModelRenderPanel extends JPanel { /** * 在 GL 上下文线程上异步执行任务并返回结果 + * * @param task 要在 GL 上下文线程中执行的有返回值的任务 * @return CompletableFuture 用于获取任务执行结果 */ @@ -3495,6 +3499,7 @@ public class ModelRenderPanel extends JPanel { /** * 同步在 GL 上下文线程上执行任务(会阻塞当前线程直到任务完成) + * * @param task 要在 GL 上下文线程中执行的任务 * @throws Exception 如果任务执行出错 */ @@ -3509,6 +3514,7 @@ public class ModelRenderPanel extends JPanel { /** * 同步在 GL 上下文线程上执行任务并返回结果(会阻塞当前线程直到任务完成) + * * @param task 要在 GL 上下文线程中执行的有返回值的任务 * @return 任务执行结果 * @throws Exception 如果任务执行出错或超时 @@ -3541,7 +3547,7 @@ public class ModelRenderPanel extends JPanel { /** * 重新设置面板大小 - * + *

* 说明:当 Swing 面板被放大时,需要同时调整离屏 GLFW 窗口像素大小、GL 视口以及重分配像素读取缓冲, * 否则将把较小分辨率的图像拉伸到更大面板上导致模糊。 */ @@ -3637,7 +3643,8 @@ public class ModelRenderPanel extends JPanel { if (windowId != 0) { try { GLFW.glfwDestroyWindow(windowId); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } windowId = 0; } @@ -3654,7 +3661,8 @@ public class ModelRenderPanel extends JPanel { // 终止 GLFW(注意:如果应用中还有其他 GLFW 窗口,这里会影响它们) try { GLFW.glfwTerminate(); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } logger.info("OpenGL 资源已清理"); } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/TransformPanel.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/TransformPanel.java index 960c126..7d0d9ad 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/TransformPanel.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/TransformPanel.java @@ -1,25 +1,25 @@ package com.chuangzhou.vivid2D.render.awt; import com.chuangzhou.vivid2D.render.awt.util.OperationHistoryGlobal; -import com.chuangzhou.vivid2D.render.model.ModelPart; import com.chuangzhou.vivid2D.render.model.ModelEvent; +import com.chuangzhou.vivid2D.render.model.ModelPart; import org.joml.Vector2f; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author tzdwindows 7 */ public class TransformPanel extends JPanel implements ModelEvent { - private ModelRenderPanel renderPanel; - private List selectedParts = new ArrayList<>(); + private final ModelRenderPanel renderPanel; + private final List selectedParts = new ArrayList<>(); private boolean isMultiSelection = false; // 位置控制 @@ -47,7 +47,7 @@ public class TransformPanel extends JPanel implements ModelEvent { private boolean updatingUI = false; // 防止UI更新时触发事件 private javax.swing.Timer transformTimer; // 用于延迟处理变换输入 - private OperationHistoryGlobal operationHistory; + private final OperationHistoryGlobal operationHistory; public TransformPanel(ModelRenderPanel renderPanel) { this.renderPanel = renderPanel; diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryGlobal.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryGlobal.java index 0e68d13..ad5e6cb 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryGlobal.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryGlobal.java @@ -704,16 +704,14 @@ public class OperationHistoryGlobal { } private void handleBatchTransformRecord(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Object[] oldValues = (Object[]) params[1]; Object[] newValues = (Object[]) params[2]; } } private void executeBatchTransform(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Object[] newValues = (Object[]) params[2]; // 应用新的变换值 @@ -734,8 +732,7 @@ public class OperationHistoryGlobal { } private void undoBatchTransform(Object... params) { - if (params.length >= 2 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 2 && params[0] instanceof ModelPart part) { Object[] oldValues = (Object[]) params[1]; // 恢复旧的变换值 @@ -814,8 +811,7 @@ public class OperationHistoryGlobal { // 从参数中获取当前位置(参数索引从2开始) int paramIndex = 2; for (ModelPart part : parts) { - if (paramIndex < params.length && params[paramIndex] instanceof Vector2f) { - Vector2f targetPosition = (Vector2f) params[paramIndex]; + if (paramIndex < params.length && params[paramIndex] instanceof Vector2f targetPosition) { part.setPosition(targetPosition.x, targetPosition.y); paramIndex++; } @@ -830,8 +826,7 @@ public class OperationHistoryGlobal { // 从参数中获取当前缩放(参数索引从2开始) int paramIndex = 2; for (ModelPart part : parts) { - if (paramIndex < params.length && params[paramIndex] instanceof Vector2f) { - Vector2f targetScale = (Vector2f) params[paramIndex]; + if (paramIndex < params.length && params[paramIndex] instanceof Vector2f targetScale) { part.setScale(targetScale.x, targetScale.y); paramIndex++; } @@ -862,8 +857,7 @@ public class OperationHistoryGlobal { // 从参数中获取当前中心点(参数索引从2开始) int paramIndex = 2; for (ModelPart part : parts) { - if (paramIndex < params.length && params[paramIndex] instanceof Vector2f) { - Vector2f targetPivot = (Vector2f) params[paramIndex]; + if (paramIndex < params.length && params[paramIndex] instanceof Vector2f targetPivot) { part.setPivot(targetPivot.x, targetPivot.y); paramIndex++; } @@ -883,7 +877,7 @@ public class OperationHistoryGlobal { part.setPosition(startPosition.x, startPosition.y); } } - // System.out.println("撤回拖拽结束操作"); + // System.out.println("撤回拖拽结束操作"); } } @@ -936,8 +930,7 @@ public class OperationHistoryGlobal { // ============ 具体操作处理方法 ============ private void handlePositionRecord(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Vector2f oldPosition = (Vector2f) params[1]; Vector2f newPosition = (Vector2f) params[2]; @@ -948,24 +941,21 @@ public class OperationHistoryGlobal { } private void executePositionChange(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Vector2f newPosition = (Vector2f) params[2]; part.setPosition(newPosition.x, newPosition.y); } } private void undoPositionChange(Object... params) { - if (params.length >= 2 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 2 && params[0] instanceof ModelPart part) { Vector2f oldPosition = (Vector2f) params[1]; part.setPosition(oldPosition.x, oldPosition.y); } } private void handleRotationRecord(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { float oldRotation = (Float) params[1]; float newRotation = (Float) params[2]; @@ -975,24 +965,21 @@ public class OperationHistoryGlobal { } private void executeRotationChange(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { float newRotation = (Float) params[2]; part.setRotation(newRotation); } } private void undoRotationChange(Object... params) { - if (params.length >= 2 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 2 && params[0] instanceof ModelPart part) { float oldRotation = (Float) params[1]; part.setRotation(oldRotation); } } private void handleScaleRecord(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Vector2f oldScale = (Vector2f) params[1]; Vector2f newScale = (Vector2f) params[2]; @@ -1002,24 +989,21 @@ public class OperationHistoryGlobal { } private void executeScaleChange(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Vector2f newScale = (Vector2f) params[2]; part.setScale(newScale.x, newScale.y); } } private void undoScaleChange(Object... params) { - if (params.length >= 2 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 2 && params[0] instanceof ModelPart part) { Vector2f oldScale = (Vector2f) params[1]; part.setScale(oldScale.x, oldScale.y); } } private void handleOpacityRecord(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { float oldOpacity = (Float) params[1]; float newOpacity = (Float) params[2]; @@ -1029,24 +1013,21 @@ public class OperationHistoryGlobal { } private void executeOpacityChange(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { float newOpacity = (Float) params[2]; part.setOpacity(newOpacity); } } private void undoOpacityChange(Object... params) { - if (params.length >= 2 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 2 && params[0] instanceof ModelPart part) { float oldOpacity = (Float) params[1]; part.setOpacity(oldOpacity); } } private void handleVisibleRecord(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { boolean oldVisible = (Boolean) params[1]; boolean newVisible = (Boolean) params[2]; @@ -1056,24 +1037,21 @@ public class OperationHistoryGlobal { } private void executeVisibleChange(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { boolean newVisible = (Boolean) params[2]; part.setVisible(newVisible); } } private void undoVisibleChange(Object... params) { - if (params.length >= 2 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 2 && params[0] instanceof ModelPart part) { boolean oldVisible = (Boolean) params[1]; part.setVisible(oldVisible); } } private void handlePivotRecord(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Vector2f oldPivot = (Vector2f) params[1]; Vector2f newPivot = (Vector2f) params[2]; @@ -1083,16 +1061,14 @@ public class OperationHistoryGlobal { } private void executePivotChange(Object... params) { - if (params.length >= 3 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 3 && params[0] instanceof ModelPart part) { Vector2f newPivot = (Vector2f) params[2]; part.setPivot(newPivot.x, newPivot.y); } } private void undoPivotChange(Object... params) { - if (params.length >= 2 && params[0] instanceof ModelPart) { - ModelPart part = (ModelPart) params[0]; + if (params.length >= 2 && params[0] instanceof ModelPart part) { Vector2f oldPivot = (Vector2f) params[1]; part.setPivot(oldPivot.x, oldPivot.y); } @@ -1459,10 +1435,21 @@ public class OperationHistoryGlobal { this.canRedo = canRedo; } - public int getRegisteredOperationCount() { return registeredOperationCount; } - public int getHistorySize() { return historySize; } - public boolean canUndo() { return canUndo; } - public boolean canRedo() { return canRedo; } + public int getRegisteredOperationCount() { + return registeredOperationCount; + } + + public int getHistorySize() { + return historySize; + } + + public boolean canUndo() { + return canUndo; + } + + public boolean canRedo() { + return canRedo; + } @Override public String toString() { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryManager.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryManager.java index 183b152..0ab99f7 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryManager.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationHistoryManager.java @@ -1,14 +1,17 @@ package com.chuangzhou.vivid2D.render.awt.util; -import java.util.*; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; /** * 操作记录管理器 * 负责管理操作的撤回和重做 + * * @author tzdwindows 7 */ public class OperationHistoryManager { - private static OperationHistoryManager instance = new OperationHistoryManager(); + private static final OperationHistoryManager instance = new OperationHistoryManager(); // 操作记录栈 private final LinkedList undoStack; private final LinkedList redoStack; @@ -35,6 +38,7 @@ public class OperationHistoryManager { /** * 获取操作记录管理器实例 + * * @return 操作记录管理器实例 */ public static OperationHistoryManager getInstance() { @@ -43,8 +47,9 @@ public class OperationHistoryManager { /** * 注册操作记录器 + * * @param operationType 操作类型标识 - * @param recorder 操作记录器 + * @param recorder 操作记录器 */ public void registerRecorder(String operationType, OperationRecorder recorder) { recorderMap.put(operationType, recorder); @@ -52,8 +57,9 @@ public class OperationHistoryManager { /** * 记录操作 + * * @param operationType 操作类型 - * @param params 操作参数 + * @param params 操作参数 */ public void recordOperation(String operationType, Object... params) { if (!enabled) return; @@ -203,9 +209,20 @@ public class OperationHistoryManager { this.timestamp = System.currentTimeMillis(); } - public String getOperationType() { return operationType; } - public Object[] getParams() { return params; } - public String getDescription() { return description; } - public long getTimestamp() { return timestamp; } + public String getOperationType() { + return operationType; + } + + public Object[] getParams() { + return params; + } + + public String getDescription() { + return description; + } + + public long getTimestamp() { + return timestamp; + } } } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationListener.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationListener.java index ce1fbf5..9242d8c 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationListener.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationListener.java @@ -8,9 +8,10 @@ public interface OperationListener { /** * 操作事件回调 + * * @param operationType 操作类型 - * @param action 动作类型(record, execute, undo, redo, clear) - * @param params 操作参数 + * @param action 动作类型(record, execute, undo, redo, clear) + * @param params 操作参数 */ void onOperationEvent(String operationType, String action, Object... params); } \ No newline at end of file diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationRecorder.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationRecorder.java index 59f3503..0580109 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationRecorder.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/OperationRecorder.java @@ -3,24 +3,28 @@ package com.chuangzhou.vivid2D.render.awt.util; /** * 操作记录接口 * 用于注册需要支持撤回/重做的操作 + * * @author tzdwindows 7 */ public interface OperationRecorder { /** * 执行操作(用于重做) + * * @param params 操作参数 */ void execute(Object... params); /** * 撤销操作 + * * @param params 操作参数 */ void undo(Object... params); /** * 获取操作描述(用于UI显示) + * * @return 操作描述 */ String getDescription(); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PSD_Structure_Dumper.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PSD_Structure_Dumper.java index 612bc83..3153203 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PSD_Structure_Dumper.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PSD_Structure_Dumper.java @@ -109,7 +109,7 @@ public class PSD_Structure_Dumper { } System.out.println(" --- 额外数据块遍历结束 ---"); // 确保指针移动到下一个图层记录的开始 - if(fis.getChannel().position() != extraDataEndPos) { + if (fis.getChannel().position() != extraDataEndPos) { long diff = extraDataEndPos - fis.getChannel().position(); System.out.printf("!!! 指针与预期不符,强制跳过 %d 字节以对齐下一个图层%n", diff); skipFully(dis, diff); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/AnimationParameter.java b/src/main/java/com/chuangzhou/vivid2D/render/model/AnimationParameter.java index cbbfccf..6d8529e 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/AnimationParameter.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/AnimationParameter.java @@ -1,11 +1,11 @@ package com.chuangzhou.vivid2D.render.model; public class AnimationParameter { - private String id; + private final String id; private float value; - private float defaultValue; - private float minValue; - private float maxValue; + private final float defaultValue; + private final float minValue; + private final float maxValue; private boolean changed = false; public AnimationParameter(String id, float min, float max, float defaultValue) { @@ -24,18 +24,33 @@ public class AnimationParameter { } } - public boolean hasChanged() { return changed; } - public void markClean() { this.changed = false; } + public boolean hasChanged() { + return changed; + } - public float getValue() { return value; } + public void markClean() { + this.changed = false; + } - public String getId() { return id; } + public float getValue() { + return value; + } - public float getMinValue() { return minValue; } + public String getId() { + return id; + } - public float getMaxValue() { return maxValue; } + public float getMinValue() { + return minValue; + } - public float getDefaultValue() { return defaultValue; } + public float getMaxValue() { + return maxValue; + } + + public float getDefaultValue() { + return defaultValue; + } public void reset() { this.value = defaultValue; diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/Model2D.java b/src/main/java/com/chuangzhou/vivid2D/render/model/Model2D.java index eb3335f..5306b55 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/Model2D.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/Model2D.java @@ -1,11 +1,11 @@ package com.chuangzhou.vivid2D.render.model; -import javax.swing.tree.DefaultMutableTreeNode; import com.chuangzhou.vivid2D.render.model.data.ModelData; import com.chuangzhou.vivid2D.render.model.data.ModelMetadata; import com.chuangzhou.vivid2D.render.model.util.*; import org.joml.Matrix3f; +import javax.swing.tree.DefaultMutableTreeNode; import java.util.*; /** @@ -94,6 +94,7 @@ public class Model2D { } // ==================== 姿态管理 ==================== + /** * 添加或更新姿态 */ @@ -559,21 +560,42 @@ public class Model2D { } // ==================== Getter/Setter ==================== - public String getName() { return name; } - public void setName(String name) { this.name = name; } + public String getName() { + return name; + } - public UUID getUuid() { return uuid; } - public void setUuid(UUID uuid) { this.uuid = uuid; } + public void setName(String name) { + this.name = name; + } - public ModelMetadata getMetadata() { return metadata; } - public void setMetadata(ModelMetadata metadata) { this.metadata = metadata; } + public UUID getUuid() { + return uuid; + } - public ModelPart getRootPart() { return rootPart; } - public void setRootPart(ModelPart rootPart) { this.rootPart = rootPart; } + public void setUuid(UUID uuid) { + this.uuid = uuid; + } + + public ModelMetadata getMetadata() { + return metadata; + } + + public void setMetadata(ModelMetadata metadata) { + this.metadata = metadata; + } + + public ModelPart getRootPart() { + return rootPart; + } + + public void setRootPart(ModelPart rootPart) { + this.rootPart = rootPart; + } - - public List getMeshes() { return Collections.unmodifiableList(meshes); } + public List getMeshes() { + return Collections.unmodifiableList(meshes); + } public Map getParameters() { return Collections.unmodifiableMap(parameters); @@ -583,17 +605,35 @@ public class Model2D { return Collections.unmodifiableList(animationLayers); } - public PhysicsSystem getPhysics() { return physics; } + public PhysicsSystem getPhysics() { + return physics; + } + public ModelPose getCurrentPose() { return new ModelPose(currentPose); } - public float getBlendProgress() { return blendProgress; } - public boolean isBlending() { return blendProgress < 1.0f; } + + public float getBlendProgress() { + return blendProgress; + } + + public boolean isBlending() { + return blendProgress < 1.0f; + } + public Map getPoses() { return Collections.unmodifiableMap(poses); } - public BoundingBox getBounds() { return bounds; } - public String getVersion() { return version; } - public void setVersion(String version) { this.version = version; } + public BoundingBox getBounds() { + return bounds; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } } \ No newline at end of file diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java b/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java index c25313c..e50cad2 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java @@ -3,16 +3,16 @@ package com.chuangzhou.vivid2D.render.model; import com.chuangzhou.vivid2D.render.awt.util.OperationHistoryGlobal; import com.chuangzhou.vivid2D.render.model.util.BoundingBox; import com.chuangzhou.vivid2D.render.model.util.Deformer; +import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import com.chuangzhou.vivid2D.render.model.util.PuppetPin; import com.chuangzhou.vivid2D.render.systems.Matrix3fUtils; -import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import org.joml.Matrix3f; import org.joml.Vector2f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; import javax.swing.tree.DefaultMutableTreeNode; +import java.util.*; /** * 2D模型部件,支持层级变换和变形器 @@ -54,7 +54,7 @@ public class ModelPart { private final List events = new ArrayList<>(); private boolean inMultiSelectionOperation = false; - private boolean startLiquefy =false; + private boolean startLiquefy = false; // ====== 液化模式枚举 ====== public enum LiquifyMode { @@ -112,7 +112,7 @@ public class ModelPart { private void triggerEvent(String eventName) { for (ModelEvent event : events) { - event.trigger(eventName,this); + event.trigger(eventName, this); } } @@ -527,20 +527,20 @@ public class ModelPart { if (stroke == null || stroke.points == null) return; LiquifyMode mode = stroke.mode != null ? stroke.mode : LiquifyMode.PUSH; for (LiquifyPoint p : stroke.points) { - applyLiquify(new Vector2f(p.x, p.y), stroke.radius, stroke.strength, mode, stroke.iterations,true); + applyLiquify(new Vector2f(p.x, p.y), stroke.radius, stroke.strength, mode, stroke.iterations, true); } } /** * 对当前部件下所有网格应用液化笔效果(类似 Photoshop 的液化工具)。 * 请在使用前注册在使用addLiquifyStroke方法注册LiquifyStroke - * + *

* 注意: * - brushCenter 使用世界坐标(与 ModelPart 的世界坐标体系一致)。 * - radius 为画笔半径(像素),strength 为强度(建议范围 0.0 - 1.0,数值越大效果越强)。 * - mode 选择液化操作类型。 * - iterations 为迭代次数(>0),可用来让效果更平滑,默认 1 次即可。 - * + *

* 该方法会直接修改 mesh 的顶点并更新其边界(mesh.updateBounds)。 */ public void applyLiquify(Vector2f brushCenter, float radius, float strength, LiquifyMode mode, int iterations, boolean createVertices) { @@ -928,7 +928,7 @@ public class ModelPart { float brushArea = brushAreaWidth * brushAreaHeight; // 根据画笔大小和网格复杂度计算顶点密度 - int targetVertexCount = Math.max(4, Math.min(20, (int)(brushArea / (localRadius * localRadius * 0.5f)))); + int targetVertexCount = Math.max(4, Math.min(20, (int) (brushArea / (localRadius * localRadius * 0.5f)))); // 在画笔区域内均匀添加顶点 boolean addedVertices = addUniformVerticesInArea(mesh, newVertices, newUVs, newIndices, @@ -1899,7 +1899,6 @@ public class ModelPart { } - public void setScale(float uniformScale) { // 记录旧的世界变换,用于计算 pivot 的相对位置 Matrix3f oldWorldTransform = new Matrix3f(this.worldTransform); @@ -1992,7 +1991,8 @@ public class ModelPart { Vector2f origPivot = mesh.getOriginalPivot(); Vector2f worldPivot = Matrix3fUtils.transformPoint(this.worldTransform, origPivot); mesh.setPivot(worldPivot.x, worldPivot.y); - } catch (Exception ignored) { } + } catch (Exception ignored) { + } // ==================== 新增:初始化木偶控制点的位置 ==================== initializePuppetPinsPosition(mesh); @@ -2079,7 +2079,7 @@ public class ModelPart { // 由于 Mesh2D 的 originalPivot 已经存储了其在 ModelPart 局部坐标系中的相对位置, // 我们可以直接将 ModelPart 的新 pivot 赋值给 Mesh2D 的 originalPivot // 然后再通过变换更新 Mesh2D 的实际 pivot - if (!mesh.setOriginalPivot(new Vector2f(x, y))){ + if (!mesh.setOriginalPivot(new Vector2f(x, y))) { return false; } // Mesh2D 的实际 pivot 应该根据 ModelPart 的世界变换来计算 @@ -2289,8 +2289,13 @@ public class ModelPart { return opacity; } - public float getScaleX() { return scaleX; } - public float getScaleY() { return scaleY; } + public float getScaleX() { + return scaleX; + } + + public float getScaleY() { + return scaleY; + } public void setOpacity(float opacity) { this.opacity = Math.max(0.0f, Math.min(1.0f, opacity)); @@ -2306,7 +2311,8 @@ public class ModelPart { public float y; public float pressure = 1.0f; - public LiquifyPoint() {} + public LiquifyPoint() { + } public LiquifyPoint(float x, float y) { this.x = x; @@ -2319,9 +2325,17 @@ public class ModelPart { this.pressure = pressure; } - public float getX() { return x; } - public float getY() { return y; } - public float getPressure() { return pressure; } + public float getX() { + return x; + } + + public float getY() { + return y; + } + + public float getPressure() { + return pressure; + } } // ====== 液化笔划数据结构(包含点序列与笔划参数),提供 getter 以便反射读取 ====== @@ -2332,7 +2346,8 @@ public class ModelPart { public int iterations = 1; public List points = new ArrayList<>(); - public LiquifyStroke() {} + public LiquifyStroke() { + } public LiquifyStroke(LiquifyMode mode, float radius, float strength, int iterations) { this.mode = mode; @@ -2341,11 +2356,25 @@ public class ModelPart { this.iterations = iterations; } - public String getMode() { return mode.name(); } // PartData 反射时读取字符串也可 - public float getRadius() { return radius; } - public float getStrength() { return strength; } - public int getIterations() { return iterations; } - public List getPoints() { return points; } + public String getMode() { + return mode.name(); + } // PartData 反射时读取字符串也可 + + public float getRadius() { + return radius; + } + + public float getStrength() { + return strength; + } + + public int getIterations() { + return iterations; + } + + public List getPoints() { + return points; + } public void addPoint(float x, float y, float pressure) { this.points.add(new LiquifyPoint(x, y, pressure)); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/AnimationLayerData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/AnimationLayerData.java index f4d1f9b..c4bb5d8 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/AnimationLayerData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/AnimationLayerData.java @@ -11,6 +11,7 @@ import java.util.Map; /** * 动画层数据 + * * @author tzdwindows 7 */ public class AnimationLayerData implements Serializable { @@ -151,7 +152,8 @@ public class AnimationLayerData implements Serializable { public float value; public AnimationLayer.InterpolationType interpolation; - public KeyframeData() {} + public KeyframeData() { + } public KeyframeData(AnimationLayer.Keyframe keyframe) { this.time = keyframe.getTime(); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/MeshData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/MeshData.java index de44c6b..ab7f3fb 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/MeshData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/MeshData.java @@ -286,7 +286,8 @@ public class MeshData implements Serializable { public Vector2f uv; public boolean selected; - public SecondaryVertexData() {} + public SecondaryVertexData() { + } public SecondaryVertexData(SecondaryVertex vertex) { this.id = vertex.getId(); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelData.java index 0a26ec9..cc0aa51 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelData.java @@ -20,7 +20,7 @@ import java.util.zip.GZIPOutputStream; * @author tzdwindows 7 */ public class ModelData implements Serializable { - private static Logger logger = LoggerFactory.getLogger(ModelData.class); + private static final Logger logger = LoggerFactory.getLogger(ModelData.class); private static final long serialVersionUID = 1L; // ==================== 模型元数据 ==================== @@ -39,11 +39,11 @@ public class ModelData implements Serializable { private List parameters; private List animations; private List animationLayers; - private List physicsParticles; - private List physicsSprings; - private List physicsColliders; - private List physicsConstraints; - private List lights; + private final List physicsParticles; + private final List physicsSprings; + private final List physicsColliders; + private final List physicsConstraints; + private final List lights; private List poses; private String currentPoseName; // 当前应用的姿态名称 @@ -163,8 +163,7 @@ public class ModelData implements Serializable { // 约束(仅序列化常见两类) for (PhysicsSystem.PhysicsConstraint c : phys.getConstraints()) { - if (c instanceof PhysicsSystem.PositionConstraint) { - PhysicsSystem.PositionConstraint pc = (PhysicsSystem.PositionConstraint) c; + if (c instanceof PhysicsSystem.PositionConstraint pc) { ConstraintData cd = new ConstraintData(); cd.type = "position"; cd.particleId = pc.getParticle().getId(); @@ -174,8 +173,7 @@ public class ModelData implements Serializable { cd.strength = pc.getStrength(); cd.enabled = pc.isEnabled(); physicsConstraints.add(cd); - } else if (c instanceof PhysicsSystem.DistanceConstraint) { - PhysicsSystem.DistanceConstraint dc = (PhysicsSystem.DistanceConstraint) c; + } else if (c instanceof PhysicsSystem.DistanceConstraint dc) { ConstraintData cd = new ConstraintData(); cd.type = "distance"; cd.particleId = dc.getParticle().getId(); @@ -193,14 +191,12 @@ public class ModelData implements Serializable { ColliderData cd = new ColliderData(); cd.id = collider.getId(); cd.enabled = collider.isEnabled(); - if (collider instanceof PhysicsSystem.CircleCollider) { - PhysicsSystem.CircleCollider cc = (PhysicsSystem.CircleCollider) collider; + if (collider instanceof PhysicsSystem.CircleCollider cc) { cd.type = "circle"; cd.centerX = cc.getCenter().x; cd.centerY = cc.getCenter().y; cd.radius = cc.getRadius(); - } else if (collider instanceof PhysicsSystem.RectangleCollider) { - PhysicsSystem.RectangleCollider rc = (PhysicsSystem.RectangleCollider) collider; + } else if (collider instanceof PhysicsSystem.RectangleCollider rc) { cd.type = "rect"; cd.centerX = rc.getCenter().x; cd.centerY = rc.getCenter().y; @@ -538,7 +534,6 @@ public class ModelData implements Serializable { } - private Map deserializeTextures() { Map textureMap = new HashMap<>(); @@ -859,7 +854,6 @@ public class ModelData implements Serializable { // ==================== 内部数据类 ==================== - // ---------- 物理数据的序列化类 ---------- public static class ParticleData implements Serializable { public String id; @@ -956,7 +950,6 @@ public class ModelData implements Serializable { } - /** * 参数数据 */ @@ -969,7 +962,8 @@ public class ModelData implements Serializable { public float minValue; public float maxValue; - public ParameterData() {} + public ParameterData() { + } public ParameterData(AnimationParameter param) { this.id = param.getId(); @@ -1042,60 +1036,146 @@ public class ModelData implements Serializable { // ==================== Getter/Setter ==================== - public String getName() { return name; } - public void setName(String name) { this.name = name; } + public String getName() { + return name; + } - public String getVersion() { return version; } - public void setVersion(String version) { this.version = version; } + public void setName(String name) { + this.name = name; + } - public UUID getUuid() { return uuid; } - public void setUuid(UUID uuid) { this.uuid = uuid; } + public String getVersion() { + return version; + } - public String getAuthor() { return author; } - public void setAuthor(String author) { this.author = author; } + public void setVersion(String version) { + this.version = version; + } - public String getDescription() { return description; } - public void setDescription(String description) { this.description = description; } + public UUID getUuid() { + return uuid; + } - public long getCreationTime() { return creationTime; } - public void setCreationTime(long creationTime) { this.creationTime = creationTime; } + public void setUuid(UUID uuid) { + this.uuid = uuid; + } - public long getLastModifiedTime() { return lastModifiedTime; } - public void setLastModifiedTime(long lastModifiedTime) { this.lastModifiedTime = lastModifiedTime; } + public String getAuthor() { + return author; + } - public List getParts() { return parts; } - public void setParts(List parts) { this.parts = parts; } + public void setAuthor(String author) { + this.author = author; + } - public List getMeshes() { return meshes; } - public void setMeshes(List meshes) { this.meshes = meshes; } + public String getDescription() { + return description; + } - public List getTextures() { return textures; } - public void setTextures(List textures) { this.textures = textures; } + public void setDescription(String description) { + this.description = description; + } - public List getParameters() { return parameters; } - public void setParameters(List parameters) { this.parameters = parameters; } + public long getCreationTime() { + return creationTime; + } - public List getAnimations() { return animations; } - public void setAnimations(List animations) { this.animations = animations; } + public void setCreationTime(long creationTime) { + this.creationTime = creationTime; + } - public Vector2f getPivotPoint() { return pivotPoint; } - public void setPivotPoint(Vector2f pivotPoint) { this.pivotPoint = pivotPoint; } + public long getLastModifiedTime() { + return lastModifiedTime; + } - public float getUnitsPerMeter() { return unitsPerMeter; } - public void setUnitsPerMeter(float unitsPerMeter) { this.unitsPerMeter = unitsPerMeter; } + public void setLastModifiedTime(long lastModifiedTime) { + this.lastModifiedTime = lastModifiedTime; + } - public Map getUserData() { return userData; } - public void setUserData(Map userData) { this.userData = userData; } + public List getParts() { + return parts; + } + + public void setParts(List parts) { + this.parts = parts; + } + + public List getMeshes() { + return meshes; + } + + public void setMeshes(List meshes) { + this.meshes = meshes; + } + + public List getTextures() { + return textures; + } + + public void setTextures(List textures) { + this.textures = textures; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public List getAnimations() { + return animations; + } + + public void setAnimations(List animations) { + this.animations = animations; + } + + public Vector2f getPivotPoint() { + return pivotPoint; + } + + public void setPivotPoint(Vector2f pivotPoint) { + this.pivotPoint = pivotPoint; + } + + public float getUnitsPerMeter() { + return unitsPerMeter; + } + + public void setUnitsPerMeter(float unitsPerMeter) { + this.unitsPerMeter = unitsPerMeter; + } + + public Map getUserData() { + return userData; + } + + public void setUserData(Map userData) { + this.userData = userData; + } + + public List getAnimationLayers() { + return animationLayers; + } - public List getAnimationLayers() { return animationLayers; } public void setAnimationLayers(List animationLayers) { this.animationLayers = animationLayers; } - public List getPoses() { return poses; } - public void setPoses(List poses) { this.poses = poses; } + public List getPoses() { + return poses; + } + + public void setPoses(List poses) { + this.poses = poses; + } + + public String getCurrentPoseName() { + return currentPoseName; + } - public String getCurrentPoseName() { return currentPoseName; } public void setCurrentPoseName(String currentPoseName) { this.currentPoseName = currentPoseName; } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelMetadata.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelMetadata.java index 4a98b6a..584cf71 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelMetadata.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/ModelMetadata.java @@ -270,7 +270,7 @@ public class ModelMetadata implements Serializable, Cloneable { // 粗略估算:顶点数据 + 纹理数据 + 其他开销 long vertexDataSize = (long) vertexCount * 8 * 2; // 每个顶点8字节(float x,y),2份(原始+变形) long textureDataSize = (long) textureCount * 1024 * 1024; // 假设每个纹理1MB - long otherDataSize = (long) (parameterCount * 16 + partCount * 64 + polygonCount * 12); + long otherDataSize = parameterCount * 16L + partCount * 64L + polygonCount * 12L; return vertexDataSize + textureDataSize + otherDataSize + 1024; // +1KB元数据 } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartPoseData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartPoseData.java index cb253c0..a9d3ff2 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartPoseData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartPoseData.java @@ -6,6 +6,7 @@ import java.io.Serializable; /** * 部件姿态数据序列化类 + * * @author tzdwindows 7 */ public class PartPoseData implements Serializable { @@ -19,7 +20,8 @@ public class PartPoseData implements Serializable { public boolean visible; public float colorR, colorG, colorB; - public PartPoseData() {} + public PartPoseData() { + } public PartPoseData(String partName, ModelPose.PartPose partPose) { this.partName = partName; diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/PoseData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/PoseData.java index 12f568e..83b5053 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/PoseData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/PoseData.java @@ -8,6 +8,7 @@ import java.util.List; /** * 姿态数据序列化类 + * * @author tzdwindows 7 */ public class PoseData implements Serializable { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/RotationDeformer.java b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/RotationDeformer.java index 8360059..1234b81 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/RotationDeformer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/RotationDeformer.java @@ -4,7 +4,6 @@ import com.chuangzhou.vivid2D.render.model.util.Deformer; import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import org.joml.Vector2f; -import java.util.List; import java.util.Map; /** @@ -98,11 +97,23 @@ public class RotationDeformer extends Deformer { } // Getter/Setter - public float getBaseAngle() { return baseAngle; } - public void setBaseAngle(float baseAngle) { this.baseAngle = baseAngle; } + public float getBaseAngle() { + return baseAngle; + } - public float getAngleRange() { return angleRange; } - public void setAngleRange(float angleRange) { this.angleRange = angleRange; } + public void setBaseAngle(float baseAngle) { + this.baseAngle = baseAngle; + } - public float getCurrentAngle() { return currentAngle; } + public float getAngleRange() { + return angleRange; + } + + public void setAngleRange(float angleRange) { + this.angleRange = angleRange; + } + + public float getCurrentAngle() { + return currentAngle; + } } \ No newline at end of file diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/VertexDeformer.java b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/VertexDeformer.java index 2cea5b6..1e1c69f 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/VertexDeformer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/VertexDeformer.java @@ -29,9 +29,10 @@ public class VertexDeformer extends Deformer { } /** - * 顶点变形数据内部类 - */ - private record VertexDeformation(float originalX, float originalY, float targetX, float targetY) { } + * 顶点变形数据内部类 + */ + private record VertexDeformation(float originalX, float originalY, float targetX, float targetY) { + } /** * 添加顶点变形目标 @@ -212,17 +213,20 @@ public class VertexDeformer extends Deformer { try { String enabledKey = map.get(name + ".enabled"); if (enabledKey != null) this.enabled = Boolean.parseBoolean(enabledKey); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } try { String weightKey = map.get(name + ".weight"); if (weightKey != null) this.weight = Float.parseFloat(weightKey); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } try { String curKey = map.get(name + ".currentValue"); if (curKey != null) this.currentValue = Float.parseFloat(curKey); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } // 清空已有数据 this.vertexDeformations.clear(); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/WaveDeformer.java b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/WaveDeformer.java index bdf4645..ca0117a 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/WaveDeformer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/WaveDeformer.java @@ -4,7 +4,6 @@ import com.chuangzhou.vivid2D.render.model.util.Deformer; import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import org.joml.Vector2f; -import java.util.List; import java.util.Map; /** @@ -247,7 +246,8 @@ public class WaveDeformer extends Deformer { public float timeMultiplier = 1.0f; public float weight = 1.0f; - public WaveConfig() {} + public WaveConfig() { + } public WaveConfig(float amplitude, float frequency, float phase, float waveAngle, float timeMultiplier, float weight) { @@ -287,24 +287,56 @@ public class WaveDeformer extends Deformer { timeMultiplier = Float.parseFloat(map.get("timeMultiplier")); } - public float getTimeMultiplier() { return timeMultiplier; } - public void setTimeMultiplier(float timeMultiplier) { this.timeMultiplier = timeMultiplier; } + public float getTimeMultiplier() { + return timeMultiplier; + } - public ControlMode getControlMode() { return controlMode; } + public void setTimeMultiplier(float timeMultiplier) { + this.timeMultiplier = timeMultiplier; + } + + public ControlMode getControlMode() { + return controlMode; + } // Getter/Setter - public float getAmplitude() { return amplitude; } - public void setAmplitude(float amplitude) { this.amplitude = amplitude; } + public float getAmplitude() { + return amplitude; + } - public float getFrequency() { return frequency; } - public void setFrequency(float frequency) { this.frequency = frequency; } + public void setAmplitude(float amplitude) { + this.amplitude = amplitude; + } - public float getPhase() { return phase; } - public void setPhase(float phase) { this.phase = phase; } + public float getFrequency() { + return frequency; + } - public float getWaveAngle() { return waveAngle; } - public void setWaveAngle(float waveAngle) { this.waveAngle = waveAngle; } + public void setFrequency(float frequency) { + this.frequency = frequency; + } - public float getCurrentTime() { return currentTime; } - public void setCurrentTime(float currentTime) { this.currentTime = currentTime; } + public float getPhase() { + return phase; + } + + public void setPhase(float phase) { + this.phase = phase; + } + + public float getWaveAngle() { + return waveAngle; + } + + public void setWaveAngle(float waveAngle) { + this.waveAngle = waveAngle; + } + + public float getCurrentTime() { + return currentTime; + } + + public void setCurrentTime(float currentTime) { + this.currentTime = currentTime; + } } \ No newline at end of file diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationLayer.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationLayer.java index 58b3091..d42103a 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationLayer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationLayer.java @@ -31,7 +31,7 @@ public class AnimationLayer { private float currentTime; private boolean playing; private boolean paused; - private Map parameterOverrides; + private final Map parameterOverrides; // ==================== 事件系统 ==================== private final List eventListeners; @@ -468,22 +468,45 @@ public class AnimationLayer { // ==================== Getter/Setter ==================== - public String getName() { return name; } - public UUID getUuid() { return uuid; } + public String getName() { + return name; + } + + public UUID getUuid() { + return uuid; + } + + public float getWeight() { + return weight; + } - public float getWeight() { return weight; } public void setWeight(float weight) { this.weight = Math.max(0.0f, Math.min(1.0f, weight)); } - public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } + public boolean isEnabled() { + return enabled; + } - public BlendMode getBlendMode() { return blendMode; } - public void setBlendMode(BlendMode blendMode) { this.blendMode = blendMode; } + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } - public int getPriority() { return priority; } - public void setPriority(int priority) { this.priority = priority; } + public BlendMode getBlendMode() { + return blendMode; + } + + public void setBlendMode(BlendMode blendMode) { + this.blendMode = blendMode; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } public Map getTracks() { return Collections.unmodifiableMap(tracks); @@ -493,20 +516,37 @@ public class AnimationLayer { return Collections.unmodifiableList(clips); } - public AnimationClip getCurrentClip() { return currentClip; } + public AnimationClip getCurrentClip() { + return currentClip; + } + + public float getPlaybackSpeed() { + return playbackSpeed; + } - public float getPlaybackSpeed() { return playbackSpeed; } public void setPlaybackSpeed(float playbackSpeed) { this.playbackSpeed = Math.max(0.0f, playbackSpeed); } - public boolean isLooping() { return looping; } - public void setLooping(boolean looping) { this.looping = looping; } + public boolean isLooping() { + return looping; + } - public float getCurrentTime() { return currentTime; } + public void setLooping(boolean looping) { + this.looping = looping; + } - public boolean isPlaying() { return playing; } - public boolean isPaused() { return paused; } + public float getCurrentTime() { + return currentTime; + } + + public boolean isPlaying() { + return playing; + } + + public boolean isPaused() { + return paused; + } public Map getParameterOverrides() { return Collections.unmodifiableMap(parameterOverrides); @@ -616,12 +656,29 @@ public class AnimationLayer { } // Getter/Setter - public String getParameterId() { return parameterId; } - public List getKeyframes() { return Collections.unmodifiableList(keyframes); } - public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } - public InterpolationType getInterpolation() { return interpolation; } - public void setInterpolation(InterpolationType interpolation) { this.interpolation = interpolation; } + public String getParameterId() { + return parameterId; + } + + public List getKeyframes() { + return Collections.unmodifiableList(keyframes); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public InterpolationType getInterpolation() { + return interpolation; + } + + public void setInterpolation(InterpolationType interpolation) { + this.interpolation = interpolation; + } } /** @@ -643,9 +700,17 @@ public class AnimationLayer { } // Getter - public float getTime() { return time; } - public float getValue() { return value; } - public InterpolationType getInterpolation() { return interpolation; } + public float getTime() { + return time; + } + + public float getValue() { + return value; + } + + public InterpolationType getInterpolation() { + return interpolation; + } } /** @@ -687,9 +752,17 @@ public class AnimationLayer { } // Getter - public String getName() { return name; } - public float getTime() { return time; } - public boolean isTriggered() { return triggered; } + public String getName() { + return name; + } + + public float getTime() { + return time; + } + + public boolean isTriggered() { + return triggered; + } } /** @@ -697,11 +770,17 @@ public class AnimationLayer { */ public interface AnimationEventListener { void onAnimationStarted(AnimationLayer layer, AnimationClip clip); + void onAnimationStopped(AnimationLayer layer, AnimationClip clip); + void onAnimationPaused(AnimationLayer layer, AnimationClip clip); + void onAnimationResumed(AnimationLayer layer, AnimationClip clip); + void onAnimationCompleted(AnimationLayer layer, AnimationClip clip); + void onAnimationLooped(AnimationLayer layer, AnimationClip clip); + void onEventTriggered(AnimationLayer layer, AnimationEvent event); } @@ -709,13 +788,33 @@ public class AnimationLayer { * 简单的动画事件监听器适配器 */ public static abstract class AnimationEventAdapter implements AnimationEventListener { - @Override public void onAnimationStarted(AnimationLayer layer, AnimationClip clip) {} - @Override public void onAnimationStopped(AnimationLayer layer, AnimationClip clip) {} - @Override public void onAnimationPaused(AnimationLayer layer, AnimationClip clip) {} - @Override public void onAnimationResumed(AnimationLayer layer, AnimationClip clip) {} - @Override public void onAnimationCompleted(AnimationLayer layer, AnimationClip clip) {} - @Override public void onAnimationLooped(AnimationLayer layer, AnimationClip clip) {} - @Override public void onEventTriggered(AnimationLayer layer, AnimationEvent event) {} + @Override + public void onAnimationStarted(AnimationLayer layer, AnimationClip clip) { + } + + @Override + public void onAnimationStopped(AnimationLayer layer, AnimationClip clip) { + } + + @Override + public void onAnimationPaused(AnimationLayer layer, AnimationClip clip) { + } + + @Override + public void onAnimationResumed(AnimationLayer layer, AnimationClip clip) { + } + + @Override + public void onAnimationCompleted(AnimationLayer layer, AnimationClip clip) { + } + + @Override + public void onAnimationLooped(AnimationLayer layer, AnimationClip clip) { + } + + @Override + public void onEventTriggered(AnimationLayer layer, AnimationEvent event) { + } } // ==================== Object 方法 ==================== diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Deformer.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Deformer.java index 2428720..f039855 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Deformer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Deformer.java @@ -229,12 +229,13 @@ public abstract class Deformer { * 变形范围控制 */ public static class DeformationRange { - private Vector2f center = new Vector2f(0, 0); + private final Vector2f center = new Vector2f(0, 0); private float radius = 100.0f; private float innerRadius = 0.0f; private float falloff = 2.0f; - public DeformationRange() {} + public DeformationRange() { + } public DeformationRange(Vector2f center, float radius) { this.center.set(center); @@ -263,17 +264,40 @@ public abstract class Deformer { } // Getter/Setter - public Vector2f getCenter() { return new Vector2f(center); } - public void setCenter(Vector2f center) { this.center.set(center); } - public void setCenter(float x, float y) { this.center.set(x, y); } + public Vector2f getCenter() { + return new Vector2f(center); + } - public float getRadius() { return radius; } - public void setRadius(float radius) { this.radius = radius; } + public void setCenter(Vector2f center) { + this.center.set(center); + } - public float getInnerRadius() { return innerRadius; } - public void setInnerRadius(float innerRadius) { this.innerRadius = innerRadius; } + public void setCenter(float x, float y) { + this.center.set(x, y); + } - public float getFalloff() { return falloff; } - public void setFalloff(float falloff) { this.falloff = falloff; } + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public float getInnerRadius() { + return innerRadius; + } + + public void setInnerRadius(float innerRadius) { + this.innerRadius = innerRadius; + } + + public float getFalloff() { + return falloff; + } + + public void setFalloff(float falloff) { + this.falloff = falloff; + } } } \ No newline at end of file diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/LightSource.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/LightSource.java index 38282e1..e6f2350 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/LightSource.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/LightSource.java @@ -7,12 +7,13 @@ import java.awt.*; /** * 光源系统 + * * @author tzdwindows 7 */ public class LightSource { - private Vector2f position; - private Vector3f color; - private float intensity; + private final Vector2f position; + private final Vector3f color; + private final float intensity; private boolean enabled = true; private boolean isAmbient = false; // 是否为环境光 @@ -73,31 +74,73 @@ public class LightSource { return new Color(red, green, blue); } - public Vector2f getPosition() { return position; } - public Vector3f getColor() { return color; } - public float getIntensity() { return intensity; } - public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } + public Vector2f getPosition() { + return position; + } + + public Vector3f getColor() { + return color; + } + + public float getIntensity() { + return intensity; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } // 判断是否为环境光 - public boolean isAmbient() { return isAmbient; } - public void setAmbient(boolean ambient) { this.isAmbient = ambient; } + public boolean isAmbient() { + return isAmbient; + } + + public void setAmbient(boolean ambient) { + this.isAmbient = ambient; + } // ---- 辉光相关的 getter / setter ---- - public boolean isGlow() { return isGlow; } - public void setGlow(boolean glow) { this.isGlow = glow; } + public boolean isGlow() { + return isGlow; + } + + public void setGlow(boolean glow) { + this.isGlow = glow; + } + + public Vector2f getGlowDirection() { + return glowDirection; + } - public Vector2f getGlowDirection() { return glowDirection; } public void setGlowDirection(Vector2f glowDirection) { this.glowDirection = glowDirection != null ? glowDirection : new Vector2f(0f, 0f); } - public float getGlowIntensity() { return glowIntensity; } - public void setGlowIntensity(float glowIntensity) { this.glowIntensity = glowIntensity; } + public float getGlowIntensity() { + return glowIntensity; + } - public float getGlowRadius() { return glowRadius; } - public void setGlowRadius(float glowRadius) { this.glowRadius = glowRadius; } + public void setGlowIntensity(float glowIntensity) { + this.glowIntensity = glowIntensity; + } - public float getGlowAmount() { return glowAmount; } - public void setGlowAmount(float glowAmount) { this.glowAmount = glowAmount; } + public float getGlowRadius() { + return glowRadius; + } + + public void setGlowRadius(float glowRadius) { + this.glowRadius = glowRadius; + } + + public float getGlowAmount() { + return glowAmount; + } + + public void setGlowAmount(float glowAmount) { + this.glowAmount = glowAmount; + } } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/ModelPose.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/ModelPose.java index 59a36c3..7ae78b3 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/ModelPose.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/ModelPose.java @@ -21,12 +21,12 @@ public class ModelPose { * 单个部件的姿态数据 */ public static class PartPose { - private Vector2f position; + private final Vector2f position; private float rotation; - private Vector2f scale; + private final Vector2f scale; private float opacity; private boolean visible; - private Vector3f color; // RGB颜色乘数 + private final Vector3f color; // RGB颜色乘数 public PartPose() { this(new Vector2f(0, 0), 0.0f, new Vector2f(1, 1), 1.0f, true, new Vector3f(1, 1, 1)); @@ -93,23 +93,53 @@ public class ModelPose { // ================== Getter和Setter ================== - public Vector2f getPosition() { return new Vector2f(position); } - public void setPosition(Vector2f position) { this.position.set(position); } + public Vector2f getPosition() { + return new Vector2f(position); + } - public float getRotation() { return rotation; } - public void setRotation(float rotation) { this.rotation = rotation; } + public void setPosition(Vector2f position) { + this.position.set(position); + } - public Vector2f getScale() { return new Vector2f(scale); } - public void setScale(Vector2f scale) { this.scale.set(scale); } + public float getRotation() { + return rotation; + } - public float getOpacity() { return opacity; } - public void setOpacity(float opacity) { this.opacity = opacity; } + public void setRotation(float rotation) { + this.rotation = rotation; + } - public boolean isVisible() { return visible; } - public void setVisible(boolean visible) { this.visible = visible; } + public Vector2f getScale() { + return new Vector2f(scale); + } - public Vector3f getColor() { return new Vector3f(color); } - public void setColor(Vector3f color) { this.color.set(color); } + public void setScale(Vector2f scale) { + this.scale.set(scale); + } + + public float getOpacity() { + return opacity; + } + + public void setOpacity(float opacity) { + this.opacity = opacity; + } + + public boolean isVisible() { + return visible; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } + + public Vector3f getColor() { + return new Vector3f(color); + } + + public void setColor(Vector3f color) { + this.color.set(color); + } @Override public boolean equals(Object o) { @@ -357,14 +387,29 @@ public class ModelPose { // ================== Getter和Setter ================== - public String getName() { return name; } - public void setName(String name) { this.name = name; } + public String getName() { + return name; + } - public float getBlendTime() { return blendTime; } - public void setBlendTime(float blendTime) { this.blendTime = Math.max(0, blendTime); } + public void setName(String name) { + this.name = name; + } - public boolean isDefaultPose() { return isDefaultPose; } - public void setDefaultPose(boolean defaultPose) { isDefaultPose = defaultPose; } + public float getBlendTime() { + return blendTime; + } + + public void setBlendTime(float blendTime) { + this.blendTime = Math.max(0, blendTime); + } + + public boolean isDefaultPose() { + return isDefaultPose; + } + + public void setDefaultPose(boolean defaultPose) { + isDefaultPose = defaultPose; + } // ================== 工具方法 ================== diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/PuppetPin.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/PuppetPin.java index a37ed52..3fe9430 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/PuppetPin.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/PuppetPin.java @@ -12,15 +12,15 @@ public class PuppetPin { private static int NEXT_ID = 0; private int id; - private Vector2f position; - private Vector2f originalPosition; - private Vector2f uv; + private final Vector2f position; + private final Vector2f originalPosition; + private final Vector2f uv; private float influenceRadius = 100.0f; private boolean selected = false; private String name; // 权重贴图(顶点索引 -> 权重值) - private Map weightMap = new HashMap<>(); + private final Map weightMap = new HashMap<>(); public PuppetPin(float x, float y, float u, float v) { this.id = NEXT_ID++; @@ -97,18 +97,53 @@ public class PuppetPin { // ==================== 原有方法 ==================== // Getters and Setters - public Vector2f getPosition() { return new Vector2f(position); } - public void setPosition(float x, float y) { this.position.set(x, y); } - public void setPosition(Vector2f pos) { this.position.set(pos); } - public Vector2f getOriginalPosition() { return new Vector2f(originalPosition); } - public float getInfluenceRadius() { return influenceRadius; } - public void setInfluenceRadius(float radius) { this.influenceRadius = radius; } - public boolean isSelected() { return selected; } - public void setSelected(boolean selected) { this.selected = selected; } - public int getId() { return id; } - public String getName() { return name; } - public void setName(String name) { this.name = name; } - public Map getWeightMap() { return new HashMap<>(weightMap); } + public Vector2f getPosition() { + return new Vector2f(position); + } + + public void setPosition(float x, float y) { + this.position.set(x, y); + } + + public void setPosition(Vector2f pos) { + this.position.set(pos); + } + + public Vector2f getOriginalPosition() { + return new Vector2f(originalPosition); + } + + public float getInfluenceRadius() { + return influenceRadius; + } + + public void setInfluenceRadius(float radius) { + this.influenceRadius = radius; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getWeightMap() { + return new HashMap<>(weightMap); + } public void move(float dx, float dy) { position.add(dx, dy); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/SaveVector2f.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/SaveVector2f.java index de6e6e8..b4e8574 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/SaveVector2f.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/SaveVector2f.java @@ -5,8 +5,8 @@ import org.joml.Vector2f; /** * 工具类:用于在 Vector2f 和字符串之间进行转换。 * 例如: - * - toString(new Vector2f(1.5f, -2.0f)) => "1.5,-2.0" - * - fromString("1.5,-2.0") => new Vector2f(1.5f, -2.0f) + * - toString(new Vector2f(1.5f, -2.0f)) => "1.5,-2.0" + * - fromString("1.5,-2.0") => new Vector2f(1.5f, -2.0f) * * @author tzdwindows 7 */ @@ -26,9 +26,9 @@ public class SaveVector2f { /** * 从字符串解析为 Vector2f。 * 允许的格式: - * - "x,y" - * - "(x,y)" - * - " x , y " + * - "x,y" + * - "(x,y)" + * - " x , y " * 若格式错误则返回 (0,0) */ public static Vector2f fromString(String str) { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/SecondaryVertex.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/SecondaryVertex.java index 51b8cec..7088e6f 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/SecondaryVertex.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/SecondaryVertex.java @@ -27,11 +27,25 @@ public class SecondaryVertex { } // Getter和Setter方法 - public Vector2f getPosition() { return new Vector2f(position); } - public Vector2f getOriginalPosition() { return new Vector2f(originalPosition); } - public Vector2f getUV() { return new Vector2f(uv); } - public boolean isSelected() { return selected; } - public int getId() { return id; } + public Vector2f getPosition() { + return new Vector2f(position); + } + + public Vector2f getOriginalPosition() { + return new Vector2f(originalPosition); + } + + public Vector2f getUV() { + return new Vector2f(uv); + } + + public boolean isSelected() { + return selected; + } + + public int getId() { + return id; + } public void setPosition(float x, float y) { this.position.set(x, y); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/Camera.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/Camera.java index 6107dc0..341827e 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/Camera.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/Camera.java @@ -4,6 +4,7 @@ import org.joml.Vector2f; /** * 摄像机类 + * * @author tzdwindows 7 */ public class Camera { @@ -12,7 +13,8 @@ public class Camera { private float zPosition = 0.0f; private boolean enabled = true; - public Camera() {} + public Camera() { + } public void setPosition(float x, float y) { position.set(x, y); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferBuilder.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferBuilder.java index b43b659..c2fb1f5 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferBuilder.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferBuilder.java @@ -11,20 +11,19 @@ import java.nio.FloatBuffer; /** * 简化版 BufferBuilder,用于按顶点流构建并一次性绘制几何体。 * 每个顶点格式: float x, float y, float u, float v (共4个 float) - * + *

* 用法: - * BufferBuilder bb = new BufferBuilder(); - * bb.begin(GL11.GL_LINE_LOOP, 16); - * bb.vertex(x,y,u,v); - * ... - * bb.end(); // 立即绘制并 cleanup - * + * BufferBuilder bb = new BufferBuilder(); + * bb.begin(GL11.GL_LINE_LOOP, 16); + * bb.vertex(x,y,u,v); + * ... + * bb.end(); // 立即绘制并 cleanup + *

* 设计原则:简单、可靠、方便把临时多顶点数据提交到 GPU。 * - * + * @author tzdwindows * @version 1.2 * @since 2025-10-16 - * @author tzdwindows */ public class BufferBuilder { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(BufferBuilder.class); @@ -33,8 +32,9 @@ public class BufferBuilder { private int size; // float 数量 private int vertexCount; private int mode; // GL mode - private RenderState renderState = new RenderState(); + private final RenderState renderState = new RenderState(); private boolean stateSaved = false; + // 内置状态,用于构建完成的缓冲区 public static class BuiltBuffer { private final int vao; @@ -51,12 +51,25 @@ public class BufferBuilder { this.renderState = renderState; } - public RenderState renderState() { return renderState; } + public RenderState renderState() { + return renderState; + } - public int vao() { return vao; } - public int vbo() { return vbo; } - public int vertexCount() { return vertexCount; } - public int mode() { return mode; } + public int vao() { + return vao; + } + + public int vbo() { + return vbo; + } + + public int vertexCount() { + return vertexCount; + } + + public int mode() { + return mode; + } } /** diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferUploader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferUploader.java index 59aecdf..0df235e 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferUploader.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/BufferUploader.java @@ -7,8 +7,8 @@ import org.lwjgl.opengl.GL20; /** * 缓冲区上传器 * - * @version 1.1 - 添加颜色支持 * @author tzdwindows 7 + * @version 1.1 - 添加颜色支持 */ public class BufferUploader { @@ -65,7 +65,8 @@ public class BufferUploader { } if (currentProgram != 0) { int colorLoc = RenderSystem.getUniformLocation(currentProgram, "uColor"); - if (colorLoc == -1) {} else { + if (colorLoc == -1) { + } else { RenderSystem.uniform4f(colorLoc, state.color.x, state.color.y, state.color.z, state.color.w); } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/Tesselator.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/Tesselator.java index dd501aa..4ebae7a 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/Tesselator.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/buffer/Tesselator.java @@ -5,8 +5,8 @@ import com.chuangzhou.vivid2D.render.systems.RenderSystem; /** * 管理缓存 * - * @version 1.0 * @author tzdwindows + * @version 1.0 */ public class Tesselator { private static final int DEFAULT_BUFFER_SIZE = 2097152; // 2MB diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/CompleteShader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/CompleteShader.java index 7da84c8..42cd59c 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/CompleteShader.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/CompleteShader.java @@ -3,12 +3,18 @@ package com.chuangzhou.vivid2D.render.systems.sources; /** * 完整着色器接口 * 一个完整的着色器程序需要顶点着色器和片段着色器 + * * @author tzdwindows 7 */ public interface CompleteShader { Shader getVertexShader(); + Shader getFragmentShader(); + String getShaderName(); + boolean isDefaultShader(); - default void setDefaultUniforms(ShaderProgram program) {} + + default void setDefaultUniforms(ShaderProgram program) { + } } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/Shader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/Shader.java index ea422b5..3e2e3a0 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/Shader.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/Shader.java @@ -2,9 +2,11 @@ package com.chuangzhou.vivid2D.render.systems.sources; /** * 着色器接口 + * * @author tzdwindows 7 */ public interface Shader { String getShaderCode(); + String getShaderName(); } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/FragmentShaders.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/FragmentShaders.java index 45ada41..96efc15 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/FragmentShaders.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/FragmentShaders.java @@ -8,104 +8,105 @@ import com.chuangzhou.vivid2D.render.systems.sources.Shader; public class FragmentShaders implements Shader { public static final String FRAGMENT_SHADER_SRC = """ - #version 330 core - in vec2 vTexCoord; - in vec2 vWorldPos; - out vec4 FragColor; - - uniform sampler2D uTexture; - uniform vec4 uColor; - uniform float uOpacity; - uniform int uBlendMode; - uniform int uDebugMode; - - #define MAX_LIGHTS 8 - uniform vec2 uLightsPos[MAX_LIGHTS]; - uniform vec3 uLightsColor[MAX_LIGHTS]; - uniform float uLightsIntensity[MAX_LIGHTS]; - uniform int uLightsIsAmbient[MAX_LIGHTS]; - uniform int uLightCount; - - // 常用衰减系数(可在 shader 内微调) - const float ATT_CONST = 1.0; - const float ATT_LINEAR = 0.09; - const float ATT_QUAD = 0.032; - - void main() { - // 先采样纹理 - vec4 tex = texture(uTexture, vTexCoord); - float alpha = tex.a * uOpacity; - if (alpha <= 0.001) discard; - - // 如果没有光源,跳过光照计算(性能更好并且保持原始贴图色) - if (uLightCount == 0) { - vec3 base = tex.rgb * uColor.rgb; - // 简单的色调映射(防止数值过大) - base = clamp(base, 0.0, 1.0); - FragColor = vec4(base, alpha); - return; - } - - // 基础颜色(纹理 * 部件颜色) - vec3 baseColor = tex.rgb * uColor.rgb; - - // 全局环境光基线(可以适度提高以避免全黑) - vec3 ambient = vec3(0.06); // 小环境光补偿 - vec3 lighting = vec3(0.0); - vec3 specularAccum = vec3(0.0); - - // 累积环境光(来自被标记为环境光的光源) - for (int i = 0; i < uLightCount; ++i) { - if (uLightsIsAmbient[i] == 1) { - lighting += uLightsColor[i] * uLightsIntensity[i]; + #version 330 core + in vec2 vTexCoord; + in vec2 vWorldPos; + out vec4 FragColor; + + uniform sampler2D uTexture; + uniform vec4 uColor; + uniform float uOpacity; + uniform int uBlendMode; + uniform int uDebugMode; + + #define MAX_LIGHTS 8 + uniform vec2 uLightsPos[MAX_LIGHTS]; + uniform vec3 uLightsColor[MAX_LIGHTS]; + uniform float uLightsIntensity[MAX_LIGHTS]; + uniform int uLightsIsAmbient[MAX_LIGHTS]; + uniform int uLightCount; + + // 常用衰减系数(可在 shader 内微调) + const float ATT_CONST = 1.0; + const float ATT_LINEAR = 0.09; + const float ATT_QUAD = 0.032; + + void main() { + // 先采样纹理 + vec4 tex = texture(uTexture, vTexCoord); + float alpha = tex.a * uOpacity; + if (alpha <= 0.001) discard; + + // 如果没有光源,跳过光照计算(性能更好并且保持原始贴图色) + if (uLightCount == 0) { + vec3 base = tex.rgb * uColor.rgb; + // 简单的色调映射(防止数值过大) + base = clamp(base, 0.0, 1.0); + FragColor = vec4(base, alpha); + return; + } + + // 基础颜色(纹理 * 部件颜色) + vec3 baseColor = tex.rgb * uColor.rgb; + + // 全局环境光基线(可以适度提高以避免全黑) + vec3 ambient = vec3(0.06); // 小环境光补偿 + vec3 lighting = vec3(0.0); + vec3 specularAccum = vec3(0.0); + + // 累积环境光(来自被标记为环境光的光源) + for (int i = 0; i < uLightCount; ++i) { + if (uLightsIsAmbient[i] == 1) { + lighting += uLightsColor[i] * uLightsIntensity[i]; + } + } + // 加上基线环境光 + lighting += ambient; + + // 对每个非环境光计算基于距离的衰减与简单高光 + for (int i = 0; i < uLightCount; ++i) { + if (uLightsIsAmbient[i] == 1) continue; + + vec2 toLight = uLightsPos[i] - vWorldPos; + float dist = length(toLight); + // 标准物理式衰减 + float attenuation = ATT_CONST / (ATT_CONST + ATT_LINEAR * dist + ATT_QUAD * dist * dist); + + // 强度受光源强度和衰减影响 + float radiance = uLightsIntensity[i] * attenuation; + + // 漫反射:在纯2D情景下,法线与视线近似固定(Z向), + // 所以漫反射对所有片元是恒定的。我们用一个基于距离的柔和因子来模拟明暗变化。 + float diffuseFactor = clamp(1.0 - (dist * 0.0015), 0.0, 1.0); // 通过调节常数控制半径感觉 + vec3 diff = uLightsColor[i] * radiance * diffuseFactor; + lighting += diff; + + // 简单高光(基于视向与反射的大致模拟,产生亮点) + vec3 lightDir3 = normalize(vec3(toLight, 0.0)); + vec3 viewDir = vec3(0.0, 0.0, 1.0); + vec3 normal = vec3(0.0, 0.0, 1.0); + vec3 reflectDir = reflect(-lightDir3, normal); + float specFactor = pow(max(dot(viewDir, reflectDir), 0.0), 16.0); // 16 为高光粗糙度,可调 + float specIntensity = 0.2; // 高光强度系数 + specularAccum += uLightsColor[i] * radiance * specFactor * specIntensity; + } + + // 限制光照的最大值以避免过曝(可根据场景调整) + vec3 totalLighting = min(lighting + specularAccum, vec3(2.0)); + + // 将光照应用到基础颜色 + vec3 finalColor = baseColor * totalLighting; + + // 支持简单混合模式(保留原有行为) + if (uBlendMode == 1) finalColor = tex.rgb + uColor.rgb; + else if (uBlendMode == 2) finalColor = tex.rgb * uColor.rgb; + else if (uBlendMode == 3) finalColor = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb); + + finalColor = clamp(finalColor, 0.0, 1.0); + FragColor = vec4(finalColor, alpha); } - } - // 加上基线环境光 - lighting += ambient; - - // 对每个非环境光计算基于距离的衰减与简单高光 - for (int i = 0; i < uLightCount; ++i) { - if (uLightsIsAmbient[i] == 1) continue; - - vec2 toLight = uLightsPos[i] - vWorldPos; - float dist = length(toLight); - // 标准物理式衰减 - float attenuation = ATT_CONST / (ATT_CONST + ATT_LINEAR * dist + ATT_QUAD * dist * dist); - - // 强度受光源强度和衰减影响 - float radiance = uLightsIntensity[i] * attenuation; - - // 漫反射:在纯2D情景下,法线与视线近似固定(Z向), - // 所以漫反射对所有片元是恒定的。我们用一个基于距离的柔和因子来模拟明暗变化。 - float diffuseFactor = clamp(1.0 - (dist * 0.0015), 0.0, 1.0); // 通过调节常数控制半径感觉 - vec3 diff = uLightsColor[i] * radiance * diffuseFactor; - lighting += diff; - - // 简单高光(基于视向与反射的大致模拟,产生亮点) - vec3 lightDir3 = normalize(vec3(toLight, 0.0)); - vec3 viewDir = vec3(0.0, 0.0, 1.0); - vec3 normal = vec3(0.0, 0.0, 1.0); - vec3 reflectDir = reflect(-lightDir3, normal); - float specFactor = pow(max(dot(viewDir, reflectDir), 0.0), 16.0); // 16 为高光粗糙度,可调 - float specIntensity = 0.2; // 高光强度系数 - specularAccum += uLightsColor[i] * radiance * specFactor * specIntensity; - } - - // 限制光照的最大值以避免过曝(可根据场景调整) - vec3 totalLighting = min(lighting + specularAccum, vec3(2.0)); - - // 将光照应用到基础颜色 - vec3 finalColor = baseColor * totalLighting; - - // 支持简单混合模式(保留原有行为) - if (uBlendMode == 1) finalColor = tex.rgb + uColor.rgb; - else if (uBlendMode == 2) finalColor = tex.rgb * uColor.rgb; - else if (uBlendMode == 3) finalColor = 1.0 - (1.0 - tex.rgb) * (1.0 - uColor.rgb); - - finalColor = clamp(finalColor, 0.0, 1.0); - FragColor = vec4(finalColor, alpha); - } - """; + """; + @Override public String getShaderCode() { return FRAGMENT_SHADER_SRC; diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorFragmentShader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorFragmentShader.java index 2c3c3a1..4b6fc3b 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorFragmentShader.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorFragmentShader.java @@ -5,28 +5,29 @@ import com.chuangzhou.vivid2D.render.systems.sources.Shader; /** * 纯色着色器的片段着色器 * 只使用颜色,忽略纹理 + * * @author tzdwindows 7 */ public class SolidColorFragmentShader implements Shader { public static final String FRAGMENT_SHADER_SRC = """ - #version 330 core - out vec4 FragColor; - - uniform vec4 uColor; - uniform float uOpacity; - - void main() { - // 直接使用颜色,忽略纹理 - vec4 finalColor = uColor; - finalColor.a *= uOpacity; - - // 如果透明度太低则丢弃片段 - if (finalColor.a <= 0.001) discard; - - FragColor = finalColor; - } - """; + #version 330 core + out vec4 FragColor; + + uniform vec4 uColor; + uniform float uOpacity; + + void main() { + // 直接使用颜色,忽略纹理 + vec4 finalColor = uColor; + finalColor.a *= uOpacity; + + // 如果透明度太低则丢弃片段 + if (finalColor.a <= 0.001) discard; + + FragColor = finalColor; + } + """; @Override public String getShaderCode() { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorShader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorShader.java index 1def1e1..ad300de 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorShader.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorShader.java @@ -7,6 +7,7 @@ import com.chuangzhou.vivid2D.render.systems.sources.ShaderProgram; /** * 纯色着色器程序 * 专门用于绘制纯色几何体,如选中框、调试图形等 + * * @author tzdwindows 7 */ public class SolidColorShader implements CompleteShader { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorVertexShader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorVertexShader.java index dcc5280..014666b 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorVertexShader.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/SolidColorVertexShader.java @@ -4,25 +4,26 @@ import com.chuangzhou.vivid2D.render.systems.sources.Shader; /** * 纯色着色器的顶点着色器 + * * @author tzdwindows 7 */ public class SolidColorVertexShader implements Shader { public static final String VERTEX_SHADER_SRC = """ - #version 330 core - layout(location = 0) in vec2 aPosition; - layout(location = 1) in vec2 aTexCoord; - - uniform mat3 uModelMatrix; - uniform mat3 uViewMatrix; - uniform mat3 uProjectionMatrix; - - void main() { - // 使用 3x3 矩阵链计算屏幕位置 - vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0); - gl_Position = vec4(p.xy, 0.0, 1.0); - } - """; + #version 330 core + layout(location = 0) in vec2 aPosition; + layout(location = 1) in vec2 aTexCoord; + + uniform mat3 uModelMatrix; + uniform mat3 uViewMatrix; + uniform mat3 uProjectionMatrix; + + void main() { + // 使用 3x3 矩阵链计算屏幕位置 + vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0); + gl_Position = vec4(p.xy, 0.0, 1.0); + } + """; @Override public String getShaderCode() { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/VertexShaders.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/VertexShaders.java index 7b4cbe0..8b9f7ce 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/VertexShaders.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/VertexShaders.java @@ -12,25 +12,25 @@ import com.chuangzhou.vivid2D.render.systems.sources.Shader; public class VertexShaders implements Shader { public static final String VERTEX_SHADER_SRC = """ - #version 330 core - layout(location = 0) in vec2 aPosition; - layout(location = 1) in vec2 aTexCoord; - out vec2 vTexCoord; - out vec2 vWorldPos; - - uniform mat3 uModelMatrix; - uniform mat3 uViewMatrix; - uniform mat3 uProjectionMatrix; - - void main() { - // 使用 3x3 矩阵链计算屏幕位置(假设矩阵是二维仿射) - vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0); - gl_Position = vec4(p.xy, 0.0, 1.0); - vTexCoord = aTexCoord; - // 输出 world-space 位置供 fragment shader 使用(仅 xy) - vWorldPos = (uModelMatrix * vec3(aPosition, 1.0)).xy; - } - """; + #version 330 core + layout(location = 0) in vec2 aPosition; + layout(location = 1) in vec2 aTexCoord; + out vec2 vTexCoord; + out vec2 vWorldPos; + + uniform mat3 uModelMatrix; + uniform mat3 uViewMatrix; + uniform mat3 uProjectionMatrix; + + void main() { + // 使用 3x3 矩阵链计算屏幕位置(假设矩阵是二维仿射) + vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0); + gl_Position = vec4(p.xy, 0.0, 1.0); + vTexCoord = aTexCoord; + // 输出 world-space 位置供 fragment shader 使用(仅 xy) + vWorldPos = (uModelMatrix * vec3(aPosition, 1.0)).xy; + } + """; @Override public String getShaderCode() { diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelLayerPanelTest.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelLayerPanelTest.java index ea4e212..fc8837d 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelLayerPanelTest.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelLayerPanelTest.java @@ -32,7 +32,8 @@ public class ModelLayerPanelTest { if (person != null) { try { person.setOpacity(0.85f); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } // 创建 UI @@ -80,7 +81,8 @@ public class ModelLayerPanelTest { // 同步通知渲染面板(如果需要)去刷新模型 try { renderPanel.setModel(model); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } }); bottom.add(refreshBtn); @@ -138,7 +140,8 @@ public class ModelLayerPanelTest { // 进程退出(确保彻底关闭) try { renderPanel.dispose(); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } System.exit(0); } }); diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelLoadTest.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelLoadTest.java index 2a5cff9..f406441 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelLoadTest.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelLoadTest.java @@ -16,11 +16,11 @@ import static org.lwjgl.opengl.GL11.*; /** * ModelLoadTest - enhanced debug loader - * + *

* - 加载模型后会自动检查 model 内部结构并打印(parts, meshes, textures) * - 尝试把第一个 part 放到窗口中心以确保在可视范围内 * - 每帧确保 ModelRender 的 viewport 与窗口大小一致 - * + *

* 运行前请确保 MODEL_PATH 指向你保存的 model 文件 */ public class ModelLoadTest { @@ -115,7 +115,7 @@ public class ModelLoadTest { * 其次尝试创建空实例并调用实例方法 loadFromFile(String) */ private void loadModelFromFile(String path) { - inspectSerializedFileStructure( path); + inspectSerializedFileStructure(path); File f = new File(path); if (!f.exists()) { System.err.println("Model file not found: " + path); @@ -165,7 +165,8 @@ public class ModelLoadTest { model = inst; System.out.println("Model loaded via instance method loadFromFile"); return; - } catch (NoSuchMethodException ignored) { } + } catch (NoSuchMethodException ignored) { + } } } catch (Throwable t) { // ignore @@ -209,35 +210,50 @@ public class ModelLoadTest { private void printObjectStructure(Object obj, int indent, java.util.Set seen) { if (obj == null) { - printIndent(indent); System.out.println("null"); return; + printIndent(indent); + System.out.println("null"); + return; } if (seen.contains(obj)) { - printIndent(indent); System.out.println("<>"); return; + printIndent(indent); + System.out.println("<>"); + return; } seen.add(obj); Class cls = obj.getClass(); - printIndent(indent); System.out.println(cls.getName()); + printIndent(indent); + System.out.println(cls.getName()); // 如果是集合,列出元素类型/数目(不深入过深避免堆栈) - if (obj instanceof java.util.Collection) { - java.util.Collection col = (java.util.Collection) obj; - printIndent(indent+1); System.out.println("size=" + col.size()); + if (obj instanceof java.util.Collection col) { + printIndent(indent + 1); + System.out.println("size=" + col.size()); int i = 0; for (Object e : col) { - if (i++ > 20) { printIndent(indent+1); System.out.println("... (truncated)"); break; } - printObjectStructure(e, indent+1, seen); + if (i++ > 20) { + printIndent(indent + 1); + System.out.println("... (truncated)"); + break; + } + printObjectStructure(e, indent + 1, seen); } return; } - if (obj instanceof java.util.Map) { - java.util.Map map = (java.util.Map) obj; - printIndent(indent+1); System.out.println("size=" + map.size()); + if (obj instanceof java.util.Map map) { + printIndent(indent + 1); + System.out.println("size=" + map.size()); int i = 0; for (Object k : map.keySet()) { - if (i++ > 20) { printIndent(indent+1); System.out.println("... (truncated)"); break; } - printIndent(indent+1); System.out.println("Key:"); - printObjectStructure(k, indent+2, seen); - printIndent(indent+1); System.out.println("Value:"); - printObjectStructure(map.get(k), indent+2, seen); + if (i++ > 20) { + printIndent(indent + 1); + System.out.println("... (truncated)"); + break; + } + printIndent(indent + 1); + System.out.println("Key:"); + printObjectStructure(k, indent + 2, seen); + printIndent(indent + 1); + System.out.println("Value:"); + printObjectStructure(map.get(k), indent + 2, seen); } return; } @@ -246,12 +262,16 @@ public class ModelLoadTest { for (java.lang.reflect.Field f : fields) { f.setAccessible(true); Object val = null; - try { val = f.get(obj); } catch (Throwable ignored) {} - printIndent(indent+1); System.out.println(f.getName() + " : " + (val == null ? "null" : val.getClass().getName())); + try { + val = f.get(obj); + } catch (Throwable ignored) { + } + printIndent(indent + 1); + System.out.println(f.getName() + " : " + (val == null ? "null" : val.getClass().getName())); // 对常见自定义类型深入一层 if (val != null && !val.getClass().getName().startsWith("java.") && !val.getClass().isPrimitive()) { if (val instanceof Number || val instanceof String) continue; - printObjectStructure(val, indent+2, seen); + printObjectStructure(val, indent + 2, seen); } } } @@ -283,8 +303,7 @@ public class ModelLoadTest { if (getParts != null) { Object partsObj = getParts.invoke(model); - if (partsObj instanceof List) { - List parts = (List) partsObj; + if (partsObj instanceof List parts) { System.out.println("Parts count: " + parts.size()); for (int i = 0; i < parts.size(); i++) { Object p = parts.get(i); @@ -296,7 +315,8 @@ public class ModelLoadTest { Object name = getName != null ? getName.invoke(p) : ""; Object pos = getPosition != null ? getPosition.invoke(p) : null; System.out.println(" name=" + name + ", pos=" + pos); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } } // 如果 parts 不为空,尝试把第一个 part 放到窗口中心(如果有 setPosition) @@ -305,7 +325,7 @@ public class ModelLoadTest { try { Method setPosition = tryGetMethod(first.getClass(), "setPosition", float.class, float.class); if (setPosition != null) { - setPosition.invoke(first, (float)WINDOW_WIDTH/2f, (float)WINDOW_HEIGHT/2f); + setPosition.invoke(first, (float) WINDOW_WIDTH / 2f, (float) WINDOW_HEIGHT / 2f); System.out.println("Moved first part to window center."); } } catch (Throwable t) { @@ -317,8 +337,7 @@ public class ModelLoadTest { if (getMeshes != null) { Object meshesObj = getMeshes.invoke(model); - if (meshesObj instanceof List) { - List meshes = (List) meshesObj; + if (meshesObj instanceof List meshes) { System.out.println("Meshes count: " + meshes.size()); for (int i = 0; i < Math.min(meshes.size(), 10); i++) { Object m = meshes.get(i); @@ -330,15 +349,15 @@ public class ModelLoadTest { Object vc = getVertexCount != null ? getVertexCount.invoke(m) : null; Object tex = getTexture != null ? getTexture.invoke(m) : null; System.out.println(" vertexCount=" + vc + ", texture=" + tex); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } } } } if (getTextures != null) { Object texObj = getTextures.invoke(model); - if (texObj instanceof List) { - List texs = (List) texObj; + if (texObj instanceof List texs) { System.out.println("Textures count: " + texs.size()); for (int i = 0; i < Math.min(texs.size(), 10); i++) { Object t = texs.get(i); @@ -351,7 +370,8 @@ public class ModelLoadTest { Object h = getH != null ? getH.invoke(t) : "?"; Object id = getId != null ? getId.invoke(t) : "?"; System.out.println(" size=" + w + "x" + h + ", id=" + id); - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } } } } @@ -437,8 +457,8 @@ public class ModelLoadTest { try { ModelRender.cleanup(); - } catch (Throwable ignored) {} - + } catch (Throwable ignored) { + } if (window != MemoryUtil.NULL) { diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderLightingTest.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderLightingTest.java index f836338..5a85d12 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderLightingTest.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderLightingTest.java @@ -8,7 +8,6 @@ import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import com.chuangzhou.vivid2D.render.model.util.Texture; import com.chuangzhou.vivid2D.render.systems.RenderSystem; import org.joml.Vector2f; -import org.joml.Vector3f; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWVidMode; @@ -22,6 +21,7 @@ import java.util.Random; /** * ModelRenderLightingTest * 测试使用 Model2D + 光源进行简单光照渲染 + * * @author tzdwindows 7 */ public class ModelRenderLightingTest { @@ -34,7 +34,7 @@ public class ModelRenderLightingTest { private boolean running = true; private Model2D model; - private Random random = new Random(); + private final Random random = new Random(); private float animationTime = 0f; @@ -115,7 +115,7 @@ public class ModelRenderLightingTest { rightArm.setPosition(60, -20); Mesh2D rightArmMesh = Mesh2D.createQuad("right_arm_mesh", 18, 90); rightArmMesh.setTexture(createSolidTexture(16, 90, 0xFF6495ED)); - rightArmMesh.setSelected( true); + rightArmMesh.setSelected(true); rightArm.addMesh(rightArmMesh); // legs @@ -152,11 +152,11 @@ public class ModelRenderLightingTest { private Texture createSolidTexture(int w, int h, int rgba) { ByteBuffer buf = MemoryUtil.memAlloc(w * h * 4); - byte a = (byte)((rgba >> 24) & 0xFF); - byte r = (byte)((rgba >> 16) & 0xFF); - byte g = (byte)((rgba >> 8) & 0xFF); - byte b = (byte)(rgba & 0xFF); - for(int i=0;i> 24) & 0xFF); + byte r = (byte) ((rgba >> 16) & 0xFF); + byte g = (byte) ((rgba >> 8) & 0xFF); + byte b = (byte) (rgba & 0xFF); + for (int i = 0; i < w * h; i++) buf.put(r).put(g).put(b).put(a); buf.flip(); Texture t = new Texture("solid_" + rgba, w, h, Texture.TextureFormat.RGBA, buf); MemoryUtil.memFree(buf); @@ -166,16 +166,16 @@ public class ModelRenderLightingTest { private Texture createHeadTexture() { int width = 64, height = 64; int[] pixels = new int[width * height]; - for(int y=0;y1.0f?0:255; - int r = (int)(240*(1f - dist*0.25f)); - int g = (int)(200*(1f - dist*0.25f)); - int b = (int)(180*(1f - dist*0.25f)); - pixels[y*width + x] = (alpha<<24)|(r<<16)|(g<<8)|b; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + float dx = (x - width / 2f) / (width / 2f); + float dy = (y - height / 2f) / (height / 2f); + float dist = (float) Math.sqrt(dx * dx + dy * dy); + int alpha = dist > 1.0f ? 0 : 255; + int r = (int) (240 * (1f - dist * 0.25f)); + int g = (int) (200 * (1f - dist * 0.25f)); + int b = (int) (180 * (1f - dist * 0.25f)); + pixels[y * width + x] = (alpha << 24) | (r << 16) | (g << 8) | b; } } return new Texture("head_tex", width, height, Texture.TextureFormat.RGBA, pixels); @@ -188,11 +188,11 @@ public class ModelRenderLightingTest { while (running && !GLFW.glfwWindowShouldClose(window)) { long now = System.nanoTime(); - accumulator += (now - last)/nsPerUpdate; + accumulator += (now - last) / nsPerUpdate; last = now; while (accumulator >= 1.0) { - update(1.0f/60.0f); + update(1.0f / 60.0f); accumulator -= 1.0; } @@ -204,9 +204,9 @@ public class ModelRenderLightingTest { private void update(float dt) { animationTime += dt; - float armSwing = (float)Math.sin(animationTime*3f)*0.7f; - float legSwing = (float)Math.sin(animationTime*3f + Math.PI)*0.6f; - float headRot = (float)Math.sin(animationTime*1.4f)*0.15f; + float armSwing = (float) Math.sin(animationTime * 3f) * 0.7f; + float legSwing = (float) Math.sin(animationTime * 3f + Math.PI) * 0.6f; + float headRot = (float) Math.sin(animationTime * 1.4f) * 0.15f; ModelPart leftArm = model.getPart("left_arm"); ModelPart rightArm = model.getPart("right_arm"); @@ -214,24 +214,24 @@ public class ModelRenderLightingTest { ModelPart rightLeg = model.getPart("right_leg"); ModelPart head = model.getPart("head"); - if(leftArm!=null) leftArm.setRotation(-0.8f*armSwing - 0.2f); - if(rightArm!=null) rightArm.setRotation(0.8f*armSwing + 0.2f); - if(leftLeg!=null) leftLeg.setRotation(0.6f*legSwing); - if(rightLeg!=null) rightLeg.setRotation(-0.6f*legSwing); - if(head!=null) head.setRotation(headRot); + if (leftArm != null) leftArm.setRotation(-0.8f * armSwing - 0.2f); + if (rightArm != null) rightArm.setRotation(0.8f * armSwing + 0.2f); + if (leftLeg != null) leftLeg.setRotation(0.6f * legSwing); + if (rightLeg != null) rightLeg.setRotation(-0.6f * legSwing); + if (head != null) head.setRotation(headRot); model.update(dt); } private void render() { - RenderSystem.setClearColor(0.18f,0.18f,0.25f,1.0f); - ModelRender.render(1f/60f, model); + RenderSystem.setClearColor(0.18f, 0.18f, 0.25f, 1.0f); + ModelRender.render(1f / 60f, model); } private void cleanup() { ModelRender.cleanup(); Texture.cleanupAll(); - if(window!= MemoryUtil.NULL) GLFW.glfwDestroyWindow(window); + if (window != MemoryUtil.NULL) GLFW.glfwDestroyWindow(window); GLFW.glfwTerminate(); GLFW.glfwSetErrorCallback(null).free(); } diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest.java index 2abcc19..e5798c0 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest.java @@ -21,7 +21,6 @@ import java.util.Random; * 重写后的 ModelRender 测试示例:构造一个简单的人形(头、身体、左右手、左右腿) * 便于验证层级变换与渲染是否正确。 * - * * @author tzdwindows 7 */ public class ModelRenderTest { @@ -34,7 +33,7 @@ public class ModelRenderTest { private boolean running = true; private Model2D testModel; - private Random random = new Random(); + private final Random random = new Random(); private float animationTime = 0f; private boolean animate = true; diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest2.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest2.java index 1ca944a..b37f1ce 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest2.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTest2.java @@ -6,8 +6,6 @@ import com.chuangzhou.vivid2D.render.model.ModelPart; import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import com.chuangzhou.vivid2D.render.model.util.Texture; import com.chuangzhou.vivid2D.render.systems.RenderSystem; -import org.joml.Matrix3f; -import org.joml.Vector2f; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWVidMode; @@ -18,6 +16,7 @@ import java.nio.ByteBuffer; /** * 用于测试中心点旋转 + * * @author tzdwindows 7 */ public class ModelRenderTest2 { @@ -32,6 +31,7 @@ public class ModelRenderTest2 { private float rotationAngle = 0f; private int testCase = 0; private Mesh2D squareMesh; + public static void main(String[] args) { new ModelRenderTest2().run(); } @@ -104,7 +104,7 @@ public class ModelRenderTest2 { ModelPart square = testModel.createPart("square"); square.setPosition(0, 0); // center of window - square.setPivot(0,0); + square.setPivot(0, 0); // Create 80x80 quad centered at origin squareMesh = Mesh2D.createQuad("square_mesh", 80, 80); // Shift vertices so center is at (0,0) diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTextureTest.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTextureTest.java index 136df7e..f4c6ae0 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTextureTest.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelRenderTextureTest.java @@ -5,7 +5,6 @@ import com.chuangzhou.vivid2D.render.model.Model2D; import com.chuangzhou.vivid2D.render.model.ModelPart; import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import com.chuangzhou.vivid2D.render.model.util.Texture; -import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.opengl.GL; import org.lwjgl.system.MemoryUtil; @@ -15,6 +14,7 @@ import static org.lwjgl.opengl.GL11.*; /** * Texture Render Test Class - Debug Version + * * @author tzdwindows 7 */ public class ModelRenderTextureTest { @@ -143,10 +143,10 @@ public class ModelRenderTextureTest { // 回退到手动创建顶点 System.out.println("Using manual vertex creation"); float[] vertices = { - -width/2, -height/2, // bottom left - width/2, -height/2, // bottom right - width/2, height/2, // top right - -width/2, height/2 // top left + -width / 2, -height / 2, // bottom left + width / 2, -height / 2, // bottom right + width / 2, height / 2, // top right + -width / 2, height / 2 // top left }; float[] uvs = { @@ -203,10 +203,10 @@ public class ModelRenderTextureTest { } catch (Exception e) { // 手动创建 float[] vertices = { - -width/2, -height/2, - width/2, -height/2, - width/2, height/2, - -width/2, height/2 + -width / 2, -height / 2, + width / 2, -height / 2, + width / 2, height / 2, + -width / 2, height / 2 }; float[] uvs = { @@ -320,11 +320,16 @@ public class ModelRenderTextureTest { private String getGLErrorString(int error) { switch (error) { - case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; - case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; - case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; - case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; - default: return "Unknown Error (0x" + Integer.toHexString(error) + ")"; + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + default: + return "Unknown Error (0x" + Integer.toHexString(error) + ")"; } } diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelTest.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelTest.java index 581d2fe..909210a 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelTest.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelTest.java @@ -1,8 +1,8 @@ package com.chuangzhou.vivid2D.test; +import com.chuangzhou.vivid2D.render.model.AnimationParameter; import com.chuangzhou.vivid2D.render.model.Model2D; import com.chuangzhou.vivid2D.render.model.ModelPart; -import com.chuangzhou.vivid2D.render.model.AnimationParameter; import com.chuangzhou.vivid2D.render.model.transform.WaveDeformer; import com.chuangzhou.vivid2D.render.model.util.*; import org.joml.Vector2f; @@ -809,7 +809,6 @@ public class ModelTest { } - /** * Utility method to print part hierarchy */ diff --git a/src/main/java/com/chuangzhou/vivid2D/test/ModelTest2.java b/src/main/java/com/chuangzhou/vivid2D/test/ModelTest2.java index 341edd1..de1539d 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/ModelTest2.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/ModelTest2.java @@ -4,8 +4,8 @@ import com.chuangzhou.vivid2D.render.ModelRender; import com.chuangzhou.vivid2D.render.model.Model2D; import com.chuangzhou.vivid2D.render.model.ModelPart; import com.chuangzhou.vivid2D.render.model.util.Mesh2D; -import com.chuangzhou.vivid2D.render.model.util.Texture; import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem; +import com.chuangzhou.vivid2D.render.model.util.Texture; import com.chuangzhou.vivid2D.render.systems.RenderSystem; import org.joml.Vector2f; import org.lwjgl.glfw.GLFW; @@ -20,6 +20,7 @@ import java.util.List; /** * 物理系统使用实例 - 演示弹簧、重力和碰撞效果 + * * @author tzdwindows 7 */ public class ModelTest2 { @@ -39,7 +40,7 @@ public class ModelTest2 { private boolean springsEnabled = true; // 存储部件引用,用于清理 - private List currentParts = new ArrayList<>(); + private final List currentParts = new ArrayList<>(); // 所有测试基点(初始 xy = 0,0) private final Vector2f initialOrigin = new Vector2f(0, 0); @@ -598,13 +599,20 @@ public class ModelTest2 { */ private String getTestCaseName(int testCase) { switch (testCase) { - case 0: return "Spring Chain"; - case 1: return "Cloth Simulation"; - case 2: return "Pendulum System"; - case 3: return "Soft Body"; - case 4: return "Wind Test"; - case 5: return "Free Fall Test"; - default: return "Unknown"; + case 0: + return "Spring Chain"; + case 1: + return "Cloth Simulation"; + case 2: + return "Pendulum System"; + case 3: + return "Soft Body"; + case 4: + return "Wind Test"; + case 5: + return "Free Fall Test"; + default: + return "Unknown"; } } diff --git a/src/main/java/com/chuangzhou/vivid2D/test/TestModelGLPanel.java b/src/main/java/com/chuangzhou/vivid2D/test/TestModelGLPanel.java index 2c0e79e..a72efd6 100644 --- a/src/main/java/com/chuangzhou/vivid2D/test/TestModelGLPanel.java +++ b/src/main/java/com/chuangzhou/vivid2D/test/TestModelGLPanel.java @@ -15,6 +15,7 @@ import java.nio.ByteBuffer; /** * 在原 TestModelGLPanel 的基础上增加简单动画(手臂、腿、头部摆动) + * * @author tzdwindows 7 */ public class TestModelGLPanel {