summaryrefslogtreecommitdiff
path: root/progs/tests
diff options
context:
space:
mode:
Diffstat (limited to 'progs/tests')
-rw-r--r--progs/tests/Makefile3
-rw-r--r--progs/tests/calibrate_rast.c395
-rw-r--r--progs/tests/descrip.mms84
-rw-r--r--progs/tests/minmag.c198
-rw-r--r--progs/tests/subtex.c223
5 files changed, 819 insertions, 84 deletions
diff --git a/progs/tests/Makefile b/progs/tests/Makefile
index 9016efe9e7..7053ebc86a 100644
--- a/progs/tests/Makefile
+++ b/progs/tests/Makefile
@@ -30,6 +30,7 @@ SOURCES = \
bug_3050.c \
bug_3101.c \
bug_3195.c \
+ calibrate_rast.c \
copypixrate.c \
crossbar.c \
cva.c \
@@ -48,6 +49,7 @@ SOURCES = \
invert.c \
jkrahntest.c \
manytex.c \
+ minmag.c \
mipmap_limits.c \
multipal.c \
no_s3tc.c \
@@ -61,6 +63,7 @@ SOURCES = \
sharedtex.c \
stencilwrap.c \
stencil_wrap.c \
+ subtex \
subtexrate.c \
tex1d.c \
texcompress2.c \
diff --git a/progs/tests/calibrate_rast.c b/progs/tests/calibrate_rast.c
new file mode 100644
index 0000000000..37d8ac85e5
--- /dev/null
+++ b/progs/tests/calibrate_rast.c
@@ -0,0 +1,395 @@
+/*
+ * Automatic primitive rasterization precision test.
+ *
+ * Draw prims at various sub-pixel offsets and examine where the quad is
+ * actually drawn.
+ * Check if the range of offsets which paint the right pixels falls within
+ * OpenGL's specification.
+ * In case of failures, report the coordinate bias needed to fix the problem.
+ *
+ * Note that even Mesa/swrast fails some line tests. This is because some
+ * window coordinates wind up as 53.9999 instead of 54, for example. Enabling
+ * the small translation factor below fixes that. Revisit someday...
+ *
+ * Brian Paul
+ * 28 Feb 2008
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+
+
+static int Width = 100, Height = 100;
+static int Win;
+static float Step = 0.125;
+#if 0
+/* This tiny offset fixes errors in Mesa/Xlib */
+static float Xtrans = 0.5 * 0.125;
+static float Ytrans = 0.5 * 0.125;
+#else
+static float Xtrans = 0.0;
+static float Ytrans = 0.0;
+#endif
+
+
+static void
+PointCalibrate(int xpos, int ypos)
+{
+ GLfloat rgba[4];
+ float x, y;
+ float xmin, ymin, xmax, ymax;
+
+ xmin = ymin = 1000.0;
+ xmax = ymax = -1000.0;
+
+ for (y = -1.0; y <= 1.0; y += Step) {
+ for (x = -1.0; x <= 1.0; x += Step) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBegin(GL_POINTS);
+ glVertex2f(xpos + x, ypos + y);
+ glEnd();
+ glReadPixels(xpos, ypos, 1, 1, GL_RGBA, GL_FLOAT, rgba);
+ if (rgba[0] == 1.0 && rgba[1] == 1.0 && rgba[2] == 1.0) {
+ /* hit */
+ if (x < xmin)
+ xmin = x;
+ if (y < ymin)
+ ymin = y;
+ if (x > xmax)
+ xmax = x;
+ if (y > ymax)
+ ymax = y;
+ }
+ }
+ }
+
+ printf("Point at (%2d, %2d) drawn for x in [%6.3f, %6.3f] and y in [%6.3f, %6.3f]\n",
+ xpos, ypos,
+ xpos + xmin, xpos + xmax,
+ ypos + ymin, ypos + ymax);
+
+ if (xmax - xmin != 1.0 - Step) {
+ printf(" => Inconsistant X-axis rasterization!\n");
+ }
+ if (ymax - ymin != 1.0 - Step) {
+ printf(" => Inconsistant Y-axis rasterization!\n");
+ }
+ if (xmin < 0.0) {
+ printf(" => Points should be X biased by about %f\n", xmin);
+ }
+ if (ymin < 0.0) {
+ printf(" => Points should be Y biased by about %f\n", ymin);
+ }
+ if (xmax > 1.0) {
+ printf(" => Points should be X biased by about %f\n", 1.0 - xmax);
+ }
+ if (ymax > 1.0) {
+ printf(" => Points should be Y biased by about %f\n", 1.0 - ymax);
+ }
+
+}
+
+
+/**
+ * XXX Implement VLineCalibrate() someday
+ */
+static void
+HLineCalibrate(int xpos, int ypos, int len)
+{
+ GLfloat rgba[2][4];
+ float x, y;
+ float ymin, ymax;
+ float xmin_left, xmax_left, xmin_right, xmax_right;
+
+ xmin_left = xmin_right = 1000.0;
+ xmax_left = xmax_right = -1000.0;
+ ymin = 1000;
+ ymax = -1000.0;
+
+ /*
+ * First, check vertical positioning of the horizontal line
+ */
+ for (y = -1.0; y <= 1.0; y += Step) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBegin(GL_LINES);
+ glVertex2f(xpos, ypos + y);
+ glVertex2f(xpos + len, ypos + y);
+ glEnd();
+
+ glReadPixels(xpos + len / 2, ypos, 1, 1, GL_RGBA, GL_FLOAT, rgba);
+ if (rgba[0][0] == 1.0) {
+ /* hit */
+ if (y < ymin)
+ ymin = y;
+ if (y > ymax)
+ ymax = y;
+ }
+ }
+
+ printf("H-line at Y=%2d drawn for y in [%6.3f, %6.3f]\n",
+ ypos,
+ ypos + ymin, ypos + ymax);
+
+ if (ymax - ymin != 1.0 - Step) {
+ printf(" => Inconsistant Y-axis rasterization!\n");
+ }
+
+ if (ymin > 0.5 ) {
+ printf(" => Lines should be Y biased by about %f\n", ymin - 0.5);
+ }
+
+ if (ymax < 0.5 ) {
+ printf(" => Lines should be Y biased by about %f\n", 0.5 - ymax);
+ }
+
+ /*
+ * Second, check endpoints (for Y at 1/2 pixel)
+ */
+ for (x = -1.0; x <= 1.0; x += Step) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBegin(GL_LINES);
+ glVertex2f(xpos + x, ypos + 0.5f);
+ glVertex2f(xpos + x + len, ypos + 0.5f);
+ glEnd();
+
+ /* left end */
+ glReadPixels(xpos - 1, ypos, 2, 1, GL_RGBA, GL_FLOAT, rgba);
+ if (rgba[0][0] == 0.0 && rgba[1][0] == 1.0) {
+ /* hit */
+ if (x < xmin_left)
+ xmin_left = x;
+ if (x > xmax_left)
+ xmax_left = x;
+ }
+
+ /* right end */
+ glReadPixels(xpos + len - 1, ypos, 2, 1, GL_RGBA, GL_FLOAT, rgba);
+ if (rgba[0][0] == 1.0 && rgba[1][0] == 0.0) {
+ /* hit */
+ if (x < xmin_right)
+ xmin_right = x;
+ if (x > xmax_right)
+ xmax_right = x;
+ }
+ }
+
+ printf("H-line [%d..%d) hit left end for x in [%6.3f, %6.3f] "
+ "hit right end for x in [%6.3f, %6.3f]\n",
+ xpos, xpos + len,
+ xpos + xmin_left, xpos + xmax_left,
+ xpos + len + xmin_right, xpos + len + xmax_right);
+
+ if (xmax_left - xmin_left > 1.0 - Step) {
+ printf(" => Inconsistant left-end rasterization!\n");
+ }
+ if (xmax_right - xmin_right > 1.0 - Step) {
+ printf(" => Inconsistant right-end rasterization!\n");
+ }
+
+ if (xmin_left != xmin_right ||
+ xmax_left != xmax_right) {
+ printf(" => Inconsistant length!\n");
+ }
+
+ if (xmin_left < 0.0) {
+ printf(" => Coords should be X biased by about %f\n", xmin_left );
+ }
+ if (xmin_right < 0.0) {
+ printf(" => Coords should be X biased by about %f\n", xmin_right );
+ }
+ if (xmax_left >= 1.0) {
+ printf(" => Coords should be X biased by about %f\n", -xmax_right + 1.0);
+ }
+ if (xmax_right >= 1.0) {
+ printf(" => Coords should be X biased by about %f\n", -xmax_right + 1.0);
+ }
+
+}
+
+
+static void
+QuadCalibrate(int xpos, int ypos, int width, int height)
+{
+ GLfloat rgba1[2][4];
+ GLfloat rgba2[2][4];
+ float x, y;
+ float xmin, ymin, xmax, ymax;
+
+ xmin = ymin = 1000.0;
+ xmax = ymax = -1000.0;
+
+ for (y = -1.0; y <= 1.0; y += Step) {
+ for (x = -1.0; x <= 1.0; x += Step) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBegin(GL_QUADS);
+ glVertex2f(xpos + x, ypos + y);
+ glVertex2f(xpos + x + width, ypos + y);
+ glVertex2f(xpos + x + width, ypos + y + height);
+ glVertex2f(xpos + x, ypos + y + height);
+ glEnd();
+
+ /* horizontal measurement */
+ glReadPixels(xpos - 1, ypos + 2, 2, 1, GL_RGBA, GL_FLOAT, rgba1);
+ glReadPixels(xpos + width - 1, ypos + 2, 2, 1, GL_RGBA, GL_FLOAT, rgba2);
+ if (rgba1[0][0] == 0.0 && rgba1[1][0] == 1.0 &&
+ rgba2[0][0] == 1.0 && rgba2[1][0] == 0.0) {
+ if (x < xmin)
+ xmin = x;
+ if (x > xmax)
+ xmax = x;
+ }
+
+ /* vertical measurement */
+ glReadPixels(xpos + 2, ypos - 1, 1, 2, GL_RGBA, GL_FLOAT, rgba1);
+ glReadPixels(xpos + 2, ypos + height - 1, 1, 2, GL_RGBA, GL_FLOAT, rgba2);
+ if (rgba1[0][0] == 0.0 && rgba1[1][0] == 1.0 &&
+ rgba2[0][0] == 1.0 && rgba2[1][0] == 0.0) {
+ if (y < ymin)
+ ymin = y;
+ if (y > ymax)
+ ymax = y;
+ }
+ }
+ }
+
+ printf("Quad at (%2d, %2d)..(%2d, %2d) drawn"
+ " for x in [%6.3f, %6.3f] and y in [%6.3f, %6.3f]\n",
+ xpos, ypos,
+ xpos + width, ypos + height,
+ xpos + xmin, xpos + xmax,
+ ypos + ymin, ypos + ymax);
+
+ if (xmax - xmin != 1.0 - Step) {
+ printf(" => Inconsistant X-axis rasterization/size!\n");
+ }
+ if (ymax - ymin != 1.0 - Step) {
+ printf(" => Inconsistant Y-axis rasterization/size!\n");
+ }
+
+ if (xmin < -0.5) {
+ printf(" => Coords should be X biased by about %f\n", 0.5 + xmin );
+ }
+ if (ymin < -0.5) {
+ printf(" => Coords should be Y biased by about %f\n", 0.5 + ymin);
+ }
+ if (xmax > 0.5) {
+ printf(" => Coords should be X biased by about %f\n", -xmax + 0.5);
+ }
+ if (ymax > 0.5) {
+ printf(" => Coords should be Y biased by about %f\n", -ymax + 0.5);
+ }
+}
+
+
+/**
+ * Misc/disabled code for debugging.
+ */
+static void
+DebugTest(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+
+ glColor3f(.5, .5, .5);
+
+ glBegin(GL_LINES);
+ glVertex2f(30, 35.5);
+ glVertex2f(54, 35.5);
+ glVertex2f(54, 35.5);
+ glVertex2f(66, 35.5);
+ glEnd();
+
+ glDisable(GL_BLEND);
+ glColor3f(1,1,1);
+}
+
+
+static void
+Draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glPushMatrix();
+ glTranslatef(Xtrans, Ytrans, 0);
+
+ PointCalibrate(1, 1);
+ PointCalibrate(50, 50);
+ PointCalibrate(28, 17);
+ PointCalibrate(17, 18);
+ printf("\n");
+
+ HLineCalibrate(5, 10, 10);
+ HLineCalibrate(25, 22, 12);
+ HLineCalibrate(54, 33, 12);
+ HLineCalibrate(54+12, 33, 12);
+ printf("\n");
+
+ QuadCalibrate(2, 2, 10, 10);
+ QuadCalibrate(50, 50, 10, 10);
+ QuadCalibrate(28, 17, 12, 12);
+ QuadCalibrate(17, 28, 12, 12);
+
+ (void) DebugTest;
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, 0, height, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ glutDestroyWindow(Win);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ printf("Measurement/callibration for basic prim rasterization...\n");
+ printf("GL_RENDERER: %s\n", (char*) glGetString(GL_RENDERER));
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+ Win = glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Draw);
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/progs/tests/descrip.mms b/progs/tests/descrip.mms
deleted file mode 100644
index 567b76bc4b..0000000000
--- a/progs/tests/descrip.mms
+++ /dev/null
@@ -1,84 +0,0 @@
-# Makefile for GLUT-based demo programs for VMS
-# contributed by Jouk Jansen joukj@hrem.stm.tudelft.nl
-
-
-.first
- define gl [--.include.gl]
-
-.include [--]mms.config
-
-##### MACROS #####
-
-INCDIR = ([--.include],[-.util])
-CFLAGS = /include=$(INCDIR)/prefix=all/name=(as_is,short)/float=ieee/ieee=denorm
-
-.ifdef SHARE
-GL_LIBS = $(XLIBS)
-.else
-GL_LIBS = [--.lib]libGLUT/l,libMesaGLU/l,libMesaGL/l,$(XLIBS)
-.endif
-
-LIB_DEP = [--.lib]$(GL_LIB) [--.lib]$(GLU_LIB) [--.lib]$(GLUT_LIB)
-
-PROGS = cva.exe,\
- dinoshade.exe,\
- fogcoord.exe,\
- manytex.exe,\
- multipal.exe,\
- projtex.exe,\
- seccolor.exe,\
- sharedtex.exe,\
- texline.exe,\
- texwrap.exe,\
- vptest1.exe,\
- vptest2.exe,\
- vptest3.exe,\
- vptorus.exe,\
- vpwarpmesh.exe
-
-##### RULES #####
-.obj.exe :
- cxxlink $(MMS$TARGET_NAME),$(GL_LIBS)
-
-##### TARGETS #####
-default :
- $(MMS)$(MMSQUALIFIERS) $(PROGS)
-
-clean :
- delete *.obj;*
-
-realclean :
- delete $(PROGS)
- delete *.obj;*
-
-cva.exe : cva.obj $(LIB_DEP)
-dinoshade.exe : dinoshade.obj $(LIB_DEP)
-fogcoord.exe : fogcoord.obj $(LIB_DEP)
-manytex.exe : manytex.obj $(LIB_DEP)
-multipal.exe : multipal.obj $(LIB_DEP)
-projtex.exe : projtex.obj $(LIB_DEP)
-seccolor.exe : seccolor.obj $(LIB_DEP)
-sharedtex.exe : sharedtex.obj $(LIB_DEP)
-texline.exe : texline.obj $(LIB_DEP)
-texwrap.exe : texwrap.obj $(LIB_DEP)
-vptest1.exe : vptest1.obj $(LIB_DEP)
-vptest2.exe : vptest2.obj $(LIB_DEP)
-vptest3.exe : vptest3.obj $(LIB_DEP)
-vptorus.exe : vptorus.obj $(LIB_DEP)
-vpwarpmesh.exe : vpwarpmesh.obj $(LIB_DEP)
-
-cva.obj : cva.c
-dinoshade.obj : dinoshade.c
-fogcoord.obj : fogcoord.c
-manytex.obj : manytex.c
-multipal.obj : multipal.c
-projtex.obj : projtex.c
-seccolor.obj : seccolor.c
-sharedtex.obj : sharedtex.c
-texline.obj : texline.c
-texwrap.obj : texwrap.c
-vptest1.obj : vptest1.c
-vptest2.obj : vptest2.c
-vptest3.obj : vptest3.c
-vptorus.obj : vptorus.c
-vpwarpmesh.obj : vpwarpmesh.c
diff --git a/progs/tests/minmag.c b/progs/tests/minmag.c
new file mode 100644
index 0000000000..78ef9db03a
--- /dev/null
+++ b/progs/tests/minmag.c
@@ -0,0 +1,198 @@
+/*
+ * Test minification vs. magnification filtering.
+ * Draw two quads with different filtering modes:
+ *
+ * +--------------------------+ +--------------------------+
+ * | MagFilter = GL_LINEAR | | MagFilter = GL_LINEAR |
+ * | MinFilter = GL_LINEAR | | MinFilter = GL_NEAREST |
+ * +--------------------------+ +--------------------------+
+ *
+ * They should look different when the quad is smaller than the level 0
+ * texture size (when minifying).
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <GL/glut.h>
+
+
+static GLint Width = 1000, Height = 500;
+
+
+static GLint TexWidth = 256, TexHeight = 256;
+static GLfloat Zpos = 5;
+static GLboolean MipMap = 0*GL_TRUE;
+static GLboolean LinearFilter = GL_TRUE;
+
+
+static void
+redraw(void)
+{
+ GLfloat w = 1.0;
+ GLfloat h = 1.0;
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ glPushMatrix();
+ glTranslatef(-1.5, 0, -Zpos);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-w, -h);
+ glTexCoord2f(1, 0); glVertex2f( w, -h);
+ glTexCoord2f(1, 1); glVertex2f( w, h);
+ glTexCoord2f(0, 1); glVertex2f(-w, h);
+ glEnd();
+ glPopMatrix();
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glPushMatrix();
+ glTranslatef(1.5, 0, -Zpos);
+ glBegin(GL_POLYGON);
+ glTexCoord2f(0, 0); glVertex2f(-w, -h);
+ glTexCoord2f(1, 0); glVertex2f( w, -h);
+ glTexCoord2f(1, 1); glVertex2f( w, h);
+ glTexCoord2f(0, 1); glVertex2f(-w, h);
+ glEnd();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void
+init(void)
+{
+ GLubyte color[10][4] = {
+ { 0, 0, 0, 0 },
+ { 1, 0, 0, 0 },
+ { 0, 1, 0, 0 },
+ { 0, 0, 1, 0 },
+ { 0, 1, 1, 0 },
+ { 1, 0, 1, 0 },
+ { 1, 1, 0, 0 },
+ { 1, 0, 0, 0 },
+ { 0, 1, 0, 0 },
+ { 0, 0, 1, 0 }
+ };
+ GLubyte *texImage;
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("Left quad should be linear filtered and right should be nearest filtered.\n");
+ printf("Press z/Z to change quad distance.\n");
+
+ texImage = (GLubyte*) malloc(4 * TexWidth * TexHeight * sizeof(GLubyte));
+ assert(texImage);
+
+ {
+ GLint level = 0;
+ GLint w = TexWidth, h = TexHeight;
+ while (1) {
+ int i, j;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0;j < w; j++) {
+ if (w==1 || h==1 || (((i / 2) ^ (j / 2)) & 1)) {
+ /*if (j < i) {*/
+ texImage[(i*w+j) * 4 + 0] = 255;
+ texImage[(i*w+j) * 4 + 1] = 255;
+ texImage[(i*w+j) * 4 + 2] = 255;
+ texImage[(i*w+j) * 4 + 3] = 255;
+ }
+ else {
+ texImage[(i*w+j) * 4 + 0] = color[level][0] * 255;
+ texImage[(i*w+j) * 4 + 1] = color[level][1] * 255;
+ texImage[(i*w+j) * 4 + 2] = color[level][2] * 255;
+ texImage[(i*w+j) * 4 + 3] = color[level][3] * 255;
+ }
+ }
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, w, h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, texImage);
+
+ printf("Texture level %d: %d x %d\n", level, w, h);
+ if (!MipMap)
+ break;
+
+ if (w == 1 && h == 1)
+ break;
+ if (w > 1)
+ w /= 2;
+ if (h > 1)
+ h /= 2;
+ level++;
+ }
+ }
+
+ free(texImage);
+
+ glClearColor(0.25, 0.25, 0.25, 1.0);
+ glEnable(GL_TEXTURE_2D);
+
+ glViewport(0, 0, Width, Height);
+}
+
+
+
+static void
+Reshape(int width, int height)
+{
+ float ar = (float) width /height;
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-ar, ar, -1.0, 1.0, 5.0, 2500.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -15.0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 'z':
+ Zpos--;
+ break;
+ case 'Z':
+ Zpos++;
+ break;
+ case 'f':
+ LinearFilter = !LinearFilter;
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow(argv[0]);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(redraw);
+ init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/progs/tests/subtex.c b/progs/tests/subtex.c
new file mode 100644
index 0000000000..81ceb085aa
--- /dev/null
+++ b/progs/tests/subtex.c
@@ -0,0 +1,223 @@
+/*
+ * Test glTexSubImage mid-way through a frame.
+ *
+ * The same texture is used for both quads but it gets redefined
+ * with glTexSubImage (or glTexImage) after the first quad.
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "GL/glut.h"
+
+static GLuint Window = 0;
+static GLboolean Anim = GL_FALSE;
+static GLfloat Angle = 0.0f;
+
+
+
+static void
+first_texture(void)
+{
+ static int width=8, height=8;
+ static GLubyte tex1[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ GLubyte tex[64][3];
+ GLint i, j;
+
+ /* red on white */
+ for (i=0;i<height;i++) {
+ for (j=0;j<width;j++) {
+ int p = i*width+j;
+ if (tex1[(height-i-1)*width+j]) {
+ tex[p][0] = 255; tex[p][1] = 0; tex[p][2] = 0;
+ }
+ else {
+ tex[p][0] = 255; tex[p][1] = 255; tex[p][2] = 255;
+ }
+ }
+ }
+
+ glTexImage2D( GL_TEXTURE_2D, 0, 3, width, height, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, tex );
+}
+
+
+static void
+second_texture(void)
+{
+ static int width=8, height=8;
+
+ static GLubyte tex2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 2, 0, 0, 0,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ GLubyte tex[64][3];
+ GLint i, j;
+
+ /* green on blue */
+ for (i=0;i<height;i++) {
+ for (j=0;j<width;j++) {
+ int p = i*width+j;
+ if (tex2[(height-i-1)*width+j]) {
+ tex[p][0] = 0; tex[p][1] = 255; tex[p][2] = 0;
+ }
+ else {
+ tex[p][0] = 0; tex[p][1] = 0; tex[p][2] = 255;
+ }
+ }
+ }
+#if 0
+ glTexImage2D( GL_TEXTURE_2D, 0, 3, width, height, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, tex );
+#else
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
+ GL_RGB, GL_UNSIGNED_BYTE, tex );
+#endif
+}
+
+
+
+static void draw( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glColor3f( 1.0, 1.0, 1.0 );
+
+ /* draw first polygon */
+ glPushMatrix();
+ glTranslatef( -1.0, 0.0, 0.0 );
+ glRotatef( Angle, 0.0, 0.0, 1.0 );
+
+ first_texture();
+
+ glBegin( GL_POLYGON );
+ glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, -1.0 );
+ glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, -1.0 );
+ glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, 1.0 );
+ glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, 1.0 );
+ glEnd();
+ glPopMatrix();
+
+ /* draw second polygon */
+ glPushMatrix();
+ glTranslatef( 1.0, 0.0, 0.0 );
+ glRotatef( Angle-90.0, 0.0, 1.0, 0.0 );
+
+ second_texture();
+
+ glBegin( GL_POLYGON );
+ glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, -1.0 );
+ glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, -1.0 );
+ glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, 1.0 );
+ glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, 1.0 );
+ glEnd();
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+
+static void idle( void )
+{
+ static double t0 = -1.;
+ double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+ if (t0 < 0.0)
+ t0 = t;
+ dt = t - t0;
+ t0 = t;
+ Angle += 120.0*dt;
+ glutPostRedisplay();
+}
+
+
+
+/* change view Angle, exit upon ESC */
+static void key(unsigned char k, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (k) {
+ case 'a':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc( idle );
+ else
+ glutIdleFunc( NULL );
+ break;
+ case 27:
+ glutDestroyWindow(Window);
+ exit(0);
+ }
+}
+
+
+
+/* new window size or exposure */
+static void reshape( int width, int height )
+{
+ glViewport(0, 0, (GLint)width, (GLint)height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ /* glOrtho( -3.0, 3.0, -3.0, 3.0, -10.0, 10.0 );*/
+ glFrustum( -2.0, 2.0, -2.0, 2.0, 6.0, 20.0 );
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -8.0 );
+}
+
+
+static void init( void )
+{
+ /* Setup texturing */
+ glEnable( GL_TEXTURE_2D );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
+
+
+ glBindTexture( GL_TEXTURE_2D, 0 );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(300, 300);
+ glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
+
+ Window = glutCreateWindow("Texture Objects");
+ if (!Window) {
+ exit(1);
+ }
+
+ init();
+
+ glutReshapeFunc( reshape );
+ glutKeyboardFunc( key );
+ if (Anim)
+ glutIdleFunc( idle );
+ glutDisplayFunc( draw );
+ glutMainLoop();
+ return 0;
+}