/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/

/*
* File name 	: wgl.c
* WGL stuff. Added by Oleg Letsinsky, ajl@ultersys.ru
* Some things originated from the 3Dfx WGL functions
*/


#ifdef WIN32

#ifdef __cplusplus
extern "C" {
#endif

#include <GL/gl.h>
#include <GL/glu.h>

#ifdef __cplusplus
}
#endif

#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include "wmesadef.h"
#include "GL/wmesa.h"
#include "types.h"

#define MAX_MESA_ATTRS	20

struct __extensions__
{
    PROC	proc;
    char	*name;
};

struct __pixelformat__
{
    PIXELFORMATDESCRIPTOR	pfd;
    GLboolean doubleBuffered;
};

struct __extensions__	ext[] = {

#ifdef GL_EXT_polygon_offset
    {	(PROC)glPolygonOffsetEXT,		"glPolygonOffsetEXT"			},
#endif
    {	(PROC)glBlendEquationEXT,		"glBlendEquationEXT"			},
    {	(PROC)glBlendColorEXT,			"glBlendColorExt"			},
    {	(PROC)glVertexPointerEXT,		"glVertexPointerEXT"			},
    {	(PROC)glNormalPointerEXT,		"glNormalPointerEXT"			},
    {	(PROC)glColorPointerEXT,		"glColorPointerEXT"			},
    {	(PROC)glIndexPointerEXT,		"glIndexPointerEXT"			},
    {	(PROC)glTexCoordPointerEXT,		"glTexCoordPointer"			},
    {	(PROC)glEdgeFlagPointerEXT,		"glEdgeFlagPointerEXT"		        },
    {	(PROC)glGetPointervEXT,			"glGetPointervEXT"			},
    {	(PROC)glArrayElementEXT,		"glArrayElementEXT"			},
    {	(PROC)glDrawArraysEXT,			"glDrawArrayEXT"			},
    {	(PROC)glAreTexturesResidentEXT,	"glAreTexturesResidentEXT"	                },
    {	(PROC)glBindTextureEXT,			"glBindTextureEXT"			},
    {	(PROC)glDeleteTexturesEXT,		"glDeleteTexturesEXT"			},
    {	(PROC)glGenTexturesEXT,			"glGenTexturesEXT"			},
    {	(PROC)glIsTextureEXT,			"glIsTextureEXT"			},
    {	(PROC)glPrioritizeTexturesEXT,	"glPrioritizeTexturesEXT"		        },
    {	(PROC)glCopyTexSubImage3DEXT,	"glCopyTexSubImage3DEXT"		        },
    {	(PROC)glTexImage3DEXT,			"glTexImage3DEXT"			},
    {	(PROC)glTexSubImage3DEXT,		"glTexSubImage3DEXT"			},
};

int				qt_ext = sizeof(ext) / sizeof(ext[0]);

struct __pixelformat__	pix[] =
{
    {	{	sizeof(PIXELFORMATDESCRIPTOR),	1,
        PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_GENERIC_FORMAT|PFD_DOUBLEBUFFER|PFD_SWAP_COPY,
        PFD_TYPE_RGBA,
        24,	8,	0,	8,	8,	8,	16,	8,	24,
        0,	0,	0,	0,	0,	16,	8,	0,	0,	0,	0,	0,	0 },
        GL_TRUE
    },
    {	{	sizeof(PIXELFORMATDESCRIPTOR),	1,
        PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_GENERIC_FORMAT,
        PFD_TYPE_RGBA,
        24,	8,	0,	8,	8,	8,	16,	8,	24,
        0,	0,	0,	0,	0,	16,	8,	0,	0,	0,	0,	0,	0 },
        GL_FALSE
    },
};

int				qt_pix = sizeof(pix) / sizeof(pix[0]);

typedef struct {
    WMesaContext ctx;
    HDC hdc;
} MesaWglCtx;

#define MESAWGL_CTX_MAX_COUNT 20

static MesaWglCtx wgl_ctx[MESAWGL_CTX_MAX_COUNT];

static unsigned ctx_count = 0;
static unsigned ctx_current = 0;
static unsigned curPFD = 0;

WINGDIAPI BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,HGLRC hglrcDst,UINT mask)
{
    return(FALSE);
}

