1 | /* -*- Mode: C; tab-width: 4 -*- */ |
---|
2 | /* juggle */ |
---|
3 | |
---|
4 | #if 0 |
---|
5 | static const char sccsid[] = "@(#)juggle.c 5.00 2000/11/01 xlockmore"; |
---|
6 | #endif |
---|
7 | |
---|
8 | /*- |
---|
9 | * Copyright (c) 1996 by Tim Auckland <Tim.Auckland@Procket.com> |
---|
10 | * |
---|
11 | * Permission to use, copy, modify, and distribute this software and its |
---|
12 | * documentation for any purpose and without fee is hereby granted, |
---|
13 | * provided that the above copyright notice appear in all copies and that |
---|
14 | * both that copyright notice and this permission notice appear in |
---|
15 | * supporting documentation. |
---|
16 | * |
---|
17 | * This file is provided AS IS with no warranties of any kind. The author |
---|
18 | * shall have no liability with respect to the infringement of copyrights, |
---|
19 | * trade secrets or any patents by this file or any part thereof. In no |
---|
20 | * event will the author be liable for any lost revenue or profits or |
---|
21 | * other special, indirect and consequential damages. |
---|
22 | * |
---|
23 | * Revision History |
---|
24 | * 01-Nov-2000: Allocation checks |
---|
25 | * 1996: Written |
---|
26 | */ |
---|
27 | |
---|
28 | /*- |
---|
29 | * TODO |
---|
30 | * Fix timing to run at approx same speed on all machines. |
---|
31 | * Store shorter pattern and refill when required. |
---|
32 | * Use -cycles and -count in a rational manner. |
---|
33 | * Merge pattern selector with pattern generator. |
---|
34 | * Add clubs |
---|
35 | * Clap when all the balls are in the air |
---|
36 | */ |
---|
37 | |
---|
38 | |
---|
39 | /*- |
---|
40 | Notes on Adam Chalcraft Juggling Notation (used by permission) |
---|
41 | a-> Adam's notation s-> Site swap (Cambridge) notation |
---|
42 | |
---|
43 | To define a map from a-notation to s-notation |
---|
44 | ("site-swap"), both of which look like doubly infinite sequences of natural |
---|
45 | numbers. In s-notation, there is a restriction on what is allowed, namely |
---|
46 | for the sequence s_n, the associated function f(n)=n+s_n must be a |
---|
47 | bijection. In a-notation, there is no restriction. |
---|
48 | |
---|
49 | To go from a-notation to s-notation, you start by mapping each a_n to a |
---|
50 | permutation of N, the natural numbers. |
---|
51 | |
---|
52 | 0 -> the identity |
---|
53 | 1 -> (10) [i.e. f(1)=0, f(0)=1] |
---|
54 | 2 -> (210) [i.e. f(2)=1, f(1)=0, f(0)=2] |
---|
55 | 3 -> (3210) [i.e. f(3)=2, f(2)=1, f(1)=0, f(0)=3] |
---|
56 | etc. |
---|
57 | |
---|
58 | Then for each n, you look at how long 0 takes to get back to 0 again and |
---|
59 | you call this t_n. If a_n=0, for example, then since the identity leaves 0 |
---|
60 | alone, it gets back to 0 in 1 step, so t_n=1. If a_n=1, then f(0)=1. Now any |
---|
61 | further a_n=0 leave 1 alone, but the next a_n>0 sends 1 back to 0. Hence t_n |
---|
62 | is 2 + the number of 0's following the 1. Finally, set s_n = t_n - 1. |
---|
63 | |
---|
64 | To give some examples, it helps to have a notation for cyclic sequences. By |
---|
65 | (123), for example, I mean ...123123123123... . Now under the a-notation -> |
---|
66 | s-notation mapping we have some familiar examples: |
---|
67 | |
---|
68 | (0)->(0), (1)->(1), (2)->(2) etc. |
---|
69 | (21)->(31), (31)->(51), (41)->(71) etc. |
---|
70 | (10)->(20), (20)->(40), (30)->(60) etc. |
---|
71 | (331)->(441), (312)->(612), (303)->(504), (321)->(531) |
---|
72 | (43)->(53), (434)->(534), (433)->(633) |
---|
73 | (552)->(672) |
---|
74 | |
---|
75 | In general, the number of balls is the *average* of the s-notation, and the |
---|
76 | *maximum* of the a-notation. Another theorem is that the minimum values in |
---|
77 | the a-notation and the s-notation and equal, and preserved in the same |
---|
78 | positions. |
---|
79 | |
---|
80 | The usefulness of a-notation is the fact that there are no restrictions on |
---|
81 | what is allowed. This makes random juggle generation much easier. It also |
---|
82 | makes enumeration very easy. Another handy feature is computing changes. |
---|
83 | Suppose you can do (5) and want a neat change up to (771) in s-notation |
---|
84 | [Mike Day actually needed this example!]. Write them both in a-notation, |
---|
85 | which gives (5) and (551). Now concatenate them (in general, there may be |
---|
86 | more than one way to do this, but not in this example), to get |
---|
87 | ...55555555551551551551551... |
---|
88 | Now convert back to s-notation, to get |
---|
89 | ...55555566771771771771771... |
---|
90 | So the answer is to do two 6 throws and then go straight into (771). |
---|
91 | Coming back down of course, |
---|
92 | ...5515515515515515555555555... |
---|
93 | converts to |
---|
94 | ...7717717717716615555555555... |
---|
95 | so the answer is to do a single 661 and then drop straight down to (5). |
---|
96 | |
---|
97 | [The number of balls in the generated pattern occasionally changes. In |
---|
98 | order to decrease the number of balls I had to introduce a new symbol |
---|
99 | into the Adam notation, [*] which means 'lose the current ball'.] |
---|
100 | */ |
---|
101 | |
---|
102 | #ifdef STANDALONE |
---|
103 | #define MODE_juggle |
---|
104 | #define PROGCLASS "Juggle" |
---|
105 | #define HACK_INIT init_juggle |
---|
106 | #define HACK_DRAW draw_juggle |
---|
107 | #define juggle_opts xlockmore_opts |
---|
108 | #define DEFAULTS "*delay: 10000 \n" \ |
---|
109 | "*count: 150 \n" \ |
---|
110 | "*cycles: 30 \n" \ |
---|
111 | "*ncolors: 32 \n" |
---|
112 | #define SMOOTH_COLORS |
---|
113 | #include "xlockmore.h" /* in xscreensaver distribution */ |
---|
114 | #else /* STANDALONE */ |
---|
115 | #include "xlock.h" /* in xlockmore distribution */ |
---|
116 | #endif /* STANDALONE */ |
---|
117 | |
---|
118 | #ifdef MODE_juggle |
---|
119 | |
---|
120 | #define DEF_PATTERN "." /* All patterns */ |
---|
121 | #define DEF_TRAIL "0" /* No trace */ |
---|
122 | #ifdef UNI |
---|
123 | #define DEF_UNI "FALSE" /* No unicycle */ /* Not implemented yet */ |
---|
124 | #endif |
---|
125 | #define DEF_SOLID "FALSE" /* Not solid */ |
---|
126 | |
---|
127 | static char *pattern; |
---|
128 | static int trail; |
---|
129 | #ifdef UNI |
---|
130 | static Bool uni; |
---|
131 | #endif |
---|
132 | static Bool solid; |
---|
133 | |
---|
134 | static XrmOptionDescRec opts[] = |
---|
135 | { |
---|
136 | {(char* ) "-pattern", (char *) ".juggle.pattern", |
---|
137 | XrmoptionSepArg, (caddr_t) NULL}, |
---|
138 | {(char* ) "-trail", (char *) ".juggle.trail", |
---|
139 | XrmoptionSepArg, (caddr_t) NULL}, |
---|
140 | #ifdef UNI |
---|
141 | {(char *) "-uni", (char *) ".juggle.uni", XrmoptionNoArg, (caddr_t) "on"}, |
---|
142 | {(char *) "+uni", (char *) ".juggle.uni", XrmoptionNoArg, (caddr_t) "off"}, |
---|
143 | #endif |
---|
144 | {(char *) "-solid", (char *) ".juggle.solid", XrmoptionNoArg, (caddr_t) "on"}, |
---|
145 | {(char *) "+solid", (char *) ".juggle.solid", XrmoptionNoArg, (caddr_t) "off"} |
---|
146 | }; |
---|
147 | static argtype vars[] = |
---|
148 | { |
---|
149 | {(caddr_t *) &pattern, (char *) "pattern", |
---|
150 | (char *) "Pattern", (char *) DEF_PATTERN, t_String}, |
---|
151 | {(caddr_t *) &trail, (char *) "trail", |
---|
152 | (char *) "Trail", (char *) DEF_TRAIL, t_Int}, |
---|
153 | #ifdef UNI |
---|
154 | {(caddr_t *) &uni, (char *) "uni", |
---|
155 | (char *) "Uni", (char *) DEF_UNI, t_Bool}, |
---|
156 | #endif |
---|
157 | {(caddr_t *) &solid, (char *) "solid", |
---|
158 | (char *) "Solid", (char *) DEF_SOLID, t_Bool} |
---|
159 | }; |
---|
160 | static OptionStruct desc[] = |
---|
161 | { |
---|
162 | {(char *) "-pattern string", (char *) "Cambridge Juggling Pattern"}, |
---|
163 | {(char *) "-trail num", (char *) "Trace Juggling Patterns"}, |
---|
164 | #ifdef UNI |
---|
165 | {(char *) "-/+uni", (char *) "Unicycle"}, |
---|
166 | #endif |
---|
167 | {(char *) "-/+solid", (char *) "solid color (else its a 4 panel look (half white))"} |
---|
168 | }; |
---|
169 | |
---|
170 | ModeSpecOpt juggle_opts = |
---|
171 | {sizeof opts / sizeof opts[0], opts, |
---|
172 | sizeof vars / sizeof vars[0], vars, desc}; |
---|
173 | |
---|
174 | #ifdef USE_MODULES |
---|
175 | ModStruct juggle_description = { |
---|
176 | "juggle", "init_juggle", "draw_juggle", "release_juggle", |
---|
177 | "draw_juggle", "init_juggle", (char *) NULL, &juggle_opts, |
---|
178 | 10000, 150, 30, 1, 64, 1.0, "", |
---|
179 | "Shows a Juggler, juggling", 0, NULL |
---|
180 | }; |
---|
181 | |
---|
182 | #endif |
---|
183 | |
---|
184 | #ifdef USE_XVMSUTILS |
---|
185 | #include <X11/unix_time.h> |
---|
186 | #endif |
---|
187 | #include <time.h> |
---|
188 | #if HAVE_SYS_TIME_H |
---|
189 | #include <sys/time.h> |
---|
190 | #else |
---|
191 | #if HAVE_SYS_SELECT_H |
---|
192 | #include <sys/select.h> |
---|
193 | #endif |
---|
194 | #endif |
---|
195 | |
---|
196 | /* Figure */ |
---|
197 | #define ARMLENGTH ((int) (40.0 * sp->scale)) |
---|
198 | #define ARMWIDTH ((int) (8.0 * sqrt(sp->scale))) |
---|
199 | #define POSE ((int) (10.0 * sp->scale)) |
---|
200 | #define SX ((int) (25.0 * sp->scale)) |
---|
201 | #define SZ ((int) (25.0 * sp->scale)) |
---|
202 | #define SY ((int) (25.0 * sp->scale)) |
---|
203 | #define HIPY ((int) (85.0 * sp->scale)) |
---|
204 | #define RHIPX ((int) (-15.0 * sp->scale)) |
---|
205 | #define LHIPX ((int) (15.0 * sp->scale)) |
---|
206 | #define RFX ((int) (-25.0 * sp->scale)) |
---|
207 | #define LFX ((int) (25.0 * sp->scale)) |
---|
208 | #define FY ((int) (155.0 * sp->scale)) |
---|
209 | #define WSTY ((int) (65.0 * sp->scale)) |
---|
210 | #define NEY ((int) (15.0 * sp->scale)) |
---|
211 | #define HED ((int) (35.0 * sp->scale)) |
---|
212 | #define BALLRADIUS ARMWIDTH |
---|
213 | #define FIGURE1 7 |
---|
214 | #define FIGURE2 3 |
---|
215 | #define TRACE_LENGTH 50 |
---|
216 | #define SPIN_DEGREES 750 /* Average spinning between a throw and the next catch */ |
---|
217 | |
---|
218 | /* macros */ |
---|
219 | |
---|
220 | #ifndef XtNumber |
---|
221 | #define XtNumber(arr) ((unsigned int) (sizeof(arr) / sizeof(arr[0]))) |
---|
222 | #endif |
---|
223 | |
---|
224 | #define GRAVITY(h, t) 4*(double)(h)/((t)*(t)) |
---|
225 | |
---|
226 | #define THROW_CATCH_INTERVAL (sp->count) |
---|
227 | #define THROW_NULL_INTERVAL (sp->count * 0.5) |
---|
228 | #define CATCH_THROW_INTERVAL (sp->count * 0.2) |
---|
229 | #define COR 0.8 /* coeff of restitution of balls (1 = perfect bounce) */ |
---|
230 | |
---|
231 | |
---|
232 | /* typedefs */ |
---|
233 | |
---|
234 | typedef enum {HEIGHT, ADAM} Notation; |
---|
235 | typedef enum {Empty, Full, Ball} Throwable; |
---|
236 | typedef enum {LEFT, RIGHT} Hand; |
---|
237 | typedef enum {THROW, CATCH} Action; /* DROP is not an option */ |
---|
238 | typedef enum {ATCH, THRATCH, ACTION, LINKEDACTION, PTHRATCH, BPREDICTOR, |
---|
239 | PREDICTOR} TrajectoryStatus; |
---|
240 | |
---|
241 | typedef struct trajectory *TrajectoryPtr; |
---|
242 | |
---|
243 | typedef struct {double a, b, c, d; } Spline; |
---|
244 | |
---|
245 | typedef struct trajectory { |
---|
246 | TrajectoryPtr prev, next; /* for building list */ |
---|
247 | TrajectoryStatus status; |
---|
248 | |
---|
249 | /* Throw */ |
---|
250 | char posn; |
---|
251 | int height; |
---|
252 | int adam; |
---|
253 | |
---|
254 | /* Action */ |
---|
255 | Hand hand; |
---|
256 | Action action; |
---|
257 | |
---|
258 | /* LinkedAction */ |
---|
259 | int color; |
---|
260 | int spin, divisions; |
---|
261 | double degree_offset; |
---|
262 | TrajectoryPtr balllink; |
---|
263 | TrajectoryPtr handlink; |
---|
264 | |
---|
265 | /* PThratch */ |
---|
266 | |
---|
267 | double dx; /* initial velocity */ |
---|
268 | double dy; |
---|
269 | |
---|
270 | /* Predictor */ |
---|
271 | Throwable type; |
---|
272 | int start, finish; |
---|
273 | Spline xp, yp; |
---|
274 | int x, y; /* current position */ |
---|
275 | } Trajectory; |
---|
276 | |
---|
277 | /* structs */ |
---|
278 | |
---|
279 | typedef struct { |
---|
280 | int width; |
---|
281 | int height; |
---|
282 | double scale; |
---|
283 | int complexity; |
---|
284 | int cx; |
---|
285 | int cy; |
---|
286 | double Gr; |
---|
287 | int pattern; |
---|
288 | Trajectory *head; |
---|
289 | XPoint figure_path[FIGURE1]; |
---|
290 | XSegment figure_segs[FIGURE2]; |
---|
291 | XPoint arm[2][3]; |
---|
292 | XPoint *trace; |
---|
293 | int traceindex; |
---|
294 | int count; |
---|
295 | time_t begintime; /* seconds */ |
---|
296 | int time; /* millisecond timer */ |
---|
297 | Bool solid, uni; |
---|
298 | } jugglestruct; |
---|
299 | |
---|
300 | static jugglestruct *juggles = (jugglestruct *) NULL; |
---|
301 | |
---|
302 | typedef struct { |
---|
303 | char * pattern; |
---|
304 | char * name; |
---|
305 | } patternstruct; |
---|
306 | |
---|
307 | #define MINBALLS 2 |
---|
308 | #define MAXBALLS 7 |
---|
309 | |
---|
310 | typedef struct { |
---|
311 | int start; |
---|
312 | int number; |
---|
313 | } PatternIndex; |
---|
314 | |
---|
315 | static PatternIndex* patternindex = (PatternIndex *) NULL; |
---|
316 | |
---|
317 | /* List of popular patterns, in any order */ |
---|
318 | static patternstruct portfolio[] = { |
---|
319 | {(char *) "[+2 1]", (char *) "+3 1, Typical 2 ball juggler"}, |
---|
320 | {(char *) "[2 0]", (char *) "4 0, 2 balls 1 hand"}, |
---|
321 | {(char *) "[2 0 1]", (char *) "5 0 1"}, |
---|
322 | {(char *) "[+2 0 +2 0 0]", (char *) "+5 0 +5 0 0"}, |
---|
323 | {(char *) "[3]", (char *) "3, cascade"}, |
---|
324 | {(char *) "[+3]", (char *) "+3, reverse cascade"}, |
---|
325 | {(char *) "[=3]", (char *) "=3, cascade under arm"}, |
---|
326 | {(char *) "[&3]", (char *) "&3, cascade catching under arm"}, |
---|
327 | {(char *) "[_3]", (char *) "_3, bouncing cascade"}, |
---|
328 | {(char *) "[+3 x3 =3]", (char *) "+3 x3 =3, Mill's mess"}, |
---|
329 | {(char *) "[3 2 1]", (char *) "5 3 1"}, |
---|
330 | {(char *) "[3 3 1]", (char *) "4 4 1"}, |
---|
331 | {(char *) "[3 1 2]", (char *) "6 1 2, See-saw"}, |
---|
332 | {(char *) "[=3 3 1 2]", (char *) "=4 5 1 2"}, |
---|
333 | {(char *) "[=3 2 2 3 1 2]", (char *) "=6 2 2 5 1 2, =4 5 1 2 stretched"}, |
---|
334 | {(char *) "[+3 3 1 3]", (char *) "+4 4 1 3, anemic shower box"}, |
---|
335 | {(char *) "[3 3 1]", (char *) "4 4 1"}, |
---|
336 | {(char *) "[+3 2 3]", (char *) "+4 2 3"}, |
---|
337 | {(char *) "[+3 1]", (char *) "+5 1, 3 shower"}, |
---|
338 | {(char *) "[_3 1]", (char *) "_5 1, bouncing 3 shower"}, |
---|
339 | {(char *) "[3 0 3 0 3]", (char *) "5 0 5 0 5, shake 3 out of 5"}, |
---|
340 | {(char *) "[3 3 3 0 0]", (char *) "5 5 5 0 0, flash 3 out of 5"}, |
---|
341 | {(char *) "[3 3 0]", (char *) "4 5 0, complete waste of a 5 ball juggler"}, |
---|
342 | {(char *) "[3 3 3 0 0 0 0]", (char *) "7 7 7 0 0 0 0, 3 flash"}, |
---|
343 | {(char *) "[+3 0 +3 0 +3 0 0]", (char *) "+7 0 +7 0 +7 0 0"}, |
---|
344 | {(char *) "[4]", (char *) "4, 4 cascade"}, |
---|
345 | {(char *) "[+4 3]", (char *) "+5 3, 4 ball half shower"}, |
---|
346 | {(char *) "[4 4 2]", (char *) "5 5 2"}, |
---|
347 | {(char *) "[+4 4 4 +4]", (char *) "+4 4 4 +4, 4 columns"}, |
---|
348 | {(char *) "[4 3 +4]", (char *) "5 3 +4"}, |
---|
349 | {(char *) "[+4 1]", (char *) "+7 1, 4 shower"}, |
---|
350 | {(char *) "[4 4 4 4 0]", (char *) "5 5 5 5 0, learning 5"}, |
---|
351 | {(char *) "[5]", (char *) "5, 5 cascade"}, |
---|
352 | {(char *) "[_5 _5 _5 _5 _5 5 5 5 5 5]", (char *) "_5 _5 _5 _5 _5 5 5 5 5 5, jump rope"}, |
---|
353 | {(char *) "[+5 x5 =5]", (char *) "+5 x5 =5, Mill's mess for 5"}, |
---|
354 | {(char *) "[6]", (char *) "6, 6 cascade"}, |
---|
355 | {(char *) "[7]", (char *) "7, 7 cascade"}, |
---|
356 | {(char *) "[_7]", (char *) "_7, bouncing 7 cascade"}, |
---|
357 | }; |
---|
358 | |
---|
359 | /* Private Functions */ |
---|
360 | |
---|
361 | /* list management */ |
---|
362 | |
---|
363 | /* t receives trajectory to be created. ot must point to an existing |
---|
364 | trajectory or be identical to t to start a new list. */ |
---|
365 | #define INSERT_AFTER_TOP(t, ot) \ |
---|
366 | if ((t = (Trajectory *)calloc(1, sizeof(Trajectory))) == NULL) \ |
---|
367 | {free_juggle(sp); return;} \ |
---|
368 | (t)->next = (ot)->next; \ |
---|
369 | (t)->prev = (ot); \ |
---|
370 | (ot)->next = (t); \ |
---|
371 | (t)->next->prev = (t) |
---|
372 | #define INSERT_AFTER(t, ot) \ |
---|
373 | if ((t = (Trajectory *)calloc(1, sizeof(Trajectory))) == NULL) \ |
---|
374 | {free_juggle(sp); return False;} \ |
---|
375 | (t)->next = (ot)->next; \ |
---|
376 | (t)->prev = (ot); \ |
---|
377 | (ot)->next = (t); \ |
---|
378 | (t)->next->prev = (t) |
---|
379 | |
---|
380 | |
---|
381 | /* t must point to an existing trajectory. t must not be an |
---|
382 | expression ending ->next or ->prev */ |
---|
383 | #define REMOVE(t) \ |
---|
384 | (t)->next->prev = (t)->prev; \ |
---|
385 | (t)->prev->next = (t)->next; \ |
---|
386 | (void) free((void *) t) |
---|
387 | |
---|
388 | static void |
---|
389 | free_pattern(jugglestruct *sp) { |
---|
390 | if (sp->head != NULL) { |
---|
391 | while (sp->head->next != sp->head) { |
---|
392 | Trajectory *t = sp->head->next; |
---|
393 | |
---|
394 | REMOVE(t); /* don't eliminate t */ |
---|
395 | } |
---|
396 | (void) free((void *) sp->head); |
---|
397 | sp->head = (Trajectory *) NULL; |
---|
398 | } |
---|
399 | } |
---|
400 | |
---|
401 | static void |
---|
402 | free_juggle(jugglestruct *sp) |
---|
403 | { |
---|
404 | if (sp->trace != NULL) { |
---|
405 | (void) free((void *) sp->trace); |
---|
406 | sp->trace = (XPoint *) NULL; |
---|
407 | } |
---|
408 | free_pattern(sp); |
---|
409 | } |
---|
410 | |
---|
411 | static Bool |
---|
412 | add_throw(jugglestruct *sp, char type, int h, Notation n) |
---|
413 | { |
---|
414 | Trajectory *t; |
---|
415 | |
---|
416 | INSERT_AFTER(t, sp->head->prev); |
---|
417 | t->posn = type; |
---|
418 | if (n == ADAM) { |
---|
419 | t->adam = h; |
---|
420 | t->status = ATCH; |
---|
421 | } else { |
---|
422 | t->height = h; |
---|
423 | t->status = THRATCH; |
---|
424 | } |
---|
425 | return True; |
---|
426 | } |
---|
427 | |
---|
428 | /* add a Thratch to the performance */ |
---|
429 | static Bool |
---|
430 | program(ModeInfo *mi, const char *patn, int repeat) |
---|
431 | { |
---|
432 | jugglestruct *sp = &juggles[MI_SCREEN(mi)]; |
---|
433 | const char *p; |
---|
434 | int h, i, seen; |
---|
435 | Notation notation; |
---|
436 | char type; |
---|
437 | |
---|
438 | if (MI_IS_VERBOSE(mi)) { |
---|
439 | (void) fprintf(stderr, "%s x %d\n", patn, repeat); |
---|
440 | } |
---|
441 | |
---|
442 | for(i=0; i < repeat; i++) { |
---|
443 | type=' '; |
---|
444 | h = 0; |
---|
445 | seen = 0; |
---|
446 | notation = HEIGHT; |
---|
447 | for(p=patn; *p; p++) { |
---|
448 | if (*p >= '0' && *p <='9') { |
---|
449 | seen = 1; |
---|
450 | h = 10*h + (*p - '0'); |
---|
451 | } else { |
---|
452 | Notation nn = notation; |
---|
453 | switch (*p) { |
---|
454 | case '[': /* begin Adam notation */ |
---|
455 | notation = ADAM; |
---|
456 | break; |
---|
457 | case '-': /* Inside throw */ |
---|
458 | case '+': /* Outside throw */ |
---|
459 | case '=': /* Cross throw */ |
---|
460 | case '&': /* Cross catch */ |
---|
461 | case 'x': /* Cross throw and catch */ |
---|
462 | case '_': /* Bounce */ |
---|
463 | type = *p; |
---|
464 | break; |
---|
465 | case '*': /* Lose ball */ |
---|
466 | seen = 1; |
---|
467 | h = -1; |
---|
468 | /* fall through */ |
---|
469 | case ']': /* end Adam notation */ |
---|
470 | nn = HEIGHT; |
---|
471 | /* fall through */ |
---|
472 | case ' ': |
---|
473 | if (seen) { |
---|
474 | if (!add_throw(sp, type, h, notation)) |
---|
475 | return False; |
---|
476 | type=' '; |
---|
477 | h = 0; |
---|
478 | seen = 0; |
---|
479 | } |
---|
480 | notation = nn; |
---|
481 | break; |
---|
482 | default: |
---|
483 | (void) fprintf(stderr, "Unexpected pattern instruction: '%s'\n", p); |
---|
484 | break; |
---|
485 | } |
---|
486 | } |
---|
487 | } |
---|
488 | if (seen) { |
---|
489 | if (!add_throw(sp, type, h, notation)) |
---|
490 | return False; |
---|
491 | } |
---|
492 | } |
---|
493 | return True; |
---|
494 | } |
---|
495 | |
---|
496 | /* |
---|
497 | ~~~~\~~~~~\~~~ |
---|
498 | \\~\\~\~\\\~~~ |
---|
499 | \\~\\\\~\\\~\~ |
---|
500 | \\\\\\\\\\\~\\ |
---|
501 | |
---|
502 | [33134231334021] |
---|
503 | |
---|
504 | 4 4 1 3 12 2 4 1 4 4 13 0 3 1 |
---|
505 | |
---|
506 | */ |
---|
507 | #define BOUNCEOVER 10 |
---|
508 | |
---|
509 | static void |
---|
510 | adam(jugglestruct *sp) |
---|
511 | { |
---|
512 | Trajectory *t, *p; |
---|
513 | for(t = sp->head->next; t != sp->head; t = t->next) { |
---|
514 | if (t->status == ATCH) { |
---|
515 | int a = t->adam; |
---|
516 | t->height = 0; |
---|
517 | for(p = t->next; a > 0 && p != sp->head; p = p->next) { |
---|
518 | if (p->status != ATCH || p->adam < 0 || p->adam>= a) { |
---|
519 | a--; |
---|
520 | } |
---|
521 | t->height++; |
---|
522 | } |
---|
523 | if(t->height > BOUNCEOVER && t->posn == ' '){ |
---|
524 | t->posn = '_'; /* high defaults can be bounced */ |
---|
525 | } |
---|
526 | t->status = THRATCH; |
---|
527 | #if 0 |
---|
528 | (void) fprintf(stderr, "%d\t%d\n", t->adam, t->height); |
---|
529 | #endif |
---|
530 | } |
---|
531 | } |
---|
532 | } |
---|
533 | |
---|
534 | /* Split Thratch notation into explicit throws and catches. |
---|
535 | Usually Catch follows Throw in same hand, but take care of special |
---|
536 | cases. */ |
---|
537 | |
---|
538 | /* ..n1.. -> .. LTn RT1 LC RC .. */ |
---|
539 | /* ..nm.. -> .. LTn LC RTm RC .. */ |
---|
540 | |
---|
541 | static Bool |
---|
542 | part(jugglestruct *sp) |
---|
543 | { |
---|
544 | Trajectory *t, *nt, *p; |
---|
545 | Hand hand = (LRAND() & 1) ? RIGHT : LEFT; |
---|
546 | |
---|
547 | for (t = sp->head->next; t != sp->head; t = t->next) { |
---|
548 | if (t->status > THRATCH) { |
---|
549 | hand = t->hand; |
---|
550 | } else if (t->status == THRATCH) { |
---|
551 | char posn = '='; |
---|
552 | |
---|
553 | /* plausibility check */ |
---|
554 | if (t->height <= 2 && t->posn == '_') { |
---|
555 | t->posn = ' '; /* no short bounces */ |
---|
556 | } |
---|
557 | if (t->height <= 1 && (t->posn == '=' || t->posn == '&')) { |
---|
558 | t->posn = ' '; /* 1's need close catches */ |
---|
559 | } |
---|
560 | |
---|
561 | switch (t->posn) { |
---|
562 | /* throw catch */ |
---|
563 | case ' ': /* fall through */ |
---|
564 | case '-': posn = '-'; t->posn = '+'; break; |
---|
565 | case '+': posn = '+'; t->posn = '-'; break; |
---|
566 | case '=': posn = '='; t->posn = '+'; break; |
---|
567 | case '&': posn = '+'; t->posn = '='; break; |
---|
568 | case 'x': posn = '='; t->posn = '='; break; |
---|
569 | case '_': posn = '_'; t->posn = '-'; break; |
---|
570 | default: (void) fprintf(stderr, "unexpected posn %c\n", t->posn); break; |
---|
571 | } |
---|
572 | hand = (Hand) ((hand + 1) % 2); |
---|
573 | t->status = ACTION; |
---|
574 | t->hand = hand; |
---|
575 | p = t->prev; |
---|
576 | |
---|
577 | if (t->height == 1) { |
---|
578 | p = p->prev; /* early throw */ |
---|
579 | } |
---|
580 | t->action = CATCH; |
---|
581 | INSERT_AFTER(nt, p); |
---|
582 | nt->status = ACTION; |
---|
583 | nt->action = THROW; |
---|
584 | nt->height = t->height; |
---|
585 | nt->hand = hand; |
---|
586 | nt->posn = posn; |
---|
587 | } |
---|
588 | } |
---|
589 | return True; |
---|
590 | } |
---|
591 | |
---|
592 | /* Connnect up throws and catches to figure out which ball goes where. |
---|
593 | Do the same with the juggler's hands. */ |
---|
594 | |
---|
595 | static void |
---|
596 | lob(ModeInfo *mi) |
---|
597 | { |
---|
598 | jugglestruct *sp = &juggles[MI_SCREEN(mi)]; |
---|
599 | Trajectory *t, *p; |
---|
600 | int h; |
---|
601 | for (t = sp->head->next; t != sp->head; t = t->next) { |
---|
602 | if (t->status == ACTION) { |
---|
603 | #if 0 |
---|
604 | (void) fprintf(stderr, (t->action == CATCH) ? "A %c%c%c\n" : "A %c%c%c%d\n", |
---|
605 | t->posn, |
---|
606 | t->hand ? 'R' : 'L', |
---|
607 | (t->action == THROW) ? 'T' : (t->action == CATCH ? 'C' : 'N'), |
---|
608 | t->height); |
---|
609 | #endif |
---|
610 | if (t->action == THROW) { |
---|
611 | if (t->type == Empty) { |
---|
612 | if (MI_NPIXELS(mi) > 2) { |
---|
613 | t->color = 1 + NRAND(MI_NPIXELS(mi) - 2); |
---|
614 | } |
---|
615 | t->spin = NRAND(5) - 2; |
---|
616 | t->degree_offset = NRAND(360); |
---|
617 | t->divisions = 2 * ((LRAND() & 1) + 1); |
---|
618 | } |
---|
619 | |
---|
620 | /* search forward for next hand catch */ |
---|
621 | for (p = t->next; t->handlink == NULL && p != sp->head; p = p->next) { |
---|
622 | if (p->action == CATCH) { |
---|
623 | if (t->handlink == NULL && p->hand == t->hand) { |
---|
624 | t->handlink = p; /* next catch in this hand */ |
---|
625 | } |
---|
626 | } |
---|
627 | } |
---|
628 | |
---|
629 | if (t->height > 0) { |
---|
630 | h = t->height - 1; |
---|
631 | |
---|
632 | /* search forward for next ball catch */ |
---|
633 | for (p = t->next; t->balllink == NULL&& p != sp->head; p = p->next) { |
---|
634 | if (p->action == CATCH) { |
---|
635 | if (t->balllink == NULL && --h < 1) { /* caught */ |
---|
636 | #if 0 |
---|
637 | if (p->type == Full) { |
---|
638 | /* dropped */ |
---|
639 | } |
---|
640 | #endif |
---|
641 | t->balllink = p; /* complete trajectory */ |
---|
642 | p->type = Full; |
---|
643 | p->color = t->color; /* accept catch */ |
---|
644 | p->spin = t->spin; |
---|
645 | p->degree_offset = t->degree_offset; |
---|
646 | p->divisions = t->divisions; |
---|
647 | } |
---|
648 | } |
---|
649 | } |
---|
650 | } |
---|
651 | t->type = Empty; /* thrown */ |
---|
652 | } else if (t->action == CATCH) { |
---|
653 | /* search forward for next throw from this hand */ |
---|
654 | for (p = t->next; t->handlink == NULL && p != sp->head; p = p->next) { |
---|
655 | if (p->action == THROW && p->hand == t->hand) { |
---|
656 | p->type = t->type; /* pass ball */ |
---|
657 | p->color = t->color; /* pass color */ |
---|
658 | p->spin = NRAND(5) - 2; |
---|
659 | p->degree_offset = NRAND(360); |
---|
660 | p->divisions = 2 * ((LRAND() & 1) + 1); |
---|
661 | t->handlink = p; |
---|
662 | } |
---|
663 | } |
---|
664 | } |
---|
665 | t->status = LINKEDACTION; |
---|
666 | } |
---|
667 | } |
---|
668 | } |
---|
669 | |
---|
670 | /* Convert hand position symbols into actual time/space coordinates */ |
---|
671 | static void |
---|
672 | positions(jugglestruct *sp) |
---|
673 | { |
---|
674 | Trajectory *t; |
---|
675 | int now = 0; |
---|
676 | for (t = sp->head->next; t != sp->head; t = t->next) { |
---|
677 | if (t->status == PTHRATCH) { |
---|
678 | now = t->start; |
---|
679 | } else if (t->status == LINKEDACTION) { |
---|
680 | int xo = 0, yo; |
---|
681 | |
---|
682 | /* time */ |
---|
683 | if (t->action == CATCH) { |
---|
684 | if (t->type == Empty) { |
---|
685 | now += (int) THROW_NULL_INTERVAL; /* failed catch is short */ |
---|
686 | } else { |
---|
687 | now += THROW_CATCH_INTERVAL; /* successful catch */ |
---|
688 | } |
---|
689 | } else { |
---|
690 | now += (int) CATCH_THROW_INTERVAL; /* throws are very short */ |
---|
691 | } |
---|
692 | t->start = now; |
---|
693 | |
---|
694 | /* space */ |
---|
695 | yo = ARMLENGTH; |
---|
696 | switch (t->posn) { |
---|
697 | case '-': xo = SX - POSE; break; |
---|
698 | case '_': |
---|
699 | case '+': xo = SX + POSE; break; |
---|
700 | case '=': xo = - SX - POSE; yo += 2 * POSE; break; |
---|
701 | default: (void) fprintf(stderr, "unexpected posn %c\n", t->posn); break; |
---|
702 | } |
---|
703 | t->x = sp->cx + ((t->hand == LEFT) ? xo : -xo); |
---|
704 | t->y = sp->cy + yo; |
---|
705 | |
---|
706 | t->status = PTHRATCH; |
---|
707 | } |
---|
708 | } |
---|
709 | } |
---|
710 | |
---|
711 | |
---|
712 | /* Private physics functions */ |
---|
713 | |
---|
714 | static Spline |
---|
715 | makeSpline(int x0, double dx0, int t0, int x1, double dx1, int t1) |
---|
716 | { |
---|
717 | Spline s; |
---|
718 | double a, b, c, d; |
---|
719 | int x10; |
---|
720 | double t10; |
---|
721 | |
---|
722 | x10 = x1 - x0; |
---|
723 | t10 = t1 - t0; |
---|
724 | a = ((dx0 + dx1)*t10 - 2*x10) / (t10*t10*t10); |
---|
725 | b = (3*x10 - (2*dx0 + dx1)*t10) / (t10*t10); |
---|
726 | c = dx0; |
---|
727 | d = x0; |
---|
728 | s.a = a; |
---|
729 | s.b = -3*a*t0 + b; |
---|
730 | s.c = (3*a*t0 - 2*b)*t0 + c; |
---|
731 | s.d = ((-a*t0 + b)*t0 - c)*t0 +d; |
---|
732 | return s; |
---|
733 | } |
---|
734 | |
---|
735 | static double |
---|
736 | makeSplinePair(Spline *s1, Spline *s2, |
---|
737 | int x0, double dx0, int t0, |
---|
738 | int x1, int t1, |
---|
739 | int x2, double dx2, int t2) |
---|
740 | { |
---|
741 | int x10, x21; |
---|
742 | double t21, t10, t20, dx1; |
---|
743 | x10 = x1 - x0; |
---|
744 | x21 = x2 - x1; |
---|
745 | t21 = t2 - t1; |
---|
746 | t10 = t1 - t0; |
---|
747 | t20 = t2 - t0; |
---|
748 | dx1 = (3*x10*t21*t21 + 3*x21*t10*t10 + 3*dx0*t10*t21*t21 |
---|
749 | - dx2*t10*t10*t21 - 4*dx0*t10*t21*t21) / |
---|
750 | (2*t10*t21*t20); |
---|
751 | *s1 = makeSpline(x0, dx0, t0, x1, dx1, t1); |
---|
752 | *s2 = makeSpline(x1, dx1, t1, x2, dx2, t2); |
---|
753 | return dx1; |
---|
754 | } |
---|
755 | |
---|
756 | /* Turn abstract timings into physically appropriate ball trajectories. */ |
---|
757 | static Bool |
---|
758 | projectile(jugglestruct *sp) |
---|
759 | { |
---|
760 | Trajectory *t, *n; |
---|
761 | for (t = sp->head->next; t != sp->head; t = t->next) { |
---|
762 | if (t->status != PTHRATCH) { |
---|
763 | continue; |
---|
764 | } |
---|
765 | if (t->action == THROW) { |
---|
766 | if (t->balllink != NULL) { |
---|
767 | if (t->posn == '_') { /* Bounce once */ |
---|
768 | double tc, y0, yf, yc, tb, e, i; |
---|
769 | |
---|
770 | tc = t->balllink->start - t->start; |
---|
771 | |
---|
772 | yf = sp->cy + FY; |
---|
773 | y0 = t->y; |
---|
774 | yc = t->balllink->y; |
---|
775 | e = 1; /* permissible error in yc */ |
---|
776 | |
---|
777 | /* |
---|
778 | tb = time to bounce |
---|
779 | yt = height at catch time after one bounce |
---|
780 | one or three roots according to timing |
---|
781 | find one by interval bisection |
---|
782 | */ |
---|
783 | tb = tc; |
---|
784 | for(i = tc / 2; i > 0; i/=2){ |
---|
785 | double dy, dt, yt; |
---|
786 | if(tb == 0){ |
---|
787 | (void) fprintf(stderr, "div by zero!\n"); |
---|
788 | break; |
---|
789 | } |
---|
790 | dy = (yf - y0)/tb + 0.5*sp->Gr*tb; |
---|
791 | dt = tc - tb; |
---|
792 | yt = -COR*dy*dt + 0.5*sp->Gr*dt*dt + yf; |
---|
793 | if(yt > yc + e){ |
---|
794 | tb-=i; |
---|
795 | }else if(yt < yc - e){ |
---|
796 | tb+=i; |
---|
797 | }else{ |
---|
798 | break; |
---|
799 | } |
---|
800 | } |
---|
801 | |
---|
802 | { |
---|
803 | double t0, dy; |
---|
804 | |
---|
805 | t->dx = (t->balllink->x - t->x) / tc; |
---|
806 | |
---|
807 | /* ball follows parabola down */ |
---|
808 | INSERT_AFTER(n, t->prev); |
---|
809 | n->start = t->start; |
---|
810 | n->finish = (int) (t->start + tb); |
---|
811 | n->type = Ball; |
---|
812 | n->color = t->color; |
---|
813 | n->spin = t->spin; |
---|
814 | n->degree_offset = t->degree_offset; |
---|
815 | n->divisions = t->divisions; |
---|
816 | n->status = PREDICTOR; |
---|
817 | |
---|
818 | t->dy = (yf - y0)/tb - 0.5*sp->Gr*tb; |
---|
819 | t0 = n->start; |
---|
820 | /* Represent parabola as a degenerate spline - |
---|
821 | linear in x, quadratic in y */ |
---|
822 | n->xp.a = 0; |
---|
823 | n->xp.b = 0; |
---|
824 | n->xp.c = t->dx; |
---|
825 | n->xp.d = -t->dx*t0 + t->x; |
---|
826 | n->yp.a = 0; |
---|
827 | n->yp.b = sp->Gr/2; |
---|
828 | n->yp.c = -sp->Gr*t0 + t->dy; |
---|
829 | n->yp.d = sp->Gr/2*t0*t0 - t->dy*t0 + t->y; |
---|
830 | |
---|
831 | |
---|
832 | /* ball follows parabola up */ |
---|
833 | INSERT_AFTER(n, t->prev); |
---|
834 | n->start = (int) (t0 + tb); |
---|
835 | n->finish = (int) (t0 + tc); |
---|
836 | n->type = Ball; |
---|
837 | n->color = t->color; |
---|
838 | n->spin = t->spin; |
---|
839 | n->degree_offset = t->degree_offset; |
---|
840 | n->divisions = t->divisions; |
---|
841 | n->status = PREDICTOR; |
---|
842 | |
---|
843 | n->xp.a = 0; |
---|
844 | n->xp.b = 0; |
---|
845 | n->xp.c = t->dx; |
---|
846 | n->xp.d = -t->dx*t0 + t->x; |
---|
847 | |
---|
848 | dy = (yf - y0)/tb + 0.5*sp->Gr*tb; |
---|
849 | t0 = n->start; |
---|
850 | /* Represent parabola as a degenerate spline - |
---|
851 | linear in x, quadratic in y */ |
---|
852 | n->yp.a = 0; |
---|
853 | n->yp.b = sp->Gr/2; |
---|
854 | n->yp.c = -sp->Gr*t0 - COR*dy; |
---|
855 | n->yp.d = sp->Gr/2*t0*t0 + COR*dy*t0 + yf; |
---|
856 | } |
---|
857 | |
---|
858 | t->status = BPREDICTOR; |
---|
859 | |
---|
860 | } else { |
---|
861 | double t0, dt; |
---|
862 | |
---|
863 | /* ball follows parabola */ |
---|
864 | INSERT_AFTER(n, t->prev); |
---|
865 | n->start = t->start; |
---|
866 | n->finish = t->balllink->start; |
---|
867 | n->type = Ball; |
---|
868 | n->color = t->color; |
---|
869 | n->spin = t->spin; |
---|
870 | n->degree_offset = t->degree_offset; |
---|
871 | n->divisions = t->divisions; |
---|
872 | n->status = PREDICTOR; |
---|
873 | |
---|
874 | t0 = n->start; |
---|
875 | dt = t->balllink->start - t->start; |
---|
876 | t->dx = (t->balllink->x - t->x) / dt; |
---|
877 | t->dy = (t->balllink->y - t->y) / dt - sp->Gr/2 * dt; |
---|
878 | |
---|
879 | /* Represent parabola as a degenerate spline - |
---|
880 | linear in x, quadratic in y */ |
---|
881 | n->xp.a = 0; |
---|
882 | n->xp.b = 0; |
---|
883 | n->xp.c = t->dx; |
---|
884 | n->xp.d = -t->dx*t0 + t->x; |
---|
885 | n->yp.a = 0; |
---|
886 | n->yp.b = sp->Gr/2; |
---|
887 | n->yp.c = -sp->Gr*t0 + t->dy; |
---|
888 | n->yp.d = sp->Gr/2*t0*t0 - t->dy*t0 + t->y; |
---|
889 | |
---|
890 | |
---|
891 | t->status = BPREDICTOR; |
---|
892 | } |
---|
893 | } else { /* Zero Throw */ |
---|
894 | t->status = BPREDICTOR; |
---|
895 | } |
---|
896 | } |
---|
897 | } |
---|
898 | return True; |
---|
899 | } |
---|
900 | |
---|
901 | /* Turn abstract hand motions into cubic splines. */ |
---|
902 | static void |
---|
903 | hands(jugglestruct *sp) |
---|
904 | { |
---|
905 | Trajectory *t, *u, *v; |
---|
906 | for (t = sp->head->next; t != sp->head; t = t->next) { |
---|
907 | /* no throw => no velocity */ |
---|
908 | if (t->status != BPREDICTOR) { |
---|
909 | continue; |
---|
910 | } |
---|
911 | |
---|
912 | u = t->handlink; |
---|
913 | if (u == NULL) { /* no next catch */ |
---|
914 | continue; |
---|
915 | } |
---|
916 | v = u->handlink; |
---|
917 | if (v == NULL) { /* no next throw */ |
---|
918 | continue; |
---|
919 | } |
---|
920 | |
---|
921 | /* double spline takes hand from throw, thru catch, to |
---|
922 | next throw */ |
---|
923 | |
---|
924 | t->finish = u->start; |
---|
925 | t->status = PREDICTOR; |
---|
926 | |
---|
927 | u->finish = v->start; |
---|
928 | u->status = PREDICTOR; |
---|
929 | |
---|
930 | (void) makeSplinePair(&t->xp, &u->xp, |
---|
931 | t->x, t->dx, t->start, |
---|
932 | u->x, u->start, |
---|
933 | v->x, v->dx, v->start); |
---|
934 | (void) makeSplinePair(&t->yp, &u->yp, |
---|
935 | t->y, t->dy, t->start, |
---|
936 | u->y, u->start, |
---|
937 | v->y, v->dy, v->start); |
---|
938 | |
---|
939 | t->status = PREDICTOR; |
---|
940 | } |
---|
941 | } |
---|
942 | |
---|
943 | /* Given target x, y find_elbow puts hand at target if possible, |
---|
944 | * otherwise makes hand point to the target */ |
---|
945 | static void |
---|
946 | find_elbow(jugglestruct *sp, XPoint *h, XPoint *e, int x, int y, int z) |
---|
947 | { |
---|
948 | double r, h2, t; |
---|
949 | |
---|
950 | h2 = x*x + y*y + z*z; |
---|
951 | if (h2 > 4*ARMLENGTH*ARMLENGTH) { |
---|
952 | t = ARMLENGTH/sqrt(h2); |
---|
953 | e->x = (short) (t*x); |
---|
954 | e->y = (short) (t*y); |
---|
955 | h->x = 2 * e->x; |
---|
956 | h->y = 2 * e->y; |
---|
957 | } else { |
---|
958 | r = sqrt((double)(x*x + z*z)); |
---|
959 | t = sqrt(4 * ARMLENGTH * ARMLENGTH / h2 - 1); |
---|
960 | e->x = (short) (x*(1 - y*t/r)/2); |
---|
961 | e->y = (short) ((y + r*t)/2); |
---|
962 | h->x = x; |
---|
963 | h->y = y; |
---|
964 | } |
---|
965 | } |
---|
966 | |
---|
967 | /* NOTE: returned x, y adjusted for arm reach */ |
---|
968 | static void |
---|
969 | draw_arm(ModeInfo * mi, Hand side, int *x, int *y) |
---|
970 | { |
---|
971 | Display *dpy = MI_DISPLAY(mi); |
---|
972 | Window win = MI_WINDOW(mi); |
---|
973 | GC gc = MI_GC(mi); |
---|
974 | jugglestruct *sp = &juggles[MI_SCREEN(mi)]; |
---|
975 | |
---|
976 | int sig = (side == LEFT) ? 1 : -1; |
---|
977 | |
---|
978 | XSetLineAttributes(dpy, gc, |
---|
979 | ARMWIDTH, LineSolid, CapRound, JoinRound); |
---|
980 | if (sp->arm[side][0].x != *x || sp->arm[side][0].y != *y) { |
---|
981 | XPoint h, e; |
---|
982 | XSetForeground(dpy, gc, MI_BLACK_PIXEL(mi)); |
---|
983 | find_elbow(sp, &h, &e, *x - sig*SX - sp->cx, *y - SY - sp->cy, SZ); |
---|
984 | XDrawLines(dpy, win, gc, sp->arm[side], 3, CoordModeOrigin); |
---|
985 | *x = sp->arm[side][0].x = sp->cx + sig*SX + h.x; |
---|
986 | *y = sp->arm[side][0].y = sp->cy + SY + h.y; |
---|
987 | sp->arm[side][1].x = sp->cx + sig*SX + e.x; |
---|
988 | sp->arm[side][1].y = sp->cy + SY + e.y; |
---|
989 | } |
---|
990 | XSetForeground(dpy, gc, MI_WHITE_PIXEL(mi)); |
---|
991 | XDrawLines(dpy, win, gc, sp->arm[side], 3, CoordModeOrigin); |
---|
992 | XSetLineAttributes(dpy, gc, |
---|
993 | 1, LineSolid, CapNotLast, JoinRound); |
---|
994 | } |
---|
995 | |
---|
996 | static void |
---|
997 | draw_figure(ModeInfo * mi) |
---|
998 | { |
---|
999 | Display *dpy = MI_DISPLAY(mi); |
---|
1000 | Window win = MI_WINDOW(mi); |
---|
1001 | GC gc = MI_GC(mi); |
---|
1002 | jugglestruct *sp = &juggles[MI_SCREEN(mi)]; |
---|
1003 | |
---|
1004 | XSetLineAttributes(dpy, gc, |
---|
1005 | ARMWIDTH, LineSolid, CapRound, JoinRound); |
---|
1006 | XSetForeground(dpy, gc, MI_WHITE_PIXEL(mi)); |
---|
1007 | XDrawLines(dpy, win, gc, sp->figure_path, FIGURE1, CoordModeOrigin); |
---|
1008 | XDrawSegments(dpy, win, gc, sp->figure_segs, FIGURE2); |
---|
1009 | XDrawArc(dpy, win, gc, |
---|
1010 | sp->cx - HED/2, sp->cy + NEY - HED, HED, HED, 0, 64*360); |
---|
1011 | XSetLineAttributes(dpy, gc, |
---|
1012 | 1, LineSolid, CapNotLast, JoinRound); |
---|
1013 | } |
---|
1014 | |
---|
1015 | |
---|
1016 | /* dumps a human-readable rendition of the current state of the juggle |
---|
1017 | pipeline to stderr for debugging */ |
---|
1018 | #ifdef OLDDEBUG |
---|
1019 | static void |
---|
1020 | dump(jugglestruct *sp) |
---|
1021 | { |
---|
1022 | Trajectory *t; |
---|
1023 | |
---|
1024 | for (t = sp->head->next; t != sp->head; t = t->next) { |
---|
1025 | switch (t->status) { |
---|
1026 | case THROW: |
---|
1027 | (void) fprintf(stderr, "T %c%d\n", t->posn, t->height); |
---|
1028 | break; |
---|
1029 | case ACTION: |
---|
1030 | (void) fprintf(stderr, t->action == CATCH?"A %c%c%c\n":"A %c%c%c%d\n", |
---|
1031 | t->posn, |
---|
1032 | t->hand ? 'R' : 'L', |
---|
1033 | (t->action == THROW)?'T':(t->action == CATCH?'C':'N'), |
---|
1034 | t->height); |
---|
1035 | break; |
---|
1036 | case LINKEDACTION: |
---|
1037 | (void) fprintf(stderr, "L %c%c%c%d %d\n", |
---|
1038 | t->posn, |
---|
1039 | t->hand?'R':'L', |
---|
1040 | (t->action == THROW)?'T':(t->action == CATCH?'C':'N'), |
---|
1041 | t->height, t->color); |
---|
1042 | break; |
---|
1043 | case PTHRATCH: |
---|
1044 | (void) fprintf(stderr, "O %c%c%c%d %d %2d %6d %6d\n", t->posn, |
---|
1045 | t->hand?'R':'L', |
---|
1046 | (t->action == THROW)?'T':(t->action == CATCH?'C':'N'), |
---|
1047 | t->height, t->type, t->color, |
---|
1048 | t->start, t->finish); |
---|
1049 | break; |
---|
1050 | case PREDICTOR: |
---|
1051 | (void) fprintf(stderr, "P %c %2d %6d %6d %g\n", |
---|
1052 | t->type == Ball?'b':t->type == Empty?'e':'f', |
---|
1053 | t->color, |
---|
1054 | t->start, t->finish, t->yp.c); |
---|
1055 | break; |
---|
1056 | default: |
---|
1057 | (void) fprintf(stderr, "status %d not implemented\n", t->status); |
---|
1058 | break; |
---|
1059 | } |
---|
1060 | } |
---|
1061 | } |
---|
1062 | #endif |
---|
1063 | |
---|
1064 | static int get_num_balls(const char *j) |
---|
1065 | { |
---|
1066 | int balls = 0; |
---|
1067 | const char *p; |
---|
1068 | int h = 0; |
---|
1069 | for (p = j; *p; p++) { |
---|
1070 | if (*p >= '0' && *p <='9') { /* digit */ |
---|
1071 | h = 10*h + (*p - '0'); |
---|
1072 | } else { |
---|
1073 | if (h > balls) { |
---|
1074 | balls = h; |
---|
1075 | } |
---|
1076 | h = 0; |
---|
1077 | } |
---|
1078 | } |
---|
1079 | return balls; |
---|
1080 | } |
---|
1081 | |
---|
1082 | #ifdef __cplusplus |
---|
1083 | extern "C" { |
---|
1084 | #endif |
---|
1085 | |
---|
1086 | static int compare_num_balls(const void *p1, const void *p2) |
---|
1087 | { |
---|
1088 | int i = get_num_balls(((patternstruct*)p1)->pattern); |
---|
1089 | int j = get_num_balls(((patternstruct*)p2)->pattern); |
---|
1090 | if (i > j) { |
---|
1091 | return (1); |
---|
1092 | } else if (i < j) { |
---|
1093 | return (-1); |
---|
1094 | } else { |
---|
1095 | return (0); |
---|
1096 | } |
---|
1097 | } |
---|
1098 | |
---|
1099 | #ifdef __cplusplus |
---|
1100 | } |
---|
1101 | #endif |
---|
1102 | |
---|
1103 | /* Public functions */ |
---|
1104 | |
---|
1105 | void |
---|
1106 | release_juggle(ModeInfo * mi) |
---|
1107 | { |
---|
1108 | if (juggles != NULL) { |
---|
1109 | int screen; |
---|
1110 | |
---|
1111 | for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) |
---|
1112 | free_juggle(&juggles[screen]); |
---|
1113 | (void) free((void *) juggles); |
---|
1114 | juggles = (jugglestruct *) NULL; |
---|
1115 | } |
---|
1116 | if (patternindex != NULL) { |
---|
1117 | (void) free((void *) patternindex); |
---|
1118 | patternindex = (PatternIndex *) NULL; |
---|
1119 | } |
---|
1120 | } |
---|
1121 | |
---|
1122 | void |
---|
1123 | init_juggle(ModeInfo * mi) |
---|
1124 | { |
---|
1125 | jugglestruct *sp; |
---|
1126 | int i; |
---|
1127 | XPoint figure1[FIGURE1]; |
---|
1128 | XSegment figure2[FIGURE2]; |
---|
1129 | if (pattern != NULL && *pattern == '.') { |
---|
1130 | pattern = NULL; |
---|
1131 | } |
---|
1132 | if (pattern == NULL && patternindex == NULL) { |
---|
1133 | /* pattern list needs indexing */ |
---|
1134 | int nelements = sizeof(portfolio)/sizeof(patternstruct); |
---|
1135 | int maxballs; |
---|
1136 | int numpat = 0; |
---|
1137 | |
---|
1138 | /* sort according to number of balls */ |
---|
1139 | qsort((void*)portfolio, nelements, |
---|
1140 | sizeof(patternstruct), compare_num_balls); |
---|
1141 | |
---|
1142 | /* last pattern has most balls */ |
---|
1143 | maxballs = get_num_balls(portfolio[nelements - 1].pattern); |
---|
1144 | /* allocate index */ |
---|
1145 | if ((patternindex = (PatternIndex *) calloc(maxballs + 1, |
---|
1146 | sizeof (PatternIndex))) == NULL) { |
---|
1147 | return; |
---|
1148 | } |
---|
1149 | |
---|
1150 | /* run through sorted list, indexing start of each group |
---|
1151 | and number in group */ |
---|
1152 | maxballs = 1; |
---|
1153 | for (i = 0; i < nelements; i++) { |
---|
1154 | int b = get_num_balls(portfolio[i].pattern); |
---|
1155 | if (b > maxballs) { |
---|
1156 | if (MI_IS_VERBOSE(mi)) { |
---|
1157 | (void) fprintf(stderr, "%d %d ball pattern%s\n", |
---|
1158 | numpat, maxballs, (numpat == 1) ? "" : "s"); |
---|
1159 | } |
---|
1160 | patternindex[maxballs].number = numpat; |
---|
1161 | maxballs = b; |
---|
1162 | numpat = 1; |
---|
1163 | patternindex[maxballs].start = i; |
---|
1164 | } else { |
---|
1165 | numpat++; |
---|
1166 | } |
---|
1167 | } |
---|
1168 | if (MI_IS_VERBOSE(mi)) { |
---|
1169 | (void) fprintf(stderr, "%d %d ball pattern%s\n", |
---|
1170 | numpat, maxballs, (numpat == 1) ? "" : "s"); |
---|
1171 | } |
---|
1172 | patternindex[maxballs].number = numpat; |
---|
1173 | } |
---|
1174 | |
---|
1175 | if (juggles == NULL) { /* allocate jugglestruct */ |
---|
1176 | if ((juggles = (jugglestruct *) calloc(MI_NUM_SCREENS(mi), |
---|
1177 | sizeof (jugglestruct))) == NULL) { |
---|
1178 | release_juggle(mi); |
---|
1179 | return; |
---|
1180 | } |
---|
1181 | } |
---|
1182 | sp = &juggles[MI_SCREEN(mi)]; |
---|
1183 | |
---|
1184 | sp->count = 0; |
---|
1185 | |
---|
1186 | if (MI_IS_FULLRANDOM(mi)) { |
---|
1187 | sp->solid = (Bool) (LRAND() & 1); |
---|
1188 | #ifdef UNI |
---|
1189 | sp->uni = (Bool) (LRAND() & 1); |
---|
1190 | #endif |
---|
1191 | } else { |
---|
1192 | sp->solid = solid; |
---|
1193 | #ifdef UNI |
---|
1194 | sp->uni = uni; |
---|
1195 | #endif |
---|
1196 | } |
---|
1197 | |
---|
1198 | sp->width = MI_WIDTH(mi); |
---|
1199 | sp->height = MI_HEIGHT(mi); |
---|
1200 | sp->count = ABS(MI_COUNT(mi)); |
---|
1201 | if (sp->count == 0) |
---|
1202 | sp->count = 150; |
---|
1203 | sp->scale = sp->height / 480.0; |
---|
1204 | /* vary x a little so the juggler does not burn the screen */ |
---|
1205 | sp->cx = sp->width / 2 + RFX + NRAND(LFX - RFX + 1); |
---|
1206 | sp->cy = sp->height - FY - ((int) sp->uni) * FY / 3; /* raise higher */ |
---|
1207 | /* "7" hits top of screen */ |
---|
1208 | sp->Gr = GRAVITY(sp->cy, 7 * THROW_CATCH_INTERVAL); |
---|
1209 | |
---|
1210 | figure1[0].x = LHIPX, figure1[0].y = HIPY; |
---|
1211 | figure1[1].x = 0, figure1[1].y = WSTY; |
---|
1212 | figure1[2].x = SX, figure1[2].y = SY; |
---|
1213 | figure1[3].x = -SX, figure1[3].y = SY; |
---|
1214 | figure1[4].x = 0, figure1[4].y = WSTY; |
---|
1215 | figure1[5].x = RHIPX, figure1[5].y = HIPY; |
---|
1216 | figure1[6].x = LHIPX, figure1[6].y = HIPY; |
---|
1217 | figure2[0].x1 = 0, figure2[0].y1 = SY, |
---|
1218 | figure2[0].x2 = 0, figure2[0].y2 = NEY; |
---|
1219 | figure2[1].x1 = LHIPX, figure2[1].y1 = HIPY, |
---|
1220 | figure2[1].x2 = LFX, figure2[1].y2 = FY; |
---|
1221 | figure2[2].x1 = RHIPX, figure2[2].y1 = HIPY, |
---|
1222 | figure2[2].x2 = RFX, figure2[2].y2 = FY; |
---|
1223 | |
---|
1224 | /* Body Path */ |
---|
1225 | for (i = 0; i < FIGURE1; i++) { |
---|
1226 | sp->figure_path[i].x = figure1[i].x + sp->cx; |
---|
1227 | sp->figure_path[i].y = figure1[i].y + sp->cy; |
---|
1228 | } |
---|
1229 | /* Body Segments */ |
---|
1230 | for (i = 0; i < FIGURE2; i++) { |
---|
1231 | sp->figure_segs[i].x1 = figure2[i].x1 + sp->cx; |
---|
1232 | sp->figure_segs[i].y1 = figure2[i].y1 + sp->cy; |
---|
1233 | sp->figure_segs[i].x2 = figure2[i].x2 + sp->cx; |
---|
1234 | sp->figure_segs[i].y2 = figure2[i].y2 + sp->cy; |
---|
1235 | } |
---|
1236 | /* Shoulders */ |
---|
1237 | sp->arm[LEFT][2].x = sp->cx + SX; |
---|
1238 | sp->arm[LEFT][2].y = sp->cy + SY; |
---|
1239 | sp->arm[RIGHT][2].x = sp->cx - SX; |
---|
1240 | sp->arm[RIGHT][2].y = sp->cy + SY; |
---|
1241 | |
---|
1242 | if (sp->trace == NULL) { |
---|
1243 | if ((sp->trace = (XPoint *)calloc(trail, sizeof(XPoint))) == NULL) { |
---|
1244 | free_juggle(sp); |
---|
1245 | return; |
---|
1246 | } |
---|
1247 | } |
---|
1248 | |
---|
1249 | /* Clear the background. */ |
---|
1250 | MI_CLEARWINDOW(mi); |
---|
1251 | |
---|
1252 | draw_figure(mi); |
---|
1253 | |
---|
1254 | /* record start time */ |
---|
1255 | sp->begintime = time(NULL); |
---|
1256 | |
---|
1257 | free_pattern(sp); |
---|
1258 | |
---|
1259 | /* create circular list */ |
---|
1260 | INSERT_AFTER_TOP(sp->head, sp->head); |
---|
1261 | |
---|
1262 | /* generate pattern */ |
---|
1263 | if (pattern == NULL) { |
---|
1264 | |
---|
1265 | #define MAXPAT 10 |
---|
1266 | #define MAXREPEAT 30 |
---|
1267 | #define CHANGE_BIAS 8 /* larger makes num_ball changes less likely */ |
---|
1268 | #define POSITION_BIAS 20 /* larger makes hand movements less likely */ |
---|
1269 | |
---|
1270 | int count = 0; |
---|
1271 | int num_balls = MINBALLS + NRAND(MAXBALLS - MINBALLS); |
---|
1272 | while (count < MI_CYCLES(mi)) { |
---|
1273 | char buf[MAXPAT * 3 + 3], *b = buf; |
---|
1274 | int maxseen = 0; |
---|
1275 | int l = NRAND(MAXPAT) + 1; |
---|
1276 | int t = NRAND(MAXREPEAT) + 1; |
---|
1277 | |
---|
1278 | { /* vary number of balls */ |
---|
1279 | int new_balls = num_balls; |
---|
1280 | int change; |
---|
1281 | |
---|
1282 | if (new_balls == 2) /* Do not juggle 2 that often */ |
---|
1283 | change = NRAND(2 + CHANGE_BIAS / 4); |
---|
1284 | else |
---|
1285 | change = NRAND(2 + CHANGE_BIAS); |
---|
1286 | switch (change) { |
---|
1287 | case 0: |
---|
1288 | new_balls++; |
---|
1289 | break; |
---|
1290 | case 1: |
---|
1291 | new_balls--; |
---|
1292 | break; |
---|
1293 | default: |
---|
1294 | break; /* NO-OP */ |
---|
1295 | } |
---|
1296 | if (new_balls < MINBALLS) { |
---|
1297 | new_balls += 2; |
---|
1298 | } |
---|
1299 | if (new_balls > MAXBALLS) { |
---|
1300 | new_balls -= 2; |
---|
1301 | } |
---|
1302 | if (new_balls < num_balls) { |
---|
1303 | if (!program(mi, "[*]", 1)) /* lose ball */ |
---|
1304 | return; |
---|
1305 | } |
---|
1306 | num_balls = new_balls; |
---|
1307 | } |
---|
1308 | count++; |
---|
1309 | |
---|
1310 | if (NRAND(2) && patternindex[num_balls].number) { |
---|
1311 | /* Pick from PortFolio */ |
---|
1312 | if (!program(mi, |
---|
1313 | portfolio[patternindex[num_balls].start + |
---|
1314 | NRAND(patternindex[num_balls].number)].pattern, |
---|
1315 | t)) |
---|
1316 | return; |
---|
1317 | } else { |
---|
1318 | /* Invent a new pattern */ |
---|
1319 | *b++='['; |
---|
1320 | for(i = 0; i < l; i++){ |
---|
1321 | int n, m; |
---|
1322 | do { /* Triangular Distribution => high values more likely */ |
---|
1323 | m = NRAND(num_balls + 1); |
---|
1324 | n = NRAND(num_balls + 1); |
---|
1325 | } while(m >= n); |
---|
1326 | if (n == num_balls) { |
---|
1327 | maxseen = 1; |
---|
1328 | } |
---|
1329 | switch(NRAND(6 + POSITION_BIAS)){ |
---|
1330 | case 0: /* Inside throw */ |
---|
1331 | *b++ = '-'; break; |
---|
1332 | case 1: /* Outside throw */ |
---|
1333 | *b++ = '+'; break; |
---|
1334 | case 2: /* Cross throw */ |
---|
1335 | *b++ = '='; break; |
---|
1336 | case 3: /* Cross catch */ |
---|
1337 | *b++ = '&'; break; |
---|
1338 | case 4: /* Cross throw and catch */ |
---|
1339 | *b++ = 'x'; break; |
---|
1340 | case 5: /* Bounce */ |
---|
1341 | *b++ = '_'; break; |
---|
1342 | default: |
---|
1343 | break; /* NO-OP */ |
---|
1344 | } |
---|
1345 | |
---|
1346 | *b++ = n + '0'; |
---|
1347 | *b++ = ' '; |
---|
1348 | } |
---|
1349 | *b++ = ']'; |
---|
1350 | *b = '\0'; |
---|
1351 | if (maxseen) { |
---|
1352 | if (!program(mi, buf, t)) |
---|
1353 | return; |
---|
1354 | } |
---|
1355 | } |
---|
1356 | } |
---|
1357 | } else { /* pattern supplied in height or 'a' notation */ |
---|
1358 | if (!program(mi, pattern, MI_CYCLES(mi))) |
---|
1359 | return; |
---|
1360 | } |
---|
1361 | |
---|
1362 | adam(sp); |
---|
1363 | |
---|
1364 | if (!part(sp)) |
---|
1365 | return; |
---|
1366 | |
---|
1367 | lob(mi); |
---|
1368 | |
---|
1369 | positions(sp); |
---|
1370 | |
---|
1371 | if (!projectile(sp)) |
---|
1372 | return; |
---|
1373 | |
---|
1374 | hands(sp); |
---|
1375 | |
---|
1376 | #ifdef OLDDEBUG |
---|
1377 | dump(sp); |
---|
1378 | #endif |
---|
1379 | } |
---|
1380 | |
---|
1381 | #define CUBIC(s, t) ((((s).a * (t) + (s).b) * (t) + (s).c) * (t) + (s).d) |
---|
1382 | |
---|
1383 | #ifdef SUNOS4 |
---|
1384 | /*- |
---|
1385 | * Workaround SunOS 4 framebuffer bug which causes balls to leave dust |
---|
1386 | * trace behind when erased |
---|
1387 | */ |
---|
1388 | #define ERASE_BALL(x,y) \ |
---|
1389 | XSetForeground(dpy, gc, MI_BLACK_PIXEL(mi)); \ |
---|
1390 | XFillArc(dpy, window, gc, \ |
---|
1391 | (x) - BALLRADIUS - 2, (y) - BALLRADIUS - 2, \ |
---|
1392 | 2*(BALLRADIUS + 2), 2*(BALLRADIUS + 2), 0, 23040) |
---|
1393 | #else |
---|
1394 | |
---|
1395 | #define ERASE_BALL(x,y) \ |
---|
1396 | XSetForeground(dpy, gc, MI_BLACK_PIXEL(mi)); \ |
---|
1397 | XFillArc(dpy, window, gc, \ |
---|
1398 | (x) - BALLRADIUS, (y) - BALLRADIUS, \ |
---|
1399 | 2*BALLRADIUS, 2*BALLRADIUS, 0, 23040) |
---|
1400 | #endif |
---|
1401 | |
---|
1402 | static void |
---|
1403 | draw_juggle_ball(ModeInfo *mi, unsigned long color, int x, int y, double degree_offset, int divisions) |
---|
1404 | { |
---|
1405 | Display *dpy = MI_DISPLAY(mi); |
---|
1406 | Window window = MI_WINDOW(mi); |
---|
1407 | GC gc = MI_GC(mi); |
---|
1408 | jugglestruct *sp = &juggles[MI_SCREEN(mi)]; |
---|
1409 | int offset; |
---|
1410 | |
---|
1411 | XSetForeground(dpy, gc, color); |
---|
1412 | if ((color == MI_WHITE_PIXEL(mi)) || |
---|
1413 | ((divisions != 2) && (divisions != 4)) || sp->solid) { |
---|
1414 | XFillArc(dpy, window, gc, |
---|
1415 | x - BALLRADIUS, y - BALLRADIUS, |
---|
1416 | 2*BALLRADIUS, 2*BALLRADIUS, |
---|
1417 | 0, 23040); |
---|
1418 | return; |
---|
1419 | } |
---|
1420 | offset = (int) (degree_offset * 64); |
---|
1421 | if (divisions == 4) { /* 90 degree divisions */ |
---|
1422 | XFillArc(dpy, window, gc, |
---|
1423 | x - BALLRADIUS, y - BALLRADIUS, |
---|
1424 | 2*BALLRADIUS, 2*BALLRADIUS, |
---|
1425 | offset, 5760); |
---|
1426 | XFillArc(dpy, window, gc, |
---|
1427 | x - BALLRADIUS, y - BALLRADIUS, |
---|
1428 | 2*BALLRADIUS, 2*BALLRADIUS, |
---|
1429 | (offset + 11520) % 23040, 5760); |
---|
1430 | XSetForeground(dpy, gc, MI_WHITE_PIXEL(mi)); |
---|
1431 | XFillArc(dpy, window, gc, |
---|
1432 | x - BALLRADIUS, y - BALLRADIUS, |
---|
1433 | 2*BALLRADIUS, 2*BALLRADIUS, |
---|
1434 | (offset + 5760) % 23040, 5760); |
---|
1435 | XFillArc(dpy, window, gc, |
---|
1436 | x - BALLRADIUS, y - BALLRADIUS, |
---|
1437 | 2*BALLRADIUS, 2*BALLRADIUS, |
---|
1438 | (offset + 17280) % 23040, 5760); |
---|
1439 | } else { /* 180 degree divisions */ |
---|
1440 | XFillArc(dpy, window, gc, |
---|
1441 | x - BALLRADIUS, y - BALLRADIUS, |
---|
1442 | 2*BALLRADIUS, 2*BALLRADIUS, |
---|
1443 | offset, 11520); |
---|
1444 | XSetForeground(dpy, gc, MI_WHITE_PIXEL(mi)); |
---|
1445 | XFillArc(dpy, window, gc, |
---|
1446 | x - BALLRADIUS, y - BALLRADIUS, |
---|
1447 | 2*BALLRADIUS, 2*BALLRADIUS, |
---|
1448 | (offset + 11520) % 23040, 11520); |
---|
1449 | } |
---|
1450 | XFlush(dpy); |
---|
1451 | } |
---|
1452 | |
---|
1453 | void |
---|
1454 | draw_juggle(ModeInfo * mi) |
---|
1455 | { |
---|
1456 | Display *dpy = MI_DISPLAY(mi); |
---|
1457 | Window window = MI_WINDOW(mi); |
---|
1458 | GC gc = MI_GC(mi); |
---|
1459 | Trajectory *traj; |
---|
1460 | int future = 0; |
---|
1461 | int length = 0; |
---|
1462 | jugglestruct *sp; |
---|
1463 | |
---|
1464 | if (juggles == NULL) |
---|
1465 | return; |
---|
1466 | sp = &juggles[MI_SCREEN(mi)]; |
---|
1467 | if (sp->trace == NULL) |
---|
1468 | return; |
---|
1469 | |
---|
1470 | MI_IS_DRAWN(mi) = True; |
---|
1471 | |
---|
1472 | draw_figure(mi); |
---|
1473 | |
---|
1474 | { |
---|
1475 | struct timeval tv; |
---|
1476 | # ifdef GETTIMEOFDAY_TWO_ARGS |
---|
1477 | struct timezone tzp; |
---|
1478 | gettimeofday(&tv, &tzp); |
---|
1479 | # else |
---|
1480 | gettimeofday(&tv); |
---|
1481 | # endif |
---|
1482 | |
---|
1483 | sp->time = (int) ((tv.tv_sec - sp->begintime)*1000 + tv.tv_usec/1000); |
---|
1484 | } |
---|
1485 | for (traj = sp->head->next; traj != sp->head; traj = traj->next) { |
---|
1486 | length++; |
---|
1487 | if (traj->status != PREDICTOR) { |
---|
1488 | continue; |
---|
1489 | } |
---|
1490 | if (traj->start > future) { |
---|
1491 | future = traj->start; |
---|
1492 | } |
---|
1493 | if (sp->time < traj->start) { /* early */ |
---|
1494 | continue; |
---|
1495 | } else if (sp->time < traj->finish) { /* working */ |
---|
1496 | int x = (int) CUBIC(traj->xp, sp->time); |
---|
1497 | int y = (int) CUBIC(traj->yp, sp->time); |
---|
1498 | unsigned long color; |
---|
1499 | |
---|
1500 | if (MI_NPIXELS(mi) > 2) { |
---|
1501 | color = MI_PIXEL(mi, traj->color); |
---|
1502 | } else { |
---|
1503 | color = MI_WHITE_PIXEL(mi); |
---|
1504 | } |
---|
1505 | if (traj->type == Empty || traj->type == Full) { |
---|
1506 | draw_arm(mi, traj->hand, &x, &y); |
---|
1507 | } |
---|
1508 | if (traj->type == Ball || traj->type == Full) { |
---|
1509 | if(trail > 0) { |
---|
1510 | ERASE_BALL(sp->trace[sp->traceindex].x, |
---|
1511 | sp->trace[sp->traceindex].y); |
---|
1512 | sp->trace[sp->traceindex].x = traj->x; |
---|
1513 | sp->trace[sp->traceindex].y = traj->y; |
---|
1514 | if (++sp->traceindex >= trail) { |
---|
1515 | sp->traceindex = 0; |
---|
1516 | } |
---|
1517 | } else { |
---|
1518 | ERASE_BALL(traj->x, traj->y); |
---|
1519 | } |
---|
1520 | draw_juggle_ball(mi, color, x, y, traj->degree_offset, traj->divisions); |
---|
1521 | traj->degree_offset = traj->degree_offset + |
---|
1522 | SPIN_DEGREES * traj->spin / sp->count; |
---|
1523 | if (traj->degree_offset < 0.0) |
---|
1524 | traj->degree_offset += 360.0; |
---|
1525 | else if (traj->degree_offset >= 360.0) |
---|
1526 | traj->degree_offset -= 360.0; |
---|
1527 | } |
---|
1528 | traj->x = x; |
---|
1529 | traj->y = y; |
---|
1530 | } else { /* expired */ |
---|
1531 | Trajectory *n = traj; |
---|
1532 | |
---|
1533 | ERASE_BALL(traj->x, traj->y); |
---|
1534 | traj=traj->prev; |
---|
1535 | REMOVE(n); |
---|
1536 | } |
---|
1537 | } |
---|
1538 | |
---|
1539 | /*** FIXME-BEGIN ***/ |
---|
1540 | /* pattern generator would refill here when necessary */ |
---|
1541 | #if 1 |
---|
1542 | if (future == 0) { |
---|
1543 | #else |
---|
1544 | if (sp->count > MI_CYCLES(mi)) { /* pick a new juggle */ |
---|
1545 | #endif |
---|
1546 | init_juggle(mi); |
---|
1547 | } |
---|
1548 | /*** FIXME-END ***/ |
---|
1549 | |
---|
1550 | } |
---|
1551 | |
---|
1552 | #endif /* MODE_juggle */ |
---|