]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/timmy/timmy.c
add games/mus midi converter (by qu7uux)
[plan9front.git] / sys / src / games / timmy / timmy.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <draw.h>
5 #include <mouse.h>
6 #include <keyboard.h>
7 #include <cursor.h>
8 #include "dat.h"
9 #include "fns.h"
10
11 Screen *scr;
12 Image *work, *tray;
13 Image *grey;
14 Obj trayo;
15 Obj worko;
16 Obj runo;
17 Mousectl *mc;
18 Keyboardctl *kc;
19 Obj *carry;
20 int showcarry;
21 extern int Steps;
22
23 void *
24 emalloc(ulong sz)
25 {
26         void *v;
27         
28         v = malloc(sz);
29         if(v == nil) sysfatal("malloc: %r");
30         memset(v, 0, sz);
31         setmalloctag(v, getcallerpc(&sz));
32         return v;
33 }
34
35 Image *
36 rgb(u32int c)
37 {
38         return allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c);
39 }
40
41 void
42 addtray(ObjT *t, ...)
43 {
44         Obj *o;
45         va_list va;
46         static double trayw;
47         
48         va_start(va, t);
49         for(; t != nil; t = va_arg(va, ObjT *)){
50                 o = mkobj(t);
51                 o->tab->move(o, 0, 0, 0);
52                 trayw += TraySpc;
53                 o->tab->move(o, trayw + Dx(o->bbox)/2, TrayH/2, 0);
54                 trayw += Dx(o->bbox);
55                 objcat(&trayo, o);
56         }
57         va_end(va);
58 }
59
60 static void
61 drawtray(void)
62 {
63         Obj *o;
64         
65         for(o = trayo.next; o != &trayo; o = o->next)
66                 o->tab->draw(o, tray);
67 }
68
69 static void
70 screeninit(void)
71 {
72         grey = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
73         scr = allocscreen(screen, display->white, 0);
74         work = allocwindow(scr, Rect(screen->r.min.x, screen->r.min.y, screen->r.max.x, screen->r.max.y - TrayH), 0, 0xFFFFFFFF);
75         tray = allocwindow(scr, Rect(screen->r.min.x, screen->r.max.y - TrayH, screen->r.max.x, screen->r.max.y), 0, 0xCCCCCCFF);
76 }
77
78 static Obj *
79 objclick(Point p, Obj *l)
80 {
81         Obj *o;
82
83         for(o = l->next; o != l; o = o->next)
84                 if(ptinrect(p, o->bbox))
85                         return o;
86         return nil;
87 }
88
89 static void
90 workdraw(void)
91 {
92         Obj *o;
93
94         draw(work, work->r, display->white, nil, ZP);
95         for(o = worko.next; o != &worko; o = o->next)
96                 o->tab->draw(o, work);
97         if(carry != nil && showcarry)
98                 carry->tab->draw(carry, work);
99         flushimage(display, 1);
100 }
101
102 static void
103 rundraw(void)
104 {
105         Obj *o;
106
107         draw(work, work->r, display->white, nil, ZP);
108         for(o = runo.next; o != &runo; o = o->next)
109                 o->tab->draw(o, work);
110         flushimage(display, 1);
111 }
112
113 static int
114 canhinge(Obj *a, Obj *b)
115 {
116         Hinge *h, *k;
117         
118         if(a->hinge == nil || b->hinge == nil) return 0;
119         for(h = a->hinge; h != nil; h = h->onext)
120                 for(k = b->hinge; k != nil; k = k->onext)
121                         if(vecdist(h->p, k->p) <= HingeSep)
122                                 return 1;
123         return 0;
124 }
125
126 static int
127 hinge(Obj *a, Obj *b)
128 {
129         Hinge *h, *k, *l;
130         
131         if(a->hinge == nil || b->hinge == nil) return 0;
132         for(h = a->hinge; h != nil; h = h->onext)
133                 for(k = b->hinge; k != nil; k = k->onext)
134                         if(vecdist(h->p, k->p) <= HingeSep){
135                                 h->cprev->cnext = k;
136                                 k->cprev->cnext = h;
137                                 l = h->cprev;
138                                 h->cprev = k->cprev;
139                                 k->cprev = l;
140                                 b->tab->move(b, b->p.x + h->p.x - k->p.x, b->p.y + h->p.y - k->p.y, b->θ);
141                                 return 1;
142                         }
143         return 0;       
144 }
145
146 static void
147 place(void)
148 {
149         Obj *o;
150         int hinges;
151         
152         hinges = 0;
153         for(o = worko.next; o != &worko; o = o->next)
154                 if(objcoll(o, carry))
155                         if(canhinge(o, carry))
156                                 hinges++;
157                         else
158                                 return;
159         for(o = worko.next; hinges > 0 && o != &worko; o = o->next)
160                 if(objcoll(o, carry))
161                         hinges -= hinge(o, carry);
162         if(hinges != 0) print("hinge error\n");
163         objcat(&worko, carry);
164         carry = nil;
165         workdraw();
166 }
167
168 static void
169 mouse(void)
170 {
171         static int lbut = -1;
172         Point p;
173         
174         if(lbut < 0)
175                 lbut = mc->buttons;
176         if(ptinrect(mc->xy, work->r)){
177                 p = subpt(mc->xy, work->r.min);
178                 if(carry != nil && (carry->p.x != p.x || carry->p.y != p.y || !showcarry)){
179                         carry->tab->move(carry, p.x, p.y, carry->θ);
180                         showcarry = 1;
181                         workdraw();
182                 }
183         }else if(showcarry){
184                 showcarry = 0;
185                 if(carry != nil)
186                         workdraw();
187         }
188         if((~mc->buttons & lbut & 1) != 0){
189                 if(ptinrect(mc->xy, tray->r)){
190                         carry = objclick(subpt(mc->xy, tray->r.min), &trayo);
191                         if(carry != nil)
192                                 carry = objdup(carry);
193                 }else if(ptinrect(mc->xy, work->r)){
194                         if(carry != nil)
195                                 place();
196                         else{
197                                 carry = objclick(subpt(mc->xy, work->r.min), &worko);
198                                 if(carry != nil)
199                                         objexcise(carry);
200                         }
201                 }
202         }
203         if((~mc->buttons & lbut & 4) != 0){
204                 if(carry != nil){
205                         freeobj(carry);
206                         carry = nil;
207                         showcarry = 0;
208                         workdraw();
209                 }else if(ptinrect(mc->xy, work->r)){
210                         carry = objclick(subpt(mc->xy, work->r.min), &worko);
211                         if(carry != nil)
212                                 carry = objdup(carry);
213                 }
214         }
215         lbut = mc->buttons;
216 }
217
218 static void
219 run(void)
220 {
221         Obj *o, *oo;
222         Rune r;
223         static Cursor cursor;
224
225         for(o = runo.next; o != &runo; o = oo){
226                 oo = o->next;
227                 freeobj(o);
228         }
229         for(o = worko.next; o != &worko; o = o->next)
230                 objcat(&runo, objdup(o));
231         copyhinges(&worko, &runo);
232         setcursor(mc, &cursor);
233         for(;;){
234                 Alt a[] = {
235                         {mc->c, &mc->Mouse, CHANRCV},
236                         {kc->c, &r, CHANRCV},
237                         {nil, nil, CHANNOBLK}
238                 };
239                 
240                 switch(alt(a)){
241                 case 0: mouse(); break;
242                 case 1:
243                         switch(r){
244                         case ' ': goto out;
245                         case Kdel: threadexitsall(nil);
246                         }
247                 }
248                 
249                 physstep();
250                 rundraw();
251         }
252 out:
253         workdraw();
254         setcursor(mc, nil);     
255 }
256
257 static void
258 key(Rune r)
259 {
260         switch(r){
261         case Kdel:
262                 threadexitsall(nil);
263         case 'w':
264                 if(carry != nil){
265                         carry->tab->move(carry, carry->p.x, carry->p.y, carry->θ - 15);
266                         workdraw();
267                 }
268                 break;
269         case 'e':
270                 if(carry != nil){
271                         carry->tab->move(carry, carry->p.x, carry->p.y, carry->θ + 15);
272                         workdraw();
273                 }
274                 break;
275         case ' ':
276                 run();
277                 break;
278         }
279 }
280
281 static void
282 usage(void)
283 {
284         fprint(2, "usage: %s [-s steps]\n", argv0);
285         threadexitsall("usage");
286 }
287
288 void
289 threadmain(int argc, char **argv)
290 {
291         void simpleinit(void);
292         Rune r;
293         char *s;
294         
295         ARGBEGIN{
296         case 's':
297                 Steps = strtol(EARGF(usage()), &s, 0);
298                 if(*s != 0) usage();
299                 break;
300         default: usage();
301         }ARGEND;
302
303         if(initdraw(nil, nil, nil) < 0) sysfatal("initdraw: %r");
304         mc = initmouse(nil, screen);
305         if(mc == nil) sysfatal("initmouse: %r");
306         kc = initkeyboard(nil);
307         if(kc == nil) sysfatal("initkeyboard: %r");
308         screeninit();
309         trayo.prev = trayo.next = &trayo;
310         worko.prev = worko.next = &worko;
311         runo.prev = runo.next = &runo;
312         simpleinit();
313         drawtray();
314         flushimage(display, 1);
315
316         for(;;){
317                 Alt a[] = {
318                         {mc->c, &mc->Mouse, CHANRCV},
319                         {kc->c, &r, CHANRCV},
320                         {nil, nil, CHANEND}
321                 };
322                 
323                 switch(alt(a)){
324                 case 0: mouse(); break;
325                 case 1: key(r); break;
326                 }
327         }
328 }