/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.34 from the
 * contents of pogl_gl_top.xs. Do not edit this file, edit pogl_gl_top.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "pogl_gl_top.xs"
/*  Last saved: Sat 10 Jul 2010 12:57:04 PM*/

/*  Copyright (c) 1998 Kenneth Albanowski. All rights reserved.
 *  Copyright (c) 2007 Bob Free. All rights reserved.
 *  Copyright (c) 2009 Chris Marshall. All rights reserved.
 *  This program is free software; you can redistribute it and/or
 *  modify it under the same terms as Perl itself.
 */

/* OpenGL GLX bindings */
#define IN_POGL_GLX_XS

#include <stdio.h>

#include "pgopogl.h"

#ifdef HAVE_GL
#include "gl_util.h"

/* Note: this is caching procs once for all contexts */
/* !!! This should instead cache per context */
#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_W32API))
#define loadProc(proc,name) \
{ \
  if (!proc) \
  { \
    proc = (void *)wglGetProcAddress(name); \
    if (!proc) croak(name " is not supported by this renderer"); \
  } \
}
#define testProc(proc,name) ((proc) ? 1 : !!(proc = (void *)wglGetProcAddress(name)))
#else /* not using WGL */
#define loadProc(proc,name)
#define testProc(proc,name) 1
#endif /* not defined _WIN32, __CYGWIN__, and HAVE_W32API */
#endif /* defined HAVE_GL */

#ifdef HAVE_GLX
#include "glx_util.h"
#endif /* defined HAVE_GLX */

#ifdef HAVE_GLU
#include "glu_util.h"
#endif /* defined HAVE_GLU */



#ifdef IN_POGL_GLX_XS
#ifdef HAVE_GLX
#  define HAVE_GLpc			/* Perl interface */
#  define nativeWindowId(d, w)	(w)
static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
    return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
}
#  define glpResizeWindow(s1,s2,w,d)	XResizeWindow(d,w,s1,s2)
#  define glpMoveWindow(s1,s2,w,d)		XMoveWindow(d,w,s1,s2)
#  define glpMoveResizeWindow(s1,s2,s3,s4,w,d)	XMoveResizeWindow(d,w,s1,s2,s3,s4)
#endif	/* defined HAVE_GLX */ 



static int debug = 0;

#ifdef HAVE_GLpc

#  define NUM_ARG 7			/* Number of mandatory args to glpcOpenWindow */

Display *dpy;
int dpy_open;
XVisualInfo *vi;
Colormap cmap;
XSetWindowAttributes swa;
Window win;
GLXContext ctx;

static int default_attributes[] = { GLX_DOUBLEBUFFER, GLX_RGBA, None };

#endif	/* defined HAVE_GLpc */ 

static int DBUFFER_HACK = 0;
#define __had_dbuffer_hack() (DBUFFER_HACK)

#endif /* End IN_POGL_GLX_XS */



/********************/
/* GPGPU Utils      */
/********************/

GLint FBO_MAX = -1;

/* Get max GPGPU data size */
int gpgpu_size(void)
{
#if defined(GL_ARB_texture_rectangle) && defined(GL_ARB_texture_float) && \
  defined(GL_ARB_fragment_program) && defined(GL_EXT_framebuffer_object)
  if (FBO_MAX == -1)
  {
    if (testProc(glProgramStringARB,"glProgramStringARB") &&
      testProc(glGenProgramsARB,"glGenProgramsARB") &&
      testProc(glBindProgramARB,"glBindProgramARB") &&
      testProc(glIsProgramARB,"glIsProgramARB") &&
      testProc(glProgramLocalParameter4fvARB,"glProgramLocalParameter4fvARB") &&
      testProc(glDeleteProgramsARB,"glDeleteProgramsARB") &&
      testProc(glGenFramebuffersEXT,"glGenFramebuffersEXT") &&
      testProc(glGenRenderbuffersEXT,"glGenRenderbuffersEXT") &&
      testProc(glBindFramebufferEXT,"glBindFramebufferEXT") &&
      testProc(glFramebufferTexture2DEXT,"glFramebufferTexture2DEXT") &&
      testProc(glBindRenderbufferEXT,"glBindRenderbufferEXT") &&
      testProc(glRenderbufferStorageEXT,"glRenderbufferStorageEXT") &&
      testProc(glFramebufferRenderbufferEXT,"glFramebufferRenderbufferEXT") &&
      testProc(glCheckFramebufferStatusEXT,"glCheckFramebufferStatusEXT") &&
      testProc(glDeleteRenderbuffersEXT,"glDeleteRenderbuffersEXT") &&
      testProc(glDeleteFramebuffersEXT,"glDeleteFramebuffersEXT"))
    {
      glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT,&FBO_MAX);
    }
    else
    {
      FBO_MAX = 0;
    }
  }
  return(FBO_MAX);
