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 com.chuangzhou.vivid2D.render.systems.RenderSystem; 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; /** * 用于测试中心点旋转 * * @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; 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 square.setPivot(0, 0); // 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() { RenderSystem.setClearColor(0.2f, 0.2f, 0.3f, 1.0f); 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"); } }