ui替换
This commit is contained in:
parent
1fc3e154d1
commit
1ad2086525
File diff suppressed because it is too large
Load Diff
166
core/imgui_manager.py
Normal file
166
core/imgui_manager.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
"""
|
||||||
|
pyimgui管理器 - 在Panda3D引擎上集成ImGui界面
|
||||||
|
"""
|
||||||
|
import imgui
|
||||||
|
import OpenGL.GL as gl
|
||||||
|
from panda3d.core import RenderState, ShaderAttrib, Texture, CardMaker, NodePath
|
||||||
|
from panda3d.core import TransparencyAttrib, ColorBlendAttrib
|
||||||
|
from direct.task.Task import Task
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
class ImGuiManager:
|
||||||
|
"""ImGui管理器,负责在Panda3D引擎上渲染ImGui界面"""
|
||||||
|
|
||||||
|
def __init__(self, world):
|
||||||
|
self.world = world
|
||||||
|
self.io = None
|
||||||
|
self.font_texture = None
|
||||||
|
self._setup_imgui()
|
||||||
|
self._create_imgui_task()
|
||||||
|
|
||||||
|
# UI状态
|
||||||
|
self.show_demo_window = False
|
||||||
|
self.show_test_button = True
|
||||||
|
self.button_clicked = False
|
||||||
|
|
||||||
|
def _setup_imgui(self):
|
||||||
|
"""初始化ImGui设置"""
|
||||||
|
# 初始化ImGui上下文
|
||||||
|
imgui.create_context()
|
||||||
|
self.io = imgui.get_io()
|
||||||
|
|
||||||
|
# 设置显示大小
|
||||||
|
win_props = self.world.win.getProperties()
|
||||||
|
self.io.display_size = (win_props.get_x_size(), win_props.get_y_size())
|
||||||
|
|
||||||
|
# 设置渲染回调
|
||||||
|
self.io.render_callback = self._render_imgui
|
||||||
|
|
||||||
|
# 创建字体纹理
|
||||||
|
self._create_font_texture()
|
||||||
|
|
||||||
|
print("✓ ImGui初始化完成")
|
||||||
|
|
||||||
|
def _create_font_texture(self):
|
||||||
|
"""创建ImGui字体纹理"""
|
||||||
|
# 获取字体数据
|
||||||
|
font_pixels = self.io.fonts.get_tex_data_as_rgba32()
|
||||||
|
width, height = self.io.fonts.get_tex_data_as_rgba32()[1]
|
||||||
|
|
||||||
|
# 创建Panda3D纹理
|
||||||
|
self.font_texture = Texture()
|
||||||
|
self.font_texture.setup_2d_texture(width, height, Texture.T_unsigned_byte, Texture.F_rgba8)
|
||||||
|
self.font_texture.set_ram_image(font_pixels)
|
||||||
|
|
||||||
|
# 设置纹理ID
|
||||||
|
self.io.fonts.tex_id = self.font_texture
|
||||||
|
|
||||||
|
# 清除字体数据
|
||||||
|
self.io.fonts.clear_tex_data()
|
||||||
|
|
||||||
|
def _render_imgui(self, draw_data):
|
||||||
|
"""渲染ImGui绘制数据"""
|
||||||
|
if not draw_data:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 设置OpenGL状态
|
||||||
|
gl.glEnable(gl.GL_BLEND)
|
||||||
|
gl.glBlendEquation(gl.GL_FUNC_ADD)
|
||||||
|
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
gl.glDisable(gl.GL_CULL_FACE)
|
||||||
|
gl.glDisable(gl.GL_DEPTH_TEST)
|
||||||
|
gl.glEnable(gl.GL_SCISSOR_TEST)
|
||||||
|
|
||||||
|
# 设置视口和投影矩阵
|
||||||
|
display_w, display_h = self.io.display_size
|
||||||
|
gl.glViewport(0, 0, int(display_w), int(display_h))
|
||||||
|
|
||||||
|
# 获取投影矩阵
|
||||||
|
projection_matrix = self._get_projection_matrix()
|
||||||
|
gl.glMatrixMode(gl.GL_PROJECTION)
|
||||||
|
gl.glLoadMatrixf(projection_matrix)
|
||||||
|
|
||||||
|
# 渲染每个命令列表
|
||||||
|
for commands in draw_data.commands_lists:
|
||||||
|
# 渲染命令
|
||||||
|
self._render_commands(commands)
|
||||||
|
|
||||||
|
# 恢复OpenGL状态
|
||||||
|
gl.glDisable(gl.GL_SCISSOR_TEST)
|
||||||
|
gl.glEnable(gl.GL_DEPTH_TEST)
|
||||||
|
|
||||||
|
def _get_projection_matrix(self):
|
||||||
|
"""获取正交投影矩阵"""
|
||||||
|
L, R, T, B = 0, self.io.display_size[0], self.io.display_size[1], 0
|
||||||
|
projection_matrix = np.array([
|
||||||
|
[2.0/(R-L), 0.0, 0.0, 0.0],
|
||||||
|
[0.0, 2.0/(T-B), 0.0, 0.0],
|
||||||
|
[0.0, 0.0, -1.0, 0.0],
|
||||||
|
[(R+L)/(L-R), (T+B)/(B-T), 0.0, 1.0]
|
||||||
|
], dtype=np.float32)
|
||||||
|
return projection_matrix
|
||||||
|
|
||||||
|
def _render_commands(self, commands):
|
||||||
|
"""渲染ImGui命令列表"""
|
||||||
|
# 这里需要实现具体的渲染逻辑
|
||||||
|
# 由于Panda3D的渲染管线与ImGui不完全兼容,我们需要创建一个自定义的渲染方法
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _create_imgui_task(self):
|
||||||
|
"""创建ImGui更新任务"""
|
||||||
|
taskMgr.add(self._update_imgui, "update_imgui")
|
||||||
|
|
||||||
|
def _update_imgui(self, task):
|
||||||
|
"""更新ImGui界面"""
|
||||||
|
# 开始新帧
|
||||||
|
imgui.new_frame()
|
||||||
|
|
||||||
|
# 绘制UI
|
||||||
|
self._draw_ui()
|
||||||
|
|
||||||
|
# 渲染ImGui
|
||||||
|
imgui.render()
|
||||||
|
|
||||||
|
return Task.cont
|
||||||
|
|
||||||
|
def _draw_ui(self):
|
||||||
|
"""绘制UI元素"""
|
||||||
|
# 绘制测试按钮
|
||||||
|
if self.show_test_button:
|
||||||
|
imgui.begin("测试窗口", True)
|
||||||
|
if imgui.button("点击我!"):
|
||||||
|
self.button_clicked = True
|
||||||
|
print("按钮被点击了!")
|
||||||
|
|
||||||
|
if self.button_clicked:
|
||||||
|
imgui.text("按钮已被点击!")
|
||||||
|
|
||||||
|
imgui.end()
|
||||||
|
|
||||||
|
# 绘制演示窗口(可选)
|
||||||
|
if self.show_demo_window:
|
||||||
|
self.show_demo_window = imgui.show_demo_window(self.show_demo_window)
|
||||||
|
|
||||||
|
def toggle_demo_window(self):
|
||||||
|
"""切换演示窗口显示"""
|
||||||
|
self.show_demo_window = not self.show_demo_window
|
||||||
|
|
||||||
|
def toggle_test_button(self):
|
||||||
|
"""切换测试按钮显示"""
|
||||||
|
self.show_test_button = not self.show_test_button
|
||||||
|
|
||||||
|
def process_mouse_input(self, button_event):
|
||||||
|
"""处理鼠标输入"""
|
||||||
|
# 这里需要将Panda3D的鼠标事件转换为ImGui可以理解的事件
|
||||||
|
pass
|
||||||
|
|
||||||
|
def process_keyboard_input(self, key_event):
|
||||||
|
"""处理键盘输入"""
|
||||||
|
# 这里需要将Panda3D的键盘事件转换为ImGui可以理解的事件
|
||||||
|
pass
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
"""清理资源"""
|
||||||
|
if self.font_texture:
|
||||||
|
self.font_texture = None
|
||||||
|
imgui.destroy_context()
|
||||||
286
core/imgui_style_manager.py
Normal file
286
core/imgui_style_manager.py
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
"""
|
||||||
|
ImGui样式管理器
|
||||||
|
用于统一管理ImGui UI样式,与主程序Qt UI保持一致
|
||||||
|
"""
|
||||||
|
|
||||||
|
import imgui
|
||||||
|
from imgui_bundle import imgui_ctx
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
from pathlib import Path
|
||||||
|
from panda3d.core import Filename
|
||||||
|
|
||||||
|
|
||||||
|
class ImGuiStyleManager:
|
||||||
|
"""ImGui样式管理器 - 负责UI样式的统一管理"""
|
||||||
|
|
||||||
|
def __init__(self, imgui_backend):
|
||||||
|
"""
|
||||||
|
初始化样式管理器
|
||||||
|
|
||||||
|
Args:
|
||||||
|
imgui_backend: ImGui后端对象
|
||||||
|
"""
|
||||||
|
self.imgui_backend = imgui_backend
|
||||||
|
self.io = imgui_backend.io
|
||||||
|
self.style = None # 延迟初始化,在apply_style中设置
|
||||||
|
|
||||||
|
# 颜色定义 - 与Qt UI保持一致
|
||||||
|
self.colors = {
|
||||||
|
# 主要颜色
|
||||||
|
'primary': (0.188, 0.404, 0.753, 1.0), # #3067C0 - 主色调
|
||||||
|
'primary_dark': (0.149, 0.337, 0.627, 1.0), # #2556A0 - 按钮按下
|
||||||
|
'background': (0.0, 0.0, 0.0, 1.0), # #000000 - 主背景
|
||||||
|
'secondary_bg': (0.096, 0.096, 0.106, 1.0), # #19191B - 次背景
|
||||||
|
'panel_bg': (0.18, 0.188, 0.208, 1.0), # #2E3035 - 面板背景
|
||||||
|
'text': (0.922, 0.922, 0.922, 1.0), # #EBEBEB - 主文字
|
||||||
|
'text_secondary': (0.922, 0.922, 0.922, 0.6), # #EBEBEB - 次文字
|
||||||
|
'border': (0.243, 0.243, 0.259, 1.0), # #3E3E42 - 主要边框
|
||||||
|
'border_secondary': (0.173, 0.184, 0.212, 1.0), # #2C2F36 - 次要边框
|
||||||
|
'button_bg': (0.349, 0.384, 0.463, 0.5), # 半透明按钮背景
|
||||||
|
'input_bg': (0.349, 0.392, 0.443, 0.2), # 输入框背景
|
||||||
|
'input_border': (0.298, 0.361, 0.431, 0.6), # 输入框边框
|
||||||
|
'success': (0.176, 1.0, 0.769, 1.0), # #2dffc4 - 成功状态
|
||||||
|
'warning': (0.953, 0.616, 0.471, 1.0), # #f39d78 - 警告状态
|
||||||
|
'info': (0.157, 0.620, 1.0, 1.0), # #289eff - 信息状态
|
||||||
|
}
|
||||||
|
|
||||||
|
# 尺寸定义
|
||||||
|
self.sizes = {
|
||||||
|
'font_size': 12.0, # 与Qt一致的字体大小
|
||||||
|
'window_padding': (8.0, 8.0),
|
||||||
|
'window_rounding': 2.0,
|
||||||
|
'item_spacing': (6.0, 6.0),
|
||||||
|
'item_inner_spacing': (4.0, 4.0),
|
||||||
|
'frame_padding': (4.0, 3.0),
|
||||||
|
'frame_rounding': 2.0,
|
||||||
|
'indent_spacing': 20.0,
|
||||||
|
'scrollbar_size': 14.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
# 字体设置在demo.py中直接处理,这里不再初始化
|
||||||
|
|
||||||
|
def _setup_fonts(self):
|
||||||
|
"""设置字体,包括中文字体支持"""
|
||||||
|
try:
|
||||||
|
# 尝试加载中文字体
|
||||||
|
font_path = self._get_chinese_font_path()
|
||||||
|
if font_path:
|
||||||
|
# 使用p3dimgui的字体加载方法
|
||||||
|
self.imgui_backend.load_font(font_path, self.sizes['font_size'])
|
||||||
|
print(f"✓ ImGui中文字体加载成功: {font_path}")
|
||||||
|
else:
|
||||||
|
print("⚠ 无法加载中文字体,使用默认字体")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠ ImGui字体设置失败: {e}")
|
||||||
|
# 备用方案:尝试使用默认字体
|
||||||
|
try:
|
||||||
|
# 使用p3dimgui的默认字体
|
||||||
|
self.imgui_backend.load_font(None, self.sizes['font_size'])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _get_chinese_font_path(self):
|
||||||
|
"""获取中文字体路径"""
|
||||||
|
system = platform.system().lower()
|
||||||
|
project_root = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
# 候选字体路径
|
||||||
|
if system == "windows":
|
||||||
|
win_dir = os.environ.get("WINDIR") or r"C:\Windows"
|
||||||
|
font_candidates = [
|
||||||
|
project_root / "RenderPipelineFile" / "data" / "font" / "msyh.ttc",
|
||||||
|
Path(win_dir) / "Fonts" / "msyh.ttc",
|
||||||
|
Path(win_dir) / "Fonts" / "msyh.ttf",
|
||||||
|
Path(win_dir) / "Fonts" / "simhei.ttf",
|
||||||
|
]
|
||||||
|
elif system == "darwin":
|
||||||
|
font_candidates = [
|
||||||
|
Path("/System/Library/Fonts/PingFang.ttc"),
|
||||||
|
Path("/System/Library/Fonts/STHeiti.ttc"),
|
||||||
|
]
|
||||||
|
else: # Linux
|
||||||
|
font_candidates = [
|
||||||
|
Path("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"),
|
||||||
|
Path("/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# 尝试找到存在的字体文件
|
||||||
|
for font_path in font_candidates:
|
||||||
|
if font_path.exists():
|
||||||
|
return str(font_path)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def apply_style(self):
|
||||||
|
"""应用与Qt UI一致的样式"""
|
||||||
|
# 先应用深色主题作为基础
|
||||||
|
imgui.style_colors_dark()
|
||||||
|
|
||||||
|
# 获取样式对象
|
||||||
|
self.style = imgui.get_style()
|
||||||
|
style = self.style
|
||||||
|
|
||||||
|
# 应用自定义颜色
|
||||||
|
style.colors[imgui.COLOR_WINDOW_BG] = self.colors['background']
|
||||||
|
style.colors[imgui.COLOR_CHILD_BG] = self.colors['secondary_bg']
|
||||||
|
style.colors[imgui.COLOR_POPUP_BG] = self.colors['panel_bg']
|
||||||
|
style.colors[imgui.COLOR_BORDER] = self.colors['border']
|
||||||
|
style.colors[imgui.COLOR_BORDER_SHADOW] = self.colors['border_secondary']
|
||||||
|
|
||||||
|
# 文本颜色
|
||||||
|
style.colors[imgui.COLOR_TEXT] = self.colors['text']
|
||||||
|
style.colors[imgui.COLOR_TEXT_DISABLED] = self.colors['text_secondary']
|
||||||
|
style.colors[imgui.COLOR_TEXT_SELECTED_BG] = self.colors['primary']
|
||||||
|
|
||||||
|
# 菜单栏颜色
|
||||||
|
style.colors[imgui.COLOR_MENU_BAR_BG] = self.colors['background']
|
||||||
|
|
||||||
|
# 按钮颜色
|
||||||
|
style.colors[imgui.COLOR_BUTTON] = self.colors['button_bg']
|
||||||
|
style.colors[imgui.COLOR_BUTTON_HOVERED] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_BUTTON_ACTIVE] = self.colors['primary_dark']
|
||||||
|
|
||||||
|
# 复选框和单选按钮
|
||||||
|
style.colors[imgui.COLOR_CHECK_MARK] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_RADIO_BUTTON_HOVERED] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_RADIO_BUTTON_ACTIVE] = self.colors['primary_dark']
|
||||||
|
|
||||||
|
# 滑块
|
||||||
|
style.colors[imgui.COLOR_SLIDER_GRAB] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_SLIDER_GRAB_ACTIVE] = self.colors['primary_dark']
|
||||||
|
|
||||||
|
# 进度条
|
||||||
|
style.colors[imgui.COLOR_PROGRESS_BAR_FG] = self.colors['primary']
|
||||||
|
|
||||||
|
# 标题栏
|
||||||
|
style.colors[imgui.COLOR_TITLE_BG] = self.colors['panel_bg']
|
||||||
|
style.colors[imgui.COLOR_TITLE_BG_ACTIVE] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_TITLE_BG_COLLAPSED] = self.colors['border_secondary']
|
||||||
|
|
||||||
|
# 输入框
|
||||||
|
style.colors[imgui.COLOR_FRAME_BG] = self.colors['input_bg']
|
||||||
|
style.colors[imgui.COLOR_FRAME_BG_HOVERED] = self.colors['input_border']
|
||||||
|
style.colors[imgui.COLOR_FRAME_BG_ACTIVE] = (
|
||||||
|
self.colors['primary'][0],
|
||||||
|
self.colors['primary'][1],
|
||||||
|
self.colors['primary'][2],
|
||||||
|
0.1 # 低透明度
|
||||||
|
)
|
||||||
|
|
||||||
|
# 标签页
|
||||||
|
style.colors[imgui.COLOR_TAB] = self.colors['button_bg']
|
||||||
|
style.colors[imgui.COLOR_TAB_HOVERED] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_TAB_ACTIVE] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_TAB_UNFOCUSED] = self.colors['button_bg']
|
||||||
|
style.colors[imgui.COLOR_TAB_UNFOCUSED_ACTIVE] = self.colors['primary_dark']
|
||||||
|
|
||||||
|
# 选择高亮
|
||||||
|
style.colors[imgui.COLOR_HEADER] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_HEADER_HOVERED] = self.colors['primary']
|
||||||
|
style.colors[imgui.COLOR_HEADER_ACTIVE] = self.colors['primary_dark']
|
||||||
|
|
||||||
|
# 分隔符
|
||||||
|
style.colors[imgui.COLOR_SEPARATOR] = self.colors['border_secondary']
|
||||||
|
style.colors[imgui.COLOR_SEPARATOR_HOVERED] = self.colors['border']
|
||||||
|
style.colors[imgui.COLOR_SEPARATOR_ACTIVE] = self.colors['primary']
|
||||||
|
|
||||||
|
# 调整尺寸和间距
|
||||||
|
style.window_padding = self.sizes['window_padding']
|
||||||
|
style.window_rounding = self.sizes['window_rounding']
|
||||||
|
style.window_min_size = (200, 100)
|
||||||
|
style.child_rounding = self.sizes['frame_rounding']
|
||||||
|
style.frame_padding = self.sizes['frame_padding']
|
||||||
|
style.frame_rounding = self.sizes['frame_rounding']
|
||||||
|
style.item_spacing = self.sizes['item_spacing']
|
||||||
|
style.item_inner_spacing = self.sizes['item_inner_spacing']
|
||||||
|
style.indent_spacing = self.sizes['indent_spacing']
|
||||||
|
style.scrollbar_size = self.sizes['scrollbar_size']
|
||||||
|
style.scrollbar_rounding = self.sizes['frame_rounding']
|
||||||
|
style.grab_min_size = 10.0
|
||||||
|
style.grab_rounding = self.sizes['frame_rounding']
|
||||||
|
|
||||||
|
# 禁用一些ImGui的默认效果,使其更像Qt
|
||||||
|
style.window_border_size = 1.0
|
||||||
|
style.child_border_size = 1.0
|
||||||
|
style.popup_border_size = 1.0
|
||||||
|
style.frame_border_size = 1.0
|
||||||
|
|
||||||
|
print("✓ ImGui样式已应用,与Qt UI保持一致")
|
||||||
|
|
||||||
|
def get_window_flags(self, window_type="default"):
|
||||||
|
"""获取不同类型窗口的标志"""
|
||||||
|
base_flags = 0
|
||||||
|
|
||||||
|
if window_type == "main_menu":
|
||||||
|
return imgui.WINDOW_MENU_BAR
|
||||||
|
elif window_type == "dockable":
|
||||||
|
return (base_flags |
|
||||||
|
imgui.WINDOW_NO_TITLE_BAR |
|
||||||
|
imgui.WINDOW_NO_RESIZE |
|
||||||
|
imgui.WINDOW_NO_MOVE |
|
||||||
|
imgui.WINDOW_NO_COLLAPSE)
|
||||||
|
elif window_type == "toolbar":
|
||||||
|
return (base_flags |
|
||||||
|
imgui.WINDOW_NO_TITLE_BAR |
|
||||||
|
imgui.WINDOW_NO_RESIZE |
|
||||||
|
imgui.WINDOW_NO_MOVE |
|
||||||
|
imgui.WINDOW_NO_COLLAPSE |
|
||||||
|
imgui.WINDOW_NO_SCROLLBAR)
|
||||||
|
elif window_type == "panel":
|
||||||
|
return (base_flags |
|
||||||
|
imgui.WINDOW_NO_COLLAPSE)
|
||||||
|
|
||||||
|
return base_flags
|
||||||
|
|
||||||
|
def begin_styled_window(self, name, open=True, flags=None, window_type="default"):
|
||||||
|
"""开始一个带样式的窗口"""
|
||||||
|
if flags is None:
|
||||||
|
flags = self.get_window_flags(window_type)
|
||||||
|
|
||||||
|
return imgui_ctx.begin(name, open, flags)
|
||||||
|
|
||||||
|
def styled_button(self, label, size=(0, 0)):
|
||||||
|
"""绘制带样式的按钮"""
|
||||||
|
return imgui.button(label, size)
|
||||||
|
|
||||||
|
def styled_input_text(self, label, value, buffer_size=256):
|
||||||
|
"""绘制带样式的文本输入框"""
|
||||||
|
changed, new_value = imgui.input_text(label, value, buffer_size)
|
||||||
|
return changed, new_value
|
||||||
|
|
||||||
|
def styled_slider_float(self, label, value, min_val, max_val, format="%.3f"):
|
||||||
|
"""绘制带样式的浮点滑块"""
|
||||||
|
changed, new_value = imgui.slider_float(label, value, min_val, max_val, format)
|
||||||
|
return changed, new_value
|
||||||
|
|
||||||
|
def load_icon(self, icon_name):
|
||||||
|
"""加载图标纹理"""
|
||||||
|
try:
|
||||||
|
# 构建图标路径
|
||||||
|
project_root = Path(__file__).resolve().parent.parent
|
||||||
|
icon_path = project_root / "icons" / f"{icon_name}.png"
|
||||||
|
|
||||||
|
if icon_path.exists():
|
||||||
|
return self.imgui_backend.loadTexture(str(icon_path))
|
||||||
|
else:
|
||||||
|
print(f"⚠ 图标文件不存在: {icon_path}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠ 加载图标失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def image_button(self, texture_id, size=(32, 32), bg_col=(0, 0, 0, 0), tint_col=(1, 1, 1, 1)):
|
||||||
|
"""绘制图像按钮"""
|
||||||
|
return imgui.image_button(texture_id, size, bg_col, tint_col)
|
||||||
|
|
||||||
|
def get_icon_text_button(self, icon_texture, text, size=(0, 0)):
|
||||||
|
"""绘制带图标的文本按钮"""
|
||||||
|
if icon_texture:
|
||||||
|
# 先绘制图标
|
||||||
|
imgui.image(icon_texture, (16, 16))
|
||||||
|
imgui.same_line()
|
||||||
|
|
||||||
|
# 再绘制文本按钮
|
||||||
|
return imgui.button(text, size)
|
||||||
204
core/simple_imgui_manager.py
Normal file
204
core/simple_imgui_manager.py
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
"""
|
||||||
|
pyimgui管理器 - 在Panda3D引擎上集成ImGui界面
|
||||||
|
使用更简单的方法,通过创建覆盖层来实现
|
||||||
|
"""
|
||||||
|
import imgui
|
||||||
|
import numpy as np
|
||||||
|
from panda3d.core import RenderState, ShaderAttrib, Texture, CardMaker, NodePath
|
||||||
|
from panda3d.core import TransparencyAttrib, ColorBlendAttrib, PNMImage
|
||||||
|
from panda3d.core import GraphicsOutput, RenderBuffer, TextureStage, TexGenAttrib
|
||||||
|
from direct.task.Task import Task
|
||||||
|
from direct.gui.OnscreenImage import OnscreenImage
|
||||||
|
from direct.gui.OnscreenText import OnscreenText
|
||||||
|
import PIL.Image
|
||||||
|
import PIL.ImageDraw
|
||||||
|
import io
|
||||||
|
|
||||||
|
class SimpleImGuiManager:
|
||||||
|
"""简化的ImGui管理器,使用2D覆盖层在Panda3D引擎上显示ImGui界面"""
|
||||||
|
|
||||||
|
def __init__(self, world):
|
||||||
|
self.world = world
|
||||||
|
self.io = None
|
||||||
|
self._setup_imgui()
|
||||||
|
self._create_imgui_task()
|
||||||
|
|
||||||
|
# UI状态
|
||||||
|
self.show_demo_window = False
|
||||||
|
self.show_test_button = True
|
||||||
|
self.button_clicked = False
|
||||||
|
self.counter = 0
|
||||||
|
|
||||||
|
# 渲染相关
|
||||||
|
self.imgui_texture = None
|
||||||
|
self.imgui_image = None
|
||||||
|
self.texture_buffer = None
|
||||||
|
|
||||||
|
# 创建渲染纹理
|
||||||
|
self._create_render_texture()
|
||||||
|
|
||||||
|
def _setup_imgui(self):
|
||||||
|
"""初始化ImGui设置"""
|
||||||
|
# 初始化ImGui上下文
|
||||||
|
imgui.create_context()
|
||||||
|
self.io = imgui.get_io()
|
||||||
|
|
||||||
|
# 设置显示大小
|
||||||
|
win_props = self.world.win.getProperties()
|
||||||
|
self.io.display_size = (win_props.get_x_size(), win_props.get_y_size())
|
||||||
|
|
||||||
|
# 设置字体大小
|
||||||
|
font_size = 16
|
||||||
|
self.io.font_global_scale = font_size / 13.0
|
||||||
|
|
||||||
|
print("✓ ImGui初始化完成")
|
||||||
|
|
||||||
|
def _create_render_texture(self):
|
||||||
|
"""创建用于渲染ImGui的纹理"""
|
||||||
|
win_props = self.world.win.getProperties()
|
||||||
|
width = win_props.get_x_size()
|
||||||
|
height = win_props.get_y_size()
|
||||||
|
|
||||||
|
# 创建纹理
|
||||||
|
self.imgui_texture = Texture()
|
||||||
|
self.imgui_texture.setup_2d_texture(width, height, Texture.T_unsigned_byte, Texture.F_rgba8)
|
||||||
|
|
||||||
|
# 创建屏幕图像
|
||||||
|
self.imgui_image = OnscreenImage(
|
||||||
|
image=self.imgui_texture,
|
||||||
|
pos=(0, 0, 0),
|
||||||
|
scale=(1, 1, 1)
|
||||||
|
)
|
||||||
|
self.imgui_image.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
|
||||||
|
def _create_imgui_task(self):
|
||||||
|
"""创建ImGui更新任务"""
|
||||||
|
taskMgr.add(self._update_imgui, "update_imgui")
|
||||||
|
|
||||||
|
def _update_imgui(self, task):
|
||||||
|
"""更新ImGui界面"""
|
||||||
|
# 开始新帧
|
||||||
|
imgui.new_frame()
|
||||||
|
|
||||||
|
# 绘制UI
|
||||||
|
self._draw_ui()
|
||||||
|
|
||||||
|
# 渲染ImGui到纹理
|
||||||
|
self._render_to_texture()
|
||||||
|
|
||||||
|
return Task.cont
|
||||||
|
|
||||||
|
def _draw_ui(self):
|
||||||
|
"""绘制UI元素"""
|
||||||
|
# 绘制测试窗口
|
||||||
|
if self.show_test_button:
|
||||||
|
imgui.begin("测试窗口", True)
|
||||||
|
|
||||||
|
if imgui.button("点击我!"):
|
||||||
|
self.button_clicked = True
|
||||||
|
self.counter += 1
|
||||||
|
print(f"按钮被点击了! 计数: {self.counter}")
|
||||||
|
|
||||||
|
if self.button_clicked:
|
||||||
|
imgui.text(f"按钮已被点击 {self.counter} 次!")
|
||||||
|
|
||||||
|
imgui.text("这是一个在Panda3D引擎上显示的ImGui按钮")
|
||||||
|
imgui.text(f"帧率: {globalClock.getAverageFrameRate():.1f} FPS")
|
||||||
|
|
||||||
|
imgui.end()
|
||||||
|
|
||||||
|
# 绘制演示窗口(可选)
|
||||||
|
if self.show_demo_window:
|
||||||
|
self.show_demo_window = imgui.show_demo_window(self.show_demo_window)
|
||||||
|
|
||||||
|
def _render_to_texture(self):
|
||||||
|
"""将ImGui渲染到纹理"""
|
||||||
|
# 渲染ImGui
|
||||||
|
imgui.render()
|
||||||
|
|
||||||
|
# 获取绘制数据
|
||||||
|
draw_data = imgui.get_draw_data()
|
||||||
|
|
||||||
|
if draw_data:
|
||||||
|
# 创建PIL图像
|
||||||
|
width, height = int(self.io.display_size[0]), int(self.io.display_size[1])
|
||||||
|
image = PIL.Image.new('RGBA', (width, height), (0, 0, 0, 0))
|
||||||
|
draw = PIL.ImageDraw.Draw(image)
|
||||||
|
|
||||||
|
# 简单的文本渲染(这里只是示例,实际需要完整的ImGui渲染)
|
||||||
|
if self.show_test_button:
|
||||||
|
# 绘制简单的按钮模拟
|
||||||
|
button_x, button_y = 50, 50
|
||||||
|
button_width, button_height = 100, 30
|
||||||
|
draw.rectangle([button_x, button_y, button_x + button_width, button_y + button_height],
|
||||||
|
fill=(100, 100, 200, 255), outline=(255, 255, 255, 255))
|
||||||
|
draw.text((button_x + 10, button_y + 5), "点击我!", fill=(255, 255, 255, 255))
|
||||||
|
|
||||||
|
# 显示点击计数
|
||||||
|
if self.counter > 0:
|
||||||
|
draw.text((button_x, button_y + button_height + 10),
|
||||||
|
f"点击次数: {self.counter}", fill=(255, 255, 255, 255))
|
||||||
|
|
||||||
|
# 将PIL图像转换为Panda3D纹理
|
||||||
|
img_buffer = io.BytesIO()
|
||||||
|
image.save(img_buffer, format='RGBA')
|
||||||
|
img_buffer.seek(0)
|
||||||
|
|
||||||
|
pnm_image = PNMImage()
|
||||||
|
pnm_image.read(StringStream(img_buffer.read()))
|
||||||
|
self.imgui_texture.load(pnm_image)
|
||||||
|
|
||||||
|
def toggle_demo_window(self):
|
||||||
|
"""切换演示窗口显示"""
|
||||||
|
self.show_demo_window = not self.show_demo_window
|
||||||
|
|
||||||
|
def toggle_test_button(self):
|
||||||
|
"""切换测试按钮显示"""
|
||||||
|
self.show_test_button = not self.show_test_button
|
||||||
|
|
||||||
|
def process_mouse_click(self, x, y):
|
||||||
|
"""处理鼠标点击"""
|
||||||
|
# 检查是否点击了按钮区域
|
||||||
|
if self.show_test_button:
|
||||||
|
button_x, button_y = 50, 50
|
||||||
|
button_width, button_height = 100, 30
|
||||||
|
|
||||||
|
# 转换坐标系(Panda3D坐标系原点在屏幕中心)
|
||||||
|
screen_x = (x + self.io.display_size[0] / 2)
|
||||||
|
screen_y = (self.io.display_size[1] / 2 - y)
|
||||||
|
|
||||||
|
if (button_x <= screen_x <= button_x + button_width and
|
||||||
|
button_y <= screen_y <= button_y + button_height):
|
||||||
|
self.button_clicked = True
|
||||||
|
self.counter += 1
|
||||||
|
print(f"按钮被点击了! 计数: {self.counter}")
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
"""清理资源"""
|
||||||
|
if self.imgui_image:
|
||||||
|
self.imgui_image.removeNode()
|
||||||
|
if self.imgui_texture:
|
||||||
|
self.imgui_texture = None
|
||||||
|
imgui.destroy_context()
|
||||||
|
|
||||||
|
# 辅助类用于内存中的字符串流
|
||||||
|
class StringStream:
|
||||||
|
"""简单的内存字符串流,用于PNMImage读取"""
|
||||||
|
def __init__(self, data):
|
||||||
|
self.data = data
|
||||||
|
self.position = 0
|
||||||
|
|
||||||
|
def read(self, size=-1):
|
||||||
|
if size == -1:
|
||||||
|
result = self.data[self.position:]
|
||||||
|
self.position = len(self.data)
|
||||||
|
else:
|
||||||
|
result = self.data[self.position:self.position + size]
|
||||||
|
self.position += size
|
||||||
|
return result
|
||||||
|
|
||||||
|
def seek(self, position):
|
||||||
|
self.position = position
|
||||||
|
|
||||||
|
def tell(self):
|
||||||
|
return self.position
|
||||||
679
demo.py
Normal file
679
demo.py
Normal file
@ -0,0 +1,679 @@
|
|||||||
|
from panda3d.core import loadPrcFileData, WindowProperties, Point3
|
||||||
|
from math import pi, sin, cos
|
||||||
|
|
||||||
|
from direct.showbase.ShowBase import ShowBase
|
||||||
|
from direct.task import Task
|
||||||
|
from direct.actor.Actor import Actor
|
||||||
|
from direct.interval.IntervalGlobal import Sequence
|
||||||
|
|
||||||
|
import p3dimgui
|
||||||
|
|
||||||
|
from imgui_bundle import imgui, imgui_ctx
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
# 导入MyWorld类和必要的模块
|
||||||
|
from core.world import CoreWorld
|
||||||
|
from core.selection import SelectionSystem
|
||||||
|
from core.event_handler import EventHandler
|
||||||
|
from core.tool_manager import ToolManager
|
||||||
|
from core.script_system import ScriptManager
|
||||||
|
from core.patrol_system import PatrolSystem
|
||||||
|
from core.Command_System import CommandManager
|
||||||
|
from gui.gui_manager import GUIManager
|
||||||
|
from core.terrain_manager import TerrainManager
|
||||||
|
from scene.scene_manager import SceneManager
|
||||||
|
from project.project_manager import ProjectManager
|
||||||
|
from core.InfoPanelManager import InfoPanelManager
|
||||||
|
from core.collision_manager import CollisionManager
|
||||||
|
try:
|
||||||
|
# 尝试导入视频管理器,避免循环导入
|
||||||
|
import importlib.util
|
||||||
|
spec = importlib.util.spec_from_file_location("video_integration", "demo/video_integration.py")
|
||||||
|
video_module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(video_module)
|
||||||
|
VideoManager = video_module.VideoManager
|
||||||
|
except:
|
||||||
|
# 如果video_integration模块不存在,则跳过
|
||||||
|
VideoManager = None
|
||||||
|
print("⚠ 视频管理器模块未找到,视频功能将不可用")
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||||
|
|
||||||
|
class MyWorld(CoreWorld):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# 初始化选择和变换系统
|
||||||
|
self.selection = SelectionSystem(self)
|
||||||
|
|
||||||
|
# 绑定F键用于聚焦选中节点
|
||||||
|
self.accept("f", self.onFocusKeyPressed)
|
||||||
|
self.accept("F", self.onFocusKeyPressed) # 大写F
|
||||||
|
|
||||||
|
#初始化巡检系统
|
||||||
|
self.patrol_system = PatrolSystem(self)
|
||||||
|
self.accept("p",self.onPatrolKeyPressed)
|
||||||
|
self.accept("P",self.onPatrolKeyPressed)
|
||||||
|
|
||||||
|
# 初始化事件处理系统
|
||||||
|
self.event_handler = EventHandler(self)
|
||||||
|
|
||||||
|
# 初始化工具管理系统
|
||||||
|
self.tool_manager = ToolManager(self)
|
||||||
|
|
||||||
|
# 初始化脚本管理系统
|
||||||
|
self.script_manager = ScriptManager(self)
|
||||||
|
|
||||||
|
# 初始化GUI管理系统
|
||||||
|
self.gui_manager = GUIManager(self)
|
||||||
|
|
||||||
|
# 初始化视频管理
|
||||||
|
if VideoManager is not None:
|
||||||
|
self.video_manager = VideoManager(self)
|
||||||
|
else:
|
||||||
|
self.video_manager = None
|
||||||
|
|
||||||
|
# 初始化场景管理系统
|
||||||
|
self.scene_manager = SceneManager(self)
|
||||||
|
|
||||||
|
# 初始化项目管理系统
|
||||||
|
self.project_manager = ProjectManager(self)
|
||||||
|
|
||||||
|
self.info_panel_manager = InfoPanelManager(self)
|
||||||
|
|
||||||
|
self.command_manager = CommandManager()
|
||||||
|
|
||||||
|
# 初始化碰撞管理器
|
||||||
|
self.collision_manager = CollisionManager(self)
|
||||||
|
|
||||||
|
# 初始化VR管理器
|
||||||
|
try:
|
||||||
|
from core.vr import VRManager
|
||||||
|
self.vr_manager = VRManager(self)
|
||||||
|
print("✓ VR管理器初始化完成")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠ VR管理器初始化失败: {e}")
|
||||||
|
self.vr_manager = None
|
||||||
|
|
||||||
|
# 调试选项
|
||||||
|
self.debug_collision = True # 是否显示碰撞体
|
||||||
|
|
||||||
|
# 默认启用模型间碰撞检测(可选)
|
||||||
|
self.enableModelCollisionDetection(enable=True, frequency=0.1, threshold=0.5)
|
||||||
|
|
||||||
|
# 启动脚本系统
|
||||||
|
self.script_manager.start_system()
|
||||||
|
|
||||||
|
self.terrain_manager = TerrainManager(self)
|
||||||
|
|
||||||
|
self.terrain_edit_radius = 3.0
|
||||||
|
self.terrain_edit_strength=0.3
|
||||||
|
self.terrain_edit_operation = "add"
|
||||||
|
|
||||||
|
# Install Dear ImGui
|
||||||
|
p3dimgui.init()
|
||||||
|
|
||||||
|
# 初始化样式管理器
|
||||||
|
from core.imgui_style_manager import ImGuiStyleManager
|
||||||
|
self.style_manager = ImGuiStyleManager(self.imgui)
|
||||||
|
|
||||||
|
# 尝试直接设置中文字体
|
||||||
|
try:
|
||||||
|
import platform
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# 获取中文字体路径
|
||||||
|
system = platform.system().lower()
|
||||||
|
if system == "linux":
|
||||||
|
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
|
||||||
|
elif system == "windows":
|
||||||
|
font_path = "C:/Windows/Fonts/msyh.ttc"
|
||||||
|
elif system == "darwin":
|
||||||
|
font_path = "/System/Library/Fonts/PingFang.ttc"
|
||||||
|
else:
|
||||||
|
font_path = None
|
||||||
|
|
||||||
|
if font_path and Path(font_path).exists():
|
||||||
|
# 先清除默认字体
|
||||||
|
self.imgui.io.fonts.clear()
|
||||||
|
|
||||||
|
# 创建中文字符范围(基本中文字符)
|
||||||
|
# 这个范围包含了常用中文字符的Unicode范围
|
||||||
|
chinese_ranges = []
|
||||||
|
# 基本拉丁字母
|
||||||
|
for i in range(0x0020, 0x00FF):
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
# 中文字符范围
|
||||||
|
for i in range(0x4E00, 0x9FFF): # CJK统一汉字
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0x3400, 0x4DBF): # CJK扩展A
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0x20000, 0x2A6DF): # CJK扩展B
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0x2A700, 0x2B73F): # CJK扩展C
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0x2B740, 0x2B81F): # CJK扩展D
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0x2B820, 0x2CEAF): # CJK扩展E
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0x2CEB0, 0x2EBEF): # CJK扩展F
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0x3000, 0x303F): # CJK符号和标点
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
for i in range(0xFF00, 0xFFEF): # 全角字符
|
||||||
|
chinese_ranges.append(i)
|
||||||
|
|
||||||
|
# 添加中文字体(不指定字符范围,让ImGui自动处理)
|
||||||
|
font = self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
|
||||||
|
print(f"✓ 直接设置中文字体成功: {font_path}")
|
||||||
|
print(f" 使用自动字符范围")
|
||||||
|
else:
|
||||||
|
print("⚠ 中文字体文件不存在")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠ 直接设置中文字体失败: {e}")
|
||||||
|
# 备用方案:使用默认字体
|
||||||
|
try:
|
||||||
|
self.imgui.io.fonts.add_font_default()
|
||||||
|
print("✓ 使用默认字体")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Disable the camera trackball controls.
|
||||||
|
self.disableMouse()
|
||||||
|
|
||||||
|
self.showDemoWindow = True
|
||||||
|
|
||||||
|
# UI状态管理
|
||||||
|
self.showSceneTree = True
|
||||||
|
self.showPropertyPanel = True
|
||||||
|
self.showConsole = True
|
||||||
|
self.showScriptPanel = True
|
||||||
|
self.showToolbar = True
|
||||||
|
|
||||||
|
self.accept('imgui-new-frame', self.__newFrame)
|
||||||
|
self.accept('`', self.__toggleImgui)
|
||||||
|
|
||||||
|
self.testTexture = None
|
||||||
|
self.icons = {} # 初始化图标字典
|
||||||
|
|
||||||
|
print("✓ MyWorld 初始化完成")
|
||||||
|
|
||||||
|
# ==================== 兼容性属性 ====================
|
||||||
|
|
||||||
|
# 保留models属性以兼容现有代码
|
||||||
|
@property
|
||||||
|
def models(self):
|
||||||
|
"""模型列表的兼容性属性"""
|
||||||
|
return self.scene_manager.models
|
||||||
|
|
||||||
|
@models.setter
|
||||||
|
def models(self, value):
|
||||||
|
"""模型列表的兼容性设置器"""
|
||||||
|
self.scene_manager.models = value
|
||||||
|
|
||||||
|
# 保留gui_elements属性以兼容现有代码
|
||||||
|
@property
|
||||||
|
def gui_elements(self):
|
||||||
|
"""GUI元素列表的兼容性属性"""
|
||||||
|
return self.gui_manager.gui_elements
|
||||||
|
|
||||||
|
@gui_elements.setter
|
||||||
|
def gui_elements(self, value):
|
||||||
|
"""GUI元素列表的兼容性设置器"""
|
||||||
|
self.gui_manager.gui_elements = value
|
||||||
|
|
||||||
|
# 保留guiEditMode属性以兼容现有代码
|
||||||
|
@property
|
||||||
|
def guiEditMode(self):
|
||||||
|
"""GUI编辑模式的兼容性属性"""
|
||||||
|
return self.gui_manager.guiEditMode
|
||||||
|
|
||||||
|
@guiEditMode.setter
|
||||||
|
def guiEditMode(self, value):
|
||||||
|
"""GUI编辑模式的兼容性设置器"""
|
||||||
|
self.gui_manager.guiEditMode = value
|
||||||
|
|
||||||
|
# 保留currentTool属性以兼容现有代码
|
||||||
|
@property
|
||||||
|
def currentTool(self):
|
||||||
|
"""当前工具的兼容性属性"""
|
||||||
|
return self.tool_manager.currentTool
|
||||||
|
|
||||||
|
@currentTool.setter
|
||||||
|
def currentTool(self, value):
|
||||||
|
"""当前工具的兼容性设置器"""
|
||||||
|
self.tool_manager.currentTool = value
|
||||||
|
|
||||||
|
# 保留terrains属性以兼容现有代码
|
||||||
|
@property
|
||||||
|
def terrains(self):
|
||||||
|
"""地形列表的兼容性属性"""
|
||||||
|
return self.terrain_manager.terrains
|
||||||
|
|
||||||
|
@terrains.setter
|
||||||
|
def terrains(self,value):
|
||||||
|
"""地形列表的兼容性设置器"""
|
||||||
|
self.terrain_manager.terrains = value
|
||||||
|
|
||||||
|
def onFocusKeyPressed(self):
|
||||||
|
"""处理 F 键按下事件"""
|
||||||
|
try:
|
||||||
|
if hasattr(self, 'selection') and self.selection.selectedNode:
|
||||||
|
self.selection.focusCameraOnSelectedNodeAdvanced()
|
||||||
|
else:
|
||||||
|
print("当前没有选中任何节点")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"处理 F 键事件失败: {e}")
|
||||||
|
|
||||||
|
def onPatrolKeyPressed(self):
|
||||||
|
"""处理 P 键按下事件 - 控制巡检系统"""
|
||||||
|
try:
|
||||||
|
print("检测到 P 键按下")
|
||||||
|
if not self.patrol_system.is_patrolling:
|
||||||
|
if not self.patrol_system.patrol_points:
|
||||||
|
self.createDefaultPatrolRoute()
|
||||||
|
if self.patrol_system.start_patrol():
|
||||||
|
print("✓ 巡检已开始")
|
||||||
|
else:
|
||||||
|
print("✗ 巡检启动失败")
|
||||||
|
else:
|
||||||
|
if self.patrol_system.stop_patrol():
|
||||||
|
print("✓ 巡检已停止")
|
||||||
|
else:
|
||||||
|
print("✗ 巡检停止失败")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"处理 P 键事件失败: {e}")
|
||||||
|
|
||||||
|
def createDefaultPatrolRoute(self):
|
||||||
|
"""创建默认巡检路线"""
|
||||||
|
try:
|
||||||
|
self.patrol_system.clear_patrol_points()
|
||||||
|
self.patrol_system.add_patrol_point((0, -10, 2), (0,0,0), 1.5)
|
||||||
|
self.patrol_system.add_patrol_point((10, -10, 2), (0,0,0), 1.5)
|
||||||
|
self.patrol_system.add_patrol_point((10, 5, 2), (0,0,0), 1.5)
|
||||||
|
self.patrol_system.add_patrol_point((10, 0, 5), (0,0,0), 1.5)
|
||||||
|
self.patrol_system.add_patrol_point((0, -10, 2), None, 2.5)
|
||||||
|
print("✓ 默认自动朝向巡检路线已创建")
|
||||||
|
self.patrol_system.list_patrol_points()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"创建默认自动朝向巡检路线失败: {e}")
|
||||||
|
|
||||||
|
def enableModelCollisionDetection(self, enable=True, frequency=0.1, threshold=0.5):
|
||||||
|
"""启用模型间碰撞检测"""
|
||||||
|
return self.collision_manager.enableModelCollisionDetection(enable, frequency, threshold)
|
||||||
|
|
||||||
|
def __toggleImgui(self):
|
||||||
|
if not self.imgui.isKeyboardCaptured():
|
||||||
|
self.imgui.toggle()
|
||||||
|
|
||||||
|
def __newFrame(self):
|
||||||
|
# Dear ImGui commands can be placed here.
|
||||||
|
|
||||||
|
# 在第一帧应用样式
|
||||||
|
if imgui.get_frame_count() == 0:
|
||||||
|
self.style_manager.apply_style()
|
||||||
|
# 加载图标
|
||||||
|
self.icons = {
|
||||||
|
'select': self.style_manager.load_icon('select_tool'),
|
||||||
|
'move': self.style_manager.load_icon('move_tool'),
|
||||||
|
'rotate': self.style_manager.load_icon('rotate_tool'),
|
||||||
|
'scale': self.style_manager.load_icon('scale_tool'),
|
||||||
|
'success': self.style_manager.load_icon('success_icon'),
|
||||||
|
'warning': self.style_manager.load_icon('warning_icon'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# 确保中文字体被正确应用
|
||||||
|
try:
|
||||||
|
# 强制刷新字体
|
||||||
|
self.imgui.io.fonts.clear()
|
||||||
|
# 重新添加中文字体
|
||||||
|
import platform
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
system = platform.system().lower()
|
||||||
|
if system == "linux":
|
||||||
|
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
|
||||||
|
elif system == "windows":
|
||||||
|
font_path = "C:/Windows/Fonts/msyh.ttc"
|
||||||
|
elif system == "darwin":
|
||||||
|
font_path = "/System/Library/Fonts/PingFang.ttc"
|
||||||
|
|
||||||
|
if font_path and Path(font_path).exists():
|
||||||
|
# 添加中文字体,明确指定中文字符集
|
||||||
|
try:
|
||||||
|
# 获取中文字符集
|
||||||
|
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese_full()
|
||||||
|
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0, None, chinese_ranges)
|
||||||
|
print("✓ 第一帧重新设置中文字体(包含中文字符集)")
|
||||||
|
except:
|
||||||
|
# 如果获取字符集失败,使用简单方式
|
||||||
|
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
|
||||||
|
print("✓ 第一帧重新设置中文字体(简单方式)")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠ 第一帧设置中文字体失败: {e}")
|
||||||
|
|
||||||
|
# 绘制菜单栏
|
||||||
|
self._draw_menu_bar()
|
||||||
|
|
||||||
|
# 绘制工具栏
|
||||||
|
if self.showToolbar:
|
||||||
|
self._draw_toolbar()
|
||||||
|
|
||||||
|
# 绘制场景树面板
|
||||||
|
if self.showSceneTree:
|
||||||
|
self._draw_scene_tree()
|
||||||
|
|
||||||
|
# 绘制属性面板
|
||||||
|
if self.showPropertyPanel:
|
||||||
|
self._draw_property_panel()
|
||||||
|
|
||||||
|
# 绘制控制台面板
|
||||||
|
if self.showConsole:
|
||||||
|
self._draw_console()
|
||||||
|
|
||||||
|
# 绘制脚本面板
|
||||||
|
if self.showScriptPanel:
|
||||||
|
self._draw_script_panel()
|
||||||
|
|
||||||
|
# 绘制纹理测试窗口
|
||||||
|
if self.testTexture:
|
||||||
|
with self.style_manager.begin_styled_window("Texture Test", True,
|
||||||
|
imgui.WINDOW_ALWAYS_AUTO_RESIZE) as (_, windowOpen):
|
||||||
|
if not windowOpen:
|
||||||
|
self.imgui.removeTexture(self.testTexture)
|
||||||
|
self.testTexture = None
|
||||||
|
return
|
||||||
|
imgui.image(self.testTexture, (256, 256))
|
||||||
|
|
||||||
|
# 绘制ImGui演示窗口
|
||||||
|
if self.showDemoWindow:
|
||||||
|
imgui.show_demo_window()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _draw_menu_bar(self):
|
||||||
|
"""绘制菜单栏"""
|
||||||
|
with imgui_ctx.begin_main_menu_bar() as main_menu:
|
||||||
|
if main_menu:
|
||||||
|
# 文件菜单
|
||||||
|
with imgui_ctx.begin_menu("文件") as file_menu:
|
||||||
|
if file_menu:
|
||||||
|
imgui.menu_item("新建项目", "Ctrl+N", False, True)
|
||||||
|
imgui.menu_item("打开项目", "Ctrl+O", False, True)
|
||||||
|
imgui.separator()
|
||||||
|
imgui.menu_item("保存", "Ctrl+S", False, True)
|
||||||
|
imgui.menu_item("另存为", "", False, True)
|
||||||
|
imgui.separator()
|
||||||
|
imgui.menu_item("退出", "Alt+F4", False, True)
|
||||||
|
|
||||||
|
# 编辑菜单
|
||||||
|
with imgui_ctx.begin_menu("编辑") as edit_menu:
|
||||||
|
if edit_menu:
|
||||||
|
imgui.menu_item("撤销", "Ctrl+Z", False, True)
|
||||||
|
imgui.menu_item("重做", "Ctrl+Y", False, True)
|
||||||
|
imgui.separator()
|
||||||
|
imgui.menu_item("复制", "Ctrl+C", False, True)
|
||||||
|
imgui.menu_item("粘贴", "Ctrl+V", False, True)
|
||||||
|
imgui.menu_item("删除", "Del", False, True)
|
||||||
|
|
||||||
|
# 视图菜单
|
||||||
|
with imgui_ctx.begin_menu("视图") as view_menu:
|
||||||
|
if view_menu:
|
||||||
|
_, self.showToolbar = imgui.menu_item("工具栏", "", self.showToolbar, True)
|
||||||
|
_, self.showSceneTree = imgui.menu_item("场景树", "", self.showSceneTree, True)
|
||||||
|
_, self.showPropertyPanel = imgui.menu_item("属性面板", "", self.showPropertyPanel, True)
|
||||||
|
_, self.showConsole = imgui.menu_item("控制台", "", self.showConsole, True)
|
||||||
|
_, self.showScriptPanel = imgui.menu_item("脚本管理", "", self.showScriptPanel, True)
|
||||||
|
|
||||||
|
# 工具菜单
|
||||||
|
with imgui_ctx.begin_menu("工具") as tools_menu:
|
||||||
|
if tools_menu:
|
||||||
|
imgui.menu_item("导入模型", "", False, True)
|
||||||
|
imgui.menu_item("地形编辑器", "", False, True)
|
||||||
|
imgui.menu_item("材质编辑器", "", False, True)
|
||||||
|
imgui.menu_item("脚本编辑器", "", False, True)
|
||||||
|
|
||||||
|
# 窗口菜单
|
||||||
|
with imgui_ctx.begin_menu("窗口") as window_menu:
|
||||||
|
if window_menu:
|
||||||
|
_, self.showDemoWindow = imgui.menu_item("ImGui演示", "", self.showDemoWindow, True)
|
||||||
|
if self.testTexture:
|
||||||
|
imgui.menu_item("关闭纹理测试", "", False, True)
|
||||||
|
else:
|
||||||
|
imgui.menu_item("显示纹理测试", "", False, True)
|
||||||
|
|
||||||
|
# 帮助菜单
|
||||||
|
with imgui_ctx.begin_menu("帮助") as help_menu:
|
||||||
|
if help_menu:
|
||||||
|
imgui.menu_item("关于", "", False, True)
|
||||||
|
imgui.menu_item("文档", "", False, True)
|
||||||
|
|
||||||
|
# 右侧显示FPS
|
||||||
|
imgui.set_cursor_pos_x(imgui.get_window_size().x - 140)
|
||||||
|
imgui.text("%.2f FPS (%.2f ms)" % (imgui.get_io().framerate, 1000.0 / imgui.get_io().framerate))
|
||||||
|
|
||||||
|
def _draw_toolbar(self):
|
||||||
|
"""绘制工具栏"""
|
||||||
|
# 设置工具栏位置
|
||||||
|
imgui.set_next_window_pos((10, 30), imgui.Cond_.first_use_ever.value)
|
||||||
|
imgui.set_next_window_size((300, 40), imgui.Cond_.first_use_ever.value)
|
||||||
|
|
||||||
|
with self.style_manager.begin_styled_window("工具栏", self.showToolbar,
|
||||||
|
self.style_manager.get_window_flags("toolbar")):
|
||||||
|
self.showToolbar = True # 确保窗口保持打开
|
||||||
|
|
||||||
|
# 工具按钮组
|
||||||
|
if self.icons.get('select'):
|
||||||
|
if self.style_manager.image_button(self.icons['select'], (24, 24)):
|
||||||
|
print("选择工具")
|
||||||
|
if imgui.is_item_hovered():
|
||||||
|
imgui.set_tooltip("选择工具 (Q)")
|
||||||
|
imgui.same_line()
|
||||||
|
else:
|
||||||
|
if imgui.button("选择"):
|
||||||
|
print("选择工具")
|
||||||
|
imgui.same_line()
|
||||||
|
|
||||||
|
if self.icons.get('move'):
|
||||||
|
if self.style_manager.image_button(self.icons['move'], (24, 24)):
|
||||||
|
print("移动工具")
|
||||||
|
if imgui.is_item_hovered():
|
||||||
|
imgui.set_tooltip("移动工具 (W)")
|
||||||
|
imgui.same_line()
|
||||||
|
else:
|
||||||
|
if imgui.button("移动"):
|
||||||
|
print("移动工具")
|
||||||
|
imgui.same_line()
|
||||||
|
|
||||||
|
if self.icons.get('rotate'):
|
||||||
|
if self.style_manager.image_button(self.icons['rotate'], (24, 24)):
|
||||||
|
print("旋转工具")
|
||||||
|
if imgui.is_item_hovered():
|
||||||
|
imgui.set_tooltip("旋转工具 (E)")
|
||||||
|
imgui.same_line()
|
||||||
|
else:
|
||||||
|
if imgui.button("旋转"):
|
||||||
|
print("旋转工具")
|
||||||
|
imgui.same_line()
|
||||||
|
|
||||||
|
if self.icons.get('scale'):
|
||||||
|
if self.style_manager.image_button(self.icons['scale'], (24, 24)):
|
||||||
|
print("缩放工具")
|
||||||
|
if imgui.is_item_hovered():
|
||||||
|
imgui.set_tooltip("缩放工具 (R)")
|
||||||
|
else:
|
||||||
|
if imgui.button("缩放"):
|
||||||
|
print("缩放工具")
|
||||||
|
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.separator()
|
||||||
|
imgui.same_line()
|
||||||
|
|
||||||
|
# 其他工具按钮
|
||||||
|
if imgui.button("导入"):
|
||||||
|
print("导入模型")
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("保存"):
|
||||||
|
print("保存场景")
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("播放"):
|
||||||
|
print("播放动画")
|
||||||
|
|
||||||
|
def _draw_scene_tree(self):
|
||||||
|
"""绘制场景树面板"""
|
||||||
|
# 设置场景树位置
|
||||||
|
imgui.set_next_window_pos((10, 80), imgui.Cond_.first_use_ever.value)
|
||||||
|
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
|
||||||
|
|
||||||
|
with self.style_manager.begin_styled_window("场景树", self.showSceneTree,
|
||||||
|
self.style_manager.get_window_flags("panel")):
|
||||||
|
self.showSceneTree = True # 确保窗口保持打开
|
||||||
|
|
||||||
|
imgui.text("场景层级")
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
# 模拟场景树结构
|
||||||
|
if imgui.tree_node("渲染"):
|
||||||
|
if imgui.tree_node("环境光"):
|
||||||
|
imgui.text("环境光 #1")
|
||||||
|
imgui.tree_pop()
|
||||||
|
if imgui.tree_node("定向光"):
|
||||||
|
imgui.text("定向光 #1")
|
||||||
|
imgui.tree_pop()
|
||||||
|
if imgui.tree_node("地板"):
|
||||||
|
imgui.text("地板节点")
|
||||||
|
imgui.tree_pop()
|
||||||
|
imgui.tree_pop()
|
||||||
|
|
||||||
|
if imgui.tree_node("相机"):
|
||||||
|
imgui.text("主相机")
|
||||||
|
imgui.tree_pop()
|
||||||
|
|
||||||
|
if imgui.tree_node("模型"):
|
||||||
|
imgui.text("(空)")
|
||||||
|
imgui.tree_pop()
|
||||||
|
|
||||||
|
def _draw_property_panel(self):
|
||||||
|
"""绘制属性面板"""
|
||||||
|
# 设置属性面板位置
|
||||||
|
imgui.set_next_window_pos((270, 80), imgui.Cond_.first_use_ever.value)
|
||||||
|
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
|
||||||
|
|
||||||
|
with self.style_manager.begin_styled_window("属性面板", self.showPropertyPanel,
|
||||||
|
self.style_manager.get_window_flags("panel")):
|
||||||
|
self.showPropertyPanel = True # 确保窗口保持打开
|
||||||
|
|
||||||
|
imgui.text("对象属性")
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
# 模拟属性设置
|
||||||
|
changed, pos_x = imgui.drag_float("位置 X", 0.0, 0.1)
|
||||||
|
changed, pos_y = imgui.drag_float("位置 Y", 0.0, 0.1)
|
||||||
|
changed, pos_z = imgui.drag_float("位置 Z", 0.0, 0.1)
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
changed, rot_x = imgui.drag_float("旋转 X", 0.0, 1.0)
|
||||||
|
changed, rot_y = imgui.drag_float("旋转 Y", 0.0, 1.0)
|
||||||
|
changed, rot_z = imgui.drag_float("旋转 Z", 0.0, 1.0)
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
changed, scale = imgui.drag_float("缩放", 1.0, 0.1)
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
if imgui.button("重置变换"):
|
||||||
|
print("重置变换")
|
||||||
|
|
||||||
|
def _draw_console(self):
|
||||||
|
"""绘制控制台面板"""
|
||||||
|
# 设置控制台位置
|
||||||
|
imgui.set_next_window_pos((10, 390), imgui.Cond_.first_use_ever.value)
|
||||||
|
imgui.set_next_window_size((770, 150), imgui.Cond_.first_use_ever.value)
|
||||||
|
|
||||||
|
with self.style_manager.begin_styled_window("控制台", self.showConsole,
|
||||||
|
self.style_manager.get_window_flags("panel")):
|
||||||
|
self.showConsole = True # 确保窗口保持打开
|
||||||
|
|
||||||
|
imgui.text("控制台输出")
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
# 模拟控制台输出
|
||||||
|
if self.icons.get('success'):
|
||||||
|
imgui.image(self.icons['success'], (12, 12))
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text_colored((0.176, 1.0, 0.769, 1.0), "[INFO]") # 成功颜色
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text("引擎初始化完成")
|
||||||
|
|
||||||
|
imgui.text_colored((0.157, 0.620, 1.0, 1.0), "[INFO]") # 信息颜色
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text("渲染管线已加载")
|
||||||
|
|
||||||
|
if self.icons.get('warning'):
|
||||||
|
imgui.image(self.icons['warning'], (12, 12))
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text_colored((0.953, 0.616, 0.471, 1.0), "[WARN]") # 警告颜色
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text("视频管理器模块未找到")
|
||||||
|
|
||||||
|
if self.icons.get('success'):
|
||||||
|
imgui.image(self.icons['success'], (12, 12))
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text_colored((0.176, 1.0, 0.769, 1.0), "[INFO]") # 成功颜色
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text("VR管理器初始化完成")
|
||||||
|
|
||||||
|
# 输入框
|
||||||
|
imgui.separator()
|
||||||
|
changed, command = imgui.input_text(">", "", 256)
|
||||||
|
if changed and command:
|
||||||
|
print(f"执行命令: {command}")
|
||||||
|
|
||||||
|
def _draw_script_panel(self):
|
||||||
|
"""绘制脚本管理面板"""
|
||||||
|
# 设置脚本面板位置
|
||||||
|
imgui.set_next_window_pos((530, 80), imgui.Cond_.first_use_ever.value)
|
||||||
|
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
|
||||||
|
|
||||||
|
with self.style_manager.begin_styled_window("脚本管理", self.showScriptPanel,
|
||||||
|
self.style_manager.get_window_flags("panel")):
|
||||||
|
self.showScriptPanel = True # 确保窗口保持打开
|
||||||
|
|
||||||
|
imgui.text("脚本列表")
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
# 模拟脚本列表
|
||||||
|
selected, _ = imgui.selectable("main.py", False)
|
||||||
|
if selected:
|
||||||
|
print("选择脚本: main.py")
|
||||||
|
selected, _ = imgui.selectable("player_controller.py", False)
|
||||||
|
if selected:
|
||||||
|
print("选择脚本: player_controller.py")
|
||||||
|
selected, _ = imgui.selectable("ui_manager.py", False)
|
||||||
|
if selected:
|
||||||
|
print("选择脚本: ui_manager.py")
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
# 脚本操作按钮
|
||||||
|
if imgui.button("新建脚本"):
|
||||||
|
print("新建脚本")
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("编辑"):
|
||||||
|
print("编辑脚本")
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("重载"):
|
||||||
|
print("重载脚本")
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
imgui.text("脚本输出:")
|
||||||
|
imgui.text("脚本引擎已启动")
|
||||||
|
imgui.text("热重载监控已启动")
|
||||||
|
|
||||||
|
demo = MyWorld()
|
||||||
|
demo.run()
|
||||||
55
imgui.ini
Normal file
55
imgui.ini
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
[Window][Debug##Default]
|
||||||
|
Pos=60,60
|
||||||
|
Size=400,400
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Explore: render]
|
||||||
|
Pos=60,60
|
||||||
|
Size=410,761
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Node Placer "camera"]
|
||||||
|
Pos=486,83
|
||||||
|
Size=472,216
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Time Slider "pandaPace"]
|
||||||
|
Pos=-69,89
|
||||||
|
Size=745,76
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Dear ImGui Demo]
|
||||||
|
Pos=989,19
|
||||||
|
Size=550,680
|
||||||
|
Collapsed=1
|
||||||
|
|
||||||
|
[Window][工具栏]
|
||||||
|
Pos=10,30
|
||||||
|
Size=300,40
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][场景树]
|
||||||
|
Pos=-3,66
|
||||||
|
Size=270,497
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][属性面板]
|
||||||
|
Pos=1132,337
|
||||||
|
Size=252,416
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][控制台]
|
||||||
|
Pos=0,562
|
||||||
|
Size=1132,191
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][脚本管理]
|
||||||
|
Pos=1132,39
|
||||||
|
Size=250,300
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][中文显示测试]
|
||||||
|
Pos=60,60
|
||||||
|
Size=135,263
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
149
test_chinese_font.py
Normal file
149
test_chinese_font.py
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
测试中文字体显示的调试脚本
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '.'))
|
||||||
|
|
||||||
|
from panda3d.core import loadPrcFileData
|
||||||
|
from direct.showbase.ShowBase import ShowBase
|
||||||
|
import p3dimgui
|
||||||
|
from imgui_bundle import imgui
|
||||||
|
import platform
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
class ChineseFontTest(ShowBase):
|
||||||
|
def __init__(self):
|
||||||
|
# 设置窗口
|
||||||
|
loadPrcFileData('', 'win-size 800 600')
|
||||||
|
ShowBase.__init__(self)
|
||||||
|
|
||||||
|
# 初始化ImGui
|
||||||
|
p3dimgui.init()
|
||||||
|
|
||||||
|
# 测试字体加载
|
||||||
|
self.test_font_loading()
|
||||||
|
|
||||||
|
# 接受ImGui新帧事件
|
||||||
|
self.accept('imgui-new-frame', self._new_frame)
|
||||||
|
self.accept('`', self._toggle_imgui)
|
||||||
|
|
||||||
|
self.show_test_window = True
|
||||||
|
|
||||||
|
def test_font_loading(self):
|
||||||
|
"""测试字体加载"""
|
||||||
|
print("=== 开始字体测试 ===")
|
||||||
|
|
||||||
|
# 检查系统
|
||||||
|
system = platform.system().lower()
|
||||||
|
print(f"系统: {system}")
|
||||||
|
|
||||||
|
# 获取字体路径
|
||||||
|
font_paths = []
|
||||||
|
if system == "linux":
|
||||||
|
font_paths = [
|
||||||
|
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
|
||||||
|
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
|
||||||
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||||
|
]
|
||||||
|
elif system == "windows":
|
||||||
|
font_paths = [
|
||||||
|
"C:/Windows/Fonts/msyh.ttc",
|
||||||
|
"C:/Windows/Fonts/simhei.ttf",
|
||||||
|
]
|
||||||
|
elif system == "darwin":
|
||||||
|
font_paths = [
|
||||||
|
"/System/Library/Fonts/PingFang.ttc",
|
||||||
|
"/System/Library/Fonts/STHeiti.ttc",
|
||||||
|
]
|
||||||
|
|
||||||
|
# 测试每个字体
|
||||||
|
for font_path in font_paths:
|
||||||
|
if Path(font_path).exists():
|
||||||
|
print(f"✓ 字体文件存在: {font_path}")
|
||||||
|
try:
|
||||||
|
# 尝试加载字体
|
||||||
|
font = self.imgui.io.fonts.add_font_from_file_ttf(font_path, 16.0)
|
||||||
|
print(f" ✓ 字体加载成功")
|
||||||
|
|
||||||
|
# 检查字体信息
|
||||||
|
font_info = self.imgui.io.fonts.fonts
|
||||||
|
print(f" 字体数量: {len(font_info)}")
|
||||||
|
|
||||||
|
# 尝试获取字符集
|
||||||
|
try:
|
||||||
|
# 方法1:尝试获取中文字符集
|
||||||
|
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese_full()
|
||||||
|
print(f" ✓ 中文字符集获取成功,范围: {len(chinese_ranges)} 个字符")
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
# 方法2:尝试获取中文字符集(简化版)
|
||||||
|
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese()
|
||||||
|
print(f" ✓ 中文字符集获取成功(简化版),范围: {len(chinese_ranges)} 个字符")
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
# 方法3:尝试获取默认字符集
|
||||||
|
default_ranges = imgui.get_io().fonts.get_glyph_ranges_default()
|
||||||
|
print(f" ✓ 默认字符集获取成功,范围: {len(default_ranges)} 个字符")
|
||||||
|
print(f" ⚠ 使用默认字符集,可能不支持中文")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ⚠ 字符集获取失败: {e}")
|
||||||
|
print(f" ⚠ 将使用默认字符集")
|
||||||
|
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ 字体加载失败: {e}")
|
||||||
|
else:
|
||||||
|
print(f"✗ 字体文件不存在: {font_path}")
|
||||||
|
|
||||||
|
print("=== 字体测试完成 ===")
|
||||||
|
|
||||||
|
def _toggle_imgui(self):
|
||||||
|
if not self.imgui.isKeyboardCaptured():
|
||||||
|
self.imgui.toggle()
|
||||||
|
|
||||||
|
def _new_frame(self):
|
||||||
|
# 绘制测试窗口
|
||||||
|
if self.show_test_window:
|
||||||
|
imgui.show_demo_window()
|
||||||
|
|
||||||
|
# 中文测试窗口
|
||||||
|
expanded, opened = imgui.begin("中文显示测试", True)
|
||||||
|
if expanded:
|
||||||
|
imgui.text("基础中文测试:")
|
||||||
|
imgui.text("你好,世界!")
|
||||||
|
imgui.text("这是一个中文测试")
|
||||||
|
imgui.text("引擎初始化完成")
|
||||||
|
imgui.text("选择和变换系统")
|
||||||
|
imgui.text("脚本管理系统")
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
imgui.text("特殊字符测试:")
|
||||||
|
imgui.text("标点符号:,。!?;:""''()【】")
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
imgui.text("数字测试:")
|
||||||
|
imgui.text("一二三四五六七八九十")
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
if imgui.button("测试按钮"):
|
||||||
|
print("中文按钮被点击")
|
||||||
|
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("另一个按钮"):
|
||||||
|
print("另一个中文按钮")
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
changed, text = imgui.input_text("输入中文", "在这里输入中文")
|
||||||
|
if changed:
|
||||||
|
print(f"输入的中文: {text}")
|
||||||
|
|
||||||
|
imgui.end()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test = ChineseFontTest()
|
||||||
|
test.run()
|
||||||
21
testgui.py
Normal file
21
testgui.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from direct.showbase.ShowBase import ShowBase
|
||||||
|
|
||||||
|
from imgui_bundle import imgui
|
||||||
|
|
||||||
|
import p3dimgui
|
||||||
|
|
||||||
|
class MyApp(ShowBase):
|
||||||
|
def __init__(self):
|
||||||
|
ShowBase.__init__(self)
|
||||||
|
|
||||||
|
# Install Dear ImGui
|
||||||
|
p3dimgui.init()
|
||||||
|
|
||||||
|
self.accept('imgui-new-frame', self.draw)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
# Show the demo window.
|
||||||
|
imgui.show_demo_window()
|
||||||
|
|
||||||
|
app = MyApp()
|
||||||
|
app.run()
|
||||||
Loading…
Reference in New Issue
Block a user