/* * GL_ARB_shading_language_100 test application. * * Tests correctness of emited code. Runs multiple well-formed shaders and checks if * they produce valid results. * * Requires specific support on the GL implementation side. A special function printMESA() * must be supported in the language that prints current values of generic type * to the appropriate shader's info log, and optionally to the screen. * * Author: Michal Krol */ #include "framework.h" #define EPSILON 0.0001f static GLhandleARB vert = 0; static GLhandleARB prog = 0; static int get_line (FILE *f, char *line, int size) { if (fgets (line, size, f) == NULL) return 0; if (line[strlen (line) - 1] == '\n') line[strlen (line) - 1] = '\0'; return 1; } struct ATTRIB { char name[32]; GLfloat value[64][4]; GLuint count; }; struct ATTRIBS { struct ATTRIB attrib[32]; GLuint count; }; struct SHADER { char code[16000]; GLfloat output[1000]; GLuint count; }; enum SHADER_LOAD_STATE { SLS_NONE, SLS_CODE, SLS_OUTPUT }; struct PROGRAM { struct PROGRAM *next; char name[256]; struct ATTRIBS attribs; struct SHADER vertex; }; enum PROGRAM_LOAD_STATE { PLS_NONE, PLS_ATTRIB, PLS_VERTEX }; static struct PROGRAM *program = NULL; static void load_test_file (const char *filename, struct PROGRAM **program) { struct PROGRAM **currprog = program; FILE *f; char line[256]; enum PROGRAM_LOAD_STATE pls = PLS_NONE; enum SHADER_LOAD_STATE sls = SLS_NONE; f = fopen (filename, "r"); if (f == NULL) return; while (get_line (f, line, sizeof (line))) { if (line[0] == '$') { if (strncmp (line + 1, "program", 7) == 0) { if (*currprog != NULL) currprog = &(**currprog).next; *currprog = (struct PROGRAM *) (malloc (sizeof (struct PROGRAM))); if (*currprog == NULL) break; (**currprog).next = NULL; strcpy ((**currprog).name, line + 9); (**currprog).attribs.count = 0; (**currprog).vertex.code[0] = '\0'; (**currprog).vertex.count = 0; pls = PLS_NONE; } else if (strncmp (line + 1, "attrib", 6) == 0) { if (*currprog == NULL) break; strcpy ((**currprog).attribs.attrib[(**currprog).attribs.count].name, line + 8); (**currprog).attribs.attrib[(**currprog).attribs.count].count = 0; (**currprog).attribs.count++; pls = PLS_ATTRIB; } else if (strcmp (line + 1, "vertex") == 0) { if (*currprog == NULL) break; pls = PLS_VERTEX; sls = SLS_NONE; } else if (strcmp (line + 1, "code") == 0) { if (*currprog == NULL || pls != PLS_VERTEX) break; sls = SLS_CODE; } else if (strcmp (line + 1, "output") == 0) { if (*currprog == NULL || pls != PLS_VERTEX) break; sls = SLS_OUTPUT; } } else { if ((*currprog == NULL || pls == PLS_NONE || sls == SLS_NONE) && line[0] != '\0') break; if (*currprog != NULL && pls == PLS_VERTEX) { if (sls == SLS_CODE) { strcat ((**currprog).vertex.code, line); strcat ((**currprog).vertex.code, "\n"); } else if (sls == SLS_OUTPUT && line[0] != '\0') { if (strcmp (line, "true") == 0) (**currprog).vertex.output[(**currprog).vertex.count] = 1.0f; else if (strcmp (line, "false") == 0) (**currprog).vertex.output[(**currprog).vertex.count] = 0.0f; else sscanf (line, "%f", &(**currprog).vertex.output[(**currprog).vertex.count]); (**currprog).vertex.count++; } } else if (*currprog != NULL && pls == PLS_ATTRIB && line[0] != '\0') { struct ATTRIB *att = &(**currprog).attribs.attrib[(**currprog).attribs.count - 1]; GLfloat *vec = att->value[att->count]; sscanf (line, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]); att->count++; } } } fclose (f); } void InitScene (void) { prog = glCreateProgramObjectARB (); vert = glCreateShaderObjectARB (GL_VERTEX_SHADER_ARB); glAttachObjectARB (prog, vert); glDeleteObjectARB (vert); load_test_file ("cltest.txt", &program); } void RenderScene (void) { struct PROGRAM *nextprogram; char *code; GLint info_length, length; char output[65000], *p; GLuint i; if (program == NULL) exit (0); code = program->vertex.code; glShaderSourceARB (vert, 1, (const GLcharARB **) (&code), NULL); glCompileShaderARB (vert); CheckObjectStatus (vert); for (i = 0; i < program->attribs.count; i++) { const char *name = program->attribs.attrib[i].name; if (strcmp (name, "gl_Vertex") != 0) glBindAttribLocationARB (prog, i, name); } glLinkProgramARB (prog); CheckObjectStatus (prog); glUseProgramObjectARB (prog); printf ("\n--- %s\n", program->name); glGetObjectParameterivARB (vert, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_length); glBegin (GL_POINTS); if (program->attribs.count == 0) { glVertex2f (0.0f, 0.0f); } else { for (i = 0; i < program->attribs.attrib[0].count; i++) { GLuint j; for (j = 0; j < program->attribs.count; j++) { GLuint n = (j + 1) % program->attribs.count; GLfloat *vec = program->attribs.attrib[n].value[i]; const char *name = program->attribs.attrib[n].name; if (strcmp (name, "gl_Vertex") == 0) glVertex4fv (vec); else glVertexAttrib4fvARB (n, vec); } } } glEnd (); glFlush (); glGetInfoLogARB (vert, sizeof (output), &length, output); p = output + info_length - 1; for (i = 0; i < program->vertex.count; i++) { GLfloat value; if (p == NULL) { printf ("*** %s\n", "I/O error"); break; } if (strncmp (p, "true", 4) == 0) value = 1.0f; else if (strncmp (p, "false", 5) == 0) value = 0.0f; else if (sscanf (p, "%f", &value) != 1) { printf ("*** %s\n", "I/O error"); break; } if (fabs (value - program->vertex.output[i]) > EPSILON) { printf ("*** Values are different, is %f, should be %f\n", value, program->vertex.output[i]); } p = strchr (p, '\n'); if (p != NULL) p++; } if (*p != '\0') printf ("*** %s\n", "I/O error"); nextprogram = program->next; free (program); program = nextprogram; } int main (int argc, char *argv[]) { InitFramework (&argc, argv); return 0; }