]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/mandel.c
games/snes: minor oam bugs
[plan9front.git] / sys / src / games / mandel.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <mouse.h>
6 #include <cursor.h>
7
8 enum { ncolors = 600 };
9
10 double xmin = -2, xmax = 1;
11 double ymin = -1, ymax = 1;
12 Mousectl *mctl;
13 Rendez rend;
14 int stopdraw;
15 uchar *imagedata;
16 Image *image;
17 extern Cursor reading;
18 uchar colors[3 * (ncolors + 1)];
19
20 double
21 convx(Rectangle *r, int x)
22 {
23         return (xmax - xmin) * (x - r->min.x) / (r->max.x - r->min.x) + xmin;
24 }
25
26 double
27 convy(Rectangle *r, int y)
28 {
29         return (ymax - ymin) * (r->max.y - y) / (r->max.y - r->min.y) + ymin;
30 }
31
32 void
33 pixel(int x, int y)
34 {
35         draw(screen, Rect(x, y, x + 1, y + 1), display->black, nil, ZP);
36 }
37
38 ulong
39 iterate(double x, double y)
40 {
41         int i;
42         double zx, zy, zx2, zy2, v;
43
44         zx = zy = zx2 = zy2 = 0;
45         for(i = 0; i < 100; i++){
46                 zy = 2 * zx * zy + y;
47                 zx = zx2 - zy2 + x;
48                 zx2 = zx * zx;
49                 zy2 = zy * zy;
50                 if(zx2 + zy2 >= 4){
51                         v = 2 + i - log(log(sqrt(zx2 + zy2)) / log(i + 2)) / 0.69314718;
52                         return (int)(v * 1000) % ncolors;
53                 }
54         }
55         return 0;
56 }
57
58 void
59 redrawproc(void *)
60 {
61         int x, y;
62         uchar *p, *q;
63
64         qlock(rend.l);
65         for(;;){
66                 setcursor(mctl, &reading);
67                 p = imagedata;
68                 for(y = screen->r.min.y; y < screen->r.max.y; y++)
69                         for(x = screen->r.min.x; x < screen->r.max.x; x++){
70                                 if(stopdraw)
71                                         goto check;
72                                 q = colors + 3 * iterate(convx(&screen->r, x), convy(&screen->r, y));
73                                 *p++ = *q++;
74                                 *p++ = *q++;
75                                 *p++ = *q;
76                         }
77                 if(stopdraw)
78                         goto check;
79                 lockdisplay(display);
80                 loadimage(image, image->r, imagedata, Dx(image->r) * Dy(image->r) * 3);
81                 draw(screen, screen->r, image, nil, screen->r.min);
82                 flushimage(display, 1);
83                 unlockdisplay(display);
84         check:
85                 stopdraw = 0;
86                 setcursor(mctl, nil);
87                 rsleep(&rend);
88                 stopdraw = 0;
89         }
90 }
91
92 void
93 zoom(void)
94 {
95         Rectangle r;
96         double xmin_, xmax_, ymin_, ymax_;
97
98         r = getrect(3, mctl);
99         if(r.min.x == 0 && r.min.y == 0 && r.max.x == 0 && r.max.y == 0)
100                 return;
101         xmin_ = convx(&screen->r, r.min.x);
102         xmax_ = convx(&screen->r, r.max.x);
103         ymin_ = convy(&screen->r, r.max.y);
104         ymax_ = convy(&screen->r, r.min.y);
105         stopdraw = 1;
106         qlock(rend.l);
107         xmin = xmin_;
108         xmax = xmax_;
109         ymin = ymin_;
110         ymax = ymax_;
111         rwakeup(&rend);
112         qunlock(rend.l);
113 }
114
115 char *menus[] = {
116         "zoom in",
117         "reset",
118         "quit",
119         nil,
120 };
121
122 Menu menu = {
123         .item = menus
124 };
125
126 void
127 resizethread(void *)
128 {
129         ulong l;
130
131         for(;;){
132                 if(recv(mctl->resizec, &l) < 1)
133                         continue;
134                 stopdraw = 1;
135                 qlock(rend.l);
136                 if(getwindow(display, Refnone) < 0)
137                         sysfatal("getwindow: %r");
138                 freeimage(image);
139                 free(imagedata);
140                 image = allocimage(display, screen->r, RGB24, 0, DBlack);
141                 imagedata = malloc(3 * Dx(screen->r) * Dy(screen->r));
142                 rwakeup(&rend);
143                 qunlock(rend.l);
144         }
145 }
146
147 void
148 initcolors(void)
149 {
150         uchar *p;
151         int h, x;
152
153         for(p = colors + 3, h = 0; p < colors + nelem(colors); h++){
154                 x = 0xFF - abs(h % (ncolors / 3) - ncolors / 6) * 0xFF / (ncolors / 6);
155                 if(h < ncolors/6){
156                         *p++ = 0xFF;
157                         *p++ = x;
158                         *p++ = 0;
159                 }else if(h < ncolors/3){
160                         *p++ = x;
161                         *p++ = 0xFF;
162                         *p++ = 0;
163                 }else if(h < ncolors/2){
164                         *p++ = 0;
165                         *p++ = 0xFF;
166                         *p++ = x;
167                 }else if(h < 2*ncolors/3){
168                         *p++ = 0;
169                         *p++ = x;
170                         *p++ = 0xFF;
171                 }else if(h < 5*ncolors/6){
172                         *p++ = x;
173                         *p++ = 0;
174                         *p++ = 0xFF;
175                 }else{
176                         *p++ = 0xFF;
177                         *p++ = 0;
178                         *p++ = x;
179                 }
180         }
181 }
182
183 void
184 threadmain()
185 {
186         static QLock ql;
187         int rc;
188
189         if(initdraw(nil, nil, "mandelbrot") < 0)
190                 sysfatal("initdraw: %r");
191         display->locking = 1;
192         unlockdisplay(display);
193         if((mctl = initmouse(nil, screen)) == nil)
194                 sysfatal("initmouse: %r");
195         rend.l = &ql;
196         image = allocimage(display, screen->r, RGB24, 0, DBlack);
197         imagedata = malloc(3 * Dx(screen->r) * Dy(screen->r));
198         initcolors();
199         proccreate(redrawproc, nil, mainstacksize);
200         threadcreate(resizethread, nil, mainstacksize);
201         for(;;){
202                 readmouse(mctl);
203                 if(mctl->buttons & 4){
204                         lockdisplay(display);
205                         rc = menuhit(3, mctl, &menu, nil);
206                         unlockdisplay(display);
207                         switch(rc){
208                         case 0:
209                                 zoom();
210                                 break;
211                         case 1:
212                                 stopdraw = 1;
213                                 qlock(rend.l);
214                                 xmin = -2;
215                                 xmax = 1;
216                                 ymin = -1;
217                                 ymax = 1;
218                                 rwakeup(&rend);
219                                 qunlock(rend.l);
220                                 break;
221                         case 2:
222                                 threadexitsall(nil);
223                         }
224                 }
225         }
226 }
227
228 Cursor reading = {
229         {-1, -1},
230         {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, 
231          0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0, 
232          0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0, 
233          0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },
234         {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00, 
235          0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0, 
236          0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40, 
237          0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }
238 };