xref: /plan9/sys/src/games/blabs/blabs.c (revision 3e5d0078acdadead679c94c0daec143041c4b41e)
1*3e5d0078SDavid du Colombier #include	<u.h>
2*3e5d0078SDavid du Colombier #include	<libc.h>
3*3e5d0078SDavid du Colombier #include	<draw.h>
4*3e5d0078SDavid du Colombier 
5*3e5d0078SDavid du Colombier #define	NPJW		48
6*3e5d0078SDavid du Colombier #define	NSPLIT		6
7*3e5d0078SDavid du Colombier #define	NDOT		14
8*3e5d0078SDavid du Colombier #define	MAXTRACKS	128
9*3e5d0078SDavid du Colombier #define	MINV		6
10*3e5d0078SDavid du Colombier #define	PDUP		1		/* useful for debugging */
11*3e5d0078SDavid du Colombier 
12*3e5d0078SDavid du Colombier #define	nels(a)		(sizeof(a) / sizeof(a[0]))
13*3e5d0078SDavid du Colombier #define	imin(a,b)	(((a) <= (b)) ? (a) : (b))
14*3e5d0078SDavid du Colombier #define	imax(a,b)	(((a) >= (b)) ? (a) : (b))
15*3e5d0078SDavid du Colombier #define	sqr(x)		((x) * (x))
16*3e5d0078SDavid du Colombier 
17*3e5d0078SDavid du Colombier typedef struct vector	vector;
18*3e5d0078SDavid du Colombier struct vector
19*3e5d0078SDavid du Colombier {
20*3e5d0078SDavid du Colombier 	double	x;
21*3e5d0078SDavid du Colombier 	double	y;
22*3e5d0078SDavid du Colombier };
23*3e5d0078SDavid du Colombier 
24*3e5d0078SDavid du Colombier typedef struct dot	Dot;
25*3e5d0078SDavid du Colombier struct dot
26*3e5d0078SDavid du Colombier {
27*3e5d0078SDavid du Colombier 	Point	pos;
28*3e5d0078SDavid du Colombier 	Point	ivel;
29*3e5d0078SDavid du Colombier 	vector	vel;
30*3e5d0078SDavid du Colombier 	double	mass;
31*3e5d0078SDavid du Colombier 	int	charge;
32*3e5d0078SDavid du Colombier 	int	height;	/* precalculated for speed */
33*3e5d0078SDavid du Colombier 	int	width;	/* precalculated for speed */
34*3e5d0078SDavid du Colombier 	int	facei;
35*3e5d0078SDavid du Colombier 	int	spin;
36*3e5d0078SDavid du Colombier 	Image	*face;
37*3e5d0078SDavid du Colombier 	Image	*faces[4];
38*3e5d0078SDavid du Colombier 	Image	*mask;
39*3e5d0078SDavid du Colombier 	Image	*masks[4];
40*3e5d0078SDavid du Colombier 	Image	*save;
41*3e5d0078SDavid du Colombier 	int	ntracks;
42*3e5d0078SDavid du Colombier 	Point	track[MAXTRACKS];
43*3e5d0078SDavid du Colombier 	int	next_clear;
44*3e5d0078SDavid du Colombier 	int	next_write;
45*3e5d0078SDavid du Colombier };
46*3e5d0078SDavid du Colombier 
47*3e5d0078SDavid du Colombier Dot	dot[NDOT];
48*3e5d0078SDavid du Colombier Dot	*edot		= &dot[NDOT];
49*3e5d0078SDavid du Colombier int	total_spin	= 3;
50*3e5d0078SDavid du Colombier vector	no_gravity;
51*3e5d0078SDavid du Colombier vector	gravity		=
52*3e5d0078SDavid du Colombier {
53*3e5d0078SDavid du Colombier 	0.0,
54*3e5d0078SDavid du Colombier 	1.0,
55*3e5d0078SDavid du Colombier };
56*3e5d0078SDavid du Colombier 
57*3e5d0078SDavid du Colombier /* static Image	*track; */
58*3e5d0078SDavid du Colombier static Image	*im;
59*3e5d0078SDavid du Colombier static int	track_length;
60*3e5d0078SDavid du Colombier static int	track_width;
61*3e5d0078SDavid du Colombier static int	iflag;
62*3e5d0078SDavid du Colombier static double	k_floor		= 0.9;
63*3e5d0078SDavid du Colombier Image *screen;
64*3e5d0078SDavid du Colombier 
65*3e5d0078SDavid du Colombier #include "andrew.bits"
66*3e5d0078SDavid du Colombier #include "bart.bits"
67*3e5d0078SDavid du Colombier #include "bwk.bits"
68*3e5d0078SDavid du Colombier #include "dmr.bits"
69*3e5d0078SDavid du Colombier #include "doug.bits"
70*3e5d0078SDavid du Colombier #include "gerard.bits"
71*3e5d0078SDavid du Colombier #include "howard.bits"
72*3e5d0078SDavid du Colombier #include "ken.bits"
73*3e5d0078SDavid du Colombier #include "philw.bits"
74*3e5d0078SDavid du Colombier #include "pjw.bits"
75*3e5d0078SDavid du Colombier #include "presotto.bits"
76*3e5d0078SDavid du Colombier #include "rob.bits"
77*3e5d0078SDavid du Colombier #include "sean.bits"
78*3e5d0078SDavid du Colombier #include "td.bits"
79*3e5d0078SDavid du Colombier 
80*3e5d0078SDavid du Colombier Image*
eallocimage(Display * d,Rectangle r,ulong chan,int repl,int col)81*3e5d0078SDavid du Colombier eallocimage(Display *d, Rectangle r, ulong chan, int repl, int col)
82*3e5d0078SDavid du Colombier {
83*3e5d0078SDavid du Colombier 	Image *i;
84*3e5d0078SDavid du Colombier 	i = allocimage(d, r, chan, repl, col);
85*3e5d0078SDavid du Colombier 	if(i == nil) {
86*3e5d0078SDavid du Colombier 		fprint(2, "cannot allocate image\n");
87*3e5d0078SDavid du Colombier 		exits("allocimage");
88*3e5d0078SDavid du Colombier 	}
89*3e5d0078SDavid du Colombier 	return i;
90*3e5d0078SDavid du Colombier }
91*3e5d0078SDavid du Colombier 
92*3e5d0078SDavid du Colombier /*
93*3e5d0078SDavid du Colombier  * p1 dot p2
94*3e5d0078SDavid du Colombier  *	inner product
95*3e5d0078SDavid du Colombier  */
96*3e5d0078SDavid du Colombier static
97*3e5d0078SDavid du Colombier double
dotprod(vector * p1,vector * p2)98*3e5d0078SDavid du Colombier dotprod(vector *p1, vector *p2)
99*3e5d0078SDavid du Colombier {
100*3e5d0078SDavid du Colombier 	return p1->x * p2->x + p1->y * p2->y;
101*3e5d0078SDavid du Colombier }
102*3e5d0078SDavid du Colombier 
103*3e5d0078SDavid du Colombier /*
104*3e5d0078SDavid du Colombier  * r = p1 + p2
105*3e5d0078SDavid du Colombier  */
106*3e5d0078SDavid du Colombier static
107*3e5d0078SDavid du Colombier void
vecaddpt(vector * r,vector * p1,vector * p2)108*3e5d0078SDavid du Colombier vecaddpt(vector *r, vector *p1, vector *p2)
109*3e5d0078SDavid du Colombier {
110*3e5d0078SDavid du Colombier 	r->x = p1->x + p2->x;
111*3e5d0078SDavid du Colombier 	r->y = p1->y + p2->y;
112*3e5d0078SDavid du Colombier }
113*3e5d0078SDavid du Colombier 
114*3e5d0078SDavid du Colombier /*
115*3e5d0078SDavid du Colombier  * r = p1 - p2
116*3e5d0078SDavid du Colombier  */
117*3e5d0078SDavid du Colombier static
118*3e5d0078SDavid du Colombier void
vecsub(vector * r,vector * p1,vector * p2)119*3e5d0078SDavid du Colombier vecsub(vector *r, vector *p1, vector *p2)
120*3e5d0078SDavid du Colombier {
121*3e5d0078SDavid du Colombier 	r->x = p1->x - p2->x;
122*3e5d0078SDavid du Colombier 	r->y = p1->y - p2->y;
123*3e5d0078SDavid du Colombier }
124*3e5d0078SDavid du Colombier 
125*3e5d0078SDavid du Colombier /*
126*3e5d0078SDavid du Colombier  * r = v * s
127*3e5d0078SDavid du Colombier  *	multiplication of a vector by a scalar
128*3e5d0078SDavid du Colombier  */
129*3e5d0078SDavid du Colombier static
130*3e5d0078SDavid du Colombier void
scalmult(vector * r,vector * v,double s)131*3e5d0078SDavid du Colombier scalmult(vector *r, vector *v, double s)
132*3e5d0078SDavid du Colombier {
133*3e5d0078SDavid du Colombier 	r->x = v->x * s;
134*3e5d0078SDavid du Colombier 	r->y = v->y * s;
135*3e5d0078SDavid du Colombier }
136*3e5d0078SDavid du Colombier 
137*3e5d0078SDavid du Colombier static
138*3e5d0078SDavid du Colombier double
separation(Dot * p,Dot * q)139*3e5d0078SDavid du Colombier separation(Dot *p, Dot *q)
140*3e5d0078SDavid du Colombier {
141*3e5d0078SDavid du Colombier 	return sqrt((double)(sqr(q->pos.x - p->pos.x) + sqr(q->pos.y - p->pos.y)));
142*3e5d0078SDavid du Colombier }
143*3e5d0078SDavid du Colombier 
144*3e5d0078SDavid du Colombier static
145*3e5d0078SDavid du Colombier int
close_enough(Dot * p,Dot * q,double * s)146*3e5d0078SDavid du Colombier close_enough(Dot *p, Dot *q, double *s)
147*3e5d0078SDavid du Colombier {
148*3e5d0078SDavid du Colombier 	int	sepx;
149*3e5d0078SDavid du Colombier 	int	width;
150*3e5d0078SDavid du Colombier 	int	sepy;
151*3e5d0078SDavid du Colombier 
152*3e5d0078SDavid du Colombier 	sepx = p->pos.x - q->pos.x;
153*3e5d0078SDavid du Colombier 	width = p->width;
154*3e5d0078SDavid du Colombier 
155*3e5d0078SDavid du Colombier 	if (sepx < -width || sepx > width)
156*3e5d0078SDavid du Colombier 		return 0;
157*3e5d0078SDavid du Colombier 
158*3e5d0078SDavid du Colombier 	sepy = p->pos.y - q->pos.y;
159*3e5d0078SDavid du Colombier 
160*3e5d0078SDavid du Colombier 	if (sepy < -width || sepy > width)
161*3e5d0078SDavid du Colombier 		return 0;
162*3e5d0078SDavid du Colombier 
163*3e5d0078SDavid du Colombier 	if ((*s = separation(p, q)) > (double)width)
164*3e5d0078SDavid du Colombier 		return 0;
165*3e5d0078SDavid du Colombier 
166*3e5d0078SDavid du Colombier 	return 1;
167*3e5d0078SDavid du Colombier }
168*3e5d0078SDavid du Colombier 
169*3e5d0078SDavid du Colombier static
170*3e5d0078SDavid du Colombier void
ptov(vector * v,Point * p)171*3e5d0078SDavid du Colombier ptov(vector *v, Point *p)
172*3e5d0078SDavid du Colombier {
173*3e5d0078SDavid du Colombier 	v->x = (double)p->x;
174*3e5d0078SDavid du Colombier 	v->y = (double)p->y;
175*3e5d0078SDavid du Colombier }
176*3e5d0078SDavid du Colombier 
177*3e5d0078SDavid du Colombier static
178*3e5d0078SDavid du Colombier void
vtop(Point * p,vector * v)179*3e5d0078SDavid du Colombier vtop(Point *p, vector *v)
180*3e5d0078SDavid du Colombier {
181*3e5d0078SDavid du Colombier 	p->x = (int)(v->x + 0.5);
182*3e5d0078SDavid du Colombier 	p->y = (int)(v->y + 0.5);
183*3e5d0078SDavid du Colombier }
184*3e5d0078SDavid du Colombier 
185*3e5d0078SDavid du Colombier static
186*3e5d0078SDavid du Colombier void
exchange_spin(Dot * p,Dot * q)187*3e5d0078SDavid du Colombier exchange_spin(Dot *p, Dot *q)
188*3e5d0078SDavid du Colombier {
189*3e5d0078SDavid du Colombier 	int	tspin;
190*3e5d0078SDavid du Colombier 
191*3e5d0078SDavid du Colombier 	if (p->spin == 0 && q->spin == 0)
192*3e5d0078SDavid du Colombier 		return;
193*3e5d0078SDavid du Colombier 
194*3e5d0078SDavid du Colombier 	tspin = p->spin + q->spin;
195*3e5d0078SDavid du Colombier 
196*3e5d0078SDavid du Colombier 	p->spin = imax(nrand(imin(3, tspin + 1)), tspin + 1 - 3);
197*3e5d0078SDavid du Colombier 
198*3e5d0078SDavid du Colombier 	if (p->spin == 0)
199*3e5d0078SDavid du Colombier 	{
200*3e5d0078SDavid du Colombier 		p->face = p->faces[0];
201*3e5d0078SDavid du Colombier 		p->mask = p->masks[0];
202*3e5d0078SDavid du Colombier 	}
203*3e5d0078SDavid du Colombier 
204*3e5d0078SDavid du Colombier 	q->spin = tspin - p->spin;
205*3e5d0078SDavid du Colombier 
206*3e5d0078SDavid du Colombier 	if (q->spin == 0)
207*3e5d0078SDavid du Colombier 	{
208*3e5d0078SDavid du Colombier 		q->face = q->faces[0];
209*3e5d0078SDavid du Colombier 		q->mask = q->masks[0];
210*3e5d0078SDavid du Colombier 	}
211*3e5d0078SDavid du Colombier }
212*3e5d0078SDavid du Colombier 
213*3e5d0078SDavid du Colombier static
214*3e5d0078SDavid du Colombier void
exchange_charge(Dot * p,Dot * q)215*3e5d0078SDavid du Colombier exchange_charge(Dot *p, Dot *q)
216*3e5d0078SDavid du Colombier {
217*3e5d0078SDavid du Colombier 	if (p->charge == 0 && q->charge == 0)
218*3e5d0078SDavid du Colombier 	{
219*3e5d0078SDavid du Colombier 		switch (nrand(16))
220*3e5d0078SDavid du Colombier 		{
221*3e5d0078SDavid du Colombier 		case 0:
222*3e5d0078SDavid du Colombier 			p->charge = 1;
223*3e5d0078SDavid du Colombier 			q->charge = -1;
224*3e5d0078SDavid du Colombier 			break;
225*3e5d0078SDavid du Colombier 
226*3e5d0078SDavid du Colombier 		case 1:
227*3e5d0078SDavid du Colombier 			p->charge = -1;
228*3e5d0078SDavid du Colombier 			q->charge = 1;
229*3e5d0078SDavid du Colombier 			break;
230*3e5d0078SDavid du Colombier 		}
231*3e5d0078SDavid du Colombier 	}
232*3e5d0078SDavid du Colombier }
233*3e5d0078SDavid du Colombier 
234*3e5d0078SDavid du Colombier /*
235*3e5d0078SDavid du Colombier  * The aim is to completely determine the final
236*3e5d0078SDavid du Colombier  * velocities of the two interacting particles as
237*3e5d0078SDavid du Colombier  * a function of their initial velocities, masses
238*3e5d0078SDavid du Colombier  * and point of collision.  We start with the two
239*3e5d0078SDavid du Colombier  * quantities that we know are conserved in
240*3e5d0078SDavid du Colombier  * elastic collisions -- momentum and kinetic energy.
241*3e5d0078SDavid du Colombier  *
242*3e5d0078SDavid du Colombier  * Let the masses of the particles be m1 and m2;
243*3e5d0078SDavid du Colombier  * their initial velocities V1 and V2 (vector quantities
244*3e5d0078SDavid du Colombier  * represented by upper case variables, scalars lower
245*3e5d0078SDavid du Colombier  * case); their final velocities V1' and V2'.
246*3e5d0078SDavid du Colombier  *
247*3e5d0078SDavid du Colombier  * Conservation of momentum gives us:
248*3e5d0078SDavid du Colombier  *
249*3e5d0078SDavid du Colombier  * 	(1)	m1 * V1 + m2 * V2	= m1 * V1' + m2 * V2'
250*3e5d0078SDavid du Colombier  *
251*3e5d0078SDavid du Colombier  * and conservation of kinetic energy gives:
252*3e5d0078SDavid du Colombier  *
253*3e5d0078SDavid du Colombier  * 	(2)	1/2 * m1 * |V1| * |V1| + 1/2 * m2 * |V2| * |V2|	=
254*3e5d0078SDavid du Colombier  * 			1/2 * m1 * |V1'| * |V1'| + 1/2 * m2 * |V2'| * |V2'|
255*3e5d0078SDavid du Colombier  *
256*3e5d0078SDavid du Colombier  * Then, decomposing (1) into its 2D scalar components:
257*3e5d0078SDavid du Colombier  *
258*3e5d0078SDavid du Colombier  * 	(1a)	m1 * v1x + m2 * v2x	= m1 * v1x' + m2 * v2x'
259*3e5d0078SDavid du Colombier  * 	(1b)	m1 * v1y + m2 * v2y	= m1 * v1y' + m2 * v2y'
260*3e5d0078SDavid du Colombier  *
261*3e5d0078SDavid du Colombier  * and simplifying and expanding (2):
262*3e5d0078SDavid du Colombier  *
263*3e5d0078SDavid du Colombier  * 	(2a)	m1 * (v1x * v1x + v1y * v1y) +
264*3e5d0078SDavid du Colombier  * 		m2 * (v2x * v2x + v2y * v2y)
265*3e5d0078SDavid du Colombier  * 					=
266*3e5d0078SDavid du Colombier  * 		m1 * (v1x' * v1x' + v1y' * v1y') +
267*3e5d0078SDavid du Colombier  * 		m2 * (v2x' * v2x' + v2y' * v2y')
268*3e5d0078SDavid du Colombier  *
269*3e5d0078SDavid du Colombier  * We know m1, m2, V1 and V2 which leaves four unknowns:
270*3e5d0078SDavid du Colombier  *
271*3e5d0078SDavid du Colombier  * 	v1x', v1y', v2x' and v2y'
272*3e5d0078SDavid du Colombier  *
273*3e5d0078SDavid du Colombier  * but we have just three equations:
274*3e5d0078SDavid du Colombier  *
275*3e5d0078SDavid du Colombier  * 	(1a), (1b) and (2a)
276*3e5d0078SDavid du Colombier  *
277*3e5d0078SDavid du Colombier  * To remove this extra degree of freedom we add the assumption that
278*3e5d0078SDavid du Colombier  * the forces during the collision act instantaneously and exactly
279*3e5d0078SDavid du Colombier  * along the (displacement) vector joining the centres of the two objects.
280*3e5d0078SDavid du Colombier  *
281*3e5d0078SDavid du Colombier  * And unfortunately, I've forgotten the extra equation that this
282*3e5d0078SDavid du Colombier  * adds to the system(!), but it turns out that this extra constraint
283*3e5d0078SDavid du Colombier  * does allow us to solve the augmented system of equations.
284*3e5d0078SDavid du Colombier  * (I guess I could reverse engineer it from the code ...)
285*3e5d0078SDavid du Colombier  */
286*3e5d0078SDavid du Colombier static
287*3e5d0078SDavid du Colombier void
rebound(Dot * p,Dot * q,double s)288*3e5d0078SDavid du Colombier rebound(Dot *p, Dot *q, double s)
289*3e5d0078SDavid du Colombier {
290*3e5d0078SDavid du Colombier 	vector	pposn;
291*3e5d0078SDavid du Colombier 	vector	qposn;
292*3e5d0078SDavid du Colombier 	vector	pvel;
293*3e5d0078SDavid du Colombier 	vector	qvel;
294*3e5d0078SDavid du Colombier 	vector	newqp;	/* vector difference of the positions */
295*3e5d0078SDavid du Colombier 	vector	newqpu;	/* unit vector parallel to newqp */
296*3e5d0078SDavid du Colombier 	vector	newqv;	/*   "        "      "  "   velocities */
297*3e5d0078SDavid du Colombier 	double	projp;	/* projection of p's velocity in newqp direction */
298*3e5d0078SDavid du Colombier 	double	projq;	/*     "       " q's velocity in newqp direction */
299*3e5d0078SDavid du Colombier 	double	pmass;	/* mass of p */
300*3e5d0078SDavid du Colombier 	double	qmass;	/* mass of q */
301*3e5d0078SDavid du Colombier 	double	tmass;	/* sum of mass of p and q */
302*3e5d0078SDavid du Colombier 	double	dmass;	/* difference of mass of p and q */
303*3e5d0078SDavid du Colombier 	double	newp;
304*3e5d0078SDavid du Colombier 	double	newq;
305*3e5d0078SDavid du Colombier 
306*3e5d0078SDavid du Colombier 	if (s == 0.0)
307*3e5d0078SDavid du Colombier 		return;
308*3e5d0078SDavid du Colombier 
309*3e5d0078SDavid du Colombier 	ptov(&pposn, &p->pos);
310*3e5d0078SDavid du Colombier 	ptov(&qposn, &q->pos);
311*3e5d0078SDavid du Colombier 	pvel = p->vel;
312*3e5d0078SDavid du Colombier 	qvel = q->vel;
313*3e5d0078SDavid du Colombier 
314*3e5d0078SDavid du Colombier 	/*
315*3e5d0078SDavid du Colombier 	 * Transform so that p is stationary at (0,0,0);
316*3e5d0078SDavid du Colombier 	 */
317*3e5d0078SDavid du Colombier 	vecsub(&newqp, &qposn, &pposn);
318*3e5d0078SDavid du Colombier 	vecsub(&newqv, &qvel, &pvel);
319*3e5d0078SDavid du Colombier 
320*3e5d0078SDavid du Colombier 	scalmult(&newqpu, &newqp, -1.0 / s);
321*3e5d0078SDavid du Colombier 
322*3e5d0078SDavid du Colombier 	if (dotprod(&newqv, &newqpu) <= 0.0)
323*3e5d0078SDavid du Colombier 		return;
324*3e5d0078SDavid du Colombier 
325*3e5d0078SDavid du Colombier 	projp = dotprod(&pvel, &newqpu);
326*3e5d0078SDavid du Colombier 	projq = dotprod(&qvel, &newqpu);
327*3e5d0078SDavid du Colombier 	pmass = p->mass;
328*3e5d0078SDavid du Colombier 	qmass = q->mass;
329*3e5d0078SDavid du Colombier 	tmass = pmass + qmass;
330*3e5d0078SDavid du Colombier 	dmass = pmass - qmass;
331*3e5d0078SDavid du Colombier 	newp = (2.0 * qmass * projq + dmass * projp) / tmass;
332*3e5d0078SDavid du Colombier 	newq = (2.0 * pmass * projp - dmass * projq) / tmass;
333*3e5d0078SDavid du Colombier 	scalmult(&newqp, &newqpu, projp - newp);
334*3e5d0078SDavid du Colombier 	scalmult(&newqv, &newqpu, projq - newq);
335*3e5d0078SDavid du Colombier 	vecsub(&pvel, &pvel, &newqp);
336*3e5d0078SDavid du Colombier 	vecsub(&qvel, &qvel, &newqv);
337*3e5d0078SDavid du Colombier 
338*3e5d0078SDavid du Colombier 	p->vel = pvel;
339*3e5d0078SDavid du Colombier 	vtop(&p->ivel, &p->vel);
340*3e5d0078SDavid du Colombier 	q->vel = qvel;
341*3e5d0078SDavid du Colombier 	vtop(&q->ivel, &q->vel);
342*3e5d0078SDavid du Colombier 
343*3e5d0078SDavid du Colombier 	exchange_spin(p, q);
344*3e5d0078SDavid du Colombier 
345*3e5d0078SDavid du Colombier 	if (iflag)
346*3e5d0078SDavid du Colombier 		exchange_charge(p, q);
347*3e5d0078SDavid du Colombier }
348*3e5d0078SDavid du Colombier 
349*3e5d0078SDavid du Colombier static
350*3e5d0078SDavid du Colombier int
rrand(int lo,int hi)351*3e5d0078SDavid du Colombier rrand(int lo, int hi)
352*3e5d0078SDavid du Colombier {
353*3e5d0078SDavid du Colombier 	return lo + nrand(hi + 1 - lo);
354*3e5d0078SDavid du Colombier }
355*3e5d0078SDavid du Colombier 
356*3e5d0078SDavid du Colombier static
357*3e5d0078SDavid du Colombier void
drawdot(Dot * d)358*3e5d0078SDavid du Colombier drawdot(Dot *d)
359*3e5d0078SDavid du Colombier {
360*3e5d0078SDavid du Colombier 	Rectangle r;
361*3e5d0078SDavid du Colombier 	char buf[10];
362*3e5d0078SDavid du Colombier 
363*3e5d0078SDavid du Colombier 	r = d->face->r;
364*3e5d0078SDavid du Colombier 	r = rectsubpt(r, d->face->r.min);
365*3e5d0078SDavid du Colombier 	r = rectaddpt(r, d->pos);
366*3e5d0078SDavid du Colombier 	r = rectaddpt(r, screen->r.min);
367*3e5d0078SDavid du Colombier 
368*3e5d0078SDavid du Colombier 	draw(screen, r, d->face, d->mask, d->face->r.min);
369*3e5d0078SDavid du Colombier 
370*3e5d0078SDavid du Colombier 	if(PDUP > 1) {	/* assume debugging */
371*3e5d0078SDavid du Colombier 		sprint(buf, "(%d,%d)", d->pos.x, d->pos.y);
372*3e5d0078SDavid du Colombier 		string(screen, r.min, display->black, ZP, font, buf);
373*3e5d0078SDavid du Colombier 	}
374*3e5d0078SDavid du Colombier }
375*3e5d0078SDavid du Colombier 
376*3e5d0078SDavid du Colombier static
377*3e5d0078SDavid du Colombier void
undraw(Dot * d)378*3e5d0078SDavid du Colombier undraw(Dot *d)
379*3e5d0078SDavid du Colombier {
380*3e5d0078SDavid du Colombier 	Rectangle r;
381*3e5d0078SDavid du Colombier 	r = d->face->r;
382*3e5d0078SDavid du Colombier 	r = rectsubpt(r, d->face->r.min);
383*3e5d0078SDavid du Colombier 	r = rectaddpt(r, d->pos);
384*3e5d0078SDavid du Colombier 	r = rectaddpt(r, screen->r.min);
385*3e5d0078SDavid du Colombier 
386*3e5d0078SDavid du Colombier 	draw(screen, r, display->black, d->mask, d->face->r.min);
387*3e5d0078SDavid du Colombier 
388*3e5d0078SDavid du Colombier /*
389*3e5d0078SDavid du Colombier 	if (track_width > 0)
390*3e5d0078SDavid du Colombier 	{
391*3e5d0078SDavid du Colombier 		if (d->ntracks >= track_length)
392*3e5d0078SDavid du Colombier 		{
393*3e5d0078SDavid du Colombier 			bitblt(&screen, d->track[d->next_clear], track, track->r, D ^ ~S);
394*3e5d0078SDavid du Colombier 			d->next_clear = (d->next_clear + 1) % track_length;
395*3e5d0078SDavid du Colombier 			d->ntracks--;
396*3e5d0078SDavid du Colombier 		}
397*3e5d0078SDavid du Colombier 
398*3e5d0078SDavid du Colombier 		d->track[d->next_write] = Pt(d->pos.x + d->width / 2 - track_width / 2, d->pos.y + d->height / 2 - track_width / 2);
399*3e5d0078SDavid du Colombier 		bitblt(&screen, d->track[d->next_write], track, track->r, D ^ ~S);
400*3e5d0078SDavid du Colombier 		d->next_write = (d->next_write + 1) % track_length;
401*3e5d0078SDavid du Colombier 		d->ntracks++;
402*3e5d0078SDavid du Colombier 	}
403*3e5d0078SDavid du Colombier */
404*3e5d0078SDavid du Colombier }
405*3e5d0078SDavid du Colombier 
406*3e5d0078SDavid du Colombier static void
copy(Image * a,Image * b)407*3e5d0078SDavid du Colombier copy(Image *a, Image *b)
408*3e5d0078SDavid du Colombier {
409*3e5d0078SDavid du Colombier 	if(PDUP==1 || eqrect(a->r, b->r))
410*3e5d0078SDavid du Colombier 		draw(a, a->r, b, nil, b->r.min);
411*3e5d0078SDavid du Colombier 	else {
412*3e5d0078SDavid du Colombier 		int x, y;
413*3e5d0078SDavid du Colombier 		for(x = a->r.min.x; x < a->r.max.x; x++)
414*3e5d0078SDavid du Colombier 			for(y = a->r.min.y; y < a->r.max.y; y++)
415*3e5d0078SDavid du Colombier 				draw(a, Rect(x,y,x+1,y+1), b, nil, Pt(x/PDUP,y/PDUP));
416*3e5d0078SDavid du Colombier 	}
417*3e5d0078SDavid du Colombier }
418*3e5d0078SDavid du Colombier 
419*3e5d0078SDavid du Colombier static void
transpose(Image * b)420*3e5d0078SDavid du Colombier transpose(Image *b)
421*3e5d0078SDavid du Colombier {
422*3e5d0078SDavid du Colombier 	int x, y;
423*3e5d0078SDavid du Colombier 
424*3e5d0078SDavid du Colombier 	for(x = b->r.min.x; x < b->r.max.x; x++)
425*3e5d0078SDavid du Colombier 		for(y = b->r.min.y; y < b->r.max.y; y++)
426*3e5d0078SDavid du Colombier 			draw(im, Rect(y,x,y+1,x+1), b, nil, Pt(x,y));
427*3e5d0078SDavid du Colombier 
428*3e5d0078SDavid du Colombier 	draw(b, b->r, im, nil, ZP);
429*3e5d0078SDavid du Colombier }
430*3e5d0078SDavid du Colombier 
431*3e5d0078SDavid du Colombier static void
reflect1_lr(Image * b)432*3e5d0078SDavid du Colombier reflect1_lr(Image *b)
433*3e5d0078SDavid du Colombier {
434*3e5d0078SDavid du Colombier 	int x;
435*3e5d0078SDavid du Colombier 	for(x = 0; x < PDUP*NPJW; x++)
436*3e5d0078SDavid du Colombier 		draw(im, Rect(x, 0, x, PDUP*NPJW), b, nil, Pt(b->r.max.x-x,0));
437*3e5d0078SDavid du Colombier 	draw(b, b->r, im, nil, ZP);
438*3e5d0078SDavid du Colombier }
439*3e5d0078SDavid du Colombier 
440*3e5d0078SDavid du Colombier static void
reflect1_ud(Image * b)441*3e5d0078SDavid du Colombier reflect1_ud(Image *b)
442*3e5d0078SDavid du Colombier {
443*3e5d0078SDavid du Colombier 	int y;
444*3e5d0078SDavid du Colombier 	for(y = 0; y < PDUP*NPJW; y++)
445*3e5d0078SDavid du Colombier 		draw(im, Rect(0, y, PDUP*NPJW, y), b, nil, Pt(0,b->r.max.y-y));
446*3e5d0078SDavid du Colombier 	draw(b, b->r, im, nil, ZP);
447*3e5d0078SDavid du Colombier }
448*3e5d0078SDavid du Colombier 
449*3e5d0078SDavid du Colombier static
450*3e5d0078SDavid du Colombier void
rotate_clockwise(Image * b)451*3e5d0078SDavid du Colombier rotate_clockwise(Image *b)
452*3e5d0078SDavid du Colombier {
453*3e5d0078SDavid du Colombier 	transpose(b);
454*3e5d0078SDavid du Colombier 	reflect1_lr(b);
455*3e5d0078SDavid du Colombier }
456*3e5d0078SDavid du Colombier 
457*3e5d0078SDavid du Colombier static
458*3e5d0078SDavid du Colombier void
spin(Dot * d)459*3e5d0078SDavid du Colombier spin(Dot *d)
460*3e5d0078SDavid du Colombier {
461*3e5d0078SDavid du Colombier 	int	i;
462*3e5d0078SDavid du Colombier 
463*3e5d0078SDavid du Colombier 	if (d->spin > 0)
464*3e5d0078SDavid du Colombier 	{
465*3e5d0078SDavid du Colombier 		i = (d->facei + d->spin) % nels(d->faces);
466*3e5d0078SDavid du Colombier 		d->face = d->faces[i];
467*3e5d0078SDavid du Colombier 		d->mask = d->masks[i];
468*3e5d0078SDavid du Colombier 		d->facei = i;
469*3e5d0078SDavid du Colombier 	}
470*3e5d0078SDavid du Colombier 	sleep(0);
471*3e5d0078SDavid du Colombier }
472*3e5d0078SDavid du Colombier 
473*3e5d0078SDavid du Colombier static
474*3e5d0078SDavid du Colombier void
restart(Dot * d)475*3e5d0078SDavid du Colombier restart(Dot *d)
476*3e5d0078SDavid du Colombier {
477*3e5d0078SDavid du Colombier 	static int	beam;
478*3e5d0078SDavid du Colombier 
479*3e5d0078SDavid du Colombier 	d->charge = 0;
480*3e5d0078SDavid du Colombier 
481*3e5d0078SDavid du Colombier 	d->pos.x = 0;
482*3e5d0078SDavid du Colombier 	d->vel.x = 20.0 + (double)rrand(-2, 2);
483*3e5d0078SDavid du Colombier 
484*3e5d0078SDavid du Colombier 	if (beam ^= 1)
485*3e5d0078SDavid du Colombier 	{
486*3e5d0078SDavid du Colombier 		d->pos.y = screen->r.max.y - d->height;
487*3e5d0078SDavid du Colombier 		d->vel.y = -20.0 + (double)rrand(-2, 2);
488*3e5d0078SDavid du Colombier 	}
489*3e5d0078SDavid du Colombier 	else
490*3e5d0078SDavid du Colombier 	{
491*3e5d0078SDavid du Colombier 		d->pos.y = 0;
492*3e5d0078SDavid du Colombier 		d->vel.y = 20.0 + (double)rrand(-2, 2);
493*3e5d0078SDavid du Colombier 	}
494*3e5d0078SDavid du Colombier 
495*3e5d0078SDavid du Colombier 	vtop(&d->ivel, &d->vel);
496*3e5d0078SDavid du Colombier }
497*3e5d0078SDavid du Colombier 
498*3e5d0078SDavid du Colombier static
499*3e5d0078SDavid du Colombier void
upd(Dot * d)500*3e5d0078SDavid du Colombier upd(Dot *d)
501*3e5d0078SDavid du Colombier {
502*3e5d0078SDavid du Colombier 	Dot	*dd;
503*3e5d0078SDavid du Colombier 
504*3e5d0078SDavid du Colombier 	spin(d);
505*3e5d0078SDavid du Colombier 
506*3e5d0078SDavid du Colombier 	/*
507*3e5d0078SDavid du Colombier 	 * Bounce off others?
508*3e5d0078SDavid du Colombier 	 */
509*3e5d0078SDavid du Colombier 	for (dd = d + 1; dd != edot; dd++)
510*3e5d0078SDavid du Colombier 	{
511*3e5d0078SDavid du Colombier 		double	s;
512*3e5d0078SDavid du Colombier 
513*3e5d0078SDavid du Colombier 		if (close_enough(d, dd, &s))
514*3e5d0078SDavid du Colombier 			rebound(d, dd, s);
515*3e5d0078SDavid du Colombier 	}
516*3e5d0078SDavid du Colombier 
517*3e5d0078SDavid du Colombier 	if (iflag)
518*3e5d0078SDavid du Colombier 	{
519*3e5d0078SDavid du Colombier 		/*
520*3e5d0078SDavid du Colombier 		 * Going off-screen?
521*3e5d0078SDavid du Colombier 		 */
522*3e5d0078SDavid du Colombier 		if
523*3e5d0078SDavid du Colombier 		(
524*3e5d0078SDavid du Colombier 			d->pos.x + d->width < 0
525*3e5d0078SDavid du Colombier 			||
526*3e5d0078SDavid du Colombier 			d->pos.x >= Dx(screen->r)
527*3e5d0078SDavid du Colombier 			||
528*3e5d0078SDavid du Colombier 			d->pos.y + d->height < 0
529*3e5d0078SDavid du Colombier 			||
530*3e5d0078SDavid du Colombier 			d->pos.y >= Dy(screen->r)
531*3e5d0078SDavid du Colombier 		)
532*3e5d0078SDavid du Colombier 			restart(d);
533*3e5d0078SDavid du Colombier 
534*3e5d0078SDavid du Colombier 		/*
535*3e5d0078SDavid du Colombier 		 * Charge.
536*3e5d0078SDavid du Colombier 		 */
537*3e5d0078SDavid du Colombier 		if (d->charge != 0)
538*3e5d0078SDavid du Colombier 		{
539*3e5d0078SDavid du Colombier 			/*
540*3e5d0078SDavid du Colombier 			 * TODO: This is wrong -- should
541*3e5d0078SDavid du Colombier 			 * generate closed paths.  Can't
542*3e5d0078SDavid du Colombier 			 * simulate effect of B field just
543*3e5d0078SDavid du Colombier 			 * by adding in an orthogonal
544*3e5d0078SDavid du Colombier 			 * velocity component... (sigh)
545*3e5d0078SDavid du Colombier 			 */
546*3e5d0078SDavid du Colombier 			vector	f;
547*3e5d0078SDavid du Colombier 			double	s;
548*3e5d0078SDavid du Colombier 
549*3e5d0078SDavid du Colombier 			f.x = -d->vel.y;
550*3e5d0078SDavid du Colombier 			f.y = d->vel.x;
551*3e5d0078SDavid du Colombier 
552*3e5d0078SDavid du Colombier 			if ((s = sqrt(sqr(f.x) + sqr(f.y))) != 0.0)
553*3e5d0078SDavid du Colombier 			{
554*3e5d0078SDavid du Colombier 				scalmult(&f, &f, -((double)d->charge) / s);
555*3e5d0078SDavid du Colombier 
556*3e5d0078SDavid du Colombier 				vecaddpt(&d->vel, &f, &d->vel);
557*3e5d0078SDavid du Colombier 				vtop(&d->ivel, &d->vel);
558*3e5d0078SDavid du Colombier 			}
559*3e5d0078SDavid du Colombier 		}
560*3e5d0078SDavid du Colombier 	}
561*3e5d0078SDavid du Colombier 	else
562*3e5d0078SDavid du Colombier 	{
563*3e5d0078SDavid du Colombier 		/*
564*3e5d0078SDavid du Colombier 		 * Bounce off left or right border?
565*3e5d0078SDavid du Colombier 		 */
566*3e5d0078SDavid du Colombier 		if (d->pos.x < 0)
567*3e5d0078SDavid du Colombier 		{
568*3e5d0078SDavid du Colombier 			d->vel.x = fabs(d->vel.x);
569*3e5d0078SDavid du Colombier 			vtop(&d->ivel, &d->vel);
570*3e5d0078SDavid du Colombier 		}
571*3e5d0078SDavid du Colombier 		else if (d->pos.x + d->width >= Dx(screen->r))
572*3e5d0078SDavid du Colombier 		{
573*3e5d0078SDavid du Colombier 			d->vel.x = -fabs(d->vel.x);
574*3e5d0078SDavid du Colombier 			vtop(&d->ivel, &d->vel);
575*3e5d0078SDavid du Colombier 		}
576*3e5d0078SDavid du Colombier 
577*3e5d0078SDavid du Colombier 		/*
578*3e5d0078SDavid du Colombier 		 * Bounce off top or bottom border?
579*3e5d0078SDavid du Colombier 		 * (bottom is slightly inelastic)
580*3e5d0078SDavid du Colombier 		 */
581*3e5d0078SDavid du Colombier 		if (d->pos.y < 0)
582*3e5d0078SDavid du Colombier 		{
583*3e5d0078SDavid du Colombier 			d->vel.y = fabs(d->vel.y);
584*3e5d0078SDavid du Colombier 			vtop(&d->ivel, &d->vel);
585*3e5d0078SDavid du Colombier 		}
586*3e5d0078SDavid du Colombier 		else if (d->pos.y + d->height >= Dy(screen->r))
587*3e5d0078SDavid du Colombier 		{
588*3e5d0078SDavid du Colombier 			if (gravity.y == 0.0)
589*3e5d0078SDavid du Colombier 				d->vel.y = -fabs(d->vel.y);
590*3e5d0078SDavid du Colombier 			else if (d->ivel.y >= -MINV && d->ivel.y <= MINV)
591*3e5d0078SDavid du Colombier 			{
592*3e5d0078SDavid du Colombier 				/*
593*3e5d0078SDavid du Colombier 				 * y-velocity is too small --
594*3e5d0078SDavid du Colombier 				 * give it a random kick.
595*3e5d0078SDavid du Colombier 				 */
596*3e5d0078SDavid du Colombier 				d->vel.y = (double)-rrand(30, 40);
597*3e5d0078SDavid du Colombier 				d->vel.x = (double)rrand(-10, 10);
598*3e5d0078SDavid du Colombier 			}
599*3e5d0078SDavid du Colombier 			else
600*3e5d0078SDavid du Colombier 				d->vel.y = -fabs(d->vel.y) * k_floor;
601*3e5d0078SDavid du Colombier 			vtop(&d->ivel, &d->vel);
602*3e5d0078SDavid du Colombier 		}
603*3e5d0078SDavid du Colombier 	}
604*3e5d0078SDavid du Colombier 
605*3e5d0078SDavid du Colombier 	if (gravity.x != 0.0 || gravity.y != 0.0)
606*3e5d0078SDavid du Colombier 	{
607*3e5d0078SDavid du Colombier 		vecaddpt(&d->vel, &gravity, &d->vel);
608*3e5d0078SDavid du Colombier 		vtop(&d->ivel, &d->vel);
609*3e5d0078SDavid du Colombier 	}
610*3e5d0078SDavid du Colombier 
611*3e5d0078SDavid du Colombier 	d->pos = addpt(d->pos, d->ivel);
612*3e5d0078SDavid du Colombier 
613*3e5d0078SDavid du Colombier 	drawdot(d);
614*3e5d0078SDavid du Colombier }
615*3e5d0078SDavid du Colombier 
616*3e5d0078SDavid du Colombier static
617*3e5d0078SDavid du Colombier void
setup(Dot * d,char * who,uchar * face,int n_els)618*3e5d0078SDavid du Colombier setup(Dot *d, char *who, uchar *face, int n_els)
619*3e5d0078SDavid du Colombier {
620*3e5d0078SDavid du Colombier 	int	i, j, k, n;
621*3e5d0078SDavid du Colombier 	int	repl;
622*3e5d0078SDavid du Colombier 	uchar	mask;
623*3e5d0078SDavid du Colombier 	int 	nbits, bits;
624*3e5d0078SDavid du Colombier 	uchar	tmpface[NPJW*NPJW];
625*3e5d0078SDavid du Colombier 	uchar	tmpmask[NPJW*NPJW];
626*3e5d0078SDavid du Colombier 	static	Image	*im;	/* not the global */
627*3e5d0078SDavid du Colombier 	static	Image	*imask;
628*3e5d0078SDavid du Colombier 
629*3e5d0078SDavid du Colombier 	if(im == nil)
630*3e5d0078SDavid du Colombier 	{
631*3e5d0078SDavid du Colombier 		im = eallocimage(display, Rect(0,0,NPJW,NPJW), CMAP8, 0, DNofill);
632*3e5d0078SDavid du Colombier 		imask = eallocimage(display, Rect(0,0,NPJW,NPJW), CMAP8, 0, DNofill);
633*3e5d0078SDavid du Colombier 	}
634*3e5d0078SDavid du Colombier 
635*3e5d0078SDavid du Colombier 	repl = (NPJW*NPJW)/n_els;
636*3e5d0078SDavid du Colombier 	if(repl > 8) {
637*3e5d0078SDavid du Colombier 		fprint(2, "can't happen --rsc\n");
638*3e5d0078SDavid du Colombier 		exits("repl");
639*3e5d0078SDavid du Colombier 	}
640*3e5d0078SDavid du Colombier 	nbits = 8/repl;
641*3e5d0078SDavid du Colombier 	mask = (1<<(nbits))-1;
642*3e5d0078SDavid du Colombier 
643*3e5d0078SDavid du Colombier 	if(0) print("converting %s... n_els=%d repl=%d mask=%x nbits=%d...\n",
644*3e5d0078SDavid du Colombier 		who, n_els, repl, mask, nbits);
645*3e5d0078SDavid du Colombier 	n = 0;
646*3e5d0078SDavid du Colombier 	for (i = 0; i < n_els; i++)
647*3e5d0078SDavid du Colombier 	{
648*3e5d0078SDavid du Colombier 		for(j = repl; j--; ) {
649*3e5d0078SDavid du Colombier 			bits = (face[i] >> (j*nbits)) & mask;
650*3e5d0078SDavid du Colombier 			tmpface[n] = 0;
651*3e5d0078SDavid du Colombier 			tmpmask[n] = 0;
652*3e5d0078SDavid du Colombier 			for(k = 0; k < repl; k++)
653*3e5d0078SDavid du Colombier 			{
654*3e5d0078SDavid du Colombier 				tmpface[n] |= (mask-bits) << (k*nbits);
655*3e5d0078SDavid du Colombier 				tmpmask[n] |= (bits==mask ? 0 : mask) << (k*nbits);
656*3e5d0078SDavid du Colombier 			}
657*3e5d0078SDavid du Colombier 			n++;
658*3e5d0078SDavid du Colombier 		}
659*3e5d0078SDavid du Colombier 
660*3e5d0078SDavid du Colombier 	}
661*3e5d0078SDavid du Colombier 
662*3e5d0078SDavid du Colombier 	if(n != sizeof tmpface) {
663*3e5d0078SDavid du Colombier 		fprint(2, "can't happen2 --rsc\n");
664*3e5d0078SDavid du Colombier 		exits("n!=tmpface");
665*3e5d0078SDavid du Colombier 	}
666*3e5d0078SDavid du Colombier 
667*3e5d0078SDavid du Colombier 	loadimage(im, im->r, tmpface, n);
668*3e5d0078SDavid du Colombier 	loadimage(imask, imask->r, tmpmask, n);
669*3e5d0078SDavid du Colombier 
670*3e5d0078SDavid du Colombier 	for (i = 0; i < nels(d->faces); i++)
671*3e5d0078SDavid du Colombier 	{
672*3e5d0078SDavid du Colombier 		d->faces[i] = eallocimage(display, Rect(0,0,PDUP*NPJW, PDUP*NPJW),
673*3e5d0078SDavid du Colombier 			screen->chan, 0, DNofill);
674*3e5d0078SDavid du Colombier 		d->masks[i] = eallocimage(display, Rect(0,0,PDUP*NPJW, PDUP*NPJW),
675*3e5d0078SDavid du Colombier 			GREY1, 0, DNofill);
676*3e5d0078SDavid du Colombier 
677*3e5d0078SDavid du Colombier 		switch (i) {
678*3e5d0078SDavid du Colombier 		case 0:
679*3e5d0078SDavid du Colombier 			copy(d->faces[i], im);
680*3e5d0078SDavid du Colombier 			copy(d->masks[i], imask);
681*3e5d0078SDavid du Colombier 			break;
682*3e5d0078SDavid du Colombier 
683*3e5d0078SDavid du Colombier 		case 1:
684*3e5d0078SDavid du Colombier 			copy(d->faces[i], im);
685*3e5d0078SDavid du Colombier 			copy(d->masks[i], imask);
686*3e5d0078SDavid du Colombier 			rotate_clockwise(d->faces[i]);
687*3e5d0078SDavid du Colombier 			rotate_clockwise(d->masks[i]);
688*3e5d0078SDavid du Colombier 			break;
689*3e5d0078SDavid du Colombier 
690*3e5d0078SDavid du Colombier 		default:
691*3e5d0078SDavid du Colombier 			copy(d->faces[i], d->faces[i-2]);
692*3e5d0078SDavid du Colombier 			copy(d->masks[i], d->masks[i-2]);
693*3e5d0078SDavid du Colombier 			reflect1_lr(d->faces[i]);
694*3e5d0078SDavid du Colombier 			reflect1_ud(d->faces[i]);
695*3e5d0078SDavid du Colombier 			reflect1_lr(d->masks[i]);
696*3e5d0078SDavid du Colombier 			reflect1_ud(d->masks[i]);
697*3e5d0078SDavid du Colombier 			break;
698*3e5d0078SDavid du Colombier 		}
699*3e5d0078SDavid du Colombier 	}
700*3e5d0078SDavid du Colombier 	d->face = d->faces[0];
701*3e5d0078SDavid du Colombier 	d->mask = d->masks[0];
702*3e5d0078SDavid du Colombier 
703*3e5d0078SDavid du Colombier 	d->height = Dy(im->r);
704*3e5d0078SDavid du Colombier 	d->width = Dx(im->r);
705*3e5d0078SDavid du Colombier 
706*3e5d0078SDavid du Colombier 	d->mass = 1.0;
707*3e5d0078SDavid du Colombier 
708*3e5d0078SDavid du Colombier 	d->spin = nrand(imin(3, total_spin + 1));
709*3e5d0078SDavid du Colombier 	total_spin -= d->spin;
710*3e5d0078SDavid du Colombier 
711*3e5d0078SDavid du Colombier 	d->pos.x = nrand(screen->r.max.x - d->width);
712*3e5d0078SDavid du Colombier 	d->pos.y = nrand(screen->r.max.y - d->height);
713*3e5d0078SDavid du Colombier 
714*3e5d0078SDavid du Colombier 	d->vel.x = (double)rrand(-20, 20);
715*3e5d0078SDavid du Colombier 	d->vel.y = (double)rrand(-20, 20);
716*3e5d0078SDavid du Colombier 	vtop(&d->ivel, &d->vel);
717*3e5d0078SDavid du Colombier 
718*3e5d0078SDavid du Colombier 	drawdot(d);
719*3e5d0078SDavid du Colombier }
720*3e5d0078SDavid du Colombier 
721*3e5d0078SDavid du Colombier int
msec(void)722*3e5d0078SDavid du Colombier msec(void)
723*3e5d0078SDavid du Colombier {
724*3e5d0078SDavid du Colombier 	static int fd;
725*3e5d0078SDavid du Colombier 	int n;
726*3e5d0078SDavid du Colombier 	char buf[64];
727*3e5d0078SDavid du Colombier 
728*3e5d0078SDavid du Colombier 	if(fd <= 0)
729*3e5d0078SDavid du Colombier 		fd = open("/dev/msec", OREAD);
730*3e5d0078SDavid du Colombier 	if(fd < 0)
731*3e5d0078SDavid du Colombier 		return 0;
732*3e5d0078SDavid du Colombier 	if(seek(fd, 0, 0) < 0)
733*3e5d0078SDavid du Colombier 		return 0;
734*3e5d0078SDavid du Colombier 	if((n=read(fd, buf, sizeof(buf)-1)) < 0)
735*3e5d0078SDavid du Colombier 		return 0;
736*3e5d0078SDavid du Colombier 	buf[n] = 0;
737*3e5d0078SDavid du Colombier 	return atoi(buf);
738*3e5d0078SDavid du Colombier }
739*3e5d0078SDavid du Colombier 
740*3e5d0078SDavid du Colombier /*
741*3e5d0078SDavid du Colombier  * debugging: make del pause so that we can
742*3e5d0078SDavid du Colombier  * inspect window.
743*3e5d0078SDavid du Colombier  */
744*3e5d0078SDavid du Colombier jmp_buf j;
745*3e5d0078SDavid du Colombier static void
myhandler(void * v,char * s)746*3e5d0078SDavid du Colombier myhandler(void *v, char *s)
747*3e5d0078SDavid du Colombier {
748*3e5d0078SDavid du Colombier 	if(strcmp(s, "interrupt") == 0)
749*3e5d0078SDavid du Colombier 		notejmp(v, j, -1);
750*3e5d0078SDavid du Colombier 	noted(NDFLT);
751*3e5d0078SDavid du Colombier }
752*3e5d0078SDavid du Colombier 
753*3e5d0078SDavid du Colombier void
main(int argc,char * argv[])754*3e5d0078SDavid du Colombier main(int argc, char *argv[])
755*3e5d0078SDavid du Colombier {
756*3e5d0078SDavid du Colombier 	int c;
757*3e5d0078SDavid du Colombier 	long now, then;
758*3e5d0078SDavid du Colombier 
759*3e5d0078SDavid du Colombier 	ARGBEGIN
760*3e5d0078SDavid du Colombier 	{
761*3e5d0078SDavid du Colombier 	case 'i':
762*3e5d0078SDavid du Colombier 		iflag = 1;
763*3e5d0078SDavid du Colombier 		gravity = no_gravity;
764*3e5d0078SDavid du Colombier 		track_length = 64;
765*3e5d0078SDavid du Colombier 		track_width = 2;
766*3e5d0078SDavid du Colombier 		break;
767*3e5d0078SDavid du Colombier 
768*3e5d0078SDavid du Colombier 	case 'k':
769*3e5d0078SDavid du Colombier 		k_floor = atof(ARGF());
770*3e5d0078SDavid du Colombier 		break;
771*3e5d0078SDavid du Colombier 
772*3e5d0078SDavid du Colombier 	case 'n':
773*3e5d0078SDavid du Colombier 		track_length = atoi(ARGF());
774*3e5d0078SDavid du Colombier 		break;
775*3e5d0078SDavid du Colombier 
776*3e5d0078SDavid du Colombier 	case 'w':
777*3e5d0078SDavid du Colombier 		track_width = atoi(ARGF());
778*3e5d0078SDavid du Colombier 		break;
779*3e5d0078SDavid du Colombier 
780*3e5d0078SDavid du Colombier 	case 'x':
781*3e5d0078SDavid du Colombier 		gravity.x = atof(ARGF());
782*3e5d0078SDavid du Colombier 		break;
783*3e5d0078SDavid du Colombier 
784*3e5d0078SDavid du Colombier 	case 'y':
785*3e5d0078SDavid du Colombier 		gravity.y = atof(ARGF());
786*3e5d0078SDavid du Colombier 		break;
787*3e5d0078SDavid du Colombier 
788*3e5d0078SDavid du Colombier 	default:
789*3e5d0078SDavid du Colombier 		fprint(2, "Usage: %s [-i] [-k k_floor] [-n track_length] [-w track_width] [-x gravityx] [-y gravityy]\n", argv0);
790*3e5d0078SDavid du Colombier 		exits("usage");
791*3e5d0078SDavid du Colombier 	} ARGEND
792*3e5d0078SDavid du Colombier 
793*3e5d0078SDavid du Colombier 	if (track_length > MAXTRACKS)
794*3e5d0078SDavid du Colombier 		track_length = MAXTRACKS;
795*3e5d0078SDavid du Colombier 
796*3e5d0078SDavid du Colombier 	if (track_length == 0)
797*3e5d0078SDavid du Colombier 		track_width = 0;
798*3e5d0078SDavid du Colombier 
799*3e5d0078SDavid du Colombier 	srand(time(0));
800*3e5d0078SDavid du Colombier 
801*3e5d0078SDavid du Colombier 	initdraw(0,0,0);
802*3e5d0078SDavid du Colombier 	im = eallocimage(display, Rect(0, 0, PDUP*NPJW, PDUP*NPJW), CMAP8, 0, DNofill);
803*3e5d0078SDavid du Colombier 
804*3e5d0078SDavid du Colombier 	draw(screen, screen->r, display->black, nil, ZP);
805*3e5d0078SDavid du Colombier 
806*3e5d0078SDavid du Colombier /*	track = balloc(Rect(0, 0, track_width, track_width), 0); */
807*3e5d0078SDavid du Colombier 
808*3e5d0078SDavid du Colombier 	edot = &dot[0];
809*3e5d0078SDavid du Colombier 
810*3e5d0078SDavid du Colombier 	setup(edot++, "andrew", andrewbits, nels(andrewbits));
811*3e5d0078SDavid du Colombier 	setup(edot++, "bart", bartbits, nels(bartbits));
812*3e5d0078SDavid du Colombier 	setup(edot++, "bwk", bwkbits, nels(bwkbits));
813*3e5d0078SDavid du Colombier 	setup(edot++, "dmr", dmrbits, nels(dmrbits));
814*3e5d0078SDavid du Colombier 	setup(edot++, "doug", dougbits, nels(dougbits));
815*3e5d0078SDavid du Colombier 	setup(edot++, "gerard", gerardbits, nels(gerardbits));
816*3e5d0078SDavid du Colombier 	setup(edot++, "howard", howardbits, nels(howardbits));
817*3e5d0078SDavid du Colombier 	setup(edot++, "ken", kenbits, nels(kenbits));
818*3e5d0078SDavid du Colombier 	setup(edot++, "philw", philwbits, nels(philwbits));
819*3e5d0078SDavid du Colombier 	setup(edot++, "pjw", pjwbits, nels(pjwbits));
820*3e5d0078SDavid du Colombier 	setup(edot++, "presotto", presottobits, nels(presottobits));
821*3e5d0078SDavid du Colombier 	setup(edot++, "rob", robbits, nels(robbits));
822*3e5d0078SDavid du Colombier 	setup(edot++, "sean", seanbits, nels(seanbits));
823*3e5d0078SDavid du Colombier 	setup(edot++, "td", tdbits, nels(tdbits));
824*3e5d0078SDavid du Colombier 
825*3e5d0078SDavid du Colombier 	if(PDUP > 1) {	/* assume debugging */
826*3e5d0078SDavid du Colombier 		setjmp(j);
827*3e5d0078SDavid du Colombier 		read(0, &c, 1);
828*3e5d0078SDavid du Colombier 
829*3e5d0078SDavid du Colombier 		/* make DEL pause so that we can inspect window */
830*3e5d0078SDavid du Colombier 		notify(myhandler);
831*3e5d0078SDavid du Colombier 	}
832*3e5d0078SDavid du Colombier 	SET(c);
833*3e5d0078SDavid du Colombier 	USED(c);
834*3e5d0078SDavid du Colombier 
835*3e5d0078SDavid du Colombier #define DELAY 100
836*3e5d0078SDavid du Colombier 	for (then = msec();; then = msec())
837*3e5d0078SDavid du Colombier 	{
838*3e5d0078SDavid du Colombier 		Dot	*d;
839*3e5d0078SDavid du Colombier 
840*3e5d0078SDavid du Colombier 		for (d = dot; d != edot; d++)
841*3e5d0078SDavid du Colombier 			undraw(d);
842*3e5d0078SDavid du Colombier 		for (d = dot; d != edot; d++)
843*3e5d0078SDavid du Colombier 			upd(d);
844*3e5d0078SDavid du Colombier 		draw(screen, screen->r, screen, nil, screen->r.min);
845*3e5d0078SDavid du Colombier 		flushimage(display, 1);
846*3e5d0078SDavid du Colombier 		now = msec();
847*3e5d0078SDavid du Colombier 		if(now - then < DELAY)
848*3e5d0078SDavid du Colombier 			sleep(DELAY - (now - then));
849*3e5d0078SDavid du Colombier 	}
850*3e5d0078SDavid du Colombier }
851