progs/glsl: compile with scons and glew
[mesa.git] / progs / glsl / convolutions.c
1 /**
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.
5 * Author: Zack Rusin
6 */
7
8 #include <GL/glew.h>
9
10 #define GL_GLEXT_PROTOTYPES
11 #include "readtex.h"
12
13 #include <GL/glut.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <assert.h>
17 #include <math.h>
18
19 enum Filter {
20 GAUSSIAN_BLUR,
21 SHARPEN,
22 MEAN_REMOVAL,
23 EMBOSS,
24 EDGE_DETECT,
25 NO_FILTER,
26 LAST
27 };
28 #define QUIT LAST
29
30 struct BoundingBox {
31 float minx, miny, minz;
32 float maxx, maxy, maxz;
33 };
34 struct Texture {
35 GLuint id;
36 GLfloat x;
37 GLfloat y;
38 GLint width;
39 GLint height;
40 GLenum format;
41 };
42
43 static const char *textureLocation = "../images/girl2.rgb";
44
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;
49 static GLint menuId;
50 static enum Filter filter = GAUSSIAN_BLUR;
51
52
53 static void checkError(int line)
54 {
55 GLenum err = glGetError();
56 if (err) {
57 printf("GL Error %s (0x%x) at line %d\n",
58 gluErrorString(err), (int) err, line);
59 }
60 }
61
62 static void loadAndCompileShader(GLuint shader, const char *text)
63 {
64 GLint stat;
65
66 glShaderSource(shader, 1, (const GLchar **) &text, NULL);
67
68 glCompileShader(shader);
69
70 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
71 if (!stat) {
72 GLchar log[1000];
73 GLsizei len;
74 glGetShaderInfoLog(shader, 1000, &len, log);
75 fprintf(stderr, "Problem compiling shader: %s\n", log);
76 exit(1);
77 }
78 else {
79 printf("Shader compiled OK\n");
80 }
81 }
82
83 static void readShader(GLuint shader, const char *filename)
84 {
85 const int max = 100*1000;
86 int n;
87 char *buffer = (char*) malloc(max);
88 FILE *f = fopen(filename, "r");
89 if (!f) {
90 fprintf(stderr, "Unable to open shader file %s\n", filename);
91 exit(1);
92 }
93
94 n = fread(buffer, 1, max, f);
95 printf("Read %d bytes from shader file %s\n", n, filename);
96 if (n > 0) {
97 buffer[n] = 0;
98 loadAndCompileShader(shader, buffer);
99 }
100
101 fclose(f);
102 free(buffer);
103 }
104
105
106 static void
107 checkLink(GLuint prog)
108 {
109 GLint stat;
110 glGetProgramiv(prog, GL_LINK_STATUS, &stat);
111 if (!stat) {
112 GLchar log[1000];
113 GLsizei len;
114 glGetProgramInfoLog(prog, 1000, &len, log);
115 fprintf(stderr, "Linker error:\n%s\n", log);
116 }
117 else {
118 fprintf(stderr, "Link success!\n");
119 }
120 }
121
122 static void fillConvolution(GLint *k,
123 GLfloat *scale,
124 GLfloat *color)
125 {
126 switch(filter) {
127 case GAUSSIAN_BLUR:
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;
131
132 *scale = 1./16.;
133 break;
134 case SHARPEN:
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;
138
139 *scale = 1./3.;
140 break;
141 case MEAN_REMOVAL:
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;
145
146 *scale = 1./1.;
147 break;
148 case EMBOSS:
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;
152
153 *scale = 1./1.;
154 color[0] = 0.5;
155 color[1] = 0.5;
156 color[2] = 0.5;
157 color[3] = 0.5;
158 break;
159 case EDGE_DETECT:
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;
163
164 *scale = 1.;
165 color[0] = 0.5;
166 color[1] = 0.5;
167 color[2] = 0.5;
168 color[3] = 0.5;
169 break;
170 case NO_FILTER:
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;
174
175 *scale = 1.;
176 break;
177 default:
178 assert(!"Unhandled switch value");
179 }
180 }
181
182 static void setupConvolution()
183 {
184 GLint *kernel = (GLint*)malloc(sizeof(GLint) * 9);
185 GLfloat scale;
186 GLfloat *vecKer = (GLfloat*)malloc(sizeof(GLfloat) * 9 * 4);
187 GLuint loc;
188 GLuint i;
189 GLfloat baseColor[4];
190 baseColor[0] = 0;
191 baseColor[1] = 0;
192 baseColor[2] = 0;
193 baseColor[3] = 0;
194
195 fillConvolution(kernel, &scale, baseColor);
196 /*vector of 4*/
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];
202 }
203
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]);
211
212 free(vecKer);
213 free(kernel);
214 }
215
216 static void createProgram(const char *vertProgFile,
217 const char *fragProgFile)
218 {
219 GLuint fragShader = 0, vertShader = 0;
220
221 program = glCreateProgram();
222 if (vertProgFile) {
223 vertShader = glCreateShader(GL_VERTEX_SHADER);
224 readShader(vertShader, vertProgFile);
225 glAttachShader(program, vertShader);
226 }
227
228 if (fragProgFile) {
229 fragShader = glCreateShader(GL_FRAGMENT_SHADER);
230 readShader(fragShader, fragProgFile);
231 glAttachShader(program, fragShader);
232 }
233
234 glLinkProgram(program);
235 checkLink(program);
236
237 glUseProgram(program);
238
239 /*
240 assert(glIsProgram(program));
241 assert(glIsShader(fragShader));
242 assert(glIsShader(vertShader));
243 */
244
245 checkError(__LINE__);
246 {/*texture*/
247 GLuint texLoc = glGetUniformLocationARB(program, "srcTex");
248 glUniform1iARB(texLoc, 0);
249 }
250 {/*setup offsets */
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,
255 0.0 , 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);
262 }
263 setupConvolution();
264
265 checkError(__LINE__);
266 }
267
268
269 static void readTexture(const char *filename)
270 {
271 GLubyte *data;
272
273 texture.x = 0;
274 texture.y = 0;
275
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,
286 &texture.format);
287 if (!data) {
288 printf("Error: couldn't load texture image '%s'\n", filename);
289 exit(1);
290 }
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);
296 }
297
298 static void menuSelected(int entry)
299 {
300 switch (entry) {
301 case QUIT:
302 exit(0);
303 break;
304 default:
305 filter = (enum Filter)entry;
306 }
307 setupConvolution();
308
309 glutPostRedisplay();
310 }
311
312 static void menuInit()
313 {
314 menuId = glutCreateMenu(menuSelected);
315
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);
322
323 glutAddMenuEntry("Quit", QUIT);
324
325 glutAttachMenu(GLUT_RIGHT_BUTTON);
326 }
327
328 static void init()
329 {
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");
334 exit(1);
335 }
336
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));
340
341 menuInit();
342 readTexture(textureLocation);
343 createProgram("convolution.vert", "convolution.frag");
344
345 glEnable(GL_TEXTURE_2D);
346 glClearColor(1.0, 1.0, 1.0, 1.0);
347 /*glShadeModel(GL_SMOOTH);*/
348 glShadeModel(GL_FLAT);
349 }
350
351 static void reshape(int width, int height)
352 {
353 glViewport(0, 0, width, height);
354 glMatrixMode(GL_PROJECTION);
355 glLoadIdentity();
356 box.minx = 0;
357 box.maxx = width;
358 box.miny = 0;
359 box.maxy = height;
360 box.minz = 0;
361 box.maxz = 1;
362 glOrtho(box.minx, box.maxx, box.miny, box.maxy, -999999, 999999);
363 glMatrixMode(GL_MODELVIEW);
364 }
365
366 static void keyPress(unsigned char key, int x, int y)
367 {
368 switch(key) {
369 case 27:
370 exit(0);
371 default:
372 return;
373 }
374 glutPostRedisplay();
375 }
376
377 static void
378 special(int k, int x, int y)
379 {
380 switch (k) {
381 case GLUT_KEY_UP:
382 viewRotx += 2.0;
383 break;
384 case GLUT_KEY_DOWN:
385 viewRotx -= 2.0;
386 break;
387 case GLUT_KEY_LEFT:
388 viewRoty += 2.0;
389 break;
390 case GLUT_KEY_RIGHT:
391 viewRoty -= 2.0;
392 break;
393 default:
394 return;
395 }
396 glutPostRedisplay();
397 }
398
399
400 static void draw()
401 {
402 GLfloat center[2];
403 GLfloat anchor[2];
404
405 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
406
407 glLoadIdentity();
408 glPushMatrix();
409
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;
414
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);
420
421 glTranslatef(anchor[0], anchor[1], 0);
422 glBegin(GL_TRIANGLE_STRIP);
423 {
424 glColor3f(1., 0., 0.);
425 glTexCoord2f(0, 0);
426 glVertex3f(0, 0, 0);
427
428 glColor3f(0., 1., 0.);
429 glTexCoord2f(0, 1.0);
430 glVertex3f(0, texture.height, 0);
431
432 glColor3f(1., 0., 0.);
433 glTexCoord2f(1.0, 0);
434 glVertex3f(texture.width, 0, 0);
435
436 glColor3f(0., 1., 0.);
437 glTexCoord2f(1, 1);
438 glVertex3f(texture.width, texture.height, 0);
439 }
440 glEnd();
441
442 glPopMatrix();
443
444 glutSwapBuffers();
445 }
446
447 int main(int argc, char **argv)
448 {
449 glutInit(&argc, argv);
450
451 glutInitWindowPosition(0, 0);
452 glutInitWindowSize(400, 400);
453 glutInitDisplayMode(GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE);
454
455 if (!glutCreateWindow("Image Convolutions")) {
456 fprintf(stderr, "Couldn't create window!\n");
457 exit(1);
458 }
459
460 glewInit();
461 init();
462
463 glutReshapeFunc(reshape);
464 glutKeyboardFunc(keyPress);
465 glutSpecialFunc(special);
466 glutDisplayFunc(draw);
467
468
469 glutMainLoop();
470 return 0;
471 }