refactor(animation):优化动画系统字段不可变性与getter方法格式- 将AnimationClip中的creationTime字段设为final

- 将AnimationLayer中的parameterOverrides字段设为final
- 将AnimationParameter中的id、defaultValue、minValue、maxValue字段设为final
- 将LightSource中的position、color、intensity字段设为final
- 统一所有getter方法的代码格式,增加换行与大括号
- 优化Mesh2D中部分条件判断逻辑与字段final声明- 调整部分JavaDoc注释格式与空行位置提升可读性
This commit is contained in:
tzdwindows 7
2025-10-25 17:12:21 +08:00
parent a9c2d202d3
commit 3add504321
14 changed files with 558 additions and 224 deletions

View File

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

View File

@@ -94,7 +94,10 @@ public class PsdParser {
}
} finally {
try { reader.dispose(); } catch (Exception ignored) {}
try {
reader.dispose();
} catch (Exception ignored) {
}
}
return result;

View File

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

View File

@@ -9,6 +9,7 @@ import java.io.Serializable;
/**
* LightSource 的序列化数据类(扩展:包含辉光/Glow 的序列化字段)
*
* @author tzdwindows 7
*/
public class LightSourceData implements Serializable {

View File

@@ -80,8 +80,7 @@ public class PartData implements Serializable {
// 期望的方法签名: public List<YourStrokeClass> 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) {

View File

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

View File

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

View File

@@ -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<String, String> userData;
@@ -554,9 +554,17 @@ public class AnimationClip {
}
// Getter方法
public String getParameterId() { return parameterId; }
public List<Keyframe> getKeyframes() { return Collections.unmodifiableList(keyframes); }
public float getDefaultValue() { return defaultValue; }
public String getParameterId() {
return parameterId;
}
public List<Keyframe> 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<String, AnimationCurve> 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<String, String> getUserData() {
return Collections.unmodifiableMap(userData);
}
public void setUserData(Map<String, String> userData) {
this.userData = new ConcurrentHashMap<>(userData);
}

View File

@@ -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;
}
// ==================== 静态工厂方法 ====================

View File

@@ -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<SecondaryVertex> secondaryVertices = new ArrayList<>();
private final List<SecondaryVertex> 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<PuppetPin> puppetPins = new ArrayList<>();
private final List<PuppetPin> 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;
}

View File

@@ -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物理系统用于处理模型的物理模拟
* 支持弹簧系统、碰撞检测、重力等物理效果
*
* <p>
* 调整点:
* - 使用半隐式symplecticEuler 积分,替代之前的纯 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() {

View File

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

View File

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

View File

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