fractal effect is cooking
[dosdemo] / src / fract.c
1 #include <string.h>
2 #include <limits.h>
3 #include "demo.h"
4 #include "screen.h"
5 #include "gfxutil.h"
6
7 struct vec2x {
8         long x, y;
9 };
10
11 static int init(void);
12 static void destroy(void);
13 static void draw(void);
14 static int julia(long x, long y, long cx, long cy, int max_iter);
15 static int calc_walk(struct vec2x *path, long x, long y, int max_steps);
16
17 static struct screen scr = {
18         "fract",
19         init,
20         destroy,
21         0, 0,
22         draw
23 };
24
25 static long aspect_24x8 = (long)(1.3333333 * 256.0);
26 static long xscale_24x8 = (long)(1.3333333 * 1.2 * 256.0);
27 static long yscale_24x8 = (long)(1.2 * 256.0);
28 static int cx, cy;
29 static int max_iter = 50;
30
31 #define WALK_SIZE       20
32
33 struct screen *fract_screen(void)
34 {
35         return &scr;
36 }
37
38 static int init(void)
39 {
40         return 0;
41 }
42
43 static void destroy(void)
44 {
45 }
46
47 #define PACK_RGB16(r, g, b) \
48         (((((r) >> 3) & 0x1f) << 11) | ((((g) >> 2) & 0x3f) << 5) | (((b) >> 3) & 0x1f))
49
50 static void draw(void)
51 {
52         int i, j, len, x, y;
53         unsigned short *pixels = fb_pixels;
54         struct vec2x walkpos[WALK_SIZE];
55
56         cx = mouse_x;
57         cy = mouse_y;
58
59         for(i=0; i<fb_height; i++) {
60                 for(j=0; j<fb_width; j++) {
61                         unsigned char pidx = julia(j, i, cx, cy, max_iter) & 0xff;
62                         *pixels++ = (pidx >> 3) | ((pidx >> 2) << 5) | ((pidx >> 3) << 11);
63                 }
64         }
65
66         pixels = fb_pixels;
67
68         if((len = calc_walk(walkpos, mouse_x, mouse_y, WALK_SIZE))) {
69                 x = walkpos[0].x >> 16;
70                 y = walkpos[0].y >> 16;
71
72                 for(i=1; i<len; i++) {
73                         int x0 = x;
74                         int y0 = y;
75                         int x1 = walkpos[i].x >> 16;
76                         int y1 = walkpos[i].y >> 16;
77
78                         if(clip_line(&x0, &y0, &x1, &y1, 0, 0, fb_width - 1, fb_height - 1)) {
79                                 draw_line(x0, y0, x1, y1, PACK_RGB16(32, 128, 255));
80                         }
81                         x = x1;
82                         y = y1;
83                 }
84         }
85
86         pixels[mouse_y * fb_width + mouse_x] = 0xffe;
87 }
88
89 static long normalize_coord(long x, long range)
90 {
91         /* 2 * x / range - 1*/
92         return (x << 17) / range - 65536;
93 }
94
95 static long device_coord(long x, long range)
96 {
97         /* (x + 1) / 2 * (range - 1) */
98         return ((x + 65536) >> 1) * (range - 1);
99 }
100
101 static int julia(long x, long y, long cx, long cy, int max_iter)
102 {
103         int i;
104
105         /* convert to fixed point roughly [-1, 1] */
106         x = (normalize_coord(x, fb_width) >> 8) * xscale_24x8;
107         y = (normalize_coord(y, fb_height) >> 8) * yscale_24x8;
108         cx = (normalize_coord(cx, fb_width) >> 8) * xscale_24x8;
109         cy = (normalize_coord(cy, fb_height) >> 8) * yscale_24x8;
110
111         for(i=0; i<max_iter; i++) {
112                 /* z_n = z_{n-1}**2 + c */
113                 long px = x >> 8;
114                 long py = y >> 8;
115
116                 if(px * px + py * py > (4 << 16)) {
117                         break;
118                 }
119                 x = px * px - py * py + cx;
120                 y = (px * py << 1) + cy;
121         }
122
123         return i < max_iter ? (256 * i / max_iter) : 0;
124 }
125
126 static int calc_walk(struct vec2x *path, long x, long y, int max_steps)
127 {
128         int i;
129         long cx, cy;
130
131         /* convert to fixed point roughly [-1, 1] */
132         x = cx = (normalize_coord(x, fb_width) >> 8) * xscale_24x8;
133         y = cy = (normalize_coord(y, fb_height) >> 8) * yscale_24x8;
134
135         for(i=0; i<max_steps; i++) {
136                 /* z_n = z_{n-1}**2 + c */
137                 long px = x >> 8;
138                 long py = y >> 8;
139
140                 path[i].x = device_coord((x << 8) / xscale_24x8, fb_width);
141                 path[i].y = device_coord((y << 8) / yscale_24x8, fb_height);
142
143                 if(px * px + py * py > (4 << 16)) {
144                         break;
145                 }
146                 x = px * px - py * py + cx;
147                 y = (px * py << 1) + cy;
148         }
149
150         return i;
151 }