summaryrefslogtreecommitdiffstats
path: root/progs/tests/debugger.c
diff options
context:
space:
mode:
Diffstat (limited to 'progs/tests/debugger.c')
-rw-r--r--progs/tests/debugger.c733
1 files changed, 733 insertions, 0 deletions
diff --git a/progs/tests/debugger.c b/progs/tests/debugger.c
new file mode 100644
index 00000000000..4c6955bcfc6
--- /dev/null
+++ b/progs/tests/debugger.c
@@ -0,0 +1,733 @@
+/*
+ * Test the GL_MESA_program_debug extension
+ */
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+
+/*
+ * Print the string with line numbers
+ */
+static void list_program(const GLubyte *string, GLsizei len)
+{
+ const char *c = (const char *) string;
+ int i, line = 1, printNumber = 1;
+
+ for (i = 0; i < len; i++) {
+ if (printNumber) {
+ printf("%3d ", line);
+ printNumber = 0;
+ }
+ if (*c == '\n') {
+ line++;
+ printNumber = 1;
+ }
+ putchar(*c);
+ c++;
+ }
+ putchar('\n');
+}
+
+
+/*
+ * Return the line number and column number that corresponds to the
+ * given program position. Also return a null-terminated copy of that
+ * line of the program string.
+ */
+static const GLubyte *
+find_line_column(const GLubyte *string, const GLubyte *pos,
+ GLint *line, GLint *col)
+{
+ const GLubyte *lineStart = string;
+ const GLubyte *p = string;
+ GLubyte *s;
+ int len;
+
+ *line = 1;
+
+ while (p != pos) {
+ if (*p == (GLubyte) '\n') {
+ (*line)++;
+ lineStart = p + 1;
+ }
+ p++;
+ }
+
+ *col = (pos - lineStart) + 1;
+
+ /* return copy of this line */
+ while (*p != 0 && *p != '\n')
+ p++;
+ len = p - lineStart;
+ s = (GLubyte *) malloc(len + 1);
+ memcpy(s, lineStart, len);
+ s[len] = 0;
+
+ return s;
+}
+
+
+#define ARB_VERTEX_PROGRAM 1
+#define ARB_FRAGMENT_PROGRAM 2
+#define NV_VERTEX_PROGRAM 3
+#define NV_FRAGMENT_PROGRAM 4
+
+
+struct breakpoint {
+ enum {PIXEL, LINE} type;
+ int x, y;
+ int line;
+ GLboolean enabled;
+};
+
+#define MAX_BREAKPOINTS 100
+static struct breakpoint Breakpoints[MAX_BREAKPOINTS];
+static int NumBreakpoints = 0;
+
+
+
+/*
+ * Interactive debugger
+ */
+static void Debugger2(GLenum target, GLvoid *data)
+{
+ static GLuint skipCount = 0;
+ const GLubyte *ln;
+ GLint pos, line, column;
+ GLint id;
+ int progType;
+ GLint len;
+ GLubyte *program;
+ GLboolean stop;
+ int i;
+
+ /* Sigh, GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV so it's a bit
+ * hard to distinguish between them.
+ */
+ if (target == GL_FRAGMENT_PROGRAM_ARB)
+ progType = ARB_FRAGMENT_PROGRAM;
+ else if (target == GL_FRAGMENT_PROGRAM_NV)
+ progType = NV_FRAGMENT_PROGRAM;
+ else
+ progType = NV_VERTEX_PROGRAM;
+
+ /* Until we hit zero, continue rendering */
+ if (skipCount > 0) {
+ skipCount--;
+ return;
+ }
+
+ /* Get id of the program and current position */
+ switch (progType) {
+ case ARB_FRAGMENT_PROGRAM:
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
+ break;
+ case NV_FRAGMENT_PROGRAM:
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_BINDING_NV, &id);
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
+ break;
+ case ARB_VERTEX_PROGRAM:
+ glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
+ glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
+ break;
+ case NV_VERTEX_PROGRAM:
+ glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &id);
+ glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
+ break;
+ default:
+ abort();
+ }
+
+ /* get program string */
+ if (progType == ARB_VERTEX_PROGRAM ||
+ progType == ARB_FRAGMENT_PROGRAM)
+ glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &len);
+ else
+ glGetProgramivNV(id, GL_PROGRAM_LENGTH_NV, &len);
+ program = malloc(len + 1);
+ if (progType == ARB_VERTEX_PROGRAM ||
+ progType == ARB_FRAGMENT_PROGRAM)
+ glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, program);
+ else
+ glGetProgramStringNV(id, GL_PROGRAM_STRING_NV, program);
+
+
+ /* Get current line number, column, line string */
+ ln = find_line_column(program, program + pos, &line, &column);
+
+ /* test breakpoints */
+ if (NumBreakpoints > 0)
+ stop = GL_FALSE;
+ else
+ stop = GL_TRUE;
+ for (i = 0; i < NumBreakpoints; i++) {
+ if (Breakpoints[i].enabled) {
+ switch (Breakpoints[i].type) {
+ case PIXEL:
+ if (progType == ARB_FRAGMENT_PROGRAM) {
+
+ }
+ else if (progType == NV_FRAGMENT_PROGRAM) {
+ GLfloat pos[4];
+ int px, py;
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 6, (GLubyte *) "f[WPOS]", pos);
+ px = (int) pos[0];
+ py = (int) pos[1];
+ printf("%d, %d\n", px, py);
+ if (px == Breakpoints[i].x &&
+ py == Breakpoints[i].y) {
+ printf("Break at pixel (%d, %d)\n", px, py);
+ stop = GL_TRUE;
+ }
+ }
+ break;
+ case LINE:
+ if (line == Breakpoints[i].line) {
+ /* hit a breakpoint! */
+ printf("Break at line %d\n", line);
+ stop = GL_TRUE;
+ }
+ break;
+ }
+ }
+ }
+ if (!stop) {
+ free(program);
+ return;
+ }
+
+ printf("%d: %s\n", line, ln);
+
+ /* get commands from stdin */
+ while (1) {
+ char command[1000], *cmd;
+
+ /* print prompt and get command */
+ printf("(%s %d) ", (target == GL_VERTEX_PROGRAM_ARB ? "vert" : "frag"),
+ line);
+ fgets(command, 999, stdin);
+
+ /* skip leading whitespace */
+ for (cmd = command; cmd[0] == ' '; cmd++)
+ ;
+
+ if (!cmd[0])
+ /* nothing (repeat the previous cmd?) */
+ continue;
+
+ switch (cmd[0]) {
+ case 's':
+ /* skip N instructions */
+ i = atoi(cmd + 2);
+ skipCount = i;
+ printf("Skipping %d instructions\n", i);
+ return;
+ case 'n':
+ /* next */
+ return;
+ case 'c':
+ return;
+ case 'd':
+ /* dump machine state */
+ if (progType == NV_FRAGMENT_PROGRAM) {
+ static const char *inRegs[] = {
+ "f[WPOS]", "f[COL0]", "f[COL1]", "f[FOGC]",
+ "f[TEX0]", "f[TEX1]", "f[TEX2]", "f[TEX3]",
+ NULL
+ };
+ static const char *outRegs[] = {
+ "o[COLR]", "o[COLH]", "o[DEPR]", NULL
+ };
+ GLfloat v[4];
+ int i;
+ printf("Fragment input attributes:\n");
+ for (i = 0; inRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ strlen(inRegs[i]),
+ (const GLubyte *) inRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", inRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Fragment output attributes:\n");
+ for (i = 0; outRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ strlen(outRegs[i]),
+ (const GLubyte *) outRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", outRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Temporaries:\n");
+ for (i = 0; i < 4; i++) {
+ char temp[100];
+ GLfloat v[4];
+ sprintf(temp, "R%d", i);
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ strlen(temp),
+ (const GLubyte *) temp, v);
+ printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
+ }
+ }
+ else if (progType == NV_VERTEX_PROGRAM) {
+ GLfloat v[4];
+ int i;
+ static const char *inRegs[] = {
+ "v[OPOS]", "v[WGHT]", "v[NRML]", "v[COL0]",
+ "v[COL1]", "v[FOGC]", "v[6]", "v[7]",
+ "v[TEX0]", "v[TEX1]", "v[TEX2]", "v[TEX3]",
+ "v[TEX4]", "v[TEX5]", "v[TEX6]", "v[TEX7]",
+ NULL
+ };
+ static const char *outRegs[] = {
+ "o[HPOS]", "o[COL0]", "o[COL1]", "o[BFC0]",
+ "o[BFC1]", "o[FOGC]", "o[PSIZ]",
+ "o[TEX0]", "o[TEX1]", "o[TEX2]", "o[TEX3]",
+ "o[TEX4]", "o[TEX5]", "o[TEX6]", "o[TEX7]",
+ NULL
+ };
+ printf("Vertex input attributes:\n");
+ for (i = 0; inRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
+ strlen(inRegs[i]),
+ (const GLubyte *) inRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", inRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Vertex output attributes:\n");
+ for (i = 0; outRegs[i]; i++) {
+ glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
+ strlen(outRegs[i]),
+ (const GLubyte *) outRegs[i], v);
+ printf(" %s: %g, %g, %g, %g\n", outRegs[i],
+ v[0], v[1], v[2], v[3]);
+ }
+ printf("Temporaries:\n");
+ for (i = 0; i < 4; i++) {
+ char temp[100];
+ GLfloat v[4];
+ sprintf(temp, "R%d", i);
+ glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
+ strlen(temp),
+ (const GLubyte *) temp, v);
+ printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
+ }
+ }
+ break;
+ case 'l':
+ /* list */
+ list_program(program, len);
+ break;
+ case 'p':
+ /* print */
+ {
+ GLfloat v[4];
+ char *c;
+ cmd++;
+ while (*cmd == ' ')
+ cmd++;
+ c = cmd;
+ while (*c) {
+ if (*c == '\n' || *c == '\r')
+ *c = 0;
+ else
+ c++;
+ }
+ glGetProgramRegisterfvMESA(target, strlen(cmd),
+ (const GLubyte *) cmd, v);
+ if (glGetError() == GL_NO_ERROR)
+ printf("%s = %g, %g, %g, %g\n", cmd, v[0], v[1], v[2], v[3]);
+ else
+ printf("Invalid expression\n");
+ }
+ break;
+ case 'b':
+ if (cmd[1] == ' ' && isdigit(cmd[2])) {
+ char *comma = strchr(cmd, ',');
+ if (comma) {
+ /* break at pixel */
+ int x = atoi(cmd + 2);
+ int y = atoi(comma + 1);
+ if (NumBreakpoints < MAX_BREAKPOINTS) {
+ Breakpoints[NumBreakpoints].type = PIXEL;
+ Breakpoints[NumBreakpoints].x = x;
+ Breakpoints[NumBreakpoints].y = y;
+ Breakpoints[NumBreakpoints].enabled = GL_TRUE;
+ NumBreakpoints++;
+ printf("Breakpoint %d: break at pixel (%d, %d)\n",
+ NumBreakpoints, x, y);
+ }
+ }
+ else {
+ /* break at line */
+ int l = atoi(cmd + 2);
+ if (l && NumBreakpoints < MAX_BREAKPOINTS) {
+ Breakpoints[NumBreakpoints].type = LINE;
+ Breakpoints[NumBreakpoints].line = l;
+ Breakpoints[NumBreakpoints].enabled = GL_TRUE;
+ NumBreakpoints++;
+ printf("Breakpoint %d: break at line %d\n",
+ NumBreakpoints, l);
+ }
+ }
+ }
+ else {
+ /* list breakpoints */
+ printf("Breakpoints:\n");
+ for (i = 0; i < NumBreakpoints; i++) {
+ switch (Breakpoints[i].type) {
+ case LINE:
+ printf(" %d: break at line %d\n",
+ i + 1, Breakpoints[i].line);
+ break;
+ case PIXEL:
+ printf(" %d: break at pixel (%d, %d)\n",
+ i + 1, Breakpoints[i].x, Breakpoints[i].y);
+ break;
+ }
+ }
+ }
+ break;
+ case 'h':
+ /* help */
+ printf("Debugger commands:\n");
+ printf(" b list breakpoints\n");
+ printf(" b N break at line N\n");
+ printf(" b x,y break at pixel x,y\n");
+ printf(" c continue execution\n");
+ printf(" d display register values\n");
+ printf(" h help\n");
+ printf(" l list program\n");
+ printf(" n next instruction\n");
+ printf(" p V print value V\n");
+ printf(" s N skip N instructions\n");
+ break;
+ default:
+ printf("Unknown command: %c\n", cmd[0]);
+ }
+ }
+}
+
+
+/*
+ * Print current line, some registers, and continue.
+ */
+static void Debugger(GLenum target, GLvoid *data)
+{
+ GLint pos;
+ const GLubyte *ln;
+ GLint line, column;
+ GLfloat v[4];
+
+ assert(target == GL_FRAGMENT_PROGRAM_NV);
+
+ glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
+
+ ln = find_line_column((const GLubyte *) data, (const GLubyte *) data + pos,
+ &line, &column);
+ printf("%d:%d: %s\n", line, column, (char *) ln);
+
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 2, (const GLubyte *) "R0", v);
+ printf(" R0 = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 7, (const GLubyte *) "f[WPOS]", v);
+ printf(" o[WPOS] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
+ glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
+ 7, (const GLubyte *) "o[COLR]", v);
+ printf(" o[COLR] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
+
+ free((void *) ln);
+}
+
+
+
+
+/**********************************************************************/
+
+static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
+static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
+static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
+static GLfloat Delta = 1.0;
+
+static GLuint FragProg;
+static GLuint VertProg;
+static GLboolean Anim = GL_TRUE;
+static GLboolean Wire = GL_FALSE;
+static GLboolean PixelLight = GL_TRUE;
+
+static GLfloat Xrot = 0, Yrot = 0;
+
+
+#define NAMED_PARAMETER4FV(prog, name, v) \
+ glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v)
+
+
+static void Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ if (PixelLight) {
+ NAMED_PARAMETER4FV(FragProg, "LightPos", LightPos);
+ glEnable(GL_FRAGMENT_PROGRAM_NV);
+ glEnable(GL_VERTEX_PROGRAM_NV);
+ glDisable(GL_LIGHTING);
+ }
+ else {
+ glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+ glDisable(GL_FRAGMENT_PROGRAM_NV);
+ glDisable(GL_VERTEX_PROGRAM_NV);
+ glEnable(GL_LIGHTING);
+ }
+
+ glPushMatrix();
+ glRotatef(Xrot, 1, 0, 0);
+ glRotatef(Yrot, 0, 1, 0);
+
+#if 1
+ glutSolidSphere(2.0, 10, 5);
+#else
+ {
+ GLUquadricObj *q = gluNewQuadric();
+ gluQuadricNormals(q, GL_SMOOTH);
+ gluQuadricTexture(q, GL_TRUE);
+ glRotatef(90, 1, 0, 0);
+ glTranslatef(0, 0, -1);
+ gluCylinder(q, 1.0, 1.0, 2.0, 24, 1);
+ gluDeleteQuadric(q);
+ }
+#endif
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Idle(void)
+{
+ LightPos[0] += Delta;
+ if (LightPos[0] > 25.0)
+ Delta = -1.0;
+ else if (LightPos[0] <- 25.0)
+ Delta = 1.0;
+ glutPostRedisplay();
+}
+
+
+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 );
+ /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.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 ' ':
+ Anim = !Anim;
+ if (Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+ break;
+ case 'x':
+ LightPos[0] -= 1.0;
+ break;
+ case 'X':
+ LightPos[0] += 1.0;
+ break;
+ case 'w':
+ Wire = !Wire;
+ if (Wire)
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ else
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ break;
+ case 'p':
+ PixelLight = !PixelLight;
+ if (PixelLight) {
+ printf("Per-pixel lighting\n");
+ }
+ else {
+ printf("Conventional lighting\n");
+ }
+ break;
+ case 27:
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+static void SpecialKey( int key, int x, int y )
+{
+ const GLfloat step = 3.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 Init( int argc, char *argv[] )
+{
+ static const char *fragProgramText =
+ "!!FP1.0\n"
+ "DECLARE Diffuse; \n"
+ "DECLARE Specular; \n"
+ "DECLARE LightPos; \n"
+
+ "# Compute normalized LightPos, put it in R0\n"
+ "DP3 R0.x, LightPos, LightPos;\n"
+ "RSQ R0.y, R0.x;\n"
+ "MUL R0, LightPos, R0.y;\n"
+
+ "# Compute normalized normal, put it in R1\n"
+ "DP3 R1, f[TEX0], f[TEX0]; \n"
+ "RSQ R1.y, R1.x;\n"
+ "MUL R1, f[TEX0], R1.y;\n"
+
+ "# Compute dot product of light direction and normal vector\n"
+ "DP3 R2, R0, R1;\n"
+
+ "MUL R3, Diffuse, R2; # diffuse attenuation\n"
+
+ "POW R4, R2.x, {20.0}.x; # specular exponent\n"
+
+ "MUL R5, Specular, R4; # specular attenuation\n"
+
+ "ADD o[COLR], R3, R5; # add diffuse and specular colors\n"
+ "END \n"
+ ;
+
+ static const char *vertProgramText =
+ "!!VP1.0\n"
+ "# typical modelview/projection transform\n"
+ "DP4 o[HPOS].x, c[0], v[OPOS] ;\n"
+ "DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
+ "DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
+ "DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
+ "# transform normal by inv transpose of modelview, put in tex0\n"
+ "DP4 o[TEX0].x, c[4], v[NRML] ;\n"
+ "DP4 o[TEX0].y, c[5], v[NRML] ;\n"
+ "DP4 o[TEX0].z, c[6], v[NRML] ;\n"
+ "DP4 o[TEX0].w, c[7], v[NRML] ;\n"
+ "END\n";
+ ;
+
+ if (!glutExtensionSupported("GL_NV_vertex_program")) {
+ printf("Sorry, this demo requires GL_NV_vertex_program\n");
+ exit(1);
+ }
+ if (!glutExtensionSupported("GL_NV_fragment_program")) {
+ printf("Sorry, this demo requires GL_NV_fragment_program\n");
+ exit(1);
+ }
+
+ glGenProgramsNV(1, &FragProg);
+ assert(FragProg > 0);
+ glGenProgramsNV(1, &VertProg);
+ assert(VertProg > 0);
+
+ /*
+ * Fragment program
+ */
+ glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg,
+ strlen(fragProgramText),
+ (const GLubyte *) fragProgramText);
+ assert(glIsProgramNV(FragProg));
+ glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg);
+
+ NAMED_PARAMETER4FV(FragProg, "Diffuse", Diffuse);
+ NAMED_PARAMETER4FV(FragProg, "Specular", Specular);
+
+ /*
+ * Vertex program
+ */
+ glLoadProgramNV(GL_VERTEX_PROGRAM_NV, VertProg,
+ strlen(vertProgramText),
+ (const GLubyte *) vertProgramText);
+ assert(glIsProgramNV(VertProg));
+ glBindProgramNV(GL_VERTEX_PROGRAM_NV, VertProg);
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
+ glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
+
+ /*
+ * Misc init
+ */
+ glClearColor(0.3, 0.3, 0.3, 0.0);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHTING);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("Press p to toggle between per-pixel and per-vertex lighting\n");
+
+#ifdef GL_MESA_program_debug
+ if (argc > 1 && strcmp(argv[1], "fragment") == 0) {
+ printf(">> Debugging fragment program\n");
+ glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB, Debugger2,
+ (GLvoid *) fragProgramText);
+ glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA);
+ }
+ else {
+ printf(">> Debugging vertex program\n");
+ glProgramCallbackMESA(GL_VERTEX_PROGRAM_ARB, Debugger2,
+ (GLvoid *) fragProgramText);
+ glEnable(GL_VERTEX_PROGRAM_CALLBACK_MESA);
+ }
+#endif
+}
+
+
+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]);
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutSpecialFunc( SpecialKey );
+ glutDisplayFunc( Display );
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init(argc, argv);
+ glutMainLoop();
+ return 0;
+}