diff options
| author | Ian Romanick <ian.d.romanick@intel.com> | 2009-08-18 12:20:36 -0700 | 
|---|---|---|
| committer | Ian Romanick <ian.d.romanick@intel.com> | 2009-08-18 12:20:36 -0700 | 
| commit | a512985fd81c1ed4ccc5e69aaa05015cf7ff844d (patch) | |
| tree | 69e6e898deaeaed2b4dfb5851707c68261c464de /progs | |
| parent | 0b5af41c6fae2809f4567a7cecbd207e5e4f3ab5 (diff) | |
| parent | c80bc3abcd3939e5e2d45aea4b01ff22bfec244b (diff) | |
Merge branch 'master' into asm-shader-rework-1
Conflicts:
	src/mesa/shader/arbprogparse.c
Diffstat (limited to 'progs')
48 files changed, 5374 insertions, 383 deletions
diff --git a/progs/demos/cubemap.c b/progs/demos/cubemap.c index 1f9f290575..0df5ff09c3 100644 --- a/progs/demos/cubemap.c +++ b/progs/demos/cubemap.c @@ -43,6 +43,9 @@  #include "GL/glut.h"  #include "readtex.h" +#ifndef GL_TEXTURE_CUBE_MAP_SEAMLESS +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#endif  static GLfloat Xrot = 0, Yrot = 0;  static GLfloat EyeDist = 10; @@ -53,6 +56,8 @@ static GLint FrameParity = 0;  static GLenum FilterIndex = 0;  static GLint ClampIndex = 0;  static GLboolean supportFBO = GL_FALSE; +static GLboolean supportSeamless = GL_FALSE; +static GLboolean seamless = GL_FALSE;  static struct { @@ -91,7 +96,9 @@ static struct { -#define eps1 0.99 +/* The effects of GL_ARB_seamless_cube_map don't show up unless eps1 is 1.0. + */ +#define eps1 1.0 /*0.99*/  #define br   20.0  /* box radius */  static const GLfloat tex_coords[] = { @@ -231,6 +238,13 @@ static void draw( void )     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER,                     FilterModes[FilterIndex].mag_mode); +   if (supportSeamless) { +      if (seamless) { +	 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); +      } else { +	 glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); +      } +   }     wrap = ClampModes[ClampIndex].mode;     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, wrap);     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, wrap); @@ -321,6 +335,11 @@ static void key(unsigned char k, int x, int y)           mode = !mode;           set_mode(mode);           break; +      case 's': +	 seamless = ! seamless; +	 printf("Seamless cube map filtering is %sabled\n", +		(seamless) ? "en" : "dis" ); +	 break;        case 'v':           use_vertex_arrays = ! use_vertex_arrays;           printf( "Vertex arrays are %sabled\n", @@ -502,23 +521,26 @@ static void load_envmaps(void)  static void init( GLboolean useImageFiles )  {     /* check for extensions */ -   { -      char *exten = (char *) glGetString(GL_EXTENSIONS); -      if (!strstr(exten, "GL_ARB_texture_cube_map")) { -         printf("Sorry, this demo requires GL_ARB_texture_cube_map\n"); -         exit(0); -      } +   if (!GLEW_ARB_texture_cube_map) { +      printf("Sorry, this demo requires GL_ARB_texture_cube_map\n"); +      exit(0); +   } -      /* Needed for glGenerateMipmapEXT / auto mipmapping -       */ -      if (strstr(exten, "GL_EXT_framebuffer_object")) { -         supportFBO = GL_TRUE; -      } -      else if (!strstr(exten, "GL_SGIS_generate_mipmap")) { -         printf("Sorry, this demo requires GL_EXT_framebuffer_object or GL_SGIS_generate_mipmap\n"); -         exit(0); -      } +   /* Needed for glGenerateMipmapEXT / auto mipmapping +    */ +   supportFBO = GLEW_EXT_framebuffer_object; + +   if (!supportFBO && !GLEW_SGIS_generate_mipmap) { +      printf("Sorry, this demo requires GL_EXT_framebuffer_object or " +	     "GL_SGIS_generate_mipmap\n"); +      exit(0);     } + +   /* GLEW doesn't know about this extension yet, so use the old GLUT function +    * to check for availability. +    */ +   supportSeamless = glutExtensionSupported("GL_ARB_seamless_cube_map"); +     printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));     if (useImageFiles) { diff --git a/progs/egl/Makefile b/progs/egl/Makefile index d3c32d46f7..fd72f540ca 100644 --- a/progs/egl/Makefile +++ b/progs/egl/Makefile @@ -17,6 +17,7 @@ PROGRAMS = \  	eglgears \  	eglscreen \  	peglgears \ +	xeglbindtex \  	xeglgears \  	xeglthreads \  	xegl_tri @@ -84,6 +85,12 @@ peglgears.o: peglgears.c $(HEADERS)  	$(CC) -c $(CFLAGS) -I$(TOP)/include peglgears.c +xeglbindtex: xeglbindtex.o $(TOP)/$(LIB_DIR)/libEGL.so +	$(CC) $(CFLAGS) xeglbindtex.o -L$(TOP)/$(LIB_DIR) -lEGL -lGL $(LIBDRM_LIB) $(APP_LIB_DEPS) -o $@ + +xeglbindtex.o: xeglbindtex.c $(HEADERS) +	$(CC) -c $(CFLAGS) -I$(TOP)/include xeglbindtex.c +  xeglgears: xeglgears.o $(TOP)/$(LIB_DIR)/libEGL.so  	$(CC) $(CFLAGS) xeglgears.o -L$(TOP)/$(LIB_DIR) -lEGL -lGL $(LIBDRM_LIB) $(APP_LIB_DEPS) -o $@ diff --git a/progs/egl/xeglbindtex.c b/progs/egl/xeglbindtex.c new file mode 100644 index 0000000000..fdd9fe2b87 --- /dev/null +++ b/progs/egl/xeglbindtex.c @@ -0,0 +1,474 @@ +/* + * Simple demo for eglBindTexImage.  Based on xegl_tri.c by + * + * Copyright (C) 2008  Brian Paul   All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The spec says that eglBindTexImage supports only OpenGL ES context, but this + * demo uses OpenGL context.  Keep in mind that this is non-standard. + */ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <GL/gl.h> +#include <EGL/egl.h> + +static EGLDisplay dpy; +static EGLContext ctx_win, ctx_pbuf; +static EGLSurface surf_win, surf_pbuf; +static GLuint tex_pbuf; + +static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0; +static GLboolean blend = GL_TRUE; +static GLuint color_flow; + +static void +make_pbuffer(int width, int height) +{ +   static const EGLint config_attribs[] = { +      EGL_RED_SIZE, 8, +      EGL_GREEN_SIZE, 8, +      EGL_BLUE_SIZE, 8, +      EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE, +      EGL_NONE +   }; +   EGLint pbuf_attribs[] = { +      EGL_WIDTH, width, +      EGL_HEIGHT, height, +      EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB, +      EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, +      EGL_NONE +   }; +   EGLConfig config; +   EGLint num_configs; + +   if (!eglChooseConfig(dpy, config_attribs, &config, 1, &num_configs)) { +      printf("Error: couldn't get an EGL visual config for pbuffer\n"); +      exit(1); +   } + +   eglBindAPI(EGL_OPENGL_API); +   ctx_pbuf = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL ); +   surf_pbuf = eglCreatePbufferSurface(dpy, config, pbuf_attribs); +   if (surf_pbuf == EGL_NO_SURFACE) { +      printf("failed to allocate pbuffer\n"); +      exit(1); +   } + +   glGenTextures(1, &tex_pbuf); +} + +static void +use_pbuffer(void) +{ +   static int initialized; + +   eglMakeCurrent(dpy, surf_pbuf, surf_pbuf, ctx_pbuf); +   if (!initialized) { +      EGLint width, height; +      GLfloat ar; + +      initialized = 1; + +      eglQuerySurface(dpy, surf_pbuf, EGL_WIDTH, &width); +      eglQuerySurface(dpy, surf_pbuf, EGL_WIDTH, &height); +      ar = (GLfloat) width / (GLfloat) height; + +      glViewport(0, 0, (GLint) width, (GLint) height); + +      glMatrixMode(GL_PROJECTION); +      glLoadIdentity(); +      glFrustum(-ar, ar, -1, 1, 1.0, 10.0); + +      glMatrixMode(GL_MODELVIEW); +      glLoadIdentity(); + +      /* y-inverted */ +      glScalef(1.0, -1.0, 1.0); + +      glTranslatef(0.0, 0.0, -5.0); + +      glClearColor(0.2, 0.2, 0.2, 0.0); +   } +} + +static void +make_window(Display *x_dpy, const char *name, +            int x, int y, int width, int height, +            Window *winRet) +{ +   static const EGLint attribs[] = { +      EGL_RED_SIZE, 8, +      EGL_GREEN_SIZE, 8, +      EGL_BLUE_SIZE, 8, +      EGL_ALPHA_SIZE, 8, +      EGL_DEPTH_SIZE, 8, +      EGL_NONE +   }; + +   int scrnum; +   XSetWindowAttributes attr; +   unsigned long mask; +   Window root; +   Window win; +   XVisualInfo *visInfo, visTemplate; +   int num_visuals; +   EGLConfig config; +   EGLint num_configs, vid; + +   scrnum = DefaultScreen( x_dpy ); +   root = RootWindow( x_dpy, scrnum ); + +   if (!eglChooseConfig(dpy, attribs, &config, 1, &num_configs)) { +      printf("Error: couldn't get an EGL visual config\n"); +      exit(1); +   } + +   if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { +      printf("Error: eglGetConfigAttrib() failed\n"); +      exit(1); +   } + +   /* The X window visual must match the EGL config */ +   visTemplate.visualid = vid; +   visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); +   if (!visInfo) { +      printf("Error: couldn't get X visual\n"); +      exit(1); +   } + +   /* window attributes */ +   attr.background_pixel = 0; +   attr.border_pixel = 0; +   attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone); +   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; +   attr.override_redirect = 0; +   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect; + +   win = XCreateWindow( x_dpy, root, 0, 0, width, height, +		        0, visInfo->depth, InputOutput, +		        visInfo->visual, mask, &attr ); + +   /* set hints and properties */ +   { +      XSizeHints sizehints; +      sizehints.x = x; +      sizehints.y = y; +      sizehints.width  = width; +      sizehints.height = height; +      sizehints.flags = USSize | USPosition; +      XSetNormalHints(x_dpy, win, &sizehints); +      XSetStandardProperties(x_dpy, win, name, name, +                              None, (char **)NULL, 0, &sizehints); +   } + +   eglBindAPI(EGL_OPENGL_API); +   ctx_win = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL ); +   if (!ctx_win) { +      printf("Error: glXCreateContext failed\n"); +      exit(1); +   } + +   surf_win = eglCreateWindowSurface(dpy, config, win, NULL); + +   XFree(visInfo); + +   *winRet = win; +} + +static void +use_window(void) +{ +   static int initialized; + +   eglMakeCurrent(dpy, surf_win, surf_win, ctx_win); +   if (!initialized) { +      initialized = 1; +      glEnable(GL_TEXTURE_2D); +      glBindTexture(GL_TEXTURE_2D, tex_pbuf); +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + +      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +   } +} + +static void +draw_triangle(void) +{ +   static const GLfloat verts[3][2] = { +      { -3, -3 }, +      {  3, -3 }, +      {  0,  3 } +   }; +   GLfloat colors[3][3] = { +      { 1, 0, 0 }, +      { 0, 1, 0 }, +      { 0, 0, 1 } +   }; +   GLint i; + +   /* flow the color */ +   for (i = 0; i < 3; i++) { +      GLint first = (i + color_flow / 256) % 3; +      GLint second = (first + 1) % 3; +      GLint third = (second + 1) % 3; +      GLfloat c = (color_flow % 256) / 256.0f; + +      c = c * c * c; +      colors[i][first] = 1.0f - c; +      colors[i][second] = c; +      colors[i][third] = 0.0f; +   } + +   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +   glVertexPointer(2, GL_FLOAT, 0, verts); +   glColorPointer(3, GL_FLOAT, 0, colors); +   glEnableClientState(GL_VERTEX_ARRAY); +   glEnableClientState(GL_COLOR_ARRAY); + +   glDrawArrays(GL_TRIANGLES, 0, 3); + +   glDisableClientState(GL_VERTEX_ARRAY); +   glDisableClientState(GL_COLOR_ARRAY); +} + +static void +draw_textured_cube(void) +{ +   static const GLfloat verts[][2] = { +      { -4, -4 }, +      {  4, -4 }, +      {  4,  4 }, +      { -4,  4 } +   }; +   static const GLfloat colors[][4] = { +      { 1, 1, 1, 0.5 }, +      { 1, 1, 1, 0.5 }, +      { 1, 1, 1, 0.5 }, +      { 1, 1, 1, 0.5 } +   }; +   static const GLfloat texs[][2] = { +      { 0, 0 }, +      { 1, 0 }, +      { 1, 1 }, +      { 0, 1 } +   }; +   static const GLfloat xforms[6][4] = { +      {   0, 0, 1, 0 }, +      {  90, 0, 1, 0 }, +      { 180, 0, 1, 0 }, +      { 270, 0, 1, 0 }, +      {  90, 1, 0, 0 }, +      { -90, 1, 0, 0 } +   }; +   GLint i; + +   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +   if (blend) { +      glDisable(GL_DEPTH_TEST); +      glEnable(GL_BLEND); +   } else { +      glEnable(GL_DEPTH_TEST); +      glDisable(GL_BLEND); +   } + +   glVertexPointer(2, GL_FLOAT, 0, verts); +   glColorPointer(4, GL_FLOAT, 0, colors); +   glTexCoordPointer(2, GL_FLOAT, 0, texs); + +   glEnableClientState(GL_VERTEX_ARRAY); +   glEnableClientState(GL_COLOR_ARRAY); +   glEnableClientState(GL_TEXTURE_COORD_ARRAY); + +   for (i = 0; i < 6; i++) { +      glPushMatrix(); +      glRotatef(xforms[i][0], xforms[i][1], xforms[i][2], xforms[i][3]); +      glTranslatef(0, 0, 4.1); +      glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +      glPopMatrix(); +   } + +   glDisableClientState(GL_VERTEX_ARRAY); +   glDisableClientState(GL_COLOR_ARRAY); +   glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +static void +draw(void) +{ +   use_pbuffer(); +   draw_triangle(); + +   use_window(); + +   eglBindTexImage(dpy, surf_pbuf, EGL_BACK_BUFFER); + +   glPushMatrix(); +   glRotatef(view_rotx, 1, 0, 0); +   glRotatef(view_roty, 0, 1, 0); +   glRotatef(view_rotz, 0, 0, 1); + +   draw_textured_cube(); + +   glPopMatrix(); + +   eglReleaseTexImage(dpy, surf_pbuf, EGL_BACK_BUFFER); +} + +/* new window size or exposure */ +static void +reshape(int width, int height) +{ +   GLfloat ar = (GLfloat) width / (GLfloat) height; + +   use_window(); + +   glViewport(0, 0, (GLint) width, (GLint) height); + +   glMatrixMode(GL_PROJECTION); +   glLoadIdentity(); +   glFrustum(-ar, ar, -1, 1, 5.0, 60.0); + +   glMatrixMode(GL_MODELVIEW); +   glLoadIdentity(); +   glTranslatef(0.0, 0.0, -40.0); +} + +static void +event_loop(Display *x_dpy, Window win) +{ +   while (1) { +      int redraw = 1; + +      if (XPending(x_dpy) > 0) { +         XEvent event; +         XNextEvent(x_dpy, &event); + +         switch (event.type) { +         case Expose: +            redraw = 1; +            break; +         case ConfigureNotify: +            reshape(event.xconfigure.width, event.xconfigure.height); +            break; +         case KeyPress: +            { +               char buffer[10]; +               int r, code; +               code = XLookupKeysym(&event.xkey, 0); +               if (code == XK_Left) { +                  view_roty += 5.0; +               } +               else if (code == XK_Right) { +                  view_roty -= 5.0; +               } +               else if (code == XK_Up) { +                  view_rotx += 5.0; +               } +               else if (code == XK_Down) { +                  view_rotx -= 5.0; +               } +               else if (code == XK_b) { +                  blend = !blend; +               } +               else { +                  r = XLookupString(&event.xkey, buffer, sizeof(buffer), +                        NULL, NULL); +                  if (buffer[0] == 27) { +                     /* escape */ +                     return; +                  } +               } +            } +            redraw = 1; +            break; +         default: +            ; /*no-op*/ +         } +      } + +      if (redraw) { +         view_rotx += 1.0; +         view_roty += 2.0; +         view_rotz += 1.5; +         color_flow += 20; +         draw(); +         eglSwapBuffers(dpy, surf_win); +      } +   } +} + +int +main(int argc, char *argv[]) +{ +   const int winWidth = 300, winHeight = 300; +   Display *x_dpy; +   Window win; +   char *dpyName = NULL; +   EGLint egl_major, egl_minor; +   const char *s; + +   x_dpy = XOpenDisplay(dpyName); +   if (!x_dpy) { +      printf("Error: couldn't open display %s\n", +	     dpyName ? dpyName : getenv("DISPLAY")); +      return -1; +   } + +   dpy = eglGetDisplay(x_dpy); +   if (!dpy) { +      printf("Error: eglGetDisplay() failed\n"); +      return -1; +   } + +   if (!eglInitialize(dpy, &egl_major, &egl_minor)) { +      printf("Error: eglInitialize() failed\n"); +      return -1; +   } + +   s = eglQueryString(dpy, EGL_VERSION); +   printf("EGL_VERSION = %s\n", s); + +   make_window(x_dpy, "color flow", 0, 0, winWidth, winHeight, &win); +   make_pbuffer(winWidth, winHeight); + +   XMapWindow(x_dpy, win); + +   reshape(winWidth, winHeight); +   event_loop(x_dpy, win); + +   glDeleteTextures(1, &tex_pbuf); + +   eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +   eglTerminate(dpy); + +   XDestroyWindow(x_dpy, win); +   XCloseDisplay(x_dpy); + +   return 0; +} diff --git a/progs/glsl/.gitignore b/progs/glsl/.gitignore index 39d90c23ac..986775bac2 100644 --- a/progs/glsl/.gitignore +++ b/progs/glsl/.gitignore @@ -22,6 +22,7 @@ samplers_array  shaderutil.c  shaderutil.h  shadow_sampler +shtest  skinning  texaaline  texdemo1 diff --git a/progs/glsl/Makefile b/progs/glsl/Makefile index eedd866c95..0875bdd795 100644 --- a/progs/glsl/Makefile +++ b/progs/glsl/Makefile @@ -14,6 +14,11 @@ LIBS = -L$(TOP)/$(LIB_DIR) -l$(GLUT_LIB) -l$(GLEW_LIB) -l$(GLU_LIB) -l$(GL_LIB)  INCLUDE_DIRS = -I$(TOP)/progs/util +# using : to avoid APP_CC pointing to CC loop +CC:=$(APP_CC) +CFLAGS += -I$(INCDIR) +LDLIBS=$(LIBS) +  DEMO_SOURCES = \  	array.c \  	bitmap.c \ @@ -33,6 +38,7 @@ DEMO_SOURCES = \  	points.c \  	samplers.c \  	shadow_sampler.c \ +	shtest.c \  	skinning.c \  	texaaline.c \  	texdemo1.c \ @@ -52,28 +58,16 @@ UTIL_SOURCES = \  	readtex.c  UTIL_OBJS = $(UTIL_SOURCES:.c=.o) - - +PROG_OBJS = $(DEMO_SOURCES:.c=.o)  PROGS = $(DEMO_SOURCES:%.c=%) - - -##### RULES ##### - -# make .o file from .c file: -.c.o: -	$(APP_CC) -c -I$(INCDIR) $(CFLAGS) $< -o $@ - - -# make executable from .o files -.o: -	$(APP_CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $< $(UTIL_OBJS) $(LIBS) -o $@ - -  ##### TARGETS #####  default: $(PROGS) +$(PROG_OBJS): $(UTIL_HEADERS) + +$(PROGS): $(UTIL_OBJS)  clean:  	-rm -f $(PROGS) @@ -83,7 +77,6 @@ clean:  	-rm -f readtex.* -  ##### Extra dependencies  extfuncs.h: $(TOP)/progs/util/extfuncs.h @@ -101,138 +94,3 @@ shaderutil.c: $(TOP)/progs/util/shaderutil.c  shaderutil.h: $(TOP)/progs/util/shaderutil.h  	cp $< . - - -array.o: $(UTIL_HEADERS) - -array: array.o  $(UTIL_OBJS) - - -bitmap.o: $(UTIL_HEADERS) - -bitmap: bitmap.o $(UTIL_OBJS) - - -brick.o: $(UTIL_HEADERS) - -brick: brick.o $(UTIL_OBJS) - - -bump.o: $(UTIL_HEADERS) - -bump: bump.o $(UTIL_OBJS) - - -convolutions.o: $(UTIL_HEADERS) - -convolutions: convolutions.o $(UTIL_OBJS) - - -deriv.o: deriv.c $(UTIL_HEADERS) - -deriv: deriv.o $(UTIL_OBJS) - - -identity.o: $(UTIL_HEADERS) - -identity: identity.o $(UTIL_OBJS) - - -fragcoord.o: $(UTIL_HEADERS) - -fragcoord: fragcoord.o $(UTIL_OBJS) - - -linktest.o: $(UTIL_HEADERS) - -linktest: linktest.o $(UTIL_OBJS) - - -mandelbrot.o: $(UTIL_HEADERS) - -mandelbrot: mandelbrot.o $(UTIL_OBJS) - - -multinoise.o: $(UTIL_HEADERS) - -multinoise: multinoise.o $(UTIL_OBJS) - - -multitex.o: $(UTIL_HEADERS) - -multitex: multitex.o $(UTIL_OBJS) - - -noise.o: $(UTIL_HEADERS) - -noise: noise.o $(UTIL_OBJS) - - -noise2.o: $(UTIL_HEADERS) - -noise2: noise2.o $(UTIL_OBJS) - - -points.o: $(UTIL_HEADERS) - -points: points.o $(UTIL_OBJS) - - -pointcoord.o: $(UTIL_HEADERS) - -pointcoord: pointcoord.o $(UTIL_OBJS) - - -samplers.o: $(UTIL_HEADERS) - -samplers: samplers.o $(UTIL_OBJS) - - -samplers_array.o: $(UTIL_HEADERS) - -samplers_array: samplers_array.o $(UTIL_OBJS) - - -shadow_sampler.o: $(UTIL_HEADERS) - -shadow_sampler: shadow_sampler.o $(UTIL_OBJS) - - -skinning.o: $(UTIL_HEADERS) - -skinning: skinning.o $(UTIL_OBJS) - - -texaaline.o: $(UTIL_HEADERS) - -texaaline: texaaline.o $(UTIL_OBJS) - - -texdemo1.o: $(UTIL_HEADERS) - -texdemo1: texdemo1.o $(UTIL_OBJS) - - -toyball.o: $(UTIL_HEADERS) - -toyball: toyball.o $(UTIL_OBJS) - - -twoside.o: $(UTIL_HEADERS) - -twoside: twoside.o $(UTIL_OBJS) - - -trirast.o: $(UTIL_HEADERS) - -trirast: trirast.o $(UTIL_OBJS) - - -vert-or-frag-only.o: $(UTIL_HEADERS) - -vert-or-frag-only: vert-or-frag-only.o $(UTIL_OBJS) - - -vert-tex.o: $(UTIL_HEADERS) - -vert-tex: vert-tex.o $(UTIL_OBJS) diff --git a/progs/glsl/brick.c b/progs/glsl/brick.c index 1d08b231e7..20417aa462 100644 --- a/progs/glsl/brick.c +++ b/progs/glsl/brick.c @@ -24,12 +24,12 @@ static GLuint program;  static struct uniform_info Uniforms[] = {     /* vert */ -   { "LightPosition",     3, GL_FLOAT, { 0.1, 0.1, 9.0, 0}, -1 }, +   { "LightPosition",     1, GL_FLOAT_VEC3, { 0.1, 0.1, 9.0, 0}, -1 },     /* frag */ -   { "BrickColor",        3, GL_FLOAT, { 0.8, 0.2, 0.2, 0 }, -1 }, -   { "MortarColor",       3, GL_FLOAT, { 0.6, 0.6, 0.6, 0 }, -1 }, -   { "BrickSize",         2, GL_FLOAT, { 1.0, 0.3, 0, 0 }, -1 }, -   { "BrickPct",          2, GL_FLOAT, { 0.9, 0.8, 0, 0 }, -1 }, +   { "BrickColor",        1, GL_FLOAT_VEC3, { 0.8, 0.2, 0.2, 0 }, -1 }, +   { "MortarColor",       1, GL_FLOAT_VEC3, { 0.6, 0.6, 0.6, 0 }, -1 }, +   { "BrickSize",         1, GL_FLOAT_VEC2, { 1.0, 0.3, 0, 0 }, -1 }, +   { "BrickPct",          1, GL_FLOAT_VEC2, { 0.9, 0.8, 0, 0 }, -1 },     END_OF_UNIFORMS  }; @@ -148,7 +148,8 @@ Init(void)     glUseProgram(program); -   InitUniforms(program, Uniforms); +   SetUniformValues(program, Uniforms); +   PrintUniforms(Uniforms);     assert(glGetError() == 0); @@ -183,7 +184,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 400);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/brick.shtest b/progs/glsl/brick.shtest new file mode 100644 index 0000000000..8a2152692e --- /dev/null +++ b/progs/glsl/brick.shtest @@ -0,0 +1,8 @@ +vs CH06-brick.vert +fs CH06-brick.frag +uniform LightPosition GL_FLOAT_VEC3 0.1 0.1 9.0 +uniform BrickColor GL_FLOAT_VEC3 0.8 0.2 0.2 +uniform MortarColor GL_FLOAT_VEC3 0.6 0.6 0.6 +uniform BrickSize  GL_FLOAT_VEC2 1.0 0.3 +uniform BrickPct GL_FLOAT_VEC2 0.9 0.8 + diff --git a/progs/glsl/bump.c b/progs/glsl/bump.c index ddb986abcb..87669aec73 100644 --- a/progs/glsl/bump.c +++ b/progs/glsl/bump.c @@ -24,11 +24,11 @@ static GLuint program;  static struct uniform_info Uniforms[] = { -   { "LightPosition",    3, GL_FLOAT, { 0.57737, 0.57735, 0.57735, 0.0 }, -1 }, -   { "SurfaceColor",     3, GL_FLOAT, { 0.8, 0.8, 0.2, 0 }, -1 }, -   { "BumpDensity",      1, GL_FLOAT, { 10.0, 0, 0, 0 }, -1 }, -   { "BumpSize",         1, GL_FLOAT, { 0.125, 0, 0, 0 }, -1 }, -   { "SpecularFactor",   1, GL_FLOAT, { 0.5, 0, 0, 0 }, -1 }, +   { "LightPosition",  1, GL_FLOAT_VEC3, { 0.57737, 0.57735, 0.57735, 0.0 }, -1 }, +   { "SurfaceColor",   1, GL_FLOAT_VEC3, { 0.8, 0.8, 0.2, 0 }, -1 }, +   { "BumpDensity",    1, GL_FLOAT, { 10.0, 0, 0, 0 }, -1 }, +   { "BumpSize",       1, GL_FLOAT, { 0.125, 0, 0, 0 }, -1 }, +   { "SpecularFactor", 1, GL_FLOAT, { 0.5, 0, 0, 0 }, -1 },     END_OF_UNIFORMS  }; @@ -242,7 +242,8 @@ Init(void)     CheckError(__LINE__); -   InitUniforms(program, Uniforms); +   SetUniformValues(program, Uniforms); +   PrintUniforms(Uniforms);     CheckError(__LINE__); @@ -280,7 +281,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 400);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/convolutions.c b/progs/glsl/convolutions.c index 22ce7edcdc..c2fb76e1aa 100644 --- a/progs/glsl/convolutions.c +++ b/progs/glsl/convolutions.c @@ -448,7 +448,6 @@ int main(int argc, char **argv)  {     glutInit(&argc, argv); -   glutInitWindowPosition(0, 0);     glutInitWindowSize(400, 400);     glutInitDisplayMode(GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE); diff --git a/progs/glsl/deriv.c b/progs/glsl/deriv.c index 9cf1e40e3e..265a515715 100644 --- a/progs/glsl/deriv.c +++ b/progs/glsl/deriv.c @@ -220,7 +220,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(200, 200);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/fragcoord.c b/progs/glsl/fragcoord.c index 9f56a038c9..3dfcec87a5 100644 --- a/progs/glsl/fragcoord.c +++ b/progs/glsl/fragcoord.c @@ -166,7 +166,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(WinWidth, WinHeight);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/identity.c b/progs/glsl/identity.c index a772ccd716..526e9b82c1 100644 --- a/progs/glsl/identity.c +++ b/progs/glsl/identity.c @@ -187,7 +187,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(200, 200);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/mandelbrot.c b/progs/glsl/mandelbrot.c index 38dffc3e74..b05ef37fae 100644 --- a/progs/glsl/mandelbrot.c +++ b/progs/glsl/mandelbrot.c @@ -25,7 +25,7 @@ static GLuint program;  static struct uniform_info Uniforms[] = {     /* vert */ -   { "LightPosition",        3, GL_FLOAT, { 0.1, 0.1, 9.0, 0}, -1 }, +   { "LightPosition",        1, GL_FLOAT_VEC3, { 0.1, 0.1, 9.0, 0}, -1 },     { "SpecularContribution", 1, GL_FLOAT, { 0.5, 0, 0, 0 }, -1 },     { "DiffuseContribution",  1, GL_FLOAT, { 0.5, 0, 0, 0 }, -1 },     { "Shininess",            1, GL_FLOAT, { 20.0, 0, 0, 0 }, -1 }, @@ -34,9 +34,9 @@ static struct uniform_info Uniforms[] = {     { "Zoom",                 1, GL_FLOAT, { 0.125, 0, 0, 0 }, -1 },     { "Xcenter",              1, GL_FLOAT, { -1.5, 0, 0, 0 }, -1 },     { "Ycenter",              1, GL_FLOAT, { .005, 0, 0, 0 }, -1 }, -   { "InnerColor",           3, GL_FLOAT, { 1, 0, 0, 0 }, -1 }, -   { "OuterColor1",          3, GL_FLOAT, { 0, 1, 0, 0 }, -1 }, -   { "OuterColor2",          3, GL_FLOAT, { 0, 0, 1, 0 }, -1 }, +   { "InnerColor",           1, GL_FLOAT_VEC3, { 1, 0, 0, 0 }, -1 }, +   { "OuterColor1",          1, GL_FLOAT_VEC3, { 0, 1, 0, 0 }, -1 }, +   { "OuterColor2",          1, GL_FLOAT_VEC3, { 0, 0, 1, 0 }, -1 },     END_OF_UNIFORMS  }; @@ -159,7 +159,8 @@ Init(void)     glUseProgram(program); -   InitUniforms(program, Uniforms); +   SetUniformValues(program, Uniforms); +   PrintUniforms(Uniforms);     uZoom = glGetUniformLocation(program, "Zoom");     uXcenter = glGetUniformLocation(program, "Xcenter"); @@ -198,7 +199,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 400);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/mandelbrot.shtest b/progs/glsl/mandelbrot.shtest new file mode 100644 index 0000000000..4f4e5c747e --- /dev/null +++ b/progs/glsl/mandelbrot.shtest @@ -0,0 +1,13 @@ +vs CH18-mandel.vert +fs CH18-mandel.frag +uniform LightPosition        GL_FLOAT_VEC3 0.1 0.1 9.0 +uniform SpecularContribution GL_FLOAT 0.5 +uniform DiffuseContribution  GL_FLOAT 0.5 +uniform Shininess            GL_FLOAT 20.0 +uniform Iterations           GL_FLOAT 12 +uniform Zoom                 GL_FLOAT 0.125 +uniform Xcenter              GL_FLOAT -1.5 +uniform Ycenter              GL_FLOAT .005 +uniform InnerColor           GL_FLOAT_VEC3 1 0 0 +uniform OuterColor1          GL_FLOAT_VEC3 0 1 0 +uniform OuterColor2          GL_FLOAT_VEC3 0 0 1 diff --git a/progs/glsl/multinoise.c b/progs/glsl/multinoise.c index 0afe230801..0d4026e29c 100644 --- a/progs/glsl/multinoise.c +++ b/progs/glsl/multinoise.c @@ -262,7 +262,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 400);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/multitex.c b/progs/glsl/multitex.c index 5e971716ad..6ec9c833e6 100644 --- a/progs/glsl/multitex.c +++ b/progs/glsl/multitex.c @@ -59,8 +59,8 @@ static GLint VertCoord_attr = -1, TexCoord0_attr = -1, TexCoord1_attr = -1;  /* value[0] = tex unit */  static struct uniform_info Uniforms[] = { -   { "tex1",  1, GL_INT, { 0, 0, 0, 0 }, -1 }, -   { "tex2",  1, GL_INT, { 1, 0, 0, 0 }, -1 }, +   { "tex1",  1, GL_SAMPLER_2D, { 0, 0, 0, 0 }, -1 }, +   { "tex2",  1, GL_SAMPLER_2D, { 1, 0, 0, 0 }, -1 },     END_OF_UNIFORMS  }; @@ -134,7 +134,7 @@ DrawPolygonArray(void)     if (VertCoord_attr >= 0) {        glVertexAttribPointer(VertCoord_attr, 2, GL_FLOAT, GL_FALSE, -                                 0, VertCoords); +                                 0, vertPtr);        glEnableVertexAttribArray(VertCoord_attr);     }     else { @@ -143,11 +143,11 @@ DrawPolygonArray(void)     }     glVertexAttribPointer(TexCoord0_attr, 2, GL_FLOAT, GL_FALSE, -                              0, Tex0Coords); +                              0, tex0Ptr);     glEnableVertexAttribArray(TexCoord0_attr);     glVertexAttribPointer(TexCoord1_attr, 2, GL_FLOAT, GL_FALSE, -                              0, Tex1Coords); +                              0, tex1Ptr);     glEnableVertexAttribArray(TexCoord1_attr);     glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -328,7 +328,8 @@ CreateProgram(const char *vertProgFile, const char *fragProgFile,     glUseProgram(program); -   InitUniforms(program, uniforms); +   SetUniformValues(program, uniforms); +   PrintUniforms(Uniforms);     VertCoord_attr = glGetAttribLocation(program, "VertCoord");     if (VertCoord_attr > 0) { diff --git a/progs/glsl/multitex.shtest b/progs/glsl/multitex.shtest new file mode 100644 index 0000000000..5be45f6c7c --- /dev/null +++ b/progs/glsl/multitex.shtest @@ -0,0 +1,6 @@ +vs multitex.vert +fs multitex.frag +texture 0 ../images/tile.rgb +texture 1 ../images/tree2.rgba +uniform tex1  GL_SAMPLER_2D  0 +uniform tex2  GL_SAMPLER_2D  1 diff --git a/progs/glsl/noise.c b/progs/glsl/noise.c index 59f594e78b..fdab263ea6 100644 --- a/progs/glsl/noise.c +++ b/progs/glsl/noise.c @@ -35,8 +35,8 @@ static const char *FragShaderText =  static struct uniform_info Uniforms[] = { -   { "Scale",    4, GL_FLOAT, { 0.5, 0.4, 0.0, 0}, -1 }, -   { "Bias",     4, GL_FLOAT, { 0.5, 0.3, 0.0, 0}, -1 }, +   { "Scale",    1, GL_FLOAT_VEC4, { 0.5, 0.4, 0.0, 0}, -1 }, +   { "Bias",     1, GL_FLOAT_VEC4, { 0.5, 0.3, 0.0, 0}, -1 },     { "Slice",    1, GL_FLOAT, { 0.5, 0, 0, 0}, -1 },     END_OF_UNIFORMS  }; @@ -179,7 +179,8 @@ Init(void)     glUseProgram(program); -   InitUniforms(program, Uniforms); +   SetUniformValues(program, Uniforms); +   PrintUniforms(Uniforms);     assert(glGetError() == 0); @@ -199,7 +200,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 400);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/noise2.c b/progs/glsl/noise2.c index e972b62673..7a28f09947 100644 --- a/progs/glsl/noise2.c +++ b/progs/glsl/noise2.c @@ -186,7 +186,6 @@ static void Init (void)  int main (int argc, char *argv[])  {  	glutInit (&argc, argv); -	glutInitWindowPosition ( 0, 0);  	glutInitWindowSize (200, 200);  	glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);  	glutCreateWindow (argv[0]); diff --git a/progs/glsl/pointcoord.c b/progs/glsl/pointcoord.c index 27b73a05de..5dced6fac3 100644 --- a/progs/glsl/pointcoord.c +++ b/progs/glsl/pointcoord.c @@ -187,7 +187,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(WinWidth, WinHeight);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/shadow_sampler.c b/progs/glsl/shadow_sampler.c index 0a4d04dd8c..0adc9d88ba 100644 --- a/progs/glsl/shadow_sampler.c +++ b/progs/glsl/shadow_sampler.c @@ -321,7 +321,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 300);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/shtest.c b/progs/glsl/shtest.c new file mode 100644 index 0000000000..2622af1313 --- /dev/null +++ b/progs/glsl/shtest.c @@ -0,0 +1,629 @@ +/* + * Simple shader test harness. + * Brian Paul + * 13 Aug 2009 + * + * Usage: + *   shtest --vs vertShaderFile --fs fragShaderFile + * + *   In this case the given vertex/frag shaders are read and compiled. + *   Random values are assigned to the uniforms. + * + * or: + *   shtest configFile + * + *   In this case a config file is read that specifies the file names + *   of the shaders plus initial values for uniforms. + * + * Example config file: + * + * vs shader.vert + * fs shader.frag + * uniform pi 3.14159 + * uniform v1 1.0 0.5 0.2 0.3 + * + */ + + +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <GL/glew.h> +#include <GL/glu.h> +#include <GL/glut.h> +#include "shaderutil.h" +#include "readtex.h" + + +typedef enum +{ +   SPHERE, +   CUBE, +   NUM_SHAPES +} shape; + + +static char *FragShaderFile = NULL; +static char *VertShaderFile = NULL; +static char *ConfigFile = NULL; + +/* program/shader objects */ +static GLuint fragShader; +static GLuint vertShader; +static GLuint Program; + + +#define MAX_UNIFORMS 100 +static struct uniform_info Uniforms[MAX_UNIFORMS]; +static GLuint NumUniforms = 0; + + +#define MAX_ATTRIBS 100 +static struct attrib_info Attribs[MAX_ATTRIBS]; +static GLuint NumAttribs = 0; + + +/** + * Config file info. + */ +struct config_file +{ +   struct name_value +   { +      char name[100]; +      float value[4]; +      int type; +   } uniforms[100]; + +   int num_uniforms; +}; + + +static GLint win = 0; +static GLboolean Anim = GL_FALSE; +static GLfloat TexRot = 0.0; +static GLfloat xRot = 0.0f, yRot = 0.0f, zRot = 0.0f; +static shape Object = SPHERE; + + +static float +RandomFloat(float min, float max) +{ +   int k = rand() % 10000; +   float x = min + (max - min) * k / 10000.0; +   return x; +} + + +/** Set new random values for uniforms */ +static void +RandomUniformValues(void) +{ +   GLuint i; +   for (i = 0; i < NumUniforms; i++) { +      if (Uniforms[i].type == GL_FLOAT) { +         Uniforms[i].value[0] = RandomFloat(0.0, 1.0); +      } +      else { +         Uniforms[i].value[0] = RandomFloat(-1.0, 2.0); +         Uniforms[i].value[1] = RandomFloat(-1.0, 2.0); +         Uniforms[i].value[2] = RandomFloat(-1.0, 2.0); +         Uniforms[i].value[3] = RandomFloat(-1.0, 2.0); +      } +   } +} + + +static void +Idle(void) +{ +   yRot += 2.0; +   if (yRot > 360.0) +      yRot -= 360.0; +   glutPostRedisplay(); +} + + + +static void +SquareVertex(GLfloat s, GLfloat t, GLfloat size) +{ +   GLfloat x = -size + s * 2.0 * size; +   GLfloat y = -size + t * 2.0 * size; +   GLuint i; + +   glMultiTexCoord2f(GL_TEXTURE0, s, t); +   glMultiTexCoord2f(GL_TEXTURE1, s, t); +   glMultiTexCoord2f(GL_TEXTURE2, s, t); +   glMultiTexCoord2f(GL_TEXTURE3, s, t); + +   /* assign (s,t) to the generic attributes */ +   for (i = 0; i < NumAttribs; i++) { +      if (Attribs[i].location >= 0) { +         glVertexAttrib2f(Attribs[i].location, s, t); +      } +   } + +   glVertex2f(x, y); +} + + +/* + * Draw a square, specifying normal and tangent vectors. + */ +static void +Square(GLfloat size) +{ +   GLint tangentAttrib = 1; +   glNormal3f(0, 0, 1); +   glVertexAttrib3f(tangentAttrib, 1, 0, 0); +   glBegin(GL_POLYGON); +#if 1 +   SquareVertex(0, 0, size); +   SquareVertex(1, 0, size); +   SquareVertex(1, 1, size); +   SquareVertex(0, 1, size); +#else +   glTexCoord2f(0, 0);  glVertex2f(-size, -size); +   glTexCoord2f(1, 0);  glVertex2f( size, -size); +   glTexCoord2f(1, 1);  glVertex2f( size,  size); +   glTexCoord2f(0, 1);  glVertex2f(-size,  size); +#endif +   glEnd(); +} + + +static void +Cube(GLfloat size) +{ +   /* +X */ +   glPushMatrix(); +   glRotatef(90, 0, 1, 0); +   glTranslatef(0, 0, size); +   Square(size); +   glPopMatrix(); + +   /* -X */ +   glPushMatrix(); +   glRotatef(-90, 0, 1, 0); +   glTranslatef(0, 0, size); +   Square(size); +   glPopMatrix(); + +   /* +Y */ +   glPushMatrix(); +   glRotatef(90, 1, 0, 0); +   glTranslatef(0, 0, size); +   Square(size); +   glPopMatrix(); + +   /* -Y */ +   glPushMatrix(); +   glRotatef(-90, 1, 0, 0); +   glTranslatef(0, 0, size); +   Square(size); +   glPopMatrix(); + + +   /* +Z */ +   glPushMatrix(); +   glTranslatef(0, 0, size); +   Square(size); +   glPopMatrix(); + +   /* -Z */ +   glPushMatrix(); +   glRotatef(180, 0, 1, 0); +   glTranslatef(0, 0, size); +   Square(size); +   glPopMatrix(); +} + + +static void +Sphere(GLfloat radius, GLint slices, GLint stacks) +{ +   static GLUquadricObj *q = NULL; + +   if (!q) { +      q = gluNewQuadric(); +      gluQuadricDrawStyle(q, GLU_FILL); +      gluQuadricNormals(q, GLU_SMOOTH); +      gluQuadricTexture(q, GL_TRUE); +   } + +   gluSphere(q, radius, slices, stacks); +} + + +static void +Redisplay(void) +{ +   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +    +   glPushMatrix(); +   glRotatef(xRot, 1.0f, 0.0f, 0.0f); +   glRotatef(yRot, 0.0f, 1.0f, 0.0f); +   glRotatef(zRot, 0.0f, 0.0f, 1.0f); + +   glMatrixMode(GL_TEXTURE); +   glLoadIdentity(); +   glRotatef(TexRot, 0.0f, 1.0f, 0.0f); +   glMatrixMode(GL_MODELVIEW); + +   if (Object == SPHERE) { +      Sphere(2.0, 20, 10); +   } +   else if (Object == CUBE) { +      Cube(2.0); +   } + +   glPopMatrix(); + +   glutSwapBuffers(); +} + + +static void +Reshape(int width, int height) +{ +   glViewport(0, 0, width, height); +   glMatrixMode(GL_PROJECTION); +   glLoadIdentity(); +   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); +   glMatrixMode(GL_MODELVIEW); +   glLoadIdentity(); +   glTranslatef(0.0f, 0.0f, -15.0f); +} + + +static void +CleanUp(void) +{ +   glDeleteShader(fragShader); +   glDeleteShader(vertShader); +   glDeleteProgram(Program); +   glutDestroyWindow(win); +} + + +static void +Key(unsigned char key, int x, int y) +{ +   const GLfloat step = 2.0; +  (void) x; +  (void) y; + +   switch(key) { +   case 'a': +      Anim = !Anim; +      if (Anim) +         glutIdleFunc(Idle); +      else +         glutIdleFunc(NULL); +      break; +   case 'z': +      zRot += step; +      break; +   case 'Z': +      zRot -= step; +      break; +   case 'o': +      Object = (Object + 1) % NUM_SHAPES; +      break; +   case 'r': +      RandomUniformValues(); +      SetUniformValues(Program, Uniforms); +      PrintUniforms(Uniforms); +      break; +   case 27: +      CleanUp(); +      exit(0); +      break; +   } +   glutPostRedisplay(); +} + + +static void +SpecialKey(int key, int x, int y) +{ +   const GLfloat step = 2.0; + +  (void) x; +  (void) y; + +   switch(key) { +   case GLUT_KEY_UP: +      xRot += step; +      break; +   case GLUT_KEY_DOWN: +      xRot -= step; +      break; +   case GLUT_KEY_LEFT: +      yRot -= step; +      break; +   case GLUT_KEY_RIGHT: +      yRot += step; +      break; +   } +   glutPostRedisplay(); +} + + +static void +InitUniforms(const struct config_file *conf, +             struct uniform_info uniforms[]) +{ +   int i; + +   for (i = 0; i < conf->num_uniforms; i++) { +      int j; +      for (j = 0; uniforms[j].name; j++) { +         if (strcmp(uniforms[j].name, conf->uniforms[i].name) == 0) { +            uniforms[j].type = conf->uniforms[i].type; +            uniforms[j].value[0] = conf->uniforms[i].value[0]; +            uniforms[j].value[1] = conf->uniforms[i].value[1]; +            uniforms[j].value[2] = conf->uniforms[i].value[2]; +            uniforms[j].value[3] = conf->uniforms[i].value[3]; +         } +      } +   } +} + + +static void +LoadTexture(GLint unit, const char *texFileName) +{ +   GLint imgWidth, imgHeight; +   GLenum imgFormat; +   GLubyte *image = NULL; +   GLuint tex; +   GLenum filter = GL_LINEAR; + +   image = LoadRGBImage(texFileName, &imgWidth, &imgHeight, &imgFormat); +   if (!image) { +      printf("Couldn't read %s\n", texFileName); +      exit(1); +   } + +   printf("Load Texture: unit %d: %s %d x %d\n", +          unit, texFileName, imgWidth, imgHeight); + +   glActiveTexture(GL_TEXTURE0 + unit); +   glGenTextures(1, &tex); +   glBindTexture(GL_TEXTURE_2D, tex); + +   gluBuild2DMipmaps(GL_TEXTURE_2D, 4, imgWidth, imgHeight, +                     imgFormat, GL_UNSIGNED_BYTE, image); +   free(image); +       +   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); +   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); +   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); +} + + +static GLenum +TypeFromName(const char *n) +{ +   static const struct { +      const char *name; +      GLenum type; +   } types[] = { +      { "GL_FLOAT", GL_FLOAT }, +      { "GL_FLOAT_VEC2", GL_FLOAT_VEC2 }, +      { "GL_FLOAT_VEC3", GL_FLOAT_VEC3 }, +      { "GL_FLOAT_VEC4", GL_FLOAT_VEC4 }, +      { "GL_INT", GL_INT }, +      { "GL_INT_VEC2", GL_INT_VEC2 }, +      { "GL_INT_VEC3", GL_INT_VEC3 }, +      { "GL_INT_VEC4", GL_INT_VEC4 }, +      { "GL_SAMPLER_2D", GL_SAMPLER_2D }, +      { NULL, 0 } +   }; +   GLuint i; + +   for (i = 0; types[i].name; i++) { +      if (strcmp(types[i].name, n) == 0) +         return types[i].type; +   } +   abort(); +   return GL_NONE; +} + + + +/** + * Read a config file. + */ +static void +ReadConfigFile(const char *filename, struct config_file *conf) +{ +   char line[1000]; +   FILE *f; + +   f = fopen(filename, "r"); +   if (!f) { +      fprintf(stderr, "Unable to open config file %s\n", filename); +      exit(1); +   } + +   conf->num_uniforms = 0; + +   /* ugly but functional parser */ +   while (!feof(f)) { +      fgets(line, sizeof(line), f); +      if (!feof(f) && line[0]) { +         if (strncmp(line, "vs ", 3) == 0) { +            VertShaderFile = strdup(line + 3); +            VertShaderFile[strlen(VertShaderFile) - 1] = 0; +         } +         else if (strncmp(line, "fs ", 3) == 0) { +            FragShaderFile = strdup(line + 3); +            FragShaderFile[strlen(FragShaderFile) - 1] = 0; +         } +         else if (strncmp(line, "texture ", 8) == 0) { +            char texFileName[100]; +            int unit, k; +            k = sscanf(line + 8, "%d %s", &unit, texFileName); +            assert(k == 2); +            LoadTexture(unit, texFileName); +         } +         else if (strncmp(line, "uniform ", 8) == 0) { +            char name[1000], typeName[100]; +            int k; +            float v1 = 0.0F, v2 = 0.0F, v3 = 0.0F, v4 = 0.0F; +            GLenum type; + +            k = sscanf(line + 8, "%s %s %f %f %f %f", name, typeName, +                       &v1, &v2, &v3, &v4); + +            type = TypeFromName(typeName); + +            strcpy(conf->uniforms[conf->num_uniforms].name, name); +            conf->uniforms[conf->num_uniforms].value[0] = v1; +            conf->uniforms[conf->num_uniforms].value[1] = v2; +            conf->uniforms[conf->num_uniforms].value[2] = v3; +            conf->uniforms[conf->num_uniforms].value[3] = v4; +            conf->uniforms[conf->num_uniforms].type = type; +            conf->num_uniforms++; +         } +         else { +            if (strlen(line) > 1) { +               fprintf(stderr, "syntax error in: %s\n", line); +               break; +            } +         } +      } +   } + +   fclose(f); +} + + +static void +Init(void) +{ +   struct config_file config; +   memset(&config, 0, sizeof(config)); + +   if (ConfigFile) +      ReadConfigFile(ConfigFile, &config); + +   if (!VertShaderFile) { +      fprintf(stderr, "Error: no vertex shader\n"); +      exit(1); +   } + +   if (!FragShaderFile) { +      fprintf(stderr, "Error: no fragment shader\n"); +      exit(1); +   } + +   if (!ShadersSupported()) +      exit(1); + +   vertShader = CompileShaderFile(GL_VERTEX_SHADER, VertShaderFile); +   fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragShaderFile); +   Program = LinkShaders(vertShader, fragShader); + +   glUseProgram(Program); + +   NumUniforms = GetUniforms(Program, Uniforms); +   if (config.num_uniforms) { +      InitUniforms(&config, Uniforms); +   } +   else { +      RandomUniformValues(); +   } +   SetUniformValues(Program, Uniforms); +   PrintUniforms(Uniforms); + +   NumAttribs = GetAttribs(Program, Attribs); +   PrintAttribs(Attribs); + +   //assert(glGetError() == 0); + +   glClearColor(0.4f, 0.4f, 0.8f, 0.0f); + +   glEnable(GL_DEPTH_TEST); + +   glColor3f(1, 0, 0); +} + + +static void +Keys(void) +{ +   printf("Keyboard:\n"); +   printf("       a  Animation toggle\n"); +   printf("       r  Randomize uniform values\n"); +   printf("       o  Change object\n"); +   printf("  arrows  Rotate object\n"); +   printf("     ESC  Exit\n"); +} + + +static void +Usage(void) +{ +   printf("Usage:\n"); +   printf("   shtest config.shtest\n"); +   printf("       Run w/ given config file.\n"); +   printf("   shtest --vs vertShader --fs fragShader\n"); +   printf("       Load/compile given shaders.\n"); +} + + +static void +ParseOptions(int argc, char *argv[]) +{ +   int i; + +   if (argc == 1) { +      Usage(); +      exit(1); +   } + +   for (i = 1; i < argc; i++) { +      if (strcmp(argv[i], "--fs") == 0) { +         FragShaderFile = argv[i+1]; +         i++; +      } +      else if (strcmp(argv[i], "--vs") == 0) { +         VertShaderFile = argv[i+1]; +         i++; +      } +      else { +         /* assume the arg is a config file */ +         ConfigFile = argv[i]; +         break; +      } +   } +} + + +int +main(int argc, char *argv[]) +{ +   glutInit(&argc, argv); +   glutInitWindowSize(400, 400); +   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); +   win = glutCreateWindow(argv[0]); +   glewInit(); +   glutReshapeFunc(Reshape); +   glutKeyboardFunc(Key); +   glutSpecialFunc(SpecialKey); +   glutDisplayFunc(Redisplay); +   ParseOptions(argc, argv); +   Init(); +   Keys(); +   glutMainLoop(); +   return 0; +} + diff --git a/progs/glsl/texaaline.c b/progs/glsl/texaaline.c index 1f566c86a6..2481c0f36e 100644 --- a/progs/glsl/texaaline.c +++ b/progs/glsl/texaaline.c @@ -351,7 +351,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(WinWidth, WinHeight);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/texdemo1.c b/progs/glsl/texdemo1.c index d55f9e7dd9..5b1913a722 100644 --- a/progs/glsl/texdemo1.c +++ b/progs/glsl/texdemo1.c @@ -53,14 +53,14 @@ static int win = 0;  static struct uniform_info ReflectUniforms[] = { -   { "cubeTex",  1, GL_INT, { 0, 0, 0, 0 }, -1 }, -   { "lightPos", 3, GL_FLOAT, { 10, 10, 20, 0 }, -1 }, +   { "cubeTex",  1, GL_SAMPLER_CUBE, { 0, 0, 0, 0 }, -1 }, +   { "lightPos", 1, GL_FLOAT_VEC3, { 10, 10, 20, 0 }, -1 },     END_OF_UNIFORMS  };  static struct uniform_info SimpleUniforms[] = { -   { "tex2d",    1, GL_INT,   { 1, 0, 0, 0 }, -1 }, -   { "lightPos", 3, GL_FLOAT, { 10, 10, 20, 0 }, -1 }, +   { "tex2d",    1, GL_SAMPLER_2D, { 1, 0, 0, 0 }, -1 }, +   { "lightPos", 1, GL_FLOAT_VEC3, { 10, 10, 20, 0 }, -1 },     END_OF_UNIFORMS  }; @@ -382,7 +382,8 @@ CreateProgram(const char *vertProgFile, const char *fragProgFile,     glUseProgram(program); -   InitUniforms(program, uniforms); +   SetUniformValues(program, uniforms); +   PrintUniforms(uniforms);     return program;  } diff --git a/progs/glsl/toyball.c b/progs/glsl/toyball.c index 7fe27aebfe..c502f24077 100644 --- a/progs/glsl/toyball.c +++ b/progs/glsl/toyball.c @@ -24,18 +24,18 @@ static GLuint program;  static struct uniform_info Uniforms[] = { -   { "LightDir",       4, GL_FLOAT, { 0.57737, 0.57735, 0.57735, 0.0 }, -1 }, -   { "HVector",        4, GL_FLOAT, { 0.32506, 0.32506, 0.88808, 0.0 }, -1 }, -   { "BallCenter",     4, GL_FLOAT, { 0.0, 0.0, 0.0, 1.0 }, -1 }, -   { "SpecularColor",  4, GL_FLOAT, { 0.4, 0.4, 0.4, 60.0 }, -1 }, -   { "Red",         4, GL_FLOAT, { 0.6, 0.0, 0.0, 1.0 }, -1 }, -   { "Blue",        4, GL_FLOAT, { 0.0, 0.3, 0.6, 1.0 }, -1 }, -   { "Yellow",      4, GL_FLOAT, { 0.6, 0.5, 0.0, 1.0 }, -1 }, -   { "HalfSpace0",  4, GL_FLOAT, { 1.0, 0.0, 0.0, 0.2 }, -1 }, -   { "HalfSpace1",  4, GL_FLOAT, { 0.309016994, 0.951056516, 0.0, 0.2 }, -1 }, -   { "HalfSpace2",  4, GL_FLOAT, { -0.809016994, 0.587785252, 0.0, 0.2 }, -1 }, -   { "HalfSpace3",  4, GL_FLOAT, { -0.809016994, -0.587785252, 0.0, 0.2 }, -1 }, -   { "HalfSpace4",  4, GL_FLOAT, { 0.309116994, -0.951056516, 0.0, 0.2 }, -1 }, +   { "LightDir",    1, GL_FLOAT_VEC4, { 0.57737, 0.57735, 0.57735, 0.0 }, -1 }, +   { "HVector",     1, GL_FLOAT_VEC4, { 0.32506, 0.32506, 0.88808, 0.0 }, -1 }, +   { "BallCenter",  1, GL_FLOAT_VEC4, { 0.0, 0.0, 0.0, 1.0 }, -1 }, +   { "SpecularColor", 1, GL_FLOAT_VEC4, { 0.4, 0.4, 0.4, 60.0 }, -1 }, +   { "Red",         1, GL_FLOAT_VEC4, { 0.6, 0.0, 0.0, 1.0 }, -1 }, +   { "Blue",        1, GL_FLOAT_VEC4, { 0.0, 0.3, 0.6, 1.0 }, -1 }, +   { "Yellow",      1, GL_FLOAT_VEC4, { 0.6, 0.5, 0.0, 1.0 }, -1 }, +   { "HalfSpace0",  1, GL_FLOAT_VEC4, { 1.0, 0.0, 0.0, 0.2 }, -1 }, +   { "HalfSpace1",  1, GL_FLOAT_VEC4, { 0.309016994, 0.951056516, 0.0, 0.2 }, -1 }, +   { "HalfSpace2",  1, GL_FLOAT_VEC4, { -0.809016994, 0.587785252, 0.0, 0.2 }, -1 }, +   { "HalfSpace3",  1, GL_FLOAT_VEC4, { -0.809016994, -0.587785252, 0.0, 0.2 }, -1 }, +   { "HalfSpace4",  1, GL_FLOAT_VEC4, { 0.309116994, -0.951056516, 0.0, 0.2 }, -1 },     { "InOrOutInit", 1, GL_FLOAT, { -3.0, 0, 0, 0 }, -1 },     { "StripeWidth", 1, GL_FLOAT, {  0.3, 0, 0, 0 }, -1 },     { "FWidth",      1, GL_FLOAT, { 0.005, 0, 0, 0 }, -1 }, @@ -173,7 +173,8 @@ Init(void)     glUseProgram(program); -   InitUniforms(program, Uniforms); +   SetUniformValues(program, Uniforms); +   PrintUniforms(Uniforms);     assert(glGetError() == 0); @@ -204,7 +205,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 400);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/toyball.shtest b/progs/glsl/toyball.shtest new file mode 100644 index 0000000000..887663abd3 --- /dev/null +++ b/progs/glsl/toyball.shtest @@ -0,0 +1,17 @@ +vs CH11-toyball.vert +fs CH11-toyball.frag +uniform LightDir      GL_FLOAT_VEC4 0.57737 0.57735 0.57735 0.0 +uniform HVector       GL_FLOAT_VEC4 0.32506 0.32506 0.88808 0.0 +uniform BallCenter    GL_FLOAT_VEC4 0.0 0.0 0.0 1.0 +uniform SpecularColor GL_FLOAT_VEC4 0.4 0.4 0.4 60.0 +uniform Red           GL_FLOAT_VEC4 0.6 0.0 0.0 1.0 +uniform Blue          GL_FLOAT_VEC4 0.0 0.3 0.6 1.0 +uniform Yellow        GL_FLOAT_VEC4 0.6 0.5 0.0 1.0 +uniform HalfSpace0    GL_FLOAT_VEC4 1.0 0.0 0.0 0.2 +uniform HalfSpace1    GL_FLOAT_VEC4 .309016994 0.951056516 0.0 0.2 +uniform HalfSpace2    GL_FLOAT_VEC4 -0.809016994 0.587785252 0.0 0.2 +uniform HalfSpace3    GL_FLOAT_VEC4 -0.809016994 -0.587785252 0.0 0.2 +uniform HalfSpace4    GL_FLOAT_VEC4 .309116994 -0.951056516 0.0 0.2 +uniform InOrOutInit   GL_FLOAT -3.0 +uniform StripeWidth   GL_FLOAT 0.3 +uniform FWidth        GL_FLOAT .005 diff --git a/progs/glsl/trirast.c b/progs/glsl/trirast.c index f7546f25a2..53bd91ef97 100644 --- a/progs/glsl/trirast.c +++ b/progs/glsl/trirast.c @@ -239,7 +239,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(WinWidth, WinHeight);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/twoside.c b/progs/glsl/twoside.c index b6c1b477dd..a57484f96c 100644 --- a/progs/glsl/twoside.c +++ b/progs/glsl/twoside.c @@ -285,7 +285,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(WinWidth, WinHeight);     glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);     win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/vert-or-frag-only.c b/progs/glsl/vert-or-frag-only.c index 81fcab8c5b..148991ca83 100644 --- a/progs/glsl/vert-or-frag-only.c +++ b/progs/glsl/vert-or-frag-only.c @@ -173,7 +173,6 @@ int  main(int argc, char *argv[])  {     glutInit(&argc, argv); -   glutInitWindowPosition( 0, 0);     glutInitWindowSize(400, 200);     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);     Win = glutCreateWindow(argv[0]); diff --git a/progs/glsl/vert-tex.c b/progs/glsl/vert-tex.c index e791a5759a..4c8bfa587a 100644 --- a/progs/glsl/vert-tex.c +++ b/progs/glsl/vert-tex.c @@ -43,7 +43,7 @@ static GLfloat xRot = -70.0f, yRot = 0.0f, zRot = 0.0f;  /* value[0] = tex unit */  static struct uniform_info Uniforms[] = { -   { "tex1",  1, GL_INT, { 0, 0, 0, 0 }, -1 }, +   { "tex1",  1, GL_SAMPLER_2D, { 0, 0, 0, 0 }, -1 },     END_OF_UNIFORMS  }; diff --git a/progs/tests/SConscript b/progs/tests/SConscript index b17fa90593..bb6a1d2b8a 100644 --- a/progs/tests/SConscript +++ b/progs/tests/SConscript @@ -72,6 +72,7 @@ progs = [      'fogcoord',      'fptest1',      'fptexture', +    'getteximage',      'glutfx',      'interleave',      'invert', diff --git a/progs/tests/floattex.c b/progs/tests/floattex.c index ad14cacdcb..39302ce3af 100644 --- a/progs/tests/floattex.c +++ b/progs/tests/floattex.c @@ -33,7 +33,7 @@ static const char *VertShaderText =     "} \n";  static struct uniform_info Uniforms[] = { -   { "tex1",  1, GL_INT, { 0, 0, 0, 0 }, -1 }, +   { "tex1",  1, GL_SAMPLER_2D, { 0, 0, 0, 0 }, -1 },     END_OF_UNIFORMS  }; @@ -189,7 +189,7 @@ CreateProgram(void)     glUseProgram_func(program); -   InitUniforms(program, Uniforms); +   SetUniformValues(program, Uniforms);     return program;  } diff --git a/progs/tests/getprocaddress.c b/progs/tests/getprocaddress.c index ca66025d2d..a09ea58e1d 100644 --- a/progs/tests/getprocaddress.c +++ b/progs/tests/getprocaddress.c @@ -39,13 +39,2600 @@ typedef void (*generic_func)();  #define EQUAL(X, Y)  (fabs((X) - (Y)) < 0.001) -/** +/* This macro simplifies the task of querying an extension function + * pointer and checking to see whether it resolved. + */ +#define DECLARE_GLFUNC_PTR(name,type) \ +   type name = (type) glXGetProcAddressARB((const GLubyte *) "gl" #name) + +/******************************************************************** + * Generic helper functions used by the test functions. + */ + +static void CheckGLError(int line, const char *file, const char *function) +{ +    int errorCode; +    glFinish(); +    errorCode  = glGetError(); +    if (errorCode == GL_NO_ERROR) return; +    while (errorCode != GL_NO_ERROR) { +	fprintf(stderr, "OpenGL error 0x%x (%s) at line %d of file %s in function %s()\n", +	    errorCode, +	    errorCode == GL_INVALID_VALUE? "GL_INVALID_VALUE": +	    errorCode == GL_INVALID_ENUM? "GL_INVALID_ENUM": +	    errorCode == GL_INVALID_OPERATION? "GL_INVALID_OPERATION": +	    errorCode == GL_STACK_OVERFLOW? "GL_STACK_OVERFLOW": +	    errorCode == GL_STACK_UNDERFLOW? "GL_STACK_UNDERFLOW": +	    errorCode == GL_OUT_OF_MEMORY? "GL_OUT_OF_MEMORY": +	    "unknown", +	    line, file, function); +	errorCode = glGetError(); +    } +    fflush(stderr); +} + +static GLboolean  +compare_bytes(const char *errorLabel, GLuint expectedSize,  +   const GLubyte *expectedData, GLuint actualSize, const GLubyte *actualData) +{ +   int i; + +   if (expectedSize == actualSize && +      memcmp(expectedData, actualData, actualSize) == 0) { +      /* All is well */ +      return GL_TRUE; +   } + +   /* Trouble; we don't match.  Print out why. */ +   fprintf(stderr, "%s: actual data is not as expected\n", errorLabel); +   for (i = 0; i <= 1; i++) { +      const GLubyte *ptr; +      int size; +      char *label; +      int j; + +      switch(i) { +         case 0: +            label = "expected"; +            size = expectedSize; +            ptr = expectedData; +            break; +         case 1: +            label = "  actual"; +            size = actualSize; +            ptr = actualData; +            break; +      } +       +      fprintf(stderr, "    %s: size %d: {", label, size); +      for (j = 0; j < size; j++) { +         fprintf(stderr, "%s0x%02x", j > 0 ? ", " : "", ptr[j]); +      } +      fprintf(stderr, "}\n"); +   } + +   /* We fail if the data is unexpected. */ +   return GL_FALSE; +} + + +static GLboolean  +compare_ints(const char *errorLabel, GLuint expectedSize,  +   const GLint *expectedData, GLuint actualSize, const GLint *actualData) +{ +   int i; + +   if (expectedSize == actualSize && +      memcmp(expectedData, actualData, actualSize*sizeof(*expectedData)) == 0) { +      /* All is well */ +      return GL_TRUE; +   } + +   /* Trouble; we don't match.  Print out why. */ +   fprintf(stderr, "%s: actual data is not as expected\n", errorLabel); +   for (i = 0; i <= 1; i++) { +      const GLint *ptr; +      int size; +      char *label; +      int j; + +      switch(i) { +         case 0: +            label = "expected"; +            size = expectedSize; +            ptr = expectedData; +            break; +         case 1: +            label = "  actual"; +            size = actualSize; +            ptr = actualData; +            break; +      } +       +      fprintf(stderr, "    %s: size %d: {", label, size); +      for (j = 0; j < size; j++) { +         fprintf(stderr, "%s%d", j > 0 ? ", " : "", ptr[j]); +      } +      fprintf(stderr, "}\n"); +   } + +   /* We fail if the data is unexpected. */ +   return GL_FALSE; +} + +#define MAX_CONVERTED_VALUES 4 +static GLboolean  +compare_shorts_to_ints(const char *errorLabel, GLuint expectedSize,  +   const GLshort *expectedData, GLuint actualSize, const GLint *actualData) +{ +   int i; +   GLint convertedValues[MAX_CONVERTED_VALUES]; + +   if (expectedSize > MAX_CONVERTED_VALUES) { +      fprintf(stderr, "%s: too much data [need %d values, have %d values]\n", +         errorLabel, expectedSize, MAX_CONVERTED_VALUES); +      return GL_FALSE; +   } + +   for (i = 0; i < expectedSize; i++) { +      convertedValues[i] = (GLint) expectedData[i]; +   } + +   return compare_ints(errorLabel, expectedSize, convertedValues,  +      actualSize, actualData); +} + +static GLboolean  +compare_floats(const char *errorLabel, GLuint expectedSize,  +   const GLfloat *expectedData, GLuint actualSize, const GLfloat *actualData) +{ +   int i; + +   if (expectedSize == actualSize && +      memcmp(expectedData, actualData, actualSize*sizeof(*expectedData)) == 0) { +      /* All is well */ +      return GL_TRUE; +   } + +   /* Trouble; we don't match.  Print out why. */ +   fprintf(stderr, "%s: actual data is not as expected\n", errorLabel); +   for (i = 0; i <= 1; i++) { +      const GLfloat *ptr; +      int size; +      char *label; +      int j; + +      switch(i) { +         case 0: +            label = "expected"; +            size = expectedSize; +            ptr = expectedData; +            break; +         case 1: +            label = "  actual"; +            size = actualSize; +            ptr = actualData; +            break; +      } +       +      fprintf(stderr, "    %s: size %d: {", label, size); +      for (j = 0; j < size; j++) { +         fprintf(stderr, "%s%f", j > 0 ? ", " : "", ptr[j]); +      } +      fprintf(stderr, "}\n"); +   } + +   /* We fail if the data is unexpected. */ +   return GL_FALSE; +} + +static GLboolean  +compare_doubles(const char *errorLabel, GLuint expectedSize,  +   const GLdouble *expectedData, GLuint actualSize, const GLdouble *actualData) +{ +   int i; + +   if (expectedSize == actualSize ||  +      memcmp(expectedData, actualData, actualSize*sizeof(*expectedData)) == 0) { +      /* All is well */ +      return GL_TRUE; +   } + +   /* Trouble; we don't match.  Print out why. */ +   fprintf(stderr, "%s: actual data is not as expected\n", errorLabel); +   for (i = 0; i <= 1; i++) { +      const GLdouble *ptr; +      int size; +      char *label; +      int j; + +      switch(i) { +         case 0: +            label = "expected"; +            size = expectedSize; +            ptr = expectedData; +            break; +         case 1: +            label = "  actual"; +            size = actualSize; +            ptr = actualData; +            break; +      } +       +      fprintf(stderr, "    %s: size %d: {", label, size); +      for (j = 0; j < size; j++) { +         fprintf(stderr, "%s%f", j > 0 ? ", " : "", ptr[j]); +      } +      fprintf(stderr, "}\n"); +   } + +   /* We fail if the data is unexpected. */ +   return GL_FALSE; +} + +/******************************************************************** + * Functions to assist with GL_ARB_texture_compressiong testing + */ + +static GLboolean +check_texture_format_supported(GLenum format) +{ +   GLint numFormats; +   GLint *formats; +   register int i; + +   glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, &numFormats); +   formats = malloc(numFormats * sizeof(GLint)); +   if (formats == NULL) { +      fprintf(stderr, "check_texture_format_supported: could not allocate memory for %d GLints\n",  +         numFormats); +      return GL_FALSE; +   } +    +   memset(formats, 0, numFormats * sizeof(GLint)); +   glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS_ARB, formats); + +   for (i = 0; i < numFormats; i++) { +      if (formats[i] == format) { +         free(formats); +         return GL_TRUE; +      } +   } + +   /* We didn't find the format we were looking for.  Give an error. */ +#define FORMAT_NAME(x) (\ +   x == GL_COMPRESSED_RGB_FXT1_3DFX ? "GL_COMPRESSED_RGB_FXT1_3DFX" : \ +   x == GL_COMPRESSED_RGBA_FXT1_3DFX ? "GL_COMPRESSED_RGBA_FXT1_3DFX" : \ +   x == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? "GL_COMPRESSED_RGB_S3TC_DXT1_EXT" : \ +   x == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT" : \ +   x == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ? "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT" : \ +   x == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ? "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT" : \ +   x == GL_RGB_S3TC ? "GL_RGB_S3TC" : \ +   x == GL_RGB4_S3TC ? "GL_RGB4_S3TC" : \ +   x == GL_RGBA_S3TC ? "GL_RGBA_S3TC" : \ +   x == GL_RGBA4_S3TC ? "GL_RGBA4_S3TC" : \ +   "unknown") +   fprintf(stderr, "check_texture_format_supported: unsupported format 0x%04x [%s]\n", +      format, FORMAT_NAME(format)); +   fprintf(stderr, "supported formats:"); +   for (i = 0; i < numFormats; i++) { +      fprintf(stderr, " 0x%04x [%s]", formats[i], FORMAT_NAME(formats[i])); +   } +   fprintf(stderr, "\n"); +   return GL_FALSE; +} + +/* This helper function compresses an RGBA texture and compares it + * against the expected compressed data.  It returns GL_TRUE if all + * went as expected, or GL_FALSE in the case of error. + */ +static GLboolean +check_texture_compression(const char *message, GLenum dimension, +   GLint width, GLint height, GLint depth, const GLubyte *texture,  +   int expectedCompressedSize, const GLubyte *expectedCompressedData) +{ +   /* These are the data we query about the texture. */ +   GLint isCompressed; +   GLenum compressedFormat; +   GLint compressedSize; +   GLubyte *compressedData; + +   /* We need this function pointer to operate. */ +   DECLARE_GLFUNC_PTR(GetCompressedTexImageARB, PFNGLGETCOMPRESSEDTEXIMAGEARBPROC); +   if (GetCompressedTexImageARB == NULL) { +      fprintf(stderr,  +         "%s: could not query GetCompressedTexImageARB function pointer\n", +         message); +      return GL_FALSE; +   } + +   /* Verify that we actually have the GL_COMPRESSED_RGBA_S3TC_DXT3_EXT format available. */ +   if (!check_texture_format_supported(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT)) { +      return GL_FALSE; +   } + +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   /* Set up the base image, requesting that the GL library compress it. */ +   switch(dimension) { +      case GL_TEXTURE_1D: +         glTexImage1D(GL_TEXTURE_1D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            width, 0,  +            GL_RGBA, GL_UNSIGNED_BYTE, texture); +         break; +      case GL_TEXTURE_2D: +         glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            width, height, 0,  +            GL_RGBA, GL_UNSIGNED_BYTE, texture); +         break; +      case GL_TEXTURE_3D: +         glTexImage3D(GL_TEXTURE_3D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            width, height, depth, 0,  +            GL_RGBA, GL_UNSIGNED_BYTE, texture); +         break; +      default: +         fprintf(stderr, "%s: unknown dimension 0x%04x.\n", message, dimension); +         return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Make sure the texture is compressed, and pull it out if it is. */ +   glGetTexLevelParameteriv(dimension, 0, GL_TEXTURE_COMPRESSED_ARB,  +      &isCompressed); +   if (!isCompressed) { +      fprintf(stderr, "%s: could not compress GL_COMPRESSED_RGBA_S3TC_DXT3_EXT texture\n", +         message); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   glGetTexLevelParameteriv(dimension, 0, GL_TEXTURE_INTERNAL_FORMAT,  +      (GLint *)&compressedFormat); +   if (compressedFormat != GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) { +      fprintf(stderr, "%s: got internal format 0x%04x, expected GL_COMPRESSED_RGBA_S3TC_DXT3_EXT [0x%04x]\n", +         __FUNCTION__, compressedFormat, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   glGetTexLevelParameteriv(dimension, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &compressedSize); +   compressedData = malloc(compressedSize); +   if (compressedData == NULL) { +      fprintf(stderr, "%s: could not malloc %d bytes for compressed texture\n", +         message, compressedSize); +      return GL_FALSE; +   } +   memset(compressedData, 0, compressedSize); +   (*GetCompressedTexImageARB)(dimension, 0, compressedData); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Compare it to the expected compressed data. The compare_bytes() +    * call will print out diagnostics in the case of failure. +    */ +   if (!compare_bytes(message,  +      expectedCompressedSize, expectedCompressedData, +      compressedSize, compressedData)) { + +      free(compressedData); +      return GL_FALSE; +   } + +   /* All done.  Free our allocated data and return success. */ +   free(compressedData); +   return GL_TRUE; +} + +/* We'll use one function to exercise 1D, 2D, and 3D textures. */ + +/* The test function for compressed 3D texture images requires several + * different function pointers that have to be queried.  This function + * gets all the function pointers it needs itself, and so is suitable for  + * use to test any and all of the incorporated functions. + */ + +static GLboolean +exercise_CompressedTextures(GLenum dimension) +{ +   /* Set up a basic (uncompressed) texture.  We're doing a blue/yellow +    * checkerboard.  The 8x4/32-pixel board is well-suited to S3TC +    * compression, which works on 4x4 blocks of pixels. +    */ +#define B 0,0,255,255 +#define Y 255,255,0,255 +#define TEXTURE_WIDTH 16  +#define TEXTURE_HEIGHT 4 +#define TEXTURE_DEPTH 1 +   static GLubyte texture[TEXTURE_WIDTH*TEXTURE_HEIGHT*TEXTURE_DEPTH*4] = { +      B, B, Y, Y, B, B, Y, Y, B, B, Y, Y, B, B, Y, Y, +      B, B, Y, Y, B, B, Y, Y, B, B, Y, Y, B, B, Y, Y, +      Y, Y, B, B, Y, Y, B, B, Y, Y, B, B, Y, Y, B, B,  +      Y, Y, B, B, Y, Y, B, B, Y, Y, B, B, Y, Y, B, B,  +   }; +#undef B +#undef Y +   GLubyte uncompressedTexture[TEXTURE_WIDTH*TEXTURE_HEIGHT*TEXTURE_DEPTH*4]; + +   /* We'll use this as a texture subimage. */ +#define R 255,0,0,255 +#define G 0,255,0,255 +#define SUBTEXTURE_WIDTH 4 +#define SUBTEXTURE_HEIGHT 4 +#define SUBTEXTURE_DEPTH 1 +   static GLubyte subtexture[SUBTEXTURE_WIDTH*SUBTEXTURE_HEIGHT*SUBTEXTURE_DEPTH*4] = { +      G, G, R, R, +      G, G, R, R, +      R, R, G, G, +      R, R, G, G, +   }; +#undef R +#undef G + +   /* These are the expected compressed textures.  (In the case of +    * a failed comparison, the test program will print out the +    * actual compressed data in a format that can be directly used +    * here, if desired.)  The brave of heart can calculate the compression  +    * themselves based on the formulae described at: +    *   http://en.wikipedia.org/wiki/S3_Texture_Compression +    * In a nutshell, each group of 16 bytes encodes a 4x4 texture block. +    * The first eight bytes of each group are 4-bit alpha values +    * for each of the 16 pixels in the texture block. +    * The next four bytes in each group are LSB-first RGB565 colors; the +    * first two bytes are identified as the color C0, and the next two +    * are the color C1.  (Two more colors C2 and C3 will be calculated  +    * from these, but do not appear in the compression data.)  The +    * last 4 bytes of the group are sixteen 2-bit indices that, for +    * each of the 16 pixels in the texture block, select one of the +    * colors C0, C1, C2, or C3. +    * +    * For example, our blue/yellow checkerboard is made up of +    * four identical 4x4 blocks.  Each of those blocks will +    * be encoded as: eight bytes of 0xff (16 alpha values, each 0xf), +    * C0 as the RGB565 color yellow (0xffe0), encoded LSB-first; +    * C1 as the RGB565 color blue (0x001f), encoded LSB-first; +    * and 4 bytes of 16 2-bit color indices reflecting the +    * choice of color for each of the 16 pixels: +    *     00, 00, 01, 01, = 0x05 +    *     00, 00, 01, 01, = 0x05 +    *     01, 01, 00, 00, = 0x50 +    *     01, 01, 00, 00, = 0x50 +    */ +   static GLubyte compressedTexture[] = { +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0xe0, 0xff, 0x1f, 0x00, 0x05, 0x05, 0x50, 0x50, +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0xe0, 0xff, 0x1f, 0x00, 0x05, 0x05, 0x50, 0x50, +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0xe0, 0xff, 0x1f, 0x00, 0x05, 0x05, 0x50, 0x50, +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0xe0, 0xff, 0x1f, 0x00, 0x05, 0x05, 0x50, 0x50 +   }; + +   /* The similar calculations for the 4x4 subtexture are left +    * as an exercise for the reader. +    */ +   static GLubyte compressedSubTexture[] = { +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0x00, 0xf8, 0xe0, 0x07, 0x05, 0x05, 0x50, 0x50, +   }; + +   /* The combined texture replaces the initial blue/yellow +    * block with the green/red block.  (I'd wanted to do +    * the more interesting exercise of putting the +    * green/red block in the middle of the blue/yellow +    * texture, which is a non-trivial replacement, but +    * the attempt produces GL_INVALID_OPERATION, showing +    * that you can only replace whole blocks of  +    * subimages with S3TC.)  The combined texture looks +    * like: +    *      G G R R  B B Y Y  B B Y Y  B B Y Y +    *      G G R R  B B Y Y  B B Y Y  B B Y Y +    *      R R G G  Y Y B B  Y Y B B  Y Y B B  +    *      R R G G  Y Y B B  Y Y B B  Y Y B B  +    * which encodes just like the green/red block followed +    * by 3 copies of the yellow/blue block. +    */ +   static GLubyte compressedCombinedTexture[] = { +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0x00, 0xf8, 0xe0, 0x07, 0x05, 0x05, 0x50, 0x50, +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0xe0, 0xff, 0x1f, 0x00, 0x05, 0x05, 0x50, 0x50, +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0xe0, 0xff, 0x1f, 0x00, 0x05, 0x05, 0x50, 0x50, +      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +      0xe0, 0xff, 0x1f, 0x00, 0x05, 0x05, 0x50, 0x50 +   }; + +   /* These are the data we query about the texture. */ +   GLint queryIsCompressed; +   GLenum queryCompressedFormat; +   GLint queryCompressedSize; +   GLubyte queryCompressedData[sizeof(compressedTexture)]; + +   /* Query the function pointers we need.  We actually won't need most +    * of these (the "dimension" parameter dictates whether we're testing +    * 1D, 2D, or 3D textures), but we'll have them all ready just in case. +    */ +   DECLARE_GLFUNC_PTR(GetCompressedTexImageARB, PFNGLGETCOMPRESSEDTEXIMAGEARBPROC); +   DECLARE_GLFUNC_PTR(CompressedTexImage3DARB, PFNGLCOMPRESSEDTEXIMAGE3DARBPROC); +   DECLARE_GLFUNC_PTR(CompressedTexSubImage3DARB, PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC); +   DECLARE_GLFUNC_PTR(CompressedTexImage2DARB, PFNGLCOMPRESSEDTEXIMAGE2DARBPROC); +   DECLARE_GLFUNC_PTR(CompressedTexSubImage2DARB, PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC); +   DECLARE_GLFUNC_PTR(CompressedTexImage1DARB, PFNGLCOMPRESSEDTEXIMAGE1DARBPROC); +   DECLARE_GLFUNC_PTR(CompressedTexSubImage1DARB, PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC); + +   /* If the necessary functions are missing, we can't continue */ +   if (GetCompressedTexImageARB == NULL) { +      fprintf(stderr, "%s: GetCompressedTexImageARB function is missing\n", +         __FUNCTION__); +      return GL_FALSE; +   } +   switch (dimension) { +      case GL_TEXTURE_1D: +         if (CompressedTexImage1DARB == NULL || CompressedTexSubImage1DARB == NULL) { +            fprintf(stderr, "%s: 1D compressed texture functions are missing\n", +               __FUNCTION__); +            return GL_FALSE; +         }; +         break; +      case GL_TEXTURE_2D: +         if (CompressedTexImage2DARB == NULL || CompressedTexSubImage2DARB == NULL) { +            fprintf(stderr, "%s: 2D compressed texture functions are missing\n", +               __FUNCTION__); +            return GL_FALSE; +         }; +         break; +      case GL_TEXTURE_3D: +         if (CompressedTexImage3DARB == NULL || CompressedTexSubImage3DARB == NULL) { +            fprintf(stderr, "%s: 3D compressed texture functions are missing\n", +               __FUNCTION__); +            return GL_FALSE; +         }; +         break; +      default: +         fprintf(stderr, "%s: unknown texture dimension 0x%04x passed.\n", +            __FUNCTION__, dimension); +         return GL_FALSE; +   } +    +   /* Check the compression of our base texture image. */ +   if (!check_texture_compression("texture compression", dimension, +         TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH, texture, +         sizeof(compressedTexture), compressedTexture)) { + +      /* Something's wrong with texture compression.  The function +       * above will have printed an appropriate error. +       */ +      return GL_FALSE; +   } + +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Do the same for our texture subimage */ +   if (!check_texture_compression("subtexture compression", dimension, +         SUBTEXTURE_WIDTH, SUBTEXTURE_HEIGHT, SUBTEXTURE_DEPTH, subtexture, +         sizeof(compressedSubTexture), compressedSubTexture)) { + +      /* Something's wrong with texture compression.  The function +       * above will have printed an appropriate error. +       */ +      return GL_FALSE; +   } + +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Send the base compressed texture down to the hardware. */ +   switch(dimension) { +      case GL_TEXTURE_3D: +         (*CompressedTexImage3DARB)(GL_TEXTURE_3D, 0,  +            GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH, 0,  +            sizeof(compressedTexture), compressedTexture); +         break; + +      case GL_TEXTURE_2D: +         (*CompressedTexImage2DARB)(GL_TEXTURE_2D, 0,  +            GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            TEXTURE_WIDTH, TEXTURE_HEIGHT, 0,  +            sizeof(compressedTexture), compressedTexture); +         break; + +      case GL_TEXTURE_1D: +         (*CompressedTexImage1DARB)(GL_TEXTURE_1D, 0,  +            GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            TEXTURE_WIDTH, 0,  +            sizeof(compressedTexture), compressedTexture); +         break; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* For grins, query it to make sure it is as expected. */ +   glGetTexLevelParameteriv(dimension, 0, GL_TEXTURE_COMPRESSED_ARB,  +      &queryIsCompressed); +   if (!queryIsCompressed) { +      fprintf(stderr, "%s: compressed texture did not come back as compressed\n", +         __FUNCTION__); +      return GL_FALSE; +   } +   glGetTexLevelParameteriv(dimension, 0, GL_TEXTURE_INTERNAL_FORMAT,  +      (GLint *)&queryCompressedFormat); +   if (queryCompressedFormat != GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) { +      fprintf(stderr, "%s: got internal format 0x%04x, expected GL_COMPRESSED_RGBA_S3TC_DXT3_EXT [0x%04x]\n", +         __FUNCTION__, queryCompressedFormat, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); +      return GL_FALSE; +   } +   glGetTexLevelParameteriv(dimension, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB,  +      &queryCompressedSize); +   if (queryCompressedSize != sizeof(compressedTexture)) { +      fprintf(stderr, "%s: compressed 3D texture changed size: expected %d, actual %d\n", +         __FUNCTION__, sizeof(compressedTexture), queryCompressedSize); +      return GL_FALSE; +   } +   (*GetCompressedTexImageARB)(dimension, 0, queryCompressedData); +   if (!compare_bytes( +      "exercise_CompressedTextures:doublechecking compressed texture", +      sizeof(compressedTexture), compressedTexture, +      queryCompressedSize, queryCompressedData)) { +      return GL_FALSE; +   } + +   /* Now apply the texture subimage.  The current implementation of +    * S3TC requires that subimages be only applied to whole blocks. +    */ +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   switch(dimension) { +      case GL_TEXTURE_3D: +         (*CompressedTexSubImage3DARB)(GL_TEXTURE_3D, 0,  +            0, 0, 0, /* offsets */ +            SUBTEXTURE_WIDTH, SUBTEXTURE_HEIGHT, SUBTEXTURE_DEPTH, +            GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            sizeof(compressedSubTexture), compressedSubTexture); +         break; +      case GL_TEXTURE_2D: +         (*CompressedTexSubImage2DARB)(GL_TEXTURE_2D, 0,  +            0, 0, /* offsets */ +            SUBTEXTURE_WIDTH, SUBTEXTURE_HEIGHT, +            GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            sizeof(compressedSubTexture), compressedSubTexture); +         break; +      case GL_TEXTURE_1D: +         (*CompressedTexSubImage2DARB)(GL_TEXTURE_2D, 0,  +            0, 0, /* offsets */ +            SUBTEXTURE_WIDTH, SUBTEXTURE_HEIGHT, +            GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,  +            sizeof(compressedSubTexture), compressedSubTexture); +         break; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query the compressed texture back now, and see that it +    * is as expected. +    */ +   (*GetCompressedTexImageARB)(dimension, 0, queryCompressedData); +   if (!compare_bytes("exercise_CompressedTextures:combined texture", +      sizeof(compressedCombinedTexture), compressedCombinedTexture, +      queryCompressedSize, queryCompressedData)) { +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Just for the exercise, uncompress the texture and pull it out.  +    * We don't check it because the compression is lossy, so it won't +    * compare exactly to the source texture; we just  +    * want to exercise the code paths that convert it. +    */ +   glGetTexImage(dimension, 0, GL_RGBA, GL_UNSIGNED_BYTE, uncompressedTexture); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* If we survived this far, we pass. */ +   return GL_TRUE; +} + +/************************************************************************** + * Functions to assist with GL_EXT_framebuffer_object and + * GL_EXT_framebuffer_blit testing. + */ + +#define FB_STATUS_NAME(x) (\ +   x == GL_FRAMEBUFFER_COMPLETE_EXT ? "GL_FRAMEBUFFER_COMPLETE_EXT" : \ +   x == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT ? "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT" : \ +   x == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT ? "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT" : \ +   x == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT ? "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT" : \ +   x == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT ? "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT" : \ +   x == GL_FRAMEBUFFER_UNSUPPORTED_EXT ? "GL_FRAMEBUFFER_UNSUPPORTED_EXT" : \ +   x == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT ? "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT" : \ +   x == GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT ? "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT" : \ +   x == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT ? "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT" : \ +   "unknown") + +static GLboolean +exercise_framebuffer(void) +{ +   GLuint framebufferID = 0; +   GLuint renderbufferID = 0; +    +   /* Dimensions of the framebuffer and renderbuffers are arbitrary. +    * Since they won't be shown on-screen, we can use whatever we want. +    */ +   const GLint Width = 100; +   const GLint Height = 100; + +   /* Every function we use will be referenced through function pointers. +    * This will allow this test program to run on OpenGL implementations +    * that *don't* implement these extensions (though the implementation +    * used to compile them must have up-to-date header files). +    */ +   DECLARE_GLFUNC_PTR(GenFramebuffersEXT, PFNGLGENFRAMEBUFFERSEXTPROC); +   DECLARE_GLFUNC_PTR(IsFramebufferEXT, PFNGLISFRAMEBUFFEREXTPROC); +   DECLARE_GLFUNC_PTR(DeleteFramebuffersEXT, PFNGLDELETEFRAMEBUFFERSEXTPROC); +   DECLARE_GLFUNC_PTR(BindFramebufferEXT, PFNGLBINDFRAMEBUFFEREXTPROC); +   DECLARE_GLFUNC_PTR(GenRenderbuffersEXT, PFNGLGENRENDERBUFFERSEXTPROC); +   DECLARE_GLFUNC_PTR(IsRenderbufferEXT, PFNGLISRENDERBUFFEREXTPROC); +   DECLARE_GLFUNC_PTR(DeleteRenderbuffersEXT, PFNGLDELETERENDERBUFFERSEXTPROC); +   DECLARE_GLFUNC_PTR(BindRenderbufferEXT, PFNGLBINDRENDERBUFFEREXTPROC); +   DECLARE_GLFUNC_PTR(FramebufferRenderbufferEXT, PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC); +   DECLARE_GLFUNC_PTR(RenderbufferStorageEXT, PFNGLRENDERBUFFERSTORAGEEXTPROC); +   DECLARE_GLFUNC_PTR(CheckFramebufferStatusEXT, PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC); + +   /* The BlitFramebuffer function comes from a different extension. +    * It's possible for an implementation to implement all the above, +    * but not BlitFramebuffer; so it's okay if this one comes back +    * NULL, as we can still test the rest. +    */ +   DECLARE_GLFUNC_PTR(BlitFramebufferEXT, PFNGLBLITFRAMEBUFFEREXTPROC); + +   /* We cannot test unless we have all the function pointers. */ +   if ( +      GenFramebuffersEXT == NULL || +      IsFramebufferEXT == NULL ||  +      DeleteFramebuffersEXT == NULL || +      BindFramebufferEXT == NULL || +      GenRenderbuffersEXT == NULL || +      IsRenderbufferEXT == NULL || +      DeleteRenderbuffersEXT == NULL || +      BindRenderbufferEXT == NULL || +      FramebufferRenderbufferEXT == NULL || +      RenderbufferStorageEXT == NULL || +      CheckFramebufferStatusEXT == NULL +   ) { +      fprintf(stderr, "%s: could not locate all framebuffer functions\n", +         __FUNCTION__); +      return GL_FALSE; +   } + +   /* Generate a framebuffer for us to play with. */ +   (*GenFramebuffersEXT)(1, &framebufferID); +   if (framebufferID == 0) { +      fprintf(stderr, "%s: failed to generate a frame buffer ID.\n", +         __FUNCTION__); +      return GL_FALSE; +   } +   /* The generated name is not a framebuffer object until bound. */ +   (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, framebufferID); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   if (!(*IsFramebufferEXT)(framebufferID)) { +      fprintf(stderr, "%s: generated a frame buffer ID 0x%x that wasn't a framebuffer\n", +         __FUNCTION__, framebufferID); +      (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +      (*DeleteFramebuffersEXT)(1, &framebufferID); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   { +      GLint queriedFramebufferID; +      glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &queriedFramebufferID); +      if (queriedFramebufferID != framebufferID) { +         fprintf(stderr, "%s: bound frame buffer 0x%x, but queried 0x%x\n", +            __FUNCTION__, framebufferID, queriedFramebufferID); +         (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +         (*DeleteFramebuffersEXT)(1, &framebufferID); +         return GL_FALSE; +      } +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Create a color buffer to attach to the frame buffer object, so +    * we can actually operate on it.  We go through the same basic checks +    * with the renderbuffer that we do with the framebuffer. +    */ +   (*GenRenderbuffersEXT)(1, &renderbufferID); +   if (renderbufferID == 0) { +      fprintf(stderr, "%s: could not generate a renderbuffer ID\n", +         __FUNCTION__); +      (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +      (*DeleteFramebuffersEXT)(1, &framebufferID); +      return GL_FALSE; +   } +   (*BindRenderbufferEXT)(GL_RENDERBUFFER_EXT, renderbufferID); +   if (!(*IsRenderbufferEXT)(renderbufferID)) { +      fprintf(stderr, "%s: generated renderbuffer 0x%x is not a renderbuffer\n", +         __FUNCTION__, renderbufferID); +      (*BindRenderbufferEXT)(GL_RENDERBUFFER_EXT, 0); +      (*DeleteRenderbuffersEXT)(1, &renderbufferID); +      (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +      (*DeleteFramebuffersEXT)(1, &framebufferID); +      return GL_FALSE; +   } +   { +      GLint queriedRenderbufferID = 0; +      glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &queriedRenderbufferID); +      if (renderbufferID != queriedRenderbufferID) { +         fprintf(stderr, "%s: bound renderbuffer 0x%x, but got 0x%x\n", +            __FUNCTION__, renderbufferID, queriedRenderbufferID); +         (*BindRenderbufferEXT)(GL_RENDERBUFFER_EXT, 0); +         (*DeleteRenderbuffersEXT)(1, &renderbufferID); +         (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +         (*DeleteFramebuffersEXT)(1, &framebufferID); +         return GL_FALSE; +      } +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Add the renderbuffer as a color attachment to the current +    * framebuffer (which is our generated framebuffer). +    */ +   (*FramebufferRenderbufferEXT)(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, +      GL_RENDERBUFFER_EXT, renderbufferID); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* The renderbuffer will need some dimensions and storage space. */ +   (*RenderbufferStorageEXT)(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* That should be everything we need.  If we set up to draw and to +    * read from our color attachment, we should be "framebuffer complete", +    * meaning the framebuffer is ready to go. +    */ +   glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); +   glReadBuffer(GL_COLOR_ATTACHMENT1_EXT); +   { +      GLenum status = (*CheckFramebufferStatusEXT)(GL_FRAMEBUFFER_EXT); +      if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { +         fprintf(stderr, "%s: framebuffer not complete; status = %s [0x%x]\n", +            __FUNCTION__, FB_STATUS_NAME(status), status); +         glReadBuffer(0); +         glDrawBuffer(0); +         (*BindRenderbufferEXT)(GL_RENDERBUFFER_EXT, 0); +         (*DeleteRenderbuffersEXT)(1, &renderbufferID); +         (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +         (*DeleteFramebuffersEXT)(1, &framebufferID); +         return GL_FALSE; +      } +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Define the contents of the frame buffer */ +   glClearColor(0.5, 0.5, 0.5, 0.0); +   glClear(GL_COLOR_BUFFER_BIT); + +   /* If the GL_EXT_framebuffer_blit is supported, attempt a framebuffer +    * blit from (5,5)-(10,10) to (90,90)-(95,95).  This is *not* an +    * error if framebuffer_blit is *not* supported (as we can still +    * effectively test the other functions). +    */ +   if (BlitFramebufferEXT != NULL) { +      (*BlitFramebufferEXT)(5, 5, 10, 10, 90, 90, 95, 95, +         GL_COLOR_BUFFER_BIT, GL_NEAREST); +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* We could now test to see whether the framebuffer had the desired +    * contents.  As this is just a touch test, we'll leave that for now. +    * Clean up and go home. +    */ +   glReadBuffer(0); +   glDrawBuffer(0); +   (*BindRenderbufferEXT)(GL_RENDERBUFFER_EXT, 0); +   (*DeleteRenderbuffersEXT)(1, &renderbufferID); +   (*BindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +   (*DeleteFramebuffersEXT)(1, &framebufferID); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   return GL_TRUE; +} + +/************************************************************************** + * Functions to assist with GL_ARB_shader_objects testing. + */ + +static void +print_info_log(const char *message, GLhandleARB object) +{ +   DECLARE_GLFUNC_PTR(GetObjectParameterivARB, PFNGLGETOBJECTPARAMETERIVARBPROC); +   DECLARE_GLFUNC_PTR(GetInfoLogARB, PFNGLGETINFOLOGARBPROC); +   int logLength, queryLength; +   char *log; + +   if (GetObjectParameterivARB == NULL) { +      fprintf(stderr, "%s: could not get GetObjectParameterivARB address\n", +         message); +      return; +   } +   if (GetInfoLogARB == NULL) { +      fprintf(stderr, "%s: could not get GetInfoLogARB address\n", +         message); +      return; +   } + +   (*GetObjectParameterivARB)(object, GL_OBJECT_INFO_LOG_LENGTH_ARB,  +      &logLength); +   if (logLength == 0) { +      fprintf(stderr, "%s: info log length is 0\n", message); +      return; +   } +   log = malloc(logLength); +   if (log == NULL) { +      fprintf(stderr, "%s: could not malloc %d bytes for info log\n", +         message, logLength); +   } +   else { +      (*GetInfoLogARB)(object, logLength, &queryLength, log); +      fprintf(stderr, "%s: info log says '%s'\n", +         message, log); +   } +   free(log); +} + +static GLboolean +exercise_uniform_start(const char *fragmentShaderText, const char *uniformName, +   GLhandleARB *returnProgram, GLint *returnUniformLocation) +{ +   DECLARE_GLFUNC_PTR(CreateShaderObjectARB, PFNGLCREATESHADEROBJECTARBPROC); +   DECLARE_GLFUNC_PTR(ShaderSourceARB, PFNGLSHADERSOURCEARBPROC); +   DECLARE_GLFUNC_PTR(CompileShaderARB, PFNGLCOMPILESHADERARBPROC); +   DECLARE_GLFUNC_PTR(CreateProgramObjectARB, PFNGLCREATEPROGRAMOBJECTARBPROC); +   DECLARE_GLFUNC_PTR(AttachObjectARB, PFNGLATTACHOBJECTARBPROC); +   DECLARE_GLFUNC_PTR(LinkProgramARB, PFNGLLINKPROGRAMARBPROC); +   DECLARE_GLFUNC_PTR(UseProgramObjectARB, PFNGLUSEPROGRAMOBJECTARBPROC); +   DECLARE_GLFUNC_PTR(ValidateProgramARB, PFNGLVALIDATEPROGRAMARBPROC); +   DECLARE_GLFUNC_PTR(GetUniformLocationARB, PFNGLGETUNIFORMLOCATIONARBPROC); +   DECLARE_GLFUNC_PTR(DeleteObjectARB, PFNGLDELETEOBJECTARBPROC); +   DECLARE_GLFUNC_PTR(GetObjectParameterivARB, PFNGLGETOBJECTPARAMETERIVARBPROC); +   GLhandleARB fs, program; +   GLint uniformLocation; +   GLint shaderCompiled, programValidated; + +   if (CreateShaderObjectARB == NULL || +       ShaderSourceARB == NULL || +       CompileShaderARB == NULL || +       CreateProgramObjectARB == NULL || +       AttachObjectARB == NULL || +       LinkProgramARB == NULL || +       UseProgramObjectARB == NULL || +       ValidateProgramARB == NULL || +       GetUniformLocationARB == NULL || +       DeleteObjectARB == NULL || +       GetObjectParameterivARB == NULL || +       0) { +      return GL_FALSE; +   } + +   /* Create the trivial fragment shader and program.  For safety +    * we'll check to make sure they compile and link correctly. +    */ +   fs = (*CreateShaderObjectARB)(GL_FRAGMENT_SHADER_ARB); +   (*ShaderSourceARB)(fs, 1, &fragmentShaderText, NULL); +   (*CompileShaderARB)(fs); +   (*GetObjectParameterivARB)(fs, GL_OBJECT_COMPILE_STATUS_ARB, +      &shaderCompiled); +   if (!shaderCompiled) { +      print_info_log("shader did not compile", fs); +      (*DeleteObjectARB)(fs); +      CheckGLError(__LINE__, __FILE__, __FUNCTION__); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   program = (*CreateProgramObjectARB)(); +   (*AttachObjectARB)(program, fs); +   (*LinkProgramARB)(program); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Make sure we're going to run successfully */ +   (*ValidateProgramARB)(program); +   (*GetObjectParameterivARB)(program, GL_OBJECT_VALIDATE_STATUS_ARB,  +      &programValidated); +   if (!programValidated) {;  +      print_info_log("program did not validate", program); +      (*DeleteObjectARB)(program); +      (*DeleteObjectARB)(fs); +      CheckGLError(__LINE__, __FILE__, __FUNCTION__); +      return GL_FALSE; +   } + +   /* Put the program in place.  We're not allowed to assign to uniform +    * variables used by the program until the program is put into use. +    */ +   (*UseProgramObjectARB)(program); + +   /* Once the shader is in place, we're free to delete it; this +    * won't affect the copy that's part of the program. +    */ +   (*DeleteObjectARB)(fs); + +   /* Find the location index of the uniform variable we declared; +    * the caller will ned that to set the value. +    */ +   uniformLocation = (*GetUniformLocationARB)(program, uniformName); +   if (uniformLocation == -1) { +      fprintf(stderr, "%s: could not determine uniform location\n", +         __FUNCTION__); +      (*DeleteObjectARB)(program); +      CheckGLError(__LINE__, __FILE__, __FUNCTION__); +      return GL_FALSE; +   } + +   /* All done with what we're supposed to do - return the program +    * handle and the uniform location to the caller. +    */ +   *returnProgram = program; +   *returnUniformLocation = uniformLocation; +   return GL_TRUE; +} + +static void +exercise_uniform_end(GLhandleARB program) +{ +   DECLARE_GLFUNC_PTR(UseProgramObjectARB, PFNGLUSEPROGRAMOBJECTARBPROC); +   DECLARE_GLFUNC_PTR(DeleteObjectARB, PFNGLDELETEOBJECTARBPROC); +   if (UseProgramObjectARB == NULL || DeleteObjectARB == NULL) { +      return; +   } + +   /* Turn off our program by setting the special value 0, and +    * then delete the program object. +    */ +   (*UseProgramObjectARB)(0); +   (*DeleteObjectARB)(program); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +} + +/************************************************************************** + * Exercises for fences + */ +static GLboolean +exercise_fences(void) +{ +   DECLARE_GLFUNC_PTR(DeleteFencesNV, PFNGLDELETEFENCESNVPROC); +   DECLARE_GLFUNC_PTR(FinishFenceNV, PFNGLFINISHFENCENVPROC); +   DECLARE_GLFUNC_PTR(GenFencesNV, PFNGLGENFENCESNVPROC); +   DECLARE_GLFUNC_PTR(GetFenceivNV, PFNGLGETFENCEIVNVPROC); +   DECLARE_GLFUNC_PTR(IsFenceNV, PFNGLISFENCENVPROC); +   DECLARE_GLFUNC_PTR(SetFenceNV, PFNGLSETFENCENVPROC); +   DECLARE_GLFUNC_PTR(TestFenceNV, PFNGLTESTFENCENVPROC); +   GLuint fence; +   GLint fenceStatus, fenceCondition; +   int count; + +   /* Make sure we have all the function pointers we need. */ +   if (GenFencesNV == NULL || +      SetFenceNV == NULL || +      IsFenceNV == NULL || +      GetFenceivNV == NULL || +      TestFenceNV == NULL || +      FinishFenceNV == NULL || +      DeleteFencesNV == NULL) { +      fprintf(stderr, "%s: don't have all the fence functions\n", +         __FUNCTION__); +      return GL_FALSE; +   } + +   /* Create and set a simple fence. */ +   (*GenFencesNV)(1, &fence); +   (*SetFenceNV)(fence, GL_ALL_COMPLETED_NV); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Make sure it reads as a fence. */ +   if (!(*IsFenceNV)(fence)) { +      fprintf(stderr, "%s: set fence is not a fence\n", __FUNCTION__); +      (*DeleteFencesNV)(1, &fence); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Try to read back its current status and condition. */ +   (*GetFenceivNV)(fence, GL_FENCE_CONDITION_NV, &fenceCondition); +   if (fenceCondition != GL_ALL_COMPLETED_NV) { +      fprintf(stderr, "%s: expected fence condition 0x%x, got 0x%x\n", +         __FUNCTION__, GL_ALL_COMPLETED_NV, fenceCondition); +      (*DeleteFencesNV)(1, &fence); +      return GL_FALSE; +   } +   (*GetFenceivNV)(fence, GL_FENCE_STATUS_NV, &fenceStatus); +   if (fenceStatus != GL_TRUE && fenceStatus != GL_FALSE) { +      fprintf(stderr,"%s: fence status should be GL_TRUE or GL_FALSE, got 0x%x\n", +         __FUNCTION__, fenceStatus); +      (*DeleteFencesNV)(1, &fence); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Set the fence again, query its status, and wait for it to finish +    * two different ways: once by looping on TestFence(), and a  +    * second time by a simple call to FinishFence(); +    */ +   (*SetFenceNV)(fence, GL_ALL_COMPLETED_NV); +   glFlush(); +   count = 1; +   while (!(*TestFenceNV)(fence)) { +      count++; +      if (count == 0) { +         break; +      } +   } +   if (count == 0) { +      fprintf(stderr, "%s: fence never returned true\n", __FUNCTION__); +      (*DeleteFencesNV)(1, &fence); +      return GL_FALSE; +   } +   (*SetFenceNV)(fence, GL_ALL_COMPLETED_NV); +   (*FinishFenceNV)(fence); +   if ((*TestFenceNV)(fence) != GL_TRUE) { +      fprintf(stderr, "%s: finished fence does not have status GL_TRUE\n", +         __FUNCTION__); +      (*DeleteFencesNV)(1, &fence); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* All done.  Delete the fence and return. */ +   (*DeleteFencesNV)(1, &fence); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   return GL_TRUE; +} + +/************************************************************************** + * Exercises for buffer objects + */ +enum Map_Buffer_Usage{ Use_Map_Buffer, Use_Map_Buffer_Range}; +static GLboolean +exercise_buffer_objects(enum Map_Buffer_Usage usage) +{ +#define BUFFER_DATA_SIZE 1024 +   GLuint bufferID; +   GLint bufferMapped; +   static GLubyte data[BUFFER_DATA_SIZE] = {0}; +   float *dataPtr; + +   /* Get the function pointers we need.  These are from +    * GL_ARB_vertex_buffer_object and are required in all +    * cases. +    */ +   DECLARE_GLFUNC_PTR(GenBuffersARB, PFNGLGENBUFFERSARBPROC); +   DECLARE_GLFUNC_PTR(BindBufferARB, PFNGLBINDBUFFERARBPROC); +   DECLARE_GLFUNC_PTR(BufferDataARB, PFNGLBUFFERDATAARBPROC); +   DECLARE_GLFUNC_PTR(MapBufferARB, PFNGLMAPBUFFERARBPROC); +   DECLARE_GLFUNC_PTR(UnmapBufferARB, PFNGLUNMAPBUFFERARBPROC); +   DECLARE_GLFUNC_PTR(DeleteBuffersARB, PFNGLDELETEBUFFERSARBPROC); +   DECLARE_GLFUNC_PTR(GetBufferParameterivARB, PFNGLGETBUFFERPARAMETERIVARBPROC); + +   /* These are from GL_ARB_map_buffer_range, and are optional +    * unless we're given Use_Map_Buffer_Range.  Note that they do *not* +    * have the standard "ARB" suffixes; this is because the extension +    * was introduced *after* a superset was standardized in OpenGL 3.0. +    * (The extension really only exists to allow the functionality on +    * devices that cannot implement a full OpenGL 3.0 driver.) +    */ +   DECLARE_GLFUNC_PTR(FlushMappedBufferRange, PFNGLFLUSHMAPPEDBUFFERRANGEPROC); +   DECLARE_GLFUNC_PTR(MapBufferRange, PFNGLMAPBUFFERRANGEPROC); +    +   /* This is from APPLE_flush_buffer_range, and is optional even if +    * we're given Use_Map_Buffer_Range.  Test it before using it. +    */ +   DECLARE_GLFUNC_PTR(BufferParameteriAPPLE, PFNGLBUFFERPARAMETERIAPPLEPROC); + +   /* Make sure we have all the function pointers we need. */ +   if (GenBuffersARB == NULL || +      BindBufferARB == NULL || +      BufferDataARB == NULL || +      MapBufferARB == NULL || +      UnmapBufferARB == NULL || +      DeleteBuffersARB == NULL || +      GetBufferParameterivARB == NULL) { +      fprintf(stderr, "%s: missing basic MapBuffer functions\n", __FUNCTION__); +      return GL_FALSE; +   } +   if (usage == Use_Map_Buffer_Range) { +      if (FlushMappedBufferRange == NULL || MapBufferRange == NULL) { +         fprintf(stderr, "%s: missing MapBufferRange functions\n", __FUNCTION__); +         return GL_FALSE; +      } +   } + +   /* Create and define a buffer */ +   (*GenBuffersARB)(1, &bufferID); +   (*BindBufferARB)(GL_ARRAY_BUFFER_ARB, bufferID); +   (*BufferDataARB)(GL_ARRAY_BUFFER_ARB, BUFFER_DATA_SIZE, data,  +      GL_DYNAMIC_DRAW_ARB); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* If we're using MapBufferRange, and if the BufferParameteriAPPLE +    * function is present, use it before mapping.  This particular +    * use is a no-op, intended just to exercise the entry point. +    */ +   if (usage == Use_Map_Buffer_Range && BufferParameteriAPPLE != NULL) { +      (*BufferParameteriAPPLE)(GL_ARRAY_BUFFER_ARB,  +         GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE); +   } + +   /* Map it, and make sure it's mapped. */ +   switch(usage) { +      case Use_Map_Buffer: +         dataPtr = (float *) (*MapBufferARB)( +            GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +         break; +      case Use_Map_Buffer_Range: +         dataPtr = (float *)(*MapBufferRange)(GL_ARRAY_BUFFER_ARB, +            4, 16, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); +         break; +   } +   if (dataPtr == NULL) { +      fprintf(stderr, "%s: %s returned NULL\n", __FUNCTION__, +         usage == Use_Map_Buffer ? "MapBuffer" : "MapBufferRange"); +      (*BindBufferARB)(GL_ARRAY_BUFFER_ARB, 0); +      (*DeleteBuffersARB)(1, &bufferID); +      return GL_FALSE; +   } +   (*GetBufferParameterivARB)(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAPPED_ARB,  +      &bufferMapped); +   if (!bufferMapped) { +      fprintf(stderr, "%s: buffer should be mapped but isn't\n", __FUNCTION__); +      (*BindBufferARB)(GL_ARRAY_BUFFER_ARB, 0); +      (*DeleteBuffersARB)(1, &bufferID); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Write something to it, just to make sure we don't segfault. */ +   *dataPtr = 1.5; + +   /* Unmap to show we're finished with the buffer.  Note that if we're +    * using MapBufferRange, we first have to flush the range we modified. +    */ +   if (usage == Use_Map_Buffer_Range) { +      (*FlushMappedBufferRange)(GL_ARRAY_BUFFER_ARB, 4, 16); +   } +   if (!(*UnmapBufferARB)(GL_ARRAY_BUFFER_ARB)) { +      fprintf(stderr, "%s: UnmapBuffer failed\n", __FUNCTION__); +      (*BindBufferARB)(GL_ARRAY_BUFFER_ARB, 0); +      (*DeleteBuffersARB)(1, &bufferID); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* All done. */ +   (*BindBufferARB)(GL_ARRAY_BUFFER_ARB, 0); +   (*DeleteBuffersARB)(1, &bufferID); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); +   return GL_TRUE; + +#undef BUFFER_DATA_SIZE +} + +/************************************************************************** + * Exercises for occlusion query + */ +static GLboolean +exercise_occlusion_query(void) +{ +   GLuint queryObject; +   GLint queryReady; +   GLuint querySampleCount; +   GLint queryCurrent; +   GLint queryCounterBits; + +   /* Get the function pointers we need.  These are from +    * GL_ARB_vertex_buffer_object and are required in all +    * cases. +    */ +   DECLARE_GLFUNC_PTR(GenQueriesARB, PFNGLGENQUERIESARBPROC); +   DECLARE_GLFUNC_PTR(BeginQueryARB, PFNGLBEGINQUERYARBPROC); +   DECLARE_GLFUNC_PTR(GetQueryivARB, PFNGLGETQUERYIVARBPROC); +   DECLARE_GLFUNC_PTR(EndQueryARB, PFNGLENDQUERYARBPROC); +   DECLARE_GLFUNC_PTR(IsQueryARB, PFNGLISQUERYARBPROC); +   DECLARE_GLFUNC_PTR(GetQueryObjectivARB, PFNGLGETQUERYOBJECTIVARBPROC); +   DECLARE_GLFUNC_PTR(GetQueryObjectuivARB, PFNGLGETQUERYOBJECTUIVARBPROC); +   DECLARE_GLFUNC_PTR(DeleteQueriesARB, PFNGLDELETEQUERIESARBPROC); + +   /* Make sure we have all the function pointers we need. */ +   if (GenQueriesARB == NULL || +      BeginQueryARB == NULL || +      GetQueryivARB == NULL || +      EndQueryARB == NULL || +      IsQueryARB == NULL || +      GetQueryObjectivARB == NULL || +      GetQueryObjectuivARB == NULL || +      DeleteQueriesARB == NULL) { +      fprintf(stderr, "%s: don't have all the Query functions\n", __FUNCTION__); +      return GL_FALSE; +   } + +   /* Create a query object, and start a query. */ +   (*GenQueriesARB)(1, &queryObject); +   (*BeginQueryARB)(GL_SAMPLES_PASSED_ARB, queryObject); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* While we're in the query, check the functions that are supposed +    * to return which query we're in and how many bits of resolution +    * we get. +    */ +   (*GetQueryivARB)(GL_SAMPLES_PASSED_ARB, GL_CURRENT_QUERY_ARB, &queryCurrent); +   if (queryCurrent != queryObject) { +      fprintf(stderr, "%s: current query 0x%x != set query 0x%x\n", +         __FUNCTION__, queryCurrent, queryObject); +      (*EndQueryARB)(GL_SAMPLES_PASSED_ARB); +      (*DeleteQueriesARB)(1, &queryObject); +      return GL_FALSE; +   } +   (*GetQueryivARB)(GL_SAMPLES_PASSED_ARB, GL_QUERY_COUNTER_BITS_ARB,  +      &queryCounterBits); +   if (queryCounterBits < 1) { +      fprintf(stderr, "%s: query counter bits is too small (%d)\n", +         __FUNCTION__, queryCounterBits); +      (*EndQueryARB)(GL_SAMPLES_PASSED_ARB); +      (*DeleteQueriesARB)(1, &queryObject); +      return GL_FALSE; +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Finish up the query.  Since we didn't draw anything, the result +    * should be 0 passed samples. +    */ +   (*EndQueryARB)(GL_SAMPLES_PASSED_ARB); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Routine existence test */ +   if (!(*IsQueryARB)(queryObject)) { +      fprintf(stderr, "%s: query object 0x%x fails existence test\n", +         __FUNCTION__, queryObject); +      (*DeleteQueriesARB)(1, &queryObject); +      return GL_FALSE; +   } + +   /* Loop until the query is ready, then get back the result.  We use +    * the signed query for the boolean value of whether the result is +    * available, but the unsigned query to actually pull the result; +    * this is just to test both entrypoints, but in a real query you may +    * need the extra bit of resolution. +    */ +   queryReady = GL_FALSE; +   do { +      (*GetQueryObjectivARB)(queryObject, GL_QUERY_RESULT_AVAILABLE_ARB,  +         &queryReady); +   } while (!queryReady); +   (*GetQueryObjectuivARB)(queryObject, GL_QUERY_RESULT_ARB, &querySampleCount); +   (*DeleteQueriesARB)(1, &queryObject); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* If sample count isn't 0, something's funny. */ +   if (querySampleCount > 0) { +      fprintf(stderr, "%s: expected query result of 0, got %ud\n", +         __FUNCTION__, querySampleCount); +      return GL_FALSE; +   } + +   /* Here, all is well. */ +   return GL_TRUE; +} + +/**************************************************************************   * The following functions are used to check that the named OpenGL function   * actually does what it's supposed to do. - * The naming of these functions is signficant.  The getprocaddress.py script + * The naming of these functions is significant.  The getprocaddress.py script   * scans this file and extracts these function names.   */ +static GLboolean +test_WeightPointerARB(generic_func func) +{ +   /* Assume we have at least 2 vertex units (or this extension makes +    * no sense), and establish a set of 2-element vector weights. +    * We use floats that can be represented exactly in binary +    * floating point formats so we can compare correctly later. +    * We also make sure the 0th entry matches the default weights, +    * so we can restore the default easily. +    */ +#define USE_VERTEX_UNITS 2 +#define USE_WEIGHT_INDEX 3 +   static GLfloat weights[] = { +      1.0,   0.0, +      0.875, 0.125, +      0.75,  0.25, +      0.625, 0.375, +      0.5,   0.5, +      0.375, 0.625, +      0.25,  0.75, +      0.125, 0.875,  +      0.0,   1.0, +   }; +   GLint numVertexUnits; +   GLfloat *currentWeights; +   int i; +   int errorCount = 0; + +   PFNGLWEIGHTPOINTERARBPROC WeightPointerARB = (PFNGLWEIGHTPOINTERARBPROC) func; + +   /* Make sure we have at least two vertex units */ +   glGetIntegerv(GL_MAX_VERTEX_UNITS_ARB, &numVertexUnits); +   if (numVertexUnits < USE_VERTEX_UNITS) { +      fprintf(stderr, "%s: need %d vertex units, got %d\n",  +         __FUNCTION__, USE_VERTEX_UNITS, numVertexUnits); +      return GL_FALSE; +   } +    +   /* Make sure we allocate enough room to query all the current weights */ +   currentWeights = (GLfloat *)malloc(numVertexUnits * sizeof(GLfloat)); +   if (currentWeights == NULL) { +      fprintf(stderr, "%s: couldn't allocate room for %d floats\n", +         __FUNCTION__, numVertexUnits); +      return GL_FALSE; +   } + +   /* Set up the pointer, enable the state, and try to send down a +    * weight vector (we'll arbitrarily send index 2). +    */ +   (*WeightPointerARB)(USE_VERTEX_UNITS, GL_FLOAT, 0, weights); +   glEnableClientState(GL_WEIGHT_ARRAY_ARB); +   glArrayElement(USE_WEIGHT_INDEX); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Verify that it changed the current state. */ +   glGetFloatv(GL_CURRENT_WEIGHT_ARB, currentWeights); +   for (i = 0; i < numVertexUnits; i++) { +      if (i < USE_VERTEX_UNITS) { +         /* This is one of the units we explicitly set. */ +         if (currentWeights[i] != weights[USE_VERTEX_UNITS*USE_WEIGHT_INDEX + i]) { +            fprintf(stderr, "%s: current weight at index %d is %f, should be %f\n", +               __FUNCTION__, i, currentWeights[i],  +               weights[USE_VERTEX_UNITS*USE_WEIGHT_INDEX + i]); +            errorCount++; +         } +      } +      else { +         /* All other weights should be 0. */ +         if (currentWeights[i] != 0.0) { +            fprintf(stderr, "%s: current weight at index %d is %f, should be %f\n", +               __FUNCTION__, i, 0.0, +               weights[USE_VERTEX_UNITS*USE_WEIGHT_INDEX + i]); +            errorCount++; +         } +      } +   } +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Restore the old state.  We know the default set of weights is in +    * index 0. +    */ +   glArrayElement(0); +   glDisableClientState(GL_WEIGHT_ARRAY_ARB); +   (*WeightPointerARB)(0, GL_FLOAT, 0, NULL); +   free(currentWeights); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* We're fine if we didn't get any mismatches. */ +   if (errorCount == 0) { +      return GL_TRUE; +   } +   else { +      return GL_FALSE; +   } +} + +/* Wrappers on the exercise_occlusion_query function */ +static GLboolean +test_GenQueriesARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} +static GLboolean +test_BeginQueryARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} +static GLboolean +test_GetQueryivARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} +static GLboolean +test_EndQueryARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} +static GLboolean +test_IsQueryARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} +static GLboolean +test_GetQueryObjectivARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} +static GLboolean +test_GetQueryObjectuivARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} +static GLboolean +test_DeleteQueriesARB(generic_func func) +{ +   (void) func; +   return exercise_occlusion_query(); +} + +/* Wrappers on the exercise_buffer_objects() function */ +static GLboolean +test_GenBuffersARB(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer); +} +static GLboolean +test_BindBufferARB(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer); +} +static GLboolean +test_BufferDataARB(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer); +} +static GLboolean +test_MapBufferARB(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer); +} +static GLboolean +test_UnmapBufferARB(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer); +} +static GLboolean +test_DeleteBuffersARB(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer); +} +static GLboolean +test_GetBufferParameterivARB(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer); +} +static GLboolean +test_FlushMappedBufferRange(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer_Range); +} +static GLboolean +test_MapBufferRange(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer_Range); +} +static GLboolean +test_BufferParameteriAPPLE(generic_func func) +{ +   (void) func; +   return exercise_buffer_objects(Use_Map_Buffer_Range); +} + +/* Wrappers on the exercise_framebuffer() function */ +static GLboolean +test_BindFramebufferEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_BindRenderbufferEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_CheckFramebufferStatusEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_DeleteFramebuffersEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_DeleteRenderbuffersEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_FramebufferRenderbufferEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_GenFramebuffersEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_GenRenderbuffersEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_IsFramebufferEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_IsRenderbufferEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_RenderbufferStorageEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} +static GLboolean +test_BlitFramebufferEXT(generic_func func) +{ +   (void) func; +   return exercise_framebuffer(); +} + +/* These are wrappers on the exercise_CompressedTextures function.  + * Unfortunately, we cannot test the 1D counterparts, because the + * texture compressions available all support 2D and higher only. + */ +static GLboolean +test_CompressedTexImage2DARB(generic_func func) +{ +   (void) func; +   return exercise_CompressedTextures(GL_TEXTURE_2D); +} +static GLboolean +test_CompressedTexSubImage2DARB(generic_func func) +{ +   (void) func; +   return exercise_CompressedTextures(GL_TEXTURE_2D); +} +static GLboolean +test_CompressedTexImage3DARB(generic_func func) +{ +   (void) func; +   return exercise_CompressedTextures(GL_TEXTURE_3D); +} +static GLboolean +test_CompressedTexSubImage3DARB(generic_func func) +{ +   (void) func; +   return exercise_CompressedTextures(GL_TEXTURE_3D); +} +static GLboolean +test_GetCompressedTexImageARB(generic_func func) +{ +   (void) func; +   return exercise_CompressedTextures(GL_TEXTURE_3D); +} + +/* Wrappers on exercise_fences(). */ +static GLboolean +test_DeleteFencesNV(generic_func func) +{ +   (void) func; +   return exercise_fences(); +} +static GLboolean +test_GenFencesNV(generic_func func) +{ +   (void) func; +   return exercise_fences(); +} +static GLboolean +test_SetFenceNV(generic_func func) +{ +   (void) func; +   return exercise_fences(); +} +static GLboolean +test_TestFenceNV(generic_func func) +{ +   (void) func; +   return exercise_fences(); +} +static GLboolean +test_FinishFenceNV(generic_func func) +{ +   (void) func; +   return exercise_fences(); +} +static GLboolean +test_GetFenceivNV(generic_func func) +{ +   (void) func; +   return exercise_fences(); +} +static GLboolean +test_IsFenceNV(generic_func func) +{ +   (void) func; +   return exercise_fences(); +} + +/* A bunch of glUniform*() tests */ +static GLboolean +test_Uniform1iv(generic_func func) +{ +   PFNGLUNIFORM1IVARBPROC Uniform1ivARB = (PFNGLUNIFORM1IVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform int uniformColor;"  +      "void main() {gl_FragColor.r = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[1] = {1}; +   GLint queriedUniform[1]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * so we must set it using integer versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform1ivARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 1, uniform, 1, queriedUniform); +} + +static GLboolean +test_Uniform1i(generic_func func) +{ +   PFNGLUNIFORM1IARBPROC Uniform1iARB = (PFNGLUNIFORM1IARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform int uniformColor;" +      "void main() {gl_FragColor.r = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[1] = {1}; +   GLint queriedUniform[4]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * so we must set it using integer versions +    * of the Uniform* functions. +    */ +   (*Uniform1iARB)(uniformLocation, uniform[0]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 1, uniform, 1, queriedUniform); +} + +static GLboolean +test_Uniform1fv(generic_func func) +{ +   PFNGLUNIFORM1FVARBPROC Uniform1fvARB = (PFNGLUNIFORM1FVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform float uniformColor;" +      "void main() {gl_FragColor.r = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[1] = {1.1}; +   GLfloat queriedUniform[1]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is a float +    * so we must set it using float versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform1fvARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 1, uniform, 1, queriedUniform); +} + +static GLboolean +test_Uniform1f(generic_func func) +{ +   PFNGLUNIFORM1FARBPROC Uniform1fARB = (PFNGLUNIFORM1FARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform float uniformColor;" +      "void main() {gl_FragColor.r = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[1] = {1.1}; +   GLfloat queriedUniform[1]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is a float +    * so we must set it using float versions +    * of the Uniform* functions. +    */ +   (*Uniform1fARB)(uniformLocation, uniform[0]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 1, uniform, 1, queriedUniform); +} + +static GLboolean +test_Uniform2iv(generic_func func) +{ +   PFNGLUNIFORM2IVARBPROC Uniform2ivARB = (PFNGLUNIFORM2IVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform ivec2 uniformColor;"  +      "void main() {gl_FragColor.rg = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[2] = {1,2}; +   GLint queriedUniform[2]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * vector 2 (ivec2), so we must set it using integer versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform2ivARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 2, uniform, 2, queriedUniform); +} + +static GLboolean +test_Uniform2i(generic_func func) +{ +   PFNGLUNIFORM2IARBPROC Uniform2iARB = (PFNGLUNIFORM2IARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform ivec2 uniformColor;" +      "void main() {gl_FragColor.rg = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[2] = {1,2}; +   GLint queriedUniform[4]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * vector 2 (ivec2), so we must set it using integer versions +    * of the Uniform* functions. +    */ +   (*Uniform2iARB)(uniformLocation, uniform[0], uniform[1]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 2, uniform, 2, queriedUniform); +} + +static GLboolean +test_Uniform2fv(generic_func func) +{ +   PFNGLUNIFORM2FVARBPROC Uniform2fvARB = (PFNGLUNIFORM2FVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform vec2 uniformColor;" +      "void main() {gl_FragColor.rg = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[2] = {1.1,2.2}; +   GLfloat queriedUniform[2]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is a float +    * vector 2 (vec2), so we must set it using float versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform2fvARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 2, uniform, 2, queriedUniform); +} + +static GLboolean +test_Uniform2f(generic_func func) +{ +   PFNGLUNIFORM2FARBPROC Uniform2fARB = (PFNGLUNIFORM2FARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform vec2 uniformColor;" +      "void main() {gl_FragColor.rg = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[2] = {1.1,2.2}; +   GLfloat queriedUniform[2]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is a float +    * vector 2 (vec2), so we must set it using float versions +    * of the Uniform* functions. +    */ +   (*Uniform2fARB)(uniformLocation, uniform[0], uniform[1]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 2, uniform, 2, queriedUniform); +} + +static GLboolean +test_Uniform3iv(generic_func func) +{ +   PFNGLUNIFORM3IVARBPROC Uniform3ivARB = (PFNGLUNIFORM3IVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform ivec3 uniformColor;"  +      "void main() {gl_FragColor.rgb = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[3] = {1,2,3}; +   GLint queriedUniform[3]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * vector 3 (ivec3), so we must set it using integer versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform3ivARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 3, uniform, 3, queriedUniform); +} + +static GLboolean +test_Uniform3i(generic_func func) +{ +   PFNGLUNIFORM3IARBPROC Uniform3iARB = (PFNGLUNIFORM3IARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform ivec3 uniformColor;" +      "void main() {gl_FragColor.rgb = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[3] = {1,2,3}; +   GLint queriedUniform[4]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * vector 3 (ivec3), so we must set it using integer versions +    * of the Uniform* functions. +    */ +   (*Uniform3iARB)(uniformLocation, uniform[0], uniform[1], uniform[2]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 3, uniform, 3, queriedUniform); +} + +static GLboolean +test_Uniform3fv(generic_func func) +{ +   PFNGLUNIFORM3FVARBPROC Uniform3fvARB = (PFNGLUNIFORM3FVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform vec3 uniformColor;" +      "void main() {gl_FragColor.rgb = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[3] = {1.1,2.2,3.3}; +   GLfloat queriedUniform[3]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is a float +    * vector 3 (vec3), so we must set it using float versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform3fvARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 3, uniform, 3, queriedUniform); +} + +static GLboolean +test_Uniform3f(generic_func func) +{ +   PFNGLUNIFORM3FARBPROC Uniform3fARB = (PFNGLUNIFORM3FARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform vec3 uniformColor;" +      "void main() {gl_FragColor.rgb = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[3] = {1.1,2.2,3.3}; +   GLfloat queriedUniform[3]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is a float +    * vector 3 (vec3), so we must set it using float versions +    * of the Uniform* functions. +    */ +   (*Uniform3fARB)(uniformLocation, uniform[0], uniform[1], uniform[2]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 3, uniform, 3, queriedUniform); +} + +static GLboolean +test_Uniform4iv(generic_func func) +{ +   PFNGLUNIFORM4IVARBPROC Uniform4ivARB = (PFNGLUNIFORM4IVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform ivec4 uniformColor; void main() {gl_FragColor = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[4] = {1,2,3,4}; +   GLint queriedUniform[4]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * vector (ivec4), so we must set it using integer versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform4ivARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 4, uniform, 4, queriedUniform); +} + +static GLboolean +test_Uniform4i(generic_func func) +{ +   PFNGLUNIFORM4IARBPROC Uniform4iARB = (PFNGLUNIFORM4IARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformivARB, PFNGLGETUNIFORMIVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform ivec4 uniformColor; void main() {gl_FragColor = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLint uniform[4] = {1,2,3,4}; +   GLint queriedUniform[4]; + +   if (GetUniformivARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * vector (ivec4), so we must set it using integer versions +    * of the Uniform* functions. +    */ +   (*Uniform4iARB)(uniformLocation, uniform[0], uniform[1], uniform[2], +      uniform[3]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformivARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_ints(__FUNCTION__, 4, uniform, 4, queriedUniform); +} + +static GLboolean +test_Uniform4fv(generic_func func) +{ +   PFNGLUNIFORM4FVARBPROC Uniform4fvARB = (PFNGLUNIFORM4FVARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform vec4 uniformColor; void main() {gl_FragColor = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[4] = {1.1,2.2,3.3,4.4}; +   GLfloat queriedUniform[4]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is a float +    * vector (vec4), so we must set it using float versions +    * of the Uniform* functions.  The "1" means we're setting +    * one vector's worth of information. +    */ +   (*Uniform4fvARB)(uniformLocation, 1, uniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 4, uniform, 4, queriedUniform); +} + +static GLboolean +test_Uniform4f(generic_func func) +{ +   PFNGLUNIFORM4FARBPROC Uniform4fARB = (PFNGLUNIFORM4FARBPROC) func; +   DECLARE_GLFUNC_PTR(GetUniformfvARB, PFNGLGETUNIFORMFVARBPROC); + +   /* This is a trivial fragment shader that sets the color of the +    * fragment to the uniform value passed in. +    */ +   static const char *fragmentShaderText =  +      "uniform vec4 uniformColor; void main() {gl_FragColor = uniformColor;}"; +   static const char *uniformName = "uniformColor"; + +   GLhandleARB program; +   GLint uniformLocation; +   const GLfloat uniform[4] = {1.1,2.2,3.3,4.4}; +   GLfloat queriedUniform[4]; + +   if (GetUniformfvARB == NULL) { +      return GL_FALSE; +   } + +   /* Call a helper function to compile up the shader and give +    * us back the validated program and uniform location. +    * If it fails, something's wrong and we can't continue. +    */ +   if (!exercise_uniform_start(fragmentShaderText, uniformName,  +      &program, &uniformLocation)) { +      return GL_FALSE; +   } + +   /* Set the value of the program uniform.  Note that you must +    * use a compatible type.  Our uniform above is an integer +    * vector (ivec4), so we must set it using integer versions +    * of the Uniform* functions. +    */ +   (*Uniform4fARB)(uniformLocation, uniform[0], uniform[1], uniform[2], +      uniform[3]); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Query it back */ +   (*GetUniformfvARB)(program, uniformLocation, queriedUniform); +   CheckGLError(__LINE__, __FILE__, __FUNCTION__); + +   /* Clean up before we check to see whether it came back unscathed */ +   exercise_uniform_end(program); + +   /* Now check to see whether the uniform came back as expected.  This +    * will return GL_TRUE if all is well, or GL_FALSE if the comparison failed. +    */ +   return compare_floats(__FUNCTION__, 4, uniform, 4, queriedUniform); +}  static GLboolean  test_ActiveTextureARB(generic_func func) @@ -107,6 +2694,40 @@ test_VertexAttrib1fvARB(generic_func func)  }  static GLboolean +test_VertexAttrib1dvARB(generic_func func) +{ +   PFNGLVERTEXATTRIB1DVARBPROC vertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) func; +   PFNGLGETVERTEXATTRIBDVARBPROC getVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvARB"); + +   const GLdouble v[1] = {25.0}; +   const GLdouble def[1] = {0}; +   GLdouble res[4]; +   GLboolean pass; +   (*vertexAttrib1dvARB)(6, v); +   (*getVertexAttribdvARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res); +   pass = (res[0] == 25.0 && res[1] == 0.0 && res[2] == 0.0 && res[3] == 1.0); +   (*vertexAttrib1dvARB)(6, def); +   return pass; +} + +static GLboolean +test_VertexAttrib1svARB(generic_func func) +{ +   PFNGLVERTEXATTRIB1SVARBPROC vertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) func; +   PFNGLGETVERTEXATTRIBIVARBPROC getVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivARB"); + +   const GLshort v[1] = {25.0}; +   const GLshort def[1] = {0}; +   GLint res[4]; +   GLboolean pass; +   (*vertexAttrib1svARB)(6, v); +   (*getVertexAttribivARB)(6, GL_CURRENT_VERTEX_ATTRIB_ARB, res); +   pass = (res[0] == 25 && res[1] == 0 && res[2] == 0 && res[3] == 1); +   (*vertexAttrib1svARB)(6, def); +   return pass; +} + +static GLboolean  test_VertexAttrib4NubvARB(generic_func func)  {     PFNGLVERTEXATTRIB4NUBVARBPROC vertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) func; @@ -177,7 +2798,6 @@ test_VertexAttrib4NsvARB(generic_func func)     return pass;  } -  static GLboolean  test_VertexAttrib4NusvARB(generic_func func)  { @@ -195,42 +2815,110 @@ test_VertexAttrib4NusvARB(generic_func func)     return pass;  } +static GLboolean +test_VertexAttrib1sNV(generic_func func) +{ +   PFNGLVERTEXATTRIB1SNVPROC vertexAttrib1sNV = (PFNGLVERTEXATTRIB1SNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 0, 0, 1}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttrib1sNV)(6, v[0]); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib1sNV)(6, def[0]); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +}  static GLboolean -test_VertexAttrib4ubNV(generic_func func) +test_VertexAttrib1fNV(generic_func func)  { -   PFNGLVERTEXATTRIB4UBNVPROC vertexAttrib4ubNV = (PFNGLVERTEXATTRIB4UBNVPROC) func; +   PFNGLVERTEXATTRIB1FNVPROC vertexAttrib1fNV = (PFNGLVERTEXATTRIB1FNVPROC) func;     PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); -   const GLubyte v[4] = {255, 0, 255, 0}; -   const GLubyte def[4] = {0, 0, 0, 255}; +   const GLfloat v[4] = {2.5, 0.0, 0.0, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1};     GLfloat res[4]; -   GLboolean pass; -   (*vertexAttrib4ubNV)(6, v[0], v[1], v[2], v[3]); +   (*vertexAttrib1fNV)(6, v[0]);     (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); -   pass = (res[0] == 1.0 && res[1] == 0.0 && res[2] == 1.0 && res[3] == 0.0); -   (*vertexAttrib4ubNV)(6, def[0], def[1], def[2], def[3]); -   return pass; +   (*vertexAttrib1fNV)(6, def[0]); +   return compare_floats(__FUNCTION__, 4, v, 4, res);  } +static GLboolean +test_VertexAttrib1dNV(generic_func func) +{ +   PFNGLVERTEXATTRIB1DNVPROC vertexAttrib1dNV = (PFNGLVERTEXATTRIB1DNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 0.0, 0.0, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib1dNV)(6, v[0]); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib1dNV)(6, def[0]); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +}  static GLboolean  test_VertexAttrib2sNV(generic_func func)  {     PFNGLVERTEXATTRIB2SNVPROC vertexAttrib2sNV = (PFNGLVERTEXATTRIB2SNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 0, 1}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttrib2sNV)(6, v[0], v[1]); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib2sNV)(6, def[0], def[1]); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib2fNV(generic_func func) +{ +   PFNGLVERTEXATTRIB2FNVPROC vertexAttrib2fNV = (PFNGLVERTEXATTRIB2FNVPROC) func;     PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); -   const GLshort v[2] = {2, -4,}; -   const GLshort def[2] = {0, 0}; +   const GLfloat v[4] = {2.5, 4.25, 0.0, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1};     GLfloat res[4]; -   GLboolean pass; -   (*vertexAttrib2sNV)(6, v[0], v[1]); +   (*vertexAttrib2fNV)(6, v[0], v[1]);     (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); -   pass = (EQUAL(res[0], 2) && EQUAL(res[1], -4) && EQUAL(res[2], 0) && res[3] == 1.0); -   (*vertexAttrib2sNV)(6, def[0], def[1]); -   return pass; +   (*vertexAttrib2fNV)(6, def[0], def[1]); +   return compare_floats(__FUNCTION__, 4, v, 4, res);  } +static GLboolean +test_VertexAttrib2dNV(generic_func func) +{ +   PFNGLVERTEXATTRIB2DNVPROC vertexAttrib2dNV = (PFNGLVERTEXATTRIB2DNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 0.0, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib2dNV)(6, v[0], v[1]); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib2dNV)(6, def[0], def[1]); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib3sNV(generic_func func) +{ +   PFNGLVERTEXATTRIB3SNVPROC vertexAttrib3sNV = (PFNGLVERTEXATTRIB3SNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 7, 1}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttrib3sNV)(6, v[0], v[1], v[2]); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib3sNV)(6, def[0], def[1], def[2]); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +}  static GLboolean  test_VertexAttrib3fNV(generic_func func) @@ -238,35 +2926,467 @@ test_VertexAttrib3fNV(generic_func func)     PFNGLVERTEXATTRIB3FNVPROC vertexAttrib3fNV = (PFNGLVERTEXATTRIB3FNVPROC) func;     PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); -   const GLfloat v[3] = {0.2, 0.4, 0.8}; -   const GLfloat def[3] = {0, 0, 0}; +   const GLfloat v[4] = {2.5, 4.25, 7.125, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1};     GLfloat res[4]; -   GLboolean pass;     (*vertexAttrib3fNV)(6, v[0], v[1], v[2]);     (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); -   pass = (EQUAL(res[0], 0.2) && EQUAL(res[1], 0.4) && EQUAL(res[2], 0.8) && res[3] == 1.0);     (*vertexAttrib3fNV)(6, def[0], def[1], def[2]); -   return pass; +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib3dNV(generic_func func) +{ +   PFNGLVERTEXATTRIB3DNVPROC vertexAttrib3dNV = (PFNGLVERTEXATTRIB3DNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 7.125, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib3dNV)(6, v[0], v[1], v[2]); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib3dNV)(6, def[0], def[1], def[2]); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib4sNV(generic_func func) +{ +   PFNGLVERTEXATTRIB4SNVPROC vertexAttrib4sNV = (PFNGLVERTEXATTRIB4SNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 7, 5}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttrib4sNV)(6, v[0], v[1], v[2], v[3]); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4sNV)(6, def[0], def[1], def[2], def[3]); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib4fNV(generic_func func) +{ +   PFNGLVERTEXATTRIB4FNVPROC vertexAttrib4fNV = (PFNGLVERTEXATTRIB4FNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 4.25, 7.125, 5.0625}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttrib4fNV)(6, v[0], v[1], v[2], v[3]); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4fNV)(6, def[0], def[1], def[2], def[3]); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib4dNV(generic_func func) +{ +   PFNGLVERTEXATTRIB4DNVPROC vertexAttrib4dNV = (PFNGLVERTEXATTRIB4DNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 7.125, 5.0625}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib4dNV)(6, v[0], v[1], v[2], v[3]); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4dNV)(6, def[0], def[1], def[2], def[3]); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib4ubNV(generic_func func) +{ +   PFNGLVERTEXATTRIB4UBNVPROC vertexAttrib4ubNV = (PFNGLVERTEXATTRIB4UBNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLubyte v[4] = {255, 0, 255, 0}; +   const GLubyte def[4] = {0, 0, 0, 255}; +   GLfloat res[4]; +   /* There's no byte-value query; so we use the float-value query. +    * Bytes are interpreted as steps between 0 and 1, so the +    * expected float values will be 0.0 for byte value 0 and 1.0 for +    * byte value 255. +    */ +   GLfloat expectedResults[4] = {1.0, 0.0, 1.0, 0.0}; +   (*vertexAttrib4ubNV)(6, v[0], v[1], v[2], v[3]); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4ubNV)(6, def[0], def[1], def[2], def[3]); +   return compare_floats(__FUNCTION__, 4, expectedResults, 4, res); +} + +static GLboolean +test_VertexAttrib1fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB1FVNVPROC vertexAttrib1fvNV = (PFNGLVERTEXATTRIB1FVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 0.0, 0.0, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttrib1fvNV)(6, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib1fvNV)(6, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib1dvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB1DVNVPROC vertexAttrib1dvNV = (PFNGLVERTEXATTRIB1DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 0.0, 0.0, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib1dvNV)(6, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib1dvNV)(6, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib2svNV(generic_func func) +{ +   PFNGLVERTEXATTRIB2SVNVPROC vertexAttrib2svNV = (PFNGLVERTEXATTRIB2SVNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 0, 1}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttrib2svNV)(6, v); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib2svNV)(6, def); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib2fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB2FVNVPROC vertexAttrib2fvNV = (PFNGLVERTEXATTRIB2FVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 4.25, 0.0, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttrib2fvNV)(6, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib2fvNV)(6, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib2dvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB2DVNVPROC vertexAttrib2dvNV = (PFNGLVERTEXATTRIB2DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 0.0, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib2dvNV)(6, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib2dvNV)(6, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res);  } +static GLboolean +test_VertexAttrib3svNV(generic_func func) +{ +   PFNGLVERTEXATTRIB3SVNVPROC vertexAttrib3svNV = (PFNGLVERTEXATTRIB3SVNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 7, 1}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttrib3svNV)(6, v); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib3svNV)(6, def); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib3fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB3FVNVPROC vertexAttrib3fvNV = (PFNGLVERTEXATTRIB3FVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 4.25, 7.125, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttrib3fvNV)(6, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib3fvNV)(6, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib3dvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB3DVNVPROC vertexAttrib3dvNV = (PFNGLVERTEXATTRIB3DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 7.125, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib3dvNV)(6, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib3dvNV)(6, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib4svNV(generic_func func) +{ +   PFNGLVERTEXATTRIB4SVNVPROC vertexAttrib4svNV = (PFNGLVERTEXATTRIB4SVNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 7, 5}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttrib4svNV)(6, v); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4svNV)(6, def); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib4fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB4FVNVPROC vertexAttrib4fvNV = (PFNGLVERTEXATTRIB4FVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 4.25, 7.125, 5.0625}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttrib4fvNV)(6, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4fvNV)(6, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +}  static GLboolean  test_VertexAttrib4dvNV(generic_func func)  {     PFNGLVERTEXATTRIB4DVNVPROC vertexAttrib4dvNV = (PFNGLVERTEXATTRIB4DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 7.125, 5.0625}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttrib4dvNV)(6, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4dvNV)(6, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttrib4ubvNV(generic_func func) +{ +   PFNGLVERTEXATTRIB4UBVNVPROC vertexAttrib4ubvNV = (PFNGLVERTEXATTRIB4UBVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLubyte v[4] = {255, 0, 255, 0}; +   const GLubyte def[4] = {0, 0, 0, 255}; +   GLfloat res[4]; +   /* There's no byte-value query; so we use the float-value query. +    * Bytes are interpreted as steps between 0 and 1, so the +    * expected float values will be 0.0 for byte value 0 and 1.0 for +    * byte value 255. +    */ +   GLfloat expectedResults[4] = {1.0, 0.0, 1.0, 0.0}; +   (*vertexAttrib4ubvNV)(6, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttrib4ubvNV)(6, def); +   return compare_floats(__FUNCTION__, 4, expectedResults, 4, res); +} + +static GLboolean +test_VertexAttribs1fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS1FVNVPROC vertexAttribs1fvNV = (PFNGLVERTEXATTRIBS1FVNVPROC) func;     PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); -   const GLdouble v[4] = {0.2, 0.4, 0.8, 1.2}; +   const GLfloat v[4] = {2.5, 0.0, 0.0, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttribs1fvNV)(6, 1, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs1fvNV)(6, 1, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs1dvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS1DVNVPROC vertexAttribs1dvNV = (PFNGLVERTEXATTRIBS1DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 0.0, 0.0, 1.0};     const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttribs1dvNV)(6, 1, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs1dvNV)(6, 1, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs2svNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS2SVNVPROC vertexAttribs2svNV = (PFNGLVERTEXATTRIBS2SVNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 0, 1}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttribs2svNV)(6, 1, v); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs2svNV)(6, 1, def); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs2fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS2FVNVPROC vertexAttribs2fvNV = (PFNGLVERTEXATTRIBS2FVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 4.25, 0.0, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1};     GLfloat res[4]; -   GLboolean pass; -   (*vertexAttrib4dvNV)(6, v); +   (*vertexAttribs2fvNV)(6, 1, v);     (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); -   pass = (EQUAL(res[0], 0.2) && EQUAL(res[1], 0.4) && EQUAL(res[2], 0.8) && EQUAL(res[3], 1.2)); -   (*vertexAttrib4dvNV)(6, def); -   return pass; +   (*vertexAttribs2fvNV)(6, 1, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res);  } +static GLboolean +test_VertexAttribs2dvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS2DVNVPROC vertexAttribs2dvNV = (PFNGLVERTEXATTRIBS2DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 0.0, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttribs2dvNV)(6, 1, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs2dvNV)(6, 1, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs3svNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS3SVNVPROC vertexAttribs3svNV = (PFNGLVERTEXATTRIBS3SVNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 7, 1}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttribs3svNV)(6, 1, v); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs3svNV)(6, 1, def); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs3fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS3FVNVPROC vertexAttribs3fvNV = (PFNGLVERTEXATTRIBS3FVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 4.25, 7.125, 1.0}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttribs3fvNV)(6, 1, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs3fvNV)(6, 1, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs3dvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS3DVNVPROC vertexAttribs3dvNV = (PFNGLVERTEXATTRIBS3DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 7.125, 1.0}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttribs3dvNV)(6, 1, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs3dvNV)(6, 1, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs4svNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS4SVNVPROC vertexAttribs4svNV = (PFNGLVERTEXATTRIBS4SVNVPROC) func; +   PFNGLGETVERTEXATTRIBIVNVPROC getVertexAttribivNV = (PFNGLGETVERTEXATTRIBIVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribivNV"); + +   const GLshort v[4] = {2, 4, 7, 5}; +   const GLshort def[4] = {0, 0, 0, 1}; +   GLint res[4]; +   (*vertexAttribs4svNV)(6, 1, v); +   (*getVertexAttribivNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs4svNV)(6, 1, def); +   return compare_shorts_to_ints(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs4fvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS4FVNVPROC vertexAttribs4fvNV = (PFNGLVERTEXATTRIBS4FVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLfloat v[4] = {2.5, 4.25, 7.125, 5.0625}; +   const GLfloat def[4] = {0, 0, 0, 1}; +   GLfloat res[4]; +   (*vertexAttribs4fvNV)(6, 1, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs4fvNV)(6, 1, def); +   return compare_floats(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs4dvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS4DVNVPROC vertexAttribs4dvNV = (PFNGLVERTEXATTRIBS4DVNVPROC) func; +   PFNGLGETVERTEXATTRIBDVNVPROC getVertexAttribdvNV = (PFNGLGETVERTEXATTRIBDVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribdvNV"); + +   const GLdouble v[4] = {2.5, 4.25, 7.125, 5.0625}; +   const GLdouble def[4] = {0, 0, 0, 1}; +   GLdouble res[4]; +   (*vertexAttribs4dvNV)(6, 1, v); +   (*getVertexAttribdvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs4dvNV)(6, 1, def); +   return compare_doubles(__FUNCTION__, 4, v, 4, res); +} + +static GLboolean +test_VertexAttribs4ubvNV(generic_func func) +{ +   PFNGLVERTEXATTRIBS4UBVNVPROC vertexAttribs4ubvNV = (PFNGLVERTEXATTRIBS4UBVNVPROC) func; +   PFNGLGETVERTEXATTRIBFVNVPROC getVertexAttribfvNV = (PFNGLGETVERTEXATTRIBFVNVPROC) glXGetProcAddressARB((const GLubyte *) "glGetVertexAttribfvNV"); + +   const GLubyte v[4] = {255, 0, 255, 0}; +   const GLubyte def[4] = {0, 0, 0, 255}; +   GLfloat res[4]; +   /* There's no byte-value query; so we use the float-value query. +    * Bytes are interpreted as steps between 0 and 1, so the +    * expected float values will be 0.0 for byte value 0 and 1.0 for +    * byte value 255. +    */ +   GLfloat expectedResults[4] = {1.0, 0.0, 1.0, 0.0}; +   (*vertexAttribs4ubvNV)(6, 1, v); +   (*getVertexAttribfvNV)(6, GL_CURRENT_ATTRIB_NV, res); +   (*vertexAttribs4ubvNV)(6, 1, def); +   return compare_floats(__FUNCTION__, 4, expectedResults, 4, res); +}  static GLboolean  test_StencilFuncSeparateATI(generic_func func) @@ -387,17 +3507,32 @@ extension_supported(const char *haystack, const char *needle)  } -static void +/* Run all the known extension function tests, if the extension is supported. + * Return a count of how many failed. + */ +static int  check_functions( const char *extensions )  {     struct name_test_pair *entry; -   int failures = 0, passes = 0; -   int totalFail = 0, totalPass = 0; +   int failures = 0, passes = 0, untested = 0; +   int totalFail = 0, totalPass = 0, totalUntested = 0, totalUnsupported = 0;     int doTests; +   const char *version = (const char *) glGetString(GL_VERSION); +   /* The functions list will have "real" entries (consisting of +    * a GL function name and a pointer to an exercise function for +    * that GL function), and "group" entries (indicated as +    * such by having a "-" as the first character of the name). +    * "Group" names always start with the "-" character, and can +    * be numeric (e.g. "-1.0", "-2.1"), indicating that a particular +    * OpenGL version is required for the following functions; or can be +    * an extension name (e.g. "-GL_ARB_multitexture") that means +    * that the named extension is required for the following functions. +    */     for (entry = functions; entry->name; entry++) { +      /* Check if this is a group indicator */        if (entry->name[0] == '-') { -         const char *version = (const char *) glGetString(GL_VERSION); +         /* A group indicator; check if it's an OpenGL version group */           if (entry->name[1] == '1') {              /* check GL version 1.x */              if (version[0] == '1' && @@ -419,14 +3554,27 @@ check_functions( const char *extensions )              /* check if the named extension is available */              doTests = extension_supported(extensions, entry->name+1);           } + +         /* doTests is now set if we're starting an OpenGL version +          * group, and the running OpenGL version is at least the +          * version required; or if we're starting an OpenGL extension +          * group, and the extension is supported. +          */           if (doTests)              printf("Testing %s functions\n", entry->name + 1); -         totalFail += failures; -         totalPass += passes; + +         /* Each time we hit a title function, reset the function +          * counts. +          */           failures = 0;           passes = 0; +         untested = 0;        }        else if (doTests) { +         /* Here, we know we're trying to exercise a function for +          * a supported extension.  See whether we have a test for +          * it, and try to run it. +          */           generic_func funcPtr = (generic_func) glXGetProcAddressARB((const GLubyte *) entry->name);           if (funcPtr) {              if (entry->test) { @@ -436,21 +3584,36 @@ check_functions( const char *extensions )                 if (b) {                    printf(" Pass\n");                    passes++; +                  totalPass++;                 }                 else {                    printf(" FAIL!!!\n");                    failures++; +                  totalFail++;                 }              }              else { -               passes++; +               untested++; +               totalUntested++;              }           }           else {              printf("   glXGetProcAddress(%s) failed!\n", entry->name);              failures++; +            totalFail++;           }        } +      else { +         /* Here, we have a function that belongs to a group that +          * is known to be unsupported. +          */ +         totalUnsupported++; +      } + +      /* Make sure a poor test case doesn't leave any lingering +       * OpenGL errors. +       */ +      CheckGLError(__LINE__, __FILE__, __FUNCTION__);        if (doTests && (!(entry+1)->name || (entry+1)->name[0] == '-')) {           if (failures > 0) { @@ -459,18 +3622,29 @@ check_functions( const char *extensions )           if (passes > 0) {              printf("   %d passed.\n", passes);           } +         if (untested > 0) { +            printf("   %d untested.\n", untested); +         }        }     } -   totalFail += failures; -   totalPass += passes;     printf("-----------------------------\n"); -   printf("Total: %d pass  %d fail\n", totalPass, totalFail); +   printf("Total: %d pass  %d fail  %d untested  %d unsupported  %d total\n",  +      totalPass, totalFail, totalUntested, totalUnsupported, +      totalPass + totalFail + totalUntested + totalUnsupported); + +   return totalFail;  } +/* Return an error code */ +#define ERROR_NONE 0 +#define ERROR_NO_VISUAL 1 +#define ERROR_NO_CONTEXT 2 +#define ERROR_NO_MAKECURRENT 3 +#define ERROR_FAILED 4 -static void +static int  print_screen_info(Display *dpy, int scrnum, Bool allowDirect)  {     Window win; @@ -496,6 +3670,7 @@ print_screen_info(Display *dpy, int scrnum, Bool allowDirect)     GLXContext ctx;     XVisualInfo *visinfo;     int width = 100, height = 100; +   int failures;     root = RootWindow(dpy, scrnum); @@ -504,7 +3679,7 @@ print_screen_info(Display *dpy, int scrnum, Bool allowDirect)        visinfo = glXChooseVisual(dpy, scrnum, attribDouble);        if (!visinfo) {           fprintf(stderr, "Error: couldn't find RGB GLX visual\n"); -         return; +         return ERROR_NO_VISUAL;        }     } @@ -521,26 +3696,29 @@ print_screen_info(Display *dpy, int scrnum, Bool allowDirect)     if (!ctx) {        fprintf(stderr, "Error: glXCreateContext failed\n");        XDestroyWindow(dpy, win); -      return; +      return ERROR_NO_CONTEXT;     } -   if (glXMakeCurrent(dpy, win, ctx)) { -      check_functions( (const char *) glGetString(GL_EXTENSIONS) ); -   } -   else { +   if (!glXMakeCurrent(dpy, win, ctx)) {        fprintf(stderr, "Error: glXMakeCurrent failed\n"); +      glXDestroyContext(dpy, ctx); +      XDestroyWindow(dpy, win); +      return ERROR_NO_MAKECURRENT;     } +   failures = check_functions( (const char *) glGetString(GL_EXTENSIONS) );     glXDestroyContext(dpy, ctx);     XDestroyWindow(dpy, win); -} +   return (failures == 0 ? ERROR_NONE : ERROR_FAILED); +}  int  main(int argc, char *argv[])  {     char *displayName = NULL;     Display *dpy; +   int returnCode;     dpy = XOpenDisplay(displayName);     if (!dpy) { @@ -548,9 +3726,9 @@ main(int argc, char *argv[])        return -1;     } -   print_screen_info(dpy, 0, GL_TRUE); +   returnCode = print_screen_info(dpy, 0, GL_TRUE);     XCloseDisplay(dpy); -   return 0; +   return returnCode;  } diff --git a/progs/tests/getprocaddress.py b/progs/tests/getprocaddress.py index 8adfc51bd6..699195bd48 100644 --- a/progs/tests/getprocaddress.py +++ b/progs/tests/getprocaddress.py @@ -52,7 +52,7 @@ static struct name_test_pair functions[] = {"""  		prev_category = None -		for f in api.functionIterateByOffset(): +		for f in api.functionIterateByCategory():  			[category, num] = api.get_category_for_name( f.name )  			if category != prev_category:  				print '   { "-%s", NULL},' % category diff --git a/progs/tests/getteximage.c b/progs/tests/getteximage.c index e4818a8fab..71f29b4ac8 100644 --- a/progs/tests/getteximage.c +++ b/progs/tests/getteximage.c @@ -15,7 +15,7 @@ static int Win;  static void -TestGetTexImage(void) +TestGetTexImage(GLboolean npot)  {     GLuint iter;     GLubyte *data = (GLubyte *) malloc(1024 * 1024 * 4); @@ -27,8 +27,8 @@ TestGetTexImage(void)     for (iter = 0; iter < 8; iter++) {        GLint p = (iter % 8) + 3; -      GLint w = (1 << p); -      GLint h = (1 << p); +      GLint w = npot ? (p * 20) : (1 << p); +      GLint h = npot ? (p * 10) : (1 << p);        GLuint i;        GLint level = 0; @@ -83,63 +83,94 @@ ColorsEqual(const GLubyte ref[4], const GLubyte act[4])  static void -TestGetTexImageRTT(void) +TestGetTexImageRTT(GLboolean npot)  {     GLuint iter; -   GLuint fb, tex; -   GLint w = 512; -   GLint h = 256; -   GLint level = 0; -    -   glGenTextures(1, &tex); -   glGenFramebuffersEXT(1, &fb); - -   glBindTexture(GL_TEXTURE_2D, tex); -   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, -                GL_RGBA, GL_UNSIGNED_BYTE, NULL); - -   glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb); -   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, -                             GL_TEXTURE_2D, tex, level);     printf("Render to texture + glGetTexImage:\n"); -   printf("  Testing %d x %d tex image\n", w, h); +     for (iter = 0; iter < 8; iter++) { -      GLubyte color[4]; -      GLubyte *data2 = (GLubyte *) malloc(w * h * 4); -      GLuint i; -      /* random clear color */ -      for (i = 0; i < 4; i++) { -         color[i] = rand() % 256; +      GLuint fb, tex; +      GLint w, h; +      GLint level = 0; + +      if (npot) { +         w = 200 + iter * 40; +         h = 200 + iter * 12; +      } +      else { +         w = 4 << iter; +         h = 4 << iter;        } -      glClearColor(color[0] / 255.0, -                   color[1] / 255.0, -                   color[2] / 255.0, -                   color[3] / 255.0); +      glGenTextures(1, &tex); +      glGenFramebuffersEXT(1, &fb); -      glClear(GL_COLOR_BUFFER_BIT); +      glBindTexture(GL_TEXTURE_2D, tex); +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, +                   GL_RGBA, GL_UNSIGNED_BYTE, NULL); -      /* get */ -      glGetTexImage(GL_TEXTURE_2D, level, GL_RGBA, GL_UNSIGNED_BYTE, data2); +      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); +      glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, +                                GL_TEXTURE_2D, tex, level); -      /* compare */ -      for (i = 0; i < w * h; i += 4) { -         if (!ColorsEqual(color, data2 + i * 4)) { -            printf("Render to texture failure!\n"); -            abort(); +      glViewport(0, 0, w, h); + +      printf("  Testing %d x %d tex image\n", w, h); +      { +         static const GLubyte blue[4] = {0, 0, 255, 255}; +         GLubyte color[4]; +         GLubyte *data2 = (GLubyte *) malloc(w * h * 4); +         GLuint i; + +         /* random clear color */ +         for (i = 0; i < 4; i++) { +            color[i] = rand() % 256; +         } + +         glClearColor(color[0] / 255.0, +                      color[1] / 255.0, +                      color[2] / 255.0, +                      color[3] / 255.0); + +         glClear(GL_COLOR_BUFFER_BIT); + +         /* draw polygon over top half, in blue */ +         glColor4ubv(blue); +         glRectf(0, 0.5, 1.0, 1.0); + +         /* get */ +         glGetTexImage(GL_TEXTURE_2D, level, GL_RGBA, GL_UNSIGNED_BYTE, data2); + +         /* compare */ +         for (i = 0; i < w * h; i += 4) { +            if (i < w * h / 2) { +               /* lower half */ +               if (!ColorsEqual(color, data2 + i * 4)) { +                  printf("Render to texture failure (expected clear color)!\n"); +                  abort(); +               } +            } +            else { +               /* upper half */ +               if (!ColorsEqual(blue, data2 + i * 4)) { +                  printf("Render to texture failure (expected blue)!\n"); +                  abort(); +               } +            }           } + +         free(data2);        } -      free(data2); -   } +      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +      glDeleteFramebuffersEXT(1, &fb); +      glDeleteTextures(1, &tex); -   glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); -   glDeleteFramebuffersEXT(1, &fb); -   glDeleteTextures(1, &tex); +   }     printf("Passed\n");  } @@ -152,11 +183,16 @@ Draw(void)  {     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -   TestGetTexImage(); +   TestGetTexImage(GL_FALSE); +   if (glutExtensionSupported("GL_ARB_texture_non_power_of_two")) +      TestGetTexImage(GL_TRUE);     if (glutExtensionSupported("GL_EXT_framebuffer_object") || -       glutExtensionSupported("GL_ARB_framebuffer_object")) -      TestGetTexImageRTT(); +       glutExtensionSupported("GL_ARB_framebuffer_object")) { +      TestGetTexImageRTT(GL_FALSE); +      if (glutExtensionSupported("GL_ARB_texture_non_power_of_two")) +         TestGetTexImageRTT(GL_TRUE); +   }     glutDestroyWindow(Win);     exit(0); @@ -171,10 +207,10 @@ Reshape(int width, int height)     glViewport(0, 0, width, height);     glMatrixMode(GL_PROJECTION);     glLoadIdentity(); -   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); +   glOrtho(0, 1, 0, 1, -1, 1);     glMatrixMode(GL_MODELVIEW);     glLoadIdentity(); -   glTranslatef(0.0, 0.0, -15.0); +   glTranslatef(0.0, 0.0, 0.0);  } diff --git a/progs/tests/texcompsub.c b/progs/tests/texcompsub.c index 79a5f958a1..50106bf1e2 100644 --- a/progs/tests/texcompsub.c +++ b/progs/tests/texcompsub.c @@ -6,6 +6,7 @@  #include <assert.h>  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <GL/glew.h>  #include <GL/glut.h> @@ -31,6 +32,8 @@ CheckError(int line)  static void  LoadCompressedImage(void)  { +   unsigned char ImgDataTemp[ImgSize / 4]; +   unsigned i;     const GLenum filter = GL_LINEAR;     glTexImage2D(Target, 0, CompFormat, ImgWidth, ImgHeight, 0,                  GL_RGB, GL_UNSIGNED_BYTE, NULL); @@ -40,11 +43,24 @@ LoadCompressedImage(void)                                  0, 0, /* pos */                                  ImgWidth, ImgHeight / 2,                                  CompFormat, ImgSize / 2, ImgData + ImgSize / 2); -   /* top half */ + +   /* top left */ +   for (i = 0; i < ImgHeight / 8; i++) { +      memcpy(&ImgDataTemp[i * ImgWidth], &ImgData[i * 2 * ImgWidth], ImgWidth); +   }     glCompressedTexSubImage2DARB(Target, 0,                                  0, ImgHeight / 2, /* pos */ -                                ImgWidth, ImgHeight / 2, -                                CompFormat, ImgSize / 2, ImgData); +                                ImgWidth / 2, ImgHeight / 2, +                                CompFormat, ImgSize / 4, ImgDataTemp); + +   /* top right */ +   for (i = 0; i < ImgHeight / 8; i++) { +      memcpy(&ImgDataTemp[i * ImgWidth], &ImgData[i * 2 * ImgWidth + ImgWidth], ImgWidth); +   } +   glCompressedTexSubImage2DARB(Target, 0, +                                ImgWidth / 2, ImgHeight / 2, /* pos */ +                                ImgWidth / 2, ImgHeight / 2, +                                CompFormat, ImgSize / 4, ImgDataTemp);     glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, filter);     glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, filter); diff --git a/progs/tests/texwrap.c b/progs/tests/texwrap.c index 12f045b72e..92c8a2f14c 100644 --- a/progs/tests/texwrap.c +++ b/progs/tests/texwrap.c @@ -258,8 +258,26 @@ static void Init( void )     }     glBindTexture(GL_TEXTURE_2D, BORDER_TEXTURE); +#ifdef TEST_PBO_DLIST +   /* test fetching teximage from PBO in display list */ +   { +      GLuint b = 42, l = 10; + +      glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, b); +      glBufferDataARB(GL_PIXEL_UNPACK_BUFFER, sizeof(BorderImage), +                      BorderImage, GL_STREAM_DRAW); + +      glNewList(l, GL_COMPILE); +      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SIZE+2, SIZE+2, 1, +                GL_RGBA, GL_UNSIGNED_BYTE, (void *) 0/* BorderImage*/); +      glEndList(); +      glCallList(l); +      glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0); +   } +#else     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SIZE+2, SIZE+2, 1,                  GL_RGBA, GL_UNSIGNED_BYTE, (void *) BorderImage); +#endif     for (i = 0; i < SIZE; i++) {        for (j = 0; j < SIZE; j++) { diff --git a/progs/trivial/.gitignore b/progs/trivial/.gitignore index dce733a70a..4d6e405c50 100644 --- a/progs/trivial/.gitignore +++ b/progs/trivial/.gitignore @@ -5,10 +5,17 @@ clear-random  clear-repeat  clear-scissor  clear-undefined +createwin +dlist-begin-call-end  dlist-dangling  dlist-degenerate  dlist-edgeflag  dlist-edgeflag-dangling +dlist-flat-tri +dlist-mat-tri +dlist-recursive-call +dlist-tri-flat-tri +dlist-tri-mat-tri  draw2arrays  drawarrays  drawelements @@ -31,6 +38,7 @@ lineloop  lineloop-clip  lineloop-elts  linestrip +linestrip-clip  linestrip-flat-stipple  linestrip-stipple  linestrip-stipple-wide @@ -71,8 +79,10 @@ quadstrip-cont  quadstrip-flat  readtex.c  readtex.h +readpixels  tri  tri-alpha +tri-alpha-tex  tri-array-interleaved  tri-blend  tri-blend-color @@ -80,6 +90,7 @@ tri-blend-max  tri-blend-min  tri-blend-revsub  tri-blend-sub +tri-clear  tri-clip  tri-cull  tri-cull-both @@ -94,6 +105,7 @@ tri-fog  tri-fp  tri-fp-const-imm  tri-lit +tri-lit-material  tri-logicop-none  tri-logicop-xor  tri-mask-tri @@ -102,6 +114,7 @@ tri-orig  tri-query  tri-repeat  tri-scissor-tri +tri-square  tri-stencil  tri-stipple  tri-tex @@ -111,6 +124,7 @@ tri-unfilled  tri-unfilled-clip  tri-unfilled-edgeflag  tri-unfilled-fog +tri-unfilled-point  tri-unfilled-smooth  tri-unfilled-tri  tri-unfilled-tri-lit @@ -119,6 +133,7 @@ tri-unfilled-userclip-stip  tri-userclip  tri-viewport  tri-z +tri-z-9  tri-z-eq  trifan  trifan-flat diff --git a/progs/trivial/Makefile b/progs/trivial/Makefile index 3bd8faff99..70728616d2 100644 --- a/progs/trivial/Makefile +++ b/progs/trivial/Makefile @@ -18,6 +18,7 @@ SOURCES = \  	clear-repeat.c \  	clear-random.c \  	clear.c \ +	createwin.c \  	dlist-dangling.c \  	dlist-flat-tri.c \  	dlist-mat-tri.c \ @@ -48,6 +49,7 @@ SOURCES = \  	lineloop-clip.c \  	lineloop-elts.c \  	lineloop.c \ +	linestrip-clip.c \  	linestrip-flat-stipple.c \  	linestrip-stipple-wide.c \  	linestrip-stipple.c \ @@ -87,7 +89,9 @@ SOURCES = \  	quadstrip-cont.c \  	quadstrip-flat.c \  	quadstrip.c \ +	readpixels.c \  	tri-alpha.c \ +	tri-alpha-tex.c \  	tri-array-interleaved.c \  	tri-blend-color.c \  	tri-blend-max.c \ @@ -95,6 +99,7 @@ SOURCES = \  	tri-blend-revsub.c \  	tri-blend-sub.c \  	tri-blend.c \ +	tri-clear.c \  	tri-clip.c \  	tri-cull-both.c \  	tri-cull.c \ @@ -117,6 +122,7 @@ SOURCES = \  	tri-query.c \  	tri-repeat.c \  	tri-scissor-tri.c \ +	tri-square.c \  	tri-stencil.c \  	tri-stipple.c \  	tri-multitex-vbo.c \ @@ -126,6 +132,7 @@ SOURCES = \  	tri-unfilled-fog.c \  	tri-unfilled-edgeflag.c \  	tri-unfilled-clip.c \ +	tri-unfilled-point.c \  	tri-unfilled-smooth.c \  	tri-unfilled-tri.c \  	tri-unfilled-tri-lit.c \ @@ -134,6 +141,7 @@ SOURCES = \  	tri-unfilled.c \  	tri-userclip.c \  	tri-viewport.c \ +	tri-z-9.c \  	tri-z-eq.c \  	tri-z.c \  	tri.c \ diff --git a/progs/util/shaderutil.c b/progs/util/shaderutil.c index 13b68d90e0..489e71cc30 100644 --- a/progs/util/shaderutil.c +++ b/progs/util/shaderutil.c @@ -9,21 +9,12 @@  #include <assert.h>  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <GL/glew.h>  #include <GL/glut.h>  #include "shaderutil.h" -static void -Init(void) -{ -   static GLboolean firstCall = GL_TRUE; -   if (firstCall) { -      firstCall = GL_FALSE; -   } -} - -  GLboolean  ShadersSupported(void)  { @@ -47,8 +38,6 @@ CompileShaderText(GLenum shaderType, const char *text)     GLuint shader;     GLint stat; -   Init(); -     shader = glCreateShader(shaderType);     glShaderSource(shader, 1, (const GLchar **) &text, NULL);     glCompileShader(shader); @@ -79,9 +68,6 @@ CompileShaderFile(GLenum shaderType, const char *filename)     GLuint shader;     FILE *f; -   Init(); - -     f = fopen(filename, "r");     if (!f) {        fprintf(stderr, "Unable to open shader file %s\n", filename); @@ -136,7 +122,7 @@ LinkShaders(GLuint vertShader, GLuint fragShader)  void -InitUniforms(GLuint program, struct uniform_info uniforms[]) +SetUniformValues(GLuint program, struct uniform_info uniforms[])  {     GLuint i; @@ -144,28 +130,133 @@ InitUniforms(GLuint program, struct uniform_info uniforms[])        uniforms[i].location           = glGetUniformLocation(program, uniforms[i].name); -      printf("Uniform %s location: %d\n", uniforms[i].name, -             uniforms[i].location); - -      switch (uniforms[i].size) { -      case 1: -         if (uniforms[i].type == GL_INT) -            glUniform1i(uniforms[i].location, -                             (GLint) uniforms[i].value[0]); -         else -            glUniform1fv(uniforms[i].location, 1, uniforms[i].value); +      switch (uniforms[i].type) { +      case GL_INT: +      case GL_SAMPLER_1D: +      case GL_SAMPLER_2D: +      case GL_SAMPLER_3D: +      case GL_SAMPLER_CUBE: +      case GL_SAMPLER_2D_RECT_ARB: +         glUniform1i(uniforms[i].location, +                     (GLint) uniforms[i].value[0]); +         break; +      case GL_FLOAT: +         glUniform1fv(uniforms[i].location, 1, uniforms[i].value);           break; -      case 2: +      case GL_FLOAT_VEC2:           glUniform2fv(uniforms[i].location, 1, uniforms[i].value);           break; -      case 3: +      case GL_FLOAT_VEC3:           glUniform3fv(uniforms[i].location, 1, uniforms[i].value);           break; -      case 4: +      case GL_FLOAT_VEC4:           glUniform4fv(uniforms[i].location, 1, uniforms[i].value);           break;        default: -         abort(); +         if (strncmp(uniforms[i].name, "gl_", 3) == 0) { +            /* built-in uniform: ignore */ +         } +         else { +            fprintf(stderr, +                    "Unexpected uniform data type in SetUniformValues\n"); +            abort(); +         }        }     }  } + + +/** Get list of uniforms used in the program */ +GLuint +GetUniforms(GLuint program, struct uniform_info uniforms[]) +{ +   GLint n, max, i; + +   glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); +   glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max); + +   for (i = 0; i < n; i++) { +      GLint size, len; +      GLenum type; +      char name[100]; + +      glGetActiveUniform(program, i, 100, &len, &size, &type, name); + +      uniforms[i].name = strdup(name); +      uniforms[i].size = size; +      uniforms[i].type = type; +      uniforms[i].location = glGetUniformLocation(program, name); +   } + +   uniforms[i].name = NULL; /* end of list */ + +   return n; +} + + +void +PrintUniforms(const struct uniform_info uniforms[]) +{ +   GLint i; + +   printf("Uniforms:\n"); + +   for (i = 0; uniforms[i].name; i++) { +      printf("  %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n", +             i, +             uniforms[i].name, +             uniforms[i].size, +             uniforms[i].type, +             uniforms[i].location, +             uniforms[i].value[0], +             uniforms[i].value[1], +             uniforms[i].value[2], +             uniforms[i].value[3]); +   } +} + + +/** Get list of attribs used in the program */ +GLuint +GetAttribs(GLuint program, struct attrib_info attribs[]) +{ +   GLint n, max, i; + +   glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); +   glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max); + +   for (i = 0; i < n; i++) { +      GLint size, len; +      GLenum type; +      char name[100]; + +      glGetActiveAttrib(program, i, 100, &len, &size, &type, name); + +      attribs[i].name = strdup(name); +      attribs[i].size = size; +      attribs[i].type = type; +      attribs[i].location = glGetAttribLocation(program, name); +   } + +   attribs[i].name = NULL; /* end of list */ + +   return n; +} + + +void +PrintAttribs(const struct attrib_info attribs[]) +{ +   GLint i; + +   printf("Attribs:\n"); + +   for (i = 0; attribs[i].name; i++) { +      printf("  %d: %s size=%d type=0x%x loc=%d\n", +             i, +             attribs[i].name, +             attribs[i].size, +             attribs[i].type, +             attribs[i].location); +   } +} diff --git a/progs/util/shaderutil.h b/progs/util/shaderutil.h index cfb8c1f3b0..0a6be02675 100644 --- a/progs/util/shaderutil.h +++ b/progs/util/shaderutil.h @@ -6,8 +6,8 @@  struct uniform_info  {     const char *name; -   GLuint size; -   GLenum type;  /**< GL_FLOAT or GL_INT */ +   GLuint size;  /**< number of value[] elements: 1, 2, 3 or 4 */ +   GLenum type;  /**< GL_FLOAT, GL_FLOAT_VEC4, GL_INT, etc */     GLfloat value[4];     GLint location;  /**< filled in by InitUniforms() */  }; @@ -15,6 +15,15 @@ struct uniform_info  #define END_OF_UNIFORMS   { NULL, 0, GL_NONE, { 0, 0, 0, 0 }, -1 } +struct attrib_info +{ +   const char *name; +   GLuint size;  /**< number of value[] elements: 1, 2, 3 or 4 */ +   GLenum type;  /**< GL_FLOAT, GL_FLOAT_VEC4, GL_INT, etc */ +   GLint location; +}; + +  extern GLboolean  ShadersSupported(void); @@ -28,7 +37,18 @@ extern GLuint  LinkShaders(GLuint vertShader, GLuint fragShader);  extern void -InitUniforms(GLuint program, struct uniform_info uniforms[]); +SetUniformValues(GLuint program, struct uniform_info uniforms[]); + +extern GLuint +GetUniforms(GLuint program, struct uniform_info uniforms[]); + +extern void +PrintUniforms(const struct uniform_info uniforms[]); +extern GLuint +GetAttribs(GLuint program, struct attrib_info attribs[]); + +extern void +PrintAttribs(const struct attrib_info attribs[]);  #endif /* SHADER_UTIL_H */ diff --git a/progs/vp/arl-static.txt b/progs/vp/arl-static.txt index aea87b79a4..83aebf689e 100644 --- a/progs/vp/arl-static.txt +++ b/progs/vp/arl-static.txt @@ -1,5 +1,5 @@  !!ARBvp1.0 -PARAM arr[5]  = { {.0,.1,.2,.3}, {.4,.5,.6,.7}, {.8,.9,.10,.1}, {.12,.3,.4,.14}, {.5,.8,.1,.9},  {.2,0,.4,.1}, {.6,.1,.8,.9}}; +PARAM arr[7]  = { {.0,.1,.2,.3}, {.4,.5,.6,.7}, {.8,.9,.10,.1}, {.12,.3,.4,.14}, {.5,.8,.1,.9},  {.2,0,.4,.1}, {.6,.1,.8,.9}};  ADDRESS addr;  ARL addr.x, {3}.x;  MOV result.color, arr[addr.x]; diff --git a/progs/vp/arl-unused.txt b/progs/vp/arl-unused.txt index 7bdbb8e86c..c2afe3c092 100644 --- a/progs/vp/arl-unused.txt +++ b/progs/vp/arl-unused.txt @@ -1,5 +1,5 @@  !!ARBvp1.0 -PARAM arr[5]  = { {.0,.1,.2,.3}, {.4,.5,.6,.7}, {.8,.9,.10,.1}, {.12,.3,.4,.14}, {.5,.8,.1,.9},  {.2,0,.4,.1}, {.6,.1,.8,.9}}; +PARAM arr[7]  = { {.0,.1,.2,.3}, {.4,.5,.6,.7}, {.8,.9,.10,.1}, {.12,.3,.4,.14}, {.5,.8,.1,.9},  {.2,0,.4,.1}, {.6,.1,.8,.9}};  ADDRESS addr;  ARL addr.x, {3}.x;  # not actually used  MOV result.color, arr[3]; diff --git a/progs/xdemos/Makefile b/progs/xdemos/Makefile index 6581df8039..53e1c54ef3 100644 --- a/progs/xdemos/Makefile +++ b/progs/xdemos/Makefile @@ -26,6 +26,7 @@ PROGS = \  	glxsnoop \  	glxswapcontrol \  	manywin \ +	multictx \  	offset \  	overlay \  	pbinfo \ diff --git a/progs/xdemos/glxcontexts.c b/progs/xdemos/glxcontexts.c index 481749be3d..9f83679acd 100644 --- a/progs/xdemos/glxcontexts.c +++ b/progs/xdemos/glxcontexts.c @@ -378,6 +378,9 @@ make_window( Display *dpy, const char *name,     scrnum = DefaultScreen( dpy );     root = RootWindow( dpy, scrnum ); +   if (visinfo) +	   XFree(visinfo); +     visinfo = glXChooseVisual( dpy, scrnum, attribs );     if (!visinfo) {        printf("Error: couldn't get an RGB, Double-buffered visual\n"); diff --git a/progs/xdemos/glxgears.c b/progs/xdemos/glxgears.c index bc84ee3dbd..088f25a357 100644 --- a/progs/xdemos/glxgears.c +++ b/progs/xdemos/glxgears.c @@ -23,10 +23,7 @@   * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)   * Port by Brian Paul  23 March 2001   * - * Command line options: - *    -info      print GL implementation information - *    -stereo    use stereo enabled GLX visual - * + * See usage() below for command line options.   */ @@ -45,10 +42,6 @@ typedef int (*PFNGLXGETSWAPINTERVALMESAPROC)(void);  #endif -static int is_glx_extension_supported(Display *dpy, const char *query); - -static void query_vsync(Display *dpy); -  #define BENCHMARK  #ifdef BENCHMARK @@ -572,7 +565,7 @@ make_window( Display *dpy, const char *name,  /**   * Determine whether or not a GLX extension is supported.   */ -int +static int  is_glx_extension_supported(Display *dpy, const char *query)  {     const int scrnum = DefaultScreen(dpy); @@ -592,7 +585,7 @@ is_glx_extension_supported(Display *dpy, const char *query)  /**   * Attempt to determine whether or not the display is synched to vblank.   */ -void +static void  query_vsync(Display *dpy)  {     int interval = 0; diff --git a/progs/xdemos/glxswapcontrol.c b/progs/xdemos/glxswapcontrol.c index df9f7ad784..cd60d460a0 100644 --- a/progs/xdemos/glxswapcontrol.c +++ b/progs/xdemos/glxswapcontrol.c @@ -587,6 +587,9 @@ event_loop(Display *dpy, Window win)        angle += 2.0;        draw(); + +      glXSwapBuffers(dpy, win); +        if ( get_frame_usage != NULL ) {  	 GLfloat   temp; @@ -594,8 +597,6 @@ event_loop(Display *dpy, Window win)  	 frame_usage += temp;        } -      glXSwapBuffers(dpy, win); -        /* calc framerate */        {           static int t0 = -1; diff --git a/progs/xdemos/multictx.c b/progs/xdemos/multictx.c new file mode 100644 index 0000000000..75255b2860 --- /dev/null +++ b/progs/xdemos/multictx.c @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2009  VMware, Inc.   All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Test rendering with two contexts into one window. + * Setup different rendering state for each context to check that + * context switching is handled properly. + * + * Brian Paul + * 6 Aug 2009 + */ + + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <unistd.h> +#include <X11/Xlib.h> +#include <X11/keysym.h> +#include <GL/gl.h> +#include <GL/glx.h> + + + +#ifndef M_PI +#define M_PI 3.14159265 +#endif + + +/** Event handler results: */ +#define NOP 0 +#define EXIT 1 +#define DRAW 2 + +static GLfloat view_rotx = 0.0, view_roty = 210.0, view_rotz = 0.0; +static GLint gear1, gear2; +static GLfloat angle = 0.0; + +static GLboolean animate = GL_TRUE;	/* Animation */ + + +static double +current_time(void) +{ +   struct timeval tv; +#ifdef __VMS +   (void) gettimeofday(&tv, NULL ); +#else +   struct timezone tz; +   (void) gettimeofday(&tv, &tz); +#endif +   return (double) tv.tv_sec + tv.tv_usec / 1000000.0; +} + + +/* + * + *  Draw a gear wheel.  You'll probably want to call this function when + *  building a display list since we do a lot of trig here. + *  + *  Input:  inner_radius - radius of hole at center + *          outer_radius - radius at center of teeth + *          width - width of gear + *          teeth - number of teeth + *          tooth_depth - depth of tooth + */ +static void +gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, +     GLint teeth, GLfloat tooth_depth) +{ +   GLint i; +   GLfloat r0, r1, r2; +   GLfloat angle, da; +   GLfloat u, v, len; + +   r0 = inner_radius; +   r1 = outer_radius - tooth_depth / 2.0; +   r2 = outer_radius + tooth_depth / 2.0; + +   da = 2.0 * M_PI / teeth / 4.0; + +   glShadeModel(GL_FLAT); + +   glNormal3f(0.0, 0.0, 1.0); + +   /* draw front face */ +   glBegin(GL_QUAD_STRIP); +   for (i = 0; i <= teeth; i++) { +      angle = i * 2.0 * M_PI / teeth; +      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); +      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); +      if (i < teeth) { +	 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); +	 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), +		    width * 0.5); +      } +   } +   glEnd(); + +   /* draw front sides of teeth */ +   glBegin(GL_QUADS); +   da = 2.0 * M_PI / teeth / 4.0; +   for (i = 0; i < teeth; i++) { +      angle = i * 2.0 * M_PI / teeth; + +      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); +      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); +      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), +		 width * 0.5); +      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), +		 width * 0.5); +   } +   glEnd(); + +   glNormal3f(0.0, 0.0, -1.0); + +   /* draw back face */ +   glBegin(GL_QUAD_STRIP); +   for (i = 0; i <= teeth; i++) { +      angle = i * 2.0 * M_PI / teeth; +      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); +      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); +      if (i < teeth) { +	 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), +		    -width * 0.5); +	 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); +      } +   } +   glEnd(); + +   /* draw back sides of teeth */ +   glBegin(GL_QUADS); +   da = 2.0 * M_PI / teeth / 4.0; +   for (i = 0; i < teeth; i++) { +      angle = i * 2.0 * M_PI / teeth; + +      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), +		 -width * 0.5); +      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), +		 -width * 0.5); +      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); +      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); +   } +   glEnd(); + +   /* draw outward faces of teeth */ +   glBegin(GL_QUAD_STRIP); +   for (i = 0; i < teeth; i++) { +      angle = i * 2.0 * M_PI / teeth; + +      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); +      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); +      u = r2 * cos(angle + da) - r1 * cos(angle); +      v = r2 * sin(angle + da) - r1 * sin(angle); +      len = sqrt(u * u + v * v); +      u /= len; +      v /= len; +      glNormal3f(v, -u, 0.0); +      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); +      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); +      glNormal3f(cos(angle), sin(angle), 0.0); +      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), +		 width * 0.5); +      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), +		 -width * 0.5); +      u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); +      v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); +      glNormal3f(v, -u, 0.0); +      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), +		 width * 0.5); +      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), +		 -width * 0.5); +      glNormal3f(cos(angle), sin(angle), 0.0); +   } + +   glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); +   glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); + +   glEnd(); + +   glShadeModel(GL_SMOOTH); + +   /* draw inside radius cylinder */ +   glBegin(GL_QUAD_STRIP); +   for (i = 0; i <= teeth; i++) { +      angle = i * 2.0 * M_PI / teeth; +      glNormal3f(-cos(angle), -sin(angle), 0.0); +      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); +      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); +   } +   glEnd(); +} + + +static void +draw(int ctx) +{ +   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +   glPushMatrix(); +   glRotatef(view_rotx, 1.0, 0.0, 0.0); +   glRotatef(view_roty + angle, 0.0, 1.0, 0.0); +   glRotatef(view_rotz, 0.0, 0.0, 1.0); + +   if (ctx == 0) { +      glDisable(GL_CULL_FACE); +      glPushMatrix(); +      glRotatef(angle, 0.0, 0.0, 1.0); +      glCallList(gear1); +      glPopMatrix(); +      /* This should not effect the other context's rendering */ +      glEnable(GL_CULL_FACE); +      glCullFace(GL_FRONT_AND_BACK); +   } +   else { +      glPushMatrix(); +      glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); +      glCallList(gear2); +      glPopMatrix(); +   } + +   glPopMatrix(); + +   /* this flush is important since we'll be switching contexts next */ +   glFlush(); +} + + + +static void +draw_frame(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2) +{ +   static double tRot0 = -1.0; +   double dt, t = current_time(); + +   if (tRot0 < 0.0) +      tRot0 = t; +   dt = t - tRot0; +   tRot0 = t; + +   if (animate) { +      /* advance rotation for next frame */ +      angle += 70.0 * dt;  /* 70 degrees per second */ +      if (angle > 3600.0) +         angle -= 3600.0; +   } + +   glXMakeCurrent(dpy, (GLXDrawable) win, ctx1); +   draw(0); + +   glXMakeCurrent(dpy, (GLXDrawable) win, ctx2); +   draw(1); + +   glXSwapBuffers(dpy, win); +} + + +/* new window size or exposure */ +static void +reshape(Display *dpy, Window win, +        GLXContext ctx1, GLXContext ctx2, int width, int height) +{ +   int i; + +   width /= 2; + +   /* loop: left half of window, right half of window */ +   for (i = 0; i < 2; i++) { +      if (i == 0) +         glXMakeCurrent(dpy, win, ctx1); +      else +         glXMakeCurrent(dpy, win, ctx2); + +      glViewport(width * i, 0, width, height); +      glScissor(width * i, 0, width, height); + +      { +         GLfloat h = (GLfloat) height / (GLfloat) width; + +         glMatrixMode(GL_PROJECTION); +         glLoadIdentity(); +         glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); +      } + +      glMatrixMode(GL_MODELVIEW); +      glLoadIdentity(); +      glTranslatef(0.0, 0.0, -30.0); +   } +} +    + + +static void +init(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2) +{ +   static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; +   static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 }; +   static GLfloat green[4] = { 0.0, 0.8, 0.2, 0.5 }; +   /*static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };*/ + +   /* first ctx */ +   { +      static GLuint stipple[32] = { +         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, +         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, + +         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, +         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, + +         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, +         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, + +         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, +         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00 +      }; + +      glXMakeCurrent(dpy, win, ctx1); + +      glLightfv(GL_LIGHT0, GL_POSITION, pos); +      glEnable(GL_LIGHTING); +      glEnable(GL_LIGHT0); +      glEnable(GL_DEPTH_TEST); + +      gear1 = glGenLists(1); +      glNewList(gear1, GL_COMPILE); +      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); +      gear(1.0, 4.0, 1.0, 20, 0.7); +      glEndList(); + +      glEnable(GL_NORMALIZE); +      glEnable(GL_SCISSOR_TEST); +      glClearColor(0.4, 0.4, 0.4, 1.0); + +      glPolygonStipple((GLubyte *) stipple); +      glEnable(GL_POLYGON_STIPPLE); +   } + +   /* second ctx */ +   { +      glXMakeCurrent(dpy, win, ctx2); + +      glLightfv(GL_LIGHT0, GL_POSITION, pos); +      glEnable(GL_LIGHTING); +      glEnable(GL_LIGHT0); +      glEnable(GL_DEPTH_TEST); + +      gear2 = glGenLists(1); +      glNewList(gear2, GL_COMPILE); +      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); +      gear(1.5, 3.0, 1.5, 16, 0.7); +      glEndList(); + +      glEnable(GL_NORMALIZE); +      glEnable(GL_SCISSOR_TEST); +      glClearColor(0.6, 0.6, 0.6, 1.0); + +      glEnable(GL_BLEND); +      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +   } +} + + +/** + * Create an RGB, double-buffered window. + * Return the window and two context handles. + */ +static void +make_window_and_contexts( Display *dpy, const char *name, +                          int x, int y, int width, int height, +                          Window *winRet, +                          GLXContext *ctxRet1, +                          GLXContext *ctxRet2) +{ +   int attribs[] = { GLX_RGBA, +                     GLX_RED_SIZE, 1, +                     GLX_GREEN_SIZE, 1, +                     GLX_BLUE_SIZE, 1, +                     GLX_DOUBLEBUFFER, +                     GLX_DEPTH_SIZE, 1, +                     None }; +   int scrnum; +   XSetWindowAttributes attr; +   unsigned long mask; +   Window root; +   Window win; +   XVisualInfo *visinfo; + +   scrnum = DefaultScreen( dpy ); +   root = RootWindow( dpy, scrnum ); + +   visinfo = glXChooseVisual( dpy, scrnum, attribs ); +   if (!visinfo) { +      printf("Error: couldn't get an RGB, Double-buffered visual\n"); +      exit(1); +   } + +   /* window attributes */ +   attr.background_pixel = 0; +   attr.border_pixel = 0; +   attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); +   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; +   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + +   win = XCreateWindow( dpy, root, x, y, width, height, +		        0, visinfo->depth, InputOutput, +		        visinfo->visual, mask, &attr ); + +   /* set hints and properties */ +   { +      XSizeHints sizehints; +      sizehints.x = x; +      sizehints.y = y; +      sizehints.width  = width; +      sizehints.height = height; +      sizehints.flags = USSize | USPosition; +      XSetNormalHints(dpy, win, &sizehints); +      XSetStandardProperties(dpy, win, name, name, +                              None, (char **)NULL, 0, &sizehints); +   } + +   *winRet = win; +   *ctxRet1 = glXCreateContext( dpy, visinfo, NULL, True ); +   *ctxRet2 = glXCreateContext( dpy, visinfo, NULL, True ); + +   if (!*ctxRet1 || !*ctxRet2) { +      printf("Error: glXCreateContext failed\n"); +      exit(1); +   } + +   XFree(visinfo); +} + + +/** + * Handle one X event. + * \return NOP, EXIT or DRAW + */ +static int +handle_event(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2, +             XEvent *event) +{ +   (void) dpy; +   (void) win; + +   switch (event->type) { +   case Expose: +      return DRAW; +   case ConfigureNotify: +      reshape(dpy, win, ctx1, ctx2, +              event->xconfigure.width, event->xconfigure.height); +      break; +   case KeyPress: +      { +         char buffer[10]; +         int r, code; +         code = XLookupKeysym(&event->xkey, 0); +         if (code == XK_Left) { +            view_roty += 5.0; +         } +         else if (code == XK_Right) { +            view_roty -= 5.0; +         } +         else if (code == XK_Up) { +            view_rotx += 5.0; +         } +         else if (code == XK_Down) { +            view_rotx -= 5.0; +         } +         else { +            r = XLookupString(&event->xkey, buffer, sizeof(buffer), +                              NULL, NULL); +            if (buffer[0] == 27) { +               /* escape */ +               return EXIT; +            } +            else if (buffer[0] == 'a' || buffer[0] == 'A') { +               animate = !animate; +            } +         } +         return DRAW; +      } +   } +   return NOP; +} + + +static void +event_loop(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2) +{ +   while (1) { +      int op; +      while (!animate || XPending(dpy) > 0) { +         XEvent event; +         XNextEvent(dpy, &event); +         op = handle_event(dpy, win, ctx1, ctx2, &event); +         if (op == EXIT) +            return; +         else if (op == DRAW) +            break; +      } + +      draw_frame(dpy, win, ctx1, ctx2); +   } +} + + +int +main(int argc, char *argv[]) +{ +   unsigned int winWidth = 800, winHeight = 400; +   int x = 0, y = 0; +   Display *dpy; +   Window win; +   GLXContext ctx1, ctx2; +   char *dpyName = NULL; +   GLboolean printInfo = GL_FALSE; +   int i; + +   for (i = 1; i < argc; i++) { +      if (strcmp(argv[i], "-display") == 0) { +         dpyName = argv[i+1]; +         i++; +      } +      else { +         return 1; +      } +   } + +   dpy = XOpenDisplay(dpyName); +   if (!dpy) { +      printf("Error: couldn't open display %s\n", +	     dpyName ? dpyName : getenv("DISPLAY")); +      return -1; +   } + +   make_window_and_contexts(dpy, "multictx", x, y, winWidth, winHeight, +                            &win, &ctx1, &ctx2); +   XMapWindow(dpy, win); + +   if (printInfo) { +      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER)); +      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION)); +      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR)); +      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); +   } + +   init(dpy, win, ctx1, ctx2); + +   /* Set initial projection/viewing transformation. +    * We can't be sure we'll get a ConfigureNotify event when the window +    * first appears. +    */ +   reshape(dpy, win, ctx1, ctx2, winWidth, winHeight); + +   event_loop(dpy, win, ctx1, ctx2); + +   glDeleteLists(gear1, 1); +   glDeleteLists(gear2, 1); +   glXDestroyContext(dpy, ctx1); +   glXDestroyContext(dpy, ctx2); +   XDestroyWindow(dpy, win); +   XCloseDisplay(dpy); + +   return 0; +}  | 
