re-enable screenshot saving
[maximus:mightymandel.git] / src / mightymandel.c
1 #define _POSIX_C_SOURCE 199309L
2
3 #include <gtk/gtk.h>
4 #include <gdk/gdkkeysyms.h>
5 #include <gtk/gtkgl.h>
6
7 #include <string.h>
8 #include <time.h>
9 #include <mpfr.h>
10
11 #include "utility.h"
12 #include "shader.h"
13 #include "record.h"
14 #include "view.h"
15
16 #include "fp32_fillc.h"
17 #include "fp32_init.h"
18 #include "fp64_init.h"
19 #include "fpxx_init.h"
20 #include "fp32_step.h"
21 #include "fp64_step.h"
22 #include "fpxx_step.h"
23 #include "fp32_unescaped.h"
24 #include "fp64_unescaped.h"
25 #include "fpxx_unescaped.h"
26 #include "fp32_escaped.h"
27 #include "fp64_escaped.h"
28 #include "fpxx_escaped.h"
29 #include "fp32_colour.h"
30
31 #include "state.h"
32 #include "interact.h"
33 #include "render.h"
34 #include "view.h"
35 #include "parse.h"
36
37 struct S S;
38 bool FP64 = true;
39
40 GtkWidget *drawingArea = 0;
41 guint idleCallback = 0;
42
43 gboolean idle_handler(GtkWidget *w);
44
45 void add_idle() {
46   if (! idleCallback) {
47     g_idle_add((GSourceFunc) idle_handler, drawingArea);
48     idleCallback = 1;
49   }
50 }
51
52 void reshapecb(int new_width, int new_height) {
53
54   view_reshape(&S.render.view, new_width, new_height);
55   if (S.record.buffer) {
56     free(S.record.buffer);
57     S.record.buffer = 0;
58   }
59   render_begin(&S.render);
60   S.stale = 1;
61 }
62
63 void begincb() {
64   glewInit();
65   render_begin(&S.render);
66 }
67
68 void endcb() {
69   render_end(&S.render);
70 }
71
72 int displaycb() {
73   return render_display(&S.render);
74 }
75
76 int idlecb() {
77   return render_idle(&S.render);
78 }
79
80
81 gboolean delete_handler(GtkWidget *w, GdkEvent *e, gpointer u) {
82   GdkGLContext *c = gtk_widget_get_gl_context(drawingArea);
83   GdkGLDrawable *d = gtk_widget_get_gl_drawable(drawingArea);
84   if (gdk_gl_drawable_gl_begin(d, c)) {
85     endcb();
86     gdk_gl_drawable_gl_end(d);
87   }
88   gtk_main_quit();
89   return 1;
90 }
91
92 gboolean button_handler(GtkWidget *w, GdkEventButton *e, gpointer u) {
93   GdkGLContext *c = gtk_widget_get_gl_context(drawingArea);
94   GdkGLDrawable *d = gtk_widget_get_gl_drawable(drawingArea);
95   if (! gdk_gl_drawable_gl_begin(d, c)) {
96     return 0;
97   }
98   if (e->type == GDK_BUTTON_PRESS) {
99     switch (e->button) {
100       case 1: interact_mouse(b_left,   e->x, e->y, e->state & GDK_SHIFT_MASK, e->state & GDK_CONTROL_MASK); break;
101       case 2: interact_mouse(b_middle, e->x, e->y, e->state & GDK_SHIFT_MASK, e->state & GDK_CONTROL_MASK); break;
102       case 3: interact_mouse(b_right,  e->x, e->y, e->state & GDK_SHIFT_MASK, e->state & GDK_CONTROL_MASK); break;
103     }
104   }
105   gdk_gl_drawable_gl_end(d);
106   return 1;
107 }
108
109 gboolean scroll_handler(GtkWidget *w, GdkEventScroll *e, gpointer data) {
110   switch (e->direction) {
111     case GDK_SCROLL_UP:   interact_mouse(b_up,   e->x, e->y, e->state & GDK_SHIFT_MASK, e->state & GDK_CONTROL_MASK); break;
112     case GDK_SCROLL_DOWN: interact_mouse(b_down, e->x, e->y, e->state & GDK_SHIFT_MASK, e->state & GDK_CONTROL_MASK); break;
113     default: break;
114   }
115   return 1;
116 }
117
118 gboolean key_press_handler(GtkWidget *w, GdkEventKey* e, GMainLoop *l) {
119   int shift = e->state & GDK_SHIFT_MASK;
120   if (e->type == GDK_KEY_PRESS) {
121     switch (e->keyval) {
122       case GDK_q: case GDK_Escape: delete_handler(w, 0, 0); break;
123       case GDK_Page_Up:   view_zoom(&S.render.view, shift ?  10 :  1); S.stale = 1; add_idle(); break;
124       case GDK_Page_Down: view_zoom(&S.render.view, shift ? -10 : -1); S.stale = 1; add_idle(); break;
125       case GDK_s: S.record.screenshot = true; add_idle(); break;
126     }
127   }
128   return 1;
129 }
130
131 void screen_changed_handler(GtkWidget *w, GdkScreen* s_old, gpointer data) {
132   GdkScreen *s = gtk_widget_get_screen(w);
133   GdkColormap *m = gdk_screen_get_rgba_colormap(s);
134   if (! m) {
135     m = gdk_screen_get_rgb_colormap(s);
136   }
137   gtk_widget_set_colormap(w, m);
138 }
139
140 void realize_handler(GtkWidget *w, gpointer data) {
141   GdkGLContext *c = gtk_widget_get_gl_context(w);
142   GdkGLDrawable *d = gtk_widget_get_gl_drawable(w);
143   if (! gdk_gl_drawable_gl_begin(d, c)) {
144     return;
145   }
146   begincb();
147   gdk_gl_drawable_gl_end(d);
148 }
149
150 gboolean configure_handler(GtkWidget *w, GdkEventConfigure *e, gpointer data) {
151   GdkGLContext *c = gtk_widget_get_gl_context(w);
152   GdkGLDrawable *d = gtk_widget_get_gl_drawable(w);
153   if (! gdk_gl_drawable_gl_begin(d, c)) {
154     return 0;
155   }
156   reshapecb(w->allocation.width, w->allocation.height);
157   gdk_gl_drawable_gl_end(d);
158   return 1;
159 }
160
161 gboolean expose_handler(GtkWidget *w, GdkEventExpose *e, gpointer data) {
162   GdkGLContext *c = gtk_widget_get_gl_context(w);
163   GdkGLDrawable *d = gtk_widget_get_gl_drawable(w);
164   if (! gdk_gl_drawable_gl_begin(d, c)) {
165     return 0;
166   }
167   if (displaycb() && gdk_gl_drawable_is_double_buffered(d)) {
168     gdk_gl_drawable_swap_buffers(d);
169   }
170   gdk_gl_drawable_gl_end(d);
171   return 1;
172 }
173
174 gboolean draw_handler(GtkWidget *w) {
175   gtk_widget_queue_draw(w);
176   return 1;
177 }
178
179 gboolean idle_handler(GtkWidget *w) {
180   GdkGLContext *c = gtk_widget_get_gl_context(w);
181   GdkGLDrawable *d = gtk_widget_get_gl_drawable(w);
182   if (! gdk_gl_drawable_gl_begin(d, c)) {
183     return 0;
184   }
185   idleCallback = idlecb();
186   gdk_gl_drawable_gl_end(d);
187   return idleCallback;
188 }
189
190 int main(int argc, char **argv) {
191   srand(time(NULL));
192   state_init();
193   gtk_init(&argc, &argv);
194   gtk_gl_init(&argc, &argv);
195   glewExperimental = GL_TRUE;
196   int loaded = 0;
197   for (int i = 1; i < argc; ++i) {
198     if (0 == strcmp("-32", argv[i])) { FP64 = false; }
199     else if (! loaded) {
200       char *b = load_file(argv[i]);
201       if (b) {
202         loaded = 1;
203         if (! parse(&parser_mm,  b, S.render.view.centerx, S.render.view.centery, S.render.view.radius))
204         if (! parse(&parser_sft, b, S.render.view.centerx, S.render.view.centery, S.render.view.radius))
205         if (! parse(&parser_mdz, b, S.render.view.centerx, S.render.view.centery, S.render.view.radius))
206           loaded = 0;
207         free(b);
208       }
209     }
210   }
211
212 #if 0
213   S.rendering = 1;
214   S.record.video = 1;
215   mpfr_set_ui(S.render.view.radius, 256, MPFR_RNDN);
216 #endif
217
218   GdkGLConfig *c = gdk_gl_config_new_by_mode((GdkGLConfigMode) (GDK_GL_MODE_RGB | GDK_GL_MODE_ALPHA | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE));
219   GtkWidget *w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
220   gtk_widget_add_events(w, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
221   g_signal_connect(G_OBJECT(w), "delete-event",         G_CALLBACK(delete_handler), 0);
222   g_signal_connect(G_OBJECT(w), "button-press-event",   G_CALLBACK(button_handler), 0);
223   g_signal_connect(G_OBJECT(w), "button-release-event", G_CALLBACK(button_handler), 0);
224   g_signal_connect(G_OBJECT(w), "screen-changed",       G_CALLBACK(screen_changed_handler), 0);
225   g_signal_connect(G_OBJECT(w), "scroll-event",         G_CALLBACK(scroll_handler), 0);
226   g_signal_connect(G_OBJECT(w), "key-press-event",      G_CALLBACK(key_press_handler), 0);
227   GtkWidget *d = drawingArea = gtk_drawing_area_new();
228   gtk_widget_set_size_request(d, S.render.view.width, S.render.view.height);
229   gtk_widget_set_gl_capability(d, c, 0, 1, GDK_GL_RGBA_TYPE);
230   g_signal_connect_after(G_OBJECT(d), "realize",        G_CALLBACK(realize_handler), 0);
231   g_signal_connect(G_OBJECT(d), "configure-event",      G_CALLBACK(configure_handler), 0);
232   g_signal_connect(G_OBJECT(d), "expose-event",         G_CALLBACK(expose_handler), 0);
233   gtk_container_add (GTK_CONTAINER(w), d);
234   gtk_widget_show(d);
235   gtk_window_set_resizable(GTK_WINDOW(w), 0);
236   gtk_widget_set_app_paintable(w, 1);
237   gtk_window_set_decorated(GTK_WINDOW(w), 1);
238   screen_changed_handler(w, 0, 0);
239   screen_changed_handler(d, 0, 0);
240   gtk_widget_realize(w);
241   gdk_window_set_back_pixmap(w->window, 0, 0);
242   gtk_widget_show(w);
243   g_timeout_add(100, (GSourceFunc) draw_handler, d);
244   add_idle();
245   gtk_main();
246   return 0;
247 }