fractorb

view src/main.c @ 3:f440ecffc45a

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