#else
  return(0);
#endif
}

/* Get max square array width for a given GPGPU data size */
int gpgpu_width(int len)
{
  int max = gpgpu_size();
  if (max && len && !(len%3))
  {
    int count = len / 3;
    int w = (int)sqrt(count);

    while ((w <= count) && (w <= max))
    {
      if (!(count%w)) return(w);
      w++;
    }
  }
  return(0);
}

#ifdef GL_ARB_fragment_program
static char affine_prog[] =
  "!!ARBfp1.0\n"
  "PARAM affine[4] = {program.local[0..3]};\n"
  "TEMP decal;\n"
  "TEX decal, fragment.texcoord[0], texture[0], RECT;\n"
  "MOV decal.w, 1.0;\n"
  "DP4 result.color.x, decal, affine[0];\n"
  "DP4 result.color.y, decal, affine[1];\n"
  "DP4 result.color.z, decal, affine[2];\n"
  "END\n";

/* Enable affine shader program */
void enable_affine(oga_struct * oga)
{
  if (!oga) return;
  if (!oga->affine_handle)
  {
    /* Load shader program */
    glGenProgramsARB(1,&oga->affine_handle);
    glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,oga->affine_handle);
    glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
      GL_PROGRAM_FORMAT_ASCII_ARB, strlen(affine_prog),affine_prog);

    /* Validate shader program */
    if (!glIsProgramARB(oga->affine_handle))
    {
      GLint errorPos;
      glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB,&errorPos);
      if (errorPos < 0) errorPos = strlen(affine_prog);
      croak("Affine fragment program error\n%s",&affine_prog[errorPos]);
    }
  }
  glEnable(GL_FRAGMENT_PROGRAM_ARB);
}

/* Disable affine shader program */
void disable_affine(oga_struct * oga)
{
  if (!oga) return;
  if (oga->affine_handle) glDisable(GL_FRAGMENT_PROGRAM_ARB);
}
#endif

#ifdef GL_EXT_framebuffer_object
/* Unbind an FBO to an OGA */
void release_fbo(oga_struct * oga)
{
  if (oga->fbo_handle)
  {
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    glDeleteFramebuffersEXT(1,&oga->fbo_handle);
  }

  if (oga->tex_handle[0] || oga->tex_handle[1])
  {
    glBindTexture(oga->target,0);	
    if (oga->tex_handle[0]) glDeleteTextures(1,&oga->tex_handle[0]);
    if (oga->tex_handle[1]) glDeleteTextures(1,&oga->tex_handle[1]);
  }
}

