1985 lines
77 KiB
Python
1985 lines
77 KiB
Python
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
|
||
from panda3d.core import NodePath
|
||
|
||
import p3dimgui
|
||
|
||
from imgui_bundle import imgui, imgui_ctx
|
||
|
||
import sys
|
||
import os
|
||
import warnings
|
||
from pathlib import Path
|
||
|
||
# 导入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
|
||
from core.CustomMouseController import CustomMouseController
|
||
from core.resource_manager import ResourceManager
|
||
from ui.lui_manager import LUIManager
|
||
from ui.panels.editor_panels import EditorPanels
|
||
from ui.panels.script_panels import ScriptPanels
|
||
from ui.panels.dialog_panels import DialogPanels
|
||
from ui.panels.interaction_panels import InteractionPanels
|
||
from ui.panels.create_actions import CreateActions
|
||
from ui.panels.object_factory import ObjectFactory
|
||
from ui.panels.animation_tools import AnimationTools
|
||
from ui.panels.property_helpers import PropertyHelpers
|
||
from ui.panels.app_actions import AppActions
|
||
from core.model_drag_drop import ModelDragDropService
|
||
from ssbo_component.ssbo_editor import SSBOEditor
|
||
from TransformGizmo.transform_gizmo import TransformGizmo
|
||
|
||
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__()
|
||
|
||
# 设置窗口为最大化模式
|
||
props = WindowProperties()
|
||
#props.set_maximized(True)
|
||
self.win.request_properties(props)
|
||
print("✓ 窗口已设置为最大化模式")
|
||
|
||
# 初始化选择和变换系统
|
||
self.selection = SelectionSystem(self)
|
||
|
||
# 绑定F键用于聚焦选中节点
|
||
self.accept("f", self.onFocusKeyPressed)
|
||
self.accept("F", self.onFocusKeyPressed) # 大写F
|
||
|
||
self.use_ssbo_mouse_picking = True
|
||
if not self.use_ssbo_mouse_picking:
|
||
self.accept("mouse1", self.onMouseClick)
|
||
# Keep release/move bindings even in SSBO mode so gizmo drag can work.
|
||
self.accept("mouse1-up", self.onMouseRelease)
|
||
self.accept("mouse-move", self.onMouseMove)
|
||
self.accept("drag", self.onMouseMove)
|
||
|
||
# 初始化事件处理系统
|
||
self.event_handler = EventHandler(self)
|
||
|
||
# 初始化工具管理系统
|
||
self.tool_manager = ToolManager(self)
|
||
|
||
# 初始化脚本管理系统
|
||
self.script_manager = ScriptManager(self)
|
||
|
||
# 初始化GUI管理系统
|
||
self.gui_manager = GUIManager(self)
|
||
|
||
# 初始化LUI管理系统
|
||
self.lui_manager = LUIManager(self)
|
||
|
||
# 新的坐标系
|
||
self.newTransform = TransformGizmo(self)
|
||
self._setup_transform_gizmo_light_sync()
|
||
|
||
# 初始化视频管理
|
||
if VideoManager is not None:
|
||
self.video_manager = VideoManager(self)
|
||
else:
|
||
self.video_manager = None
|
||
|
||
# 初始化场景管理系统
|
||
# print(f"[DEBUG] 初始化场景管理系统...")
|
||
self.scene_manager = SceneManager(self)
|
||
# print(f"[DEBUG] 场景管理系统初始化完成")
|
||
|
||
# 初始化项目管理系统
|
||
# print(f"[DEBUG] 初始化项目管理系统...")
|
||
self.project_manager = ProjectManager(self)
|
||
# print(f"[DEBUG] 项目管理系统初始化完成")
|
||
|
||
self.info_panel_manager = InfoPanelManager(self)
|
||
|
||
self.command_manager = CommandManager()
|
||
|
||
# 初始化碰撞管理器
|
||
self.collision_manager = CollisionManager(self)
|
||
|
||
# 初始化资源管理器
|
||
self.resource_manager = ResourceManager(self)
|
||
|
||
# 初始化Actor缓存系统(用于动画控制)
|
||
self._actor_cache = {}
|
||
print("✓ Actor缓存系统初始化完成")
|
||
|
||
# 初始化自定义鼠标控制器(视角移动)
|
||
self.mouse_controller = CustomMouseController(self)
|
||
self.mouse_controller.setUp(mouse_speed=25, move_speed=20)
|
||
print("✓ 自定义鼠标控制器初始化完成")
|
||
|
||
# 初始化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
|
||
|
||
# VR调试相关变量
|
||
self.vr_debug_enabled = False
|
||
self.vr_detailed_mode = True
|
||
self.vr_performance_monitor = False
|
||
|
||
# 调试选项
|
||
self.debug_collision = True # 是否显示碰撞体
|
||
|
||
# 默认启用模型间碰撞检测(可选)
|
||
if self.use_ssbo_mouse_picking:
|
||
self.enableModelCollisionDetection(enable=False, frequency=0.1, threshold=0.5)
|
||
else:
|
||
self.enableModelCollisionDetection(enable=True, frequency=0.1, threshold=0.5)
|
||
|
||
# 碰撞检测UI相关变量
|
||
self._selected_collision_shape = "球形 (Sphere)" # 默认选择的碰撞形状
|
||
|
||
# 启动脚本系统
|
||
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(
|
||
wantPlaceManager=False,
|
||
wantExplorerManager=False,
|
||
wantTimeSliderManager=False,
|
||
)
|
||
# Let ssbo_component reuse the existing imgui backend instance.
|
||
self.imgui_backend = self.imgui
|
||
# Initialize SSBO editor and let it own mouse1 picking.
|
||
# Do not auto-load a default model here; models are loaded from import flow.
|
||
self.ssbo_editor = None
|
||
if self.use_ssbo_mouse_picking:
|
||
self.ssbo_editor = SSBOEditor(
|
||
base_app=self,
|
||
render_pipeline=self.render_pipeline,
|
||
model_path=None,
|
||
font_path=None,
|
||
)
|
||
self.ssbo_editor.bind_transform_gizmo(self.newTransform)
|
||
print("SSBOEditor mouse picking enabled (waiting for imported model)")
|
||
|
||
imgui.get_io().config_flags |= imgui.ConfigFlags_.docking_enable
|
||
print("✓ ImGui Docking功能已启用")
|
||
|
||
# 初始化样式管理器
|
||
from core.imgui_style_manager import ImGuiStyleManager
|
||
self.style_manager = ImGuiStyleManager(self.imgui, self)
|
||
self.editor_panels = EditorPanels(self)
|
||
self.script_panels = ScriptPanels(self)
|
||
self.dialog_panels = DialogPanels(self)
|
||
self.interaction_panels = InteractionPanels(self)
|
||
self.create_actions = CreateActions(self)
|
||
self.object_factory = ObjectFactory(self)
|
||
self.animation_tools = AnimationTools(self)
|
||
self.property_helpers = PropertyHelpers(self)
|
||
self.app_actions = AppActions(self)
|
||
|
||
# 简化的初始化字体设置(只使用中文字体)
|
||
try:
|
||
# 先清除默认字体
|
||
self.imgui.io.fonts.clear()
|
||
|
||
# 尝试加载中文字体
|
||
import platform
|
||
system = platform.system().lower()
|
||
if system == "linux":
|
||
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.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.add_font_from_file_ttf(font_path, 14.0)
|
||
print(f"✓ 初始化中文字体成功: {font_path}")
|
||
else:
|
||
# 回退到原来的字体
|
||
fallback_font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
|
||
if fallback_font_path and Path(fallback_font_path).exists():
|
||
self.imgui.io.fonts.add_font_from_file_ttf(fallback_font_path, 14.0)
|
||
print(f"✓ 初始化回退字体成功: {fallback_font_path}")
|
||
else:
|
||
self.imgui.io.fonts.add_font_default()
|
||
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 = False
|
||
|
||
# UI状态管理
|
||
self.showSceneTree = True
|
||
self.showPropertyPanel = True
|
||
self.showConsole = True
|
||
self.showScriptPanel = not self.use_ssbo_mouse_picking
|
||
self.showToolbar = True
|
||
self.showResourceManager = True
|
||
self.showWebPanel = False
|
||
self.webPanelUrl = "https://www.baidu.com"
|
||
|
||
# 脚本系统状态变量
|
||
self.hotReloadEnabled = True
|
||
self._new_script_name = "new_script"
|
||
self._selected_template = 0
|
||
self._mount_script_index = 0
|
||
|
||
# 变换监控相关
|
||
self._transform_monitoring = False
|
||
self._monitored_node = None
|
||
self._last_transform_values = {}
|
||
self._transform_update_timer = 0
|
||
self._transform_update_interval = 0.05 # 50ms检查一次
|
||
self._clipboard_pos = None # 位置剪贴板
|
||
|
||
# 颜色选择器相关
|
||
self._color_picker_active = False
|
||
self._color_picker_target = None # (target_object, property_name)
|
||
self._color_picker_current_color = (1.0, 1.0, 1.0, 1.0)
|
||
self._color_picker_callback = None
|
||
|
||
# 字体选择器相关
|
||
self._font_selector_active = False
|
||
self._font_selector_target = None # (target_object, property_name)
|
||
self._font_selector_current_font = ""
|
||
self._font_selector_callback = None
|
||
self._available_fonts = [] # 可用字体列表
|
||
self._refresh_available_fonts()
|
||
|
||
# 菜单状态管理
|
||
self.show_new_project_dialog = False
|
||
self.show_open_project_dialog = False
|
||
self.show_save_as_dialog = False
|
||
|
||
# 路径选择对话框状态
|
||
self.show_path_browser = False
|
||
self.path_browser_mode = "" # "new_project" 或 "open_project"
|
||
self.path_browser_current_path = os.getcwd()
|
||
self.path_browser_selected_path = ""
|
||
self.path_browser_items = []
|
||
|
||
# 快捷键映射
|
||
self.shortcut_keys = {
|
||
'Ctrl+N': self._on_new_project,
|
||
'Ctrl+O': self._on_open_project,
|
||
'Ctrl+S': self._on_save_project,
|
||
'Alt+F4': self._on_exit
|
||
}
|
||
|
||
# 键盘状态跟踪
|
||
self.ctrl_pressed = False
|
||
self.alt_pressed = False
|
||
|
||
# 消息系统
|
||
self.messages = []
|
||
self.max_messages = 5 # 最多显示5条消息
|
||
|
||
# 剪切板系统
|
||
self.clipboard = []
|
||
self.clipboard_mode = "" # "copy" 或 "cut"
|
||
|
||
# 视角控制状态
|
||
self.camera_control_enabled = True
|
||
self.show_camera_info = False
|
||
|
||
# 拖拽导入状态
|
||
self.dragged_files = []
|
||
self.is_dragging = False
|
||
self.show_drag_overlay = False
|
||
self.drag_drop_monitor = None
|
||
self._resource_manager_window_rect = None
|
||
self._resource_drop_targets = []
|
||
self._scene_tree_window_rect = None
|
||
self._property_panel_window_rect = None
|
||
self._script_panel_window_rect = None
|
||
self._console_window_rect = None
|
||
self._toolbar_window_rect = None
|
||
self._drag_scene_tree_hover_node = None
|
||
self.model_drag_drop = ModelDragDropService(self)
|
||
self.showLUIEditor = not self.use_ssbo_mouse_picking
|
||
|
||
# 导入功能状态
|
||
self.show_import_dialog = False
|
||
self.import_file_path = ""
|
||
self.supported_formats = [".gltf", ".glb", ".fbx", ".bam", ".egg", ".obj"]
|
||
|
||
# 创建功能状态
|
||
self.show_3d_text_dialog = False
|
||
self.show_3d_image_dialog = False
|
||
self.show_gui_button_dialog = False
|
||
self.show_gui_label_dialog = False
|
||
self.show_gui_entry_dialog = False
|
||
self.show_gui_image_dialog = False
|
||
self.show_video_screen_dialog = False
|
||
self.show_2d_video_screen_dialog = False
|
||
self.show_spherical_video_dialog = False
|
||
self.show_virtual_screen_dialog = False
|
||
self.show_spot_light_dialog = False
|
||
self.show_point_light_dialog = False
|
||
self.show_terrain_dialog = False
|
||
self.show_heightmap_browser = False
|
||
self.show_script_dialog = False
|
||
self.show_script_browser = False
|
||
|
||
# 高度图浏览器状态
|
||
self.heightmap_browser_current_path = os.getcwd()
|
||
self.heightmap_browser_selected_path = ""
|
||
self.heightmap_browser_items = []
|
||
self.heightmap_file_path = ""
|
||
self.supported_heightmap_formats = [".png", ".jpg", ".jpeg", ".bmp", ".tiff", ".tif"]
|
||
|
||
# 脚本浏览器状态
|
||
self.script_browser_current_path = os.getcwd()
|
||
self.script_browser_selected_path = ""
|
||
self.script_browser_items = []
|
||
|
||
# 对话框参数存储
|
||
self.dialog_params = {} # 存储各种对话框的参数
|
||
|
||
# 脚本系统状态
|
||
self.hotReloadEnabled = False
|
||
|
||
# 初始化高度图浏览器
|
||
self._refresh_heightmap_browser()
|
||
|
||
# 初始化脚本浏览器
|
||
self._refresh_script_browser()
|
||
|
||
self.accept('imgui-new-frame', self.__newFrame)
|
||
self.accept('`', self.__toggleImgui)
|
||
|
||
# 添加键盘事件监听用于快捷键
|
||
self.accept('control', self._on_ctrl_pressed)
|
||
self.accept('control-up', self._on_ctrl_released)
|
||
self.accept('alt', self._on_alt_pressed)
|
||
self.accept('alt-up', self._on_alt_released)
|
||
self.accept('n', self._on_n_pressed)
|
||
self.accept('o', self._on_o_pressed)
|
||
self.accept('control-s', self._on_save_project)
|
||
self.accept('f4', self._on_f4_pressed)
|
||
|
||
# 编辑功能快捷键
|
||
self.accept('control-z', self._on_undo)
|
||
self.accept('control-y', self._on_redo)
|
||
self.accept('control-x', self._on_cut)
|
||
self.accept('control-c', self._on_copy)
|
||
self.accept('control-v', self._on_paste)
|
||
self.accept('delete', self._on_delete_pressed)
|
||
self.accept('escape', self._on_escape_pressed)
|
||
|
||
# 滚轮事件
|
||
self.accept('wheel_up', self._on_wheel_up)
|
||
self.accept('wheel_down', self._on_wheel_down)
|
||
|
||
self.testTexture = None
|
||
self.icons = {} # 初始化图标字典
|
||
|
||
# 添加初始化消息
|
||
self.add_success_message("MyWorld 初始化完成")
|
||
self.add_info_message("ImGui菜单系统已就绪")
|
||
self.add_info_message("快捷键已启用 (Ctrl+N, Ctrl+O, Ctrl+S, Alt+F4)")
|
||
|
||
# 启用拖拽导入功能
|
||
self.setup_drag_drop_support()
|
||
self.add_info_message("拖拽导入功能已启用 - 可将3D文件拖拽到窗口中导入")
|
||
|
||
print("✓ MyWorld 初始化完成")
|
||
# print(f"[DEBUG] MyWorld 初始化完成,所有管理器已就绪")
|
||
# print(f"[DEBUG] 场景管理器: {hasattr(self, 'scene_manager')}")
|
||
# print(f"[DEBUG] 项目管理器: {hasattr(self, 'project_manager')}")
|
||
# print(f"[DEBUG] GUI管理器: {hasattr(self, 'gui_manager')}")
|
||
# print(f"[DEBUG] 脚本管理器: {hasattr(self, 'script_manager')}")
|
||
|
||
# ==================== 兼容性属性 ====================
|
||
|
||
# 保留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 onMouseClick(self):
|
||
"""处理鼠标点击事件"""
|
||
print("\n=== 鼠标点击事件触发 ===")
|
||
try:
|
||
# 检查鼠标是否有效
|
||
if not self.mouseWatcherNode.hasMouse():
|
||
print("❌ 鼠标无效或不在窗口内")
|
||
return
|
||
|
||
print("✓ 鼠标位置有效")
|
||
|
||
# 获取鼠标位置
|
||
mouse_x = self.mouseWatcherNode.getMouseX()
|
||
mouse_y = self.mouseWatcherNode.getMouseY()
|
||
print(f"📍 鼠标标准化坐标: ({mouse_x:.3f}, {mouse_y:.3f})")
|
||
|
||
# 转换为窗口坐标
|
||
winWidth, winHeight = self.win.getSize()
|
||
window_x = (mouse_x + 1) * 0.5 * winWidth
|
||
window_y = (1 - mouse_y) * 0.5 * winHeight
|
||
print(f"📍 鼠标窗口坐标: ({window_x:.1f}, {window_y:.1f})")
|
||
print(f"📐 窗口尺寸: {winWidth} x {winHeight}")
|
||
|
||
# 检查ImGui是否捕获了鼠标
|
||
imgui_captured = self.processImGuiMouseClick(window_x, window_y)
|
||
print(f"🖱️ ImGui捕获状态: {imgui_captured}")
|
||
if imgui_captured:
|
||
print("❌ ImGui处理了该事件,跳过3D场景选择")
|
||
return
|
||
|
||
# 调用事件处理器进行射线检测和选择
|
||
if hasattr(self, 'event_handler'):
|
||
print("✓ 找到事件处理器,开始处理选择")
|
||
self.event_handler.mousePressEventLeft({
|
||
'x': window_x,
|
||
'y': window_y
|
||
})
|
||
else:
|
||
print("❌ 未找到事件处理器")
|
||
|
||
except Exception as e:
|
||
print(f"❌ 处理鼠标点击事件失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def onMouseRelease(self):
|
||
"""处理鼠标释放事件"""
|
||
try:
|
||
# 检查鼠标是否有效
|
||
if not self.mouseWatcherNode.hasMouse():
|
||
return
|
||
|
||
# 获取鼠标位置
|
||
mouse_x = self.mouseWatcherNode.getMouseX()
|
||
mouse_y = self.mouseWatcherNode.getMouseY()
|
||
|
||
# 转换为窗口坐标
|
||
winWidth, winHeight = self.win.getSize()
|
||
window_x = (mouse_x + 1) * 0.5 * winWidth
|
||
window_y = (1 - mouse_y) * 0.5 * winHeight
|
||
|
||
# 调用事件处理器
|
||
if hasattr(self, 'event_handler'):
|
||
self.event_handler.mouseReleaseEventLeft({
|
||
'x': window_x,
|
||
'y': window_y
|
||
})
|
||
|
||
except Exception as e:
|
||
print(f"处理鼠标释放事件失败: {e}")
|
||
|
||
def onMouseMove(self):
|
||
"""处理鼠标移动事件"""
|
||
try:
|
||
# 检查鼠标是否有效
|
||
if not self.mouseWatcherNode.hasMouse():
|
||
return
|
||
|
||
# 获取鼠标位置
|
||
mouse_x = self.mouseWatcherNode.getMouseX()
|
||
mouse_y = self.mouseWatcherNode.getMouseY()
|
||
|
||
# 转换为窗口坐标
|
||
winWidth, winHeight = self.win.getSize()
|
||
window_x = (mouse_x + 1) * 0.5 * winWidth
|
||
window_y = (1 - mouse_y) * 0.5 * winHeight
|
||
|
||
# 调用事件处理器
|
||
if hasattr(self, 'event_handler'):
|
||
self.event_handler.mouseMoveEvent({
|
||
'x': window_x,
|
||
'y': window_y
|
||
})
|
||
|
||
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.
|
||
|
||
# 创建全屏DockSpace(在第一帧之后创建)
|
||
if imgui.get_frame_count() > 0:
|
||
viewport = imgui.get_main_viewport()
|
||
imgui.dock_space_over_viewport(0, viewport, imgui.DockNodeFlags_.passthru_central_node)
|
||
|
||
# 在第一帧应用样式
|
||
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'),
|
||
'property_select_image': self.style_manager.load_icon('property_select_image'),
|
||
'delete_fail_icon': self.style_manager.load_icon('delete_fail_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/opentype/noto/NotoSansCJK-Regular.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.add_font_from_file_ttf(font_path, 14.0)
|
||
print(f"✓ 中文字体加载成功: {font_path}")
|
||
else:
|
||
# 回退到原来的字体
|
||
fallback_font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
|
||
if fallback_font_path and Path(fallback_font_path).exists():
|
||
self.imgui.io.fonts.add_font_from_file_ttf(fallback_font_path, 14.0)
|
||
print(f"✓ 回退字体加载成功: {fallback_font_path}")
|
||
else:
|
||
self.imgui.io.fonts.add_font_default()
|
||
print("✓ 使用默认字体")
|
||
|
||
except Exception as e:
|
||
print(f"⚠ 字体初始化失败: {e}")
|
||
try:
|
||
self.imgui.io.fonts.add_font_default()
|
||
print("✓ 使用备用默认字体")
|
||
except:
|
||
pass
|
||
|
||
# 获取窗口尺寸
|
||
display_size = imgui.get_io().display_size
|
||
window_width = display_size.x
|
||
window_height = display_size.y
|
||
|
||
# 每帧重置窗口命中区域,由各面板绘制时重新填充
|
||
self._resource_manager_window_rect = None
|
||
self._resource_drop_targets = []
|
||
self._scene_tree_window_rect = None
|
||
self._property_panel_window_rect = None
|
||
self._script_panel_window_rect = None
|
||
self._console_window_rect = None
|
||
self._toolbar_window_rect = None
|
||
self._drag_scene_tree_hover_node = None
|
||
|
||
# 绘制菜单栏
|
||
self._draw_menu_bar()
|
||
|
||
# 绘制停靠布局
|
||
self._draw_docked_layout(window_width, window_height)
|
||
|
||
# 处理系统层外部拖入
|
||
self._process_external_drop_events()
|
||
|
||
# 绘制纹理测试窗口
|
||
if self.testTexture:
|
||
with self.style_manager.begin_styled_window("Texture Test", True,
|
||
imgui.WindowFlags_.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()
|
||
|
||
# 绘制对话框
|
||
self._draw_new_project_dialog()
|
||
self._draw_open_project_dialog()
|
||
self._draw_path_browser()
|
||
self._draw_import_dialog()
|
||
|
||
# 绘制颜色选择器
|
||
self._draw_color_picker()
|
||
|
||
# 绘制字体选择器
|
||
self._draw_font_selector()
|
||
|
||
# 绘制创建功能对话框
|
||
self._draw_3d_text_dialog()
|
||
self._draw_3d_image_dialog()
|
||
self._draw_gui_button_dialog()
|
||
self._draw_gui_label_dialog()
|
||
self._draw_gui_entry_dialog()
|
||
self._draw_gui_image_dialog()
|
||
self._draw_video_screen_dialog()
|
||
self._draw_2d_video_screen_dialog()
|
||
self._draw_spherical_video_dialog()
|
||
self._draw_virtual_screen_dialog()
|
||
self._draw_spot_light_dialog()
|
||
self._draw_point_light_dialog()
|
||
self._draw_terrain_dialog()
|
||
self._draw_heightmap_browser()
|
||
self._draw_script_dialog()
|
||
|
||
# 绘制纹理选择对话框
|
||
self._draw_texture_file_dialog()
|
||
self._draw_script_browser()
|
||
|
||
# 绘制右键菜单
|
||
self._draw_context_menus()
|
||
|
||
# 绘制拖拽界面
|
||
self._draw_drag_drop_interface()
|
||
|
||
# 绘制LUI编辑器
|
||
if self.showLUIEditor and hasattr(self, 'lui_manager'):
|
||
self.lui_manager.draw_editor()
|
||
|
||
# 更新变换监控
|
||
dt = imgui.get_io().delta_time
|
||
self.update_transform_monitoring(dt)
|
||
|
||
def _draw_docked_layout(self, window_width, window_height):
|
||
"""绘制可停靠的布局(支持拖拽)"""
|
||
# 左侧场景树面板
|
||
if self.showSceneTree:
|
||
self._draw_scene_tree()
|
||
|
||
# 资源管理器面板
|
||
if self.showResourceManager:
|
||
self._draw_resource_manager()
|
||
|
||
# 属性面板
|
||
if self.showPropertyPanel:
|
||
self._draw_property_panel()
|
||
|
||
# Web面板
|
||
if self.showWebPanel:
|
||
self._draw_web_panel()
|
||
|
||
# 脚本面板
|
||
if self.showScriptPanel:
|
||
self._draw_script_panel()
|
||
|
||
# 底部控制台
|
||
if self.showConsole:
|
||
self._draw_console()
|
||
|
||
# 顶部工具栏
|
||
if self.showToolbar:
|
||
self._draw_toolbar()
|
||
|
||
def _sync_rp_light_from_node(self, node):
|
||
"""将灯光包装节点的位置同步到 RenderPipeline 灯光对象。"""
|
||
try:
|
||
if not node or node.isEmpty() or (not node.hasPythonTag("rp_light_object")):
|
||
# 兼容旧场景:仅有 light_type 标签时尝试补绑 rp_light_object
|
||
if not node or node.isEmpty() or (not node.hasTag("light_type")):
|
||
return False
|
||
scene_manager = getattr(self, "scene_manager", None)
|
||
if scene_manager:
|
||
try:
|
||
light_type = node.getTag("light_type")
|
||
if light_type == "spot_light" and hasattr(scene_manager, "_recreateSpotLight"):
|
||
scene_manager._recreateSpotLight(node)
|
||
elif light_type == "point_light" and hasattr(scene_manager, "_recreatePointLight"):
|
||
scene_manager._recreatePointLight(node)
|
||
except Exception:
|
||
pass
|
||
light_obj = node.getPythonTag("rp_light_object") if node.hasPythonTag("rp_light_object") else None
|
||
if not light_obj:
|
||
return False
|
||
|
||
world_pos = node.getPos(self.render)
|
||
try:
|
||
light_obj.setPos(world_pos)
|
||
except Exception:
|
||
try:
|
||
light_obj.setPos(world_pos.x, world_pos.y, world_pos.z)
|
||
except Exception:
|
||
try:
|
||
light_obj.pos = Point3(world_pos)
|
||
except Exception:
|
||
return False
|
||
return True
|
||
except Exception:
|
||
return False
|
||
|
||
def _on_transform_gizmo_drag_event(self, payload):
|
||
"""TransformGizmo 拖拽事件回调:实时同步灯光位置。"""
|
||
try:
|
||
node = payload.get("target") if isinstance(payload, dict) else None
|
||
if node and (not node.isEmpty()):
|
||
self._sync_rp_light_from_node(node)
|
||
except Exception:
|
||
pass
|
||
|
||
def _setup_transform_gizmo_light_sync(self):
|
||
"""为 newTransform 注册灯光同步事件钩子。"""
|
||
tg = getattr(self, "newTransform", None)
|
||
if not tg:
|
||
return
|
||
try:
|
||
from TransformGizmo.events import GizmoEvent
|
||
hooks = {
|
||
"move": {
|
||
GizmoEvent.DRAG_MOVE: [self._on_transform_gizmo_drag_event],
|
||
GizmoEvent.DRAG_END: [self._on_transform_gizmo_drag_event],
|
||
},
|
||
"rotate": {
|
||
GizmoEvent.DRAG_MOVE: [self._on_transform_gizmo_drag_event],
|
||
GizmoEvent.DRAG_END: [self._on_transform_gizmo_drag_event],
|
||
},
|
||
"scale": {
|
||
GizmoEvent.DRAG_MOVE: [self._on_transform_gizmo_drag_event],
|
||
GizmoEvent.DRAG_END: [self._on_transform_gizmo_drag_event],
|
||
},
|
||
}
|
||
tg.set_event_hooks(hooks, replace=False)
|
||
except Exception as e:
|
||
print(f"绑定 TransformGizmo 灯光同步事件失败: {e}")
|
||
|
||
def _draw_menu_bar(self):
|
||
self.editor_panels.draw_menu_bar()
|
||
|
||
def _draw_toolbar(self):
|
||
self.editor_panels.draw_toolbar()
|
||
|
||
def _draw_scene_tree(self, *args, **kwargs):
|
||
return self.editor_panels._draw_scene_tree(*args, **kwargs)
|
||
|
||
def _build_scene_tree(self, *args, **kwargs):
|
||
return self.editor_panels._build_scene_tree(*args, **kwargs)
|
||
|
||
def _draw_scene_node(self, *args, **kwargs):
|
||
return self.editor_panels._draw_scene_node(*args, **kwargs)
|
||
|
||
def _show_node_context_menu(self, *args, **kwargs):
|
||
return self.editor_panels._show_node_context_menu(*args, **kwargs)
|
||
|
||
def _draw_resource_manager(self, *args, **kwargs):
|
||
return self.editor_panels._draw_resource_manager(*args, **kwargs)
|
||
|
||
def _draw_property_panel(self, *args, **kwargs):
|
||
return self.editor_panels._draw_property_panel(*args, **kwargs)
|
||
|
||
def _draw_web_panel(self, *args, **kwargs):
|
||
return self.editor_panels._draw_web_panel(*args, **kwargs)
|
||
|
||
def _draw_node_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_node_properties(*args, **kwargs)
|
||
|
||
def _getActor(self, *args, **kwargs):
|
||
return self.animation_tools._getActor(*args, **kwargs)
|
||
|
||
def _getModelFormat(self, *args, **kwargs):
|
||
return self.animation_tools._getModelFormat(*args, **kwargs)
|
||
|
||
def _processAnimationNames(self, *args, **kwargs):
|
||
return self.animation_tools._processAnimationNames(*args, **kwargs)
|
||
|
||
def _isLikelyBoneGroup(self, *args, **kwargs):
|
||
return self.animation_tools._isLikelyBoneGroup(*args, **kwargs)
|
||
|
||
def _analyzeAnimationQuality(self, *args, **kwargs):
|
||
return self.animation_tools._analyzeAnimationQuality(*args, **kwargs)
|
||
|
||
def _playAnimation(self, *args, **kwargs):
|
||
return self.animation_tools._playAnimation(*args, **kwargs)
|
||
|
||
def _pauseAnimation(self, *args, **kwargs):
|
||
return self.animation_tools._pauseAnimation(*args, **kwargs)
|
||
|
||
def _stopAnimation(self, *args, **kwargs):
|
||
return self.animation_tools._stopAnimation(*args, **kwargs)
|
||
|
||
def _loopAnimation(self, *args, **kwargs):
|
||
return self.animation_tools._loopAnimation(*args, **kwargs)
|
||
|
||
def _setAnimationSpeed(self, *args, **kwargs):
|
||
return self.animation_tools._setAnimationSpeed(*args, **kwargs)
|
||
|
||
def _clear_animation_cache(self, *args, **kwargs):
|
||
return self.animation_tools._clear_animation_cache(*args, **kwargs)
|
||
def _get_node_type_from_node(self, node):
|
||
"""从节点判断其类型"""
|
||
# 检查是否为GUI元素
|
||
if hasattr(node, 'getPythonTag') and node.getPythonTag('gui_element'):
|
||
return "GUI元素"
|
||
|
||
# 检查是否为光源
|
||
node_name = node.getName() or ""
|
||
if "light" in node_name.lower() or "Light" in node_name:
|
||
return "光源"
|
||
|
||
# 检查是否为相机
|
||
if "camera" in node_name.lower() or "Camera" in node_name:
|
||
return "相机"
|
||
|
||
# 检查是否为模型
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
if hasattr(self.scene_manager, 'models') and node in self.scene_manager.models:
|
||
return "模型"
|
||
|
||
# 默认为几何体
|
||
return "几何体"
|
||
|
||
def _draw_status_badges(self, *args, **kwargs):
|
||
return self.editor_panels._draw_status_badges(*args, **kwargs)
|
||
|
||
def _draw_transform_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_transform_properties(*args, **kwargs)
|
||
|
||
def _draw_gui_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_gui_properties(*args, **kwargs)
|
||
|
||
def _draw_light_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_light_properties(*args, **kwargs)
|
||
|
||
def _draw_model_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_model_properties(*args, **kwargs)
|
||
|
||
def _draw_animation_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_animation_properties(*args, **kwargs)
|
||
|
||
def _draw_collision_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_collision_properties(*args, **kwargs)
|
||
|
||
def _draw_shape_specific_parameters(self, *args, **kwargs):
|
||
return self.editor_panels._draw_shape_specific_parameters(*args, **kwargs)
|
||
|
||
def _draw_sphere_parameters(self, *args, **kwargs):
|
||
return self.editor_panels._draw_sphere_parameters(*args, **kwargs)
|
||
|
||
def _draw_box_parameters(self, *args, **kwargs):
|
||
return self.editor_panels._draw_box_parameters(*args, **kwargs)
|
||
|
||
def _draw_capsule_parameters(self, *args, **kwargs):
|
||
return self.editor_panels._draw_capsule_parameters(*args, **kwargs)
|
||
|
||
def _draw_plane_parameters(self, *args, **kwargs):
|
||
return self.editor_panels._draw_plane_parameters(*args, **kwargs)
|
||
|
||
def _draw_property_actions(self, *args, **kwargs):
|
||
return self.editor_panels._draw_property_actions(*args, **kwargs)
|
||
|
||
def _draw_appearance_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_appearance_properties(*args, **kwargs)
|
||
|
||
def _draw_material_properties(self, *args, **kwargs):
|
||
return self.editor_panels._draw_material_properties(*args, **kwargs)
|
||
|
||
def _draw_shading_model_panel(self, *args, **kwargs):
|
||
return self.editor_panels._draw_shading_model_panel(*args, **kwargs)
|
||
|
||
|
||
def _apply_gui_font(self, *args, **kwargs):
|
||
return self.property_helpers._apply_gui_font(*args, **kwargs)
|
||
|
||
def _apply_gui_font_size(self, *args, **kwargs):
|
||
return self.property_helpers._apply_gui_font_size(*args, **kwargs)
|
||
|
||
def _apply_gui_font_style(self, *args, **kwargs):
|
||
return self.property_helpers._apply_gui_font_style(*args, **kwargs)
|
||
|
||
def _has_collision(self, *args, **kwargs):
|
||
return self.property_helpers._has_collision(*args, **kwargs)
|
||
|
||
def _get_current_collision_shape(self, *args, **kwargs):
|
||
return self.property_helpers._get_current_collision_shape(*args, **kwargs)
|
||
|
||
def _get_current_collision_shape_type(self, *args, **kwargs):
|
||
return self.property_helpers._get_current_collision_shape_type(*args, **kwargs)
|
||
|
||
def _get_collision_position_offset(self, *args, **kwargs):
|
||
return self.property_helpers._get_collision_position_offset(*args, **kwargs)
|
||
|
||
def _is_collision_visible(self, *args, **kwargs):
|
||
return self.property_helpers._is_collision_visible(*args, **kwargs)
|
||
|
||
def _add_collision_to_node(self, *args, **kwargs):
|
||
return self.property_helpers._add_collision_to_node(*args, **kwargs)
|
||
|
||
def _remove_collision_from_node(self, *args, **kwargs):
|
||
return self.property_helpers._remove_collision_from_node(*args, **kwargs)
|
||
|
||
def _toggle_collision_visibility(self, *args, **kwargs):
|
||
return self.property_helpers._toggle_collision_visibility(*args, **kwargs)
|
||
|
||
def _update_collision_position(self, *args, **kwargs):
|
||
return self.property_helpers._update_collision_position(*args, **kwargs)
|
||
|
||
def _get_shape_type_from_name(self, *args, **kwargs):
|
||
return self.property_helpers._get_shape_type_from_name(*args, **kwargs)
|
||
|
||
def _get_sphere_radius(self, *args, **kwargs):
|
||
return self.property_helpers._get_sphere_radius(*args, **kwargs)
|
||
|
||
def _update_sphere_radius(self, *args, **kwargs):
|
||
return self.property_helpers._update_sphere_radius(*args, **kwargs)
|
||
|
||
def _get_box_size(self, *args, **kwargs):
|
||
return self.property_helpers._get_box_size(*args, **kwargs)
|
||
|
||
def _update_box_size(self, *args, **kwargs):
|
||
return self.property_helpers._update_box_size(*args, **kwargs)
|
||
|
||
def _get_capsule_radius(self, *args, **kwargs):
|
||
return self.property_helpers._get_capsule_radius(*args, **kwargs)
|
||
|
||
def _update_capsule_radius(self, *args, **kwargs):
|
||
return self.property_helpers._update_capsule_radius(*args, **kwargs)
|
||
|
||
def _get_capsule_height(self, *args, **kwargs):
|
||
return self.property_helpers._get_capsule_height(*args, **kwargs)
|
||
|
||
def _update_capsule_height(self, *args, **kwargs):
|
||
return self.property_helpers._update_capsule_height(*args, **kwargs)
|
||
|
||
def _get_plane_normal(self, *args, **kwargs):
|
||
return self.property_helpers._get_plane_normal(*args, **kwargs)
|
||
|
||
def _update_plane_normal(self, *args, **kwargs):
|
||
return self.property_helpers._update_plane_normal(*args, **kwargs)
|
||
|
||
def _manual_collision_detection(self, *args, **kwargs):
|
||
return self.property_helpers._manual_collision_detection(*args, **kwargs)
|
||
|
||
def _update_node_name(self, *args, **kwargs):
|
||
return self.property_helpers._update_node_name(*args, **kwargs)
|
||
|
||
def _get_material_base_color(self, *args, **kwargs):
|
||
return self.property_helpers._get_material_base_color(*args, **kwargs)
|
||
|
||
def _update_material_base_color(self, *args, **kwargs):
|
||
return self.property_helpers._update_material_base_color(*args, **kwargs)
|
||
|
||
def _update_material_roughness(self, *args, **kwargs):
|
||
return self.property_helpers._update_material_roughness(*args, **kwargs)
|
||
|
||
def _update_material_metallic(self, *args, **kwargs):
|
||
return self.property_helpers._update_material_metallic(*args, **kwargs)
|
||
|
||
def _update_material_ior(self, *args, **kwargs):
|
||
return self.property_helpers._update_material_ior(*args, **kwargs)
|
||
|
||
def _apply_material_preset(self, *args, **kwargs):
|
||
return self.property_helpers._apply_material_preset(*args, **kwargs)
|
||
|
||
def _apply_material_to_node(self, *args, **kwargs):
|
||
return self.property_helpers._apply_material_to_node(*args, **kwargs)
|
||
|
||
def _reset_material(self, *args, **kwargs):
|
||
return self.property_helpers._reset_material(*args, **kwargs)
|
||
|
||
def _select_texture_for_material(self, *args, **kwargs):
|
||
return self.property_helpers._select_texture_for_material(*args, **kwargs)
|
||
|
||
def _apply_texture_to_material(self, *args, **kwargs):
|
||
return self.property_helpers._apply_texture_to_material(*args, **kwargs)
|
||
|
||
def _clear_all_textures(self, *args, **kwargs):
|
||
return self.property_helpers._clear_all_textures(*args, **kwargs)
|
||
|
||
def _display_current_textures(self, *args, **kwargs):
|
||
return self.property_helpers._display_current_textures(*args, **kwargs)
|
||
|
||
def _update_shading_model(self, *args, **kwargs):
|
||
return self.property_helpers._update_shading_model(*args, **kwargs)
|
||
|
||
def _update_transparency(self, *args, **kwargs):
|
||
return self.property_helpers._update_transparency(*args, **kwargs)
|
||
|
||
def _draw_texture_file_dialog(self, *args, **kwargs):
|
||
return self.property_helpers._draw_texture_file_dialog(*args, **kwargs)
|
||
|
||
def start_transform_monitoring(self, *args, **kwargs):
|
||
return self.property_helpers.start_transform_monitoring(*args, **kwargs)
|
||
|
||
def stop_transform_monitoring(self, *args, **kwargs):
|
||
return self.property_helpers.stop_transform_monitoring(*args, **kwargs)
|
||
|
||
def _update_last_transform_values(self, *args, **kwargs):
|
||
return self.property_helpers._update_last_transform_values(*args, **kwargs)
|
||
|
||
def _check_transform_changes(self, *args, **kwargs):
|
||
return self.property_helpers._check_transform_changes(*args, **kwargs)
|
||
|
||
def update_transform_monitoring(self, *args, **kwargs):
|
||
return self.property_helpers.update_transform_monitoring(*args, **kwargs)
|
||
|
||
def show_color_picker(self, *args, **kwargs):
|
||
return self.property_helpers.show_color_picker(*args, **kwargs)
|
||
|
||
def _draw_color_picker(self, *args, **kwargs):
|
||
return self.property_helpers._draw_color_picker(*args, **kwargs)
|
||
|
||
def _apply_color_selection(self, *args, **kwargs):
|
||
return self.property_helpers._apply_color_selection(*args, **kwargs)
|
||
|
||
def _draw_color_button(self, *args, **kwargs):
|
||
return self.property_helpers._draw_color_button(*args, **kwargs)
|
||
|
||
def _refresh_available_fonts(self, *args, **kwargs):
|
||
return self.property_helpers._refresh_available_fonts(*args, **kwargs)
|
||
|
||
def show_font_selector(self, *args, **kwargs):
|
||
return self.property_helpers.show_font_selector(*args, **kwargs)
|
||
|
||
def _draw_font_selector(self, *args, **kwargs):
|
||
return self.property_helpers._draw_font_selector(*args, **kwargs)
|
||
|
||
def _apply_font_selection(self, *args, **kwargs):
|
||
return self.property_helpers._apply_font_selection(*args, **kwargs)
|
||
|
||
def _draw_font_selector_button(self, *args, **kwargs):
|
||
return self.property_helpers._draw_font_selector_button(*args, **kwargs)
|
||
def _draw_console(self, *args, **kwargs):
|
||
return self.script_panels._draw_console(*args, **kwargs)
|
||
|
||
def _draw_script_panel(self, *args, **kwargs):
|
||
return self.script_panels._draw_script_panel(*args, **kwargs)
|
||
|
||
def _draw_script_status_group(self, *args, **kwargs):
|
||
return self.script_panels._draw_script_status_group(*args, **kwargs)
|
||
|
||
def _draw_create_script_group(self, *args, **kwargs):
|
||
return self.script_panels._draw_create_script_group(*args, **kwargs)
|
||
|
||
def _draw_available_scripts_group(self, *args, **kwargs):
|
||
return self.script_panels._draw_available_scripts_group(*args, **kwargs)
|
||
|
||
def _draw_script_mounting_group(self, *args, **kwargs):
|
||
return self.script_panels._draw_script_mounting_group(*args, **kwargs)
|
||
|
||
|
||
def _toggle_hot_reload(self, *args, **kwargs):
|
||
return self.app_actions._toggle_hot_reload(*args, **kwargs)
|
||
|
||
def _create_new_script(self, *args, **kwargs):
|
||
return self.app_actions._create_new_script(*args, **kwargs)
|
||
|
||
def _refresh_scripts_list(self, *args, **kwargs):
|
||
return self.app_actions._refresh_scripts_list(*args, **kwargs)
|
||
|
||
def _reload_all_scripts(self, *args, **kwargs):
|
||
return self.app_actions._reload_all_scripts(*args, **kwargs)
|
||
|
||
def _on_script_selected(self, *args, **kwargs):
|
||
return self.app_actions._on_script_selected(*args, **kwargs)
|
||
|
||
def _edit_script(self, *args, **kwargs):
|
||
return self.app_actions._edit_script(*args, **kwargs)
|
||
|
||
def _mount_script_to_selected(self, *args, **kwargs):
|
||
return self.app_actions._mount_script_to_selected(*args, **kwargs)
|
||
|
||
def _unmount_script_from_selected(self, *args, **kwargs):
|
||
return self.app_actions._unmount_script_from_selected(*args, **kwargs)
|
||
|
||
def _on_new_project(self, *args, **kwargs):
|
||
return self.app_actions._on_new_project(*args, **kwargs)
|
||
|
||
def _on_open_project(self, *args, **kwargs):
|
||
return self.app_actions._on_open_project(*args, **kwargs)
|
||
|
||
def _on_save_project(self, *args, **kwargs):
|
||
return self.app_actions._on_save_project(*args, **kwargs)
|
||
|
||
def _on_save_as_project(self, *args, **kwargs):
|
||
return self.app_actions._on_save_as_project(*args, **kwargs)
|
||
|
||
def _on_exit(self, *args, **kwargs):
|
||
return self.app_actions._on_exit(*args, **kwargs)
|
||
|
||
def _on_ctrl_pressed(self, *args, **kwargs):
|
||
return self.app_actions._on_ctrl_pressed(*args, **kwargs)
|
||
|
||
def _on_ctrl_released(self, *args, **kwargs):
|
||
return self.app_actions._on_ctrl_released(*args, **kwargs)
|
||
|
||
def _on_alt_pressed(self, *args, **kwargs):
|
||
return self.app_actions._on_alt_pressed(*args, **kwargs)
|
||
|
||
def _on_alt_released(self, *args, **kwargs):
|
||
return self.app_actions._on_alt_released(*args, **kwargs)
|
||
|
||
def _on_n_pressed(self, *args, **kwargs):
|
||
return self.app_actions._on_n_pressed(*args, **kwargs)
|
||
|
||
def _on_o_pressed(self, *args, **kwargs):
|
||
return self.app_actions._on_o_pressed(*args, **kwargs)
|
||
|
||
def _on_f4_pressed(self, *args, **kwargs):
|
||
return self.app_actions._on_f4_pressed(*args, **kwargs)
|
||
|
||
def _on_delete_pressed(self, *args, **kwargs):
|
||
return self.app_actions._on_delete_pressed(*args, **kwargs)
|
||
|
||
def _on_escape_pressed(self, *args, **kwargs):
|
||
return self.app_actions._on_escape_pressed(*args, **kwargs)
|
||
|
||
def _on_wheel_up(self, *args, **kwargs):
|
||
return self.app_actions._on_wheel_up(*args, **kwargs)
|
||
|
||
def _on_wheel_down(self, *args, **kwargs):
|
||
return self.app_actions._on_wheel_down(*args, **kwargs)
|
||
|
||
def _is_mouse_over_imgui(self, *args, **kwargs):
|
||
return self.app_actions._is_mouse_over_imgui(*args, **kwargs)
|
||
|
||
def processImGuiMouseClick(self, *args, **kwargs):
|
||
return self.app_actions.processImGuiMouseClick(*args, **kwargs)
|
||
|
||
def add_message(self, *args, **kwargs):
|
||
return self.app_actions.add_message(*args, **kwargs)
|
||
|
||
def add_success_message(self, *args, **kwargs):
|
||
return self.app_actions.add_success_message(*args, **kwargs)
|
||
|
||
def add_error_message(self, *args, **kwargs):
|
||
return self.app_actions.add_error_message(*args, **kwargs)
|
||
|
||
def add_warning_message(self, *args, **kwargs):
|
||
return self.app_actions.add_warning_message(*args, **kwargs)
|
||
|
||
def add_info_message(self, *args, **kwargs):
|
||
return self.app_actions.add_info_message(*args, **kwargs)
|
||
|
||
def _on_undo(self, *args, **kwargs):
|
||
return self.app_actions._on_undo(*args, **kwargs)
|
||
|
||
def _on_redo(self, *args, **kwargs):
|
||
return self.app_actions._on_redo(*args, **kwargs)
|
||
|
||
def _on_copy(self, *args, **kwargs):
|
||
return self.app_actions._on_copy(*args, **kwargs)
|
||
|
||
def _on_cut(self, *args, **kwargs):
|
||
return self.app_actions._on_cut(*args, **kwargs)
|
||
|
||
def _on_paste(self, *args, **kwargs):
|
||
return self.app_actions._on_paste(*args, **kwargs)
|
||
|
||
def _on_delete(self, *args, **kwargs):
|
||
return self.app_actions._on_delete(*args, **kwargs)
|
||
|
||
def _delete_node(self, *args, **kwargs):
|
||
return self.app_actions._delete_node(*args, **kwargs)
|
||
|
||
def _perform_node_cleanup(self, *args, **kwargs):
|
||
return self.app_actions._perform_node_cleanup(*args, **kwargs)
|
||
|
||
def _create_new_project(self, *args, **kwargs):
|
||
return self.app_actions._create_new_project(*args, **kwargs)
|
||
|
||
def _open_project_path(self, *args, **kwargs):
|
||
return self.app_actions._open_project_path(*args, **kwargs)
|
||
|
||
def _save_project_impl(self, *args, **kwargs):
|
||
return self.app_actions._save_project_impl(*args, **kwargs)
|
||
|
||
def _open_project_impl(self, *args, **kwargs):
|
||
return self.app_actions._open_project_impl(*args, **kwargs)
|
||
|
||
def _create_new_project_impl(self, *args, **kwargs):
|
||
return self.app_actions._create_new_project_impl(*args, **kwargs)
|
||
|
||
def _update_window_title(self, *args, **kwargs):
|
||
return self.app_actions._update_window_title(*args, **kwargs)
|
||
|
||
def _import_model_for_runtime(self, *args, **kwargs):
|
||
return self.app_actions._import_model_for_runtime(*args, **kwargs)
|
||
|
||
def _on_import_model(self, *args, **kwargs):
|
||
return self.app_actions._on_import_model(*args, **kwargs)
|
||
|
||
def _import_model(self, *args, **kwargs):
|
||
return self.app_actions._import_model(*args, **kwargs)
|
||
|
||
def _import_model_with_menu_logic(self, *args, **kwargs):
|
||
return self.app_actions._import_model_with_menu_logic(*args, **kwargs)
|
||
|
||
def _draw_new_project_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_new_project_dialog(*args, **kwargs)
|
||
|
||
def _draw_open_project_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_open_project_dialog(*args, **kwargs)
|
||
|
||
def _draw_path_browser(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_path_browser(*args, **kwargs)
|
||
|
||
def _draw_import_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_import_dialog(*args, **kwargs)
|
||
|
||
def _refresh_path_browser(self, *args, **kwargs):
|
||
return self.dialog_panels._refresh_path_browser(*args, **kwargs)
|
||
|
||
def _apply_selected_path(self, *args, **kwargs):
|
||
return self.dialog_panels._apply_selected_path(*args, **kwargs)
|
||
|
||
def _draw_gui_button_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_gui_button_dialog(*args, **kwargs)
|
||
|
||
def _draw_gui_label_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_gui_label_dialog(*args, **kwargs)
|
||
|
||
def _draw_gui_entry_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_gui_entry_dialog(*args, **kwargs)
|
||
|
||
def _draw_gui_image_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_gui_image_dialog(*args, **kwargs)
|
||
|
||
def _draw_3d_text_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_3d_text_dialog(*args, **kwargs)
|
||
|
||
def _draw_3d_image_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_3d_image_dialog(*args, **kwargs)
|
||
|
||
def _draw_video_screen_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_video_screen_dialog(*args, **kwargs)
|
||
|
||
def _draw_2d_video_screen_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_2d_video_screen_dialog(*args, **kwargs)
|
||
|
||
def _draw_spherical_video_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_spherical_video_dialog(*args, **kwargs)
|
||
|
||
def _draw_virtual_screen_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_virtual_screen_dialog(*args, **kwargs)
|
||
|
||
def _draw_spot_light_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_spot_light_dialog(*args, **kwargs)
|
||
|
||
def _draw_point_light_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_point_light_dialog(*args, **kwargs)
|
||
|
||
def _draw_terrain_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_terrain_dialog(*args, **kwargs)
|
||
|
||
def _draw_script_dialog(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_script_dialog(*args, **kwargs)
|
||
|
||
def _draw_script_browser(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_script_browser(*args, **kwargs)
|
||
|
||
def _refresh_script_browser(self, *args, **kwargs):
|
||
return self.dialog_panels._refresh_script_browser(*args, **kwargs)
|
||
|
||
def _draw_heightmap_browser(self, *args, **kwargs):
|
||
return self.dialog_panels._draw_heightmap_browser(*args, **kwargs)
|
||
|
||
def _refresh_heightmap_browser(self, *args, **kwargs):
|
||
return self.dialog_panels._refresh_heightmap_browser(*args, **kwargs)
|
||
|
||
def setup_drag_drop_support(self):
|
||
"""初始化拖拽支持。"""
|
||
return self.model_drag_drop.setup_drag_drop_support()
|
||
|
||
def _is_point_in_resource_manager(self, drop_pos):
|
||
"""判断投放坐标是否命中资源管理器窗口。"""
|
||
return self.model_drag_drop.is_point_in_resource_manager(drop_pos)
|
||
|
||
def _resolve_resource_drop_target_dir(self, drop_pos):
|
||
"""根据投放坐标解析资源管理器中的目标目录。"""
|
||
return self.model_drag_drop.resolve_resource_drop_target_dir(drop_pos)
|
||
|
||
def _process_external_drop_events(self):
|
||
"""处理外部拖入(系统文件拖拽)事件。"""
|
||
return self.model_drag_drop.process_external_drop_events()
|
||
|
||
def _handle_external_drop(self, file_paths, drop_pos=None):
|
||
"""把外部拖入文件分发到资源管理器或场景。"""
|
||
return self.model_drag_drop.handle_external_drop(file_paths, drop_pos)
|
||
|
||
def add_dragged_file(self, file_path):
|
||
"""添加拖拽的文件"""
|
||
return self.model_drag_drop.add_dragged_file(file_path)
|
||
|
||
def clear_dragged_files(self):
|
||
"""清空拖拽文件列表"""
|
||
return self.model_drag_drop.clear_dragged_files()
|
||
|
||
def process_dragged_files(self):
|
||
"""处理拖拽的文件"""
|
||
return self.model_drag_drop.process_dragged_files()
|
||
|
||
def _import_model_from_path(self, file_path):
|
||
"""从路径导入模型的内部方法"""
|
||
return self.model_drag_drop.import_model_from_path(file_path)
|
||
|
||
def _draw_drag_drop_interface(self, *args, **kwargs):
|
||
return self.interaction_panels._draw_drag_drop_interface(*args, **kwargs)
|
||
|
||
def _handle_drag_drop_completion(self, *args, **kwargs):
|
||
return self.interaction_panels._handle_drag_drop_completion(*args, **kwargs)
|
||
|
||
def _draw_drag_overlay(self, *args, **kwargs):
|
||
return self.interaction_panels._draw_drag_overlay(*args, **kwargs)
|
||
|
||
def _draw_drag_status(self, *args, **kwargs):
|
||
return self.interaction_panels._draw_drag_status(*args, **kwargs)
|
||
|
||
def _draw_context_menus(self, *args, **kwargs):
|
||
return self.interaction_panels._draw_context_menus(*args, **kwargs)
|
||
|
||
def _delete_node_simple(self, *args, **kwargs):
|
||
return self.interaction_panels._delete_node_simple(*args, **kwargs)
|
||
|
||
def _copy_node(self, *args, **kwargs):
|
||
return self.interaction_panels._copy_node(*args, **kwargs)
|
||
|
||
|
||
def _on_create_empty_object(self, *args, **kwargs):
|
||
return self.create_actions._on_create_empty_object(*args, **kwargs)
|
||
|
||
def _on_create_cube(self, *args, **kwargs):
|
||
return self.create_actions._on_create_cube(*args, **kwargs)
|
||
|
||
def _on_create_sphere(self, *args, **kwargs):
|
||
return self.create_actions._on_create_sphere(*args, **kwargs)
|
||
|
||
def _on_create_cylinder(self, *args, **kwargs):
|
||
return self.create_actions._on_create_cylinder(*args, **kwargs)
|
||
|
||
def _on_create_plane(self, *args, **kwargs):
|
||
return self.create_actions._on_create_plane(*args, **kwargs)
|
||
|
||
def _on_create_3d_text(self, *args, **kwargs):
|
||
return self.create_actions._on_create_3d_text(*args, **kwargs)
|
||
|
||
def _on_create_3d_image(self, *args, **kwargs):
|
||
return self.create_actions._on_create_3d_image(*args, **kwargs)
|
||
|
||
def _on_create_gui_button(self, *args, **kwargs):
|
||
return self.create_actions._on_create_gui_button(*args, **kwargs)
|
||
|
||
def _on_create_gui_label(self, *args, **kwargs):
|
||
return self.create_actions._on_create_gui_label(*args, **kwargs)
|
||
|
||
def _on_create_gui_entry(self, *args, **kwargs):
|
||
return self.create_actions._on_create_gui_entry(*args, **kwargs)
|
||
|
||
def _on_create_gui_image(self, *args, **kwargs):
|
||
return self.create_actions._on_create_gui_image(*args, **kwargs)
|
||
|
||
def _on_create_video_screen(self, *args, **kwargs):
|
||
return self.create_actions._on_create_video_screen(*args, **kwargs)
|
||
|
||
def _on_create_2d_video_screen(self, *args, **kwargs):
|
||
return self.create_actions._on_create_2d_video_screen(*args, **kwargs)
|
||
|
||
def _on_create_spherical_video(self, *args, **kwargs):
|
||
return self.create_actions._on_create_spherical_video(*args, **kwargs)
|
||
|
||
def _on_create_virtual_screen(self, *args, **kwargs):
|
||
return self.create_actions._on_create_virtual_screen(*args, **kwargs)
|
||
|
||
def _on_create_spot_light(self, *args, **kwargs):
|
||
return self.create_actions._on_create_spot_light(*args, **kwargs)
|
||
|
||
def _on_create_point_light(self, *args, **kwargs):
|
||
return self.create_actions._on_create_point_light(*args, **kwargs)
|
||
|
||
def _on_create_flat_terrain(self, *args, **kwargs):
|
||
return self.create_actions._on_create_flat_terrain(*args, **kwargs)
|
||
|
||
def _on_create_heightmap_terrain(self, *args, **kwargs):
|
||
return self.create_actions._on_create_heightmap_terrain(*args, **kwargs)
|
||
|
||
def _on_create_script(self, *args, **kwargs):
|
||
return self.create_actions._on_create_script(*args, **kwargs)
|
||
|
||
def _on_load_script(self, *args, **kwargs):
|
||
return self.create_actions._on_load_script(*args, **kwargs)
|
||
|
||
def _on_reload_all_scripts(self, *args, **kwargs):
|
||
return self.create_actions._on_reload_all_scripts(*args, **kwargs)
|
||
|
||
def _on_open_scripts_manager(self, *args, **kwargs):
|
||
return self.create_actions._on_open_scripts_manager(*args, **kwargs)
|
||
|
||
def _on_create_2d_sample_panel(self, *args, **kwargs):
|
||
return self.create_actions._on_create_2d_sample_panel(*args, **kwargs)
|
||
|
||
def _on_create_3d_sample_panel(self, *args, **kwargs):
|
||
return self.create_actions._on_create_3d_sample_panel(*args, **kwargs)
|
||
|
||
def _on_create_web_panel(self, *args, **kwargs):
|
||
return self.create_actions._on_create_web_panel(*args, **kwargs)
|
||
|
||
|
||
def createEmptyObject(self, *args, **kwargs):
|
||
return self.object_factory.createEmptyObject(*args, **kwargs)
|
||
|
||
def create3DText(self, *args, **kwargs):
|
||
return self.object_factory.create3DText(*args, **kwargs)
|
||
|
||
def create3DImage(self, *args, **kwargs):
|
||
return self.object_factory.create3DImage(*args, **kwargs)
|
||
|
||
def createCube(self, *args, **kwargs):
|
||
return self.object_factory.createCube(*args, **kwargs)
|
||
|
||
def createSphere(self, *args, **kwargs):
|
||
return self.object_factory.createSphere(*args, **kwargs)
|
||
|
||
def createCylinder(self, *args, **kwargs):
|
||
return self.object_factory.createCylinder(*args, **kwargs)
|
||
|
||
def createPlane(self, *args, **kwargs):
|
||
return self.object_factory.createPlane(*args, **kwargs)
|
||
|
||
def create2DSamplePanel(self, *args, **kwargs):
|
||
return self.object_factory.create2DSamplePanel(*args, **kwargs)
|
||
|
||
def create3DSamplePanel(self, *args, **kwargs):
|
||
return self.object_factory.create3DSamplePanel(*args, **kwargs)
|
||
|
||
def createWebPanel(self, *args, **kwargs):
|
||
return self.object_factory.createWebPanel(*args, **kwargs)
|
||
def createGUIButton(self, pos=(0, 0, 0), text="按钮", size=0.1):
|
||
"""创建2D GUI按钮"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
# 使用简化的创建方法,不依赖QT树形控件
|
||
return self._create_simple_gui_button(pos, text, size)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建GUI按钮失败: {e}")
|
||
return None
|
||
|
||
def _create_simple_gui_button(self, pos=(0, 0, 0), text="按钮", size=0.1):
|
||
"""创建简单的GUI按钮,不依赖QT树形控件"""
|
||
try:
|
||
from direct.gui.DirectGui import DirectButton
|
||
from panda3d.core import TextNode
|
||
|
||
# 转换坐标系统
|
||
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1)
|
||
|
||
# 设置中文字体
|
||
font = self._get_chinese_font()
|
||
|
||
# 处理scale参数
|
||
if isinstance(size, (list, tuple)) and len(size) >= 2:
|
||
scale_value = size[0] # 使用宽度作为缩放值
|
||
else:
|
||
scale_value = size
|
||
|
||
# 创建按钮
|
||
button = DirectButton(
|
||
text=text,
|
||
pos=gui_pos,
|
||
scale=scale_value,
|
||
text_font=font,
|
||
command=self._on_gui_button_click
|
||
)
|
||
|
||
# 创建包装对象
|
||
button_wrapper = type('GUIElement', (), {})()
|
||
button_wrapper.node = button
|
||
button_wrapper.name = text
|
||
button_wrapper.gui_type = "GUI_BUTTON"
|
||
button_wrapper.position = pos
|
||
button_wrapper.size = size
|
||
|
||
# 添加到GUI管理器
|
||
self.gui_manager.gui_elements.append(button_wrapper)
|
||
|
||
print(f"✓ GUI按钮创建成功: {text}")
|
||
return button_wrapper
|
||
except Exception as e:
|
||
print(f"✗ 创建简单GUI按钮失败: {e}")
|
||
return None
|
||
|
||
def _on_gui_button_click(self):
|
||
"""GUI按钮点击事件处理"""
|
||
print("GUI按钮被点击了")
|
||
|
||
def _toggle_vr_mode(self):
|
||
"""切换VR模式"""
|
||
if self.vr_manager:
|
||
if self.vr_manager.is_enabled():
|
||
self._exit_vr_mode()
|
||
else:
|
||
self.vr_manager.enable()
|
||
self.add_info_message("已进入VR模式")
|
||
else:
|
||
self.add_error_message("VR管理器未初始化")
|
||
|
||
def _exit_vr_mode(self):
|
||
"""退出VR模式"""
|
||
if self.vr_manager:
|
||
self.vr_manager.disable()
|
||
self.add_info_message("已退出VR模式")
|
||
|
||
def _show_vr_status(self):
|
||
"""显示VR状态"""
|
||
if self.vr_manager:
|
||
status = "已启用" if self.vr_manager.is_enabled() else "未启用"
|
||
self.add_info_message(f"VR状态: {status}")
|
||
|
||
# 显示设备信息
|
||
if self.vr_manager.is_enabled():
|
||
devices = self.vr_manager.get_connected_devices()
|
||
if devices:
|
||
self.add_info_message(f"连接的设备: {', '.join(devices)}")
|
||
else:
|
||
self.add_info_message("未检测到VR设备")
|
||
else:
|
||
self.add_error_message("VR管理器未初始化")
|
||
|
||
def _show_vr_settings(self):
|
||
"""显示VR设置"""
|
||
if self.vr_manager:
|
||
self.add_info_message("VR设置对话框待实现")
|
||
else:
|
||
self.add_error_message("VR管理器未初始化")
|
||
|
||
def _show_vr_performance_report(self):
|
||
"""显示VR性能报告"""
|
||
if self.vr_manager and self.vr_manager.is_enabled():
|
||
report = self.vr_manager.get_performance_report()
|
||
self.add_info_message(f"VR性能报告: {report}")
|
||
else:
|
||
self.add_info_message("VR未启用或管理器未初始化")
|
||
|
||
def _get_chinese_font(self):
|
||
"""获取中文字体"""
|
||
try:
|
||
from panda3d.core import TextNode
|
||
import os
|
||
from pathlib import Path
|
||
|
||
# 尝试加载中文字体
|
||
font_paths = [
|
||
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc", # Linux文泉驿微米黑
|
||
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", # Noto Sans CJK
|
||
"/System/Library/Fonts/PingFang.ttc", # macOS
|
||
"C:/Windows/Fonts/simhei.ttf", # Windows
|
||
"C:/Windows/Fonts/msyh.ttc" # Windows微软雅黑
|
||
]
|
||
|
||
for font_path in font_paths:
|
||
if Path(font_path).exists():
|
||
font = TextNode.getDefaultFont()
|
||
# 尝试加载字体
|
||
try:
|
||
font = self.loader.loadFont(font_path)
|
||
print(f"✓ 为GUI加载中文字体成功: {font_path}")
|
||
return font
|
||
except:
|
||
print(f"⚠️ 字体加载失败,尝试下一个: {font_path}")
|
||
continue
|
||
|
||
# 如果所有字体都加载失败,返回默认字体
|
||
print("⚠️ 无法加载中文字体,使用默认字体")
|
||
return TextNode.getDefaultFont()
|
||
|
||
except Exception as e:
|
||
print(f"⚠️ 获取中文字体失败: {e}")
|
||
from panda3d.core import TextNode
|
||
return TextNode.getDefaultFont()
|
||
|
||
def createGUILabel(self, pos=(0, 0, 0), text="标签", size=0.08):
|
||
"""创建2D GUI标签"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
# 使用简化的创建方法,不依赖QT树形控件
|
||
return self._create_simple_gui_label(pos, text, size)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建GUI标签失败: {e}")
|
||
return None
|
||
|
||
def _create_simple_gui_label(self, pos=(0, 0, 0), text="标签", size=0.08):
|
||
"""创建简单的GUI标签,不依赖QT树形控件"""
|
||
try:
|
||
from direct.gui.DirectGui import DirectLabel
|
||
|
||
# 转换坐标系统
|
||
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1)
|
||
|
||
# 设置中文字体
|
||
font = self._get_chinese_font()
|
||
|
||
# 处理scale参数
|
||
if isinstance(size, (list, tuple)) and len(size) >= 2:
|
||
scale_value = size[0] # 使用宽度作为缩放值
|
||
else:
|
||
scale_value = size
|
||
|
||
# 创建标签
|
||
label = DirectLabel(
|
||
text=text,
|
||
pos=gui_pos,
|
||
scale=scale_value,
|
||
text_font=font,
|
||
text_fg=(1, 1, 1, 1) # 白色文字
|
||
)
|
||
|
||
# 创建包装对象
|
||
label_wrapper = type('GUIElement', (), {})()
|
||
label_wrapper.node = label
|
||
label_wrapper.name = text
|
||
label_wrapper.gui_type = "GUI_LABEL"
|
||
label_wrapper.position = pos
|
||
label_wrapper.size = size
|
||
|
||
# 添加到GUI管理器
|
||
self.gui_manager.gui_elements.append(label_wrapper)
|
||
|
||
print(f"✓ GUI标签创建成功: {text}")
|
||
return label_wrapper
|
||
except Exception as e:
|
||
print(f"✗ 创建简单GUI标签失败: {e}")
|
||
return None
|
||
|
||
def createGUIEntry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08):
|
||
"""创建2D GUI文本输入框"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
# 使用简化的创建方法,不依赖QT树形控件
|
||
return self._create_simple_gui_entry(pos, placeholder, size)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建GUI输入框失败: {e}")
|
||
return None
|
||
|
||
def _create_simple_gui_entry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08):
|
||
"""创建简单的GUI输入框,不依赖QT树形控件"""
|
||
try:
|
||
from direct.gui.DirectGui import DirectEntry
|
||
|
||
# 转换坐标系统
|
||
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1)
|
||
|
||
# 设置中文字体
|
||
font = self._get_chinese_font()
|
||
|
||
# 处理scale参数
|
||
if isinstance(size, (list, tuple)) and len(size) >= 2:
|
||
scale_value = size[0] # 使用宽度作为缩放值
|
||
else:
|
||
scale_value = size
|
||
|
||
# 创建输入框
|
||
entry = DirectEntry(
|
||
text=placeholder,
|
||
pos=gui_pos,
|
||
scale=scale_value,
|
||
text_font=font,
|
||
width=20, # 字符宽度
|
||
numLines=1, # 行数
|
||
focus=1 # 自动获取焦点
|
||
)
|
||
|
||
# 创建包装对象
|
||
entry_wrapper = type('GUIElement', (), {})()
|
||
entry_wrapper.node = entry
|
||
entry_wrapper.name = placeholder
|
||
entry_wrapper.gui_type = "GUI_ENTRY"
|
||
entry_wrapper.position = pos
|
||
entry_wrapper.size = size
|
||
|
||
# 添加到GUI管理器
|
||
self.gui_manager.gui_elements.append(entry_wrapper)
|
||
|
||
print(f"✓ GUI输入框创建成功: {placeholder}")
|
||
return entry_wrapper
|
||
except Exception as e:
|
||
print(f"✗ 创建简单GUI输入框失败: {e}")
|
||
return None
|
||
|
||
def createGUIImage(self, pos=(0, 0, 0), image_path=None, size=2):
|
||
"""创建2D GUI图片"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
# 使用简化的创建方法,不依赖QT树形控件
|
||
return self._create_simple_gui_image(pos, image_path, size)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建GUI图片失败: {e}")
|
||
return None
|
||
|
||
def _create_simple_gui_image(self, pos=(0, 0, 0), image_path=None, size=2):
|
||
"""创建简单的GUI图片,不依赖QT树形控件"""
|
||
try:
|
||
from direct.gui.DirectGui import DirectFrame
|
||
from panda3d.core import Filename
|
||
|
||
# 转换坐标系统
|
||
gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1)
|
||
|
||
# 处理scale参数
|
||
if isinstance(size, (list, tuple)) and len(size) >= 2:
|
||
scale_value = size[0] # 使用宽度作为缩放值
|
||
else:
|
||
scale_value = size
|
||
|
||
# 创建图片框架
|
||
if image_path and os.path.exists(image_path):
|
||
# 加载纹理
|
||
tex = self.loader.loadTexture(Filename.fromOsSpecific(image_path))
|
||
image = DirectFrame(
|
||
image=tex,
|
||
pos=gui_pos,
|
||
scale=scale_value
|
||
)
|
||
image_name = os.path.basename(image_path)
|
||
else:
|
||
# 创建一个彩色框架作为占位符
|
||
image = DirectFrame(
|
||
frameColor=(0.5, 0.5, 0.5, 1.0), # 灰色
|
||
frameSize=(-scale_value, scale_value, -scale_value, scale_value),
|
||
pos=gui_pos
|
||
)
|
||
image_name = "占位符图片"
|
||
|
||
# 创建包装对象
|
||
image_wrapper = type('GUIElement', (), {})()
|
||
image_wrapper.node = image
|
||
image_wrapper.name = image_name
|
||
image_wrapper.gui_type = "GUI_IMAGE"
|
||
image_wrapper.position = pos
|
||
image_wrapper.size = size
|
||
image_wrapper.image_path = image_path
|
||
|
||
# 添加到GUI管理器
|
||
self.gui_manager.gui_elements.append(image_wrapper)
|
||
|
||
print(f"✓ GUI图片创建成功: {image_name}")
|
||
return image_wrapper
|
||
except Exception as e:
|
||
print(f"✗ 创建简单GUI图片失败: {e}")
|
||
return None
|
||
|
||
def createVideoScreen(self, pos=(0, 0, 0), size=1, video_path=None):
|
||
"""创建视频屏幕"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
return self.gui_manager.createVideoScreen(pos, size, video_path)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建视频屏幕失败: {e}")
|
||
return None
|
||
|
||
def create2DVideoScreen(self, pos=(0, 0, 0), size=0.2, video_path=None):
|
||
"""创建2D视频屏幕"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
return self.gui_manager.createGUI2DVideoScreen(pos, size, video_path)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建2D视频屏幕失败: {e}")
|
||
return None
|
||
|
||
def createSphericalVideo(self, pos=(0, 0, 0), radius=5.0, video_path=None):
|
||
"""创建360度视频"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
return self.gui_manager.createSphericalVideo(pos, radius, video_path)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建球形视频失败: {e}")
|
||
return None
|
||
|
||
def createVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"):
|
||
"""创建虚拟屏幕"""
|
||
try:
|
||
if hasattr(self, 'gui_manager') and self.gui_manager:
|
||
return self.gui_manager.createGUIVirtualScreen(pos, size, text)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建虚拟屏幕失败: {e}")
|
||
return None
|
||
|
||
# ==================== 光源创建方法 ====================
|
||
|
||
def createSpotLight(self, pos=(0, 0, 5)):
|
||
"""创建聚光灯"""
|
||
try:
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
return self.scene_manager.createSpotLight(pos)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建聚光灯失败: {e}")
|
||
return None
|
||
|
||
def createPointLight(self, pos=(0, 0, 5)):
|
||
"""创建点光源"""
|
||
try:
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
return self.scene_manager.createPointLight(pos)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建点光源失败: {e}")
|
||
return None
|
||
|
||
# ==================== 地形创建方法 ====================
|
||
|
||
def createFlatTerrain(self, size=(10, 10), resolution=129):
|
||
"""创建平面地形"""
|
||
try:
|
||
if hasattr(self, 'terrain_manager') and self.terrain_manager:
|
||
return self.terrain_manager.createFlatTerrain(size, resolution)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建平面地形失败: {e}")
|
||
return None
|
||
|
||
def createTerrainFromHeightMap(self, heightmap_path, scale=(1.0, 1.0, 10.0)):
|
||
"""从高度图创建地形"""
|
||
try:
|
||
if hasattr(self, 'terrain_manager') and self.terrain_manager:
|
||
return self.terrain_manager.createTerrainFromHeightMap(heightmap_path, scale)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建高度图地形失败: {e}")
|
||
return None
|
||
|
||
# ==================== 脚本创建方法 ====================
|
||
|
||
def createScript(self, script_name, template="basic"):
|
||
"""创建脚本"""
|
||
try:
|
||
if hasattr(self, 'script_manager') and self.script_manager:
|
||
return self.script_manager.createScript(script_name, template)
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建脚本失败: {e}")
|
||
return None
|
||
|
||
def loadScript(self, script_path):
|
||
"""加载脚本"""
|
||
try:
|
||
if hasattr(self, 'script_manager') and self.script_manager:
|
||
return self.script_manager.loadScript(script_path)
|
||
return None
|
||
except Exception as e:
|
||
print(f"加载脚本失败: {e}")
|
||
return None
|
||
|
||
demo = MyWorld()
|
||
demo.run()
|