feat(model): 实现动画层数据序列化与纹理管理增强
- 添加 AnimationLayerData 类用于动画层的序列化支持- 增强 Model2D 的 addTexture 方法,添加空值检查和重复纹理处理 - 在 ModelData 中添加动画层序列化与反序列化逻辑 - 扩展 TextureData 结构以支持完整纹理参数和元数据- 改进纹理反序列化过程,添加错误处理和后备纹理创建- 更新模型测试用例以验证新功能和修复的问题 - 优化网格序列化逻辑,避免重复序列化相同网格- 添加日志记录支持以提高调试能力 重要 - 完全实现了模型的保存和加载(贴图待测试)
This commit is contained in:
601
src/main/java/com/chuangzhou/vivid2D/test/ModelTest.java
Normal file
601
src/main/java/com/chuangzhou/vivid2D/test/ModelTest.java
Normal file
@@ -0,0 +1,601 @@
|
||||
package com.chuangzhou.vivid2D.test;
|
||||
|
||||
import com.chuangzhou.vivid2D.render.model.Model2D;
|
||||
import com.chuangzhou.vivid2D.render.model.ModelPart;
|
||||
import com.chuangzhou.vivid2D.render.model.AnimationParameter;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
||||
import com.chuangzhou.vivid2D.render.model.util.AnimationLayer;
|
||||
import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem;
|
||||
import com.chuangzhou.vivid2D.render.model.util.ModelPose;
|
||||
import com.chuangzhou.vivid2D.render.model.util.BoundingBox;
|
||||
import com.chuangzhou.vivid2D.render.model.util.Texture;
|
||||
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();
|
||||
|
||||
// Other existing tests...
|
||||
testAnimationSystem();
|
||||
testPhysicsSystem();
|
||||
testComplexTransformations();
|
||||
testPerformance();
|
||||
|
||||
} finally {
|
||||
// Cleanup OpenGL
|
||||
cleanupOpenGL();
|
||||
}
|
||||
|
||||
System.out.println("=== Model2D Extended Save and Load Test Complete ===");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user