ui替换
This commit is contained in:
parent
1ad2086525
commit
3f6ae9185e
@ -1,166 +0,0 @@
|
|||||||
"""
|
|
||||||
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()
|
|
||||||
@ -1,204 +0,0 @@
|
|||||||
"""
|
|
||||||
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
|
|
||||||
Loading…
Reference in New Issue
Block a user