Convert libGL and DRI drivers to require libdrm.
[mesa-demos.git] / src / tests / debugger.c
blob4c6955bcfc64c9d7c69e65f6902ec7d7e7cd3c24
1 /*
2 * Test the GL_MESA_program_debug extension
3 */
6 #include <assert.h>
7 #include <ctype.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #define GL_GLEXT_PROTOTYPES
13 #include <GL/glut.h>
17 * Print the string with line numbers
19 static void list_program(const GLubyte *string, GLsizei len)
21 const char *c = (const char *) string;
22 int i, line = 1, printNumber = 1;
24 for (i = 0; i < len; i++) {
25 if (printNumber) {
26 printf("%3d ", line);
27 printNumber = 0;
29 if (*c == '\n') {
30 line++;
31 printNumber = 1;
33 putchar(*c);
34 c++;
36 putchar('\n');
41 * Return the line number and column number that corresponds to the
42 * given program position. Also return a null-terminated copy of that
43 * line of the program string.
45 static const GLubyte *
46 find_line_column(const GLubyte *string, const GLubyte *pos,
47 GLint *line, GLint *col)
49 const GLubyte *lineStart = string;
50 const GLubyte *p = string;
51 GLubyte *s;
52 int len;
54 *line = 1;
56 while (p != pos) {
57 if (*p == (GLubyte) '\n') {
58 (*line)++;
59 lineStart = p + 1;
61 p++;
64 *col = (pos - lineStart) + 1;
66 /* return copy of this line */
67 while (*p != 0 && *p != '\n')
68 p++;
69 len = p - lineStart;
70 s = (GLubyte *) malloc(len + 1);
71 memcpy(s, lineStart, len);
72 s[len] = 0;
74 return s;
78 #define ARB_VERTEX_PROGRAM 1
79 #define ARB_FRAGMENT_PROGRAM 2
80 #define NV_VERTEX_PROGRAM 3
81 #define NV_FRAGMENT_PROGRAM 4
84 struct breakpoint {
85 enum {PIXEL, LINE} type;
86 int x, y;
87 int line;
88 GLboolean enabled;
91 #define MAX_BREAKPOINTS 100
92 static struct breakpoint Breakpoints[MAX_BREAKPOINTS];
93 static int NumBreakpoints = 0;
98 * Interactive debugger
100 static void Debugger2(GLenum target, GLvoid *data)
102 static GLuint skipCount = 0;
103 const GLubyte *ln;
104 GLint pos, line, column;
105 GLint id;
106 int progType;
107 GLint len;
108 GLubyte *program;
109 GLboolean stop;
110 int i;
112 /* Sigh, GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV so it's a bit
113 * hard to distinguish between them.
115 if (target == GL_FRAGMENT_PROGRAM_ARB)
116 progType = ARB_FRAGMENT_PROGRAM;
117 else if (target == GL_FRAGMENT_PROGRAM_NV)
118 progType = NV_FRAGMENT_PROGRAM;
119 else
120 progType = NV_VERTEX_PROGRAM;
122 /* Until we hit zero, continue rendering */
123 if (skipCount > 0) {
124 skipCount--;
125 return;
128 /* Get id of the program and current position */
129 switch (progType) {
130 case ARB_FRAGMENT_PROGRAM:
131 glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
132 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
133 break;
134 case NV_FRAGMENT_PROGRAM:
135 glGetIntegerv(GL_FRAGMENT_PROGRAM_BINDING_NV, &id);
136 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
137 break;
138 case ARB_VERTEX_PROGRAM:
139 glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
140 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
141 break;
142 case NV_VERTEX_PROGRAM:
143 glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &id);
144 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
145 break;
146 default:
147 abort();
150 /* get program string */
151 if (progType == ARB_VERTEX_PROGRAM ||
152 progType == ARB_FRAGMENT_PROGRAM)
153 glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &len);
154 else
155 glGetProgramivNV(id, GL_PROGRAM_LENGTH_NV, &len);
156 program = malloc(len + 1);
157 if (progType == ARB_VERTEX_PROGRAM ||
158 progType == ARB_FRAGMENT_PROGRAM)
159 glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, program);
160 else
161 glGetProgramStringNV(id, GL_PROGRAM_STRING_NV, program);
164 /* Get current line number, column, line string */
165 ln = find_line_column(program, program + pos, &line, &column);
167 /* test breakpoints */
168 if (NumBreakpoints > 0)
169 stop = GL_FALSE;
170 else
171 stop = GL_TRUE;
172 for (i = 0; i < NumBreakpoints; i++) {
173 if (Breakpoints[i].enabled) {
174 switch (Breakpoints[i].type) {
175 case PIXEL:
176 if (progType == ARB_FRAGMENT_PROGRAM) {
179 else if (progType == NV_FRAGMENT_PROGRAM) {
180 GLfloat pos[4];
181 int px, py;
182 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
183 6, (GLubyte *) "f[WPOS]", pos);
184 px = (int) pos[0];
185 py = (int) pos[1];
186 printf("%d, %d\n", px, py);
187 if (px == Breakpoints[i].x &&
188 py == Breakpoints[i].y) {
189 printf("Break at pixel (%d, %d)\n", px, py);
190 stop = GL_TRUE;
193 break;
194 case LINE:
195 if (line == Breakpoints[i].line) {
196 /* hit a breakpoint! */
197 printf("Break at line %d\n", line);
198 stop = GL_TRUE;
200 break;
204 if (!stop) {
205 free(program);
206 return;
209 printf("%d: %s\n", line, ln);
211 /* get commands from stdin */
212 while (1) {
213 char command[1000], *cmd;
215 /* print prompt and get command */
216 printf("(%s %d) ", (target == GL_VERTEX_PROGRAM_ARB ? "vert" : "frag"),
217 line);
218 fgets(command, 999, stdin);
220 /* skip leading whitespace */
221 for (cmd = command; cmd[0] == ' '; cmd++)
224 if (!cmd[0])
225 /* nothing (repeat the previous cmd?) */
226 continue;
228 switch (cmd[0]) {
229 case 's':
230 /* skip N instructions */
231 i = atoi(cmd + 2);
232 skipCount = i;
233 printf("Skipping %d instructions\n", i);
234 return;
235 case 'n':
236 /* next */
237 return;
238 case 'c':
239 return;
240 case 'd':
241 /* dump machine state */
242 if (progType == NV_FRAGMENT_PROGRAM) {
243 static const char *inRegs[] = {
244 "f[WPOS]", "f[COL0]", "f[COL1]", "f[FOGC]",
245 "f[TEX0]", "f[TEX1]", "f[TEX2]", "f[TEX3]",
246 NULL
248 static const char *outRegs[] = {
249 "o[COLR]", "o[COLH]", "o[DEPR]", NULL
251 GLfloat v[4];
252 int i;
253 printf("Fragment input attributes:\n");
254 for (i = 0; inRegs[i]; i++) {
255 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
256 strlen(inRegs[i]),
257 (const GLubyte *) inRegs[i], v);
258 printf(" %s: %g, %g, %g, %g\n", inRegs[i],
259 v[0], v[1], v[2], v[3]);
261 printf("Fragment output attributes:\n");
262 for (i = 0; outRegs[i]; i++) {
263 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
264 strlen(outRegs[i]),
265 (const GLubyte *) outRegs[i], v);
266 printf(" %s: %g, %g, %g, %g\n", outRegs[i],
267 v[0], v[1], v[2], v[3]);
269 printf("Temporaries:\n");
270 for (i = 0; i < 4; i++) {
271 char temp[100];
272 GLfloat v[4];
273 sprintf(temp, "R%d", i);
274 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
275 strlen(temp),
276 (const GLubyte *) temp, v);
277 printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
280 else if (progType == NV_VERTEX_PROGRAM) {
281 GLfloat v[4];
282 int i;
283 static const char *inRegs[] = {
284 "v[OPOS]", "v[WGHT]", "v[NRML]", "v[COL0]",
285 "v[COL1]", "v[FOGC]", "v[6]", "v[7]",
286 "v[TEX0]", "v[TEX1]", "v[TEX2]", "v[TEX3]",
287 "v[TEX4]", "v[TEX5]", "v[TEX6]", "v[TEX7]",
288 NULL
290 static const char *outRegs[] = {
291 "o[HPOS]", "o[COL0]", "o[COL1]", "o[BFC0]",
292 "o[BFC1]", "o[FOGC]", "o[PSIZ]",
293 "o[TEX0]", "o[TEX1]", "o[TEX2]", "o[TEX3]",
294 "o[TEX4]", "o[TEX5]", "o[TEX6]", "o[TEX7]",
295 NULL
297 printf("Vertex input attributes:\n");
298 for (i = 0; inRegs[i]; i++) {
299 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
300 strlen(inRegs[i]),
301 (const GLubyte *) inRegs[i], v);
302 printf(" %s: %g, %g, %g, %g\n", inRegs[i],
303 v[0], v[1], v[2], v[3]);
305 printf("Vertex output attributes:\n");
306 for (i = 0; outRegs[i]; i++) {
307 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
308 strlen(outRegs[i]),
309 (const GLubyte *) outRegs[i], v);
310 printf(" %s: %g, %g, %g, %g\n", outRegs[i],
311 v[0], v[1], v[2], v[3]);
313 printf("Temporaries:\n");
314 for (i = 0; i < 4; i++) {
315 char temp[100];
316 GLfloat v[4];
317 sprintf(temp, "R%d", i);
318 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
319 strlen(temp),
320 (const GLubyte *) temp, v);
321 printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
324 break;
325 case 'l':
326 /* list */
327 list_program(program, len);
328 break;
329 case 'p':
330 /* print */
332 GLfloat v[4];
333 char *c;
334 cmd++;
335 while (*cmd == ' ')
336 cmd++;
337 c = cmd;
338 while (*c) {
339 if (*c == '\n' || *c == '\r')
340 *c = 0;
341 else
342 c++;
344 glGetProgramRegisterfvMESA(target, strlen(cmd),
345 (const GLubyte *) cmd, v);
346 if (glGetError() == GL_NO_ERROR)
347 printf("%s = %g, %g, %g, %g\n", cmd, v[0], v[1], v[2], v[3]);
348 else
349 printf("Invalid expression\n");
351 break;
352 case 'b':
353 if (cmd[1] == ' ' && isdigit(cmd[2])) {
354 char *comma = strchr(cmd, ',');
355 if (comma) {
356 /* break at pixel */
357 int x = atoi(cmd + 2);
358 int y = atoi(comma + 1);
359 if (NumBreakpoints < MAX_BREAKPOINTS) {
360 Breakpoints[NumBreakpoints].type = PIXEL;
361 Breakpoints[NumBreakpoints].x = x;
362 Breakpoints[NumBreakpoints].y = y;
363 Breakpoints[NumBreakpoints].enabled = GL_TRUE;
364 NumBreakpoints++;
365 printf("Breakpoint %d: break at pixel (%d, %d)\n",
366 NumBreakpoints, x, y);
369 else {
370 /* break at line */
371 int l = atoi(cmd + 2);
372 if (l && NumBreakpoints < MAX_BREAKPOINTS) {
373 Breakpoints[NumBreakpoints].type = LINE;
374 Breakpoints[NumBreakpoints].line = l;
375 Breakpoints[NumBreakpoints].enabled = GL_TRUE;
376 NumBreakpoints++;
377 printf("Breakpoint %d: break at line %d\n",
378 NumBreakpoints, l);
382 else {
383 /* list breakpoints */
384 printf("Breakpoints:\n");
385 for (i = 0; i < NumBreakpoints; i++) {
386 switch (Breakpoints[i].type) {
387 case LINE:
388 printf(" %d: break at line %d\n",
389 i + 1, Breakpoints[i].line);
390 break;
391 case PIXEL:
392 printf(" %d: break at pixel (%d, %d)\n",
393 i + 1, Breakpoints[i].x, Breakpoints[i].y);
394 break;
398 break;
399 case 'h':
400 /* help */
401 printf("Debugger commands:\n");
402 printf(" b list breakpoints\n");
403 printf(" b N break at line N\n");
404 printf(" b x,y break at pixel x,y\n");
405 printf(" c continue execution\n");
406 printf(" d display register values\n");
407 printf(" h help\n");
408 printf(" l list program\n");
409 printf(" n next instruction\n");
410 printf(" p V print value V\n");
411 printf(" s N skip N instructions\n");
412 break;
413 default:
414 printf("Unknown command: %c\n", cmd[0]);
421 * Print current line, some registers, and continue.
423 static void Debugger(GLenum target, GLvoid *data)
425 GLint pos;
426 const GLubyte *ln;
427 GLint line, column;
428 GLfloat v[4];
430 assert(target == GL_FRAGMENT_PROGRAM_NV);
432 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
434 ln = find_line_column((const GLubyte *) data, (const GLubyte *) data + pos,
435 &line, &column);
436 printf("%d:%d: %s\n", line, column, (char *) ln);
438 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
439 2, (const GLubyte *) "R0", v);
440 printf(" R0 = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
441 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
442 7, (const GLubyte *) "f[WPOS]", v);
443 printf(" o[WPOS] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
444 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
445 7, (const GLubyte *) "o[COLR]", v);
446 printf(" o[COLR] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
448 free((void *) ln);
454 /**********************************************************************/
456 static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
457 static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
458 static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
459 static GLfloat Delta = 1.0;
461 static GLuint FragProg;
462 static GLuint VertProg;
463 static GLboolean Anim = GL_TRUE;
464 static GLboolean Wire = GL_FALSE;
465 static GLboolean PixelLight = GL_TRUE;
467 static GLfloat Xrot = 0, Yrot = 0;
470 #define NAMED_PARAMETER4FV(prog, name, v) \
471 glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v)
474 static void Display( void )
476 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
478 if (PixelLight) {
479 NAMED_PARAMETER4FV(FragProg, "LightPos", LightPos);
480 glEnable(GL_FRAGMENT_PROGRAM_NV);
481 glEnable(GL_VERTEX_PROGRAM_NV);
482 glDisable(GL_LIGHTING);
484 else {
485 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
486 glDisable(GL_FRAGMENT_PROGRAM_NV);
487 glDisable(GL_VERTEX_PROGRAM_NV);
488 glEnable(GL_LIGHTING);
491 glPushMatrix();
492 glRotatef(Xrot, 1, 0, 0);
493 glRotatef(Yrot, 0, 1, 0);
495 #if 1
496 glutSolidSphere(2.0, 10, 5);
497 #else
499 GLUquadricObj *q = gluNewQuadric();
500 gluQuadricNormals(q, GL_SMOOTH);
501 gluQuadricTexture(q, GL_TRUE);
502 glRotatef(90, 1, 0, 0);
503 glTranslatef(0, 0, -1);
504 gluCylinder(q, 1.0, 1.0, 2.0, 24, 1);
505 gluDeleteQuadric(q);
507 #endif
509 glPopMatrix();
511 glutSwapBuffers();
515 static void Idle(void)
517 LightPos[0] += Delta;
518 if (LightPos[0] > 25.0)
519 Delta = -1.0;
520 else if (LightPos[0] <- 25.0)
521 Delta = 1.0;
522 glutPostRedisplay();
526 static void Reshape( int width, int height )
528 glViewport( 0, 0, width, height );
529 glMatrixMode( GL_PROJECTION );
530 glLoadIdentity();
531 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
532 /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
533 glMatrixMode( GL_MODELVIEW );
534 glLoadIdentity();
535 glTranslatef( 0.0, 0.0, -15.0 );
539 static void Key( unsigned char key, int x, int y )
541 (void) x;
542 (void) y;
543 switch (key) {
544 case ' ':
545 Anim = !Anim;
546 if (Anim)
547 glutIdleFunc(Idle);
548 else
549 glutIdleFunc(NULL);
550 break;
551 case 'x':
552 LightPos[0] -= 1.0;
553 break;
554 case 'X':
555 LightPos[0] += 1.0;
556 break;
557 case 'w':
558 Wire = !Wire;
559 if (Wire)
560 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
561 else
562 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
563 break;
564 case 'p':
565 PixelLight = !PixelLight;
566 if (PixelLight) {
567 printf("Per-pixel lighting\n");
569 else {
570 printf("Conventional lighting\n");
572 break;
573 case 27:
574 exit(0);
575 break;
577 glutPostRedisplay();
580 static void SpecialKey( int key, int x, int y )
582 const GLfloat step = 3.0;
583 (void) x;
584 (void) y;
585 switch (key) {
586 case GLUT_KEY_UP:
587 Xrot -= step;
588 break;
589 case GLUT_KEY_DOWN:
590 Xrot += step;
591 break;
592 case GLUT_KEY_LEFT:
593 Yrot -= step;
594 break;
595 case GLUT_KEY_RIGHT:
596 Yrot += step;
597 break;
599 glutPostRedisplay();
603 static void Init( int argc, char *argv[] )
605 static const char *fragProgramText =
606 "!!FP1.0\n"
607 "DECLARE Diffuse; \n"
608 "DECLARE Specular; \n"
609 "DECLARE LightPos; \n"
611 "# Compute normalized LightPos, put it in R0\n"
612 "DP3 R0.x, LightPos, LightPos;\n"
613 "RSQ R0.y, R0.x;\n"
614 "MUL R0, LightPos, R0.y;\n"
616 "# Compute normalized normal, put it in R1\n"
617 "DP3 R1, f[TEX0], f[TEX0]; \n"
618 "RSQ R1.y, R1.x;\n"
619 "MUL R1, f[TEX0], R1.y;\n"
621 "# Compute dot product of light direction and normal vector\n"
622 "DP3 R2, R0, R1;\n"
624 "MUL R3, Diffuse, R2; # diffuse attenuation\n"
626 "POW R4, R2.x, {20.0}.x; # specular exponent\n"
628 "MUL R5, Specular, R4; # specular attenuation\n"
630 "ADD o[COLR], R3, R5; # add diffuse and specular colors\n"
631 "END \n"
634 static const char *vertProgramText =
635 "!!VP1.0\n"
636 "# typical modelview/projection transform\n"
637 "DP4 o[HPOS].x, c[0], v[OPOS] ;\n"
638 "DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
639 "DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
640 "DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
641 "# transform normal by inv transpose of modelview, put in tex0\n"
642 "DP4 o[TEX0].x, c[4], v[NRML] ;\n"
643 "DP4 o[TEX0].y, c[5], v[NRML] ;\n"
644 "DP4 o[TEX0].z, c[6], v[NRML] ;\n"
645 "DP4 o[TEX0].w, c[7], v[NRML] ;\n"
646 "END\n";
649 if (!glutExtensionSupported("GL_NV_vertex_program")) {
650 printf("Sorry, this demo requires GL_NV_vertex_program\n");
651 exit(1);
653 if (!glutExtensionSupported("GL_NV_fragment_program")) {
654 printf("Sorry, this demo requires GL_NV_fragment_program\n");
655 exit(1);
658 glGenProgramsNV(1, &FragProg);
659 assert(FragProg > 0);
660 glGenProgramsNV(1, &VertProg);
661 assert(VertProg > 0);
664 * Fragment program
666 glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg,
667 strlen(fragProgramText),
668 (const GLubyte *) fragProgramText);
669 assert(glIsProgramNV(FragProg));
670 glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg);
672 NAMED_PARAMETER4FV(FragProg, "Diffuse", Diffuse);
673 NAMED_PARAMETER4FV(FragProg, "Specular", Specular);
676 * Vertex program
678 glLoadProgramNV(GL_VERTEX_PROGRAM_NV, VertProg,
679 strlen(vertProgramText),
680 (const GLubyte *) vertProgramText);
681 assert(glIsProgramNV(VertProg));
682 glBindProgramNV(GL_VERTEX_PROGRAM_NV, VertProg);
683 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
684 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
687 * Misc init
689 glClearColor(0.3, 0.3, 0.3, 0.0);
690 glEnable(GL_DEPTH_TEST);
691 glEnable(GL_LIGHT0);
692 glEnable(GL_LIGHTING);
693 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
694 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
695 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
697 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
698 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
700 #ifdef GL_MESA_program_debug
701 if (argc > 1 && strcmp(argv[1], "fragment") == 0) {
702 printf(">> Debugging fragment program\n");
703 glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB, Debugger2,
704 (GLvoid *) fragProgramText);
705 glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA);
707 else {
708 printf(">> Debugging vertex program\n");
709 glProgramCallbackMESA(GL_VERTEX_PROGRAM_ARB, Debugger2,
710 (GLvoid *) fragProgramText);
711 glEnable(GL_VERTEX_PROGRAM_CALLBACK_MESA);
713 #endif
717 int main( int argc, char *argv[] )
719 glutInit( &argc, argv );
720 glutInitWindowPosition( 0, 0 );
721 glutInitWindowSize( 200, 200 );
722 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
723 glutCreateWindow(argv[0]);
724 glutReshapeFunc( Reshape );
725 glutKeyboardFunc( Key );
726 glutSpecialFunc( SpecialKey );
727 glutDisplayFunc( Display );
728 if (Anim)
729 glutIdleFunc(Idle);
730 Init(argc, argv);
731 glutMainLoop();
732 return 0;