/* Enable an FBO bound to an OGA */
void enable_fbo(oga_struct * oga, int w, int h, GLuint target,
  GLuint pixel_type, GLuint pixel_format, GLuint element_size)
{
  if (!oga) return;

  if ((oga->fbo_w != w) || (oga->fbo_h != h) ||
    (oga->target != target) ||
    (oga->pixel_type != pixel_type) ||
    (oga->pixel_format != pixel_format) ||
    (oga->element_size != element_size)) release_fbo(oga);

  if (!oga->fbo_handle)
  {
    GLenum status;

    /* Save params */
    oga->fbo_w = w;
    oga->fbo_h = h;
    oga->target = target;
    oga->pixel_type = pixel_type;
    oga->pixel_format = pixel_format;
    oga->element_size = element_size;

    /* Set up FBO */
    glGenTextures(2,oga->tex_handle);
    glGenFramebuffersEXT(1,&oga->fbo_handle);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,oga->fbo_handle);

    glViewport(0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0,w,0,h);
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity();

    glBindTexture(target,oga->tex_handle[1]);
    glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(target,GL_TEXTURE_WRAP_S,GL_CLAMP);
    glTexParameteri(target,GL_TEXTURE_WRAP_T,GL_CLAMP);

    glTexImage2D(target,0,pixel_type,w,h,0,
      pixel_format,element_size,0);

    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
      GL_COLOR_ATTACHMENT0_EXT,target,oga->tex_handle[1],0);

    status = glCheckFramebufferStatusEXT(GL_RENDERBUFFER_EXT);
    if (status) croak("enable_fbo status: %04X\n",status);
  }
  else
  {
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,oga->fbo_handle);
  }

  /* Load data */
  glBindTexture(target,oga->tex_handle[0]);
  glTexImage2D(target,0,pixel_type,w,h,0,
    pixel_format,element_size,oga->data);

  glEnable(target);
  //glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
  glBindTexture(target,oga->tex_handle[0]);
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
}

/* Disable an FBO bound to an OGA */
void disable_fbo(oga_struct * oga)
{
  if (!oga) return;
  if (oga->fbo_handle)
  {
    glDisable(oga->target);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
  }
}
#endif




#line 302 "pogl_gl_top.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#line 446 "pogl_gl_top.c"

XS_EUPXS(XS_OpenGL__have_gl); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL__have_gl)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 300 "pogl_gl_top.xs"
#ifdef HAVE_GL
	RETVAL = 1;
#else
	RETVAL = 0;
#endif /* defined HAVE_GL */
#line 463 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL__have_glu); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL__have_glu)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 312 "pogl_gl_top.xs"
#ifdef HAVE_GLU
	RETVAL = 1;
#else
	RETVAL = 0;
#endif /* defined HAVE_GLU */
#line 485 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL__have_glut); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL__have_glut)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 324 "pogl_gl_top.xs"
#if defined(HAVE_GLUT) || defined(HAVE_FREEGLUT)
	RETVAL = 1;
#else
	RETVAL = 0;
#endif /* defined HAVE_GLUT or HAVE_FREEGLUT */
#line 507 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL__have_freeglut); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL__have_freeglut)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 336 "pogl_gl_top.xs"
#if defined(HAVE_FREEGLUT)
	RETVAL = 1;
#else
	RETVAL = 0;
#endif /* defined HAVE_FREEGLUT */
#line 529 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL__have_glx); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL__have_glx)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 348 "pogl_gl_top.xs"
#ifdef HAVE_GLX
	RETVAL = 1;
#else
	RETVAL = 0;
#endif /* defined HAVE_GLX */
#line 551 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL__have_glp); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL__have_glp)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 360 "pogl_gl_top.xs"
#ifdef HAVE_GLpc
	RETVAL = 1;
#else
	RETVAL = 0;
#endif /* defined HAVE_GLpc */
#line 573 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}

#ifdef IN_POGL_GLX_XS
#define XSubPPtmpAAAA 1


XS_EUPXS(XS_OpenGL___had_dbuffer_hack); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL___had_dbuffer_hack)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;

	RETVAL = __had_dbuffer_hack();
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}

#ifdef HAVE_GLpc			/* GLX */
#define XSubPPtmpAAAB 1


