diff --git a/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java b/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java index c771e22..19d5df4 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java @@ -6,7 +6,10 @@ import com.chuangzhou.vivid2D.render.systems.buffer.Tesselator; import com.chuangzhou.vivid2D.render.systems.sources.ShaderManagement; import com.chuangzhou.vivid2D.render.systems.sources.ShaderProgram; import org.joml.Vector4f; -import org.lwjgl.opengl.*; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL33; import org.lwjgl.stb.STBTTAlignedQuad; import org.lwjgl.stb.STBTTBakedChar; import org.lwjgl.system.MemoryStack; @@ -15,10 +18,12 @@ import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; -import static org.lwjgl.stb.STBTruetype.*; +import static org.lwjgl.stb.STBTruetype.stbtt_BakeFontBitmap; +import static org.lwjgl.stb.STBTruetype.stbtt_GetBakedQuad; /** * 支持 ASCII + 中文的 OpenGL 文本渲染器 + * * @author tzdwindows 7 */ public final class TextRenderer { @@ -153,7 +158,7 @@ public final class TextRenderer { width += bakedChar.xadvance() * scale; } else { // 对于未找到的字符,使用空格宽度 - width += 0.5f * scale; // 估计值 + width += 0.5f * scale; // 估计值 } } } @@ -317,7 +322,15 @@ public final class TextRenderer { logger.debug("TextRenderer cleaned up"); } - public boolean isInitialized() { return initialized; } - public int getAsciiTextureId() { return asciiTextureId; } - public int getChineseTextureId() { return chineseTextureId; } + public boolean isInitialized() { + return initialized; + } + + public int getAsciiTextureId() { + return asciiTextureId; + } + + public int getChineseTextureId() { + return chineseTextureId; + } } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PsdParser.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PsdParser.java index 0756ce0..45200cf 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PsdParser.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/util/PsdParser.java @@ -94,7 +94,10 @@ public class PsdParser { } } finally { - try { reader.dispose(); } catch (Exception ignored) {} + try { + reader.dispose(); + } catch (Exception ignored) { + } } return result; diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/ModelEvent.java b/src/main/java/com/chuangzhou/vivid2D/render/model/ModelEvent.java index 8aa3896..77b769c 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/ModelEvent.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/ModelEvent.java @@ -2,8 +2,9 @@ package com.chuangzhou.vivid2D.render.model; /** * 模型事件 + * * @author tzdwindows 7 */ public interface ModelEvent { - void trigger(String eventName,Object eventBus); + void trigger(String eventName, Object eventBus); } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/LightSourceData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/LightSourceData.java index 0e8336c..432458e 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/LightSourceData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/LightSourceData.java @@ -9,6 +9,7 @@ import java.io.Serializable; /** * LightSource 的序列化数据类(扩展:包含辉光/Glow 的序列化字段) + * * @author tzdwindows 7 */ public class LightSourceData implements Serializable { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartData.java index 5471b9e..0965530 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/PartData.java @@ -80,8 +80,7 @@ public class PartData implements Serializable { // 期望的方法签名: public List getLiquifyStrokes() java.lang.reflect.Method m = part.getClass().getMethod("getLiquifyStrokes"); Object strokesObj = m.invoke(part); - if (strokesObj instanceof List) { - List strokes = (List) strokesObj; + if (strokesObj instanceof List strokes) { for (Object s : strokes) { // 支持两种情况:存储为自定义类型(有 getMode/getRadius/getStrength/getIterations/getPoints 方法) // 或者直接存储为通用 Map/POJO。我们做宽松处理:通过反射尽可能读取常见字段。 @@ -91,37 +90,39 @@ public class PartData implements Serializable { java.lang.reflect.Method gm = s.getClass().getMethod("getMode"); Object modeObj = gm.invoke(s); if (modeObj != null) strokeData.mode = modeObj.toString(); - } catch (NoSuchMethodException ignored) {} + } catch (NoSuchMethodException ignored) { + } try { java.lang.reflect.Method gr = s.getClass().getMethod("getRadius"); Object r = gr.invoke(s); if (r instanceof Number) strokeData.radius = ((Number) r).floatValue(); - } catch (NoSuchMethodException ignored) {} + } catch (NoSuchMethodException ignored) { + } try { java.lang.reflect.Method gs = s.getClass().getMethod("getStrength"); Object st = gs.invoke(s); if (st instanceof Number) strokeData.strength = ((Number) st).floatValue(); - } catch (NoSuchMethodException ignored) {} + } catch (NoSuchMethodException ignored) { + } try { java.lang.reflect.Method gi = s.getClass().getMethod("getIterations"); Object it = gi.invoke(s); if (it instanceof Number) strokeData.iterations = ((Number) it).intValue(); - } catch (NoSuchMethodException ignored) {} + } catch (NoSuchMethodException ignored) { + } // 读取点列表 try { java.lang.reflect.Method gp = s.getClass().getMethod("getPoints"); Object ptsObj = gp.invoke(s); - if (ptsObj instanceof List) { - List pts = (List) ptsObj; + if (ptsObj instanceof List pts) { for (Object p : pts) { // 支持 Vector2f 或自定义点类型(有 getX/getY/getPressure) LiquifyPointData pd = new LiquifyPointData(); - if (p instanceof org.joml.Vector2f) { - org.joml.Vector2f v = (org.joml.Vector2f) p; + if (p instanceof Vector2f v) { pd.x = v.x; pd.y = v.y; pd.pressure = 1.0f; @@ -144,8 +145,7 @@ public class PartData implements Serializable { } } catch (NoSuchMethodException ex) { // 最后尝试 Map 形式(键 x,y) - if (p instanceof Map) { - Map mapP = (Map) p; + if (p instanceof Map mapP) { Object ox = mapP.get("x"); Object oy = mapP.get("y"); if (ox instanceof Number && oy instanceof Number) { @@ -160,7 +160,8 @@ public class PartData implements Serializable { strokeData.points.add(pd); } } - } catch (NoSuchMethodException ignored) {} + } catch (NoSuchMethodException ignored) { + } // 如果没有 mode,则用默认 PUSH if (strokeData.mode == null) strokeData.mode = ModelPart.LiquifyMode.PUSH.name(); @@ -236,7 +237,8 @@ public class PartData implements Serializable { ModelPart.LiquifyMode modeEnum = ModelPart.LiquifyMode.PUSH; try { modeEnum = ModelPart.LiquifyMode.valueOf(stroke.mode); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } // 对每个点进行重放:调用 applyLiquify(存在于 ModelPart) if (stroke.points != null) { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/data/TextureData.java b/src/main/java/com/chuangzhou/vivid2D/render/model/data/TextureData.java index 37b6473..32af8c1 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/data/TextureData.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/data/TextureData.java @@ -115,10 +115,10 @@ public class TextureData implements Serializable { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = (y * width + x) * components; - if (components >= 1) data[index] = (byte)((x * 255) / width); // R - if (components >= 2) data[index + 1] = (byte)((y * 255) / height); // G - if (components >= 3) data[index + 2] = (byte)128; // B - if (components >= 4) data[index + 3] = (byte)255; // A + if (components >= 1) data[index] = (byte) ((x * 255) / width); // R + if (components >= 2) data[index + 1] = (byte) ((y * 255) / height); // G + if (components >= 3) data[index + 2] = (byte) 128; // B + if (components >= 4) data[index + 3] = (byte) 255; // A } } return data; diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/ScaleDeformer.java b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/ScaleDeformer.java index c693a6c..aec4de4 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/transform/ScaleDeformer.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/transform/ScaleDeformer.java @@ -5,11 +5,11 @@ import com.chuangzhou.vivid2D.render.model.util.Mesh2D; import com.chuangzhou.vivid2D.render.model.util.SaveVector2f; import org.joml.Vector2f; -import java.util.List; import java.util.Map; /** * 缩放变形器 - 围绕中心点缩放顶点 + * * @author tzdwindows 7 */ public class ScaleDeformer extends Deformer { @@ -94,11 +94,23 @@ public class ScaleDeformer extends Deformer { } // Getter/Setter - public Vector2f getBaseScale() { return new Vector2f(baseScale); } - public void setBaseScale(Vector2f baseScale) { this.baseScale.set(baseScale); } + public Vector2f getBaseScale() { + return new Vector2f(baseScale); + } - public Vector2f getScaleRange() { return new Vector2f(scaleRange); } - public void setScaleRange(Vector2f scaleRange) { this.scaleRange.set(scaleRange); } + public void setBaseScale(Vector2f baseScale) { + this.baseScale.set(baseScale); + } - public Vector2f getCurrentScale() { return new Vector2f(currentScale); } + public Vector2f getScaleRange() { + return new Vector2f(scaleRange); + } + + public void setScaleRange(Vector2f scaleRange) { + this.scaleRange.set(scaleRange); + } + + public Vector2f getCurrentScale() { + return new Vector2f(currentScale); + } } \ No newline at end of file diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationClip.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationClip.java index 1dbbd6d..227fa1d 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationClip.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/AnimationClip.java @@ -25,7 +25,7 @@ public class AnimationClip { // ==================== 元数据 ==================== private String author; private String description; - private long creationTime; + private final long creationTime; private long lastModifiedTime; private Map userData; @@ -554,9 +554,17 @@ public class AnimationClip { } // Getter方法 - public String getParameterId() { return parameterId; } - public List getKeyframes() { return Collections.unmodifiableList(keyframes); } - public float getDefaultValue() { return defaultValue; } + public String getParameterId() { + return parameterId; + } + + public List getKeyframes() { + return Collections.unmodifiableList(keyframes); + } + + public float getDefaultValue() { + return defaultValue; + } } /** @@ -578,9 +586,17 @@ public class AnimationClip { } // 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; + } @Override public String toString() { @@ -621,10 +637,21 @@ public class AnimationClip { } // Getter方法 - public String getName() { return name; } - public float getTime() { return time; } - public Runnable getAction() { return action; } - public boolean isTriggered() { return triggered; } + public String getName() { + return name; + } + + public float getTime() { + return time; + } + + public Runnable getAction() { + return action; + } + + public boolean isTriggered() { + return triggered; + } @Override public String toString() { @@ -646,23 +673,39 @@ public class AnimationClip { // ==================== Getter/Setter ==================== - public String getName() { return name; } - public UUID getUuid() { return uuid; } + public String getName() { + return name; + } + + public UUID getUuid() { + return uuid; + } + + public float getDuration() { + return duration; + } - public float getDuration() { return duration; } public void setDuration(float duration) { this.duration = Math.max(0.0f, duration); markModified(); } - public float getFramesPerSecond() { return framesPerSecond; } + public float getFramesPerSecond() { + return framesPerSecond; + } + public void setFramesPerSecond(float framesPerSecond) { this.framesPerSecond = Math.max(1.0f, framesPerSecond); markModified(); } - public boolean isLooping() { return looping; } - public void setLooping(boolean looping) { this.looping = looping; } + public boolean isLooping() { + return looping; + } + + public void setLooping(boolean looping) { + this.looping = looping; + } public Map getCurves() { return Collections.unmodifiableMap(curves); @@ -676,18 +719,34 @@ public class AnimationClip { return Collections.unmodifiableMap(defaultValues); } - public String getAuthor() { return author; } - public void setAuthor(String author) { this.author = author; } + public String getAuthor() { + return author; + } - public String getDescription() { return description; } - public void setDescription(String description) { this.description = description; } + public void setAuthor(String author) { + this.author = author; + } - public long getCreationTime() { return creationTime; } - public long getLastModifiedTime() { return lastModifiedTime; } + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public long getCreationTime() { + return creationTime; + } + + public long getLastModifiedTime() { + return lastModifiedTime; + } public Map getUserData() { return Collections.unmodifiableMap(userData); } + public void setUserData(Map userData) { this.userData = new ConcurrentHashMap<>(userData); } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java index a857f52..dcf2158 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java @@ -290,7 +290,7 @@ public class BoundingBox { return new Vector2f[0]; } - return new Vector2f[] { + return new Vector2f[]{ new Vector2f(minX, minY), // 左下 new Vector2f(maxX, minY), // 右下 new Vector2f(maxX, maxY), // 右上 @@ -516,10 +516,21 @@ public class BoundingBox { // ==================== Getter方法 ==================== - public float getMinX() { return minX; } - public float getMinY() { return minY; } - public float getMaxX() { return maxX; } - public float getMaxY() { return maxY; } + public float getMinX() { + return minX; + } + + public float getMinY() { + return minY; + } + + public float getMaxX() { + return maxX; + } + + public float getMaxY() { + return maxY; + } public float getWidth() { return valid ? maxX - minX : 0.0f; @@ -529,12 +540,25 @@ public class BoundingBox { return valid ? maxY - minY : 0.0f; } - public float getLeft() { return minX; } - public float getRight() { return maxX; } - public float getBottom() { return minY; } - public float getTop() { return maxY; } + public float getLeft() { + return minX; + } - public boolean isValid() { return valid; } + public float getRight() { + return maxX; + } + + public float getBottom() { + return minY; + } + + public float getTop() { + return maxY; + } + + public boolean isValid() { + return valid; + } // ==================== 静态工厂方法 ==================== diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java index e77e559..3315b52 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java @@ -11,6 +11,14 @@ 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.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL30; +import org.lwjgl.system.MemoryUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.nio.FloatBuffer; import java.nio.IntBuffer; @@ -19,12 +27,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.joml.Vector4f; -import org.lwjgl.opengl.*; -import org.lwjgl.system.MemoryUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * 2D网格类,用于存储和管理2D模型的几何数据 * 支持顶点、UV坐标、索引和变形操作 @@ -42,7 +44,7 @@ public class Mesh2D { private ModelPart modelPart; // ==================== 二级顶点支持 ==================== - private List secondaryVertices = new ArrayList<>(); + private final List secondaryVertices = new ArrayList<>(); private boolean showSecondaryVertices = false; public Vector4f secondaryVertexColor = new Vector4f(0.0f, 1.0f, 0.0f, 1.0f); // 绿色二级顶点 public Vector4f selectedSecondaryVertexColor = new Vector4f(1.0f, 0.0f, 0.0f, 1.0f); // 红色选中的二级顶点 @@ -77,14 +79,14 @@ public class Mesh2D { // ==================== 液化状态渲染 ==================== public boolean showLiquifyOverlay = false; - private Vector4f liquifyOverlayColor = new Vector4f(1.0f, 0.5f, 0.0f, 0.3f); // 半透明橙色 + private final Vector4f liquifyOverlayColor = new Vector4f(1.0f, 0.5f, 0.0f, 0.3f); // 半透明橙色 // ==================== 木偶工具 ==================== - private List puppetPins = new ArrayList<>(); + private final List puppetPins = new ArrayList<>(); private PuppetPin selectedPuppetPin = null; private boolean showPuppetPins = true; - private Vector4f puppetPinColor = new Vector4f(1.0f, 0.0f, 0.0f, 1.0f); // 红色控制点 - private Vector4f selectedPuppetPinColor = new Vector4f(1.0f, 1.0f, 0.0f, 1.0f); // 黄色选中的控制点 + private final Vector4f puppetPinColor = new Vector4f(1.0f, 0.0f, 0.0f, 1.0f); // 红色控制点 + private final Vector4f selectedPuppetPinColor = new Vector4f(1.0f, 1.0f, 0.0f, 1.0f); // 黄色选中的控制点 private float puppetPinSize = 8.0f; // ==================== 常量 ==================== @@ -377,6 +379,7 @@ public class Mesh2D { public boolean getShowPuppetPins() { return showPuppetPins; } + /** * 绘制木偶控制点 */ @@ -516,7 +519,7 @@ public class Mesh2D { * 绘制控制点信息 */ private void drawPuppetPinInfo(BufferBuilder bb, PuppetPin pin, float x, float y) { - String infoText = pin.getName() + " (R:" + (int)pin.getInfluenceRadius() + ")"; + String infoText = pin.getName() + " (R:" + (int) pin.getInfluenceRadius() + ")"; TextRenderer textRenderer = ModelRender.getTextRenderer(); if (textRenderer != null) { float textWidth = textRenderer.getTextWidth(infoText); @@ -986,8 +989,8 @@ public class Mesh2D { float[] vertices = { -hw, -hh, // 左下 hw, -hh, // 右下 - hw, hh, // 右上 - -hw, hh // 左上 + hw, hh, // 右上 + -hw, hh // 左上 }; float[] uvs = { @@ -2296,11 +2299,7 @@ public class Mesh2D { } float squaredLength = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); - if (dot > squaredLength) { - return false; // 在线段终点之后 - } - - return true; + return !(dot > squaredLength); // 在线段终点之后 } public boolean containsPoint(Vector2f point) { @@ -2385,6 +2384,7 @@ public class Mesh2D { } // ==================== 状态管理 ==================== + /** * 标记数据已修改 */ @@ -2614,8 +2614,7 @@ public class Mesh2D { // 恢复之前的 program(如果我们切换过) if (switchedProgram) { - if (prevProgram != 0) RenderSystem.useProgram(prevProgram); - else RenderSystem.useProgram(0); + RenderSystem.useProgram(prevProgram); } // 选中框绘制(需要切换到固色 shader) @@ -3039,6 +3038,7 @@ public class Mesh2D { bb.vertex(centerX - arrowSize, rotationHandleY + arrowSize, 0.0f, 0.0f); bb.endImmediate(); } + private void drawCenterPoint(BufferBuilder bb, float minX, float minY, float maxX, float maxY) { // 使用 Mesh2D 的 pivot 作为中心点位置,但当 pivot 不在 bounds 内时回退为 bounds 中心(避免渲染时跳回 0,0 的情况) float centerX = pivot.x; @@ -3233,6 +3233,7 @@ public class Mesh2D { bounds[3] + expand }; } + public void draw() { if (!visible) return; if (indices == null || indices.length == 0) return; @@ -3332,7 +3333,7 @@ public class Mesh2D { // ==================== Getter/Setter ==================== public String getName() { - if (modelPart != null){ + if (modelPart != null) { return modelPart.getName(); } return name; @@ -3456,17 +3457,26 @@ public class Mesh2D { */ public String getDrawModeString() { switch (drawMode) { - case POINTS: return "POINTS"; - case LINES: return "LINES"; - case LINE_STRIP: return "LINE_STRIP"; - case TRIANGLES: return "TRIANGLES"; - case TRIANGLE_STRIP: return "TRIANGLE_STRIP"; - case TRIANGLE_FAN: return "TRIANGLE_FAN"; - default: return "UNKNOWN"; + case POINTS: + return "POINTS"; + case LINES: + return "LINES"; + case LINE_STRIP: + return "LINE_STRIP"; + case TRIANGLES: + return "TRIANGLES"; + case TRIANGLE_STRIP: + return "TRIANGLE_STRIP"; + case TRIANGLE_FAN: + return "TRIANGLE_FAN"; + default: + return "UNKNOWN"; } } - /** 标记或查询网格顶点是否已经被烘焙到世界坐标 */ + /** + * 标记或查询网格顶点是否已经被烘焙到世界坐标 + */ public void setBakedToWorld(boolean baked) { this.bakedToWorld = baked; } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/PhysicsSystem.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/PhysicsSystem.java index 0d0f83c..01c0d58 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/PhysicsSystem.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/PhysicsSystem.java @@ -4,13 +4,16 @@ import com.chuangzhou.vivid2D.render.model.Model2D; import com.chuangzhou.vivid2D.render.model.ModelPart; import org.joml.Vector2f; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 2D物理系统,用于处理模型的物理模拟 * 支持弹簧系统、碰撞检测、重力等物理效果 - * + *

* 调整点: * - 使用半隐式(symplectic)Euler 积分,替代之前的纯 Verlet(更稳定且直观) * - 在约束迭代后同步速度(根据位置变化计算),避免约束把位置推回后速度不一致导致僵化 @@ -471,8 +474,7 @@ public class PhysicsSystem { private void applyToModel(Model2D model) { for (PhysicsParticle particle : particles.values()) { Object userData = particle.getUserData(); - if (userData instanceof ModelPart) { - ModelPart part = (ModelPart) userData; + if (userData instanceof ModelPart part) { part.setPosition(particle.getPosition()); // 可选:根据速度设置旋转 @@ -611,11 +613,8 @@ public class PhysicsSystem { Vector2f positionDelta = new Vector2f(particle.getPosition()) .sub(particle.getPreviousPosition()); // 现在可以正常使用了 float positionDeltaSquared = positionDelta.lengthSquared(); - if (positionDeltaSquared > 0.001f) { // 位置变化阈值,可调整 - return true; - } - - return false; + // 位置变化阈值,可调整 + return positionDeltaSquared > 0.001f; }); // 检查是否有活跃的约束 @@ -731,31 +730,78 @@ public class PhysicsSystem { } // Getter/Setter 方法 - public String getId() { return id; } - public Vector2f getPosition() { return new Vector2f(position); } + public String getId() { + return id; + } + + public Vector2f getPosition() { + return new Vector2f(position); + } + public void setPosition(Vector2f position) { this.position.set(position); } - public Vector2f getVelocity() { return new Vector2f(velocity); } + + public Vector2f getVelocity() { + return new Vector2f(velocity); + } + public void setVelocity(Vector2f velocity) { this.velocity.set(velocity); } - public Vector2f getAcceleration() { return new Vector2f(acceleration); } + + public Vector2f getAcceleration() { + return new Vector2f(acceleration); + } + public float getMass() { if (Float.isInfinite(mass)) return Float.POSITIVE_INFINITY; return mass; } - public float getInverseMass() { return inverseMass; } - public float getRadius() { return radius; } - public void setRadius(float radius) { this.radius = radius; } - public boolean isMovable() { return movable; } - public void setMovable(boolean movable) { this.movable = movable; } - public boolean isAffectedByGravity() { return affectedByGravity; } - public void setAffectedByGravity(boolean affectedByGravity) { this.affectedByGravity = affectedByGravity; } - public Object getUserData() { return userData; } - public void setUserData(Object userData) { this.userData = userData; } - public boolean isAffectedByWind() { return affectedByWind; } - public void setAffectedByWind(boolean affectedByWind) { this.affectedByWind = affectedByWind; } + + public float getInverseMass() { + return inverseMass; + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public boolean isMovable() { + return movable; + } + + public void setMovable(boolean movable) { + this.movable = movable; + } + + public boolean isAffectedByGravity() { + return affectedByGravity; + } + + public void setAffectedByGravity(boolean affectedByGravity) { + this.affectedByGravity = affectedByGravity; + } + + public Object getUserData() { + return userData; + } + + public void setUserData(Object userData) { + this.userData = userData; + } + + public boolean isAffectedByWind() { + return affectedByWind; + } + + public void setAffectedByWind(boolean affectedByWind) { + this.affectedByWind = affectedByWind; + } } /** @@ -814,14 +860,37 @@ public class PhysicsSystem { } // Getter/Setter 方法 - public String getId() { return id; } - public PhysicsParticle getParticleA() { return particleA; } - public PhysicsParticle getParticleB() { return particleB; } - public float getRestLength() { return restLength; } - public float getStiffness() { return stiffness; } - public float getDamping() { return damping; } - public boolean isEnabled() { return enabled; } - public void setEnabled(boolean enabled) { this.enabled = enabled; } + public String getId() { + return id; + } + + public PhysicsParticle getParticleA() { + return particleA; + } + + public PhysicsParticle getParticleB() { + return particleB; + } + + public float getRestLength() { + return restLength; + } + + public float getStiffness() { + return stiffness; + } + + public float getDamping() { + return damping; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } /** @@ -829,8 +898,11 @@ public class PhysicsSystem { */ public interface PhysicsConstraint { void apply(float deltaTime); + PhysicsParticle getParticle(); + boolean isEnabled(); + void setEnabled(boolean enabled); } @@ -863,13 +935,36 @@ public class PhysicsSystem { } // Getter/Setter 方法 - @Override public PhysicsParticle getParticle() { return particle; } - @Override public boolean isEnabled() { return enabled; } - @Override public void setEnabled(boolean enabled) { this.enabled = enabled; } - public Vector2f getTargetPosition() { return new Vector2f(targetPosition); } - public void setTargetPosition(Vector2f targetPosition) { this.targetPosition.set(targetPosition); } - public float getStrength() { return strength; } - public void setStrength(float strength) { this.strength = Math.max(0.0f, Math.min(1.0f, strength)); } + @Override + public PhysicsParticle getParticle() { + return particle; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Vector2f getTargetPosition() { + return new Vector2f(targetPosition); + } + + public void setTargetPosition(Vector2f targetPosition) { + this.targetPosition.set(targetPosition); + } + + public float getStrength() { + return strength; + } + + public void setStrength(float strength) { + this.strength = Math.max(0.0f, Math.min(1.0f, strength)); + } } /** @@ -902,11 +997,28 @@ public class PhysicsSystem { } // Getter/Setter 方法 - @Override public PhysicsParticle getParticle() { return particle; } - @Override public boolean isEnabled() { return enabled; } - @Override public void setEnabled(boolean enabled) { this.enabled = enabled; } - public PhysicsParticle getTarget() { return target; } - public float getMaxDistance() { return maxDistance; } + @Override + public PhysicsParticle getParticle() { + return particle; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public PhysicsParticle getTarget() { + return target; + } + + public float getMaxDistance() { + return maxDistance; + } } /** @@ -914,9 +1026,13 @@ public class PhysicsSystem { */ public interface PhysicsCollider { boolean collidesWith(PhysicsParticle particle); + void resolveCollision(PhysicsParticle particle, float deltaTime); + String getId(); + boolean isEnabled(); + void setEnabled(boolean enabled); } @@ -973,12 +1089,32 @@ public class PhysicsSystem { } // Getter/Setter 方法 - @Override public String getId() { return id; } - @Override public boolean isEnabled() { return enabled; } - @Override public void setEnabled(boolean enabled) { this.enabled = enabled; } - public Vector2f getCenter() { return new Vector2f(center); } - public void setCenter(Vector2f center) { this.center.set(center); } - public float getRadius() { return radius; } + @Override + public String getId() { + return id; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Vector2f getCenter() { + return new Vector2f(center); + } + + public void setCenter(Vector2f center) { + this.center.set(center); + } + + public float getRadius() { + return radius; + } } /** @@ -1059,13 +1195,36 @@ public class PhysicsSystem { } // Getter/Setter 方法 - @Override public String getId() { return id; } - @Override public boolean isEnabled() { return enabled; } - @Override public void setEnabled(boolean enabled) { this.enabled = enabled; } - public Vector2f getCenter() { return new Vector2f(center); } - public void setCenter(Vector2f center) { this.center.set(center); } - public float getWidth() { return width; } - public float getHeight() { return height; } + @Override + public String getId() { + return id; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Vector2f getCenter() { + return new Vector2f(center); + } + + public void setCenter(Vector2f center) { + this.center.set(center); + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } } /** @@ -1090,12 +1249,29 @@ public class PhysicsSystem { } // Getter 方法 - public int getParticleCount() { return particleCount; } - public int getSpringCount() { return springCount; } - public int getConstraintCount() { return constraintCount; } - public int getColliderCount() { return colliderCount; } - public float getAverageUpdateTime() { return averageUpdateTime; } - public int getTotalUpdates() { return totalUpdates; } + public int getParticleCount() { + return particleCount; + } + + public int getSpringCount() { + return springCount; + } + + public int getConstraintCount() { + return constraintCount; + } + + public int getColliderCount() { + return colliderCount; + } + + public float getAverageUpdateTime() { + return averageUpdateTime; + } + + public int getTotalUpdates() { + return totalUpdates; + } @Override public String toString() { diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Texture.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Texture.java index 3d9263b..9a96d28 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Texture.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Texture.java @@ -1,12 +1,7 @@ package com.chuangzhou.vivid2D.render.model.util; import com.chuangzhou.vivid2D.render.systems.RenderSystem; -import org.lwjgl.opengl.GL; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; -import org.lwjgl.opengl.GL13; -import org.lwjgl.opengl.GL14; -import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.*; import org.lwjgl.stb.STBImage; import org.lwjgl.stb.STBImageWrite; import org.lwjgl.system.MemoryUtil; @@ -75,9 +70,17 @@ public class Texture { this.glFormat = glFormat; } - public int getComponents() { return components; } - public int getGLInternalFormat() { return glInternalFormat; } - public int getGLFormat() { return glFormat; } + public int getComponents() { + return components; + } + + public int getGLInternalFormat() { + return glInternalFormat; + } + + public int getGLFormat() { + return glFormat; + } } public enum TextureType { @@ -95,7 +98,9 @@ public class Texture { this.glType = glType; } - public int getGLType() { return glType; } + public int getGLType() { + return glType; + } } public enum TextureFilter { @@ -112,7 +117,9 @@ public class Texture { this.glFilter = glFilter; } - public int getGLFilter() { return glFilter; } + public int getGLFilter() { + return glFilter; + } } public enum TextureWrap { @@ -127,7 +134,9 @@ public class Texture { this.glWrap = glWrap; } - public int getGLWrap() { return glWrap; } + public int getGLWrap() { + return glWrap; + } } // ==================== STB 图像加载 ==================== @@ -244,7 +253,8 @@ public class Texture { // 恢复原先的 UNPACK_ALIGNMENT try { GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, prevUnpack); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } unbind(); } } @@ -333,10 +343,10 @@ public class Texture { * 从当前纹理裁剪出一个子纹理并返回新的 Texture。 * 仅支持 UNSIGNED_BYTE 类型的纹理(常见的 8-bit per component 图像)。 * - * @param x 裁剪区域左上角 X(像素) - * @param y 裁剪区域左上角 Y(像素) - * @param w 裁剪区域宽度(像素) - * @param h 裁剪区域高度(像素) + * @param x 裁剪区域左上角 X(像素) + * @param y 裁剪区域左上角 Y(像素) + * @param w 裁剪区域宽度(像素) + * @param h 裁剪区域高度(像素) * @param newName 新纹理名称 * @return 新创建的子纹理 */ @@ -869,10 +879,14 @@ public class Texture { */ public static TextureFormat getTextureFormat(int components) { switch (components) { - case 1: return TextureFormat.RED; - case 2: return TextureFormat.RG; - case 3: return TextureFormat.RGB; - case 4: return TextureFormat.RGBA; + case 1: + return TextureFormat.RED; + case 2: + return TextureFormat.RG; + case 3: + return TextureFormat.RGB; + case 4: + return TextureFormat.RGBA; default: throw new IllegalArgumentException("Unsupported number of components: " + components); } @@ -1071,7 +1085,6 @@ public class Texture { } - /** * 从字节数组创建纹理 */ @@ -1196,13 +1209,20 @@ public class Texture { */ private String getGLErrorString(int error) { switch (error) { - case GL11.GL_INVALID_ENUM: return "GL_INVALID_ENUM"; - case GL11.GL_INVALID_VALUE: return "GL_INVALID_VALUE"; - case GL11.GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; - case GL11.GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; - case GL11.GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; - case GL11.GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; - default: return "Unknown Error (0x" + Integer.toHexString(error) + ")"; + case GL11.GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL11.GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL11.GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL11.GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + case GL11.GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; + case GL11.GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; + default: + return "Unknown Error (0x" + Integer.toHexString(error) + ")"; } } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/RenderSystem.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/RenderSystem.java index be8b2e6..28925f6 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/RenderSystem.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/RenderSystem.java @@ -26,6 +26,7 @@ import java.util.function.Supplier; */ public final class RenderSystem { private static final Logger logger = LoggerFactory.getLogger(RenderSystem.class); + private RenderSystem() { /* no instances */ } // ================== 线程管理 ================== @@ -155,7 +156,7 @@ public final class RenderSystem { java.nio.FloatBuffer floatBuf = org.lwjgl.system.MemoryUtil.memAllocFloat(4); try { GL11.glGetFloatv(GL11.GL_COLOR_CLEAR_VALUE, floatBuf); - this.clearColor = new float[] { + this.clearColor = new float[]{ floatBuf.get(0), floatBuf.get(1), floatBuf.get(2), floatBuf.get(3) }; @@ -166,7 +167,7 @@ public final class RenderSystem { java.nio.IntBuffer viewportBuf = org.lwjgl.system.MemoryUtil.memAllocInt(4); try { GL11.glGetIntegerv(GL11.GL_VIEWPORT, viewportBuf); - this.viewport = new int[] { + this.viewport = new int[]{ viewportBuf.get(0), viewportBuf.get(1), viewportBuf.get(2), viewportBuf.get(3) }; @@ -187,8 +188,8 @@ public final class RenderSystem { this.blendDstFactor = GL11.GL_ONE_MINUS_SRC_ALPHA; this.activeTexture = GL13.GL_TEXTURE0; this.boundTexture = 0; - this.clearColor = new float[] {0.0f, 0.0f, 0.0f, 1.0f}; - this.viewport = new int[] {0, 0, viewportWidth, viewportHeight}; + this.clearColor = new float[]{0.0f, 0.0f, 0.0f, 1.0f}; + this.viewport = new int[]{0, 0, viewportWidth, viewportHeight}; } public void restore() { @@ -657,6 +658,7 @@ public final class RenderSystem { assertOnRenderThread(); GL11.glLineWidth(width); } + public static void drawElements(int mode, int count, int type, long indices) { if (!isOnRenderThread()) { recordRenderCall(() -> _drawElements(mode, count, type, indices)); @@ -1206,8 +1208,9 @@ public final class RenderSystem { /** * 设置着色器纹理 + * * @param textureUnit 纹理单元 (0, 1, 2, ...) - * @param texture 纹理对象 + * @param texture 纹理对象 */ public static void setShaderTexture(int textureUnit, com.chuangzhou.vivid2D.render.model.util.Texture texture) { if (!isOnRenderThread()) { @@ -1247,8 +1250,9 @@ public final class RenderSystem { /** * 设置着色器纹理 - 接受纹理ID的版本 + * * @param textureUnit 纹理单元 - * @param textureId 纹理ID + * @param textureId 纹理ID */ public static void setShaderTexture(int textureUnit, int textureId) { if (!isOnRenderThread()) { @@ -1433,6 +1437,7 @@ public final class RenderSystem { return false; } + public static void pixelStore(int pname, int param) { if (!isOnRenderThread()) { recordRenderCall(() -> _pixelStore(pname, param)); @@ -1514,6 +1519,7 @@ public final class RenderSystem { logger.info("Max Texture Units: {}", GL11.glGetInteger(GL20.GL_MAX_TEXTURE_IMAGE_UNITS)); } + public static void setupDefaultState() { beginInitialization(); @@ -1559,17 +1565,22 @@ public final class RenderSystem { } logger.error("OpenGL error during {}: {}\n{}", - operation, getGLErrorString(error), stackTraceBuilder.toString()); + operation, getGLErrorString(error), stackTraceBuilder); } } private static String getGLErrorString(int error) { switch (error) { - case GL11.GL_INVALID_ENUM: return "GL_INVALID_ENUM"; - case GL11.GL_INVALID_VALUE: return "GL_INVALID_VALUE"; - case GL11.GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; - case GL11.GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; - default: return "Unknown (0x" + Integer.toHexString(error) + ")"; + case GL11.GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL11.GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL11.GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL11.GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + default: + return "Unknown (0x" + Integer.toHexString(error) + ")"; } } diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java index fa416b4..0007641 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java @@ -1,18 +1,20 @@ package com.chuangzhou.vivid2D.render.systems.sources.def; -import com.chuangzhou.vivid2D.render.systems.sources.*; - +import com.chuangzhou.vivid2D.render.systems.sources.CompleteShader; +import com.chuangzhou.vivid2D.render.systems.sources.Shader; +import com.chuangzhou.vivid2D.render.systems.sources.ShaderProgram; import org.joml.Vector4f; /** * 文本着色器 + * * @author tzdwindows 7 */ public class TextShader implements CompleteShader { private final VertexShader vertexShader = new VertexShader(); private final FragmentShader fragmentShader = new FragmentShader(); - private Vector4f color = new Vector4f(1,1,1,1); + private final Vector4f color = new Vector4f(1, 1, 1, 1); public void setColor(Vector4f color) { this.color.set(color); @@ -50,20 +52,20 @@ public class TextShader implements CompleteShader { @Override public String getShaderCode() { return """ - #version 330 core - layout(location = 0) in vec2 aPosition; - layout(location = 1) in vec2 aTexCoord; + #version 330 core + layout(location = 0) in vec2 aPosition; + layout(location = 1) in vec2 aTexCoord; - uniform mat3 uProjectionMatrix; + uniform mat3 uProjectionMatrix; - out vec2 vTexCoord; + out vec2 vTexCoord; - void main() { - vec3 p = uProjectionMatrix * vec3(aPosition, 1.0); - gl_Position = vec4(p.xy, 0.0, 1.0); - vTexCoord = aTexCoord; - } - """; + void main() { + vec3 p = uProjectionMatrix * vec3(aPosition, 1.0); + gl_Position = vec4(p.xy, 0.0, 1.0); + vTexCoord = aTexCoord; + } + """; } @Override @@ -76,19 +78,19 @@ public class TextShader implements CompleteShader { @Override public String getShaderCode() { return """ - #version 330 core - in vec2 vTexCoord; - out vec4 FragColor; + #version 330 core + in vec2 vTexCoord; + out vec4 FragColor; - uniform sampler2D uTexture; - uniform vec4 uColor; + uniform sampler2D uTexture; + uniform vec4 uColor; - void main() { - // 使用 .r 通道读取单通道纹理 - float alpha = texture(uTexture, vTexCoord).r; - FragColor = vec4(uColor.rgb, uColor.a * alpha); - } - """; + void main() { + // 使用 .r 通道读取单通道纹理 + float alpha = texture(uTexture, vTexCoord).r; + FragColor = vec4(uColor.rgb, uColor.a * alpha); + } + """; } @Override