rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@2
|
3 #include <string.h>
|
nuclear@1
|
4 #include <math.h>
|
nuclear@2
|
5 #include <errno.h>
|
nuclear@2
|
6 #include <dirent.h>
|
nuclear@0
|
7 #include <GL/glew.h>
|
nuclear@0
|
8 #include <GL/glut.h>
|
nuclear@0
|
9 #include "sdr.h"
|
nuclear@0
|
10
|
nuclear@3
|
11 enum {
|
nuclear@3
|
12 SDR_LINE_DIST_BIT = 1,
|
nuclear@3
|
13 SDR_PLOT_ORBIT_BIT = 2
|
nuclear@3
|
14 };
|
nuclear@3
|
15 const char *sdrdef[] = {
|
nuclear@3
|
16 "#define LINE_DIST\n",
|
nuclear@3
|
17 "#define PLOT_ORBIT\n"
|
nuclear@3
|
18 };
|
nuclear@3
|
19 #define NUM_SDR_BITS (sizeof sdrdef / sizeof *sdrdef)
|
nuclear@3
|
20 #define NUM_SHADERS (1 << NUM_SDR_BITS)
|
nuclear@3
|
21
|
nuclear@0
|
22 int init(void);
|
nuclear@0
|
23 void cleanup(void);
|
nuclear@0
|
24 void disp(void);
|
nuclear@0
|
25 void reshape(int x, int y);
|
nuclear@1
|
26 void keydown(unsigned char key, int x, int y);
|
nuclear@1
|
27 void keyup(unsigned char key, int x, int y);
|
nuclear@0
|
28 void mouse(int bn, int st, int x, int y);
|
nuclear@0
|
29 void motion(int x, int y);
|
nuclear@2
|
30 void screenshot(void);
|
nuclear@0
|
31
|
nuclear@1
|
32 static int win_width = 1280, win_height = 800;
|
nuclear@1
|
33 static float win_aspect;
|
nuclear@1
|
34 static int mouse_x = 640, mouse_y = 400;
|
nuclear@3
|
35 static unsigned int prog_mbrot[NUM_SHADERS];
|
nuclear@0
|
36
|
nuclear@1
|
37 static float view_center[2] = {0.7, 0.0};
|
nuclear@1
|
38 static float view_scale = 1.2;
|
nuclear@1
|
39
|
nuclear@3
|
40 static unsigned int sdrflags;
|
nuclear@1
|
41
|
nuclear@0
|
42 int main(int argc, char **argv)
|
nuclear@0
|
43 {
|
nuclear@0
|
44 glutInit(&argc, argv);
|
nuclear@0
|
45 glutInitWindowSize(1280, 800);
|
nuclear@0
|
46 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
|
nuclear@0
|
47 glutCreateWindow("fractorb");
|
nuclear@0
|
48
|
nuclear@0
|
49 glutDisplayFunc(disp);
|
nuclear@0
|
50 glutReshapeFunc(reshape);
|
nuclear@1
|
51 glutKeyboardFunc(keydown);
|
nuclear@1
|
52 glutKeyboardUpFunc(keyup);
|
nuclear@0
|
53 glutMouseFunc(mouse);
|
nuclear@0
|
54 glutMotionFunc(motion);
|
nuclear@0
|
55
|
nuclear@0
|
56 if(init() == -1) {
|
nuclear@0
|
57 return 1;
|
nuclear@0
|
58 }
|
nuclear@0
|
59 atexit(cleanup);
|
nuclear@0
|
60
|
nuclear@0
|
61 glutMainLoop();
|
nuclear@0
|
62 return 0;
|
nuclear@0
|
63 }
|
nuclear@0
|
64
|
nuclear@0
|
65
|
nuclear@0
|
66 int init(void)
|
nuclear@0
|
67 {
|
nuclear@3
|
68 int i, j;
|
nuclear@3
|
69 unsigned int vs = 0, ps[NUM_SHADERS] = {0};
|
nuclear@3
|
70
|
nuclear@0
|
71 glewInit();
|
nuclear@0
|
72
|
nuclear@3
|
73 if(!(vs = load_vertex_shader("vertex.glsl"))) {
|
nuclear@0
|
74 return -1;
|
nuclear@0
|
75 }
|
nuclear@3
|
76
|
nuclear@3
|
77 for(i=0; i<NUM_SHADERS; i++) {
|
nuclear@3
|
78 clear_shader_header(GL_FRAGMENT_SHADER);
|
nuclear@3
|
79 for(j=0; j<NUM_SDR_BITS; j++) {
|
nuclear@3
|
80 if(i & (1 << j)) {
|
nuclear@3
|
81 add_shader_header(GL_FRAGMENT_SHADER, sdrdef[j]);
|
nuclear@3
|
82 }
|
nuclear@3
|
83 }
|
nuclear@3
|
84
|
nuclear@3
|
85 if(!(ps[i] = load_pixel_shader("mbrot.glsl"))) {
|
nuclear@3
|
86 goto err;
|
nuclear@3
|
87 }
|
nuclear@3
|
88
|
nuclear@3
|
89 if(!(prog_mbrot[i] = create_program_link(vs, ps[i], 0))) {
|
nuclear@3
|
90 goto err;
|
nuclear@3
|
91 }
|
nuclear@3
|
92 }
|
nuclear@0
|
93 return 0;
|
nuclear@3
|
94
|
nuclear@3
|
95 err:
|
nuclear@3
|
96 for(i=0; i<NUM_SHADERS; i++) {
|
nuclear@3
|
97 if(prog_mbrot[i]) {
|
nuclear@3
|
98 free_program(prog_mbrot[i]);
|
nuclear@3
|
99 prog_mbrot[i] = 0;
|
nuclear@3
|
100 }
|
nuclear@3
|
101 if(ps[i]) {
|
nuclear@3
|
102 free_shader(ps[i]);
|
nuclear@3
|
103 }
|
nuclear@3
|
104 }
|
nuclear@3
|
105 if(vs) {
|
nuclear@3
|
106 free_shader(vs);
|
nuclear@3
|
107 }
|
nuclear@3
|
108 return -1;
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 void cleanup(void)
|
nuclear@0
|
112 {
|
nuclear@3
|
113 int i;
|
nuclear@3
|
114
|
nuclear@3
|
115 for(i=0; i<NUM_SHADERS; i++) {
|
nuclear@3
|
116 free_program(prog_mbrot[i]);
|
nuclear@3
|
117 prog_mbrot[i] = 0;
|
nuclear@3
|
118 }
|
nuclear@0
|
119 }
|
nuclear@0
|
120
|
nuclear@1
|
121 void pixel_to_complex(float *res, float px, float py)
|
nuclear@1
|
122 {
|
nuclear@1
|
123 float u = (2.0 * px / win_width - 1.0) * win_aspect;
|
nuclear@1
|
124 float v = 2.0 * py / win_height - 1.0;
|
nuclear@1
|
125 res[0] = u * view_scale - view_center[0];
|
nuclear@1
|
126 res[1] = v * view_scale - view_center[1];
|
nuclear@1
|
127 }
|
nuclear@1
|
128
|
nuclear@0
|
129 void disp(void)
|
nuclear@0
|
130 {
|
nuclear@1
|
131 int i;
|
nuclear@1
|
132 float seed[2];
|
nuclear@1
|
133 static const float verts[][2] = {{-1, -1}, {1, -1}, {1, 1}, {-1, 1}};
|
nuclear@1
|
134 static const float corners[][2] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
|
nuclear@1
|
135
|
nuclear@1
|
136 pixel_to_complex(seed, mouse_x, mouse_y);
|
nuclear@1
|
137
|
nuclear@3
|
138 set_uniform_float2(prog_mbrot[sdrflags], "seed", seed[0], seed[1]);
|
nuclear@3
|
139 set_uniform_float(prog_mbrot[sdrflags], "view_scale", view_scale);
|
nuclear@3
|
140 set_uniform_float2(prog_mbrot[sdrflags], "view_center", view_center[0], view_center[1]);
|
nuclear@3
|
141 glUseProgram(prog_mbrot[sdrflags]);
|
nuclear@0
|
142
|
nuclear@0
|
143 glBegin(GL_QUADS);
|
nuclear@1
|
144 for(i=0; i<4; i++) {
|
nuclear@1
|
145 float bv[2];
|
nuclear@1
|
146 pixel_to_complex(bv, (win_width - 1) * corners[i][0], (win_height - 1) * corners[i][1]);
|
nuclear@1
|
147 glTexCoord2f(bv[0], bv[1]);
|
nuclear@1
|
148 glVertex2f(verts[i][0], verts[i][1]);
|
nuclear@1
|
149 }
|
nuclear@0
|
150 glEnd();
|
nuclear@0
|
151
|
nuclear@0
|
152 glutSwapBuffers();
|
nuclear@0
|
153 }
|
nuclear@0
|
154
|
nuclear@0
|
155 void reshape(int x, int y)
|
nuclear@0
|
156 {
|
nuclear@0
|
157 glViewport(0, 0, x, y);
|
nuclear@0
|
158
|
nuclear@1
|
159 win_aspect = (float)x / (float)y;
|
nuclear@1
|
160 win_width = x;
|
nuclear@1
|
161 win_height = y;
|
nuclear@0
|
162 }
|
nuclear@0
|
163
|
nuclear@1
|
164 static int keystate[256];
|
nuclear@1
|
165
|
nuclear@1
|
166 void keydown(unsigned char key, int x, int y)
|
nuclear@0
|
167 {
|
nuclear@1
|
168 static int fullscreen;
|
nuclear@1
|
169 static int prev_width, prev_height;
|
nuclear@1
|
170
|
nuclear@1
|
171 switch(key) {
|
nuclear@1
|
172 case 27:
|
nuclear@0
|
173 exit(0);
|
nuclear@1
|
174
|
nuclear@1
|
175 case 'f':
|
nuclear@1
|
176 fullscreen = !fullscreen;
|
nuclear@1
|
177 if(fullscreen) {
|
nuclear@1
|
178 prev_width = win_width;
|
nuclear@1
|
179 prev_height = win_height;
|
nuclear@1
|
180 glutFullScreen();
|
nuclear@1
|
181 } else {
|
nuclear@1
|
182 glutReshapeWindow(prev_width, prev_height);
|
nuclear@1
|
183 }
|
nuclear@1
|
184 break;
|
nuclear@1
|
185
|
nuclear@3
|
186 case ' ':
|
nuclear@3
|
187 sdrflags ^= SDR_LINE_DIST_BIT;
|
nuclear@3
|
188 glutPostRedisplay();
|
nuclear@3
|
189 break;
|
nuclear@3
|
190
|
nuclear@3
|
191 case 'o':
|
nuclear@3
|
192 sdrflags ^= SDR_PLOT_ORBIT_BIT;
|
nuclear@3
|
193 glutPostRedisplay();
|
nuclear@3
|
194 break;
|
nuclear@3
|
195
|
nuclear@2
|
196 case '`':
|
nuclear@2
|
197 screenshot();
|
nuclear@2
|
198 break;
|
nuclear@2
|
199
|
nuclear@1
|
200 default:
|
nuclear@1
|
201 break;
|
nuclear@0
|
202 }
|
nuclear@1
|
203 keystate[key] = 1;
|
nuclear@0
|
204 }
|
nuclear@0
|
205
|
nuclear@1
|
206 void keyup(unsigned char key, int x, int y)
|
nuclear@1
|
207 {
|
nuclear@1
|
208 keystate[key] = 0;
|
nuclear@1
|
209 }
|
nuclear@1
|
210
|
nuclear@1
|
211 static int prev_x, prev_y;
|
nuclear@1
|
212 static int bnstate[8];
|
nuclear@1
|
213
|
nuclear@0
|
214 void mouse(int bn, int st, int x, int y)
|
nuclear@0
|
215 {
|
nuclear@1
|
216 prev_x = x;
|
nuclear@1
|
217 prev_y = y;
|
nuclear@1
|
218 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
|
nuclear@0
|
219 }
|
nuclear@0
|
220
|
nuclear@0
|
221 void motion(int x, int y)
|
nuclear@0
|
222 {
|
nuclear@1
|
223 int dx = x - prev_x;
|
nuclear@1
|
224 int dy = y - prev_y;
|
nuclear@1
|
225 prev_x = x;
|
nuclear@1
|
226 prev_y = y;
|
nuclear@1
|
227
|
nuclear@1
|
228 if(!(dx | dy)) return;
|
nuclear@1
|
229
|
nuclear@1
|
230 if(bnstate[0]) {
|
nuclear@1
|
231 if(keystate['s']) {
|
nuclear@1
|
232 mouse_x = x;
|
nuclear@1
|
233 mouse_y = y;
|
nuclear@1
|
234 } else if(keystate['z']) {
|
nuclear@1
|
235 float s = sqrt(view_scale);
|
nuclear@1
|
236 view_scale += dy * 0.01 * s;
|
nuclear@1
|
237 if(view_scale < 1e-8) view_scale = 1e-8;
|
nuclear@1
|
238 } else {
|
nuclear@1
|
239 float s = sqrt(view_scale);
|
nuclear@1
|
240 view_center[0] += 0.01 * dx * s;
|
nuclear@1
|
241 view_center[1] += 0.01 * dy * s;
|
nuclear@1
|
242 }
|
nuclear@1
|
243 glutPostRedisplay();
|
nuclear@1
|
244 }
|
nuclear@0
|
245 }
|
nuclear@2
|
246
|
nuclear@2
|
247 void screenshot(void)
|
nuclear@2
|
248 {
|
nuclear@2
|
249 FILE *fp;
|
nuclear@2
|
250 DIR *dir;
|
nuclear@2
|
251 struct dirent *dent;
|
nuclear@2
|
252 unsigned char *img;
|
nuclear@2
|
253 static int shotnum = -1;
|
nuclear@2
|
254 char fname[128];
|
nuclear@2
|
255
|
nuclear@2
|
256 if(shotnum == -1) {
|
nuclear@2
|
257 shotnum = 1;
|
nuclear@2
|
258 if((dir = opendir("."))) {
|
nuclear@2
|
259 while((dent = readdir(dir))) {
|
nuclear@2
|
260 int num;
|
nuclear@2
|
261 if(sscanf(dent->d_name, "img%d.ppm", &num) == 1) {
|
nuclear@2
|
262 if(num >= shotnum) shotnum = num + 1;
|
nuclear@2
|
263 }
|
nuclear@2
|
264 }
|
nuclear@2
|
265 closedir(dir);
|
nuclear@2
|
266 }
|
nuclear@2
|
267 } else {
|
nuclear@2
|
268 ++shotnum;
|
nuclear@2
|
269 }
|
nuclear@2
|
270
|
nuclear@2
|
271 sprintf(fname, "img%04d.ppm", shotnum > 0 ? shotnum : 0);
|
nuclear@2
|
272 if(!(fp = fopen(fname, "wb"))) {
|
nuclear@2
|
273 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
|
nuclear@2
|
274 return;
|
nuclear@2
|
275 }
|
nuclear@2
|
276
|
nuclear@2
|
277 if(!(img = malloc(win_width * win_height * 3))) {
|
nuclear@2
|
278 fprintf(stderr, "failed to allocate screenshot buffer\n");
|
nuclear@2
|
279 fclose(fp);
|
nuclear@2
|
280 return;
|
nuclear@2
|
281 }
|
nuclear@2
|
282
|
nuclear@2
|
283 glReadPixels(0, 0, win_width, win_height, GL_RGB, GL_UNSIGNED_BYTE, img);
|
nuclear@2
|
284
|
nuclear@2
|
285 fprintf(fp, "P6\n%d %d\n255\n", win_width, win_height);
|
nuclear@2
|
286 fwrite(img, 1, win_width * win_height * 3, fp);
|
nuclear@2
|
287 fclose(fp);
|
nuclear@2
|
288 free(img);
|
nuclear@2
|
289 return;
|
nuclear@2
|
290 }
|