import tkinter as tk from source.packages import PackageManager from source.packages.gui import * from direct.showbase.ShowBase import ShowBase from panda3d.core import VirtualFileSystem, Material, Vec3, CullFaceAttrib, WindowProperties from direct.actor.Actor import Actor class PackageExplorer: def __init__(self, args): self.gui = tk.Tk() self.gui.title("Blackjack and Hookers: Package Explorer") self.panda = ShowBase() props = WindowProperties() props.setTitle('Blackjack and Hookers: 3D Viewport') self.panda.win.requestProperties(props) 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 self.env_root = None self.camera_root = None self.camera_accel = 100 self.panda_keymap = { 'mouse1': False } self.mouse_previous = Vec3() self.mouse_direction = Vec3() init_gui(self, args) init_packages_tree(self.tree_packages, self.package_manager, self.icons) init_panda(self, args) 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) path = node.find('**/+Character') if not path.isEmpty(): node = Actor(node) node.reparentTo(self.scene_root) node.setMaterial(mat) node.setTwoSided(False) node.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullClockwise)) 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) joints = node.getJoints() if getattr(node, 'getJoints', None) else [] if len(joints) > 0: self.tree_scene.insert('/', 'end', 'joints', text=f' Joints ({len(joints)})', image=self.icons.chart_line_link) for joint in joints: self.tree_scene.insert('joints', 'end', f'joint_{joint.getName()}', text=f' {joint.getName()}', image=self.icons.anchor) 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 mouse1_down(self): self.panda_keymap['mouse1'] = True def mouse1_up(self): self.panda_keymap['mouse1'] = False def wheel_up(self): quat = self.panda.camera.getQuat(self.camera_root) forward = quat.getForward() self.panda.camera.setPos(self.panda.camera.getPos() + forward) def wheel_down(self): quat = self.panda.camera.getQuat(self.camera_root) forward = quat.getForward() self.panda.camera.setPos(self.panda.camera.getPos() - forward) def update_input(self, task): if self.panda.mouseWatcherNode.hasMouse(): mouse = self.panda.mouseWatcherNode.getMouse() dt = self.panda.clock.getDt() self.mouse_direction = Vec3(self.mouse_previous.getX() - mouse.getX(), self.mouse_previous.getY() - mouse.getY(), 0) self.mouse_previous = Vec3(mouse.getX(), mouse.getY(), 0) if self.panda_keymap['mouse1']: self.camera_root.setH(self.panda.render, self.camera_root.getH() + self.mouse_direction.getX() * self.camera_accel) self.camera_root.setP(self.panda.render, self.camera_root.getP() + -self.mouse_direction.getY() * self.camera_accel) return task.cont 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()