XS_EUPXS(XS_OpenGL_glpcOpenWindow); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpcOpenWindow)
{
    dVAR; dXSARGS;
    if (items < 7)
       croak_xs_usage(cv,  "x, y, w, h, pw, event_mask, steal, ...");
    {
	int	x = (int)SvIV(ST(0))
;
	int	y = (int)SvIV(ST(1))
;
	int	w = (int)SvIV(ST(2))
;
	int	h = (int)SvIV(ST(3))
;
	int	pw = (int)SvIV(ST(4))
;
	long	event_mask = (long)SvIV(ST(5))
;
	int	steal = (int)SvIV(ST(6))
;
	HV *	RETVAL;
#line 403 "pogl_gl_top.xs"
{
    XEvent event;
    Window pwin = (Window)pw;
    unsigned int err;
    int *attributes = default_attributes + 1;
    int *a_buf = NULL;

    RETVAL = newHV(); /* Create hash to return GL Object info */

    if(items > NUM_ARG){
        int i;
        a_buf = (int *) malloc((items-NUM_ARG+2) * sizeof(int));
        a_buf[0] = GLX_DOUBLEBUFFER; /* Preallocate */
        attributes = a_buf + 1;
        for (i=NUM_ARG; i<items; i++) {
            attributes[i-NUM_ARG] = SvIV(ST(i));
        }
        attributes[items-NUM_ARG] = None;
    }
    if (debug) {
        int i;	
        for (i=0; attributes[i] != None; i++) {
            printf("att=%d %d\n", i, attributes[i]);
        }
    }
    /* get a connection */
    if (!dpy_open) {
        dpy = XOpenDisplay(NULL);
        dpy_open = 1;
    }
    if (!dpy) {
        croak("ERROR: failed to get an X connection");
    } else if (debug) {
        printf("Display open %x\n", dpy);
    }		

    /* get an appropriate visual */
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
    if (!vi) { /* Might have happened that one does not
                * *need* DOUBLEBUFFER, but the display does
                * not provide SINGLEBUFFER; and the semantic
                * of GLX_DOUBLEBUFFER is that if it misses,
                * only SINGLEBUFFER visuals are selected.  */
        attributes--; /* GLX_DOUBLEBUFFER preallocated there */
        vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes); /* Retry */
        if (vi)
            DBUFFER_HACK = 1;
    }
    if (a_buf)
        free(a_buf);
    if(!vi) {
        croak("ERROR: failed to get an X visual\n");
    } else if (debug) {
        printf("Visual open %x\n", vi);
    }		

    /* A blank line here will confuse xsubpp ;-) */
#ifdef HAVE_GLX
    /* create a GLX context */
    ctx = glXCreateContext(dpy, vi, 0, GL_TRUE);
    if (!ctx) {
        croak("ERROR: failed to get an X Context");
    } else if (debug) {
        printf("Context Created %x\n", ctx);
    }

    /* create a color map */
    cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
            vi->visual, AllocNone);

    /* create a window */
    swa.colormap = cmap;
    swa.border_pixel = 0;
    swa.event_mask = event_mask;
#endif	/* defined HAVE_GLX */

    if (!pwin) {
        pwin = RootWindow(dpy, vi->screen);
        if (debug) printf("Using root as parent window 0x%x\n", pwin);
    }
    if (steal) {
        win = nativeWindowId(dpy, pwin); /* What about depth/visual */
    } else {
        win = XCreateWindow(dpy, pwin, 
                x, y, w, h,
                0, vi->depth, InputOutput, vi->visual,
                CWBorderPixel|CWColormap|CWEventMask, &swa);
        /* NOTE: PDL code had CWBackPixel above */
    }
    if (!win) {
        croak("No Window");
    } else {
        if (debug) printf("win = 0x%x\n", win);
    }
    XMapWindow(dpy, win);
#ifndef HAVE_GLX  /* For OS/2 GLX emulation stuff -chm 2009.09.14 */
    /* On OS/2: cannot create a context before mapping something... */
    /* create a GLX context */
    ctx = glXCreateContext(dpy, vi, 0, GL_TRUE);
    if (!ctx)
        croak("No context!\n");

    LastEventMask = event_mask;
#else	/* HAVE_GLX, this is the default branch */
    if ( (event_mask & StructureNotifyMask) && !steal ) {
        XIfEvent(dpy, &event, WaitForNotify, (char*)win);
    }
#endif	/* not defined HAVE_GLX */

    /* connect the context to the window */
    if (!glXMakeCurrent(dpy, win, ctx))
        croak("Non current");

    if (debug)
        printf("Display=0x%x Window=0x%x Context=0x%x\n",dpy, win, ctx);

    /* Create the GL object hash information */
    hv_store(RETVAL, "Display", strlen("Display"), newSViv(PTR2IV(dpy)), 0);
    hv_store(RETVAL, "Window", strlen("Window"),   newSViv(  (IV) win ), 0);
    hv_store(RETVAL, "Context", strlen("Context"), newSViv(PTR2IV(ctx)), 0);

    hv_store(RETVAL, "GL_Version",strlen("GL_Version"), 
            newSVpv((char *) glGetString(GL_VERSION),0),0);
    hv_store(RETVAL, "GL_Vendor",strlen("GL_Vendor"), 
            newSVpv((char *) glGetString(GL_VENDOR),0),0);
    hv_store(RETVAL, "GL_Renderer",strlen("GL_Renderer"), 
            newSVpv((char *) glGetString(GL_RENDERER),0),0);

    /* clear the buffer */
    glClearColor(0,0,0,1);
    while ( (err = glGetError()) != GL_NO_ERROR ) {
        printf("ERROR issued in GL %s\n", gluErrorString(err));
    }
}
#line 760 "pogl_gl_top.c"
	{
	    SV * RETVALSV;
	    RETVALSV = newRV((SV*)RETVAL);
	    RETVALSV = sv_2mortal(RETVALSV);
	    ST(0) = RETVALSV;
	}
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL_glpRasterFont); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpRasterFont)
{
    dVAR; dXSARGS;
    if (items != 4)
       croak_xs_usage(cv,  "name, base, number, d");
    {
	char *	name = (char *)SvPV_nolen(ST(0))
;
	int	base = (int)SvIV(ST(1))
;
	int	number = (int)SvIV(ST(2))
;
	Display *	d = INT2PTR(Display *,SvIV(ST(3)))
;
	int	RETVAL;
	dXSTARG;
#line 548 "pogl_gl_top.xs"
        {
                XFontStruct *fi;
                int lb;
                fi = XLoadQueryFont(d,name);
                if(fi == NULL) {
                        die("No font %s found",name);
                }
                lb = glGenLists(number);
                if(lb == 0) {
                        die("No display lists left for font %s (need %d)",name,number);
                }
                glXUseXFont(fi->fid, base, number, lb);
                RETVAL=lb;
        }
#line 804 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL_glpPrintString); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpPrintString)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "base, str");
    {
	int	base = (int)SvIV(ST(0))
;
	char *	str = (char *)SvPV_nolen(ST(1))
;
#line 571 "pogl_gl_top.xs"
        {
                glPushAttrib(GL_LIST_BIT);
                glListBase(base);
                glCallLists(strlen(str),GL_UNSIGNED_BYTE,(GLubyte*)str);
                glPopAttrib();
        }
#line 829 "pogl_gl_top.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_OpenGL_glpDisplay); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpDisplay)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "name");
    {
	char *	name = (char *)SvPV_nolen(ST(0))
;
	Display *	RETVAL;
	dXSTARG;
#line 583 "pogl_gl_top.xs"
	    /* get a connection */
	    if (!dpy_open) {
		dpy = XOpenDisplay(name);
		dpy_open = 1;
	    }
	    if (!dpy)
		croak("No display!");
	    RETVAL = dpy;
#line 855 "pogl_gl_top.c"
	XSprePUSH; PUSHi(PTR2IV(RETVAL));
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL_glpMoveResizeWindow); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpMoveResizeWindow)
{
    dVAR; dXSARGS;
    if (items < 4 || items > 6)
       croak_xs_usage(cv,  "x, y, width, height, w=win, d=dpy");
    {
	void*	d;
	GLXDrawable	w;
	int	x = (int)SvIV(ST(0))
;
	int	y = (int)SvIV(ST(1))
;
	unsigned int	width = (unsigned int)SvUV(ST(2))
;
	unsigned int	height = (unsigned int)SvUV(ST(3))
;

	if (items < 6)
	    d = dpy;
	else {
	    d = INT2PTR(void *,SvIV(ST(5)))
;
	}

	if (items < 5)
	    w = win;
	else {
	    w = INT2PTR(GLXDrawable,SvIV(ST(4)))
;
	}

	glpMoveResizeWindow(x, y, width, height, w, d);
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_OpenGL_glpMoveWindow); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpMoveWindow)
{
    dVAR; dXSARGS;
    if (items < 2 || items > 4)
       croak_xs_usage(cv,  "x, y, w=win, d=dpy");
    {
	void*	d;
	GLXDrawable	w;
	int	x = (int)SvIV(ST(0))
;
	int	y = (int)SvIV(ST(1))
;

	if (items < 4)
	    d = dpy;
	else {
	    d = INT2PTR(void *,SvIV(ST(3)))
;
	}

	if (items < 3)
	    w = win;
	else {
	    w = INT2PTR(GLXDrawable,SvIV(ST(2)))
;
	}

	glpMoveWindow(x, y, w, d);
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_OpenGL_glpResizeWindow); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpResizeWindow)
{
    dVAR; dXSARGS;
    if (items < 2 || items > 4)
       croak_xs_usage(cv,  "width, height, w=win, d=dpy");
    {
	void*	d;
	GLXDrawable	w;
	unsigned int	width = (unsigned int)SvUV(ST(0))
;
	unsigned int	height = (unsigned int)SvUV(ST(1))
;

	if (items < 4)
	    d = dpy;
	else {
	    d = INT2PTR(void *,SvIV(ST(3)))
;
	}

	if (items < 3)
	    w = win;
	else {
	    w = INT2PTR(GLXDrawable,SvIV(ST(2)))
;
	}

	glpResizeWindow(width, height, w, d);
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_OpenGL_glXSwapBuffers); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glXSwapBuffers)
{
    dVAR; dXSARGS;
    if (items < 0 || items > 2)
       croak_xs_usage(cv,  "w=win, d=dpy");
    {
	void *	d;
	GLXDrawable	w;

	if (items < 2)
	    d = dpy;
	else {
	    d = INT2PTR(void *,SvIV(ST(1)))
;
	}

	if (items < 1)
	    w = win;
	else {
	    w = INT2PTR(GLXDrawable,SvIV(ST(0)))
;
	}
#line 629 "pogl_gl_top.xs"
	{
	    glXSwapBuffers(d,w);
	}
#line 995 "pogl_gl_top.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_OpenGL_XPending); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_XPending)
{
    dVAR; dXSARGS;
    if (items < 0 || items > 1)
       croak_xs_usage(cv,  "d=dpy");
    {
	void *	d;
	int	RETVAL;
	dXSTARG;

	if (items < 1)
	    d = dpy;
	else {
	    d = INT2PTR(void *,SvIV(ST(0)))
;
	}
#line 638 "pogl_gl_top.xs"
	{
		RETVAL = XPending(d);
	}
#line 1022 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL_glpXNextEvent); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpXNextEvent)
{
    dVAR; dXSARGS;
    if (items < 0 || items > 1)
       croak_xs_usage(cv,  "d=dpy");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	void *	d;

	if (items < 1)
	    d = dpy;
	else {
	    d = INT2PTR(void *,SvIV(ST(0)))
;
	}
#line 649 "pogl_gl_top.xs"
	{
		XEvent event;
		char buf[10];
		KeySym ks;
		XNextEvent(d,&event);
		switch(event.type) {
			case ConfigureNotify:
				EXTEND(sp,3);
				PUSHs(sv_2mortal(newSViv(event.type)));
				PUSHs(sv_2mortal(newSViv(event.xconfigure.width)));
				PUSHs(sv_2mortal(newSViv(event.xconfigure.height)));				
				break;
			case KeyPress:
			case KeyRelease:
				EXTEND(sp,2);
				PUSHs(sv_2mortal(newSViv(event.type)));
				XLookupString(&event.xkey,buf,sizeof(buf),&ks,0);
				buf[0]=(char)ks;buf[1]='\0';
				PUSHs(sv_2mortal(newSVpv(buf,1)));
				break;
			case ButtonPress:
			case ButtonRelease:
				EXTEND(sp,7);
				PUSHs(sv_2mortal(newSViv(event.type)));
				PUSHs(sv_2mortal(newSViv(event.xbutton.button)));
				PUSHs(sv_2mortal(newSViv(event.xbutton.x)));
				PUSHs(sv_2mortal(newSViv(event.xbutton.y)));
				PUSHs(sv_2mortal(newSViv(event.xbutton.x_root)));
				PUSHs(sv_2mortal(newSViv(event.xbutton.y_root)));
				PUSHs(sv_2mortal(newSViv(event.xbutton.state)));
				break;
			case MotionNotify:
				EXTEND(sp,4);
				PUSHs(sv_2mortal(newSViv(event.type)));
				PUSHs(sv_2mortal(newSViv(event.xmotion.state)));
				PUSHs(sv_2mortal(newSViv(event.xmotion.x)));
				PUSHs(sv_2mortal(newSViv(event.xmotion.y)));
				break;
			case Expose:
			default:
				EXTEND(sp,1);
				PUSHs(sv_2mortal(newSViv(event.type)));
				break;
		}
	}
#line 1092 "pogl_gl_top.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_OpenGL_glpXQueryPointer); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpXQueryPointer)
{
    dVAR; dXSARGS;
    if (items < 0 || items > 2)
       croak_xs_usage(cv,  "w=win, d=dpy");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	void *	d;
	GLXDrawable	w;

	if (items < 2)
	    d = dpy;
	else {
	    d = INT2PTR(void *,SvIV(ST(1)))
;
	}

	if (items < 1)
	    w = win;
	else {
	    w = INT2PTR(GLXDrawable,SvIV(ST(0)))
;
	}
#line 701 "pogl_gl_top.xs"
	{
		int x,y,rx,ry;
		Window r,c;
		unsigned int m;
		XQueryPointer(d,w,&r,&c,&rx,&ry,&x,&y,&m);
		EXTEND(sp,3);
		PUSHs(sv_2mortal(newSViv(x)));
		PUSHs(sv_2mortal(newSViv(y)));
		PUSHs(sv_2mortal(newSViv(m)));
	}
#line 1135 "pogl_gl_top.c"
	PUTBACK;
	return;
    }
}

#endif /* defined HAVE_GLpc */

XS_EUPXS(XS_OpenGL_glpSetDebug); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpSetDebug)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "flag");
    {
	int	flag = (int)SvIV(ST(0))
;
#line 720 "pogl_gl_top.xs"
        {
        debug = flag;
        }
#line 1156 "pogl_gl_top.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_OpenGL_glpReadTex); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpReadTex)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "file");
    {
	char *	file = (char *)SvPV_nolen(ST(0))
;
#line 730 "pogl_gl_top.xs"
	{
		GLsizei w,h;
		int d,i;
		char buf[250];
		unsigned char *image;
		FILE *fp;
		char *ret;

		fp=fopen(file,"r");

		if(!fp)	croak("couldn't open file %s",file);

		ret = fgets(buf,250,fp);		/* P3 */

		if (buf[0] != 'P' || buf[1] != '3')
			croak("Format is not P3 in file %s",file);

		ret = fgets(buf,250,fp);

		while (buf[0] == '#' && fgets(buf,250,fp));	/* Empty */

		if (2 != sscanf(buf,"%d%d",&w,&h))
			croak("couldn't read image size from file %s",file);
		if (1 != fscanf(fp,"%d",&d))
			croak("couldn't read image depth from file %s",file);
		if(d != 255)
			croak("image depth != 255 in file %s unsupported",file);
		if(w>10000 || h>10000)
			croak("suspicious size w=%d d=%d in file %s", w, d, file);

		New(1431, image, w*h*3, unsigned char);

		for(i=0;i<w*h*3;i++) {
			int v;

			if (1 != fscanf(fp,"%d",&v)) {
				Safefree(image);
				croak("Error reading number #%d of %d from file %s", i, w*h*3,file);
			}

			image[i]=(unsigned char) v;
		}

		fclose(fp);

		glTexImage2D(GL_TEXTURE_2D, 0, 3, w,h, 
			0, GL_RGB, GL_UNSIGNED_BYTE,image);
	}
#line 1220 "pogl_gl_top.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_OpenGL_glpHasGLUT); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpHasGLUT)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 783 "pogl_gl_top.xs"
	{
#if defined(HAVE_GLUT) || defined(HAVE_FREEGLUT)
		RETVAL = 1;
#else
		RETVAL = 0;
#endif /* defined HAVE_GLUT or HAVE_FREEGLUT */
	}
#line 1243 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_OpenGL_glpHasGPGPU); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_OpenGL_glpHasGPGPU)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 798 "pogl_gl_top.xs"
		RETVAL = gpgpu_size();
#line 1261 "pogl_gl_top.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}

#endif /* End IN_POGL_GLX_XS */
#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_OpenGL__GL__Top); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_OpenGL__GL__Top)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

        newXS_deffile("OpenGL::_have_gl", XS_OpenGL__have_gl);
        newXS_deffile("OpenGL::_have_glu", XS_OpenGL__have_glu);
        newXS_deffile("OpenGL::_have_glut", XS_OpenGL__have_glut);
        newXS_deffile("OpenGL::_have_freeglut", XS_OpenGL__have_freeglut);
        newXS_deffile("OpenGL::_have_glx", XS_OpenGL__have_glx);
        newXS_deffile("OpenGL::_have_glp", XS_OpenGL__have_glp);
#if XSubPPtmpAAAA
        newXS_deffile("OpenGL::__had_dbuffer_hack", XS_OpenGL___had_dbuffer_hack);
#if XSubPPtmpAAAB
        newXS_deffile("OpenGL::glpcOpenWindow", XS_OpenGL_glpcOpenWindow);
        newXS_deffile("OpenGL::glpRasterFont", XS_OpenGL_glpRasterFont);
        newXS_deffile("OpenGL::glpPrintString", XS_OpenGL_glpPrintString);
        newXS_deffile("OpenGL::glpDisplay", XS_OpenGL_glpDisplay);
        newXS_deffile("OpenGL::glpMoveResizeWindow", XS_OpenGL_glpMoveResizeWindow);
        newXS_deffile("OpenGL::glpMoveWindow", XS_OpenGL_glpMoveWindow);
        newXS_deffile("OpenGL::glpResizeWindow", XS_OpenGL_glpResizeWindow);
        newXS_deffile("OpenGL::glXSwapBuffers", XS_OpenGL_glXSwapBuffers);
        newXS_deffile("OpenGL::XPending", XS_OpenGL_XPending);
        newXS_deffile("OpenGL::glpXNextEvent", XS_OpenGL_glpXNextEvent);
        newXS_deffile("OpenGL::glpXQueryPointer", XS_OpenGL_glpXQueryPointer);
#endif
        newXS_deffile("OpenGL::glpSetDebug", XS_OpenGL_glpSetDebug);
        newXS_deffile("OpenGL::glpReadTex", XS_OpenGL_glpReadTex);
        newXS_deffile("OpenGL::glpHasGLUT", XS_OpenGL_glpHasGLUT);
        newXS_deffile("OpenGL::glpHasGPGPU", XS_OpenGL_glpHasGPGPU);
#endif

    /* Initialisation Section */

#if XSubPPtmpAAAA
#if XSubPPtmpAAAB
#endif
#endif
#line 1329 "pogl_gl_top.c"

    /* End of Initialisation Section */

#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