WINGDIAPI HGLRC WINAPI wglCreateContext(HDC hdc)
{
    HWND		hWnd;
    int i = 0;
    if(!(hWnd = WindowFromDC(hdc)))
    {
        SetLastError(0);
        return(NULL);
    }
    if (!ctx_count)
    {
    	for(i=0;i<MESAWGL_CTX_MAX_COUNT;i++)
    	{
    		wgl_ctx[i].ctx = NULL;
    		wgl_ctx[i].hdc = NULL;
    	}
    }
    for( i = 0; i < MESAWGL_CTX_MAX_COUNT; i++ )
    {
        if ( wgl_ctx[i].ctx == NULL )
        {
            wgl_ctx[i].ctx = WMesaCreateContext( hWnd, NULL, GL_TRUE,
                pix[curPFD-1].doubleBuffered );
            if (wgl_ctx[i].ctx == NULL)
                break;
            wgl_ctx[i].hdc = hdc;
            ctx_count++;
            return ((HGLRC)wgl_ctx[i].ctx);
        }
    }
    SetLastError(0);
    return(NULL);
}

WINGDIAPI BOOL WINAPI wglDeleteContext(HGLRC hglrc)
{
    int i;
    for ( i = 0; i < MESAWGL_CTX_MAX_COUNT; i++ )
    {
    	if ( wgl_ctx[i].ctx == hglrc )
    	{
            WMesaMakeCurrent(hglrc);
            WMesaDestroyContext();
            wgl_ctx[i].ctx = NULL;
            wgl_ctx[i].hdc = NULL;
            ctx_count--;
            return(TRUE);
    	}
    }
    SetLastError(0);
    return(FALSE);
}

WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC hdc,int iLayerPlane)
{
    SetLastError(0);
    return(NULL);
}

WINGDIAPI HGLRC WINAPI wglGetCurrentContext(VOID)
{
    return wgl_ctx[ctx_current].ctx;
}

WINGDIAPI HDC WINAPI wglGetCurrentDC(VOID)
{
    return wgl_ctx[ctx_current].hdc;
}

WINGDIAPI BOOL WINAPI wglMakeCurrent(HDC hdc,HGLRC hglrc)
{
    int i;
    for ( i = 0; i < MESAWGL_CTX_MAX_COUNT; i++ )
    {
        if ( wgl_ctx[i].ctx == hglrc )
        {
            wgl_ctx[i].hdc = hdc;
            WMesaMakeCurrent( (WMesaContext) hglrc );
            ctx_current = i;
            return TRUE;
        }
    }
    return FALSE;
}

WINGDIAPI BOOL WINAPI wglShareLists(HGLRC hglrc1,HGLRC hglrc2)
{
    return(TRUE);
}

WINGDIAPI BOOL WINAPI wglUseFontBitmapsA(HDC hdc,DWORD first,DWORD count,DWORD listBase)
{
    return(FALSE);
}

WINGDIAPI BOOL WINAPI wglUseFontBitmapsW(HDC hdc,DWORD first,DWORD count,DWORD listBase)
{
    return(FALSE);
}

WINGDIAPI BOOL WINAPI wglUseFontOutlinesA(HDC hdc,DWORD first,DWORD count,
                                  DWORD listBase,FLOAT deviation,
                                  FLOAT extrusion,int format,
                                  LPGLYPHMETRICSFLOAT lpgmf)
{
    SetLastError(0);
    return(FALSE);
}

WINGDIAPI BOOL WINAPI wglUseFontOutlinesW(HDC hdc,DWORD first,DWORD count,
                                  DWORD listBase,FLOAT deviation,
                                  FLOAT extrusion,int format,
                                  LPGLYPHMETRICSFLOAT lpgmf)
{
    SetLastError(0);
    return(FALSE);
}

WINGDIAPI BOOL WINAPI wglDescribeLayerPlane(HDC hdc,int iPixelFormat,
                                    int iLayerPlane,UINT nBytes,
                                    LPLAYERPLANEDESCRIPTOR plpd)
{
    SetLastError(0);
    return(FALSE);
}

WINGDIAPI int WINAPI wglSetLayerPaletteEntries(HDC hdc,int iLayerPlane,
                                       int iStart,int cEntries,
                                       CONST COLORREF *pcr)
{
    SetLastError(0);
    return(0);
}

WINGDIAPI int WINAPI wglGetLayerPaletteEntries(HDC hdc,int iLayerPlane,
                                       int iStart,int cEntries,
                                       COLORREF *pcr)
{
    SetLastError(0);
    return(0);
}

