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