//////////////////////////////////////////////////////////////////////////
/*
* my first glsl program, hello - glsl
* now, go!
*
*/
#define GLUT_DISABLE_ATEXIT_HACK
#include
#include
#include
#include
#include
// grid resolution
#define N 64
// vision region
const GLdouble nearVal = 1.0;
const GLdouble farVal = 20.0;
// program object ID
GLuint program = 0;
GLint timeParam;
// error buffer and error message length
GLchar *ebuffer;
GLsizei elength;
// high field data
GLfloat data[N][N];
// shader read entry function
static char* readShaderSource(const char * shaderFile)
{
char *buf = NULL;
int size(0);
FILE *file = fopen(shaderFile, "r");
if (!file) return NULL;
fseek(file, 0, SEEK_END);
size = ftell(file);
rewind(file);
if (size > 0)
{
buf = (char*)malloc(sizeof(char)*(size+1));
size = fread(buf, sizeof(char), size, file);
buf[size] = '/0';
}
fclose(file);
return buf;
}
// init OpenGL
static void initGL()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glColor3f(0.0, 0.0, 0.0);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho(-0.75, 0.75, -0.75, 0.75, -5.5, 5.5);
}
// init GLSL
static void initShader(const GLchar * vShaderFile, const GLchar * fShaderFile)
{
GLint status;
GLchar *vSource, *fSource;
GLuint vShader, fShader;
// read shader file
vSource = readShaderSource(vShaderFile);
if ( vSource == NULL )
{
printf("Failed to read vertex shader/n");
exit( EXIT_FAILURE );
}
fSource = readShaderSource(fShaderFile);
if ( fSource == NULL )
{
printf("Failed to read fragment shader/n");
exit( EXIT_FAILURE );
}
//create program and shader object
vShader = glCreateShader( GL_VERTEX_SHADER );
fShader = glCreateShader( GL_FRAGMENT_SHADER );
program = glCreateProgram();
// bind shader to program object
glAttachShader( program, vShader );
glAttachShader( program, fShader );
// read shader
glShaderSource( vShader, 1, (const GLchar**)&vSource, NULL );
glShaderSource( fShader, 1, (const GLchar**)&fSource, NULL );
// compile vertex shader
glCompileShader( vShader );
// error detection
glGetShaderiv( vShader, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
printf("Failed to compile vertex shader/n");
glGetShaderiv(vShader, GL_INFO_LOG_LENGTH, &elength);
ebuffer = (char*)malloc(elength*sizeof(char));
glGetShaderInfoLog(vShader, elength, NULL, ebuffer);
printf("%s/n", ebuffer);
exit( EXIT_FAILURE );
}
// compile fragment shader
glCompileShader( fShader );
// error detection
glGetShaderiv( fShader, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
printf("Failed to compile fragment shader/n");
glGetShaderiv(fShader, GL_INFO_LOG_LENGTH, &elength);
ebuffer = (char*)malloc(elength*sizeof(char));
glGetShaderInfoLog(fShader, elength, NULL, ebuffer);
printf("%s/n");
exit( EXIT_FAILURE );
}
// link and error detection
glLinkProgram( program );
glGetProgramiv( program, GL_LINK_STATUS, &status );
if ( status == GL_FALSE )
{
printf("Failed to link program object/n");
glGetProgramiv( program, GL_INFO_LOG_LENGTH, &elength );
ebuffer = (char*)malloc(elength*sizeof(char));
glGetProgramInfoLog(program, elength, &elength, ebuffer);
printf("%s/n");
exit( EXIT_FAILURE );
}
// use program object
glUseProgram( program );
// set uniform parameter
timeParam = glGetUniformLocation( program, "time" );
}
// mesh
void mesh()
{
int i(0), j(0);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt(2.0, 2.0, 2.0, 0.5, 0.0, 0.5, 0.0, 1.0, 0.0);
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
glBegin( GL_LINE_LOOP );
glVertex3f((float)i/N, data[i][j], (float)j/N);
glVertex3f((float)i/N, data[i][j], (float)(j+1)/N);
glVertex3f((float)(i+1)/N, data[i][j], (float)(j+1)/N);
glVertex3f((float)(i+1)/N, data[i][j], (float)j/N);
glEnd();
}
}
}
static void display()
{
// transfer run-time to shader
glUniform1f( timeParam, glutGet(GLUT_ELAPSED_TIME) );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
mesh();
glutSwapBuffers();
}
// reshape callback function
static void reshape(int w, int h)
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho(-0.75, 0.75, -0.75, 0.75, -5.5, 5.5);
glViewport(0, 0, w, h);
glutPostRedisplay();
}
// keyboard callback function
static void keyboard(unsigned char key, int x, int y)
{
switch(key)
{
case 27:
case 'Q':
case 'q':
exit( EXIT_FAILURE );
break;
default:
break;
}
}
// idle callback function
static void idle()
{
glUniform1f( timeParam, (GLfloat)glutGet(GLUT_ELAPSED_TIME) );
glutPostRedisplay();
}
// check whether GLEW and GLSL are supported
bool check()
{
const char * version = (const char*)glGetString( GL_VERSION );
printf("OpenGL version : %s/n", version);
// check OpenGL
if ( glewIsSupported("GL_VERSION_2_0") )
{
printf("Ready for OpenGL 2.0/n");
}
else
{
printf("OpenGL 2.0 not supported/n");
return false;
}
// check extensions
if ( GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader )
{
printf("Ready for GLSL/n");
}
else
{
printf("Not totally ready/n");
return false;
}
return true;
}
// main
int main(int argc, char ** argv)
{
int i(0), j(0);
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
data[i][j] = 0;
}
}
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize(512, 512);
glutCreateWindow("Simple GLSL example");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(idle);
// init GLEW, this is very important
glewInit();
// check whether GLEW and GLSL are supported
if ( !check() )
{
return 0;
}
initGL();
initShader("vmesh.vert", "fPassThrough.frag");
glutMainLoop();
return 0;
}
两个shader文件,分别存为vmesn.vert和fPassThrough.frag,代码如下:
vmesh.vert文件
//
// vertex shader
//
uniform float time;
void main()
{
float s;
vec4 t = gl_Vertex;
t.y = 0.1*sin(0.001*time + 5.0*gl_Vertex.x) * sin(0.001*time + 5.0*gl_Vertex.z);
gl_Position = gl_ModelViewProjectionMatrix * t;
gl_FrontColor = gl_Color;
}
fPassThrough.frag文件
//
// mesh shader
//
void main()
{
gl_FragColor = gl_Color;
}