def _render_stages(self):
        """ Renders the stages to the window """

        self._remove_components()
        entries_per_row = 6
        aspect = Globals.native_resolution.y / Globals.native_resolution.x
        entry_width = 235
        entry_height = (entry_width - 20) * aspect + 55

        # Store already processed images
        processed = set()
        index = -1
        # Iterate over all stages
        for stage_tex in self._stages:
            if stage_tex in processed:
                continue
            processed.add(stage_tex)
            index += 1
            stage_name = stage_tex.get_name()

            xoffs = index % entries_per_row
            yoffs = index // entries_per_row
            node = self._content_node.attach_new_node("Preview")
            node.set_sz(-1)
            node.set_pos(10 + xoffs * (entry_width - 14), 1, yoffs * (entry_height - 14 + 10))

            r, g, b = 0.2, 0.2, 0.2
            if isinstance(stage_tex, Image):
                r, g, b = 0.2, 0.4, 0.6

            stage_name = stage_name.replace("render_pipeline_internal:", "")
            parts = stage_name.split(":")
            stage_name = parts[-1]
            DirectFrame(
                parent=node,
                frameSize=(7, entry_width - 17, -7, -entry_height + 17),
                frameColor=(r, g, b, 1.0),
                pos=(0, 0, 0)
            )

            frame_hover = DirectFrame(
                parent=node,
                frameSize=(0, entry_width - 10, 0, -entry_height + 10),
                frameColor=(0, 0, 0, 0),
                pos=(0, 0, 0),
                state=DGG.NORMAL
            )
            frame_hover.bind(DGG.ENTER, partial(self._on_texture_hovered, frame_hover))
            frame_hover.bind(DGG.EXIT, partial(self._on_texture_blurred, frame_hover))
            frame_hover.bind(DGG.B1PRESS, partial(self._on_texture_clicked, stage_tex))

            Text(text=stage_name, x=15, y=29, parent=node, size=12, color=Vec3(0.8))

            # Scale image so it always fits
            w, h = stage_tex.get_x_size(), stage_tex.get_y_size()
            padd_x, padd_y = 24, 57
            scale_x = (entry_width - padd_x) / max(1, w)
            scale_y = (entry_height - padd_y) / max(1, h)
            scale_factor = min(scale_x, scale_y)

            if stage_tex.get_texture_type() == Image.TT_buffer_texture:
                scale_factor = 1
                w = entry_width - padd_x
                h = entry_height - padd_y

            preview = Sprite(
                image=stage_tex,
                w=scale_factor * w,
                h=scale_factor * h,
                any_filter=False,
                parent=node,
                x=7,
                y=40,
                transparent=False
            )

            preview.set_shader_inputs(mipmap=0, slice=0, brightness=1, tonemap=False)

            preview_shader = DisplayShaderBuilder.build(stage_tex, scale_factor * w, scale_factor * h)
            preview.set_shader(preview_shader)

        num_rows = (index + entries_per_row) // entries_per_row

        self._set_scroll_height(50 + (entry_height - 14 + 10) * num_rows)
 Renders the stages to the window 
metadrive/render_pipeline/rpcore/gui/buffer_viewer.py