# -------------------------------------------------------------------------
#
#   Albow - OpenGL widgets
#
#-------------------------------------------------------------------------

from __future__ import division
from OpenGL import GL, GLU
from widget import Widget


class GLViewport(Widget):
    is_gl_container = True

    def gl_draw_self(self, root, offset):
        rect = self.rect.move(offset)
        # GL_CLIENT_ALL_ATTRIB_BITS is borked: defined as -1 but
        # glPushClientAttrib insists on an unsigned long.
        #GL.glPushClientAttrib(0xffffffff)
        #GL.glPushAttrib(GL.GL_ALL_ATTRIB_BITS)
        GL.glViewport(rect.left, root.height - rect.bottom, rect.width, rect.height)
        self.gl_draw_viewport()
        #GL.glPopAttrib()
        #GL.glPopClientAttrib()

    def gl_draw_viewport(self):
        self.setup_matrices()
        self.gl_draw()

    def setup_matrices(self):
        GL.glMatrixMode(GL.GL_PROJECTION)
        GL.glLoadIdentity()
        self.setup_projection()
        GL.glMatrixMode(GL.GL_MODELVIEW)
        GL.glLoadIdentity()
        self.setup_modelview()

    def setup_projection(self):
        pass

    def setup_modelview(self):
        pass

    def gl_draw(self):
        pass

    def augment_mouse_event(self, event):
        Widget.augment_mouse_event(self, event)
        w, h = self.size
        viewport = numpy.array((0, 0, w, h), dtype='int32')
        self.setup_matrices()
        gf = GL.glGetDoublev
        pr_mat = gf(GL.GL_PROJECTION_MATRIX)
        mv_mat = gf(GL.GL_MODELVIEW_MATRIX)
        x, y = event.local
        y = h - y
        up = GLU.gluUnProject
        try:
            p0 = up(x, y, 0.0, mv_mat, pr_mat, viewport)
            p1 = up(x, y, 1.0, mv_mat, pr_mat, viewport)
            event.dict['ray'] = (p0, p1)
        except ValueError:  # projection failed!
            pass


import numpy

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


class GLOrtho(GLViewport):
    def __init__(self, rect=None,
                 xmin=-1, xmax=1, ymin=-1, ymax=1,
                 near=-1, far=1, **kwds):
        GLViewport.__init__(self, rect, **kwds)
        self.xmin = xmin
        self.xmax = xmax
        self.ymin = ymin
        self.ymax = ymax
        self.near = near
        self.far = far

    def setup_projection(self):
        GL.glOrtho(self.xmin, self.xmax, self.ymin, self.ymax,
                   self.near, self.far)


class GLPixelOrtho(GLOrtho):
    def __init__(self, rect=None, near=-1, far=1, **kwds):
        GLOrtho.__init__(self, rect, near, far, **kwds)
        self.xmin = 0
        self.ymin = 0
        self.xmax = self.width
        self.ymax = self.height


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


class GLPerspective(GLViewport):
    def __init__(self, rect=None, fovy=20,
                 near=0.1, far=1000, **kwds):
        GLViewport.__init__(self, rect, **kwds)
        self.fovy = fovy
        self.near = near
        self.far = far

    def setup_projection(self):
        aspect = self.width / self.height
        GLU.gluPerspective(self.fovy, aspect, self.near, self.far)
