2025-10-17 18:16:24 +08:00
|
|
|
|
package com.chuangzhou.vivid2D.test;
|
|
|
|
|
|
|
|
|
|
|
|
import com.chuangzhou.vivid2D.render.awt.ModelClickListener;
|
|
|
|
|
|
import com.chuangzhou.vivid2D.render.awt.ModelLayerPanel;
|
|
|
|
|
|
import com.chuangzhou.vivid2D.render.awt.ModelRenderPanel;
|
2025-10-18 15:27:04 +08:00
|
|
|
|
import com.chuangzhou.vivid2D.render.awt.TransformPanel;
|
2025-10-17 18:16:24 +08:00
|
|
|
|
import com.chuangzhou.vivid2D.render.model.Model2D;
|
|
|
|
|
|
import com.chuangzhou.vivid2D.render.model.ModelPart;
|
|
|
|
|
|
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
|
|
|
|
|
|
|
|
|
|
|
|
import javax.swing.*;
|
|
|
|
|
|
import java.awt.*;
|
2025-10-19 18:48:12 +08:00
|
|
|
|
import java.io.PrintStream;
|
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
|
import java.util.List;
|
2025-10-17 18:16:24 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 简单的测试示例:创建一个 Model2D,添加几层(部件),
|
|
|
|
|
|
* 然后在 JFrame 中展示 ModelLayerPanel(左侧)、ModelRenderPanel(中间渲染区)
|
|
|
|
|
|
* 和模型树(右侧)以便观察变化。
|
|
|
|
|
|
*/
|
|
|
|
|
|
public class ModelLayerPanelTest {
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
SwingUtilities.invokeLater(() -> {
|
2025-10-19 18:48:12 +08:00
|
|
|
|
System.setOut(new PrintStream(System.out, true, StandardCharsets.UTF_8));
|
|
|
|
|
|
System.setErr(new PrintStream(System.err, true, StandardCharsets.UTF_8));
|
2025-10-17 18:16:24 +08:00
|
|
|
|
// 创建示例模型并添加图层
|
|
|
|
|
|
Model2D model = new Model2D("示例模型");
|
|
|
|
|
|
|
|
|
|
|
|
// 调整一些初始属性(可选)
|
|
|
|
|
|
ModelPart person = model.getPart("人物");
|
|
|
|
|
|
if (person != null) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
person.setOpacity(0.85f);
|
2025-10-25 17:11:51 +08:00
|
|
|
|
} catch (Exception ignored) {
|
|
|
|
|
|
}
|
2025-10-17 18:16:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 UI
|
2025-10-18 15:27:04 +08:00
|
|
|
|
JFrame frame = new JFrame("ModelLayerPanel 测试(含渲染面板和变换面板)");
|
2025-10-17 18:16:24 +08:00
|
|
|
|
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
|
|
|
|
|
frame.setLayout(new BorderLayout());
|
|
|
|
|
|
|
|
|
|
|
|
// 左侧:图层面板(传入 renderPanel 后可在面板中绑定贴图到 GL 上下文)
|
|
|
|
|
|
// 先创建一个占位 renderPanel,再把它传给 layerPanel(ModelRenderPanel 构造需要尺寸)
|
|
|
|
|
|
ModelRenderPanel renderPanel = new ModelRenderPanel(model, 640, 480);
|
|
|
|
|
|
ModelLayerPanel layerPanel = new ModelLayerPanel(model, renderPanel);
|
|
|
|
|
|
layerPanel.setPreferredSize(new Dimension(260, 600));
|
|
|
|
|
|
frame.add(layerPanel, BorderLayout.WEST);
|
|
|
|
|
|
|
|
|
|
|
|
// 中间:渲染面板
|
|
|
|
|
|
renderPanel.setPreferredSize(new Dimension(640, 480));
|
|
|
|
|
|
frame.add(renderPanel, BorderLayout.CENTER);
|
|
|
|
|
|
|
2025-10-18 15:27:04 +08:00
|
|
|
|
// 创建变换面板
|
|
|
|
|
|
TransformPanel transformPanel = new TransformPanel(renderPanel);
|
|
|
|
|
|
|
|
|
|
|
|
// 右侧:创建选项卡面板,包含模型树和变换面板
|
|
|
|
|
|
JTabbedPane rightTabbedPane = new JTabbedPane();
|
|
|
|
|
|
|
|
|
|
|
|
// 模型树选项卡
|
2025-10-17 18:16:24 +08:00
|
|
|
|
JTree tree = new JTree(model.toTreeNode());
|
|
|
|
|
|
JScrollPane treeScroll = new JScrollPane(tree);
|
2025-10-18 15:27:04 +08:00
|
|
|
|
treeScroll.setPreferredSize(new Dimension(280, 600));
|
|
|
|
|
|
rightTabbedPane.addTab("模型结构", treeScroll);
|
|
|
|
|
|
|
|
|
|
|
|
// 变换面板选项卡
|
|
|
|
|
|
JScrollPane transformScroll = new JScrollPane(transformPanel);
|
|
|
|
|
|
transformScroll.setPreferredSize(new Dimension(280, 600));
|
|
|
|
|
|
rightTabbedPane.addTab("变换控制", transformScroll);
|
|
|
|
|
|
|
|
|
|
|
|
rightTabbedPane.setPreferredSize(new Dimension(300, 600));
|
|
|
|
|
|
frame.add(rightTabbedPane, BorderLayout.EAST);
|
2025-10-17 18:16:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 底部:演示按钮(刷新树以反映面板中对模型的更改)
|
|
|
|
|
|
JPanel bottom = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
|
|
|
|
|
JButton refreshBtn = new JButton("刷新模型树");
|
|
|
|
|
|
refreshBtn.addActionListener(e -> {
|
|
|
|
|
|
tree.setModel(new javax.swing.tree.DefaultTreeModel(model.toTreeNode()));
|
|
|
|
|
|
for (int i = 0; i < tree.getRowCount(); i++) tree.expandRow(i);
|
|
|
|
|
|
// 同步通知渲染面板(如果需要)去刷新模型
|
|
|
|
|
|
try {
|
|
|
|
|
|
renderPanel.setModel(model);
|
2025-10-25 17:11:51 +08:00
|
|
|
|
} catch (Exception ignored) {
|
|
|
|
|
|
}
|
2025-10-17 18:16:24 +08:00
|
|
|
|
});
|
|
|
|
|
|
bottom.add(refreshBtn);
|
|
|
|
|
|
|
|
|
|
|
|
JButton printOrderBtn = new JButton("打印部件顺序(控制台)");
|
|
|
|
|
|
printOrderBtn.addActionListener(e -> {
|
|
|
|
|
|
System.out.println("当前模型部件顺序:");
|
|
|
|
|
|
for (ModelPart p : model.getParts()) {
|
|
|
|
|
|
System.out.println(" - " + p.getName() + " (可见=" + p.isVisible() + ", 不透明度=" + p.getOpacity() + ")");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
bottom.add(printOrderBtn);
|
|
|
|
|
|
|
2025-10-18 15:27:04 +08:00
|
|
|
|
// 添加选中部件更新按钮
|
|
|
|
|
|
JButton updateSelectionBtn = new JButton("更新选中部件");
|
|
|
|
|
|
updateSelectionBtn.addActionListener(e -> {
|
|
|
|
|
|
renderPanel.executeInGLContext(() -> {
|
2025-10-19 18:48:12 +08:00
|
|
|
|
List<ModelPart> selectedPart = renderPanel.getSelectedParts();
|
|
|
|
|
|
transformPanel.setSelectedParts(selectedPart);
|
2025-10-18 15:27:04 +08:00
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
bottom.add(updateSelectionBtn);
|
|
|
|
|
|
|
2025-10-17 18:16:24 +08:00
|
|
|
|
frame.add(bottom, BorderLayout.SOUTH);
|
|
|
|
|
|
|
2025-10-18 15:27:04 +08:00
|
|
|
|
// 添加模型点击监听器,自动更新变换面板的选中部件
|
|
|
|
|
|
renderPanel.addModelClickListener(new ModelClickListener() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onModelClicked(Mesh2D mesh, float modelX, float modelY, int screenX, int screenY) {
|
|
|
|
|
|
if (mesh == null) return;
|
|
|
|
|
|
System.out.println("点击了模型:" + mesh.getName() + ",模型坐标:" + modelX + ", " + modelY + ",屏幕坐标:" + screenX + ", " + screenY);
|
|
|
|
|
|
|
|
|
|
|
|
// 自动更新变换面板的选中部件
|
2025-10-19 18:48:12 +08:00
|
|
|
|
List<ModelPart> selectedPart = renderPanel.getSelectedParts();
|
|
|
|
|
|
transformPanel.setSelectedParts(selectedPart);
|
2025-10-18 15:27:04 +08:00
|
|
|
|
|
|
|
|
|
|
// 切换到变换控制选项卡
|
|
|
|
|
|
rightTabbedPane.setSelectedIndex(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-10-17 18:16:24 +08:00
|
|
|
|
// 监听窗口关闭,确保释放 GL 资源
|
|
|
|
|
|
frame.addWindowListener(new java.awt.event.WindowAdapter() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void windowClosing(java.awt.event.WindowEvent e) {
|
|
|
|
|
|
// 先释放渲染面板相关 GL 资源与线程
|
2025-10-22 22:33:15 +08:00
|
|
|
|
//try {
|
|
|
|
|
|
// renderPanel.dispose();
|
|
|
|
|
|
//} catch (Throwable t) {
|
|
|
|
|
|
// t.printStackTrace();
|
|
|
|
|
|
//}
|
2025-10-17 18:16:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void windowClosed(java.awt.event.WindowEvent e) {
|
|
|
|
|
|
// 进程退出(确保彻底关闭)
|
|
|
|
|
|
try {
|
|
|
|
|
|
renderPanel.dispose();
|
2025-10-25 17:11:51 +08:00
|
|
|
|
} catch (Throwable ignored) {
|
|
|
|
|
|
}
|
2025-10-17 18:16:24 +08:00
|
|
|
|
System.exit(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-10-18 15:27:04 +08:00
|
|
|
|
frame.setSize(1300, 700);
|
2025-10-17 18:16:24 +08:00
|
|
|
|
frame.setLocationRelativeTo(null);
|
|
|
|
|
|
frame.setVisible(true);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-10-18 15:27:04 +08:00
|
|
|
|
}
|