#------------------------------------------------------------------------------
#
#   PyGUI - OpenGL - Win32
#
#------------------------------------------------------------------------------

import win32con as wc, win32ui as ui, win32gui as gui
import GDIPlus as gdi
import WGL
from GUI.Components import win_none
from GUI.OpenGL import WGL as wgl
from GUI.GGLViews import GLView as GGLView
from GUI.GGLPixmaps import GLPixmap as GGLPixmap
from GUI.GGLConfig import GLConfig as GGLConfig, GLConfigError
from GUI.GLContexts import GLContext
from GUI.GLTextures import Texture

win_style = wc.WS_VISIBLE | wc.WS_CLIPCHILDREN | wc.WS_CLIPSIBLINGS
win_default_size = GGLView._default_size
win_default_rect = (0, 0, win_default_size[0], win_default_size[1])

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

class GLConfig(GGLConfig):

    def _as_win_pixelattrs(self, mode):
        print "GLConfig._as_arb_pixelattrs: mode =", mode ###
        attrs = {}
        attrs[wgl.WGL_SUPPORT_OPENGL_ARB] = True
        if mode == 'screen' or mode == 'both':
            print "GLConfig: requesting screen drawing" ###
            attrs[wgl.WGL_DRAW_TO_WINDOW_ARB] = True
            if self._double_buffer:
                attrs[wgl.WGL_DOUBLE_BUFFER_ARB] = True
        if mode == 'pixmap' or mode == 'both':
            print "GLConfig: requesting pixmap drawing" ###
            attrs[wgl.WGL_DRAW_TO_PBUFFER_ARB] = True
        if self._stereo:
            attrs[wgl.WGL_STEREO_ARB] = True
        attrs[wgl.WGL_PIXEL_TYPE_ARB] = wgl.WGL_TYPE_RGBA_ARB
        bits = self._color_size
        attrs[wgl.WGL_RED_BITS_ARB] = bits
        attrs[wgl.WGL_GREEN_BITS_ARB] = bits
        attrs[wgl.WGL_BLUE_BITS_ARB] = bits
        if self._alpha:
            attrs[wgl.WGL_ALPHA_BITS_ARB] = self._alpha_size
        attrs[wgl.WGL_AUX_BUFFERS_ARB] = self._aux_buffers
        if self._depth_buffer:
            attrs[wgl.WGL_DEPTH_BITS_ARB] = self._depth_size
        if self._stencil_buffer:
            attrs[wgl.WGL_STENCIL_BITS_ARB] = self._stencil_size
        if self._accum_buffer:
            bits = self._accum_size
            attrs[wgl.WGL_ACCUM_RED_BITS_ARB] = bits
            attrs[wgl.WGL_ACCUM_GREEN_BITS_ARB] = bits
            attrs[wgl.WGL_ACCUM_BLUE_BITS_ARB] = bits
        return attrs
    
    def _from_win_pixelattrs(cls, attrs):
        self = cls.__new__(cls)
        self._double_buffer = attrs[wgl.WGL_DOUBLE_BUFFER_ARB]
        self._color_size = attrs[wgl.WGL_COLOR_BITS_ARB] // 3
        self._alpha_size = attrs[wgl.WGL_ALPHA_BITS_ARB]
        self._alpha = self._alpha_size > 0
        self._stereo = attrs[wgl.WGL_STEREO_ARB] #flags & wgl.PFD_STEREO != 0
        self._aux_buffers = attrs[wgl.WGL_AUX_BUFFERS_ARB] > 0
        self._depth_size = attrs[wgl.WGL_DEPTH_BITS_ARB]
        self._depth_buffer = self._depth_size > 0
        self._stencil_size = attrs[wgl.WGL_STENCIL_BITS_ARB]
        self._stencil_buffer = self._stencil_bits > 0
        self._accum_size = attrs[wgl.WGL_ACCUM_BITS_ARB] // 3
        self._accum_buffer = self._accum_size > 0
        self._multisample = False
        self._samples_per_pixel = 1
        return self
    
