progs/glsl: new shtest program, a simple shader test harness app
This commit includes some sample config files (*.shtest)
This commit is contained in:
@@ -33,6 +33,7 @@ DEMO_SOURCES = \
|
||||
points.c \
|
||||
samplers.c \
|
||||
shadow_sampler.c \
|
||||
shtest.c \
|
||||
skinning.c \
|
||||
texaaline.c \
|
||||
texdemo1.c \
|
||||
@@ -198,9 +199,14 @@ shadow_sampler.o: $(UTIL_HEADERS)
|
||||
shadow_sampler: shadow_sampler.o $(UTIL_OBJS)
|
||||
|
||||
|
||||
skinning.o: $(UTIL_HEADERS)
|
||||
shtest.o: $(UTIL_HEADERS)
|
||||
|
||||
skinning: skinning.o $(UTIL_OBJS)
|
||||
shtest: shtest.o $(UTIL_OBJS)
|
||||
|
||||
|
||||
shtest.o: $(UTIL_HEADERS)
|
||||
|
||||
shtest: shtest.o $(UTIL_OBJS)
|
||||
|
||||
|
||||
texaaline.o: $(UTIL_HEADERS)
|
||||
|
8
progs/glsl/brick.shtest
Normal file
8
progs/glsl/brick.shtest
Normal file
@@ -0,0 +1,8 @@
|
||||
vs CH06-brick.vert
|
||||
fs CH06-brick.frag
|
||||
uniform LightPosition 0.1 0.1 9.0
|
||||
uniform BrickColor 0.8 0.2 0.2
|
||||
uniform MortarColor 0.6 0.6 0.6
|
||||
uniform BrickSize 1.0 0.3
|
||||
uniform BrickPct 0.9 0.8
|
||||
|
14
progs/glsl/mandelbrot.shtest
Normal file
14
progs/glsl/mandelbrot.shtest
Normal file
@@ -0,0 +1,14 @@
|
||||
vs CH18-mandel.vert
|
||||
fs CH18-mandel.frag
|
||||
uniform LightPosition 0.1 0.1 9.0
|
||||
uniform SpecularContribution 0.5
|
||||
uniform DiffuseContribution 0.5
|
||||
uniform Shininess 20.0
|
||||
uniform Iterations 12
|
||||
uniform Zoom 0.125
|
||||
uniform Xcenter -1.5
|
||||
uniform Ycenter .005
|
||||
uniform InnerColor 1 0 0
|
||||
uniform OuterColor1 0 1 0
|
||||
uniform OuterColor2 0 0 1
|
||||
|
562
progs/glsl/shtest.c
Normal file
562
progs/glsl/shtest.c
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Simple shader test harness.
|
||||
* Brian Paul
|
||||
* 13 Aug 2009
|
||||
*
|
||||
* Usage:
|
||||
* shtest --vs vertShaderFile --fs fragShaderFile
|
||||
*
|
||||
* In this case the given vertex/frag shaders are read and compiled.
|
||||
* Random values are assigned to the uniforms.
|
||||
*
|
||||
* or:
|
||||
* shtest configFile
|
||||
*
|
||||
* In this case a config file is read that specifies the file names
|
||||
* of the shaders plus initial values for uniforms.
|
||||
*
|
||||
* Example config file:
|
||||
*
|
||||
* vs shader.vert
|
||||
* fs shader.frag
|
||||
* uniform pi 3.14159
|
||||
* uniform v1 1.0 0.5 0.2 0.3
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <GL/glew.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glut.h>
|
||||
#include "shaderutil.h"
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPHERE,
|
||||
CUBE,
|
||||
NUM_SHAPES
|
||||
} shape;
|
||||
|
||||
|
||||
static char *FragShaderFile = NULL;
|
||||
static char *VertShaderFile = NULL;
|
||||
static char *ConfigFile = NULL;
|
||||
|
||||
/* program/shader objects */
|
||||
static GLuint fragShader;
|
||||
static GLuint vertShader;
|
||||
static GLuint Program;
|
||||
|
||||
|
||||
#define MAX_UNIFORMS 100
|
||||
static struct uniform_info Uniforms[MAX_UNIFORMS];
|
||||
static GLuint NumUniforms = 0;
|
||||
|
||||
|
||||
#define MAX_ATTRIBS 100
|
||||
static struct attrib_info Attribs[MAX_ATTRIBS];
|
||||
static GLuint NumAttribs = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Config file info.
|
||||
*/
|
||||
struct config_file
|
||||
{
|
||||
struct name_value
|
||||
{
|
||||
char name[100];
|
||||
float value[4];
|
||||
int type;
|
||||
} uniforms[100];
|
||||
|
||||
int num_uniforms;
|
||||
};
|
||||
|
||||
|
||||
static GLint win = 0;
|
||||
static GLboolean Anim = GL_FALSE;
|
||||
static GLfloat TexRot = 0.0;
|
||||
static GLfloat xRot = 0.0f, yRot = 0.0f, zRot = 0.0f;
|
||||
static shape Object = SPHERE;
|
||||
|
||||
|
||||
static float
|
||||
RandomFloat(float min, float max)
|
||||
{
|
||||
int k = rand() % 10000;
|
||||
float x = min + (max - min) * k / 10000.0;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
/** Set new random values for uniforms */
|
||||
static void
|
||||
RandomUniformValues(void)
|
||||
{
|
||||
GLuint i;
|
||||
for (i = 0; i < NumUniforms; i++) {
|
||||
if (Uniforms[i].type == GL_FLOAT) {
|
||||
Uniforms[i].value[0] = RandomFloat(0.0, 1.0);
|
||||
}
|
||||
else {
|
||||
Uniforms[i].value[0] = RandomFloat(-1.0, 2.0);
|
||||
Uniforms[i].value[1] = RandomFloat(-1.0, 2.0);
|
||||
Uniforms[i].value[2] = RandomFloat(-1.0, 2.0);
|
||||
Uniforms[i].value[3] = RandomFloat(-1.0, 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Idle(void)
|
||||
{
|
||||
yRot += 2.0;
|
||||
if (yRot > 360.0)
|
||||
yRot -= 360.0;
|
||||
glutPostRedisplay();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
SquareVertex(GLfloat s, GLfloat t, GLfloat size)
|
||||
{
|
||||
GLfloat x = -size + s * 2.0 * size;
|
||||
GLfloat y = -size + t * 2.0 * size;
|
||||
glTexCoord2f(s, t);
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Draw a square, specifying normal and tangent vectors.
|
||||
*/
|
||||
static void
|
||||
Square(GLfloat size)
|
||||
{
|
||||
GLint tangentAttrib = 1;
|
||||
glNormal3f(0, 0, 1);
|
||||
glVertexAttrib3f(tangentAttrib, 1, 0, 0);
|
||||
glBegin(GL_POLYGON);
|
||||
#if 0
|
||||
SquareVertex(0, 0, size);
|
||||
SquareVertex(1, 0, size);
|
||||
SquareVertex(1, 1, size);
|
||||
SquareVertex(0, 1, size);
|
||||
#else
|
||||
glTexCoord2f(0, 0); glVertex2f(-size, -size);
|
||||
glTexCoord2f(1, 0); glVertex2f( size, -size);
|
||||
glTexCoord2f(1, 1); glVertex2f( size, size);
|
||||
glTexCoord2f(0, 1); glVertex2f(-size, size);
|
||||
#endif
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Cube(GLfloat size)
|
||||
{
|
||||
/* +X */
|
||||
glPushMatrix();
|
||||
glRotatef(90, 0, 1, 0);
|
||||
glTranslatef(0, 0, size);
|
||||
Square(size);
|
||||
glPopMatrix();
|
||||
|
||||
/* -X */
|
||||
glPushMatrix();
|
||||
glRotatef(-90, 0, 1, 0);
|
||||
glTranslatef(0, 0, size);
|
||||
Square(size);
|
||||
glPopMatrix();
|
||||
|
||||
/* +Y */
|
||||
glPushMatrix();
|
||||
glRotatef(90, 1, 0, 0);
|
||||
glTranslatef(0, 0, size);
|
||||
Square(size);
|
||||
glPopMatrix();
|
||||
|
||||
/* -Y */
|
||||
glPushMatrix();
|
||||
glRotatef(-90, 1, 0, 0);
|
||||
glTranslatef(0, 0, size);
|
||||
Square(size);
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
/* +Z */
|
||||
glPushMatrix();
|
||||
glTranslatef(0, 0, size);
|
||||
Square(size);
|
||||
glPopMatrix();
|
||||
|
||||
/* -Z */
|
||||
glPushMatrix();
|
||||
glRotatef(180, 0, 1, 0);
|
||||
glTranslatef(0, 0, size);
|
||||
Square(size);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Sphere(GLfloat radius, GLint slices, GLint stacks)
|
||||
{
|
||||
static GLUquadricObj *q = NULL;
|
||||
|
||||
if (!q) {
|
||||
q = gluNewQuadric();
|
||||
gluQuadricDrawStyle(q, GLU_FILL);
|
||||
gluQuadricNormals(q, GLU_SMOOTH);
|
||||
gluQuadricTexture(q, GL_TRUE);
|
||||
}
|
||||
|
||||
gluSphere(q, radius, slices, stacks);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Redisplay(void)
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glRotatef(TexRot, 0.0f, 1.0f, 0.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
if (Object == SPHERE) {
|
||||
Sphere(2.0, 20, 10);
|
||||
}
|
||||
else if (Object == CUBE) {
|
||||
Cube(2.0);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glutSwapBuffers();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.0f, 0.0f, -15.0f);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
CleanUp(void)
|
||||
{
|
||||
glDeleteShader(fragShader);
|
||||
glDeleteShader(vertShader);
|
||||
glDeleteProgram(Program);
|
||||
glutDestroyWindow(win);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Key(unsigned char key, int x, int y)
|
||||
{
|
||||
const GLfloat step = 2.0;
|
||||
(void) x;
|
||||
(void) y;
|
||||
|
||||
switch(key) {
|
||||
case 'a':
|
||||
Anim = !Anim;
|
||||
if (Anim)
|
||||
glutIdleFunc(Idle);
|
||||
else
|
||||
glutIdleFunc(NULL);
|
||||
break;
|
||||
case 'z':
|
||||
zRot += step;
|
||||
break;
|
||||
case 'Z':
|
||||
zRot -= step;
|
||||
break;
|
||||
case 'o':
|
||||
Object = (Object + 1) % NUM_SHAPES;
|
||||
break;
|
||||
case 'r':
|
||||
RandomUniformValues();
|
||||
SetUniformValues(Program, Uniforms);
|
||||
PrintUniforms(Uniforms);
|
||||
break;
|
||||
case 27:
|
||||
CleanUp();
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
glutPostRedisplay();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
SpecialKey(int key, int x, int y)
|
||||
{
|
||||
const GLfloat step = 2.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
|
||||
InitUniforms(const struct config_file *conf,
|
||||
struct uniform_info uniforms[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < conf->num_uniforms; i++) {
|
||||
int j;
|
||||
for (j = 0; uniforms[j].name; j++) {
|
||||
if (strcmp(uniforms[j].name, conf->uniforms[i].name) == 0) {
|
||||
uniforms[j].type = conf->uniforms[i].type;
|
||||
uniforms[j].value[0] = conf->uniforms[i].value[0];
|
||||
uniforms[j].value[1] = conf->uniforms[i].value[1];
|
||||
uniforms[j].value[2] = conf->uniforms[i].value[2];
|
||||
uniforms[j].value[3] = conf->uniforms[i].value[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a config file.
|
||||
*/
|
||||
static void
|
||||
ReadConfigFile(const char *filename, struct config_file *conf)
|
||||
{
|
||||
char line[1000];
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
fprintf(stderr, "Unable to open config file %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
conf->num_uniforms = 0;
|
||||
|
||||
/* ugly but functional parser */
|
||||
while (!feof(f)) {
|
||||
fgets(line, sizeof(line), f);
|
||||
if (line[0]) {
|
||||
if (strncmp(line, "vs ", 3) == 0) {
|
||||
VertShaderFile = strdup(line + 3);
|
||||
VertShaderFile[strlen(VertShaderFile) - 1] = 0;
|
||||
}
|
||||
else if (strncmp(line, "fs ", 3) == 0) {
|
||||
FragShaderFile = strdup(line + 3);
|
||||
FragShaderFile[strlen(FragShaderFile) - 1] = 0;
|
||||
}
|
||||
else if (strncmp(line, "uniform ", 8) == 0) {
|
||||
char name[1000];
|
||||
int k;
|
||||
float v1, v2, v3, v4;
|
||||
GLenum type;
|
||||
|
||||
k = sscanf(line + 8, "%s %f %f %f %f", name, &v1, &v2, &v3, &v4);
|
||||
|
||||
switch (k) {
|
||||
case 1:
|
||||
type = GL_NONE;
|
||||
abort();
|
||||
break;
|
||||
case 2:
|
||||
type = GL_FLOAT;
|
||||
break;
|
||||
case 3:
|
||||
type = GL_FLOAT_VEC2;
|
||||
break;
|
||||
case 4:
|
||||
type = GL_FLOAT_VEC3;
|
||||
break;
|
||||
case 5:
|
||||
type = GL_FLOAT_VEC4;
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(conf->uniforms[conf->num_uniforms].name, name);
|
||||
conf->uniforms[conf->num_uniforms].value[0] = v1;
|
||||
conf->uniforms[conf->num_uniforms].value[1] = v2;
|
||||
conf->uniforms[conf->num_uniforms].value[2] = v3;
|
||||
conf->uniforms[conf->num_uniforms].value[3] = v4;
|
||||
conf->uniforms[conf->num_uniforms].type = type;
|
||||
conf->num_uniforms++;
|
||||
}
|
||||
else {
|
||||
if (strlen(line) > 1) {
|
||||
fprintf(stderr, "syntax error in: %s\n", line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Init(void)
|
||||
{
|
||||
struct config_file config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
if (ConfigFile)
|
||||
ReadConfigFile(ConfigFile, &config);
|
||||
|
||||
if (!VertShaderFile) {
|
||||
fprintf(stderr, "Error: no vertex shader\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!FragShaderFile) {
|
||||
fprintf(stderr, "Error: no fragment shader\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!ShadersSupported())
|
||||
exit(1);
|
||||
|
||||
vertShader = CompileShaderFile(GL_VERTEX_SHADER, VertShaderFile);
|
||||
fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragShaderFile);
|
||||
Program = LinkShaders(vertShader, fragShader);
|
||||
|
||||
glUseProgram(Program);
|
||||
|
||||
NumUniforms = GetUniforms(Program, Uniforms);
|
||||
if (config.num_uniforms) {
|
||||
InitUniforms(&config, Uniforms);
|
||||
}
|
||||
else {
|
||||
RandomUniformValues();
|
||||
}
|
||||
SetUniformValues(Program, Uniforms);
|
||||
PrintUniforms(Uniforms);
|
||||
|
||||
NumAttribs = GetAttribs(Program, Attribs);
|
||||
PrintAttribs(Attribs);
|
||||
|
||||
//assert(glGetError() == 0);
|
||||
|
||||
glClearColor(0.4f, 0.4f, 0.8f, 0.0f);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glColor3f(1, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Keys(void)
|
||||
{
|
||||
printf("Keyboard:\n");
|
||||
printf(" a Animation toggle\n");
|
||||
printf(" r Randomize uniform values\n");
|
||||
printf(" o Change object\n");
|
||||
printf(" arrows Rotate object\n");
|
||||
printf(" ESC Exit\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Usage(void)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf(" shtest config.shtest\n");
|
||||
printf(" Run w/ given config file.\n");
|
||||
printf(" shtest --vs vertShader --fs fragShader\n");
|
||||
printf(" Load/compile given shaders.\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ParseOptions(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc == 1) {
|
||||
Usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--fs") == 0) {
|
||||
FragShaderFile = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
else if (strcmp(argv[i], "--vs") == 0) {
|
||||
VertShaderFile = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
/* assume the arg is a config file */
|
||||
ConfigFile = argv[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
glutInit(&argc, argv);
|
||||
glutInitWindowPosition( 0, 0);
|
||||
glutInitWindowSize(400, 400);
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
|
||||
win = glutCreateWindow(argv[0]);
|
||||
glewInit();
|
||||
glutReshapeFunc(Reshape);
|
||||
glutKeyboardFunc(Key);
|
||||
glutSpecialFunc(SpecialKey);
|
||||
glutDisplayFunc(Redisplay);
|
||||
ParseOptions(argc, argv);
|
||||
Init();
|
||||
Keys();
|
||||
glutMainLoop();
|
||||
return 0;
|
||||
}
|
||||
|
17
progs/glsl/toyball.shtest
Normal file
17
progs/glsl/toyball.shtest
Normal file
@@ -0,0 +1,17 @@
|
||||
vs CH11-toyball.vert
|
||||
fs CH11-toyball.frag
|
||||
uniform LightDir 0.57737 0.57735 0.57735 0.0
|
||||
uniform HVector 0.32506 0.32506 0.88808 0.0
|
||||
uniform BallCenter 0.0 0.0 0.0 1.0
|
||||
uniform SpecularColor 0.4 0.4 0.4 60.0
|
||||
uniform Red 0.6 0.0 0.0 1.0
|
||||
uniform Blue 0.0 0.3 0.6 1.0
|
||||
uniform Yellow 0.6 0.5 0.0 1.0
|
||||
uniform HalfSpace0 1.0 0.0 0.0 0.2
|
||||
uniform HalfSpace1 .309016994 0.951056516 0.0 0.2
|
||||
uniform HalfSpace2 -0.809016994 0.587785252 0.0 0.2
|
||||
uniform HalfSpace3 -0.809016994 -0.587785252 0.0 0.2
|
||||
uniform HalfSpace4 .309116994 -0.951056516 0.0 0.2
|
||||
uniform InOrOutInit -3.0
|
||||
uniform StripeWidth 0.3
|
||||
uniform FWidth .005
|
Reference in New Issue
Block a user