mandelbrot
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/main.c Tue Jun 19 06:48:38 2012 +0300 1.3 @@ -0,0 +1,259 @@ 1.4 +/* 1.5 +A simple interactive mandelbrot fractal explorer 1.6 +Copyright (C) John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 +#include <stdio.h> 1.22 +#include <stdlib.h> 1.23 +#include <SDL.h> 1.24 +#include "mbrot.h" 1.25 +#include "palette.h" 1.26 + 1.27 +static struct { 1.28 + int width, height; 1.29 + int num_threads; 1.30 + int num_iter; 1.31 + const char *palfile; 1.32 +} opt = { 800, 600, 1, 100, "default.pal" }; 1.33 + 1.34 +void init_area(void); 1.35 +void redraw(void); 1.36 +int parse_args(int argc, char **argv); 1.37 +int handle_event(SDL_Event *ev); 1.38 +int handle_keypress(int key); 1.39 + 1.40 +static int must_redraw; 1.41 + 1.42 +static SDL_Surface *framebuffer_surf; 1.43 + 1.44 +static struct area area; 1.45 +static double aspect; 1.46 + 1.47 + 1.48 +int main(int argc, char **argv) 1.49 +{ 1.50 + if(parse_args(argc, argv) == -1) { 1.51 + return 1; 1.52 + } 1.53 + 1.54 + /* load palette file */ 1.55 + if(load_palette(opt.palfile) == -1) { 1.56 + return 1; 1.57 + } 1.58 + 1.59 + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); 1.60 + if(!(framebuffer_surf = SDL_SetVideoMode(opt.width, opt.height, 32, SDL_SWSURFACE))) { 1.61 + fprintf(stderr, "failed to initialize graphics\n"); 1.62 + return 1; 1.63 + } 1.64 + 1.65 + init_area(); 1.66 + redraw(); 1.67 + 1.68 + for(;;) { 1.69 + SDL_Event ev; 1.70 + SDL_WaitEvent(&ev); 1.71 + 1.72 + do { 1.73 + if(!handle_event(&ev)) { 1.74 + goto done; 1.75 + } 1.76 + } while(SDL_PollEvent(&ev)); 1.77 + 1.78 + if(must_redraw) { 1.79 + redraw(); 1.80 + } 1.81 + } 1.82 + 1.83 +done: 1.84 + SDL_Quit(); 1.85 + return 0; 1.86 +} 1.87 + 1.88 +void init_area(void) 1.89 +{ 1.90 + aspect = (double)opt.width / (double)opt.height; 1.91 + 1.92 + area.x = -2.0; 1.93 + area.width = 3.0; 1.94 + area.height = area.width / aspect; 1.95 + area.y = -area.height / 2.0; 1.96 +} 1.97 + 1.98 +void redraw(void) 1.99 +{ 1.100 + void *fb; 1.101 + 1.102 + if(SDL_MUSTLOCK(framebuffer_surf)) { 1.103 + SDL_LockSurface(framebuffer_surf); 1.104 + } 1.105 + 1.106 + fb = framebuffer_surf->pixels; 1.107 + draw_mandelbrot(fb, opt.width, opt.height, &area, opt.num_iter); 1.108 + 1.109 + if(SDL_MUSTLOCK(framebuffer_surf)) { 1.110 + SDL_UnlockSurface(framebuffer_surf); 1.111 + } 1.112 + 1.113 + SDL_UpdateRect(framebuffer_surf, 0, 0, opt.width, opt.height); 1.114 + 1.115 + must_redraw = 0; 1.116 +} 1.117 + 1.118 +int parse_args(int argc, char **argv) 1.119 +{ 1.120 + int i; 1.121 + char *endp; 1.122 + 1.123 + for(i=1; i<argc; i++) { 1.124 + if(argv[i][0] == '-' && argv[i][2] == 0) { 1.125 + switch(argv[i][1]) { 1.126 + case 's': 1.127 + if(sscanf(argv[++i], "%dx%d", &opt.width, &opt.height) != 2) { 1.128 + fprintf(stderr, "-s must be followed by WIDTHxHEIGHT\n"); 1.129 + return -1; 1.130 + } 1.131 + break; 1.132 + 1.133 + case 'i': 1.134 + opt.num_iter = strtol(argv[++i], &endp, 10); 1.135 + if(endp == argv[i]) { 1.136 + fprintf(stderr, "-i must be followed by the number of iterations\n"); 1.137 + return -1; 1.138 + } 1.139 + break; 1.140 + 1.141 + case 't': 1.142 + opt.num_threads = strtol(argv[++i], &endp, 10); 1.143 + if(endp == argv[i]) { 1.144 + fprintf(stderr, "-t must be followed by the number of threads\n"); 1.145 + return -1; 1.146 + } 1.147 + break; 1.148 + 1.149 + case 'p': 1.150 + opt.palfile = argv[++i]; 1.151 + break; 1.152 + 1.153 + case 'h': 1.154 + printf("usage: %s [-s <WxH>] [-i <iterations>] [-t <threads>] [-p <palette>]\n", argv[0]); 1.155 + printf(" -s <WxH> set the render size (default: %dx%d)\n", opt.width, opt.height); 1.156 + printf(" -i <iterations> set the maximum number of mandelbrot iterations (default: %d)\n", opt.num_iter); 1.157 + printf(" -t <threads> number of threads for mandelbrot calculations (default: %d)\n", opt.num_threads); 1.158 + printf(" -p <palette> use this palette file (see README) (default: %s)\n", opt.palfile); 1.159 + exit(0); 1.160 + 1.161 + default: 1.162 + fprintf(stderr, "unrecognized argument: %s\n", argv[i]); 1.163 + return -1; 1.164 + } 1.165 + } else { 1.166 + fprintf(stderr, "unexpected argument: %s\n", argv[i]); 1.167 + return -1; 1.168 + } 1.169 + } 1.170 + return 0; 1.171 +} 1.172 + 1.173 +int handle_event(SDL_Event *ev) 1.174 +{ 1.175 + static int prev_x, prev_y; 1.176 + 1.177 + switch(ev->type) { 1.178 + case SDL_KEYDOWN: 1.179 + if(!handle_keypress(ev->key.keysym.sym)) { 1.180 + return 0; 1.181 + } 1.182 + break; 1.183 + 1.184 + case SDL_MOUSEBUTTONDOWN: 1.185 + prev_x = ev->button.x; 1.186 + prev_y = ev->button.y; 1.187 + break; 1.188 + 1.189 + case SDL_MOUSEMOTION: 1.190 + { 1.191 + int dx = ev->motion.x - prev_x; 1.192 + int dy = ev->motion.y - prev_y; 1.193 + prev_x = ev->motion.x; 1.194 + prev_y = ev->motion.y; 1.195 + 1.196 + if(ev->motion.state & 1) { 1.197 + /* pan */ 1.198 + area.x -= area.width * (double)dx / (double)opt.width; 1.199 + area.y -= area.height * (double)dy / (double)opt.height; 1.200 + must_redraw = 1; 1.201 + } else if(ev->motion.state & 4) { 1.202 + /* zoom */ 1.203 + double zoom = 1.0 + (double)dy / (double)opt.height; 1.204 + double new_width = area.width * zoom; 1.205 + double new_height = area.height * zoom; 1.206 + area.x += (area.width - new_width) / 2.0; 1.207 + area.y += (area.height - new_height) / 2.0; 1.208 + area.width = new_width; 1.209 + area.height = new_height; 1.210 + must_redraw = 1; 1.211 + } 1.212 + } 1.213 + break; 1.214 + 1.215 + case SDL_VIDEOEXPOSE: 1.216 + must_redraw = 1; 1.217 + break; 1.218 + 1.219 + case SDL_QUIT: 1.220 + return 0; 1.221 + } 1.222 + return 1; 1.223 +} 1.224 + 1.225 +int handle_keypress(int key) 1.226 +{ 1.227 + switch(key) { 1.228 + case SDLK_ESCAPE: 1.229 + case 'q': 1.230 + case 'Q': 1.231 + return 0; 1.232 + 1.233 + case '-': 1.234 + if(opt.num_iter > 10) { 1.235 + opt.num_iter -= 10; 1.236 + printf("iterations: %d\n", opt.num_iter); 1.237 + must_redraw = 1; 1.238 + } 1.239 + break; 1.240 + 1.241 + case '=': 1.242 + opt.num_iter += 10; 1.243 + printf("iterations: %d\n", opt.num_iter); 1.244 + must_redraw = 1; 1.245 + break; 1.246 + 1.247 + case '?': 1.248 + case '/': 1.249 + printf("current coordinates: (%f, %f) -> (%f, %f)\n", area.x, area.y, 1.250 + area.x + area.width, area.y + area.height); 1.251 + break; 1.252 + 1.253 + case '\b': 1.254 + init_area(); 1.255 + must_redraw = 1; 1.256 + break; 1.257 + 1.258 + default: 1.259 + break; 1.260 + } 1.261 + return 1; 1.262 +}