2
* Convolution with GLSL.
3
* Note: uses GL_ARB_shader_objects, GL_ARB_vertex_shader, GL_ARB_fragment_shader,
4
* not the OpenGL 2.0 shader API.
10
#define GL_GLEXT_PROTOTYPES
31
float minx, miny, minz;
32
float maxx, maxy, maxz;
43
static const char *textureLocation = "../images/girl2.rgb";
45
static GLfloat viewRotx = 0.0, viewRoty = 0.0, viewRotz = 0.0;
46
static struct BoundingBox box;
47
static struct Texture texture;
48
static GLuint program;
50
static enum Filter filter = GAUSSIAN_BLUR;
53
static void checkError(int line)
55
GLenum err = glGetError();
57
printf("GL Error %s (0x%x) at line %d\n",
58
gluErrorString(err), (int) err, line);
62
static void loadAndCompileShader(GLuint shader, const char *text)
66
glShaderSource(shader, 1, (const GLchar **) &text, NULL);
68
glCompileShader(shader);
70
glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
74
glGetShaderInfoLog(shader, 1000, &len, log);
75
fprintf(stderr, "Problem compiling shader: %s\n", log);
79
printf("Shader compiled OK\n");
83
static void readShader(GLuint shader, const char *filename)
85
const int max = 100*1000;
87
char *buffer = (char*) malloc(max);
88
FILE *f = fopen(filename, "r");
90
fprintf(stderr, "Unable to open shader file %s\n", filename);
94
n = fread(buffer, 1, max, f);
95
printf("Read %d bytes from shader file %s\n", n, filename);
98
loadAndCompileShader(shader, buffer);
107
checkLink(GLuint prog)
110
glGetProgramiv(prog, GL_LINK_STATUS, &stat);
114
glGetProgramInfoLog(prog, 1000, &len, log);
115
fprintf(stderr, "Linker error:\n%s\n", log);
118
fprintf(stderr, "Link success!\n");
122
static void fillConvolution(GLint *k,
128
k[0] = 1; k[1] = 2; k[2] = 1;
129
k[3] = 2; k[4] = 4; k[5] = 2;
130
k[6] = 1; k[7] = 2; k[8] = 1;
135
k[0] = 0; k[1] = -2; k[2] = 0;
136
k[3] = -2; k[4] = 11; k[5] = -2;
137
k[6] = 0; k[7] = -2; k[8] = 0;
142
k[0] = -1; k[1] = -1; k[2] = -1;
143
k[3] = -1; k[4] = 9; k[5] = -1;
144
k[6] = -1; k[7] = -1; k[8] = -1;
149
k[0] = -1; k[1] = 0; k[2] = -1;
150
k[3] = 0; k[4] = 4; k[5] = 0;
151
k[6] = -1; k[7] = 0; k[8] = -1;
160
k[0] = 1; k[1] = 1; k[2] = 1;
161
k[3] = 0; k[4] = 0; k[5] = 0;
162
k[6] = -1; k[7] = -1; k[8] = -1;
171
k[0] = 0; k[1] = 0; k[2] = 0;
172
k[3] = 0; k[4] = 1; k[5] = 0;
173
k[6] = 0; k[7] = 0; k[8] = 0;
178
assert(!"Unhandled switch value");
182
static void setupConvolution()
184
GLint *kernel = (GLint*)malloc(sizeof(GLint) * 9);
186
GLfloat *vecKer = (GLfloat*)malloc(sizeof(GLfloat) * 9 * 4);
189
GLfloat baseColor[4];
195
fillConvolution(kernel, &scale, baseColor);
197
for (i = 0; i < 9; ++i) {
198
vecKer[i*4 + 0] = kernel[i];
199
vecKer[i*4 + 1] = kernel[i];
200
vecKer[i*4 + 2] = kernel[i];
201
vecKer[i*4 + 3] = kernel[i];
204
loc = glGetUniformLocationARB(program, "KernelValue");
205
glUniform4fv(loc, 9, vecKer);
206
loc = glGetUniformLocationARB(program, "ScaleFactor");
207
glUniform4f(loc, scale, scale, scale, scale);
208
loc = glGetUniformLocationARB(program, "BaseColor");
209
glUniform4f(loc, baseColor[0], baseColor[1],
210
baseColor[2], baseColor[3]);
216
static void createProgram(const char *vertProgFile,
217
const char *fragProgFile)
219
GLuint fragShader = 0, vertShader = 0;
221
program = glCreateProgram();
223
vertShader = glCreateShader(GL_VERTEX_SHADER);
224
readShader(vertShader, vertProgFile);
225
glAttachShader(program, vertShader);
229
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
230
readShader(fragShader, fragProgFile);
231
glAttachShader(program, fragShader);
234
glLinkProgram(program);
237
glUseProgram(program);
240
assert(glIsProgram(program));
241
assert(glIsShader(fragShader));
242
assert(glIsShader(vertShader));
245
checkError(__LINE__);
247
GLuint texLoc = glGetUniformLocationARB(program, "srcTex");
248
glUniform1iARB(texLoc, 0);
251
float offsets[] = { 1.0 / texture.width, 1.0 / texture.height,
252
0.0 , 1.0 / texture.height,
253
-1.0 / texture.width, 1.0 / texture.height,
254
1.0 / texture.width, 0.0,
256
-1.0 / texture.width, 0.0,
257
1.0 / texture.width, -1.0 / texture.height,
258
0.0 , -1.0 / texture.height,
259
-1.0 / texture.width, -1.0 / texture.height };
260
GLuint offsetLoc = glGetUniformLocationARB(program, "Offset");
261
glUniform2fv(offsetLoc, 9, offsets);
265
checkError(__LINE__);
269
static void readTexture(const char *filename)
276
glGenTextures(1, &texture.id);
277
glBindTexture(GL_TEXTURE_2D, texture.id);
278
glTexParameteri(GL_TEXTURE_2D,
279
GL_TEXTURE_MIN_FILTER, GL_NEAREST);
280
glTexParameteri(GL_TEXTURE_2D,
281
GL_TEXTURE_MAG_FILTER, GL_NEAREST);
282
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
283
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
284
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
285
data = LoadRGBImage(filename, &texture.width, &texture.height,
288
printf("Error: couldn't load texture image '%s'\n", filename);
291
printf("Texture %s (%d x %d)\n",
292
filename, texture.width, texture.height);
293
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
294
texture.width, texture.height, 0, texture.format,
295
GL_UNSIGNED_BYTE, data);
298
static void menuSelected(int entry)
305
filter = (enum Filter)entry;
312
static void menuInit()
314
menuId = glutCreateMenu(menuSelected);
316
glutAddMenuEntry("Gaussian blur", GAUSSIAN_BLUR);
317
glutAddMenuEntry("Sharpen", SHARPEN);
318
glutAddMenuEntry("Mean removal", MEAN_REMOVAL);
319
glutAddMenuEntry("Emboss", EMBOSS);
320
glutAddMenuEntry("Edge detect", EDGE_DETECT);
321
glutAddMenuEntry("None", NO_FILTER);
323
glutAddMenuEntry("Quit", QUIT);
325
glutAttachMenu(GLUT_RIGHT_BUTTON);
330
if (!glutExtensionSupported("GL_ARB_shader_objects") ||
331
!glutExtensionSupported("GL_ARB_vertex_shader") ||
332
!glutExtensionSupported("GL_ARB_fragment_shader")) {
333
fprintf(stderr, "Sorry, this program requires GL_ARB_shader_objects, GL_ARB_vertex_shader, and GL_ARB_fragment_shader\n");
337
fprintf(stderr, "GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
338
fprintf(stderr, "GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
339
fprintf(stderr, "GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
342
readTexture(textureLocation);
343
createProgram("convolution.vert", "convolution.frag");
345
glEnable(GL_TEXTURE_2D);
346
glClearColor(1.0, 1.0, 1.0, 1.0);
347
/*glShadeModel(GL_SMOOTH);*/
348
glShadeModel(GL_FLAT);
351
static void reshape(int width, int height)
353
glViewport(0, 0, width, height);
354
glMatrixMode(GL_PROJECTION);
362
glOrtho(box.minx, box.maxx, box.miny, box.maxy, -999999, 999999);
363
glMatrixMode(GL_MODELVIEW);
366
static void keyPress(unsigned char key, int x, int y)
378
special(int k, int x, int y)
405
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
410
center[0] = box.maxx/2;
411
center[1] = box.maxy/2;
412
anchor[0] = center[0] - texture.width/2;
413
anchor[1] = center[1] - texture.height/2;
415
glTranslatef(center[0], center[1], 0);
416
glRotatef(viewRotx, 1.0, 0.0, 0.0);
417
glRotatef(viewRoty, 0.0, 1.0, 0.0);
418
glRotatef(viewRotz, 0.0, 0.0, 1.0);
419
glTranslatef(-center[0], -center[1], 0);
421
glTranslatef(anchor[0], anchor[1], 0);
422
glBegin(GL_TRIANGLE_STRIP);
424
glColor3f(1., 0., 0.);
428
glColor3f(0., 1., 0.);
429
glTexCoord2f(0, 1.0);
430
glVertex3f(0, texture.height, 0);
432
glColor3f(1., 0., 0.);
433
glTexCoord2f(1.0, 0);
434
glVertex3f(texture.width, 0, 0);
436
glColor3f(0., 1., 0.);
438
glVertex3f(texture.width, texture.height, 0);
447
int main(int argc, char **argv)
449
glutInit(&argc, argv);
451
glutInitWindowSize(400, 400);
452
glutInitDisplayMode(GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE);
454
if (!glutCreateWindow("Image Convolutions")) {
455
fprintf(stderr, "Couldn't create window!\n");
462
glutReshapeFunc(reshape);
463
glutKeyboardFunc(keyPress);
464
glutSpecialFunc(special);
465
glutDisplayFunc(draw);