blob: 9b9ee532453ff52a92afea68cab5851fc9ca66cc [file] [log] [blame]
Brian Paulce00d232008-08-16 09:34:12 -06001#define GL_GLEXT_PROTOTYPES
2#include "readtex.h"
3
4#include <GL/glut.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
8#include <math.h>
9
10enum Filter {
11 GAUSSIAN_BLUR,
12 SHARPEN,
13 MEAN_REMOVAL,
14 EMBOSS,
15 EDGE_DETECT,
16 NO_FILTER,
17 LAST
18};
19#define QUIT LAST
20
21struct BoundingBox {
22 float minx, miny, minz;
23 float maxx, maxy, maxz;
24};
25struct Texture {
26 GLuint id;
27 GLfloat x;
28 GLfloat y;
29 GLint width;
30 GLint height;
31 GLenum format;
32};
33
34static const char *textureLocation = "../images/girl2.rgb";
35
36static GLfloat viewRotx = 0.0, viewRoty = 0.0, viewRotz = 0.0;
37static struct BoundingBox box;
38static struct Texture texture;
39static GLuint program;
40static GLint menuId;
41static enum Filter filter = GAUSSIAN_BLUR;
42
43
44static void checkError(int line)
45{
46 GLenum err = glGetError();
47 if (err) {
48 printf("GL Error %s (0x%x) at line %d\n",
49 gluErrorString(err), (int) err, line);
50 }
51}
52
53static void loadAndCompileShader(GLuint shader, const char *text)
54{
55 GLint stat;
56
57 glShaderSource(shader, 1, (const GLchar **) &text, NULL);
58
59 glCompileShader(shader);
60
61 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
62 if (!stat) {
63 GLchar log[1000];
64 GLsizei len;
65 glGetShaderInfoLog(shader, 1000, &len, log);
66 fprintf(stderr, "Problem compiling shader: %s\n", log);
67 exit(1);
68 }
69 else {
70 printf("Shader compiled OK\n");
71 }
72}
73
74static void readShader(GLuint shader, const char *filename)
75{
76 const int max = 100*1000;
77 int n;
78 char *buffer = (char*) malloc(max);
79 FILE *f = fopen(filename, "r");
80 if (!f) {
81 fprintf(stderr, "Unable to open shader file %s\n", filename);
82 exit(1);
83 }
84
85 n = fread(buffer, 1, max, f);
86 printf("Read %d bytes from shader file %s\n", n, filename);
87 if (n > 0) {
88 buffer[n] = 0;
89 loadAndCompileShader(shader, buffer);
90 }
91
92 fclose(f);
93 free(buffer);
94}
95
96
97static void
98checkLink(GLuint prog)
99{
100 GLint stat;
101 glGetProgramiv(prog, GL_LINK_STATUS, &stat);
102 if (!stat) {
103 GLchar log[1000];
104 GLsizei len;
105 glGetProgramInfoLog(prog, 1000, &len, log);
106 fprintf(stderr, "Linker error:\n%s\n", log);
107 }
108 else {
109 fprintf(stderr, "Link success!\n");
110 }
111}
112
113static void fillConvolution(GLint *k,
114 GLfloat *scale,
115 GLfloat *color)
116{
117 switch(filter) {
118 case GAUSSIAN_BLUR:
119 k[0] = 1; k[1] = 2; k[2] = 1;
120 k[3] = 2; k[4] = 4; k[5] = 2;
121 k[6] = 1; k[7] = 2; k[8] = 1;
122
123 *scale = 1./16.;
124 break;
125 case SHARPEN:
126 k[0] = 0; k[1] = -2; k[2] = 0;
127 k[3] = -2; k[4] = 11; k[5] = -2;
128 k[6] = 0; k[7] = -2; k[8] = 0;
129
130 *scale = 1./3.;
131 break;
132 case MEAN_REMOVAL:
133 k[0] = -1; k[1] = -1; k[2] = -1;
134 k[3] = -1; k[4] = 9; k[5] = -1;
135 k[6] = -1; k[7] = -1; k[8] = -1;
136
137 *scale = 1./1.;
138 break;
139 case EMBOSS:
140 k[0] = -1; k[1] = 0; k[2] = -1;
141 k[3] = 0; k[4] = 4; k[5] = 0;
142 k[6] = -1; k[7] = 0; k[8] = -1;
143
144 *scale = 1./1.;
145 color[0] = 0.5;
146 color[1] = 0.5;
147 color[2] = 0.5;
148 color[3] = 0.5;
149 break;
150 case EDGE_DETECT:
151 k[0] = 1; k[1] = 1; k[2] = 1;
152 k[3] = 0; k[4] = 0; k[5] = 0;
153 k[6] = -1; k[7] = -1; k[8] = -1;
154
155 *scale = 1.;
156 color[0] = 0.5;
157 color[1] = 0.5;
158 color[2] = 0.5;
159 color[3] = 0.5;
160 break;
161 case NO_FILTER:
162 k[0] = 0; k[1] = 0; k[2] = 0;
163 k[3] = 0; k[4] = 1; k[5] = 0;
164 k[6] = 0; k[7] = 0; k[8] = 0;
165
166 *scale = 1.;
167 break;
168 default:
169 assert(!"Unhandled switch value");
170 }
171}
172
173static void setupConvolution()
174{
175 GLint *kernel = (GLint*)malloc(sizeof(GLint) * 9);
176 GLfloat scale;
177 GLfloat *vecKer = (GLfloat*)malloc(sizeof(GLfloat) * 9 * 4);
178 GLuint loc;
179 GLuint i;
180 GLfloat baseColor[4];
181 baseColor[0] = 0;
182 baseColor[1] = 0;
183 baseColor[2] = 0;
184 baseColor[3] = 0;
185
186 fillConvolution(kernel, &scale, baseColor);
187 /*vector of 4*/
188 for (i = 0; i < 9; ++i) {
189 vecKer[i*4 + 0] = kernel[i];
190 vecKer[i*4 + 1] = kernel[i];
191 vecKer[i*4 + 2] = kernel[i];
192 vecKer[i*4 + 3] = kernel[i];
193 }
194
195 loc = glGetUniformLocationARB(program, "KernelValue");
196 glUniform4fv(loc, 9, vecKer);
197 loc = glGetUniformLocationARB(program, "ScaleFactor");
198 glUniform4f(loc, scale, scale, scale, scale);
199 loc = glGetUniformLocationARB(program, "BaseColor");
200 glUniform4f(loc, baseColor[0], baseColor[1],
201 baseColor[2], baseColor[3]);
202
203 free(vecKer);
204 free(kernel);
205}
206
207static void createProgram(const char *vertProgFile,
208 const char *fragProgFile)
209{
210 GLuint fragShader = 0, vertShader = 0;
211
212 program = glCreateProgram();
213 if (vertProgFile) {
214 vertShader = glCreateShader(GL_VERTEX_SHADER);
215 readShader(vertShader, vertProgFile);
216 glAttachShader(program, vertShader);
217 }
218
219 if (fragProgFile) {
220 fragShader = glCreateShader(GL_FRAGMENT_SHADER);
221 readShader(fragShader, fragProgFile);
222 glAttachShader(program, fragShader);
223 }
224
225 glLinkProgram(program);
226 checkLink(program);
227
228 glUseProgram(program);
229
230 assert(glIsProgram(program));
231 assert(glIsShader(fragShader));
232 assert(glIsShader(vertShader));
233
234 checkError(__LINE__);
235 {/*texture*/
236 GLuint texLoc = glGetUniformLocationARB(program, "srcTex");
237 glUniform1iARB(texLoc, 0);
238 }
239 {/*setup offsets */
240 float offsets[] = { 1.0 / texture.width, 1.0 / texture.height,
241 0.0 , 1.0 / texture.height,
242 -1.0 / texture.width, 1.0 / texture.height,
243 1.0 / texture.width, 0.0,
244 0.0 , 0.0,
245 -1.0 / texture.width, 0.0,
246 1.0 / texture.width, -1.0 / texture.height,
247 0.0 , -1.0 / texture.height,
248 -1.0 / texture.width, -1.0 / texture.height };
249 GLuint offsetLoc = glGetUniformLocationARB(program, "Offset");
250 glUniform2fv(offsetLoc, 9, offsets);
251 }
252 setupConvolution();
253
254 checkError(__LINE__);
255}
256
257
258static void readTexture(const char *filename)
259{
260 GLubyte *data;
261
262 texture.x = 0;
263 texture.y = 0;
264
265 glGenTextures(1, &texture.id);
266 glBindTexture(GL_TEXTURE_2D, texture.id);
267 glTexParameteri(GL_TEXTURE_2D,
268 GL_TEXTURE_MIN_FILTER, GL_NEAREST);
269 glTexParameteri(GL_TEXTURE_2D,
270 GL_TEXTURE_MAG_FILTER, GL_NEAREST);
271 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
272 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
273 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
274 data = LoadRGBImage(filename, &texture.width, &texture.height,
275 &texture.format);
276 if (!data) {
277 printf("Error: couldn't load texture image '%s'\n", filename);
278 exit(1);
279 }
280 printf("Texture %s (%d x %d)\n",
281 filename, texture.width, texture.height);
282 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
283 texture.width, texture.height, 0, texture.format,
284 GL_UNSIGNED_BYTE, data);
285}
286
287static void menuSelected(int entry)
288{
289 switch (entry) {
290 case QUIT:
291 exit(0);
292 break;
293 default:
294 filter = (enum Filter)entry;
295 }
296 setupConvolution();
297
298 glutPostRedisplay();
299}
300
301static void menuInit()
302{
303 menuId = glutCreateMenu(menuSelected);
304
305 glutAddMenuEntry("Gaussian blur", GAUSSIAN_BLUR);
306 glutAddMenuEntry("Sharpen", SHARPEN);
307 glutAddMenuEntry("Mean removal", MEAN_REMOVAL);
308 glutAddMenuEntry("Emboss", EMBOSS);
309 glutAddMenuEntry("Edge detect", EDGE_DETECT);
310 glutAddMenuEntry("None", NO_FILTER);
311
312 glutAddMenuEntry("Quit", QUIT);
313
314 glutAttachMenu(GLUT_RIGHT_BUTTON);
315}
316
317static void init()
318{
319 fprintf(stderr, "GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
320 fprintf(stderr, "GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
321 fprintf(stderr, "GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
322
323 menuInit();
324 readTexture(textureLocation);
325 createProgram("convolution.vert", "convolution.frag");
326
327 glEnable(GL_TEXTURE_2D);
328 glClearColor(1.0, 1.0, 1.0, 1.0);
329 /*glShadeModel(GL_SMOOTH);*/
330 glShadeModel(GL_FLAT);
331}
332
333static void reshape(int width, int height)
334{
335 glViewport(0, 0, width, height);
336 glMatrixMode(GL_PROJECTION);
337 glLoadIdentity();
338 box.minx = 0;
339 box.maxx = width;
340 box.miny = 0;
341 box.maxy = height;
342 box.minz = 0;
343 box.maxz = 1;
344 glOrtho(box.minx, box.maxx, box.miny, box.maxy, -999999, 999999);
345 glMatrixMode(GL_MODELVIEW);
346}
347
348static void keyPress(unsigned char key, int x, int y)
349{
350 switch(key) {
351 case 27:
352 exit(0);
353 default:
354 return;
355 }
356 glutPostRedisplay();
357}
358
359static void
360special(int k, int x, int y)
361{
362 switch (k) {
363 case GLUT_KEY_UP:
364 viewRotx += 2.0;
365 break;
366 case GLUT_KEY_DOWN:
367 viewRotx -= 2.0;
368 break;
369 case GLUT_KEY_LEFT:
370 viewRoty += 2.0;
371 break;
372 case GLUT_KEY_RIGHT:
373 viewRoty -= 2.0;
374 break;
375 default:
376 return;
377 }
378 glutPostRedisplay();
379}
380
381
382static void draw()
383{
384 GLfloat center[2];
385 GLfloat anchor[2];
386
387 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
388
389 glLoadIdentity();
390 glPushMatrix();
391
392 center[0] = box.maxx/2;
393 center[1] = box.maxy/2;
394 anchor[0] = center[0] - texture.width/2;
395 anchor[1] = center[1] - texture.height/2;
396
397 glTranslatef(center[0], center[1], 0);
398 glRotatef(viewRotx, 1.0, 0.0, 0.0);
399 glRotatef(viewRoty, 0.0, 1.0, 0.0);
400 glRotatef(viewRotz, 0.0, 0.0, 1.0);
401 glTranslatef(-center[0], -center[1], 0);
402
403 glTranslatef(anchor[0], anchor[1], 0);
404 glBegin(GL_TRIANGLE_STRIP);
405 {
406 glColor3f(1., 0., 0.);
407 glTexCoord2f(0, 0);
408 glVertex3f(0, 0, 0);
409
410 glColor3f(0., 1., 0.);
411 glTexCoord2f(0, 1.0);
412 glVertex3f(0, texture.height, 0);
413
414 glColor3f(1., 0., 0.);
415 glTexCoord2f(1.0, 0);
416 glVertex3f(texture.width, 0, 0);
417
418 glColor3f(0., 1., 0.);
419 glTexCoord2f(1, 1);
420 glVertex3f(texture.width, texture.height, 0);
421 }
422 glEnd();
423
424 glPopMatrix();
425
426 glFlush();
427
428 glutSwapBuffers();
429}
430
431int main(int argc, char **argv)
432{
433 glutInit(&argc, argv);
434
435 glutInitWindowPosition(0, 0);
436 glutInitWindowSize(400, 400);
437 glutInitDisplayMode(GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE);
438
439 if (!glutCreateWindow("Image Convolutions")) {
440 fprintf(stderr, "Couldn't create window!\n");
441 exit(1);
442 }
443
444 init();
445
446 glutReshapeFunc(reshape);
447 glutKeyboardFunc(keyPress);
448 glutSpecialFunc(special);
449 glutDisplayFunc(draw);
450
451
452 glutMainLoop();
453 return 0;
454}