- 引入 deformationVertex 参数控制带 VertexTag.DEFORMATION 标签的顶点- 移除对 secondaryVertex 的旧支持及相关冗余代码 - 简化插值计算逻辑并提高角度单位转换容差 - 优化顶点目标计算方法并重命名为 DeformationVertexTarget - 清理无用的反射回退和安全读取机制- 移除 liquify 工具相关的顶点渲染快捷键控制 - 删除已废弃的 LiquifyTargetPartRander 类文件 -优化导入语句并更新相关类引用路径
825 lines
34 KiB
Java
825 lines
34 KiB
Java
package com.chuangzhou.vivid2D.test;
|
|
|
|
import com.chuangzhou.vivid2D.render.model.AnimationParameter;
|
|
import com.chuangzhou.vivid2D.render.model.Mesh2D;
|
|
import com.chuangzhou.vivid2D.render.model.Model2D;
|
|
import com.chuangzhou.vivid2D.render.model.ModelPart;
|
|
import com.chuangzhou.vivid2D.render.model.transform.WaveDeformer;
|
|
import com.chuangzhou.vivid2D.render.model.util.*;
|
|
import org.joml.Vector2f;
|
|
import org.lwjgl.glfw.GLFW;
|
|
import org.lwjgl.glfw.GLFWErrorCallback;
|
|
import org.lwjgl.opengl.GL;
|
|
import org.lwjgl.system.MemoryUtil;
|
|
|
|
/**
|
|
* 用于测试Model2D模型的保存和加载功能
|
|
*
|
|
* @author tzdwindows 7
|
|
*/
|
|
public class ModelTest {
|
|
|
|
private static long window;
|
|
private static boolean glInitialized = false;
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println("=== Model2D Extended Save and Load Test Start ===");
|
|
|
|
try {
|
|
// Initialize OpenGL context for texture testing
|
|
initializeOpenGL();
|
|
|
|
// Test 1: Create model and save (with texture)
|
|
testCreateAndSaveModelWithTexture();
|
|
|
|
// Test 2: Load model and verify data including textures
|
|
testLoadAndVerifyModelWithTexture();
|
|
|
|
// Test 3: Test compressed file operations with textures
|
|
testCompressedFileOperationsWithTexture();
|
|
|
|
//testModelSaveLoadIntegrity(model, "test_model.vmdl")
|
|
|
|
// Other existing tests...
|
|
//testAnimationSystem();
|
|
//testPhysicsSystem();
|
|
//testComplexTransformations();
|
|
//testPerformance();
|
|
//Model2D model = createTestModel();
|
|
//printModelState(model);
|
|
} finally {
|
|
// Cleanup OpenGL
|
|
cleanupOpenGL();
|
|
}
|
|
|
|
System.out.println("=== Model2D Extended Save and Load Test Complete ===");
|
|
}
|
|
|
|
public static Model2D createTestModel() {
|
|
Model2D model = new Model2D("full_test_model");
|
|
model.setVersion("1.0.0");
|
|
|
|
// ==================== 创建部件层级 ====================
|
|
ModelPart root = model.createPart("root");
|
|
ModelPart body = model.createPart("body");
|
|
ModelPart head = model.createPart("head");
|
|
ModelPart leftArm = model.createPart("left_arm");
|
|
ModelPart rightArm = model.createPart("right_arm");
|
|
|
|
root.addChild(body);
|
|
body.addChild(head);
|
|
body.addChild(leftArm);
|
|
body.addChild(rightArm);
|
|
|
|
// ==================== 设置本地变换 ====================
|
|
root.setPosition(0, 0);
|
|
root.setRotation(0f);
|
|
root.setScale(1f, 1f);
|
|
|
|
body.setPosition(0, -50);
|
|
body.setRotation(10f); // body稍微旋转
|
|
body.setScale(1.1f, 1.0f);
|
|
|
|
head.setPosition(0, -50);
|
|
head.setRotation(-5f);
|
|
head.setScale(1.0f, 1.0f);
|
|
|
|
leftArm.setPosition(-30, -20);
|
|
leftArm.setRotation(20f);
|
|
leftArm.setScale(1.0f, 0.9f);
|
|
|
|
rightArm.setPosition(30, -20);
|
|
rightArm.setRotation(-20f);
|
|
rightArm.setScale(1.0f, 0.9f);
|
|
|
|
// ==================== 添加网格 ====================
|
|
Mesh2D bodyMesh = Mesh2D.createQuad("body_mesh", 40, 80);
|
|
Mesh2D headMesh = Mesh2D.createQuad("head_mesh", 50, 50);
|
|
Mesh2D leftArmMesh = Mesh2D.createQuad("left_arm_mesh", 15, 50);
|
|
Mesh2D rightArmMesh = Mesh2D.createQuad("right_arm_mesh", 15, 50);
|
|
|
|
model.addMesh(bodyMesh);
|
|
model.addMesh(headMesh);
|
|
model.addMesh(leftArmMesh);
|
|
model.addMesh(rightArmMesh);
|
|
|
|
body.addMesh(bodyMesh);
|
|
head.addMesh(headMesh);
|
|
leftArm.addMesh(leftArmMesh);
|
|
rightArm.addMesh(rightArmMesh);
|
|
|
|
// ==================== 添加纹理 ====================
|
|
Texture bodyTex = Texture.createSolidColor("body_tex", 64, 64, 0xFFFF0000);
|
|
Texture headTex = Texture.createSolidColor("head_tex", 64, 64, 0xFF00FF00);
|
|
Texture armTex = Texture.createSolidColor("arm_tex", 32, 64, 0xFF0000FF);
|
|
|
|
bodyTex.ensurePixelDataCached();
|
|
headTex.ensurePixelDataCached();
|
|
armTex.ensurePixelDataCached();
|
|
|
|
model.addTexture(bodyTex);
|
|
model.addTexture(headTex);
|
|
model.addTexture(armTex);
|
|
|
|
bodyMesh.setTexture(bodyTex);
|
|
headMesh.setTexture(headTex);
|
|
leftArmMesh.setTexture(armTex);
|
|
rightArmMesh.setTexture(armTex);
|
|
|
|
// ==================== 添加动画参数 ====================
|
|
AnimationParameter smileParam = model.createParameter("smile", 0, 1, 0.5f);
|
|
AnimationParameter walkParam = model.createParameter("walk", 0, 1, 0);
|
|
AnimationParameter waveParam = model.createParameter("wave", 0, 1, 0);
|
|
|
|
// ==================== 添加 Deformer ====================
|
|
root.addDeformer(new WaveDeformer("blink"));
|
|
root.addDeformer(new WaveDeformer("wave"));
|
|
root.addDeformer(new WaveDeformer("blink"));
|
|
|
|
// ==================== 设置元数据 ====================
|
|
model.getMetadata().setAuthor("Test Author");
|
|
model.getMetadata().setDescription("This is a full-featured test model with transforms and deformers.");
|
|
model.getMetadata().setLicense("MIT");
|
|
model.getMetadata().setFileFormatVersion("1.0.0");
|
|
model.getMetadata().setUnitsPerMeter(100.0f);
|
|
model.getMetadata().setProperty("custom_prop1", "value1");
|
|
|
|
// ==================== 添加物理 ====================
|
|
PhysicsSystem physics = model.getPhysics();
|
|
if (physics != null) {
|
|
physics.initialize();
|
|
PhysicsSystem.PhysicsParticle p1 = physics.addParticle("p1", new Vector2f(0, 0), 1f);
|
|
PhysicsSystem.PhysicsParticle p2 = physics.addParticle("p2", new Vector2f(10, 0), 1f);
|
|
physics.addSpring("spring1", p1, p2, 10f, 0.5f, 0.1f);
|
|
}
|
|
|
|
return model;
|
|
}
|
|
|
|
|
|
public static void testModelSaveLoadIntegrity(Model2D model, String filePath) {
|
|
System.out.println("\n--- Test: Model Save and Load Integrity ---");
|
|
try {
|
|
// 保存模型
|
|
model.saveToFile(filePath);
|
|
|
|
// 加载模型
|
|
Model2D loaded = Model2D.loadFromFile(filePath);
|
|
|
|
boolean integrityOk = true;
|
|
|
|
// ==================== 基本属性 ====================
|
|
if (!model.getName().equals(loaded.getName())) {
|
|
System.out.println("Name mismatch!");
|
|
integrityOk = false;
|
|
}
|
|
if (!model.getVersion().equals(loaded.getVersion())) {
|
|
System.out.println("Version mismatch!");
|
|
integrityOk = false;
|
|
}
|
|
|
|
// ==================== 部件 ====================
|
|
if (model.getParts().size() != loaded.getParts().size()) {
|
|
System.out.println("Parts count mismatch!");
|
|
integrityOk = false;
|
|
} else {
|
|
for (int i = 0; i < model.getParts().size(); i++) {
|
|
ModelPart orig = model.getParts().get(i);
|
|
ModelPart loadPart = loaded.getParts().get(i);
|
|
if (!orig.getName().equals(loadPart.getName())) {
|
|
System.out.println("Part name mismatch: " + orig.getName());
|
|
integrityOk = false;
|
|
}
|
|
// 检查变换
|
|
if (!orig.getPosition().equals(loadPart.getPosition()) ||
|
|
orig.getRotation() != loadPart.getRotation() ||
|
|
!orig.getScale().equals(loadPart.getScale())) {
|
|
System.out.println("Part transform mismatch: " + orig.getName());
|
|
integrityOk = false;
|
|
}
|
|
// 检查Deformer
|
|
if (orig.getDeformers().size() != loadPart.getDeformers().size()) {
|
|
System.out.println("Deformer count mismatch on part: " + orig.getName());
|
|
integrityOk = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ==================== 网格 ====================
|
|
if (model.getMeshes().size() != loaded.getMeshes().size()) {
|
|
System.out.println("Meshes count mismatch!");
|
|
integrityOk = false;
|
|
}
|
|
|
|
// ==================== 纹理 ====================
|
|
if (model.getTextures().size() != loaded.getTextures().size()) {
|
|
System.out.println("Textures count mismatch!");
|
|
integrityOk = false;
|
|
}
|
|
|
|
// ==================== 参数 ====================
|
|
if (model.getParameters().size() != loaded.getParameters().size()) {
|
|
System.out.println("Parameters count mismatch!");
|
|
integrityOk = false;
|
|
} else {
|
|
for (String key : model.getParameters().keySet()) {
|
|
AnimationParameter origParam = model.getParameters().get(key);
|
|
AnimationParameter loadParam = loaded.getParameters().get(key);
|
|
if (origParam.getValue() != loadParam.getValue()) {
|
|
System.out.println("Parameter value mismatch: " + key);
|
|
integrityOk = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ==================== 物理 ====================
|
|
PhysicsSystem origPhysics = model.getPhysics();
|
|
PhysicsSystem loadPhysics = loaded.getPhysics();
|
|
if ((origPhysics != null && loadPhysics == null) || (origPhysics == null && loadPhysics != null)) {
|
|
System.out.println("Physics system missing after load!");
|
|
integrityOk = false;
|
|
} else if (origPhysics != null) {
|
|
if (origPhysics.getParticles().size() != loadPhysics.getParticles().size()) {
|
|
System.out.println("Physics particle count mismatch!");
|
|
integrityOk = false;
|
|
}
|
|
if (origPhysics.getSprings().size() != loadPhysics.getSprings().size()) {
|
|
System.out.println("Physics spring count mismatch!");
|
|
integrityOk = false;
|
|
}
|
|
}
|
|
|
|
System.out.println("Integrity test " + (integrityOk ? "PASSED" : "FAILED"));
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testModelSaveLoadIntegrity: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
|
|
private static void printModelState(Model2D model) {
|
|
System.out.println(" - Name: " + model.getName());
|
|
System.out.println(" - Version: " + model.getVersion());
|
|
System.out.println(" - Parts: " + model.getParts().size());
|
|
for (ModelPart part : model.getParts()) {
|
|
printPartHierarchy(part, 1);
|
|
}
|
|
System.out.println(" - Parameters:");
|
|
for (AnimationParameter param : model.getParameters().values()) {
|
|
System.out.println(" * " + param.getId() + " = " + param.getValue());
|
|
}
|
|
System.out.println(" - Textures:");
|
|
model.getTextures().forEach((k, tex) -> {
|
|
System.out.println(" * " + tex.getName() + " (" + tex.getWidth() + "x" + tex.getHeight() + ")");
|
|
});
|
|
System.out.println(" - User Properties:");
|
|
model.getMetadata().getUserProperties().forEach((k, v) ->
|
|
System.out.println(" * " + k + ": " + v)
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Initialize OpenGL context for texture testing
|
|
*/
|
|
private static void initializeOpenGL() {
|
|
try {
|
|
// Setup error callback
|
|
GLFWErrorCallback.createPrint(System.err).set();
|
|
|
|
// Initialize GLFW
|
|
if (!GLFW.glfwInit()) {
|
|
throw new IllegalStateException("Unable to initialize GLFW");
|
|
}
|
|
|
|
// Configure GLFW
|
|
GLFW.glfwDefaultWindowHints();
|
|
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE); // Hide window
|
|
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_FALSE);
|
|
|
|
// Create window
|
|
window = GLFW.glfwCreateWindow(100, 100, "Texture Test", MemoryUtil.NULL, MemoryUtil.NULL);
|
|
if (window == MemoryUtil.NULL) {
|
|
throw new RuntimeException("Failed to create GLFW window");
|
|
}
|
|
|
|
// Make OpenGL context current
|
|
GLFW.glfwMakeContextCurrent(window);
|
|
GLFW.glfwSwapInterval(1); // Enable v-sync
|
|
|
|
// Initialize OpenGL capabilities
|
|
GL.createCapabilities();
|
|
|
|
System.out.println("OpenGL initialized successfully");
|
|
System.out.println("OpenGL Version: " + org.lwjgl.opengl.GL11.glGetString(org.lwjgl.opengl.GL11.GL_VERSION));
|
|
glInitialized = true;
|
|
} catch (Exception e) {
|
|
System.err.println("Failed to initialize OpenGL: " + e.getMessage());
|
|
// Continue without OpenGL for other tests
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cleanup OpenGL resources
|
|
*/
|
|
private static void cleanupOpenGL() {
|
|
if (window != MemoryUtil.NULL) {
|
|
GLFW.glfwDestroyWindow(window);
|
|
}
|
|
GLFW.glfwTerminate();
|
|
GLFW.glfwSetErrorCallback(null).free();
|
|
}
|
|
|
|
/**
|
|
* Test 1: Create model with textures and save to file
|
|
*/
|
|
public static void testCreateAndSaveModelWithTexture() {
|
|
System.out.println("\n--- Test 1: Create and Save Model with Textures ---");
|
|
|
|
if (!glInitialized) {
|
|
System.out.println("Skipping texture test - OpenGL not available");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Create model
|
|
Model2D model = new Model2D("textured_character");
|
|
model.setVersion("1.0.0");
|
|
|
|
// Create parts
|
|
ModelPart body = model.createPart("body");
|
|
ModelPart head = model.createPart("head");
|
|
|
|
// Build hierarchy
|
|
body.addChild(head);
|
|
|
|
// Set part properties
|
|
body.setPosition(0, 0);
|
|
head.setPosition(0, -50);
|
|
|
|
// Create test textures
|
|
System.out.println("Creating test textures...");
|
|
|
|
// Create solid color texture
|
|
Texture bodyTexture = Texture.createSolidColor("body_texture", 64, 64, 0xFFFF0000); // Red
|
|
Texture headTexture = Texture.createSolidColor("head_texture", 64, 64, 0xFF00FF00); // Green
|
|
|
|
// Create checkerboard texture
|
|
Texture checkerTexture = Texture.createCheckerboard("checker_texture", 128, 128, 16,
|
|
0xFFFFFFFF, 0xFF0000FF); // White and Blue
|
|
|
|
// === 关键修复:确保纹理数据被缓存 ===
|
|
System.out.println("Ensuring texture data is cached...");
|
|
bodyTexture.ensurePixelDataCached();
|
|
headTexture.ensurePixelDataCached();
|
|
checkerTexture.ensurePixelDataCached();
|
|
|
|
// 验证缓存状态
|
|
System.out.println("Texture cache status:");
|
|
System.out.println(" - body_texture: " + (bodyTexture.hasPixelData() ? "CACHED" : "MISSING"));
|
|
System.out.println(" - head_texture: " + (headTexture.hasPixelData() ? "CACHED" : "MISSING"));
|
|
System.out.println(" - checker_texture: " + (checkerTexture.hasPixelData() ? "CACHED" : "MISSING"));
|
|
|
|
// Add textures to model
|
|
model.addTexture(bodyTexture);
|
|
model.addTexture(headTexture);
|
|
model.addTexture(checkerTexture);
|
|
|
|
// Create meshes and assign textures
|
|
Mesh2D bodyMesh = Mesh2D.createQuad("body_mesh", 40, 80);
|
|
Mesh2D headMesh = Mesh2D.createQuad("head_mesh", 50, 50);
|
|
|
|
// Set textures for meshes
|
|
bodyMesh.setTexture(bodyTexture);
|
|
headMesh.setTexture(headTexture);
|
|
|
|
// Add meshes to model and parts
|
|
model.addMesh(bodyMesh);
|
|
model.addMesh(headMesh);
|
|
body.addMesh(bodyMesh);
|
|
head.addMesh(headMesh);
|
|
|
|
// Create animation parameters
|
|
AnimationParameter smileParam = model.createParameter("smile", 0, 1, 0);
|
|
model.setParameterValue("smile", 0.5f);
|
|
|
|
// Update model
|
|
model.update(0.016f);
|
|
|
|
// Save to regular file
|
|
String regularFilePath = "textured_character.model";
|
|
model.saveToFile(regularFilePath);
|
|
System.out.println("Textured model saved to regular file: " + regularFilePath);
|
|
|
|
// Save to compressed file
|
|
String compressedFilePath = "textured_character.model.gz";
|
|
model.saveToCompressedFile(compressedFilePath);
|
|
System.out.println("Textured model saved to compressed file: " + compressedFilePath);
|
|
|
|
// Verify model state before saving
|
|
System.out.println("Textured model created successfully:");
|
|
System.out.println(" - Name: " + model.getName());
|
|
System.out.println(" - Textures: " + model.getTextures().size());
|
|
System.out.println(" - Meshes: " + model.getMeshes().size());
|
|
|
|
// Print texture information
|
|
for (Texture texture : model.getTextures().values()) {
|
|
System.out.println(" - Texture: " + texture.getName() +
|
|
" (" + texture.getWidth() + "x" + texture.getHeight() +
|
|
", format: " + texture.getFormat() +
|
|
", cached: " + texture.hasPixelData() + ")");
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testCreateAndSaveModelWithTexture: " + e.getMessage());
|
|
e.printStackTrace();
|
|
|
|
// 提供更详细的错误信息
|
|
if (e.getCause() != null) {
|
|
System.err.println("Caused by: " + e.getCause().getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test 2: Load model with textures and verify data integrity
|
|
*/
|
|
public static void testLoadAndVerifyModelWithTexture() {
|
|
System.out.println("\n--- Test 2: Load and Verify Model with Textures ---");
|
|
|
|
if (!glInitialized) {
|
|
System.out.println("Skipping texture test - OpenGL not available");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Load from regular file
|
|
String filePath = "textured_character.model";
|
|
Model2D loadedModel = Model2D.loadFromFile(filePath);
|
|
|
|
System.out.println("Textured model loaded successfully from: " + filePath);
|
|
|
|
// Verify basic properties
|
|
System.out.println("Basic properties:");
|
|
System.out.println(" - Name: " + loadedModel.getName());
|
|
System.out.println(" - Version: " + loadedModel.getVersion());
|
|
|
|
// Verify textures
|
|
System.out.println("Textures verification:");
|
|
System.out.println(" - Total textures: " + loadedModel.getTextures().size());
|
|
|
|
for (Texture texture : loadedModel.getTextures().values()) {
|
|
System.out.println(" - Texture '" + texture.getName() + "': " +
|
|
texture.getWidth() + "x" + texture.getHeight() +
|
|
", format: " + texture.getFormat() +
|
|
", disposed: " + texture.isDisposed());
|
|
}
|
|
|
|
// Verify parts and meshes
|
|
System.out.println("Parts and meshes verification:");
|
|
for (ModelPart part : loadedModel.getParts()) {
|
|
System.out.println(" - Part '" + part.getName() + "': " +
|
|
part.getMeshes().size() + " meshes");
|
|
|
|
for (Mesh2D mesh : part.getMeshes()) {
|
|
Texture meshTexture = mesh.getTexture();
|
|
System.out.println(" * Mesh '" + mesh.getName() + "': " +
|
|
(meshTexture != null ? "has texture '" + meshTexture.getName() + "'" : "no texture"));
|
|
}
|
|
}
|
|
|
|
// Test texture functionality
|
|
System.out.println("Texture functionality test:");
|
|
Texture bodyTexture = loadedModel.getTexture("body_texture");
|
|
if (bodyTexture != null) {
|
|
System.out.println(" - Body texture validation:");
|
|
System.out.println(" * Width: " + bodyTexture.getWidth());
|
|
System.out.println(" * Height: " + bodyTexture.getHeight());
|
|
System.out.println(" * Format: " + bodyTexture.getFormat());
|
|
System.out.println(" * Memory usage: " + bodyTexture.getEstimatedMemoryUsage() + " bytes");
|
|
|
|
// Test texture binding (if OpenGL context is available)
|
|
try {
|
|
bodyTexture.bind(0);
|
|
System.out.println(" * Texture binding: SUCCESS");
|
|
bodyTexture.unbind();
|
|
} catch (Exception e) {
|
|
System.out.println(" * Texture binding: FAILED - " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
// Test parameter modification
|
|
System.out.println("Parameter modification test:");
|
|
loadedModel.setParameterValue("smile", 0.8f);
|
|
float newSmileValue = loadedModel.getParameterValue("smile");
|
|
System.out.println(" - Modified smile parameter to: " + newSmileValue);
|
|
|
|
// Test model update
|
|
loadedModel.update(0.016f);
|
|
System.out.println(" - Model update completed successfully");
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testLoadAndVerifyModelWithTexture: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test 3: Test compressed file operations with textures
|
|
*/
|
|
public static void testCompressedFileOperationsWithTexture() {
|
|
System.out.println("\n--- Test 3: Compressed File Operations with Textures ---");
|
|
|
|
if (!glInitialized) {
|
|
System.out.println("Skipping texture test - OpenGL not available");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Load from compressed file
|
|
String compressedFilePath = "textured_character.model.gz";
|
|
Model2D compressedModel = Model2D.loadFromCompressedFile(compressedFilePath);
|
|
|
|
System.out.println("Textured model loaded successfully from compressed file: " + compressedFilePath);
|
|
System.out.println(" - Name: " + compressedModel.getName());
|
|
System.out.println(" - Textures: " + compressedModel.getTextures().size());
|
|
System.out.println(" - Parts: " + compressedModel.getParts().size());
|
|
|
|
// Verify textures in compressed model
|
|
System.out.println("Compressed model texture verification:");
|
|
for (Texture texture : compressedModel.getTextures().values()) {
|
|
System.out.println(" - Texture '" + texture.getName() + "': " +
|
|
texture.getWidth() + "x" + texture.getHeight());
|
|
}
|
|
|
|
// Modify and re-save
|
|
compressedModel.setName("modified_textured_character");
|
|
compressedModel.setParameterValue("smile", 0.9f);
|
|
|
|
String newCompressedPath = "modified_textured_character.model.gz";
|
|
compressedModel.saveToCompressedFile(newCompressedPath);
|
|
System.out.println("Modified textured model saved to new compressed file: " + newCompressedPath);
|
|
|
|
// Verify the new compressed file can be loaded
|
|
Model2D reloadedModel = Model2D.loadFromCompressedFile(newCompressedPath);
|
|
System.out.println("Reloaded modified textured model verification:");
|
|
System.out.println(" - Name: " + reloadedModel.getName());
|
|
System.out.println(" - Smile parameter value: " + reloadedModel.getParameterValue("smile"));
|
|
System.out.println(" - Textures: " + reloadedModel.getTextures().size());
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testCompressedFileOperationsWithTexture: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test 4: Test animation system
|
|
*/
|
|
public static void testAnimationSystem() {
|
|
System.out.println("\n--- Test 4: Animation System Test ---");
|
|
|
|
try {
|
|
// Load model
|
|
Model2D model = Model2D.loadFromFile("test_character.model");
|
|
System.out.println("Testing animation system:");
|
|
|
|
// Test parameter-driven animation
|
|
System.out.println("Parameter-driven animation test:");
|
|
for (int frame = 0; frame < 10; frame++) {
|
|
float walkValue = (float) Math.sin(frame * 0.2f) * 0.5f + 0.5f;
|
|
float waveValue = (float) Math.sin(frame * 0.3f);
|
|
float blinkValue = frame % 20 == 0 ? 1.0f : 0.0f; // Blink every 20 frames
|
|
|
|
model.setParameterValue("walk_cycle", walkValue);
|
|
model.setParameterValue("wave", waveValue);
|
|
model.setParameterValue("blink", blinkValue);
|
|
|
|
model.update(0.016f);
|
|
|
|
System.out.println(" - Frame " + frame +
|
|
": walk=" + String.format("%.2f", walkValue) +
|
|
", wave=" + String.format("%.2f", waveValue) +
|
|
", blink=" + String.format("%.2f", blinkValue));
|
|
}
|
|
|
|
// Test pose system
|
|
System.out.println("Pose system test:");
|
|
ModelPose currentPose = model.getCurrentPose();
|
|
if (currentPose != null) {
|
|
System.out.println(" - Current pose: " + currentPose);
|
|
}
|
|
|
|
// Test animation layer blending
|
|
System.out.println("Animation layer test:");
|
|
for (AnimationLayer layer : model.getAnimationLayers()) {
|
|
System.out.println(" - Layer: " + layer.getName());
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testAnimationSystem: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test 5: Test physics system
|
|
*/
|
|
public static void testPhysicsSystem() {
|
|
System.out.println("\n--- Test 5: Physics System Test ---");
|
|
|
|
try {
|
|
// Load model
|
|
Model2D model = Model2D.loadFromFile("test_character.model");
|
|
|
|
System.out.println("Testing physics system:");
|
|
|
|
PhysicsSystem physics = model.getPhysics();
|
|
System.out.println(" - Physics system: " +
|
|
(physics != null ? "available" : "not available"));
|
|
|
|
if (physics != null) {
|
|
Vector2f gravity = physics.getGravity();
|
|
System.out.println(" - Gravity: (" + gravity.x + ", " + gravity.y + ")");
|
|
System.out.println(" - Air resistance: " + physics.getAirResistance());
|
|
System.out.println(" - Time scale: " + physics.getTimeScale());
|
|
System.out.println(" - Enabled: " + physics.isEnabled());
|
|
}
|
|
|
|
// Test physics simulation
|
|
System.out.println("Physics simulation test:");
|
|
|
|
// 初始化物理系统
|
|
physics.initialize();
|
|
|
|
// 添加一些物理粒子
|
|
PhysicsSystem.PhysicsParticle particle1 = physics.addParticle("test_particle1", new Vector2f(0, 0), 1.0f);
|
|
PhysicsSystem.PhysicsParticle particle2 = physics.addParticle("test_particle2", new Vector2f(10, 0), 1.0f);
|
|
|
|
// 添加弹簧连接
|
|
physics.addSpring("test_spring", particle1, particle2, 15.0f, 0.5f, 0.1f);
|
|
|
|
for (int step = 0; step < 15; step++) {
|
|
model.update(0.016f); // Simulate physics
|
|
|
|
if (step % 5 == 0) {
|
|
System.out.println(" - Step " + step + ": model updated with physics");
|
|
Vector2f pos1 = particle1.getPosition();
|
|
System.out.println(" Particle1 position: (" +
|
|
String.format("%.2f", pos1.x) + ", " +
|
|
String.format("%.2f", pos1.y) + ")");
|
|
}
|
|
}
|
|
|
|
// Test physics properties
|
|
System.out.println("Physics properties verification:");
|
|
System.out.println(" - Active physics: " + physics.hasActivePhysics());
|
|
System.out.println(" - Particle count: " + physics.getParticles().size());
|
|
System.out.println(" - Spring count: " + physics.getSprings().size());
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testPhysicsSystem: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test 6: Test complex transformations
|
|
*/
|
|
public static void testComplexTransformations() {
|
|
System.out.println("\n--- Test 6: Complex Transformations Test ---");
|
|
|
|
try {
|
|
// Load model
|
|
Model2D model = Model2D.loadFromFile("test_character.model");
|
|
|
|
System.out.println("Testing complex transformations:");
|
|
|
|
// Test nested transformations
|
|
ModelPart root = model.getRootPart();
|
|
if (root != null) {
|
|
Vector2f position = root.getPosition();
|
|
Vector2f scale = root.getScale();
|
|
System.out.println("Root transformation:");
|
|
System.out.println(" - Local position: (" + position.x + ", " + position.y + ")");
|
|
System.out.println(" - Rotation: " + root.getRotation() + " degrees");
|
|
System.out.println(" - Scale: (" + scale.x + ", " + scale.y + ")");
|
|
|
|
// 获取世界变换矩阵中的位置
|
|
float worldX = root.getWorldTransform().m02();
|
|
float worldY = root.getWorldTransform().m12();
|
|
System.out.println(" - World position (from matrix): (" + worldX + ", " + worldY + ")");
|
|
}
|
|
|
|
// Test transformation inheritance
|
|
System.out.println("Transformation inheritance test:");
|
|
ModelPart head = model.getPart("head");
|
|
if (head != null) {
|
|
Vector2f headPos = head.getPosition();
|
|
float headWorldX = head.getWorldTransform().m02();
|
|
float headWorldY = head.getWorldTransform().m12();
|
|
System.out.println("Head transformation (relative to body):");
|
|
System.out.println(" - Local position: (" + headPos.x + ", " + headPos.y + ")");
|
|
System.out.println(" - World position (from matrix): (" + headWorldX + ", " + headWorldY + ")");
|
|
}
|
|
|
|
// Test bounds calculation
|
|
BoundingBox bounds = model.getBounds();
|
|
if (bounds != null) {
|
|
System.out.println("Bounds calculation:");
|
|
System.out.println(" - Min: (" + bounds.getMinX() + ", " + bounds.getMinY() + ")");
|
|
System.out.println(" - Max: (" + bounds.getMaxX() + ", " + bounds.getMaxY() + ")");
|
|
System.out.println(" - Width: " + bounds.getWidth());
|
|
System.out.println(" - Height: " + bounds.getHeight());
|
|
}
|
|
|
|
// Test visibility system
|
|
System.out.println("Visibility system test:");
|
|
model.setVisible(false);
|
|
System.out.println(" - Model visible: " + model.isVisible());
|
|
model.setVisible(true);
|
|
System.out.println(" - Model visible: " + model.isVisible());
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testComplexTransformations: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test 7: Test performance with large model
|
|
*/
|
|
public static void testPerformance() {
|
|
System.out.println("\n--- Test 7: Performance Test ---");
|
|
|
|
try {
|
|
// Create a more complex model for performance testing
|
|
Model2D complexModel = new Model2D("complex_character");
|
|
|
|
// Add many parts
|
|
ModelPart root = complexModel.createPart("root");
|
|
for (int i = 0; i < 10; i++) {
|
|
ModelPart part = complexModel.createPart("part_" + i);
|
|
root.addChild(part);
|
|
part.setPosition(i * 10, i * 5);
|
|
part.setRotation(i * 5);
|
|
|
|
// Add mesh
|
|
Mesh2D mesh = Mesh2D.createQuad("mesh_" + i, 20, 20);
|
|
complexModel.addMesh(mesh);
|
|
part.addMesh(mesh);
|
|
}
|
|
|
|
// Add multiple parameters
|
|
for (int i = 0; i < 8; i++) {
|
|
complexModel.createParameter("param_" + i, 0, 1, 0);
|
|
}
|
|
|
|
System.out.println("Performance test with complex model:");
|
|
System.out.println(" - Parts: " + complexModel.getParts().size());
|
|
System.out.println(" - Parameters: " + complexModel.getParameters().size());
|
|
System.out.println(" - Meshes: " + complexModel.getMeshes().size());
|
|
|
|
// Performance test: multiple updates
|
|
long startTime = System.currentTimeMillis();
|
|
int frameCount = 100;
|
|
|
|
for (int i = 0; i < frameCount; i++) {
|
|
// Animate parameters
|
|
for (int j = 0; j < 8; j++) {
|
|
float value = (float) Math.sin(i * 0.1f + j * 0.5f) * 0.5f + 0.5f;
|
|
complexModel.setParameterValue("param_" + j, value);
|
|
}
|
|
complexModel.update(0.016f);
|
|
}
|
|
|
|
long endTime = System.currentTimeMillis();
|
|
long totalTime = endTime - startTime;
|
|
double avgTimePerFrame = (double) totalTime / frameCount;
|
|
|
|
System.out.println("Performance results:");
|
|
System.out.println(" - Total time for " + frameCount + " frames: " + totalTime + "ms");
|
|
System.out.println(" - Average time per frame: " + String.format("%.2f", avgTimePerFrame) + "ms");
|
|
System.out.println(" - Estimated FPS: " + String.format("%.1f", 1000.0 / avgTimePerFrame));
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("Error in testPerformance: " + e.getMessage());
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Utility method to print part hierarchy
|
|
*/
|
|
private static void printPartHierarchy(ModelPart part, int depth) {
|
|
String indent = " ".repeat(depth);
|
|
System.out.println(indent + "- " + part.getName() +
|
|
" (children: " + part.getChildren().size() + ")");
|
|
|
|
for (ModelPart child : part.getChildren()) {
|
|
printPartHierarchy(child, depth + 1);
|
|
}
|
|
}
|
|
} |