MBH_Demo_001/source/pkgexplore.py
2023-02-18 11:11:37 +01:00

207 lines
9.3 KiB
Python

import posixpath
import tkinter as tk
import tkinter.ttk as ttk
from source.packages import PackageManager
from direct.showbase.ShowBase import ShowBase
from panda3d.core import VirtualFileSystem, Material, NodePath
from direct.stdpy.file import walk
import simplepbr
import gltf
def get_icons():
return type('', (object,), {
'app': tk.PhotoImage(file="icons/application.png"),
'brick': tk.PhotoImage(file="icons/brick.png"),
'bricks': tk.PhotoImage(file="icons/bricks.png"),
'computer': tk.PhotoImage(file="icons/computer.png"),
'folder': tk.PhotoImage(file="icons/folder.png"),
'shape_group': tk.PhotoImage(file="icons/shape_group.png"),
'pictures': tk.PhotoImage(file="icons/pictures.png"),
'picture': tk.PhotoImage(file='icons/picture.png'),
"page_red": tk.PhotoImage(file='icons/page_red.png'),
'shape_square': tk.PhotoImage(file='icons/shape_square.png'),
'color_wheel': tk.PhotoImage(file='icons/color_wheel.png'),
'color_swatch': tk.PhotoImage(file='icons/color_swatch.png'),
'link': tk.PhotoImage(file='icons/link.png'),
'sound': tk.PhotoImage(file='icons/sound.png'),
'chart_organisation': tk.PhotoImage(file='icons/chart_organisation.png'),
'anchor': tk.PhotoImage(file='icons/anchor.png'),
'shape_flip_horizontal': tk.PhotoImage(file='icons/shape_flip_horizontal.png'),
'film': tk.PhotoImage(file='icons/film.png'),
'user': tk.PhotoImage(file='icons/user.png')
})()
def add_package_contents_to_tree(tree, package, type, name, extensions, icon_folder, icon_group, icon_item):
data_path = posixpath.join(package.mount_dir, type)
tree.insert(package.mount_dir, 'end', data_path, text=f' {name}', image=icon_group)
file_count = 0
for root, paths, files in walk(data_path):
for path in paths:
tree.insert(root, 'end', posixpath.join(root, path), text=f' {path}', image=icon_folder)
for file in files:
if file.lower().endswith(extensions):
file_count += 1
tree.insert(root, 'end', posixpath.join(root, file), text=f' {file}', image=icon_item)
tree.item(data_path, text=f' {name} ({file_count})')
def add_package_models_to_tree(tree, package, icons):
add_package_contents_to_tree(tree, package, 'models/', '3D Models', ('.glb', '.gltf', '.obj', '.egg'), icons.folder, icons.shape_group, icons.shape_square)
def add_package_textures_to_tree(tree, package, icons):
add_package_contents_to_tree(tree, package, 'textures/', 'Image Textures', ('.png', '.jpg', '.bmp'), icons.folder, icons.pictures, icons.picture)
def add_package_materials_to_tree(tree, package, icons):
add_package_contents_to_tree(tree, package, 'materials/', 'Materials', ('.json'), icons.folder, icons.color_wheel, icons.color_swatch)
def add_package_sounds_to_tree(tree, package, icons):
add_package_contents_to_tree(tree, package, 'sounds/', 'Sounds', ('.ogg', '.wav'), icons.folder, icons.sound, icons.sound)
def add_package_to_tree(tree, package, icons):
add_package_models_to_tree(tree, package, icons)
add_package_textures_to_tree(tree, package, icons)
add_package_materials_to_tree(tree, package, icons)
add_package_sounds_to_tree(tree, package, icons)
def init_packages_tree(tree, packages, icons):
tree.insert('', 'end', '/', text=' /', open=True, image=icons.app)
tree.insert('/', 'end', '/main/', text=f' Main Package "{packages.main_package.meta.name}" - {packages.main_package.meta.version}', image=icons.computer)
tree.insert('/', 'end', '/include/', text=f' Included Packages ({len(packages.package_list)})', image=icons.bricks)
add_package_to_tree(tree, packages.main_package, icons)
for package in packages.package_list:
tree.insert('/include/', 'end', package.mount_dir, text=f' "{package.meta.name}" - {package.meta.version}', image=icons.brick)
add_package_to_tree(tree, package, icons)
return tree
def init_gui(app, args):
app.gui.geometry("700x500")
app.gui.grid_rowconfigure(0, weight=10)
app.gui.grid_rowconfigure(1, weight=5)
app.gui.grid_columnconfigure(0, weight=1)
package_frame = tk.Frame(app.gui, padx=4, pady=4)
package_frame.grid(column=0, row=0, sticky="news")
package_frame.grid_columnconfigure(0, weight=1)
package_frame.grid_rowconfigure(0, weight=1)
package_frame.grid_rowconfigure(1, weight=1000)
packages_label = tk.Label(package_frame, text="Packages")
packages_label.grid(column=0, row=0, sticky="w")
packagetree_frame = tk.Frame(package_frame)
packagetree_frame.grid(column=0, row=1, sticky="news")
packagetree_frame.grid_columnconfigure(0, weight=1000)
packagetree_frame.grid_columnconfigure(1, weight=1)
packagetree_frame.grid_rowconfigure(0, weight=1)
app.tree_packages = ttk.Treeview(packagetree_frame, show="tree")
app.tree_packages.grid(column=0, row=0, sticky="news")
packagetree_scrollbar = ttk.Scrollbar(packagetree_frame, orient="vertical", command=app.tree_packages.yview)
packagetree_scrollbar.grid(column=1, row=0)
app.tree_packages.bind('<Double-1>', app.on_packagetree_doubleclick)
scene_frame = tk.Frame(app.gui, padx=4, pady=4)
scene_frame.grid(column=0, row=1, sticky="news")
scene_frame.grid_columnconfigure(0, weight=1)
scene_frame.grid_rowconfigure(0, weight=1)
scene_frame.grid_rowconfigure(1, weight=1000)
scene_label = tk.Label(scene_frame, text="Scene Graph")
scene_label.grid(column=0, row=0, sticky="w")
scenetree_frame = tk.Frame(scene_frame)
scenetree_frame.grid(column=0, row=1, sticky="news")
scenetree_frame.grid_columnconfigure(0, weight=10000)
scenetree_frame.grid_columnconfigure(1, weight=1)
scenetree_frame.grid_rowconfigure(0, weight=1)
app.tree_scene = ttk.Treeview(scenetree_frame, show="tree")
app.tree_scene.grid(column=0, row=0, sticky="news")
scenetree_scrollbar = ttk.Scrollbar(scenetree_frame, orient="vertical", command=app.tree_scene.yview)
scenetree_scrollbar.grid(column=1, row=0)
class PackageExplorer:
def __init__(self, args):
self.gui = tk.Tk()
self.panda = ShowBase()
self.package_manager = PackageManager(VirtualFileSystem.getGlobalPtr())
self.package_manager.set_main_package(args.main)
self.icons = get_icons()
self.prev = None
if args.package:
for include in args.package:
self.package_manager.include_package(include)
self.tree_packages = None
self.tree_scene = None
self.running = True
simplepbr.init()
gltf.patch_loader(self.panda.loader)
init_gui(self, args)
init_packages_tree(self.tree_packages, self.package_manager, self.icons)
env_root = NodePath('env_root')
env_root.reparentTo(self.panda.render)
axis = self.panda.loader.loadModel(self.package_manager.get_model_path('axis.glb'))
axis.reparentTo(env_root)
plane = self.panda.loader.loadModel(self.package_manager.get_model_path('debugplane.glb'))
plane.reparentTo(env_root)
self.scene_root = NodePath('scene_root')
self.scene_root.reparentTo(self.panda.render)
self.gui.protocol("WM_DELETE_WINDOW", self.on_tk_close)
def on_tk_close(self):
self.running = False
def on_packagetree_doubleclick(self, event):
item = self.tree_packages.selection()[0]
if item.lower().endswith(('.glb', '.gltf', '.obj', '.egg')):
for child in self.scene_root.getChildren():
child.removeNode()
mat = Material()
mat.setAmbient((1, 0, 0, 1))
node = self.panda.loader.loadModel(item)
node.reparentTo(self.scene_root)
node.setMaterial(mat)
self.display_scenegraph(node, item)
self.prev = node
def display_scenegraph(self, node, item):
self.tree_scene.delete(*self.tree_scene.get_children())
self.tree_scene.insert('', 'end', '/', text=f' {item}', open=True, image=self.icons.shape_square)
self.add_scene_nodes(node, '/')
def add_scene_nodes(self, node, parent):
pn = node.node()
tree_id = f'{pn.getType().getName()} {node.getName()}'
tree_name = tree_id
image = ''
match pn.getType().getName():
case 'ModelRoot':
image = self.icons.chart_organisation
case 'PandaNode':
image = self.icons.anchor
case 'GeomNode':
image = self.icons.shape_flip_horizontal
case 'AnimBundleNode':
bundle = pn.getBundle().getName()
tree_id = f'{tree_id}_"{bundle}"'
tree_name = f'"{bundle}"'
image = self.icons.film
case 'Character':
image = self.icons.user
self.tree_scene.insert(parent, 'end', tree_id, text=f' {tree_name}', open=True, image=image)
for child in node.getChildren():
self.add_scene_nodes(child, tree_id)
def loop(self):
try:
while self.running:
self.gui.update_idletasks()
self.gui.update()
self.panda.taskMgr.step()
except KeyboardInterrupt:
return
def start_explorer(args):
app = PackageExplorer(args)
app.loop()