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

import win32con as wc, win32ui as ui, win32gui as gui
#import OpenGL.GL as gl ###
import GUI.GDIPlus as gdi
from OpenGL import WGL as wgl
from OpenGL.WGL import ChoosePixelFormat
#print "Using ctypes ChoosePixelFormat"
#from WGL import ChoosePixelFormat
from GUI.WinUtils import win_none
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_pixelformat(self, mode):
        #print "GLConfig._as_win_pixelformat: mode =", mode ###
        pf = wgl.PIXELFORMATDESCRIPTOR()
        flags = wgl.PFD_SUPPORT_OPENGL
        if mode == 'screen' or mode == 'both':
            #print "GLConfig: requesting screen drawing" ###
            flags |= wgl.PFD_DRAW_TO_WINDOW
            if self._double_buffer:
                flags |= wgl.PFD_DOUBLEBUFFER | wgl.PFD_SWAP_EXCHANGE
        else:
            flags |= wgl.PFD_DOUBLEBUFFER_DONTCARE
        if mode == 'pixmap' or mode == 'both':
            #print "GLConfig: requesting pixmap drawing" ###
            flags |= wgl.PFD_DRAW_TO_BITMAP | wgl.PFD_SUPPORT_GDI
        if not self._depth_buffer:
            flags |= wgl.PFD_DEPTH_DONTCARE
        if self._stereo:
            flags |= wgl.PFD_STEREO
        else:
            flags |= wgl.PFD_STEREO_DONTCARE
        pf.dwFlags = flags & 0xffffffff
        pf.iPixelType = wgl.PFD_TYPE_RGBA
        #pf.cColorBits = 3 * self._color_size
        #pf.cColorBits = 32 ###
        pf.cRedBits = pf.cGreenBits = pf.cBluedBits = self._color_size
        if self._alpha:
            pf.cAlphaBits = self._alpha_size
        pf.cAuxBuffers = self._aux_buffers
        if self._depth_buffer:
            pf.cDepthBits = self._depth_size
        if self._stencil_buffer:
            pf.cStencilBits = self._stencil_size
        if self._accum_buffer:
            pf.cAccumBits = 3 * self._accum_size
        pf.iLayerType = wgl.PFD_MAIN_PLANE
        return pf
    
    def _from_win_pixelformat(cls, pf):
        self = cls.__new__(cls)
        flags = pf.dwFlags
        self._double_buffer = flags & wgl.PFD_DOUBLEBUFFER != 0
        self._alpha = pf.cAlphaSize > 0
        self._color_size = pf.cColorBits
        self._alpha_size = pf.cAlphaSize
        self._stereo = flags & wgl.PFD_STEREO != 0
        self._aux_buffers = pf.cAuxBuffers
        self._depth_buffer = pf.cDepthBits > 0
        self._depth_size = pf.cDepthBits
        self._stencil_buffer = pf.cStencilBits > 0
        self._stencil_size = pf.cStencilBits
        self._accum_size = pf.cAccumBits
        self._accum_buffer = self._accum_size > 0
        self._multisample = False
        self._samples_per_pixel = 1
        return self
    
    def _check_win_pixelformat(self, pf, mode):
        flags = pf.dwFlags
        if mode == 'screen' or mode == 'both':
            if not flags & wgl.PFD_DRAW_TO_WINDOW:
                raise GLConfigError("Rendering to screen not supported")
        if mode == 'pixmap' or mode == 'both':
            if not flags & wgl.PFD_DRAW_TO_BITMAP:
                raise GLConfigError("Rendering to pixmap not supported")
        if self._alpha and pf.cAlphaBits == 0:
            raise GLConfigError("Alpha channel not available")
        if self._stereo and not flags & wgl.PFD_STEREO:
            raise GLConfigError("Stereo buffer not available")
        if self._aux_buffers and pf.cAuxBuffers == 0:
            raise GLConfigError("Auxiliary buffers not available")
        if self._depth_buffer and pf.cDepthBits == 0:
            raise GLConfigError("Depth buffer not available")
        if self._stencil_buffer and pf.cStencilBits == 0:
            raise GLConfigError("Stencil buffer not available")
        if self.accum_buffer and pf.cAccumBits == 0:
            raise GLConfigError("Accumulation buffer not available")
        
    def _win_supported_pixelformat(self, hdc, mode):
        reqpf = self._as_win_pixelformat(mode)
        #print "GLConfig._win_supported_pixelformat" ###
        #print "Requested format:" ###
        #win_dump_pixelformat(reqpf) ###
        #print "GLConfig: Choosing pixel format for hdc", hdc ###
        ipf = wgl.ChoosePixelFormat(hdc, reqpf)
        #print "... result =", ipf ###
        actpf = wgl.PIXELFORMATDESCRIPTOR()
        #print "GLConfig: Describing pixel format", ipf, "for hdc", hdc ###
        wgl.DescribePixelFormat(hdc, ipf, actpf.nSize, actpf)
        #print "Actual format:" ###
        #win_dump_pixelformat(actpf) ###
        return ipf, actpf
    
    def supported(self, mode = 'both'):
        dc = win_none.GetDC()
        hdc = dc.GetSafeHdc()
        ipf, actpf = self._win_supported_pixelformat(hdc, mode)
        win_none.ReleaseDC(dc)
        return GLConfig._from_win_pixelformat(actpf)

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

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)
        self.set(**kwds)
        self._with_context(hdc, self._init_context)
        win.ReleaseDC(dc)
    
#	def _init_context(self):
#		print "GL_VENDOR:", gl.glGetString(gl.GL_VENDOR)
#		print "GL_RENDERER:", gl.glGetString(gl.GL_RENDERER)
#		print "GL_VERSION:", gl.glGetString(gl.GL_VERSION)
#		print "GL_EXTENSIONS:"
#		for name in gl.glGetString(gl.GL_EXTENSIONS).split():
#			print "   ", name
#		GGLView._init_context(self)
    
    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)
        dc0 = win_none.GetDC()
        dc = dc0.CreateCompatibleDC(dc0)
        bm = ui.CreateBitmap()
        bm.CreateCompatibleBitmap(dc0, width, height)
        win_none.ReleaseDC(dc0)
        dc.SelectObject(bm)
        self._win_dc = dc
        self._win_bm = bm
        hdc = dc.GetSafeHdc()
        win_dump_bitmap(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

def win_dump_bitmap(bm):
    info = bm.GetInfo()
    print "bmType =", info['bmType']
    print "bmWidth =", info['bmWidth']
    print "bmHeight =", info['bmHeight']
    print "bmWidthBytes =", info['bmWidthBytes']
    print "bmPlanes =", info['bmPlanes']
    print "bmBitsPixel =", info['bmBitsPixel']

    