#
#   PyGUI - OpenGL View - Gtk/GtkGLExt
#

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

from GGLConfig import GLConfig as GGLConfig, GLConfigError
from GGLViews import GLView as GGLView
from GGLPixmaps import GLPixmap as GGLPixmap
from ImageBases import ImageBase
#from GtkInput import GtkInput
from GtkPixmaps import GtkPixmap
from GLContexts import GLContext
from GLTextures import Texture
from GLDisplayLists import DisplayList

#------------------------------------------------------------------------------

def gtk_find_config_default(attr, mode_bit):
    try:
        cfg = gdkgl.Config(mode = mode_bit)
        value = cfg.get_attrib(attr)[0]
    except gdkgl.NoMatches:
        value = 0
    print "default for attr", attr, "=", value
    return value

#------------------------------------------------------------------------------

class GLConfig(GGLConfig):
    
    _alpha = False
    _color_size = 1
    _alpha_size = 1
    _depth_size = 1
    _stencil_size = 1
    _accum_size = 1
    
    def _gtk_get_config(self):
        cs = self._color_size
        as = 0
        ds = 0
        ss = 0
        acs = 0
        aas = 0
        if self._alpha:
            as = self._alpha_size
        if self._depth_buffer:
            ds = self._depth_size
        if self._stencil_buffer:
            ss = self._stencil_size
        if self._accum_buffer:
            acs = self._accum_size
            if self._alpha:
                aas = acs
        attrs = [
            gdkgl.RGBA,
            gdkgl.RED_SIZE, cs,
            gdkgl.GREEN_SIZE, cs,
            gdkgl.BLUE_SIZE, cs,
            gdkgl.ALPHA_SIZE, as,
            gdkgl.AUX_BUFFERS, self._aux_buffers,
            gdkgl.DEPTH_SIZE, ds,
            gdkgl.STENCIL_SIZE, ss,
            gdkgl.ACCUM_RED_SIZE, acs,
            gdkgl.ACCUM_GREEN_SIZE, acs,
            gdkgl.ACCUM_BLUE_SIZE, acs,
            gdkgl.ACCUM_ALPHA_SIZE, aas,
        ]
        if self._double_buffer:
            attrs += [gdkgl.DOUBLEBUFFER]
        if self._stereo:
            attrs += [gdkgl.STEREO]
        if self._multisample:
            attrs += [
                gdkgl.SAMPLE_BUFFERS, 1,
                gdkgl.SAMPLES, self._samples_per_pixel
            ]
        result = self._gdkgl_config(attrs)
        if not result and self._double_buffer:
            attrs.remove(gdkgl.DOUBLEBUFFER)
            result = self._gdkgl_config(attrs)
        if not result:
            raise GLConfigError
        return result
    
    def _gdkgl_config(self, attrs):
        try:
            return gdkgl.Config(attrib_list = attrs)
        except gdkgl.NoMatches:
            return None
    
    def _gtk_set_config(self, gtk_config):
        def attr(key):
            return gtk_config.get_attrib(key)[0]
        self._color_size = attr(gdkgl.RED_SIZE)
        self._alpha_size = attr(gdkgl.ALPHA_SIZE)
        self._alpha = gtk_config.has_alpha()
        self._double_buffer = gtk_config.is_double_buffered()
        self._stereo = gtk_config.is_stereo()
        self._aux_buffers = attr(gdkgl.AUX_BUFFERS)
        self._depth_size = attr(gdkgl.DEPTH_SIZE)
        self._depth_buffer = gtk_config.has_depth_buffer()
        self._stencil_size = attr(gdkgl.STENCIL_SIZE)
        self._stencil_buffer = gtk_config.has_stencil_buffer()
        self._accum_size = attr(gdkgl.ACCUM_RED_SIZE)
        self._accum_buffer = gtk_config.has_accum_buffer()
        self._multisample = attr(gdkgl.SAMPLE_BUFFERS) <> 0
        self._samples_per_pixel = attr(gdkgl.SAMPLES)
    
    def supported(self):
        try:
            gtk_config = self._gtk_get_config()
            pf = GLConfig.__new__(GLConfig)
            pf._gtk_set_config(gtk_config)
            return pf
        except GLConfigError:
            return None

#------------------------------------------------------------------------------

class GLView(GGLView):

    _first_expose = 0

    def __init__(self, config = None, share_group = None, **kwds):
        pf = GLConfig._from_args(config, kwds)
        GLContext.__init__(self, share_group, pf, kwds)
#		#print pf.supported().__dict__ ###
#		config = pf._gtk_get_config()
#		self._gl_config = config
#		if share:
#			gtk_share = share.shared_context._gtk_get_gl_context()
#		else:
#			gtk_share = None
        gtk_share = self._gtk_get_share()
        area = gtkgl.DrawingArea(glconfig = self._gl_config, share_list = gtk_share,
            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, _gtk_input = area,
            _gtk_focus = area, **kwds)
        #GtkInput.__init__(self, area)

    def resized(self, delta):
        self.with_context(self._gl_update_viewport)
    
    def _gtk_get_gl_context(self):
        if not self._gl_context:
            self._gtk_inner_widget.realize()
        return self._gl_context
    
    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 _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.render, flush = True)
        except:
            import sys, traceback
            sys.stderr.write("\n<<<<<<<<<< Exception while rendering a GLView\n")
            traceback.print_exc()
            sys.stderr.write(">>>>>>>>>>\n\n")
    
    def invalidate(self):
        gtk_window = self._gtk_outer_widget.window
        if gtk_window:
            width, height = self.size
            gtk_window.invalidate_rect((0, 0, width, height), 0)

#------------------------------------------------------------------------------

class GLPixmap(GtkPixmap, GGLPixmap):

    def __init__(self, width, height, config = None, share_group = None, **kwds):
        pf = GLConfig._from_args(config, kwds)
        GLContext.__init__(self, share_group, pf, kwds)
#		gl_config = pf._gtk_get_config()
#		self._gl_config = gl_config
#		if share:
#			gtk_share = share.shared_context._gtk_get_gl_context()
#		else:
#			gtk_share = None
        gtk_share = self._gtk_get_share()
        GtkPixmap.__init__(self, width, height)
        gdk_pixmap = self._gdk_pixmap
        gdkgl.ext(gdk_pixmap)
        self._gl_drawable = gdk_pixmap.set_gl_capability(glconfig = gl_config)
        print "GLPixmap: self._gl_drawable =", self._gl_drawable ###
        self._gl_context = gdkgl.Context(
            self._gl_drawable,
            direct = False,
            share_list = gtk_share,
            render_type = gdkgl.RGBA_TYPE
        )
        print "GLPixmap: self._gl_context =", self._gl_context ###
        ImageBase.__init__(self, **kwds)
        self.with_context(self._init_context)
        print "GLPixmap: initialised context" ###

    def _init_context(self):
        width, height = self.size
        glViewport(0, 0, int(width), int(height))
        print "GLPixmap: Set viewport to", width, height ###
        self.init_context()

    