fractorb

view src/main.c @ 2:03e8b9a5031d

screenshot function
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 20 Nov 2017 03:53:02 +0200
parents 436f82447c44
children f440ecffc45a
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <errno.h>
6 #include <dirent.h>
7 #include <GL/glew.h>
8 #include <GL/glut.h>
9 #include "sdr.h"
11 int init(void);
12 void cleanup(void);
13 void disp(void);
14 void reshape(int x, int y);
15 void keydown(unsigned char key, int x, int y);
16 void keyup(unsigned char key, int x, int y);
17 void mouse(int bn, int st, int x, int y);
18 void motion(int x, int y);
19 void screenshot(void);
21 static int win_width = 1280, win_height = 800;
22 static float win_aspect;
23 static int mouse_x = 640, mouse_y = 400;
24 static unsigned int prog_mbrot;
26 static float view_center[2] = {0.7, 0.0};
27 static float view_scale = 1.2;
30 int main(int argc, char **argv)
31 {
32 glutInit(&argc, argv);
33 glutInitWindowSize(1280, 800);
34 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
35 glutCreateWindow("fractorb");
37 glutDisplayFunc(disp);
38 glutReshapeFunc(reshape);
39 glutKeyboardFunc(keydown);
40 glutKeyboardUpFunc(keyup);
41 glutMouseFunc(mouse);
42 glutMotionFunc(motion);
44 if(init() == -1) {
45 return 1;
46 }
47 atexit(cleanup);
49 glutMainLoop();
50 return 0;
51 }
54 int init(void)
55 {
56 glewInit();
58 if(!(prog_mbrot = create_program_load("vertex.glsl", "mbrot.glsl"))) {
59 return -1;
60 }
61 return 0;
62 }
64 void cleanup(void)
65 {
66 free_program(prog_mbrot);
67 }
69 void pixel_to_complex(float *res, float px, float py)
70 {
71 float u = (2.0 * px / win_width - 1.0) * win_aspect;
72 float v = 2.0 * py / win_height - 1.0;
73 res[0] = u * view_scale - view_center[0];
74 res[1] = v * view_scale - view_center[1];
75 }
77 void disp(void)
78 {
79 int i;
80 float seed[2];
81 static const float verts[][2] = {{-1, -1}, {1, -1}, {1, 1}, {-1, 1}};
82 static const float corners[][2] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
84 pixel_to_complex(seed, mouse_x, mouse_y);
86 set_uniform_float2(prog_mbrot, "seed", seed[0], seed[1]);
87 set_uniform_float(prog_mbrot, "view_scale", view_scale);
88 set_uniform_float2(prog_mbrot, "view_center", view_center[0], view_center[1]);
89 glUseProgram(prog_mbrot);
91 glBegin(GL_QUADS);
92 for(i=0; i<4; i++) {
93 float bv[2];
94 pixel_to_complex(bv, (win_width - 1) * corners[i][0], (win_height - 1) * corners[i][1]);
95 glTexCoord2f(bv[0], bv[1]);
96 glVertex2f(verts[i][0], verts[i][1]);
97 }
98 glEnd();
100 glutSwapBuffers();
101 }
103 void reshape(int x, int y)
104 {
105 glViewport(0, 0, x, y);
107 win_aspect = (float)x / (float)y;
108 win_width = x;
109 win_height = y;
110 }
112 static int keystate[256];
114 void keydown(unsigned char key, int x, int y)
115 {
116 static int fullscreen;
117 static int prev_width, prev_height;
119 switch(key) {
120 case 27:
121 exit(0);
123 case 'f':
124 fullscreen = !fullscreen;
125 if(fullscreen) {
126 prev_width = win_width;
127 prev_height = win_height;
128 glutFullScreen();
129 } else {
130 glutReshapeWindow(prev_width, prev_height);
131 }
132 break;
134 case '`':
135 screenshot();
136 break;
138 default:
139 break;
140 }
141 keystate[key] = 1;
142 }
144 void keyup(unsigned char key, int x, int y)
145 {
146 keystate[key] = 0;
147 }
149 static int prev_x, prev_y;
150 static int bnstate[8];
152 void mouse(int bn, int st, int x, int y)
153 {
154 prev_x = x;
155 prev_y = y;
156 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
157 }
159 void motion(int x, int y)
160 {
161 int dx = x - prev_x;
162 int dy = y - prev_y;
163 prev_x = x;
164 prev_y = y;
166 if(!(dx | dy)) return;
168 if(bnstate[0]) {
169 if(keystate['s']) {
170 mouse_x = x;
171 mouse_y = y;
172 } else if(keystate['z']) {
173 float s = sqrt(view_scale);
174 view_scale += dy * 0.01 * s;
175 if(view_scale < 1e-8) view_scale = 1e-8;
176 } else {
177 float s = sqrt(view_scale);
178 view_center[0] += 0.01 * dx * s;
179 view_center[1] += 0.01 * dy * s;
180 }
181 glutPostRedisplay();
182 }
183 }
185 void screenshot(void)
186 {
187 FILE *fp;
188 DIR *dir;
189 struct dirent *dent;
190 unsigned char *img;
191 static int shotnum = -1;
192 char fname[128];
194 if(shotnum == -1) {
195 shotnum = 1;
196 if((dir = opendir("."))) {
197 while((dent = readdir(dir))) {
198 int num;
199 if(sscanf(dent->d_name, "img%d.ppm", &num) == 1) {
200 if(num >= shotnum) shotnum = num + 1;
201 }
202 }
203 closedir(dir);
204 }
205 } else {
206 ++shotnum;
207 }
209 sprintf(fname, "img%04d.ppm", shotnum > 0 ? shotnum : 0);
210 if(!(fp = fopen(fname, "wb"))) {
211 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
212 return;
213 }
215 if(!(img = malloc(win_width * win_height * 3))) {
216 fprintf(stderr, "failed to allocate screenshot buffer\n");
217 fclose(fp);
218 return;
219 }
221 glReadPixels(0, 0, win_width, win_height, GL_RGB, GL_UNSIGNED_BYTE, img);
223 fprintf(fp, "P6\n%d %d\n255\n", win_width, win_height);
224 fwrite(img, 1, win_width * win_height * 3, fp);
225 fclose(fp);
226 free(img);
227 return;
228 }