feat(model): 添加液化笔划数据的序列化与反序列化支持
- 在 ModelData.PartData 中新增 liquifyStrokes 字段用于保存液化笔划- 实现通过反射读取 ModelPart 的液化笔划数据(兼容旧版本)- 支持多种数据结构形式的液化点读取(Vector2f、自定义类、Map) - 反序列化时自动重放液化笔划到 ModelPart- 添加 LiquifyStrokeData 和 LiquifyPointData 用于序列化存储 - 提供深度拷贝支持以确保 liquifyStrokes 数据完整复制 - 增加 ModelLoadTest 测试类用于验证模型加载与结构检查
This commit is contained in:
450
src/main/java/com/chuangzhou/vivid2D/test/ModelLoadTest.java
Normal file
450
src/main/java/com/chuangzhou/vivid2D/test/ModelLoadTest.java
Normal file
@@ -0,0 +1,450 @@
|
||||
package com.chuangzhou.vivid2D.test;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.ModelRender;
|
||||
import com.chuangzhou.vivid2D.render.model.Model2D;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
/**
|
||||
* ModelLoadTest - enhanced debug loader
|
||||
*
|
||||
* - 加载模型后会自动检查 model 内部结构并打印(parts, meshes, textures)
|
||||
* - 尝试把第一个 part 放到窗口中心以确保在可视范围内
|
||||
* - 每帧确保 ModelRender 的 viewport 与窗口大小一致
|
||||
*
|
||||
* 运行前请确保 MODEL_PATH 指向你保存的 model 文件
|
||||
*/
|
||||
public class ModelLoadTest {
|
||||
|
||||
private long window;
|
||||
private Model2D model;
|
||||
|
||||
// Window dimensions
|
||||
private static int WINDOW_WIDTH = 800;
|
||||
private static int WINDOW_HEIGHT = 600;
|
||||
|
||||
// Debug
|
||||
private boolean enableWireframe = false;
|
||||
|
||||
// 要加载的 model 文件路径(请根据实际保存位置修改)
|
||||
private static final String MODEL_PATH = "C:\\Users\\Administrator\\Desktop\\trump_texture.model";
|
||||
|
||||
public static void main(String[] args) {
|
||||
new ModelLoadTest().run();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
init();
|
||||
loop();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() throws Exception {
|
||||
if (!glfwInit()) {
|
||||
throw new IllegalStateException("Unable to initialize GLFW");
|
||||
}
|
||||
|
||||
// Configure GLFW
|
||||
glfwDefaultWindowHints();
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
// Create window
|
||||
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Model Load Test - DEBUG", MemoryUtil.NULL, MemoryUtil.NULL);
|
||||
if (window == MemoryUtil.NULL) {
|
||||
throw new RuntimeException("Failed to create the GLFW window");
|
||||
}
|
||||
|
||||
// Center window
|
||||
GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
if (vidMode != null) {
|
||||
glfwSetWindowPos(
|
||||
window,
|
||||
(vidMode.width() - WINDOW_WIDTH) / 2,
|
||||
(vidMode.height() - WINDOW_HEIGHT) / 2
|
||||
);
|
||||
}
|
||||
|
||||
// Key callback
|
||||
glfwSetKeyCallback(window, (w, key, scancode, action, mods) -> {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
if (key == GLFW_KEY_SPACE && action == GLFW_RELEASE) {
|
||||
enableWireframe = !enableWireframe;
|
||||
System.out.println("Wireframe: " + (enableWireframe ? "ON" : "OFF"));
|
||||
}
|
||||
});
|
||||
|
||||
// Create OpenGL context
|
||||
glfwMakeContextCurrent(window);
|
||||
GL.createCapabilities();
|
||||
|
||||
// Show window
|
||||
glfwShowWindow(window);
|
||||
|
||||
// 初始化渲染系统
|
||||
ModelRender.initialize();
|
||||
|
||||
// 尝试加载 model
|
||||
loadModelFromFile(MODEL_PATH);
|
||||
|
||||
// 一些额外检查/尝试修复
|
||||
postLoadSanityChecks();
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试多种方式加载 Model2D:优先尝试静态方法 loadFromFile/fromFile/load,
|
||||
* 其次尝试创建空实例并调用实例方法 loadFromFile(String)
|
||||
*/
|
||||
private void loadModelFromFile(String path) {
|
||||
inspectSerializedFileStructure( path);
|
||||
File f = new File(path);
|
||||
if (!f.exists()) {
|
||||
System.err.println("Model file not found: " + path);
|
||||
model = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// 尝试静态工厂方法
|
||||
try {
|
||||
Method m;
|
||||
String[] names = {"loadFromFile", "fromFile", "load"};
|
||||
for (String name : names) {
|
||||
try {
|
||||
m = Model2D.class.getMethod(name, String.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
m = null;
|
||||
}
|
||||
if (m != null) {
|
||||
Object res = m.invoke(null, path);
|
||||
if (res instanceof Model2D) {
|
||||
model = (Model2D) res;
|
||||
System.out.println("Model loaded via static method: " + name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
// 继续尝试实例方法
|
||||
}
|
||||
|
||||
// 尝试实例方法
|
||||
try {
|
||||
Model2D inst = null;
|
||||
try {
|
||||
inst = Model2D.class.getConstructor().newInstance();
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
try {
|
||||
inst = Model2D.class.getConstructor(String.class).newInstance("loaded_model");
|
||||
} catch (NoSuchMethodException ex) {
|
||||
inst = null;
|
||||
}
|
||||
}
|
||||
if (inst != null) {
|
||||
try {
|
||||
Method im = Model2D.class.getMethod("loadFromFile", String.class);
|
||||
im.invoke(inst, path);
|
||||
model = inst;
|
||||
System.out.println("Model loaded via instance method loadFromFile");
|
||||
return;
|
||||
} catch (NoSuchMethodException ignored) { }
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// 最后尝试反序列化 ObjectInputStream
|
||||
try {
|
||||
java.io.ObjectInputStream ois = new java.io.ObjectInputStream(new java.io.FileInputStream(f));
|
||||
Object obj = ois.readObject();
|
||||
ois.close();
|
||||
if (obj instanceof Model2D) {
|
||||
model = (Model2D) obj;
|
||||
System.out.println("Model deserialized from file via ObjectInputStream");
|
||||
return;
|
||||
} else {
|
||||
System.err.println("Deserialized object is not Model2D: " + (obj != null ? obj.getClass() : "null"));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
System.err.println("Failed to load model from file using known methods: " + path);
|
||||
model = null;
|
||||
}
|
||||
|
||||
// ====== 追加方法:反序列化内容深度检测(帮助诊断保存文件里到底有什么) ======
|
||||
private void inspectSerializedFileStructure(String path) {
|
||||
File f = new File(path);
|
||||
if (!f.exists()) {
|
||||
System.err.println("File not found: " + path);
|
||||
return;
|
||||
}
|
||||
System.out.println("Inspecting serialized object structure in file: " + path);
|
||||
try (java.io.ObjectInputStream ois = new java.io.ObjectInputStream(new java.io.FileInputStream(f))) {
|
||||
Object obj = ois.readObject();
|
||||
printObjectStructure(obj, 0, new java.util.HashSet<>());
|
||||
} catch (Throwable t) {
|
||||
System.err.println("Failed to read/inspect serialized file: " + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void printObjectStructure(Object obj, int indent, java.util.Set<Object> seen) {
|
||||
if (obj == null) {
|
||||
printIndent(indent); System.out.println("null"); return;
|
||||
}
|
||||
if (seen.contains(obj)) {
|
||||
printIndent(indent); System.out.println("<<already seen " + obj.getClass().getName() + ">>"); return;
|
||||
}
|
||||
seen.add(obj);
|
||||
Class<?> cls = obj.getClass();
|
||||
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());
|
||||
int i = 0;
|
||||
for (Object e : col) {
|
||||
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());
|
||||
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);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 打印字段(反射),但避免进入 Java 内部类和基本类型
|
||||
java.lang.reflect.Field[] fields = cls.getDeclaredFields();
|
||||
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()));
|
||||
// 对常见自定义类型深入一层
|
||||
if (val != null && !val.getClass().getName().startsWith("java.") && !val.getClass().isPrimitive()) {
|
||||
if (val instanceof Number || val instanceof String) continue;
|
||||
printObjectStructure(val, indent+2, seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void printIndent(int n) {
|
||||
for (int i = 0; i < n; i++) System.out.print(" ");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 加载后的一些检查与尝试性修复:
|
||||
* - 打印 parts/meshes/textures 的信息
|
||||
* - 如果没有 parts/meshes,提醒并退出
|
||||
* - 如果有 part,尝试把第一个 part 放到窗口中心
|
||||
*/
|
||||
private void postLoadSanityChecks() {
|
||||
if (model == null) {
|
||||
System.err.println("Model is null after loading. Nothing to render.");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Model loaded: " + model.getClass().getName());
|
||||
|
||||
try {
|
||||
// 通过反射尝试读取 parts / meshes / textures 等
|
||||
Method getParts = tryGetMethod(Model2D.class, "getParts");
|
||||
Method getMeshes = tryGetMethod(Model2D.class, "getMeshes");
|
||||
Method getTextures = tryGetMethod(Model2D.class, "getTextures");
|
||||
|
||||
if (getParts != null) {
|
||||
Object partsObj = getParts.invoke(model);
|
||||
if (partsObj instanceof List) {
|
||||
List<?> parts = (List<?>) partsObj;
|
||||
System.out.println("Parts count: " + parts.size());
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
Object p = parts.get(i);
|
||||
System.out.println(" Part[" + i + "]: " + p.getClass().getName());
|
||||
// 尝试获取 name / position via reflection
|
||||
try {
|
||||
Method getName = tryGetMethod(p.getClass(), "getName");
|
||||
Method getPosition = tryGetMethod(p.getClass(), "getPosition");
|
||||
Object name = getName != null ? getName.invoke(p) : "<no-name>";
|
||||
Object pos = getPosition != null ? getPosition.invoke(p) : null;
|
||||
System.out.println(" name=" + name + ", pos=" + pos);
|
||||
} catch (Throwable ignored) {}
|
||||
}
|
||||
|
||||
// 如果 parts 不为空,尝试把第一个 part 放到窗口中心(如果有 setPosition)
|
||||
if (!parts.isEmpty()) {
|
||||
Object first = parts.get(0);
|
||||
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);
|
||||
System.out.println("Moved first part to window center.");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getMeshes != null) {
|
||||
Object meshesObj = getMeshes.invoke(model);
|
||||
if (meshesObj instanceof List) {
|
||||
List<?> meshes = (List<?>) meshesObj;
|
||||
System.out.println("Meshes count: " + meshes.size());
|
||||
for (int i = 0; i < Math.min(meshes.size(), 10); i++) {
|
||||
Object m = meshes.get(i);
|
||||
System.out.println(" Mesh[" + i + "]: " + m.getClass().getName());
|
||||
// try to print vertex count / texture
|
||||
try {
|
||||
Method getVertexCount = tryGetMethod(m.getClass(), "getVertexCount");
|
||||
Method getTexture = tryGetMethod(m.getClass(), "getTexture");
|
||||
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) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getTextures != null) {
|
||||
Object texObj = getTextures.invoke(model);
|
||||
if (texObj instanceof List) {
|
||||
List<?> texs = (List<?>) texObj;
|
||||
System.out.println("Textures count: " + texs.size());
|
||||
for (int i = 0; i < Math.min(texs.size(), 10); i++) {
|
||||
Object t = texs.get(i);
|
||||
System.out.println(" Texture[" + i + "]: " + t.getClass().getName());
|
||||
try {
|
||||
Method getW = tryGetMethod(t.getClass(), "getWidth");
|
||||
Method getH = tryGetMethod(t.getClass(), "getHeight");
|
||||
Method getId = tryGetMethod(t.getClass(), "getTextureId");
|
||||
Object w = getW != null ? getW.invoke(t) : "?";
|
||||
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 t) {
|
||||
System.err.println("Failed to introspect model: " + t.getMessage());
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Method tryGetMethod(Class<?> cls, String name, Class<?>... params) {
|
||||
try {
|
||||
return cls.getMethod(name, params);
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void loop() {
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
|
||||
|
||||
float last = (float) glfwGetTime();
|
||||
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
float now = (float) glfwGetTime();
|
||||
float delta = now - last;
|
||||
last = now;
|
||||
|
||||
// 每帧确保 viewport 与窗口大小一致(避免投影错位)
|
||||
IntBuffer w = MemoryUtil.memAllocInt(1);
|
||||
IntBuffer h = MemoryUtil.memAllocInt(1);
|
||||
glfwGetFramebufferSize(window, w, h);
|
||||
int ww = Math.max(1, w.get(0));
|
||||
int hh = Math.max(1, h.get(0));
|
||||
MemoryUtil.memFree(w);
|
||||
MemoryUtil.memFree(h);
|
||||
if (ww != WINDOW_WIDTH || hh != WINDOW_HEIGHT) {
|
||||
WINDOW_WIDTH = ww;
|
||||
WINDOW_HEIGHT = hh;
|
||||
ModelRender.setViewport(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
System.out.println("Viewport updated to: " + WINDOW_WIDTH + "x" + WINDOW_HEIGHT);
|
||||
}
|
||||
|
||||
// render
|
||||
render(delta);
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private void render(float deltaTime) {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
if (enableWireframe) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
} else {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
if (model == null) {
|
||||
// Nothing to render, 提示并返回
|
||||
//(仅打印一次以免刷屏)
|
||||
System.err.println("No model to render (model == null).");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ModelRender.render(deltaTime, model);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
// 额外检查 glGetError
|
||||
int err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
System.err.println("OpenGL error after render: 0x" + Integer.toHexString(err));
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
System.out.println("Cleaning up...");
|
||||
|
||||
try {
|
||||
ModelRender.cleanup();
|
||||
} catch (Throwable ignored) {}
|
||||
|
||||
|
||||
|
||||
if (window != MemoryUtil.NULL) {
|
||||
glfwDestroyWindow(window);
|
||||
}
|
||||
glfwTerminate();
|
||||
System.out.println("Finished cleanup");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
package com.chuangzhou.vivid2D.test;
|
||||
|
||||
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 org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
/**
|
||||
* Texture Render Test Class - Debug Version
|
||||
* @author tzdwindows 7
|
||||
*/
|
||||
public class ModelRenderTextureTest {
|
||||
|
||||
private long window;
|
||||
private Model2D model;
|
||||
|
||||
// Window dimensions
|
||||
private static final int WINDOW_WIDTH = 800;
|
||||
private static final int WINDOW_HEIGHT = 600;
|
||||
|
||||
// Debug flags
|
||||
private int frameCount = 0;
|
||||
private double lastFpsTime = 0;
|
||||
private boolean enableWireframe = false;
|
||||
|
||||
public static void main(String[] args) {
|
||||
new ModelRenderTextureTest().run();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
init();
|
||||
loop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// Initialize GLFW
|
||||
if (!glfwInit()) {
|
||||
throw new IllegalStateException("Unable to initialize GLFW");
|
||||
}
|
||||
|
||||
// Configure GLFW
|
||||
glfwDefaultWindowHints();
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
// Create window
|
||||
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "ModelRender Texture Test - DEBUG", MemoryUtil.NULL, MemoryUtil.NULL);
|
||||
if (window == MemoryUtil.NULL) {
|
||||
throw new RuntimeException("Failed to create the GLFW window");
|
||||
}
|
||||
|
||||
// Center window
|
||||
GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
glfwSetWindowPos(
|
||||
window,
|
||||
(vidMode.width() - WINDOW_WIDTH) / 2,
|
||||
(vidMode.height() - WINDOW_HEIGHT) / 2
|
||||
);
|
||||
|
||||
// Set callbacks
|
||||
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
if (key == GLFW_KEY_SPACE && action == GLFW_RELEASE) {
|
||||
enableWireframe = !enableWireframe;
|
||||
System.out.println("Wireframe mode: " + (enableWireframe ? "ON" : "OFF"));
|
||||
}
|
||||
if (key == GLFW_KEY_R && action == GLFW_RELEASE) {
|
||||
recreateModel();
|
||||
}
|
||||
});
|
||||
|
||||
// Create OpenGL context
|
||||
glfwMakeContextCurrent(window);
|
||||
GL.createCapabilities();
|
||||
|
||||
// Show window
|
||||
glfwShowWindow(window);
|
||||
|
||||
// Initialize ModelRender
|
||||
ModelRender.initialize();
|
||||
|
||||
// Create test model
|
||||
createTestModel();
|
||||
|
||||
System.out.println("=== DEBUG INFO ===");
|
||||
System.out.println("Press SPACE to toggle wireframe mode");
|
||||
System.out.println("Press R to recreate model");
|
||||
System.out.println("Press ESC to exit");
|
||||
System.out.println("==================");
|
||||
}
|
||||
|
||||
private void createTestModel() {
|
||||
if (model != null) {
|
||||
// Clean up previous model if exists
|
||||
System.out.println("Cleaning up previous model...");
|
||||
}
|
||||
|
||||
model = new Model2D("TextureTestModel");
|
||||
|
||||
try {
|
||||
// Load Trump image texture
|
||||
String texturePath = "G:\\鬼畜素材\\川普\\图片\\7(DJ0MH9}`)GJYHHADQDHYN.png";
|
||||
System.out.println("Loading texture: " + texturePath);
|
||||
|
||||
Texture texture = Texture.createFromFile("trump_texture", texturePath);
|
||||
model.addTexture(texture);
|
||||
|
||||
System.out.println("Texture loaded: " + texture.getWidth() + "x" + texture.getHeight());
|
||||
System.out.println("Texture ID: " + texture.getTextureId());
|
||||
System.out.println("Texture format: " + texture.getFormat());
|
||||
|
||||
// 使用与工作示例相同的方式创建网格
|
||||
// 根据纹理尺寸创建合适大小的四边形
|
||||
float width = texture.getWidth() / 2.0f; // 缩小以适应屏幕
|
||||
float height = texture.getHeight() / 2.0f;
|
||||
|
||||
// 使用 Mesh2D.createQuad 方法创建网格(如果可用)
|
||||
Mesh2D mesh;
|
||||
try {
|
||||
// 尝试使用 createQuad 方法
|
||||
mesh = Mesh2D.createQuad("trump_mesh", width, height);
|
||||
System.out.println("Using Mesh2D.createQuad method");
|
||||
} catch (Exception e) {
|
||||
// 回退到手动创建顶点
|
||||
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
|
||||
};
|
||||
|
||||
float[] uvs = {
|
||||
0.0f, 1.0f, // bottom left
|
||||
1.0f, 1.0f, // bottom right
|
||||
1.0f, 0.0f, // top right
|
||||
0.0f, 0.0f // top left
|
||||
};
|
||||
|
||||
int[] indices = {
|
||||
0, 1, 2, // first triangle
|
||||
2, 3, 0 // second triangle
|
||||
};
|
||||
|
||||
mesh = model.createMesh("trump_mesh", vertices, uvs, indices);
|
||||
}
|
||||
|
||||
mesh.setTexture(texture);
|
||||
|
||||
// Create part and add mesh
|
||||
ModelPart part = model.createPart("trump_part");
|
||||
|
||||
part.addMesh(mesh);
|
||||
part.setVisible(true);
|
||||
|
||||
// 设置部件位置到屏幕中心(使用像素坐标)
|
||||
part.setPosition(0, 0); // 800x600 窗口的中心
|
||||
|
||||
System.out.println("Model created:");
|
||||
System.out.println(" - Part count: " + model.getParts().size());
|
||||
System.out.println(" - Mesh count: " + model.getMeshes().size());
|
||||
System.out.println(" - Mesh dimensions: " + width + "x" + height);
|
||||
System.out.println(" - Part position: " + part.getPosition());
|
||||
System.out.println(" - Mesh vertex count: " + mesh.getVertexCount());
|
||||
// 测试模型保存
|
||||
model.saveToFile("C:\\Users\\Administrator\\Desktop\\trump_texture.model");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to create test model: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
createFallbackModel();
|
||||
}
|
||||
}
|
||||
|
||||
private void createFallbackModel() {
|
||||
System.out.println("Creating fallback checkerboard model...");
|
||||
|
||||
// 使用与工作示例相同的模式
|
||||
float width = 200;
|
||||
float height = 200;
|
||||
|
||||
Mesh2D mesh;
|
||||
try {
|
||||
mesh = Mesh2D.createQuad("fallback_mesh", width, height);
|
||||
} catch (Exception e) {
|
||||
// 手动创建
|
||||
float[] vertices = {
|
||||
-width/2, -height/2,
|
||||
width/2, -height/2,
|
||||
width/2, height/2,
|
||||
-width/2, height/2
|
||||
};
|
||||
|
||||
float[] uvs = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f
|
||||
};
|
||||
|
||||
int[] indices = {
|
||||
0, 1, 2,
|
||||
2, 3, 0
|
||||
};
|
||||
|
||||
mesh = model.createMesh("fallback_mesh", vertices, uvs, indices);
|
||||
}
|
||||
|
||||
// Create checkerboard texture
|
||||
Texture fallbackTexture = Texture.createCheckerboard(
|
||||
"fallback_texture",
|
||||
512, 512, 32,
|
||||
0xFFFF0000, // red
|
||||
0xFF0000FF // blue
|
||||
);
|
||||
model.addTexture(fallbackTexture);
|
||||
mesh.setTexture(fallbackTexture);
|
||||
|
||||
ModelPart part = model.createPart("fallback_part");
|
||||
part.addMesh(mesh);
|
||||
part.setVisible(true);
|
||||
part.setPosition(400, 300);
|
||||
|
||||
System.out.println("Fallback model created with size: " + width + "x" + height);
|
||||
}
|
||||
|
||||
private void recreateModel() {
|
||||
System.out.println("Recreating model...");
|
||||
createTestModel();
|
||||
}
|
||||
|
||||
private void loop() {
|
||||
// Set clear color (light gray for better visibility)
|
||||
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
|
||||
|
||||
double lastTime = glfwGetTime();
|
||||
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
double currentTime = glfwGetTime();
|
||||
float deltaTime = (float) (currentTime - lastTime);
|
||||
lastTime = currentTime;
|
||||
|
||||
// Calculate FPS
|
||||
frameCount++;
|
||||
if (currentTime - lastFpsTime >= 1.0) {
|
||||
System.out.printf("FPS: %d, Delta: %.3fms\n", frameCount, deltaTime * 1000);
|
||||
frameCount = 0;
|
||||
lastFpsTime = currentTime;
|
||||
}
|
||||
|
||||
// Render
|
||||
render(deltaTime);
|
||||
|
||||
// Swap buffers and poll events
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private void render(float deltaTime) {
|
||||
// Clear screen
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Set wireframe mode if enabled
|
||||
if (enableWireframe) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
} else {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
// Print debug info occasionally
|
||||
if (frameCount % 120 == 0) {
|
||||
System.out.println("=== RENDER DEBUG ===");
|
||||
System.out.println("Model null: " + (model == null));
|
||||
if (model != null) {
|
||||
System.out.println("Parts: " + model.getParts().size());
|
||||
System.out.println("Meshes: " + model.getMeshes().size());
|
||||
if (!model.getParts().isEmpty()) {
|
||||
ModelPart part = model.getParts().get(0);
|
||||
System.out.println("First part visible: " + part.isVisible());
|
||||
System.out.println("First part position: " + part.getPosition());
|
||||
System.out.println("First part meshes: " + part.getMeshes().size());
|
||||
}
|
||||
}
|
||||
System.out.println("===================");
|
||||
}
|
||||
|
||||
// Render using ModelRender
|
||||
try {
|
||||
ModelRender.render(deltaTime, model);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Rendering error: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Check OpenGL errors
|
||||
int error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
System.err.println("OpenGL error: " + getGLErrorString(error));
|
||||
}
|
||||
}
|
||||
|
||||
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) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
System.out.println("Cleaning up resources...");
|
||||
|
||||
// Cleanup ModelRender
|
||||
ModelRender.cleanup();
|
||||
|
||||
// Cleanup texture cache
|
||||
Texture.cleanupAll();
|
||||
|
||||
// Destroy window and terminate GLFW
|
||||
if (window != MemoryUtil.NULL) {
|
||||
glfwDestroyWindow(window);
|
||||
}
|
||||
glfwTerminate();
|
||||
|
||||
System.out.println("Cleanup completed");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user