/*
 *  file OpenGL.xs is generated by OpenGL.xs.gen 
 */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>
#include <unistd.h>
#include <stdio.h>

#define NUM_ARG 6

Display *dpy;
XVisualInfo *vi;
Colormap cmap;
XSetWindowAttributes swa;
Window win;
GLXContext cx;

static int default_attributes[] = { GLX_RGBA, /*GLX_DOUBLEBUFFER,*/  None };
static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
    return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
}


MODULE = OpenGL		PACKAGE = OpenGL


void
glpcOpenWindow(x,y,w,h,pw,event_mask, ...)
	int	x
	int	y
	int	w
	int	h
	int	pw
	long	event_mask
	CODE:
	{
	    XEvent event;
	    Window pwin=(Window)pw;
	    int *attributes = default_attributes;
	    if(items>NUM_ARG){
	        int i;
	        attributes = (int *)malloc((items-NUM_ARG+1)* sizeof(int));
	        for(i=NUM_ARG;i<items;i++) {
	            attributes[i-NUM_ARG]=SvIV(ST(i));
	        }
	        attributes[items-NUM_ARG]=None;
	    }
	    /* get a connection */
	    dpy = XOpenDisplay(0);
	    if (!dpy) { fprintf(stderr, "No display!\n");exit(-1);}
	
	    /* get an appropriate visual */
	    vi = glXChooseVisual(dpy, DefaultScreen(dpy),attributes);
	    if(!vi) { fprintf(stderr, "No visual!\n");exit(-1);}
	
	    /* create a GLX context */
	    cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
	    if(!cx){fprintf(stderr, "No context!\n");exit(-1);}
	
	    /* 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;
	    if(!pwin){pwin=RootWindow(dpy, vi->screen);}
	    win = XCreateWindow(dpy, pwin, 
				x, y, w, h,
				0, vi->depth, InputOutput, vi->visual,
				CWBorderPixel|CWColormap|CWEventMask, &swa);
	    if(!win) {
	        fprintf(stderr, "No Window\n");
	        exit(-1);
	    }
	    XMapWindow(dpy, win);
	    if(event_mask & StructureNotifyMask) {
	        XIfEvent(dpy, &event, WaitForNotify, (char*)win);
	    }

	    /* connect the context to the window */
	    if(!glXMakeCurrent(dpy, win, cx)) {
	        fprintf(stderr, "Non current\n");
	        exit(-1);
	    }
	
	    /* clear the buffer */
	    glClearColor(0,0,0,1);
	}

# If glpOpenWindow was used then glXSwapBuffers should be called
# without parameters (i.e. use the default parameters)

void
glXSwapBuffers(d=dpy,w=win)
	void *	d
	GLXDrawable	w
	CODE:
	{
	    glXSwapBuffers(d,w);
	}


int
XPending(d=dpy)
	void *	d
	CODE:
	{
		RETVAL = XPending(d);
	}
	OUTPUT:
	RETVAL

void
glpXNextEvent(d=dpy)
	void *	d
	PPCODE:
	{
		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,4);
				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)));
				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;
		}
	}

void
glpXQueryPointer(d=dpy,w=win)
	void *	d
	GLXDrawable	w
	PPCODE:
	{
		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)));
	}

#
# The following XSUBS were done by hand
# These are perl-ized versions of the corresponding opengl function
# The reason is that the API with respect to 
# arguments and/or return value differs from the C equivalent
# These functions are more elegant to call and provide better error checking
# than the equivalent counter-part that needs pointer arguments
#

void
glpClipPlane(p,a,b,c,d)
	GLenum	p
	GLdouble	a
	GLdouble	b
	GLdouble	c
	GLdouble	d
	CODE:
	{
		GLdouble e[4];
		e[0]=a;e[1]=b;e[2]=c;e[3]=d;
		glClipPlane(p,e);
	}

void
glpGetClipPlane(plane)
	GLenum	plane
	PPCODE:
	{
	    GLdouble equation[4];
	    glGetClipPlane(plane,equation);
	    EXTEND(sp,4);
	    PUSHs(sv_2mortal(newSVnv(equation[0])));
	    PUSHs(sv_2mortal(newSVnv(equation[1])));
	    PUSHs(sv_2mortal(newSVnv(equation[2])));
	    PUSHs(sv_2mortal(newSVnv(equation[3])));
	}

void
glpReadTex(file)
	char *	file
	CODE:
	{
	    GLsizei w,h;
	    int d,i;
	    char buf[250];
	    unsigned char *image;
	    FILE *fp;
	    fp=fopen(file,"r");
	    if(!fp) {
	        fprintf(stderr,"couldn't open file %s\n",file);
	        return;
	    }
	    fgets(buf,250,fp);
	    fgets(buf,250,fp);
	    fscanf(fp,"%d%d",&w,&h);
	    fscanf(fp,"%d",&d);
	    if(d != 255 || w<64 || h<64 || w>10000 || h>10000) {
	        fprintf(stderr,"error reading %s\n",file);
	        return;
	    }
	    image=(unsigned char *)malloc(w*h*3);
	    for(i=0;i<w*h*3;i++) {
		int v;
	        fscanf(fp,"%d",&v);
	        image[i]=(unsigned char) v;
	    }
	    fclose(fp);
	    glTexImage2D(GL_TEXTURE_2D, 0, 3, w,h, 
	                 0, GL_RGB, GL_UNSIGNED_BYTE,image);
	}


