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

import win32con as wc, win32ui as ui, win32gui as gui
import GUI.GDIPlus as gdi
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_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.cAlphaBits = 8 ###
        pf.cAlphaShift = 24 ###
        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, **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)
#		dc0 = win_none.GetDC()
#		dc = dc0.CreateCompatibleDC(dc0)
#		bm = ui.CreateBitmap()
#		###bm.CreateCompatibleBitmap(dc0, width, height)
#		bm.CreateCompatibleBitmap(dc0, 1, 1)
#		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']

    