Lightningbeam/PyGUI-2.5.3/GUI/Cocoa/GL.py

186 lines
7.4 KiB
Python

#
# PyGUI - OpenGL View - Cocoa
#
__all__ = ['GLConfig', 'GLView', 'GLPixmap']
import AppKit
from Foundation import NSSize
from AppKit import NSOpenGLPixelFormat, NSOpenGLView, \
NSBitmapImageRep, NSCachedImageRep, NSImage, NSAlphaFirstBitmapFormat, \
NSFloatingPointSamplesBitmapFormat
from Foundation import NSMakeRect
from OpenGL.GL import glViewport, glFlush, glFinish, glReadPixels, \
GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, \
GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, GL_FLOAT, \
glReadPixelsub, glTexImage2D, glPixelStorei, GL_UNPACK_ALIGNMENT
from OpenGL.GLU import gluBuild2DMipmaps
from GUI.GGLViews import GLView as GGLView
from GUI.GGLPixmaps import GLPixmap as GGLPixmap
from GUI.GGLConfig import GLConfig as GGLConfig
from GUI.GLContexts import GLContext
from GUI.GLTextures import Texture
from GUI.GLDisplayLists import DisplayList
from GUI.Utils import NSMultiClass, PyGUI_NS_ViewBase
#------------------------------------------------------------------------------
class GLConfig(GGLConfig):
# _ns_pixel_format NSOpenGLPixelFormat
def _ns_get_pixel_format(self, offscreen = False):
attrs = [AppKit.NSOpenGLPFAColorSize, self._color_size]
if self._double_buffer:
attrs += [AppKit.NSOpenGLPFADoubleBuffer]
if self._alpha:
attrs += [AppKit.NSOpenGLPFAAlphaSize, self._alpha_size]
if self._stereo:
attrs += [AppKit.NSOpenGLPFAStereo]
if self._aux_buffers:
attrs += [AppKit.NSOpenGLPFAAuxBuffers, self._aux_buffers]
if self._depth_buffer:
attrs += [AppKit.NSOpenGLPFADepthSize, self._depth_size]
if self._stencil_buffer:
attrs += [AppKit.NSOpenGLPFAStencilSize, self._stencil_size]
if self._accum_buffer:
attrs += [AppKit.NSOpenGLPFAAccumSize, self._accum_size]
if self._multisample:
attrs += [AppKit.NSOpenGLPFASampleBuffers, 1]
attrs += [AppKit.NSOpenGLPFASamples, self._samples_per_pixel]
if offscreen:
attrs += [AppKit.NSOpenGLPFAOffScreen]
attrs.append(0)
ns_pf = NSOpenGLPixelFormat.alloc().initWithAttributes_(attrs)
if not ns_pf and self._double_buffer:
attrs.remove(AppKit.NSOpenGLPFADoubleBuffer)
ns_pf = NSOpenGLPixelFormat.alloc().initWithAttributes_(attrs)
if not ns_pf:
raise GLConfigError
return ns_pf
def _ns_set_pixel_format(self, ns_pf):
def ns_attr(attr):
return ns_pf.getValues_forAttribute_forVirtualScreen_(attr, 0)[0]
self._ns_pixel_format = ns_pf
self._double_buffer = ns_attr(AppKit.NSOpenGLPFADoubleBuffer)
self._color_size = ns_attr(AppKit.NSOpenGLPFAColorSize)
self._alpha_size = ns_attr(AppKit.NSOpenGLPFAAlphaSize)
self._alpha = self._alpha_size > 0
self._stereo = ns_attr(AppKit.NSOpenGLPFAStereo)
self._aux_buffers = ns_attr(AppKit.NSOpenGLPFAAuxBuffers)
self._depth_size = ns_attr(AppKit.NSOpenGLPFADepthSize)
self._depth_buffer = self._depth_size > 0
self._stencil_size = ns_attr(AppKit.NSOpenGLPFAStencilSize)
self._stencil_buffer = self._stencil_size > 0
self._accum_size = ns_attr(AppKit.NSOpenGLPFAAccumSize)
self._accum_buffer = self._accum_size > 0
self._multisample = ns_attr(AppKit.NSOpenGLPFASampleBuffers) > 0
self._samples_per_pixel = ns_attr(AppKit.NSOpenGLPFASamples)
def supported(self, mode = 'both'):
try:
ns_pf = self._ns_get_pixel_format()
pf = GLConfig.__new__()
pf._ns_set_pixel_format(ns_pf)
return pf
except GLConfigError:
return None
#------------------------------------------------------------------------------
class GLView(GGLView):
# _ns_view NSOpenGLView
# _ns_context NSOpenGLContext
# _ns_flush function for flushing/swapping buffers
def __init__(self, config = None, share_group = None, **kwds):
pf = GLConfig._from_args(config, kwds)
ns_pf = pf._ns_get_pixel_format()
width, height = GGLView._default_size
ns_rect = NSMakeRect(0, 0, width, height)
ns_view = _PyGUI_NSOpenGLView.alloc().initWithFrame_pixelFormat_(
ns_rect, ns_pf)
ns_view.pygui_component = self
GGLView.__init__(self, _ns_view = ns_view)
GLContext.__init__(self, share_group = share_group, _ns_pixel_format = ns_pf)
ns_context = self._ns_context
ns_view.setOpenGLContext_(ns_context)
#ns_context.setView_(ns_view) # Docs say this is needed, but
# prints warning and seems to work without.
if pf.double_buffer:
self._ns_flush = ns_context.flushBuffer
else:
self._ns_flush = glFlush
self.set(**kwds)
self.with_context(self._init_context)
def destroy(self):
#print "GLView.destroy:", self ###
ns_view = self._ns_view
GGLView.destroy(self)
#print "GLView.destroy: breaking back link from", ns_view ###
ns_view.pygui_component = None
def invalidate(self):
self._ns_view.setNeedsDisplay_(True)
def update(self):
self._ns_view.displayIfNeeded()
def track_mouse(self):
return self._ns_track_mouse(self._ns_view)
#------------------------------------------------------------------------------
class GLPixmap(GGLPixmap):
def __init__(self, width, height, config = None, share_group = None, **kwds):
pf = GLConfig._from_args(config, kwds)
ns_pf = pf._ns_get_pixel_format()
ns_size = NSSize(width, height)
ns_cache = NSCachedImageRep.alloc().initWithSize_depth_separate_alpha_(
ns_size, 0, True, True)
ns_image = NSImage.alloc().initWithSize_(ns_size)
GLContext.__init__(self, share_group = share_group, _ns_pixel_format = ns_pf)
self._ns_context.setView_(ns_cache.window().contentView())
self._init_with_ns_image(ns_image, flipped = False)
self._ns_cache = ns_cache
self.with_context(self._init_context)
def _ns_flush(self):
glFlush()
width, height = self.size
pixels = glReadPixels(0, 0, int(width), int(height), GL_RGBA, GL_UNSIGNED_BYTE)
bytes_per_row = int(width) * 4
ns_new_bitmap = NSBitmapImageRep.alloc().\
initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel_(
(pixels, "", "", "", ""), int(width), int(height), 8, 4, True, False, AppKit.NSDeviceRGBColorSpace, bytes_per_row, 0)
ns_image = NSImage.alloc().initWithSize_(NSSize(width, height))
ns_image.addRepresentation_(ns_new_bitmap)
ns_image.lockFocus()
ns_image.unlockFocus()
self._ns_image = ns_image
self._ns_bitmap_image_rep = ns_new_bitmap
#------------------------------------------------------------------------------
class _PyGUI_NSOpenGLView(NSOpenGLView, PyGUI_NS_ViewBase):
__metaclass__ = NSMultiClass
#
# pygui_component GLView
__slots__ = ['pygui_component']
def isFlipped(self):
return True
def reshape(self):
comp = self.pygui_component
if comp.window:
comp.with_context(comp._update_viewport)
def drawRect_(self, rect):
comp = self.pygui_component
comp.with_context(comp._render, flush = True)