2025-10-08 18:45:17 +08:00
|
|
|
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;
|
2025-10-17 01:48:07 +08:00
|
|
|
import com.chuangzhou.vivid2D.render.systems.RenderSystem;
|
2025-10-08 18:45:17 +08:00
|
|
|
import org.lwjgl.glfw.GLFW;
|
|
|
|
|
import org.lwjgl.glfw.GLFWErrorCallback;
|
|
|
|
|
import org.lwjgl.glfw.GLFWVidMode;
|
|
|
|
|
import org.lwjgl.opengl.GL;
|
|
|
|
|
import org.lwjgl.system.MemoryUtil;
|
|
|
|
|
|
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 用于测试中心点旋转
|
2025-10-25 17:11:51 +08:00
|
|
|
*
|
2025-10-08 18:45:17 +08:00
|
|
|
* @author tzdwindows 7
|
|
|
|
|
*/
|
|
|
|
|
public class ModelRenderTest2 {
|
|
|
|
|
|
|
|
|
|
private static final int WINDOW_WIDTH = 800;
|
|
|
|
|
private static final int WINDOW_HEIGHT = 600;
|
|
|
|
|
private static final String WINDOW_TITLE = "Simple Pivot Test";
|
|
|
|
|
|
|
|
|
|
private long window;
|
|
|
|
|
private boolean running = true;
|
|
|
|
|
private Model2D testModel;
|
|
|
|
|
private float rotationAngle = 0f;
|
|
|
|
|
private int testCase = 0;
|
|
|
|
|
private Mesh2D squareMesh;
|
2025-10-25 17:11:51 +08:00
|
|
|
|
2025-10-08 18:45:17 +08:00
|
|
|
public static void main(String[] args) {
|
|
|
|
|
new ModelRenderTest2().run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
try {
|
|
|
|
|
init();
|
|
|
|
|
loop();
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
t.printStackTrace();
|
|
|
|
|
} finally {
|
|
|
|
|
cleanup();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void init() {
|
|
|
|
|
GLFWErrorCallback.createPrint(System.err).set();
|
|
|
|
|
|
|
|
|
|
if (!GLFW.glfwInit()) {
|
|
|
|
|
throw new IllegalStateException("Unable to initialize GLFW");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLFW.glfwDefaultWindowHints();
|
|
|
|
|
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
|
|
|
|
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE);
|
|
|
|
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
|
|
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
|
|
|
|
|
|
|
|
|
|
window = GLFW.glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, MemoryUtil.NULL, MemoryUtil.NULL);
|
|
|
|
|
if (window == MemoryUtil.NULL) throw new RuntimeException("Failed to create GLFW window");
|
|
|
|
|
|
|
|
|
|
GLFWVidMode vidMode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
|
|
|
|
|
GLFW.glfwSetWindowPos(window,
|
|
|
|
|
(vidMode.width() - WINDOW_WIDTH) / 2,
|
|
|
|
|
(vidMode.height() - WINDOW_HEIGHT) / 2);
|
|
|
|
|
|
|
|
|
|
GLFW.glfwSetKeyCallback(window, (wnd, key, scancode, action, mods) -> {
|
|
|
|
|
if (key == GLFW.GLFW_KEY_ESCAPE && action == GLFW.GLFW_RELEASE) running = false;
|
|
|
|
|
if (key == GLFW.GLFW_KEY_SPACE && action == GLFW.GLFW_RELEASE) {
|
|
|
|
|
testCase = (testCase + 1) % 3;
|
|
|
|
|
updatePivotPoint();
|
|
|
|
|
}
|
|
|
|
|
if (key == GLFW.GLFW_KEY_R && action == GLFW.GLFW_RELEASE) {
|
|
|
|
|
resetPosition();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
GLFW.glfwSetWindowSizeCallback(window, (wnd, w, h) -> ModelRender.setViewport(w, h));
|
|
|
|
|
|
|
|
|
|
GLFW.glfwMakeContextCurrent(window);
|
|
|
|
|
GLFW.glfwSwapInterval(1);
|
|
|
|
|
GLFW.glfwShowWindow(window);
|
|
|
|
|
|
|
|
|
|
GL.createCapabilities();
|
|
|
|
|
|
|
|
|
|
createSimpleTestModel();
|
|
|
|
|
ModelRender.initialize();
|
|
|
|
|
|
|
|
|
|
System.out.println("Simple pivot test initialized");
|
|
|
|
|
System.out.println("Controls: ESC = exit | SPACE = change pivot | R = reset position");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a single square mesh with vertices centered at origin
|
|
|
|
|
*/
|
|
|
|
|
private void createSimpleTestModel() {
|
|
|
|
|
testModel = new Model2D("SimpleTest");
|
|
|
|
|
|
|
|
|
|
ModelPart square = testModel.createPart("square");
|
|
|
|
|
square.setPosition(0, 0); // center of window
|
2025-10-25 17:11:51 +08:00
|
|
|
square.setPivot(0, 0);
|
2025-10-08 18:45:17 +08:00
|
|
|
// Create 80x80 quad centered at origin
|
|
|
|
|
squareMesh = Mesh2D.createQuad("square_mesh", 80, 80);
|
|
|
|
|
// Shift vertices so center is at (0,0)
|
|
|
|
|
//for (int i = 0; i < squareMesh.getVertexCount(); i++) {
|
|
|
|
|
// Vector2f v = squareMesh.getVertex(i);
|
|
|
|
|
// v.sub(0, 0);
|
|
|
|
|
// squareMesh.setVertex(i, v.x, v.y);
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
squareMesh.setTexture(createDiagnosticTexture());
|
|
|
|
|
square.addMesh(squareMesh); // do NOT bake to world coordinates
|
|
|
|
|
|
|
|
|
|
System.out.println("Simple test model created with one part only");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a diagnostic texture to see pivot visually
|
|
|
|
|
*/
|
|
|
|
|
private Texture createDiagnosticTexture() {
|
|
|
|
|
int width = 80, height = 80;
|
|
|
|
|
ByteBuffer buf = MemoryUtil.memAlloc(width * height * 4);
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
|
|
|
// center cross
|
|
|
|
|
if (x == width / 2 || y == height / 2) {
|
|
|
|
|
buf.put((byte) 255).put((byte) 255).put((byte) 255).put((byte) 255);
|
|
|
|
|
} else if (x < width / 2 && y < height / 2) {
|
|
|
|
|
buf.put((byte) 255).put((byte) 0).put((byte) 0).put((byte) 255); // top-left red
|
|
|
|
|
} else if (x >= width / 2 && y < height / 2) {
|
|
|
|
|
buf.put((byte) 0).put((byte) 255).put((byte) 0).put((byte) 255); // top-right green
|
|
|
|
|
} else if (x < width / 2 && y >= height / 2) {
|
|
|
|
|
buf.put((byte) 0).put((byte) 0).put((byte) 255).put((byte) 255); // bottom-left blue
|
|
|
|
|
} else {
|
|
|
|
|
buf.put((byte) 255).put((byte) 255).put((byte) 0).put((byte) 255); // bottom-right yellow
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf.flip();
|
|
|
|
|
Texture texture = new Texture("diagnostic", width, height, Texture.TextureFormat.RGBA, buf);
|
|
|
|
|
MemoryUtil.memFree(buf);
|
|
|
|
|
return texture;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void updatePivotPoint() {
|
|
|
|
|
ModelPart square = testModel.getPart("square");
|
|
|
|
|
if (square != null) {
|
|
|
|
|
switch (testCase) {
|
|
|
|
|
case 0:
|
|
|
|
|
square.setPivot(0, 0);
|
|
|
|
|
System.out.println("Pivot: center (0,0) - should rotate around center");
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
square.setPivot(-40, 40); // top-left corner
|
|
|
|
|
System.out.println("Pivot: top-left (-40,40) - should rotate around top-left");
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
square.setPivot(40, -40); // bottom-right corner
|
|
|
|
|
System.out.println("Pivot: bottom-right (40,-40) - should rotate around bottom-right");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void resetPosition() {
|
|
|
|
|
ModelPart square = testModel.getPart("square");
|
|
|
|
|
if (square != null) {
|
|
|
|
|
square.setPosition(400, 300);
|
|
|
|
|
square.setRotation(0);
|
|
|
|
|
rotationAngle = 0;
|
|
|
|
|
System.out.println("Position reset");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void loop() {
|
|
|
|
|
long last = System.nanoTime();
|
|
|
|
|
double nsPerUpdate = 1_000_000_000.0 / 60.0;
|
|
|
|
|
double accumulator = 0.0;
|
|
|
|
|
|
|
|
|
|
while (running && !GLFW.glfwWindowShouldClose(window)) {
|
|
|
|
|
long now = System.nanoTime();
|
|
|
|
|
accumulator += (now - last) / nsPerUpdate;
|
|
|
|
|
last = now;
|
|
|
|
|
|
|
|
|
|
while (accumulator >= 1.0) {
|
|
|
|
|
update(1.0f / 60.0f);
|
|
|
|
|
accumulator -= 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render();
|
|
|
|
|
|
|
|
|
|
GLFW.glfwSwapBuffers(window);
|
|
|
|
|
GLFW.glfwPollEvents();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void update(float dt) {
|
|
|
|
|
rotationAngle += dt * 1.5f;
|
|
|
|
|
|
|
|
|
|
ModelPart square = testModel.getPart("square");
|
|
|
|
|
if (square != null) {
|
|
|
|
|
square.setRotation(rotationAngle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
testModel.update(dt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void render() {
|
2025-10-17 01:48:07 +08:00
|
|
|
RenderSystem.setClearColor(0.2f, 0.2f, 0.3f, 1.0f);
|
2025-10-08 18:45:17 +08:00
|
|
|
ModelRender.render(1.0f / 60.0f, testModel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void cleanup() {
|
|
|
|
|
System.out.println("Cleaning up resources...");
|
|
|
|
|
ModelRender.cleanup();
|
|
|
|
|
Texture.cleanupAll();
|
|
|
|
|
if (window != MemoryUtil.NULL) GLFW.glfwDestroyWindow(window);
|
|
|
|
|
GLFW.glfwTerminate();
|
|
|
|
|
GLFW.glfwSetErrorCallback(null).free();
|
|
|
|
|
System.out.println("Test finished");
|
|
|
|
|
}
|
|
|
|
|
}
|