#	def _check_win_pixelattrs(self, attrs, mode):
#		if mode == 'screen' or mode == 'both':
#			if not attrs[wgl.WGL_DRAW_TO_WINDOW_ARB]:
#				raise GLConfigError("Rendering to screen not supported")
#		if mode == 'pixmap' or mode == 'both':
#			if not attrs[wgl.WGL_DRAW_TO_PBUFFER_ARB]:
#				raise GLConfigError("Rendering to pixmap not supported")
#		if self._alpha and attrs[wgl.WGL_ALPHA_BITS_ARB] == 0:
#			raise GLConfigError("Alpha channel not available")
#		if self._stereo and not attrs[wgl.WGL_STEREO_ARB]:
#			raise GLConfigError("Stereo buffer not available")
#		if self._aux_buffers and attrs]wgl.WGL_AUX_BUFFERS_ARB] == 0:
#			raise GLConfigError("Auxiliary buffers not available")
#		if self._depth_buffer and attrs[wgl.WGL_DEPTH_BITS_ARB] == 0:
#			raise GLConfigError("Depth buffer not available")
#		if self._stencil_buffer and attrs[wgl.WGL_STENCIL_BITS] == 0:
#			raise GLConfigError("Stencil buffer not available")
#		if self.accum_buffer and attrs[wgl.WGL_ACCUM_BITS] == 0:
#			raise GLConfigError("Accumulation buffer not available")

    _win_query_pixelattr_keys = [
        wgl.WGL_SUPPORT_OPENGL_ARB,
        wgl.WGL_DRAW_TO_WINDOW_ARB,
        wgl.WGL_DOUBLE_BUFFER_ARB,
        wgl.WGL_DRAW_TO_PBUFFER_ARB,
        wgl.WGL_STEREO_ARB,
        wgl.WGL_PIXEL_TYPE_ARB,
        wgl.WGL_COLOR_BITS_ARB,
        wgl.WGL_ALPHA_BITS_ARB,
        wgl.WGL_AUX_BUFFERS_ARB,
        wgl.WGL_DEPTH_BITS_ARB,
        wgl.WGL_STENCIL_BITS_ARB,
        wgl.WGL_ACCUM_BITS_ARB,
    ]
        
    def _win_supported_pixelformat(self, hdc, mode):
        req_attrs = self._as_win_pixelattrs(mode)
        print "GLConfig: Choosing pixel format for hdc", hdc ###
        print "Requested attributes:", req_attrs ###
        req_array = WGL.attr_array(req_attrs)
        print "Requested array:", req_array ###
        ipfs, nf = wgl.wglChoosePixelFormatEXT(hdc, req_array, None, 1)
        print "Pixel formats:", ipfs ###
        print "No. of formats:", nf ###
        if not ipfs:
            req_attrs[wgl.WGL_DOUBLE_BUFFER_ARB] = not self._double_buffer
            req_array = WGL.attr_array(req_attrs)
            ipfs, nf = wglChoosePixelFormatARB(hdc, req_array, None, 1)
        if not ipfs:
            return None, None
        print "GLConfig: Describing pixel format", ipf, "for hdc", hdc ###
        keys = _win_query_pixelattr_keys
        values = wglGetPixelFormatAttribivARB(hdc, ipf, 0, keys)
        print "Actual values:", values ###
        act_attrs = WGL.attr_dict(keys, values)
        print "Actual attrs:", act_attrs ###
        return ipfs[0], act_attrs
    
    def supported(self, mode = 'both'):
        dc = win_none.GetDC()
        hdc = dc.GetSafeHdc()
        ipf, act_attrs = self._win_supported_pixelformat(hdc, mode)
        win_none.ReleaseDC(dc)
        if ipf is None:
            return None
        return GLConfig._from_win_pixelattrs(act_attrs)

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

