blob: fbebf77fd3e82da77123776adc86d633c0baf9b7 [file] [log] [blame]
Brian Paul5366b012003-07-21 04:22:59 +00001/*
2 * Test the GL_MESA_program_debug extension
3 */
4
5
6#include <assert.h>
7#include <string.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <math.h>
11#define GL_GLEXT_PROTOTYPES
12#include <GL/glut.h>
13
14
Brian Paul6a940e82003-07-22 03:53:44 +000015/*
16 * Print the string with line numbers
17 */
18static void list_program(const GLubyte *string, GLsizei len)
19{
20 const char *c = (const char *) string;
21 int i, line = 1, printNumber = 1;
Brian Paul5366b012003-07-21 04:22:59 +000022
Brian Paul6a940e82003-07-22 03:53:44 +000023 for (i = 0; i < len; i++) {
24 if (printNumber) {
25 printf("%3d ", line);
26 printNumber = 0;
27 }
28 if (*c == '\n') {
29 line++;
30 printNumber = 1;
31 }
32 putchar(*c);
33 c++;
34 }
35 putchar('\n');
36}
37
38
39/*
40 * Return the line number and column number that corresponds to the
41 * given program position. Also return a null-terminated copy of that
42 * line of the program string.
43 */
Brian Paul5366b012003-07-21 04:22:59 +000044static const GLubyte *
45find_line_column(const GLubyte *string, const GLubyte *pos,
46 GLint *line, GLint *col)
47{
48 const GLubyte *lineStart = string;
49 const GLubyte *p = string;
50 GLubyte *s;
51 int len;
52
53 *line = 1;
54
55 while (p != pos) {
56 if (*p == (GLubyte) '\n') {
57 (*line)++;
58 lineStart = p + 1;
59 }
60 p++;
61 }
62
63 *col = (pos - lineStart) + 1;
64
65 /* return copy of this line */
66 while (*p != 0 && *p != '\n')
67 p++;
68 len = p - lineStart;
69 s = (GLubyte *) malloc(len + 1);
70 memcpy(s, lineStart, len);
71 s[len] = 0;
72
73 return s;
74}
75
76
Brian Paul6a940e82003-07-22 03:53:44 +000077#define ARB_VERTEX_PROGRAM 1
78#define ARB_FRAGMENT_PROGRAM 2
79#define NV_VERTEX_PROGRAM 3
80#define NV_FRAGMENT_PROGRAM 4
81
82
83/*
84 * Interactive debugger
85 */
86static void Debugger2(GLenum target, GLvoid *data)
87{
88 static GLboolean continueFlag = GL_FALSE;
89 const GLubyte *ln;
90 GLint pos, line, column;
91 GLint id;
92 int progType;
93 GLint len;
94 GLubyte *program;
95
96 /* Sigh, GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV so it's a bit
97 * hard to distinguish between them.
98 */
99 if (target == GL_FRAGMENT_PROGRAM_ARB)
100 progType = ARB_FRAGMENT_PROGRAM;
101 else if (target == GL_FRAGMENT_PROGRAM_NV)
102 progType = NV_FRAGMENT_PROGRAM;
103 else
104 progType = NV_VERTEX_PROGRAM;
105
106
107 if (continueFlag)
108 return;
109
110 /* Get id of the program and current position */
111 switch (progType) {
112 case ARB_FRAGMENT_PROGRAM:
113 glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
114 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
115 break;
116 case NV_FRAGMENT_PROGRAM:
117 glGetIntegerv(GL_FRAGMENT_PROGRAM_BINDING_NV, &id);
118 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
119 break;
120 case ARB_VERTEX_PROGRAM:
121 glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
122 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
123 break;
124 case NV_VERTEX_PROGRAM:
125 glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &id);
126 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
127 break;
128 default:
129 abort();
130 }
131
132 /* get program string */
133 if (progType == ARB_VERTEX_PROGRAM ||
134 progType == ARB_FRAGMENT_PROGRAM)
135 glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &len);
136 else
137 glGetProgramivNV(id, GL_PROGRAM_LENGTH_NV, &len);
138 program = malloc(len + 1);
139 if (progType == ARB_VERTEX_PROGRAM ||
140 progType == ARB_FRAGMENT_PROGRAM)
141 glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, program);
142 else
143 glGetProgramStringNV(id, GL_PROGRAM_STRING_NV, program);
144
145
146 /* Get current line number, column, line string */
147 ln = find_line_column(program, program + pos, &line, &column);
148
149 printf("%d: %s\n", line, ln);
150
151 /* get commands from stdin */
152 while (1) {
153 char command[1000], *cmd;
154
155 /* print prompt and get command */
156 printf("(%s %d) ", (target == GL_VERTEX_PROGRAM_ARB ? "vert" : "frag"),
157 line);
158 fgets(command, 999, stdin);
159
160 /* skip leading whitespace */
161 for (cmd = command; cmd[0] == ' '; cmd++)
162 ;
163
164 if (!cmd[0])
165 /* nothing (repeat the previous cmd?) */
166 continue;
167
168 switch (cmd[0]) {
169 case 's':
170 case 'n':
171 /* step / next */
172 return;
173 case 'c':
174 continueFlag = GL_TRUE;
175 return;
176 case 'd':
177 /* dump machine state */
178 if (progType == NV_FRAGMENT_PROGRAM) {
179 static const char *inRegs[] = {
180 "f[WPOS]", "f[COL0]", "f[COL1]", "f[FOGC]",
181 "f[TEX0]", "f[TEX1]", "f[TEX2]", "f[TEX3]",
182 NULL
183 };
184 static const char *outRegs[] = {
185 "o[COLR]", "o[COLH]", "o[DEPR]", NULL
186 };
187 GLfloat v[4];
188 int i;
189 printf("Fragment input attributes:\n");
190 for (i = 0; inRegs[i]; i++) {
191 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
192 strlen(inRegs[i]),
193 (const GLubyte *) inRegs[i], v);
194 printf(" %s: %g, %g, %g, %g\n", inRegs[i],
195 v[0], v[1], v[2], v[3]);
196 }
197 printf("Fragment output attributes:\n");
198 for (i = 0; outRegs[i]; i++) {
199 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
200 strlen(outRegs[i]),
201 (const GLubyte *) outRegs[i], v);
202 printf(" %s: %g, %g, %g, %g\n", outRegs[i],
203 v[0], v[1], v[2], v[3]);
204 }
205 printf("Temporaries:\n");
206 for (i = 0; i < 4; i++) {
207 char temp[100];
208 GLfloat v[4];
209 sprintf(temp, "R%d", i);
210 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
211 strlen(temp),
212 (const GLubyte *) temp, v);
213 printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
214 }
215 }
216 else if (progType == NV_VERTEX_PROGRAM) {
217 GLfloat v[4];
218 int i;
219 static const char *inRegs[] = {
220 "v[OPOS]", "v[WGHT]", "v[NRML]", "v[COL0]",
221 "v[COL1]", "v[FOGC]", "v[6]", "v[7]",
222 "v[TEX0]", "v[TEX1]", "v[TEX2]", "v[TEX3]",
223 "v[TEX4]", "v[TEX5]", "v[TEX6]", "v[TEX7]",
224 NULL
225 };
226 static const char *outRegs[] = {
227 "o[HPOS]", "o[COL0]", "o[COL1]", "o[BFC0]",
228 "o[BFC1]", "o[FOGC]", "o[PSIZ]",
229 "o[TEX0]", "o[TEX1]", "o[TEX2]", "o[TEX3]",
230 "o[TEX4]", "o[TEX5]", "o[TEX6]", "o[TEX7]",
231 NULL
232 };
233 printf("Vertex input attributes:\n");
234 for (i = 0; inRegs[i]; i++) {
235 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
236 strlen(inRegs[i]),
237 (const GLubyte *) inRegs[i], v);
238 printf(" %s: %g, %g, %g, %g\n", inRegs[i],
239 v[0], v[1], v[2], v[3]);
240 }
241 printf("Vertex output attributes:\n");
242 for (i = 0; outRegs[i]; i++) {
243 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
244 strlen(outRegs[i]),
245 (const GLubyte *) outRegs[i], v);
246 printf(" %s: %g, %g, %g, %g\n", outRegs[i],
247 v[0], v[1], v[2], v[3]);
248 }
249 printf("Temporaries:\n");
250 for (i = 0; i < 4; i++) {
251 char temp[100];
252 GLfloat v[4];
253 sprintf(temp, "R%d", i);
254 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
255 strlen(temp),
256 (const GLubyte *) temp, v);
257 printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
258 }
259 }
260 break;
261 case 'l':
262 /* list */
263 list_program(program, len);
264 break;
265 case 'p':
266 /* print */
267 {
268 GLfloat v[4];
269 char *c;
270 cmd++;
271 while (*cmd == ' ')
272 cmd++;
273 c = cmd;
274 while (*c) {
275 if (*c == '\n' || *c == '\r')
276 *c = 0;
277 else
278 c++;
279 }
280 glGetProgramRegisterfvMESA(target, strlen(cmd),
281 (const GLubyte *) cmd, v);
282 if (glGetError() == GL_NO_ERROR)
283 printf("%s = %g, %g, %g, %g\n", cmd, v[0], v[1], v[2], v[3]);
284 else
285 printf("Invalid expression\n");
286 }
287 break;
288 case 'b':
289 /* break */
290 /* break at line number */
291 /* break at screen pixel (x,y) */
292 /* break if condition is true */
293 printf("Breakpoints not implemented yet.\n");
294 break;
295 case 'h':
296 /* help */
297 printf("Debugger commands:\n");
298 printf(" s step n next c continue\n");
299 printf(" d dump regs h help l list\n");
300 printf(" b break p print\n");
301 break;
302 default:
303 printf("Unknown command: %c\n", cmd[0]);
304 }
305 }
306}
307
308
309/*
310 * Print current line, some registers, and continue.
311 */
Brian Paul5366b012003-07-21 04:22:59 +0000312static void Debugger(GLenum target, GLvoid *data)
313{
314 GLint pos;
315 const GLubyte *ln;
316 GLint line, column;
317 GLfloat v[4];
318
319 assert(target == GL_FRAGMENT_PROGRAM_NV);
320
321 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
322
323 ln = find_line_column((const GLubyte *) data, (const GLubyte *) data + pos,
324 &line, &column);
325 printf("%d:%d: %s\n", line, column, (char *) ln);
326
327 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
328 2, (const GLubyte *) "R0", v);
329 printf(" R0 = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
330 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
331 7, (const GLubyte *) "f[WPOS]", v);
332 printf(" o[WPOS] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
333 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
334 7, (const GLubyte *) "o[COLR]", v);
335 printf(" o[COLR] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]);
336
337 free((void *) ln);
338}
339
340
341
342
343/**********************************************************************/
344
345static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
346static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
347static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
348static GLfloat Delta = 1.0;
349
350static GLuint FragProg;
351static GLuint VertProg;
352static GLboolean Anim = GL_TRUE;
353static GLboolean Wire = GL_FALSE;
354static GLboolean PixelLight = GL_TRUE;
355
356static GLfloat Xrot = 0, Yrot = 0;
357
358
359#define NAMED_PARAMETER4FV(prog, name, v) \
360 glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v)
361
362
363static void Display( void )
364{
365 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
366
367 if (PixelLight) {
368 NAMED_PARAMETER4FV(FragProg, "LightPos", LightPos);
369 glEnable(GL_FRAGMENT_PROGRAM_NV);
370 glEnable(GL_VERTEX_PROGRAM_NV);
371 glDisable(GL_LIGHTING);
372 }
373 else {
374 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
375 glDisable(GL_FRAGMENT_PROGRAM_NV);
376 glDisable(GL_VERTEX_PROGRAM_NV);
377 glEnable(GL_LIGHTING);
378 }
379
380 glPushMatrix();
381 glRotatef(Xrot, 1, 0, 0);
382 glRotatef(Yrot, 0, 1, 0);
383
384#if 1
385 glutSolidSphere(2.0, 10, 5);
386#else
387 {
388 GLUquadricObj *q = gluNewQuadric();
389 gluQuadricNormals(q, GL_SMOOTH);
390 gluQuadricTexture(q, GL_TRUE);
391 glRotatef(90, 1, 0, 0);
392 glTranslatef(0, 0, -1);
393 gluCylinder(q, 1.0, 1.0, 2.0, 24, 1);
394 gluDeleteQuadric(q);
395 }
396#endif
397
398 glPopMatrix();
399
400 glutSwapBuffers();
401}
402
403
404static void Idle(void)
405{
406 LightPos[0] += Delta;
407 if (LightPos[0] > 25.0)
408 Delta = -1.0;
409 else if (LightPos[0] <- 25.0)
410 Delta = 1.0;
411 glutPostRedisplay();
412}
413
414
415static void Reshape( int width, int height )
416{
417 glViewport( 0, 0, width, height );
418 glMatrixMode( GL_PROJECTION );
419 glLoadIdentity();
420 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
421 /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
422 glMatrixMode( GL_MODELVIEW );
423 glLoadIdentity();
424 glTranslatef( 0.0, 0.0, -15.0 );
425}
426
427
428static void Key( unsigned char key, int x, int y )
429{
430 (void) x;
431 (void) y;
432 switch (key) {
433 case ' ':
434 Anim = !Anim;
435 if (Anim)
436 glutIdleFunc(Idle);
437 else
438 glutIdleFunc(NULL);
439 break;
440 case 'x':
441 LightPos[0] -= 1.0;
442 break;
443 case 'X':
444 LightPos[0] += 1.0;
445 break;
446 case 'w':
447 Wire = !Wire;
448 if (Wire)
449 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
450 else
451 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
452 break;
453 case 'p':
454 PixelLight = !PixelLight;
455 if (PixelLight) {
456 printf("Per-pixel lighting\n");
457 }
458 else {
459 printf("Conventional lighting\n");
460 }
461 break;
462 case 27:
463 exit(0);
464 break;
465 }
466 glutPostRedisplay();
467}
468
469static void SpecialKey( int key, int x, int y )
470{
471 const GLfloat step = 3.0;
472 (void) x;
473 (void) y;
474 switch (key) {
475 case GLUT_KEY_UP:
476 Xrot -= step;
477 break;
478 case GLUT_KEY_DOWN:
479 Xrot += step;
480 break;
481 case GLUT_KEY_LEFT:
482 Yrot -= step;
483 break;
484 case GLUT_KEY_RIGHT:
485 Yrot += step;
486 break;
487 }
488 glutPostRedisplay();
489}
490
491
Brian Paul6a940e82003-07-22 03:53:44 +0000492static void Init( int argc, char *argv[] )
Brian Paul5366b012003-07-21 04:22:59 +0000493{
494 static const char *fragProgramText =
495 "!!FP1.0\n"
496 "DECLARE Diffuse; \n"
497 "DECLARE Specular; \n"
498 "DECLARE LightPos; \n"
499
500 "# Compute normalized LightPos, put it in R0\n"
501 "DP3 R0.x, LightPos, LightPos;\n"
502 "RSQ R0.y, R0.x;\n"
503 "MUL R0, LightPos, R0.y;\n"
504
505 "# Compute normalized normal, put it in R1\n"
506 "DP3 R1, f[TEX0], f[TEX0]; \n"
507 "RSQ R1.y, R1.x;\n"
508 "MUL R1, f[TEX0], R1.y;\n"
509
510 "# Compute dot product of light direction and normal vector\n"
511 "DP3 R2, R0, R1;\n"
512
513 "MUL R3, Diffuse, R2; # diffuse attenuation\n"
514
515 "POW R4, R2.x, {20.0}.x; # specular exponent\n"
516
517 "MUL R5, Specular, R4; # specular attenuation\n"
518
519 "ADD o[COLR], R3, R5; # add diffuse and specular colors\n"
520 "END \n"
521 ;
522
523 static const char *vertProgramText =
524 "!!VP1.0\n"
525 "# typical modelview/projection transform\n"
526 "DP4 o[HPOS].x, c[0], v[OPOS] ;\n"
527 "DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
528 "DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
529 "DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
530 "# transform normal by inv transpose of modelview, put in tex0\n"
531 "DP4 o[TEX0].x, c[4], v[NRML] ;\n"
532 "DP4 o[TEX0].y, c[5], v[NRML] ;\n"
533 "DP4 o[TEX0].z, c[6], v[NRML] ;\n"
534 "DP4 o[TEX0].w, c[7], v[NRML] ;\n"
535 "END\n";
536 ;
537
538 if (!glutExtensionSupported("GL_NV_vertex_program")) {
539 printf("Sorry, this demo requires GL_NV_vertex_program\n");
540 exit(1);
541 }
542 if (!glutExtensionSupported("GL_NV_fragment_program")) {
543 printf("Sorry, this demo requires GL_NV_fragment_program\n");
544 exit(1);
545 }
546
547 glGenProgramsNV(1, &FragProg);
548 assert(FragProg > 0);
549 glGenProgramsNV(1, &VertProg);
550 assert(VertProg > 0);
551
552 /*
553 * Fragment program
554 */
555 glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg,
556 strlen(fragProgramText),
557 (const GLubyte *) fragProgramText);
558 assert(glIsProgramNV(FragProg));
559 glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg);
560
561 NAMED_PARAMETER4FV(FragProg, "Diffuse", Diffuse);
562 NAMED_PARAMETER4FV(FragProg, "Specular", Specular);
563
564 /*
565 * Vertex program
566 */
567 glLoadProgramNV(GL_VERTEX_PROGRAM_NV, VertProg,
568 strlen(vertProgramText),
569 (const GLubyte *) vertProgramText);
570 assert(glIsProgramNV(VertProg));
571 glBindProgramNV(GL_VERTEX_PROGRAM_NV, VertProg);
572 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
573 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
574
575 /*
576 * Misc init
577 */
578 glClearColor(0.3, 0.3, 0.3, 0.0);
579 glEnable(GL_DEPTH_TEST);
580 glEnable(GL_LIGHT0);
581 glEnable(GL_LIGHTING);
582 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
583 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
584 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
585
586 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
587 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
588
589#ifdef GL_MESA_program_debug
Brian Paul6a940e82003-07-22 03:53:44 +0000590 if (argc > 1 && strcmp(argv[1], "fragment") == 0) {
591 printf(">> Debugging fragment program\n");
592 glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB, Debugger2,
593 (GLvoid *) fragProgramText);
594 glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA);
595 }
596 else {
597 printf(">> Debugging vertex program\n");
598 glProgramCallbackMESA(GL_VERTEX_PROGRAM_ARB, Debugger2,
599 (GLvoid *) fragProgramText);
600 glEnable(GL_VERTEX_PROGRAM_CALLBACK_MESA);
601 }
Brian Paul5366b012003-07-21 04:22:59 +0000602#endif
603}
604
605
606int main( int argc, char *argv[] )
607{
608 glutInit( &argc, argv );
609 glutInitWindowPosition( 0, 0 );
610 glutInitWindowSize( 200, 200 );
611 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
612 glutCreateWindow(argv[0]);
613 glutReshapeFunc( Reshape );
614 glutKeyboardFunc( Key );
615 glutSpecialFunc( SpecialKey );
616 glutDisplayFunc( Display );
617 if (Anim)
618 glutIdleFunc(Idle);
Brian Paul6a940e82003-07-22 03:53:44 +0000619 Init(argc, argv);
Brian Paul5366b012003-07-21 04:22:59 +0000620 glutMainLoop();
621 return 0;
622}