Render to Pygame Window

I’ve created a simple program that let’s you take a panda3d render and blit it to a Pygame Window. This could be helpful if you need pixel perfect graphics and drawing which Pygame provides while also wanting to use all of Panda3D’s wonderful features.

I’ve used pygame-ce for this.

This code is in the public domain.

import pygame
from direct.showbase.ShowBase import ShowBase
from panda3d.core import Texture, GraphicsOutput

class Window(ShowBase):
    def __init__(self):
        super().__init__(windowType='offscreen')
        self.window = pygame.Window(size=(640, 480))
        self.display_surface = self.window.get_surface()

        self.screen_texture_3d = Texture()
        self.screen_texture_3d.setMinfilter(Texture.FTLinear)
        self.win.addRenderTexture(self.screen_texture_3d, GraphicsOutput.RTMCopyRam)

        self.add_task(self.process_events)
        self.add_task(self.blit_3d, sort=-10)
        self.add_task(self.show_render, sort=30)

        self.accept('w', self.move_cam)
        self.accept('s', self.move_cam)
        self.accept('d', self.move_cam)
        self.accept('a', self.move_cam)

        self.loader.load_model('panda').reparent_to(self.render)

    def move_cam(self, event):
        k = event.get('key') or event.get('text')
        print(k, 'key')
        if k == 'w':
            self.cam.set_y(self.cam, 1)
        elif k == 's':
            self.cam.set_y(self.cam, -1)
        elif k == 'a':
            self.cam.set_x(self.cam, -1)
        elif k == 'd':
            self.cam.set_x(self.cam, 1)

    def blit_3d(self, task):
        if self.screen_texture_3d.hasRamImage():
            i = pygame.image.frombuffer(self.screen_texture_3d.get_ram_image().getData(),
                                        (self.screen_texture_3d.get_x_size(), self.screen_texture_3d.get_y_size()),
                                        "BGRA")
            self.display_surface.blit(pygame.transform.flip(i, False, True).convert())
            pygame.draw.rect(self.display_surface, (255,255,255), (0,0,100,100))
        return task.cont

    def show_render(self, task):
        self.window.flip()
        return task.cont

    def process_events(self, task):
        for event in pygame.event.get():
            print(event.dict)

            if 'pos' in event.dict:
                self.messenger.send('pos', sentArgs=[event.dict])
            elif 'unicode' in event.dict:
                self.messenger.send(event.dict['unicode'], sentArgs=[event.dict])
            elif 'text' in event.dict:
                self.messenger.send(event.dict['text'], sentArgs=[event.dict])

            if event.type == pygame.QUIT:
                quit()

        return task.cont


if __name__ == '__main__':
    example = Window()
    example.run()
3 Likes