pygameでOpenGLとその他のimageを同居させる
pygameでOpenGLをすると全画面を独占される。それだとglutでやる事と変わらない。pygameの特性を活かしきれない。そこでOpenGLをimageとして使う方法をやってみた。imageをつくるのにpycairoというライブラリーも使ってる。細かい説明も厄介なのでコードだけ。
from os import environ environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1' import pygame from OpenGL.GL import * from OpenGL.WGL import * import cairo import numpy import math from ctypes import * user32 = windll.user32 width, height = 512, 512 pygame.init() pygame.display.set_mode((width, height)) window = pygame.display.get_surface() background = pygame.Surface((width, height)) background.fill((20,20,20)) # Get OpenGL context SM_CXSCREEN, SM_CYSCREEN = 0,1 WS_OVERLAPPEDWINDOW = 0xcf0000 PFD_SUPPORT_OPENGL = 32 PFD_DOUBLEBUFFER = 1 xsc, ysc =user32.GetSystemMetrics(SM_CXSCREEN),user32.GetSystemMetrics(SM_CYSCREEN) hwnd = user32.CreateWindowExA(0,0xC018,0,WS_OVERLAPPEDWINDOW,0,0,xsc,ysc,0,0,0,0) hdc = user32.GetDC(hwnd) user32.SetForegroundWindow(hwnd) pfd = PIXELFORMATDESCRIPTOR(0,1,PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,32,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0) SetPixelFormat(hdc, ChoosePixelFormat(hdc, pfd), pfd) wglc = wglCreateContext(hdc) wglMakeCurrent(hdc, wglc) # OpenGL init program = glCreateProgram() shader = glCreateShader(GL_FRAGMENT_SHADER) glsl = ''' #version 430 out vec4 fragColor; uniform vec2 resolution; uniform float time; void main() { vec2 uv = gl_FragCoord.xy/resolution; vec3 col = 0.5 + 0.5*cos(time+uv.xyx+vec3(0,2,4)); fragColor = vec4(col,1); } ''' glShaderSource(shader, glsl) glCompileShader(shader) if glGetShaderiv(shader, GL_COMPILE_STATUS) != GL_TRUE: raise RuntimeError(glGetShaderInfoLog(shader).decode()) glAttachShader(program, shader) glLinkProgram(program) glUseProgram(program) pixels = numpy.zeros((width, height,3), numpy.uint8) gl_width = width-50 gl_height = height-200 glViewport(0, 0, gl_width, gl_height) glUniform2f(glGetUniformLocation(program, "resolution"), gl_width, gl_height) cairo_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 120, 120) def cairo_draw(surface): ctx = cairo.Context(surface) ctx.set_source_rgb(0.8, 0.5, 0.1) ctx.rectangle(10, 10, 110, 110) ctx.fill() fpsClock = pygame.time.Clock() running = True while running: time = pygame.time.get_ticks()/1000 window.blit(background, (0, 0)) glUniform1f(glGetUniformLocation(program, "time"), time) glRects(1, 1, -1, -1) glReadPixels(0, 0, pixels.shape[0],pixels.shape[1], GL_RGB, GL_UNSIGNED_BYTE, pixels) image = pygame.image.frombuffer( pixels.tobytes(), pixels.shape[:2], 'RGB') window.blit(image, (25,100), pygame.Rect(0, 0, gl_width, gl_height)) cairo_draw(cairo_surface) image = pygame.image.frombuffer( numpy.array(cairo_surface.get_data())[..., ::-1].tobytes(), (cairo_surface.get_width(),cairo_surface.get_height()), 'ARGB') x= (width-cairo_surface.get_width())/2 + 150*math.sin(time) y= (height-cairo_surface.get_height())/2 + 150*math.cos(time) window.blit(image, (x,y)) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: running = False fpsClock.tick(30) # OpenGL finish wglMakeCurrent(0, 0) wglDeleteContext(wglc) user32.ReleaseDC(hwnd, hdc) user32.PostQuitMessage(0) user32.DestroyWindow(hwnd) pygame.quit()