make clean && make && ./mandelbrot
- awsd * for moving camera;
- qe * for zoom in/out;
- QE * for rotate camera.
CC=cc | |
LIBS=-lncurses -lm | |
CFLAGS=-Wall -O3 | |
SRC=$(wildcard *.c) | |
OBJ=$(SRC:.c=.o) | |
TARGET=mandelbrot | |
all: ${OBJ} | |
${CC} $(CFLAGS) $(LIBS) $^ -o ${TARGET} | |
%.o: %.c | |
${CC} ${CFLAGS} -c $< -o $@ | |
clean: | |
rm -f *.o ${TARGET} |
#include <curses.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <math.h> | |
#define PI 3.1415926538 | |
static const char tone[] = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "; | |
static const int tone_size = 70; | |
char get_tone(int esc, int limit) { | |
return tone[tone_size * (limit - esc) / limit]; | |
} | |
int escape(double x, double y, int limit, double range) { | |
double a=0, b=0, step; | |
for(step=0;step<limit-1 && a*a+b*b<range;step++) { | |
double tmp = a*a - b*b + x; | |
b = 2*a*b + y; | |
a = tmp; | |
} | |
return step; | |
} | |
int main(void) { | |
WINDOW * mainwin; | |
if ((mainwin = initscr()) == NULL) { | |
fprintf(stderr, "Error initialising ncurses.\n"); | |
exit(EXIT_FAILURE); | |
} | |
cbreak(); | |
noecho(); | |
// nodelay(mainwin, TRUE); | |
int key = -1; | |
double cx = -0.75, cy = 0, | |
scalar_x=0.037, scalar_y=scalar_x*1.5, | |
angle = 0; | |
double mv_x = 0.15, mv_y = 0.3, mv_a = PI / 6, mv_z = 1.3; | |
int limit = 255; | |
double range = 1000.0; | |
char title[1024]; | |
do { | |
// get screen size | |
int win_x, win_y; | |
getmaxyx(mainwin, win_y, win_x); | |
// move | |
switch (key) { | |
case 65: | |
case 'w': | |
cx += win_x * scalar_x * mv_x * sin(angle); | |
cy -= win_y * scalar_y * mv_y * cos(angle); | |
break; | |
case 66: | |
case 's': | |
cx -= win_x * scalar_x * mv_x * sin(angle); | |
cy += win_y * scalar_y * mv_y * cos(angle); | |
break; | |
case 68: | |
case 'a': | |
cx -= win_x * scalar_x * mv_x * cos(angle); | |
cy -= win_y * scalar_y * mv_y * sin(angle); | |
break; | |
case 67: | |
case 'd': | |
cx += win_x * scalar_x * mv_x * cos(angle); | |
cy += win_y * scalar_y * mv_y * sin(angle); | |
break; | |
case 'q': | |
scalar_x *= mv_z; | |
scalar_y *= mv_z; | |
break; | |
case 'e': | |
scalar_x /= mv_z; | |
scalar_y /= mv_z; | |
break; | |
case 'Q': | |
angle -= mv_a; | |
if (angle < 0) angle += PI * 2; | |
break; | |
case 'E': | |
angle += mv_a; | |
if (angle > PI * 2) angle -= PI * 2; | |
break; | |
} | |
// draw | |
double sn = sin(angle), cs = cos(angle); | |
for (int y=0;y<win_y;y++) { | |
move(y, 0); | |
for (int x=0;x<win_x;x++) { | |
double oy = (y - win_y/2) * scalar_y; | |
double ox = (x - win_x/2) * scalar_x; | |
double py = cy + ox * sn + oy * cs; | |
double px = cx + ox * cs - oy * sn; | |
int esc = escape(px, py, limit, range); | |
addch(get_tone(esc, limit)); | |
} | |
} | |
int deg = (int) (angle/PI*180); | |
sprintf(title, "X:%.2f Y:%.2f Z:%.8f A:%3d", cx, cy, scalar_x, deg); | |
mvaddstr(0, 0, title); | |
refresh(); | |
key = getch(); | |
} while (TRUE); | |
delwin(mainwin); | |
endwin(); | |
refresh(); | |
return EXIT_SUCCESS; | |
} | |