Exemplo n.º 1
0
    def _create_hints(self):
        """ Creates the hints like keybindings and when reloading shaders """
        self._hint_reloading = Sprite(
            image="/$$rp/data/gui/shader_reload_hint.png",
            x=float((Globals.base.win.get_x_size()) // 2) / self._gui_scale - 465 // 2, y=220,
            parent=self._fullscreen_node)
        self.set_reload_hint_visible(False)

        if not NATIVE_CXX_LOADED:
            # Warning when using the python version
            python_warning = Sprite(
                image="/$$rp/data/gui/python_warning.png",
                x=((Globals.base.win.get_x_size()/self._gui_scale) - 1054) // 2,
                y=(Globals.base.win.get_y_size()/self._gui_scale) - 118 - 40,
                parent=self._fullscreen_node)

            Sequence(
                python_warning.color_scale_interval(0.7, Vec4(0.3, 1, 1, 0.7), blendType="easeOut"),
                python_warning.color_scale_interval(0.7, Vec4(1, 1, 1, 1.0), blendType="easeOut"),
            ).loop()

        # Keybinding hints
        self._keybinding_instructions = Sprite(
            image="/$$rp/data/gui/keybindings.png", x=30,
            y=Globals.base.win.get_y_size()//self._gui_scale - 510.0,
            parent=self._fullscreen_node, any_filter=False)
Exemplo n.º 2
0
    def _create_hints(self):
        """ Creates the hints like keybindings and when reloading shaders """
        self._hint_reloading = Sprite(
            image="/$$rp/data/gui/shader_reload_hint.png",
            x=float((Globals.base.win.get_x_size()) // 2) / self._gui_scale -
            465 // 2,
            y=220,
            parent=self._fullscreen_node)
        self.set_reload_hint_visible(False)

        if not NATIVE_CXX_LOADED:
            # Warning when using the python version
            python_warning = Sprite(
                image="/$$rp/data/gui/python_warning.png",
                x=((Globals.base.win.get_x_size() / self._gui_scale) - 1054) //
                2,
                y=(Globals.base.win.get_y_size() / self._gui_scale) - 118 - 40,
                parent=self._fullscreen_node)

            Sequence(
                python_warning.color_scale_interval(0.7,
                                                    Vec4(0.3, 1, 1, 0.7),
                                                    blendType="easeOut"),
                python_warning.color_scale_interval(0.7,
                                                    Vec4(1, 1, 1, 1.0),
                                                    blendType="easeOut"),
            ).loop()

        # Keybinding hints
        self._keybinding_instructions = Sprite(
            image="/$$rp/data/gui/keybindings.png",
            x=30,
            y=Globals.base.win.get_y_size() // self._gui_scale - 510.0,
            parent=self._fullscreen_node,
            any_filter=False)
class Debugger(RPObject):

    """ This class manages the onscreen control, and displays statistics. """

    def __init__(self, pipeline):
        RPObject.__init__(self)
        self.debug("Creating debugger")
        self.pipeline = pipeline
        self.analyzer = SceneGraphAnalyzer()

        self.fullscreen_node = Globals.base.pixel2d.attach_new_node("rp_debugger")
        self.create_components()
        self.init_keybindings()

        if self.advanced_info:
            Globals.base.doMethodLater(
                0.5, lambda task: self.collect_scene_data(), "RPDebugger_collectSceneData_initial")
        
        Globals.base.doMethodLater(0.1, self.update_stats, "RPDebugger_updateStats")

    @property
    def advanced_info(self):
        return self.pipeline.settings["pipeline.advanced_debugging_info"]

    def create_components(self):
        """ Creates the gui components """

        self.debugger_width = 460
        self.debugger_visible = False
        self.debugger_interval = None

        self.create_stats()
        self.create_hints()

        self.pipeline_logo = Sprite(
            image="/$$rp/data/gui/pipeline_logo_text.png", x=30, y=30,
            parent=self.fullscreen_node)

        if self.advanced_info:
            self.exposure_node = self.fullscreen_node.attach_new_node("ExposureWidget")
            self.exposure_widget = ExposureWidget(self.pipeline, self.exposure_node)

        self.fps_node = self.fullscreen_node.attach_new_node("FPSChart")
        self.fps_node.set_pos(Vec3(21, 1, -108 - 40))
        self.fps_widget = FPSChart(self.pipeline, self.fps_node)

        self.pixel_widget = PixelInspector(self.pipeline)
        self.buffer_viewer = BufferViewer(self.pipeline, self.fullscreen_node)
        self.pipe_viewer = PipeViewer(self.pipeline, self.fullscreen_node)
        self.rm_selector = RenderModeSelector(self.pipeline, self.fullscreen_node)
        self.error_msg_handler = ErrorMessageDisplay()

        self.handle_window_resize()

    def update(self):
        """ Updates the gui """
        self.error_msg_handler.update()
        self.pixel_widget.update()

    def collect_scene_data(self, task=None):
        """ Analyzes the scene graph to provide useful information """
        self.analyzer.clear()
        for geom_node in Globals.base.render.find_all_matches("**/+GeomNode"):
            self.analyzer.add_node(geom_node.node())
        if task:
            return task.again

    def create_stats(self):
        """ Creates the stats overlay """
        self.overlay_node = Globals.base.aspect2d.attach_new_node("Overlay")
        self.debug_lines = []

        num_lines = 6 if self.advanced_info else 1
        for i in range(num_lines):
            self.debug_lines.append(TextNode(
                pos=Vec2(0, -i * 0.046), parent=self.overlay_node, align="right", color=Vec3(0.7, 1, 1)))
        self.debug_lines[0].color = Vec4(1, 1, 0, 1)

    def create_hints(self):
        """ Creates the hints like keybindings and when reloading shaders """
        self.hint_reloading = Sprite(
            image="/$$rp/data/gui/shader_reload_hint.png",
            parent=self.fullscreen_node)
        self.set_reload_hint_visible(False)

        self.python_warning = None
        if not NATIVE_CXX_LOADED:
            # Warning when using the python version
            self.python_warning = Sprite(
                image="/$$rp/data/gui/python_warning.png",
                parent=self.fullscreen_node)
            Sequence(
                self.python_warning.color_scale_interval(
                    0.7, Vec4(0.3, 1, 1, 0.7), blendType="easeOut"),
                self.python_warning.color_scale_interval(
                    0.7, Vec4(1, 1, 1, 1.0), blendType="easeOut"),
            ).loop()

        # Keybinding hints
        self.keybinding_instructions = Sprite(
            image="/$$rp/data/gui/keybindings.png",
            parent=self.fullscreen_node, any_filter=False)

    def set_reload_hint_visible(self, flag):
        """ Sets whether the shader reload hint is visible """
        if flag:
            self.hint_reloading.show()
        else:
            self.hint_reloading.hide()

    def handle_window_resize(self):
        """ Handles the window resize, repositions the GUI elements to fit on
        screen. """
        # When using small resolutions, scale the GUI so its still useable,
        # otherwise the sub-windows are bigger than the main window
        self.gui_scale = max(0.65, min(1.0, Globals.native_resolution.x / 1920.0))
        self.fullscreen_node.set_scale(self.gui_scale)

        if self.advanced_info:
            self.exposure_node.set_pos(
                Globals.native_resolution.x // self.gui_scale - 200,
                1, -Globals.native_resolution.y // self.gui_scale + 120)
        self.hint_reloading.set_pos(
            float((Globals.native_resolution.x) // 2) / self.gui_scale - 465 // 2, 220)
        self.keybinding_instructions.set_pos(
            30, Globals.native_resolution.y // self.gui_scale - 510.0,)
        self.overlay_node.set_pos(Globals.base.get_aspect_ratio() - 0.07, 1, 1.0 - 0.07)
        if self.python_warning:
            self.python_warning.set_pos(
                (Globals.native_resolution.x // self.gui_scale - 1054) // 2,
                (Globals.native_resolution.y // self.gui_scale - 118 - 40))

        for text in self.debug_lines:
            text.set_pixel_size(16 * max(0.8, self.gui_scale))

        self.buffer_viewer.center_on_screen()
        self.pipe_viewer.center_on_screen()
        self.rm_selector.center_on_screen()

    def init_keybindings(self):
        """ Inits the debugger keybindings """
        Globals.base.accept("v", self.buffer_viewer.toggle)
        Globals.base.accept("c", self.pipe_viewer.toggle)
        Globals.base.accept("z", self.rm_selector.toggle)
        Globals.base.accept("f5", self.toggle_gui_visible)
        Globals.base.accept("f6", self.toggle_keybindings_visible)
        Globals.base.accept("r", self.pipeline.reload_shaders)
        Globals.base.accept("m", self.start_material_editor)

    def start_material_editor(self):
        """ Starts the material editor """
        self.debug("Starting material editor")
        pth = sys.executable
        editor = os.path.dirname(os.path.realpath(__file__))
        editor = os.path.join(editor, "..", "..", "toolkit", "material_editor", "main.py")
        subprocess.Popen([pth, editor], shell=True)        

    def toggle_gui_visible(self):
        """ Shows / Hides the gui """

        if not self.fullscreen_node.is_hidden():
            self.fullscreen_node.hide()
            self.overlay_node.hide()
            self.error_msg_handler.hide()
        else:
            self.fullscreen_node.show()
            self.overlay_node.show()
            self.error_msg_handler.show()

    def toggle_keybindings_visible(self):
        """ Shows / Hides the FPS graph """
        if not self.keybinding_instructions.is_hidden():
            self.keybinding_instructions.hide()
        else:
            self.keybinding_instructions.show()

    def update_stats(self, task=None):
        """ Updates the stats overlay """
        clock = Globals.clock
        self.debug_lines[0].text = "{:3.0f} fps  |  {:3.1f} ms  |  {:3.1f} ms max".format(
            clock.get_average_frame_rate(),
            1000.0 / max(0.001, clock.get_average_frame_rate()),
            clock.get_max_frame_duration() * 1000.0)

        if not self.advanced_info:
            return task.again if task else None

        text = "{:4d} states |  {:4d} transforms "
        text += "|  {:4d} cmds |  {:4d} lights |  {:4d} shadows "
        text += "|  {:5.1f}% atlas usage"
        self.debug_lines[1].text = text.format(
            RenderState.get_num_states(), TransformState.get_num_states(),
            self.pipeline.light_mgr.cmd_queue.num_processed_commands,
            self.pipeline.light_mgr.num_lights,
            self.pipeline.light_mgr.num_shadow_sources,
            self.pipeline.light_mgr.shadow_atlas_coverage)

        text = "Internal:  {:3.0f} MB VRAM |  {:5d} img |  {:5d} tex |  "
        text += "{:5d} fbos |  {:3d} plugins |  {:2d}  views  ({:2d} active)"
        tex_memory, tex_count = self.buffer_viewer.stage_information

        views, active_views = 0, 0
        for target in RenderTarget.REGISTERED_TARGETS:
            if not target.create_default_region:
                num_regions = target.internal_buffer.get_num_display_regions()
                for i, region in enumerate(target.internal_buffer.get_display_regions()):
                    # Skip overlay display region
                    if i == 0 and num_regions > 1:
                        continue
                    views += 1
                    active_views += 1 if target.active and region.active else 0

        self.debug_lines[2].text = text.format(
            tex_memory / (1024**2), len(Image.REGISTERED_IMAGES), tex_count,
            RenderTarget.NUM_ALLOCATED_BUFFERS,
            len(self.pipeline.plugin_mgr.enabled_plugins),
            views, active_views)

        text = "Scene:   {:4.0f} MB VRAM |  {:3d} tex |  {:4d} geoms "
        text += "|  {:4d} nodes |  {:7,.0f} vertices"
        scene_tex_size = 0
        for tex in TexturePool.find_all_textures():
            scene_tex_size += tex.estimate_texture_memory()

        self.debug_lines[3].text = text.format(
            scene_tex_size / (1024**2),
            len(TexturePool.find_all_textures()),
            self.analyzer.get_num_geoms(),
            self.analyzer.get_num_nodes(),
            self.analyzer.get_num_vertices(),
        )

        sun_vector = Vec3(0)
        if self.pipeline.plugin_mgr.is_plugin_enabled("scattering"):
            sun_vector = self.pipeline.plugin_mgr.instances["scattering"].sun_vector

        text = "Time:  {} ({:1.3f}) |  Sun  {:0.2f} {:0.2f} {:0.2f}"
        text += " |  X {:3.1f}  Y {:3.1f}  Z {:3.1f}"
        text += " |  {:2d} tasks |  scheduled: {:2d}"
        self.debug_lines[4].text = text.format(
            self.pipeline.daytime_mgr.formatted_time,
            self.pipeline.daytime_mgr.time,
            sun_vector.x, sun_vector.y, sun_vector.z,
            Globals.base.camera.get_x(Globals.base.render),
            Globals.base.camera.get_y(Globals.base.render),
            Globals.base.camera.get_z(Globals.base.render),
            self.pipeline.task_scheduler.num_tasks,
            self.pipeline.task_scheduler.num_scheduled_tasks,)

        text = "Scene shadows:  "
        if "pssm" in self.pipeline.plugin_mgr.enabled_plugins:
            focus = self.pipeline.plugin_mgr.instances["pssm"].scene_shadow_stage.last_focus
            if focus is not None:
                text += "{:3.1f} {:3.1f} {:3.1f} r {:3.1f}".format(
                    focus[0].x, focus[0].y, focus[0].z, focus[1])
            else:
                text += "none"
        else:
            text += "inactive"

        text += "   |  HPR  ({:3.1f}, {:3.1f}, {:3.1f})  |   {:4d} x {:4d} pixels @ {:3.1f} %"
        text += "   |  {:3d} x {:3d} tiles"
        self.debug_lines[5].text = text.format(
            Globals.base.camera.get_h(Globals.base.render),
            Globals.base.camera.get_p(Globals.base.render),
            Globals.base.camera.get_r(Globals.base.render),
            Globals.native_resolution.x,
            Globals.native_resolution.y,
            self.pipeline.settings["pipeline.resolution_scale"] * 100.0,
            self.pipeline.light_mgr.num_tiles.x,
            self.pipeline.light_mgr.num_tiles.y,)
        if task:
            return task.again