class GLView(GGLView):

    def __init__(self, config = None, share_group = None, **kwds):
        config = GLConfig._from_args(config, kwds)
        win = ui.CreateWnd()
        win.CreateWindow(None, None, win_style, win_default_rect,
            win_none, 0)
        dc = win.GetDC()
        hdc = dc.GetSafeHdc()
        GLContext.__init__(self, share_group, config, hdc, 'screen')
        GGLView.__init__(self, _win = win, **kwds)
        self._with_context(hdc, self._init_context)
        win.ReleaseDC(dc)
    
    def destroy(self):
        GLContext.destroy(self)
        GGLView.destroy(self)
    
    def with_context(self, proc, flush = False):
        win = self._win
        dc = win.GetDC()
        hdc = dc.GetSafeHdc()
        try:
            self._with_context(hdc, proc, flush)
        finally:
            win.ReleaseDC(dc)

    def OnPaint(self):
        #print "GLView.OnPaint" ###
        win = self._win
        dc, ps = win.BeginPaint()
        try:
            hdc = dc.GetSafeHdc()
            self._with_context(hdc, self.render, True)
        finally:
            win.EndPaint(ps)
    
    def _resized(self, delta):
        self.with_context(self._update_viewport)

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

#class GLPixmap(GGLPixmap):
#
#	def __init__(self, width, height, config = None, share_group = None, **kwds):
#		print "GLPixmap:", width, height, kwds ###
#		config = GLConfig._from_args(config, kwds)
#		image = gdi.Bitmap(width, height)
#		self._win_image = image
#		graphics = gdi.Graphics.from_image(image)
#		self._win_graphics = graphics
#		hdc = graphics.GetHDC()
#		self._win_hdc = hdc
#		GLContext.__init__(self, share_group, config, hdc, 'pixmap')
#		self._with_context(hdc, self._init_context)
#		print "GLPixmap: done" ###
#	
#	def __del__(self):
#		graphics = self._win_graphics
#		graphics.ReleaseHDC(self._win_hdc)
#
#	def with_context(self, proc, flush = False):
#		try:
#			self._with_context(self._hdc, proc, flush)
#		finally:
#			graphics.ReleaseHDC(hdc)

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

class GLPixmap(GGLPixmap):

    def __init__(self, width, height, config = None, share_group = None, **kwds):
        print "GLPixmap:", width, height, kwds ###
        config = GLConfig._from_args(config, kwds)
        pyhdc = gui.CreateCompatibleDC(0)
        dc = ui.CreateDCFromHandle(pyhdc)
        hdc = dc.GetSafeHdc()
        hbm = gui.CreateCompatibleBitmap(hdc, width, height)
        bm = ui.CreateBitmapFromHandle(hbm)
        dc.SelectObject(bm)
        self._win_dc = dc
        self._win_hbm = hbm
        self._win_bm = bm
        GLContext.__init__(self, share_group, config, hdc, 'pixmap')
        self._with_context(hdc, self._init_context)
        print "GLPixmap: done" ###

    def with_context(self, proc, flush = False):
        hdc = self._win_dc.GetSafeHdc()
        self._with_context(hdc, proc, flush)

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

def win_dump_pixelformat(pf):
    print "nSize =", pf.nSize
    print "nVersion =", pf.nVersion
    print "dwFlags = 0x%08x" % pf.dwFlags
    print "iPixelType =", pf.iPixelType
    print "cColorBits =", pf.cColorBits
    print "cRedBits =", pf.cRedBits
    print "cRedShift =", pf.cRedShift
    print "cGreenBits =", pf.cGreenBits
    print "cGreenShift =", pf.cGreenShift
    print "cBlueBits =", pf.cBlueBits
    print "cBlueShift =", pf.cBlueShift
    print "cAlphaBits =", pf.cAlphaBits
    print "cAlphaShift =", pf.cAlphaShift
    print "cAccumBits =", pf.cAccumBits
    print "cAccumRedBits =", pf.cAccumRedBits
    print "cAccumGreenBits =", pf.cAccumGreenBits
    print "cAccumBlueBits =", pf.cAccumBlueBits
    print "cDepthBits =", pf.cDepthBits
    print "cStencilBits =", pf.cStencilBits
    print "cAuxBuffers =", pf.cAuxBuffers
    print "iLayerType =", pf.iLayerType
    print "bReserved =", pf.bReserved
    print "dwLayerMask =", pf.dwLayerMask
    print "dwVisibleMask =", pf.dwVisibleMask
    print "dwDamageMask =", pf.dwDamageMask
