#
#   PyGUI - OpenGL View - Gtk/GtkGLExt
#

from GGLViews import GLError

try:
    from gtk import gdkgl, gtkgl
    from OpenGL.GL import glViewport, glFlush
except ImportError, e:
    raise GLError("OpenGL support is not available (%s)" % e)

from GtkInput import GtkInput
from GGLViews import GLView as GGLView

class GLView(GGLView, GtkInput):

    _gl_drawable = None
    _gl_context = None
    _first_expose = 0

    def __init__(self, double_buffer = True, alpha = False, depth_buffer = True,
            stencil_buffer = False, accum_buffer = False, multisample = False, **kwds):
        mode = gdkgl.MODE_RGB
        if double_buffer:
            mode |= gdkgl.MODE_DOUBLE
        if alpha:
            mode |= gdkgl.MODE_ALPHA
        if depth_buffer:
            mode |= gdkgl.MODE_DEPTH
        if stencil_buffer:
            mode |= gdkgl.MODE_STENCIL
        if accum_buffer:
            mode |= gdkgl.MODE_ACCUM
        if multisample:
            mode |= gdkgl.MODE_MULTISAMPLE
        config = gdkgl.Config(mode = mode)
        if not config:
            #print "GLView.__init__: retrying without double buffering" ###
            mode &= ~gdkgl.MODE_DOUBLE
            config = gdkgl.Config(mode = mode)
        if not config:
            raise GLError("Unable to create a GLView with the requested options.")
        self._gl_config = config
        area = gtkgl.DrawingArea(glconfig = config, render_type = gdkgl.RGBA_TYPE)
        area.show()
        self._gtk_connect_after(area, "realize", self._gtk_realize_signal)
        self._gtk_connect(area, "expose-event", self._gtk_expose_event_signal)
        GGLView.__init__(self, _gtk_outer = area, **kwds)
        GtkInput.__init__(self, area)

    def _gtk_realize_signal(self):
        #print "GLView._gtk_realize_signal" ###
        area = self._gtk_inner_widget
        self._gl_drawable = area.get_gl_drawable()
        self._gl_context = area.get_gl_context()
        self.with_context(self.init_context)
    
    def resized(self, delta):
        self.with_context(self._gl_update_viewport)
    
    def _gl_update_viewport(self):
        width, height = self.size
        #print "GLView._gl_update_viewport: size =", self.size ###
        glViewport(0, 0, width, height)
        self.viewport_changed()
    
    def _gtk_expose_event_signal(self, gtk_event):
        #print "GLView._gtk_expose_event_signal" ###
        if not self._first_expose:
            self.with_context(self._gl_update_viewport)
            self._first_expose = 1
        try:
            self.with_context(self._gl_refresh)
        except:
            import sys, traceback
            sys.stderr.write("\n<<<<<<<<<< Exception while rendering a GLView\n")
            traceback.print_exc()
            sys.stderr.write(">>>>>>>>>>\n\n")
    
    def _gl_refresh(self):
        self.render()
        drawable = self._gl_drawable
        if drawable.is_double_buffered():
            drawable.swap_buffers()
        else:
            glFlush()
    
    def with_context(self, proc):
        drawable = self._gl_drawable
        if drawable and drawable.gl_begin(self._gl_context):
            try:
                proc()
            finally:
                drawable.gl_end()

    def invalidate(self):
        width, height = self.size
        self._gtk_outer_widget.window.invalidate_rect((0, 0, width, height), 0)