WINGDIAPI BOOL WINAPI wglRealizeLayerPalette(HDC hdc,int iLayerPlane,BOOL bRealize)
{
    SetLastError(0);
    return(FALSE);
}

WINGDIAPI BOOL WINAPI wglSwapLayerBuffers(HDC hdc,UINT fuPlanes)
{
    if( !hdc )
    {
        WMesaSwapBuffers();
        return(TRUE);
    }
    SetLastError(0);
    return(FALSE);
}

WINGDIAPI int WINAPI wglChoosePixelFormat(HDC hdc,
                                  CONST PIXELFORMATDESCRIPTOR *ppfd)
{
    int		i,best = -1,bestdelta = 0x7FFFFFFF,delta,qt_valid_pix;

    qt_valid_pix = qt_pix;
    if(ppfd->nSize != sizeof(PIXELFORMATDESCRIPTOR) || ppfd->nVersion != 1)
    {
        SetLastError(0);
        return(0);
    }
    for(i = 0;i < qt_valid_pix;i++)
    {
        delta = 0;
        if(
            (ppfd->dwFlags & PFD_DRAW_TO_WINDOW) &&
            !(pix[i].pfd.dwFlags & PFD_DRAW_TO_WINDOW))
            continue;
        if(
            (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) &&
            !(pix[i].pfd.dwFlags & PFD_DRAW_TO_BITMAP))
            continue;
        if(
            (ppfd->dwFlags & PFD_SUPPORT_GDI) &&
            !(pix[i].pfd.dwFlags & PFD_SUPPORT_GDI))
            continue;
        if(
            (ppfd->dwFlags & PFD_SUPPORT_OPENGL) &&
            !(pix[i].pfd.dwFlags & PFD_SUPPORT_OPENGL))
            continue;
        if(
            !(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) &&
            ((ppfd->dwFlags & PFD_DOUBLEBUFFER) != (pix[i].pfd.dwFlags & PFD_DOUBLEBUFFER)))
            continue;
        if(
            !(ppfd->dwFlags & PFD_STEREO_DONTCARE) &&
            ((ppfd->dwFlags & PFD_STEREO) != (pix[i].pfd.dwFlags & PFD_STEREO)))
            continue;
        if(ppfd->iPixelType != pix[i].pfd.iPixelType)
            delta++;
        if(delta < bestdelta)
        {
            best = i + 1;
            bestdelta = delta;
            if(bestdelta == 0)
                break;
        }
    }
    if(best == -1)
    {
        SetLastError(0);
        return(0);
    }
    return(best);
}

WINGDIAPI int WINAPI wglDescribePixelFormat(HDC hdc,int iPixelFormat,UINT nBytes,
                                    LPPIXELFORMATDESCRIPTOR ppfd)
{
    int		qt_valid_pix;

    qt_valid_pix = qt_pix;
    if(iPixelFormat < 1 || iPixelFormat > qt_valid_pix || nBytes != sizeof(PIXELFORMATDESCRIPTOR))
    {
        SetLastError(0);
        return(0);
    }
    *ppfd = pix[iPixelFormat - 1].pfd;
    return(qt_valid_pix);
}

/*
* GetProcAddress - return the address of an appropriate extension
*/
WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR lpszProc)
{
    int		i;
    for(i = 0;i < qt_ext;i++)
        if(!strcmp(lpszProc,ext[i].name))
            return(ext[i].proc);

        SetLastError(0);
        return(NULL);
}

WINGDIAPI int WINAPI wglGetPixelFormat(HDC hdc)
{
    if(curPFD == 0)
    {
        SetLastError(0);
        return(0);
    }
    return(curPFD);
}

WINGDIAPI BOOL WINAPI wglSetPixelFormat(HDC hdc,int iPixelFormat,
                                PIXELFORMATDESCRIPTOR *ppfd)
{
    int		qt_valid_pix;

    qt_valid_pix = qt_pix;
    if(iPixelFormat < 1 || iPixelFormat > qt_valid_pix || ppfd->nSize != sizeof(PIXELFORMATDESCRIPTOR))
    {
        SetLastError(0);
        return(FALSE);
    }
    curPFD = iPixelFormat;
    return(TRUE);
}

WINGDIAPI BOOL WINAPI wglSwapBuffers(HDC hdc)
{
    if(wgl_ctx[ctx_current].ctx==NULL)
    {
        SetLastError(0);
        return(FALSE);
    }
    WMesaSwapBuffers();
    return(TRUE);
}

#endif /* WIN32 */