void
glpLoadMatrixd(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,ma,mb,mc,md,me,mf)
	GLdouble	m0
	GLdouble	m1
	GLdouble	m2
	GLdouble	m3
	GLdouble	m4
	GLdouble	m5
	GLdouble	m6
	GLdouble	m7
	GLdouble	m8
	GLdouble	m9
	GLdouble	ma
	GLdouble	mb
	GLdouble	mc
	GLdouble	md
	GLdouble	me
	GLdouble	mf
	CODE:
	{
		GLdouble m[16];
		m[0]= m0; m[1]= m1; m[2]= m2; m[3]= m3;
		m[4]= m4; m[5]= m5; m[6]= m6; m[7]= m7;
		m[8]= m8; m[9]= m9; m[10]=ma; m[11]=mb;
		m[12]=mc; m[13]=md; m[14]=me; m[15]=mf;
		glLoadMatrixd(m);
	}

void
glpMultMatrixd(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,ma,mb,mc,md,me,mf)
	GLdouble	m0
	GLdouble	m1
	GLdouble	m2
	GLdouble	m3
	GLdouble	m4
	GLdouble	m5
	GLdouble	m6
	GLdouble	m7
	GLdouble	m8
	GLdouble	m9
	GLdouble	ma
	GLdouble	mb
	GLdouble	mc
	GLdouble	md
	GLdouble	me
	GLdouble	mf
	CODE:
	{
		GLdouble m[16];
		m[0]= m0; m[1]= m1; m[2]= m2; m[3]= m3;
		m[4]= m4; m[5]= m5; m[6]= m6; m[7]= m7;
		m[8]= m8; m[9]= m9; m[10]=ma; m[11]=mb;
		m[12]=mc; m[13]=md; m[14]=me; m[15]=mf;
		glMultMatrixd(m);
	}

void
glpLoadMatrixf(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,ma,mb,mc,md,me,mf)
	GLfloat	m0
	GLfloat	m1
	GLfloat	m2
	GLfloat	m3
	GLfloat	m4
	GLfloat	m5
	GLfloat	m6
	GLfloat	m7
	GLfloat	m8
	GLfloat	m9
	GLfloat	ma
	GLfloat	mb
	GLfloat	mc
	GLfloat	md
	GLfloat	me
	GLfloat	mf
	CODE:
	{
		GLfloat m[16];
		m[0]= m0; m[1]= m1; m[2]= m2; m[3]= m3;
		m[4]= m4; m[5]= m5; m[6]= m6; m[7]= m7;
		m[8]= m8; m[9]= m9; m[10]=ma; m[11]=mb;
		m[12]=mc; m[13]=md; m[14]=me; m[15]=mf;
		glLoadMatrixf(m);
	}


void
glpMultMatrixf(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,ma,mb,mc,md,me,mf)
	GLfloat	m0
	GLfloat	m1
	GLfloat	m2
	GLfloat	m3
	GLfloat	m4
	GLfloat	m5
	GLfloat	m6
	GLfloat	m7
	GLfloat	m8
	GLfloat	m9
	GLfloat	ma
	GLfloat	mb
	GLfloat	mc
	GLfloat	md
	GLfloat	me
	GLfloat	mf
	CODE:
	{
		GLfloat m[16];
		m[0]= m0; m[1]= m1; m[2]= m2; m[3]= m3;
		m[4]= m4; m[5]= m5; m[6]= m6; m[7]= m7;
		m[8]= m8; m[9]= m9; m[10]=ma; m[11]=mb;
		m[12]=mc; m[13]=md; m[14]=me; m[15]=mf;
		glMultMatrixf(m);
	}


#
# Here are the glu ones that have been done so far:
#


void
gluOrtho2D(left,right,bottom,top)
	GLdouble	left
	GLdouble	right
	GLdouble	bottom
	GLdouble	top

void
gluPerspective(fovy,aspect,zNear,zFar)
	GLdouble	fovy
	GLdouble	aspect
	GLdouble	zNear
	GLdouble	zFar

void
gluLookAt(eyex,eyey,eyez,centerx,centery,centerz,upx,upy,upz)
	GLdouble	eyex
	GLdouble	eyey
	GLdouble	eyez
	GLdouble	centerx
	GLdouble	centery
	GLdouble	centerz
	GLdouble	upx
	GLdouble	upy
	GLdouble	upz




#
#  Some of the following XSUBS functions have 1 or more pointers as arguments
#  The type was changed to "char *" for each of these so you can
#  use perl's pack() routine to pass the required data to the C function.
#  See examples/texture for an example using glTexImage2D().
#  Be sure to pack your data properly (see the man page for the 
#  function) there is no sanity check here.  Use a glpFunctionName() or
#  a non-vector equivalent wherever possible
#
#  and now the gl XSUBs that were generated: 
#
##################################################

#EVAL:  `perl ./getfunctions`
