mandelbrot

annotate src/main.c @ 0:4d85805eb875

mandelbrot initial import
author John Tsiombikas <nuclear@mutantstargoat.com>
date Tue, 19 Jun 2012 06:48:38 +0300
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 A simple interactive mandelbrot fractal explorer
nuclear@0 3 Copyright (C) John Tsiombikas <nuclear@member.fsf.org>
nuclear@0 4
nuclear@0 5 This program is free software: you can redistribute it and/or modify
nuclear@0 6 it under the terms of the GNU General Public License as published by
nuclear@0 7 the Free Software Foundation, either version 3 of the License, or
nuclear@0 8 (at your option) any later version.
nuclear@0 9
nuclear@0 10 This program is distributed in the hope that it will be useful,
nuclear@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@0 13 GNU General Public License for more details.
nuclear@0 14
nuclear@0 15 You should have received a copy of the GNU General Public License
nuclear@0 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@0 17 */
nuclear@0 18 #include <stdio.h>
nuclear@0 19 #include <stdlib.h>
nuclear@0 20 #include <SDL.h>
nuclear@0 21 #include "mbrot.h"
nuclear@0 22 #include "palette.h"
nuclear@0 23
nuclear@0 24 static struct {
nuclear@0 25 int width, height;
nuclear@0 26 int num_threads;
nuclear@0 27 int num_iter;
nuclear@0 28 const char *palfile;
nuclear@0 29 } opt = { 800, 600, 1, 100, "default.pal" };
nuclear@0 30
nuclear@0 31 void init_area(void);
nuclear@0 32 void redraw(void);
nuclear@0 33 int parse_args(int argc, char **argv);
nuclear@0 34 int handle_event(SDL_Event *ev);
nuclear@0 35 int handle_keypress(int key);
nuclear@0 36
nuclear@0 37 static int must_redraw;
nuclear@0 38
nuclear@0 39 static SDL_Surface *framebuffer_surf;
nuclear@0 40
nuclear@0 41 static struct area area;
nuclear@0 42 static double aspect;
nuclear@0 43
nuclear@0 44
nuclear@0 45 int main(int argc, char **argv)
nuclear@0 46 {
nuclear@0 47 if(parse_args(argc, argv) == -1) {
nuclear@0 48 return 1;
nuclear@0 49 }
nuclear@0 50
nuclear@0 51 /* load palette file */
nuclear@0 52 if(load_palette(opt.palfile) == -1) {
nuclear@0 53 return 1;
nuclear@0 54 }
nuclear@0 55
nuclear@0 56 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
nuclear@0 57 if(!(framebuffer_surf = SDL_SetVideoMode(opt.width, opt.height, 32, SDL_SWSURFACE))) {
nuclear@0 58 fprintf(stderr, "failed to initialize graphics\n");
nuclear@0 59 return 1;
nuclear@0 60 }
nuclear@0 61
nuclear@0 62 init_area();
nuclear@0 63 redraw();
nuclear@0 64
nuclear@0 65 for(;;) {
nuclear@0 66 SDL_Event ev;
nuclear@0 67 SDL_WaitEvent(&ev);
nuclear@0 68
nuclear@0 69 do {
nuclear@0 70 if(!handle_event(&ev)) {
nuclear@0 71 goto done;
nuclear@0 72 }
nuclear@0 73 } while(SDL_PollEvent(&ev));
nuclear@0 74
nuclear@0 75 if(must_redraw) {
nuclear@0 76 redraw();
nuclear@0 77 }
nuclear@0 78 }
nuclear@0 79
nuclear@0 80 done:
nuclear@0 81 SDL_Quit();
nuclear@0 82 return 0;
nuclear@0 83 }
nuclear@0 84
nuclear@0 85 void init_area(void)
nuclear@0 86 {
nuclear@0 87 aspect = (double)opt.width / (double)opt.height;
nuclear@0 88
nuclear@0 89 area.x = -2.0;
nuclear@0 90 area.width = 3.0;
nuclear@0 91 area.height = area.width / aspect;
nuclear@0 92 area.y = -area.height / 2.0;
nuclear@0 93 }
nuclear@0 94
nuclear@0 95 void redraw(void)
nuclear@0 96 {
nuclear@0 97 void *fb;
nuclear@0 98
nuclear@0 99 if(SDL_MUSTLOCK(framebuffer_surf)) {
nuclear@0 100 SDL_LockSurface(framebuffer_surf);
nuclear@0 101 }
nuclear@0 102
nuclear@0 103 fb = framebuffer_surf->pixels;
nuclear@0 104 draw_mandelbrot(fb, opt.width, opt.height, &area, opt.num_iter);
nuclear@0 105
nuclear@0 106 if(SDL_MUSTLOCK(framebuffer_surf)) {
nuclear@0 107 SDL_UnlockSurface(framebuffer_surf);
nuclear@0 108 }
nuclear@0 109
nuclear@0 110 SDL_UpdateRect(framebuffer_surf, 0, 0, opt.width, opt.height);
nuclear@0 111
nuclear@0 112 must_redraw = 0;
nuclear@0 113 }
nuclear@0 114
nuclear@0 115 int parse_args(int argc, char **argv)
nuclear@0 116 {
nuclear@0 117 int i;
nuclear@0 118 char *endp;
nuclear@0 119
nuclear@0 120 for(i=1; i<argc; i++) {
nuclear@0 121 if(argv[i][0] == '-' && argv[i][2] == 0) {
nuclear@0 122 switch(argv[i][1]) {
nuclear@0 123 case 's':
nuclear@0 124 if(sscanf(argv[++i], "%dx%d", &opt.width, &opt.height) != 2) {
nuclear@0 125 fprintf(stderr, "-s must be followed by WIDTHxHEIGHT\n");
nuclear@0 126 return -1;
nuclear@0 127 }
nuclear@0 128 break;
nuclear@0 129
nuclear@0 130 case 'i':
nuclear@0 131 opt.num_iter = strtol(argv[++i], &endp, 10);
nuclear@0 132 if(endp == argv[i]) {
nuclear@0 133 fprintf(stderr, "-i must be followed by the number of iterations\n");
nuclear@0 134 return -1;
nuclear@0 135 }
nuclear@0 136 break;
nuclear@0 137
nuclear@0 138 case 't':
nuclear@0 139 opt.num_threads = strtol(argv[++i], &endp, 10);
nuclear@0 140 if(endp == argv[i]) {
nuclear@0 141 fprintf(stderr, "-t must be followed by the number of threads\n");
nuclear@0 142 return -1;
nuclear@0 143 }
nuclear@0 144 break;
nuclear@0 145
nuclear@0 146 case 'p':
nuclear@0 147 opt.palfile = argv[++i];
nuclear@0 148 break;
nuclear@0 149
nuclear@0 150 case 'h':
nuclear@0 151 printf("usage: %s [-s <WxH>] [-i <iterations>] [-t <threads>] [-p <palette>]\n", argv[0]);
nuclear@0 152 printf(" -s <WxH> set the render size (default: %dx%d)\n", opt.width, opt.height);
nuclear@0 153 printf(" -i <iterations> set the maximum number of mandelbrot iterations (default: %d)\n", opt.num_iter);
nuclear@0 154 printf(" -t <threads> number of threads for mandelbrot calculations (default: %d)\n", opt.num_threads);
nuclear@0 155 printf(" -p <palette> use this palette file (see README) (default: %s)\n", opt.palfile);
nuclear@0 156 exit(0);
nuclear@0 157
nuclear@0 158 default:
nuclear@0 159 fprintf(stderr, "unrecognized argument: %s\n", argv[i]);
nuclear@0 160 return -1;
nuclear@0 161 }
nuclear@0 162 } else {
nuclear@0 163 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
nuclear@0 164 return -1;
nuclear@0 165 }
nuclear@0 166 }
nuclear@0 167 return 0;
nuclear@0 168 }
nuclear@0 169
nuclear@0 170 int handle_event(SDL_Event *ev)
nuclear@0 171 {
nuclear@0 172 static int prev_x, prev_y;
nuclear@0 173
nuclear@0 174 switch(ev->type) {
nuclear@0 175 case SDL_KEYDOWN:
nuclear@0 176 if(!handle_keypress(ev->key.keysym.sym)) {
nuclear@0 177 return 0;
nuclear@0 178 }
nuclear@0 179 break;
nuclear@0 180
nuclear@0 181 case SDL_MOUSEBUTTONDOWN:
nuclear@0 182 prev_x = ev->button.x;
nuclear@0 183 prev_y = ev->button.y;
nuclear@0 184 break;
nuclear@0 185
nuclear@0 186 case SDL_MOUSEMOTION:
nuclear@0 187 {
nuclear@0 188 int dx = ev->motion.x - prev_x;
nuclear@0 189 int dy = ev->motion.y - prev_y;
nuclear@0 190 prev_x = ev->motion.x;
nuclear@0 191 prev_y = ev->motion.y;
nuclear@0 192
nuclear@0 193 if(ev->motion.state & 1) {
nuclear@0 194 /* pan */
nuclear@0 195 area.x -= area.width * (double)dx / (double)opt.width;
nuclear@0 196 area.y -= area.height * (double)dy / (double)opt.height;
nuclear@0 197 must_redraw = 1;
nuclear@0 198 } else if(ev->motion.state & 4) {
nuclear@0 199 /* zoom */
nuclear@0 200 double zoom = 1.0 + (double)dy / (double)opt.height;
nuclear@0 201 double new_width = area.width * zoom;
nuclear@0 202 double new_height = area.height * zoom;
nuclear@0 203 area.x += (area.width - new_width) / 2.0;
nuclear@0 204 area.y += (area.height - new_height) / 2.0;
nuclear@0 205 area.width = new_width;
nuclear@0 206 area.height = new_height;
nuclear@0 207 must_redraw = 1;
nuclear@0 208 }
nuclear@0 209 }
nuclear@0 210 break;
nuclear@0 211
nuclear@0 212 case SDL_VIDEOEXPOSE:
nuclear@0 213 must_redraw = 1;
nuclear@0 214 break;
nuclear@0 215
nuclear@0 216 case SDL_QUIT:
nuclear@0 217 return 0;
nuclear@0 218 }
nuclear@0 219 return 1;
nuclear@0 220 }
nuclear@0 221
nuclear@0 222 int handle_keypress(int key)
nuclear@0 223 {
nuclear@0 224 switch(key) {
nuclear@0 225 case SDLK_ESCAPE:
nuclear@0 226 case 'q':
nuclear@0 227 case 'Q':
nuclear@0 228 return 0;
nuclear@0 229
nuclear@0 230 case '-':
nuclear@0 231 if(opt.num_iter > 10) {
nuclear@0 232 opt.num_iter -= 10;
nuclear@0 233 printf("iterations: %d\n", opt.num_iter);
nuclear@0 234 must_redraw = 1;
nuclear@0 235 }
nuclear@0 236 break;
nuclear@0 237
nuclear@0 238 case '=':
nuclear@0 239 opt.num_iter += 10;
nuclear@0 240 printf("iterations: %d\n", opt.num_iter);
nuclear@0 241 must_redraw = 1;
nuclear@0 242 break;
nuclear@0 243
nuclear@0 244 case '?':
nuclear@0 245 case '/':
nuclear@0 246 printf("current coordinates: (%f, %f) -> (%f, %f)\n", area.x, area.y,
nuclear@0 247 area.x + area.width, area.y + area.height);
nuclear@0 248 break;
nuclear@0 249
nuclear@0 250 case '\b':
nuclear@0 251 init_area();
nuclear@0 252 must_redraw = 1;
nuclear@0 253 break;
nuclear@0 254
nuclear@0 255 default:
nuclear@0 256 break;
nuclear@0 257 }
nuclear@0 258 return 1;
nuclear@0 259 }