added games/timmy
parent
baf20a548b
commit
4821c261c4
|
@ -0,0 +1,51 @@
|
||||||
|
.TH TIMMY 1
|
||||||
|
.SH NAME
|
||||||
|
timmy \- physics sandbox
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B games/timmy
|
||||||
|
[
|
||||||
|
.B -s
|
||||||
|
.I steps-per-frame
|
||||||
|
]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.I Timmy
|
||||||
|
is a simple 2D physics sandbox.
|
||||||
|
.PP
|
||||||
|
To pick up an object click on it with the LMB.
|
||||||
|
New objects can be created by picking up their archetypes in the gray area on the bottom (the "tray").
|
||||||
|
To place an object in the working area click at the desired position with the LMB;
|
||||||
|
.I timmy
|
||||||
|
will refuse to place the object if it would collide with an existing one.
|
||||||
|
To abort the process \(em deleting the carried object \(em click anywhere with the RMB.
|
||||||
|
Picking up an object in the working area with the RMB will duplicate the object.
|
||||||
|
.PP
|
||||||
|
The following operations can be performed with the keyboard.
|
||||||
|
.IP w
|
||||||
|
Rotate carried object by 15° to the left.
|
||||||
|
.IP e
|
||||||
|
Rotate carried object by 15° to the right.
|
||||||
|
.IP space
|
||||||
|
Start or stop the simulation.
|
||||||
|
.IP del
|
||||||
|
Exit timmy.
|
||||||
|
.PP
|
||||||
|
The small circles on some objects are "hinges".
|
||||||
|
Two hinges can be connected by placing them on top of each other.
|
||||||
|
Their relative position will not change during the simulation; objects are however free to rotate around them.
|
||||||
|
To undo a hinge, pick up either of the objects.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.B -s
|
||||||
|
option adjusts the speed of the simulation; only integer values are permitted.
|
||||||
|
It does not compromise accuracy.
|
||||||
|
.SH SOURCE
|
||||||
|
.B /sys/src/games/timmy
|
||||||
|
.SH BUGS
|
||||||
|
.IR Timmy 's
|
||||||
|
physics may occasionally appear to originate from another universe.
|
||||||
|
.PP
|
||||||
|
.B -s
|
||||||
|
is a hack.
|
||||||
|
.SH HISTORY
|
||||||
|
.I Timmy
|
||||||
|
first appeared in 9front (June, 2016).
|
|
@ -0,0 +1,56 @@
|
||||||
|
typedef struct Hinge Hinge;
|
||||||
|
typedef struct ObjT ObjT;
|
||||||
|
typedef struct Obj Obj;
|
||||||
|
typedef struct Poly Poly;
|
||||||
|
typedef struct Vec Vec;
|
||||||
|
|
||||||
|
struct Vec {
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Poly {
|
||||||
|
int nvert;
|
||||||
|
Vec *vert;
|
||||||
|
double invI;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Hinge {
|
||||||
|
Vec p;
|
||||||
|
Vec p0;
|
||||||
|
Obj *o;
|
||||||
|
Hinge *onext;
|
||||||
|
Hinge *cnext, *cprev;
|
||||||
|
Hinge *anext;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjT {
|
||||||
|
int flags;
|
||||||
|
Poly *poly;
|
||||||
|
Hinge *hinge;
|
||||||
|
Image *line, *fill;
|
||||||
|
double imass;
|
||||||
|
void (*draw)(Obj *, Image *);
|
||||||
|
void (*move)(Obj *, double, double, double);
|
||||||
|
void (*init)(Obj *);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Obj {
|
||||||
|
ObjT *tab;
|
||||||
|
Vec p, v;
|
||||||
|
double θ, ω;
|
||||||
|
Rectangle bbox;
|
||||||
|
Poly *poly;
|
||||||
|
Hinge *hinge;
|
||||||
|
Obj *next, *prev;
|
||||||
|
int idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TrayH = 100,
|
||||||
|
TraySpc = 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEG 0.01745329251994330
|
||||||
|
#define Slop 0.5
|
||||||
|
|
||||||
|
#define HingeSep 4.0
|
|
@ -0,0 +1,25 @@
|
||||||
|
void *emalloc(ulong);
|
||||||
|
Image *rgb(u32int);
|
||||||
|
Poly *mkpoly(int, ...);
|
||||||
|
Poly *polydup(Poly *);
|
||||||
|
void polytrans(Poly *, Poly *, double, double, double);
|
||||||
|
void polydraw(Poly *, Image *, Image *, Image *);
|
||||||
|
void polybbox(Poly *, Rectangle *);
|
||||||
|
void polyfix(Poly *);
|
||||||
|
Obj *mkobj(ObjT *);
|
||||||
|
Obj *objdup(Obj *);
|
||||||
|
void objcat(Obj *, Obj *);
|
||||||
|
Vec vecadd(Vec, Vec);
|
||||||
|
Vec vecsub(Vec, Vec);
|
||||||
|
Vec vecmul(Vec, double);
|
||||||
|
Vec vecnorm(Vec);
|
||||||
|
double vecdist(Vec, Vec);
|
||||||
|
double vecdot(Vec, Vec);
|
||||||
|
Vec vecnormal(Vec);
|
||||||
|
int objcoll(Obj *, Obj *);
|
||||||
|
void freeobj(Obj *);
|
||||||
|
void objexcise(Obj *);
|
||||||
|
void addtray(ObjT *, ...);
|
||||||
|
void physstep(void);
|
||||||
|
int hinged(Obj *, Obj *);
|
||||||
|
void copyhinges(Obj *, Obj *);
|
|
@ -0,0 +1,14 @@
|
||||||
|
</$objtype/mkfile
|
||||||
|
|
||||||
|
BIN=/$objtype/bin/games
|
||||||
|
TARG=timmy
|
||||||
|
OFILES=\
|
||||||
|
timmy.$O\
|
||||||
|
simple.$O\
|
||||||
|
poly.$O\
|
||||||
|
util.$O\
|
||||||
|
phys.$O\
|
||||||
|
|
||||||
|
HFILES=dat.h fns.h
|
||||||
|
|
||||||
|
</sys/src/cmd/mkone
|
|
@ -0,0 +1,219 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
extern Obj runo;
|
||||||
|
#define Grav 10
|
||||||
|
#define Dt 0.01
|
||||||
|
#define Beta 0.5
|
||||||
|
int Steps = 4;
|
||||||
|
|
||||||
|
typedef struct Contact Contact;
|
||||||
|
struct Contact {
|
||||||
|
Obj *vo, *eo;
|
||||||
|
Vec v, n;
|
||||||
|
double pen;
|
||||||
|
double impn, impt;
|
||||||
|
double targun;
|
||||||
|
};
|
||||||
|
enum { CTSBLOCK = 64 };
|
||||||
|
|
||||||
|
Contact *cts;
|
||||||
|
int icts, ncts;
|
||||||
|
|
||||||
|
static void
|
||||||
|
colldect(Obj *a, Obj *b)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
Vec *x, *y, *z;
|
||||||
|
double d, m;
|
||||||
|
Poly *ap, *bp;
|
||||||
|
|
||||||
|
ap = a->poly;
|
||||||
|
bp = b->poly;
|
||||||
|
for(i = 0; i < ap->nvert; i++){
|
||||||
|
z = &ap->vert[i];
|
||||||
|
m = Inf(1);
|
||||||
|
for(j = 0; j < bp->nvert; j++){
|
||||||
|
x = &bp->vert[j];
|
||||||
|
y = x + 1;
|
||||||
|
d = -(z->x - x->x) * (y->y - x->y) + (z->y - x->y) * (y->x - x->x);
|
||||||
|
d /= vecdist(*x, *y);
|
||||||
|
if(d < -Slop) goto next;
|
||||||
|
if(d < m){
|
||||||
|
if(m < 0) goto next;
|
||||||
|
m = d;
|
||||||
|
if(icts == ncts)
|
||||||
|
cts = realloc(cts, sizeof(Contact) * (ncts += CTSBLOCK));
|
||||||
|
cts[icts] = (Contact){a, b, *z, vecnormal(vecsub(*x, *y)), d, 0, 0, 0};
|
||||||
|
}else if(d < 0) goto next;
|
||||||
|
}
|
||||||
|
icts++;
|
||||||
|
next: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
collresp(Contact *p)
|
||||||
|
{
|
||||||
|
double μs, μd;
|
||||||
|
Vec n, t, u, r0, r1, Δp;
|
||||||
|
double ut, un, α, γ, γt, γn, pt, mt, mn;
|
||||||
|
double r0n, r0t, r1n, r1t;
|
||||||
|
double mv, me, Iv, Ie;
|
||||||
|
|
||||||
|
n = p->n;
|
||||||
|
t = (Vec){n.y, -n.x};
|
||||||
|
mv = p->vo->tab->imass;
|
||||||
|
me = p->eo->tab->imass;
|
||||||
|
Iv = mv * p->vo->poly->invI;
|
||||||
|
Ie = me * p->eo->poly->invI;
|
||||||
|
r0 = vecsub(p->v, p->vo->p);
|
||||||
|
r1 = vecsub(p->v, p->eo->p);
|
||||||
|
Δp.x = -(t.x * p->impt + n.x * p->impn);
|
||||||
|
Δp.y = -(t.y * p->impt + n.y * p->impn);
|
||||||
|
p->vo->v = vecadd(p->vo->v, vecmul(Δp, mv));
|
||||||
|
p->vo->ω -= (Δp.x * r0.y - Δp.y * r0.x) * Iv;
|
||||||
|
p->eo->v = vecadd(p->eo->v, vecmul(Δp, -me));
|
||||||
|
p->eo->ω += (Δp.x * r1.y - Δp.y * r1.x) * Ie;
|
||||||
|
u.x = p->vo->v.x - p->vo->ω * r0.y - p->eo->v.x + p->eo->ω * r1.y;
|
||||||
|
u.y = p->vo->v.y + p->vo->ω * r0.x - p->eo->v.y - p->eo->ω * r1.x;
|
||||||
|
ut = vecdot(u, t);
|
||||||
|
un = vecdot(u, n);
|
||||||
|
r0t = vecdot(r0, t);
|
||||||
|
r0n = vecdot(r0, n);
|
||||||
|
r1t = vecdot(r1, t);
|
||||||
|
r1n = vecdot(r1, n);
|
||||||
|
γ = 0; /* accumulated normal impulse */
|
||||||
|
pt = 0; /* accumulated transverse impulse */
|
||||||
|
μs = 0.5;
|
||||||
|
μd = 0.3;
|
||||||
|
|
||||||
|
un += p->targun;
|
||||||
|
if(un >= 0 && p->pen <= 0){
|
||||||
|
p->impt = 0;
|
||||||
|
p->impn = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(p->pen > 0){
|
||||||
|
un -= Beta * p->pen / Dt;
|
||||||
|
if(un >= 0){
|
||||||
|
mn = mv + r0t * r0t * Iv;
|
||||||
|
mn += me + r1t * r1t * Ie;
|
||||||
|
γ = -un/mn;
|
||||||
|
un = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(un < 0){
|
||||||
|
/* calculate α, the effective coefficient of friction */
|
||||||
|
if(ut == 0){
|
||||||
|
α = r0t * r0n * Iv + r1t * r1n * Ie;
|
||||||
|
α /= mv + r0n * r0n * Iv + me + r1n * r1n * Ie;
|
||||||
|
if(α > μs) α = μd;
|
||||||
|
else if(α < -μs) α = -μd;
|
||||||
|
}else
|
||||||
|
α = ut < 0 ? μd : -μd;
|
||||||
|
|
||||||
|
mt = α * mv + (r0n * r0n * α - r0t * r0n) * Iv;
|
||||||
|
mt += α * me + (r1n * r1n * α - r1t * r1n) * Ie;
|
||||||
|
mn = mv + (r0t * r0t - r0n * r0t * α) * Iv;
|
||||||
|
mn += me + (r1t * r1t - r1n * r1t * α) * Ie;
|
||||||
|
/* determine events which would change α */
|
||||||
|
if(ut == 0) γt = Inf(1);
|
||||||
|
else{
|
||||||
|
γt = γ - ut / mt;
|
||||||
|
if(γt < γ) γt = Inf(1);
|
||||||
|
}
|
||||||
|
γn = γ - un / mn;
|
||||||
|
if(γn < γ) γn = Inf(1);
|
||||||
|
/* choose earlier one */
|
||||||
|
if(γt < γn){
|
||||||
|
ut = 0;
|
||||||
|
un += mn * (γt - γ);
|
||||||
|
pt += (γt - γ) * α;
|
||||||
|
γ = γt;
|
||||||
|
}else{
|
||||||
|
assert(γn < Inf(1));
|
||||||
|
un = 0;
|
||||||
|
ut += mt * (γn - γ);
|
||||||
|
pt += (γn - γ) * α;
|
||||||
|
γ = γn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p->impt = pt;
|
||||||
|
p->impn = γ;
|
||||||
|
Δp.x = t.x * pt + n.x * γ;
|
||||||
|
Δp.y = t.y * pt + n.y * γ;
|
||||||
|
p->vo->v = vecadd(p->vo->v, vecmul(Δp, mv));
|
||||||
|
p->vo->ω -= (Δp.x * r0.y - Δp.y * r0.x) * Iv;
|
||||||
|
p->eo->v = vecadd(p->eo->v, vecmul(Δp, -me));
|
||||||
|
p->eo->ω += (Δp.x * r1.y - Δp.y * r1.x) * Ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern Hinge *hinges;
|
||||||
|
|
||||||
|
static void
|
||||||
|
hingeresp(Hinge *h)
|
||||||
|
{
|
||||||
|
Obj *a, *b;
|
||||||
|
Vec u, Δp, r0, r1;
|
||||||
|
double ma, mb, Ia, Ib;
|
||||||
|
double mxx, mxy, myy, det;
|
||||||
|
|
||||||
|
a = h->o;
|
||||||
|
b = h->cnext->o;
|
||||||
|
ma = a->tab->imass;
|
||||||
|
mb = b->tab->imass;
|
||||||
|
Ia = ma * a->poly->invI;
|
||||||
|
Ib = mb * b->poly->invI;
|
||||||
|
r0 = vecsub(h->p, a->p);
|
||||||
|
r1 = vecsub(h->cnext->p, b->p);
|
||||||
|
u.x = a->v.x - a->ω * r0.y - b->v.x + b->ω * r1.y;
|
||||||
|
u.y = a->v.y + a->ω * r0.x - b->v.y - b->ω * r1.x;
|
||||||
|
u.x += Beta * (h->p.x - h->cnext->p.x) / Dt;
|
||||||
|
u.y += Beta * (h->p.y - h->cnext->p.y) / Dt;
|
||||||
|
mxx = ma + Ia * r0.x * r0.x + mb + Ib * r1.x * r1.x;
|
||||||
|
mxy = Ia * r0.x * r0.y + Ib * r1.x * r1.y;
|
||||||
|
myy = ma + Ia * r0.y * r0.y + mb + Ib * r1.y * r1.y;
|
||||||
|
det = mxx * myy - mxy * mxy;
|
||||||
|
Δp.x = (mxx * u.x + mxy * u.y) / det;
|
||||||
|
Δp.y = (myy * u.y + mxy * u.x) / det;
|
||||||
|
a->v = vecadd(a->v, vecmul(Δp, -ma));
|
||||||
|
a->ω += (Δp.x * r0.y - Δp.y * r0.x) * Ia;
|
||||||
|
b->v = vecadd(b->v, vecmul(Δp, mb));
|
||||||
|
b->ω -= (Δp.x * r1.y - Δp.y * r1.x) * Ib;
|
||||||
|
u.x = a->v.x - a->ω * r0.y - b->v.x + b->ω * r1.y;
|
||||||
|
u.y = a->v.y + a->ω * r0.x - b->v.y - b->ω * r1.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
physstep(void)
|
||||||
|
{
|
||||||
|
Obj *o, *a, *b;
|
||||||
|
int i, j, k;
|
||||||
|
Hinge *p;
|
||||||
|
|
||||||
|
for(k = 0; k < Steps; k++){
|
||||||
|
for(o = runo.next; o != &runo; o = o->next)
|
||||||
|
if(o->tab->imass != 0)
|
||||||
|
o->v.y += Grav * Dt;
|
||||||
|
icts = 0;
|
||||||
|
for(a = runo.next; a != &runo; a = a->next)
|
||||||
|
for(b = a->next; b != &runo; b = b->next){
|
||||||
|
if(!rectXrect(a->bbox, b->bbox) || a->poly == nil || b->poly == nil || hinged(a, b)) continue;
|
||||||
|
colldect(a, b);
|
||||||
|
colldect(b, a);
|
||||||
|
}
|
||||||
|
for(j = 0; j < 10; j++){
|
||||||
|
for(i = 0; i < icts; i++)
|
||||||
|
collresp(&cts[i]);
|
||||||
|
for(p = hinges; p != nil; p = p->anext)
|
||||||
|
hingeresp(p);
|
||||||
|
}
|
||||||
|
for(o = runo.next; o != &runo; o = o->next)
|
||||||
|
o->tab->move(o, o->p.x + o->v.x * Dt, o->p.y + o->v.y * Dt, o->θ + o->ω * Dt / DEG);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,323 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <mouse.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
Poly *
|
||||||
|
mkpoly(int n, ...)
|
||||||
|
{
|
||||||
|
Poly *p;
|
||||||
|
int i;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
p = emalloc(sizeof(Poly));
|
||||||
|
p->nvert = n;
|
||||||
|
p->vert = emalloc((n + 1) * sizeof(Vec));
|
||||||
|
va_start(va, n);
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
|
p->vert[i].x = va_arg(va, double);
|
||||||
|
p->vert[i].y = va_arg(va, double);
|
||||||
|
}
|
||||||
|
p->vert[n] = p->vert[0];
|
||||||
|
va_end(va);
|
||||||
|
polyfix(p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
polyfix(Poly *o)
|
||||||
|
{
|
||||||
|
double I, A, x, y, t;
|
||||||
|
Vec *p, *q;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
I = 0;
|
||||||
|
A = 0;
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
for(i = 0; i < o->nvert; i++){
|
||||||
|
p = &o->vert[i];
|
||||||
|
q = p + 1;
|
||||||
|
t = p->x * q->y - p->y * q->x;
|
||||||
|
A += t;
|
||||||
|
x += (p->x + q->x) * t / 3;
|
||||||
|
y += (p->y + q->y) * t / 3;
|
||||||
|
}
|
||||||
|
x /= A;
|
||||||
|
y /= A;
|
||||||
|
for(i = 0; i <= o->nvert; i++){
|
||||||
|
o->vert[i].x -= x;
|
||||||
|
o->vert[i].y -= y;
|
||||||
|
}
|
||||||
|
for(i = 0; i < o->nvert; i++){
|
||||||
|
p = &o->vert[i];
|
||||||
|
q = p + 1;
|
||||||
|
t = p->x * q->y - p->y * q->x;
|
||||||
|
I += (p->x * (p->x + q->x) + q->x * q->x + p->y * (p->y + q->y) + q->y * q->y) * t / 6;
|
||||||
|
}
|
||||||
|
o->invI = A / I;
|
||||||
|
}
|
||||||
|
|
||||||
|
Poly *
|
||||||
|
polydup(Poly *p)
|
||||||
|
{
|
||||||
|
Poly *q;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
q = emalloc(sizeof(Poly));
|
||||||
|
q->nvert = p->nvert;
|
||||||
|
q->vert = emalloc((p->nvert + 1) * sizeof(Vec));
|
||||||
|
for(i = 0; i <= p->nvert; i++)
|
||||||
|
q->vert[i] = p->vert[i];
|
||||||
|
q->invI = p->invI;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
polytrans(Poly *sp, Poly *dp, double x0, double y0, double θ)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double c, s, x, y;
|
||||||
|
|
||||||
|
assert(sp->nvert == dp->nvert);
|
||||||
|
c = cos(θ * DEG);
|
||||||
|
s = sin(θ * DEG);
|
||||||
|
for(i = 0; i <= sp->nvert; i++){
|
||||||
|
x = sp->vert[i].x;
|
||||||
|
y = sp->vert[i].y;
|
||||||
|
dp->vert[i].x = x0 + x * c - y * s;
|
||||||
|
dp->vert[i].y = y0 + x * s + y * c;
|
||||||
|
}
|
||||||
|
dp->invI = sp->invI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
polybbox(Poly *sp, Rectangle *t)
|
||||||
|
{
|
||||||
|
int fx, fy, cx, cy, i;
|
||||||
|
|
||||||
|
t->min.x = floor(sp->vert[0].x - Slop);
|
||||||
|
t->max.x = ceil(sp->vert[0].x + Slop) + 1;
|
||||||
|
t->min.y = floor(sp->vert[0].y - Slop);
|
||||||
|
t->max.y = ceil(sp->vert[0].y + Slop) + 1;
|
||||||
|
for(i = 1; i < sp->nvert; i++){
|
||||||
|
fx = sp->vert[i].x;
|
||||||
|
cx = ceil(fx + Slop); fx = floor(fx - Slop);
|
||||||
|
fy = sp->vert[i].y + 1;
|
||||||
|
cy = ceil(fy + Slop); fy = floor(fy - Slop);
|
||||||
|
if(fx < t->min.x) t->min.x = fx;
|
||||||
|
if(cx > t->max.x) t->max.x = cx;
|
||||||
|
if(fy < t->min.y) t->min.y = fy;
|
||||||
|
if(cy > t->max.y) t->max.y = cy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
polydraw(Poly *p, Image *d, Image *fill, Image *line)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static int maxp;
|
||||||
|
static Point *buf;
|
||||||
|
|
||||||
|
if(p->nvert + 1 > maxp){
|
||||||
|
maxp = p->nvert + 1;
|
||||||
|
free(buf);
|
||||||
|
buf = emalloc((p->nvert + 1) * sizeof(Point));
|
||||||
|
}
|
||||||
|
for(i = 0; i <= p->nvert; i++){
|
||||||
|
buf[i].x = d->r.min.x + (int)(p->vert[i].x + 0.5);
|
||||||
|
buf[i].y = d->r.min.y + (int)(p->vert[i].y + 0.5);
|
||||||
|
}
|
||||||
|
if(fill != nil) fillpoly(d, buf, p->nvert + 1, 0, fill, ZP);
|
||||||
|
if(line != nil) poly(d, buf, p->nvert + 1, 0, 0, 0, line, ZP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freepoly(Poly *p)
|
||||||
|
{
|
||||||
|
if(p == nil) return;
|
||||||
|
free(p->vert);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Hinge *
|
||||||
|
hingedup(Hinge *h, Obj *o)
|
||||||
|
{
|
||||||
|
Hinge *p, **hp, *r;
|
||||||
|
|
||||||
|
r = nil;
|
||||||
|
hp = &r;
|
||||||
|
for(; h != nil; h = h->onext){
|
||||||
|
p = emalloc(sizeof(Hinge));
|
||||||
|
p->p = h->p;
|
||||||
|
p->p0 = h->p0;
|
||||||
|
p->o = o;
|
||||||
|
p->cnext = p->cprev = p;
|
||||||
|
*hp = p;
|
||||||
|
hp = &p->onext;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj *
|
||||||
|
mkobj(ObjT *t)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
|
||||||
|
o = emalloc(sizeof(Obj));
|
||||||
|
o->tab = t;
|
||||||
|
o->hinge = hingedup(t->hinge, o);
|
||||||
|
o->tab->init(o);
|
||||||
|
o->next = o->prev = o;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj *
|
||||||
|
objdup(Obj *o)
|
||||||
|
{
|
||||||
|
Obj *p;
|
||||||
|
|
||||||
|
p = emalloc(sizeof(Obj));
|
||||||
|
*p = *o;
|
||||||
|
p->poly = polydup(o->poly);
|
||||||
|
p->next = p->prev = p;
|
||||||
|
p->hinge = hingedup(p->hinge, p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
objcat(Obj *l, Obj *o)
|
||||||
|
{
|
||||||
|
o->prev = l->prev;
|
||||||
|
o->next = l;
|
||||||
|
o->prev->next = o;
|
||||||
|
o->next->prev = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
polycheck(Poly *a, Poly *b)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
Vec *x, *y, *z;
|
||||||
|
double d, m;
|
||||||
|
|
||||||
|
for(i = 0; i < a->nvert; i++){
|
||||||
|
z = &a->vert[i];
|
||||||
|
m = Inf(1);
|
||||||
|
for(j = 0; j < b->nvert; j++){
|
||||||
|
x = &b->vert[j];
|
||||||
|
y = x + 1;
|
||||||
|
d = (z->y - x->y) * (y->x - x->x) - (z->x - x->x) * (y->y - x->y);
|
||||||
|
d /= vecdist(*x, *y);
|
||||||
|
if(d < -Slop) goto next;
|
||||||
|
if(d < m){
|
||||||
|
if(m < 0) goto next;
|
||||||
|
m = d;
|
||||||
|
}else if(d < 0) goto next;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
next:;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
objcoll(Obj *a, Obj *b)
|
||||||
|
{
|
||||||
|
if(!rectXrect(a->bbox, b->bbox)) return 0;
|
||||||
|
if(a->poly == nil || b->poly == nil) return 0;
|
||||||
|
return polycheck(a->poly, b->poly) || polycheck(b->poly, a->poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
objexcise(Obj *o)
|
||||||
|
{
|
||||||
|
Hinge *h;
|
||||||
|
|
||||||
|
o->next->prev = o->prev;
|
||||||
|
o->prev->next = o->next;
|
||||||
|
o->next = o;
|
||||||
|
o->prev = o;
|
||||||
|
for(h = o->hinge; h != nil; h = h->onext){
|
||||||
|
h->cprev->cnext = h->cnext;
|
||||||
|
h->cnext->cprev = h->cprev;
|
||||||
|
h->cprev = h;
|
||||||
|
h->cnext = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freeobj(Obj *o)
|
||||||
|
{
|
||||||
|
if(o == nil) return;
|
||||||
|
objexcise(o);
|
||||||
|
freepoly(o->poly);
|
||||||
|
free(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hinged(Obj *a, Obj *b)
|
||||||
|
{
|
||||||
|
Hinge *k, *l, *m;
|
||||||
|
|
||||||
|
if(b->hinge == nil) return 0;
|
||||||
|
for(k = a->hinge; k != nil; k = k->onext)
|
||||||
|
for(l = k->cnext; l != k; l = l->cnext)
|
||||||
|
for(m = b->hinge; m != nil; m = m->onext)
|
||||||
|
if(m == l)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hinge *hinges;
|
||||||
|
|
||||||
|
void
|
||||||
|
hingepairs(Obj *l)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
Hinge *h, *hh;
|
||||||
|
Hinge **p;
|
||||||
|
|
||||||
|
hinges = nil;
|
||||||
|
p = &hinges;
|
||||||
|
for(o = l->next; o != l; o = o->next)
|
||||||
|
for(h = o->hinge; h != nil; h = h->onext){
|
||||||
|
for(hh = h->cnext; hh != h; hh = hh->cnext)
|
||||||
|
if(hh < h)
|
||||||
|
break;
|
||||||
|
if(hh == h) continue;
|
||||||
|
*p = h;
|
||||||
|
p = &h->anext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copyhinges(Obj *sl, Obj *dl)
|
||||||
|
{
|
||||||
|
Obj *o, *p, **ol;
|
||||||
|
Hinge *h, *k, *l;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(n = 0, o = sl->next; o != sl; o = o->next)
|
||||||
|
o->idx = n++;
|
||||||
|
ol = emalloc(sizeof(Obj *) * n);
|
||||||
|
for(n = 0, o = dl->next; o != dl; o = o->next)
|
||||||
|
ol[n++] = o;
|
||||||
|
for(o = sl->next, p = dl->next; o != sl; o = o->next, p = p->next){
|
||||||
|
for(h = o->hinge, k = p->hinge; h != nil; h = h->onext, k = k->onext){
|
||||||
|
if(h->cnext == h) continue;
|
||||||
|
for(l = h->cnext->o->hinge, n = 0; l != h->cnext; l = l->onext)
|
||||||
|
n++;
|
||||||
|
for(l = ol[h->cnext->o->idx]->hinge; n != 0; n--)
|
||||||
|
l = l->onext;
|
||||||
|
l->cprev->cnext = k->cnext;
|
||||||
|
k->cnext->cprev = l->cprev;
|
||||||
|
k->cnext = l;
|
||||||
|
l->cprev = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hingepairs(dl);
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
objpolyinit(Obj *o)
|
||||||
|
{
|
||||||
|
o->poly = polydup(o->tab->poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
objpolymove(Obj *o, double x, double y, double θ)
|
||||||
|
{
|
||||||
|
Hinge *h;
|
||||||
|
double c, s;
|
||||||
|
|
||||||
|
o->p.x = x;
|
||||||
|
o->p.y = y;
|
||||||
|
o->θ = θ;
|
||||||
|
polytrans(o->tab->poly, o->poly, x, y, θ);
|
||||||
|
polybbox(o->poly, &o->bbox);
|
||||||
|
if(o->hinge != nil){
|
||||||
|
c = cos(θ * DEG);
|
||||||
|
s = sin(θ * DEG);
|
||||||
|
for(h = o->hinge; h != nil; h = h->onext){
|
||||||
|
h->p.x = c * h->p0.x - s * h->p0.y + x;
|
||||||
|
h->p.y = s * h->p0.x + c * h->p0.y + y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
objpolydraw(Obj *o, Image *i)
|
||||||
|
{
|
||||||
|
Hinge *h;
|
||||||
|
Point p;
|
||||||
|
|
||||||
|
polydraw(o->poly, i, o->tab->fill, o->tab->line);
|
||||||
|
for(h = o->hinge; h != nil; h = h->onext){
|
||||||
|
p.x = i->r.min.x + (int)(h->p.x + 0.5);
|
||||||
|
p.y = i->r.min.y + (int)(h->p.y + 0.5);
|
||||||
|
ellipse(i, p, 2, 2, 0, display->black, ZP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mkobjpoly(ObjT *t, Poly *p, Image *fill, Image *line, double imass)
|
||||||
|
{
|
||||||
|
t->init = objpolyinit;
|
||||||
|
t->draw = objpolydraw;
|
||||||
|
t->move = objpolymove;
|
||||||
|
t->poly = p;
|
||||||
|
t->line = line;
|
||||||
|
t->fill = fill;
|
||||||
|
t->imass = imass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
addhinge(ObjT *t, double x, double y)
|
||||||
|
{
|
||||||
|
Hinge *h, **hp;
|
||||||
|
|
||||||
|
h = emalloc(sizeof(Hinge));
|
||||||
|
h->p.x = x;
|
||||||
|
h->p.y = y;
|
||||||
|
h->p0 = h->p;
|
||||||
|
h->cnext = h->cprev = h;
|
||||||
|
for(hp = &t->hinge; *hp != nil; hp = &(*hp)->onext)
|
||||||
|
;
|
||||||
|
*hp = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
Poly *
|
||||||
|
mkball(int n)
|
||||||
|
{
|
||||||
|
Poly *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
p = emalloc(sizeof(Poly));
|
||||||
|
p->nvert = n;
|
||||||
|
p->vert = emalloc(sizeof(Vec) * (n + 1));
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
|
p->vert[i].x = 10 * cos(2 * PI * i / n);
|
||||||
|
p->vert[i].y = 10 * sin(2 * PI * i / n);
|
||||||
|
}
|
||||||
|
p->vert[n] = p->vert[0];
|
||||||
|
polyfix(p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjT tdomino, tboard, thboard, tball, tfix;
|
||||||
|
|
||||||
|
void
|
||||||
|
simpleinit(void)
|
||||||
|
{
|
||||||
|
mkobjpoly(&tdomino, mkpoly(4, 0.0, 0.0, 10.0, 0.0, 10.0, 40.0, 0.0, 40.0), rgb(0xFF0000FF), display->black, 10);
|
||||||
|
mkobjpoly(&tboard, mkpoly(4, 0.0, 0.0, 100.0, 0.0, 100.0, 6.0, 0.0, 6.0), rgb(0x663300FF), nil, 0);
|
||||||
|
mkobjpoly(&thboard, mkpoly(4, 0.0, 0.0, 100.0, 0.0, 100.0, 6.0, 0.0, 6.0), rgb(0x884400FF), nil, 0.5);
|
||||||
|
addhinge(&thboard, 48.0, 0.0);
|
||||||
|
addhinge(&thboard, -48.0, 0.0);
|
||||||
|
mkobjpoly(&tball, mkball(17), rgb(0x00FF00FF), nil, 3);
|
||||||
|
mkobjpoly(&tfix, mkpoly(3, 0.0, 0.0, 10.0, -17.3, 20.0, 0.0), rgb(0x663300FF), display->black, 0);
|
||||||
|
addhinge(&tfix, 0.0, 0.0);
|
||||||
|
addtray(&tdomino, &tboard, &thboard, &tfix, &tball, nil);
|
||||||
|
}
|
|
@ -0,0 +1,328 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <mouse.h>
|
||||||
|
#include <keyboard.h>
|
||||||
|
#include <cursor.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
Screen *scr;
|
||||||
|
Image *work, *tray;
|
||||||
|
Image *grey;
|
||||||
|
Obj trayo;
|
||||||
|
Obj worko;
|
||||||
|
Obj runo;
|
||||||
|
Mousectl *mc;
|
||||||
|
Keyboardctl *kc;
|
||||||
|
Obj *carry;
|
||||||
|
int showcarry;
|
||||||
|
extern int Steps;
|
||||||
|
|
||||||
|
void *
|
||||||
|
emalloc(ulong sz)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
v = malloc(sz);
|
||||||
|
if(v == nil) sysfatal("malloc: %r");
|
||||||
|
memset(v, 0, sz);
|
||||||
|
setmalloctag(v, getcallerpc(&sz));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image *
|
||||||
|
rgb(u32int c)
|
||||||
|
{
|
||||||
|
return allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
addtray(ObjT *t, ...)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
va_list va;
|
||||||
|
static double trayw;
|
||||||
|
|
||||||
|
va_start(va, t);
|
||||||
|
for(; t != nil; t = va_arg(va, ObjT *)){
|
||||||
|
o = mkobj(t);
|
||||||
|
o->tab->move(o, 0, 0, 0);
|
||||||
|
trayw += TraySpc;
|
||||||
|
o->tab->move(o, trayw + Dx(o->bbox)/2, TrayH/2, 0);
|
||||||
|
trayw += Dx(o->bbox);
|
||||||
|
objcat(&trayo, o);
|
||||||
|
}
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drawtray(void)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
|
||||||
|
for(o = trayo.next; o != &trayo; o = o->next)
|
||||||
|
o->tab->draw(o, tray);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
screeninit(void)
|
||||||
|
{
|
||||||
|
grey = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||||
|
scr = allocscreen(screen, display->white, 0);
|
||||||
|
work = allocwindow(scr, Rect(screen->r.min.x, screen->r.min.y, screen->r.max.x, screen->r.max.y - TrayH), 0, 0xFFFFFFFF);
|
||||||
|
tray = allocwindow(scr, Rect(screen->r.min.x, screen->r.max.y - TrayH, screen->r.max.x, screen->r.max.y), 0, 0xCCCCCCFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Obj *
|
||||||
|
objclick(Point p, Obj *l)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
|
||||||
|
for(o = l->next; o != l; o = o->next)
|
||||||
|
if(ptinrect(p, o->bbox))
|
||||||
|
return o;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
workdraw(void)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
|
||||||
|
draw(work, work->r, display->white, nil, ZP);
|
||||||
|
for(o = worko.next; o != &worko; o = o->next)
|
||||||
|
o->tab->draw(o, work);
|
||||||
|
if(carry != nil && showcarry)
|
||||||
|
carry->tab->draw(carry, work);
|
||||||
|
flushimage(display, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rundraw(void)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
|
||||||
|
draw(work, work->r, display->white, nil, ZP);
|
||||||
|
for(o = runo.next; o != &runo; o = o->next)
|
||||||
|
o->tab->draw(o, work);
|
||||||
|
flushimage(display, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
canhinge(Obj *a, Obj *b)
|
||||||
|
{
|
||||||
|
Hinge *h, *k;
|
||||||
|
|
||||||
|
if(a->hinge == nil || b->hinge == nil) return 0;
|
||||||
|
for(h = a->hinge; h != nil; h = h->onext)
|
||||||
|
for(k = b->hinge; k != nil; k = k->onext)
|
||||||
|
if(vecdist(h->p, k->p) <= HingeSep)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hinge(Obj *a, Obj *b)
|
||||||
|
{
|
||||||
|
Hinge *h, *k, *l;
|
||||||
|
|
||||||
|
if(a->hinge == nil || b->hinge == nil) return 0;
|
||||||
|
for(h = a->hinge; h != nil; h = h->onext)
|
||||||
|
for(k = b->hinge; k != nil; k = k->onext)
|
||||||
|
if(vecdist(h->p, k->p) <= HingeSep){
|
||||||
|
h->cprev->cnext = k;
|
||||||
|
k->cprev->cnext = h;
|
||||||
|
l = h->cprev;
|
||||||
|
h->cprev = k->cprev;
|
||||||
|
k->cprev = l;
|
||||||
|
b->tab->move(b, b->p.x + h->p.x - k->p.x, b->p.y + h->p.y - k->p.y, b->θ);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
place(void)
|
||||||
|
{
|
||||||
|
Obj *o;
|
||||||
|
int hinges;
|
||||||
|
|
||||||
|
hinges = 0;
|
||||||
|
for(o = worko.next; o != &worko; o = o->next)
|
||||||
|
if(objcoll(o, carry))
|
||||||
|
if(canhinge(o, carry))
|
||||||
|
hinges++;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
for(o = worko.next; hinges > 0 && o != &worko; o = o->next)
|
||||||
|
if(objcoll(o, carry))
|
||||||
|
hinges -= hinge(o, carry);
|
||||||
|
if(hinges != 0) print("hinge error\n");
|
||||||
|
objcat(&worko, carry);
|
||||||
|
carry = nil;
|
||||||
|
workdraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mouse(void)
|
||||||
|
{
|
||||||
|
static int lbut = -1;
|
||||||
|
Point p;
|
||||||
|
|
||||||
|
if(lbut < 0)
|
||||||
|
lbut = mc->buttons;
|
||||||
|
if(ptinrect(mc->xy, work->r)){
|
||||||
|
p = subpt(mc->xy, work->r.min);
|
||||||
|
if(carry != nil && (carry->p.x != p.x || carry->p.y != p.y || !showcarry)){
|
||||||
|
carry->tab->move(carry, p.x, p.y, carry->θ);
|
||||||
|
showcarry = 1;
|
||||||
|
workdraw();
|
||||||
|
}
|
||||||
|
}else if(showcarry){
|
||||||
|
showcarry = 0;
|
||||||
|
if(carry != nil)
|
||||||
|
workdraw();
|
||||||
|
}
|
||||||
|
if((~mc->buttons & lbut & 1) != 0){
|
||||||
|
if(ptinrect(mc->xy, tray->r)){
|
||||||
|
carry = objclick(subpt(mc->xy, tray->r.min), &trayo);
|
||||||
|
if(carry != nil)
|
||||||
|
carry = objdup(carry);
|
||||||
|
}else if(ptinrect(mc->xy, work->r)){
|
||||||
|
if(carry != nil)
|
||||||
|
place();
|
||||||
|
else{
|
||||||
|
carry = objclick(subpt(mc->xy, work->r.min), &worko);
|
||||||
|
if(carry != nil)
|
||||||
|
objexcise(carry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((~mc->buttons & lbut & 4) != 0){
|
||||||
|
if(carry != nil){
|
||||||
|
freeobj(carry);
|
||||||
|
carry = nil;
|
||||||
|
showcarry = 0;
|
||||||
|
workdraw();
|
||||||
|
}else if(ptinrect(mc->xy, work->r)){
|
||||||
|
carry = objclick(subpt(mc->xy, work->r.min), &worko);
|
||||||
|
if(carry != nil)
|
||||||
|
carry = objdup(carry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lbut = mc->buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run(void)
|
||||||
|
{
|
||||||
|
Obj *o, *oo;
|
||||||
|
Rune r;
|
||||||
|
static Cursor cursor;
|
||||||
|
|
||||||
|
for(o = runo.next; o != &runo; o = oo){
|
||||||
|
oo = o->next;
|
||||||
|
freeobj(o);
|
||||||
|
}
|
||||||
|
for(o = worko.next; o != &worko; o = o->next)
|
||||||
|
objcat(&runo, objdup(o));
|
||||||
|
copyhinges(&worko, &runo);
|
||||||
|
setcursor(mc, &cursor);
|
||||||
|
for(;;){
|
||||||
|
Alt a[] = {
|
||||||
|
{mc->c, &mc->Mouse, CHANRCV},
|
||||||
|
{kc->c, &r, CHANRCV},
|
||||||
|
{nil, nil, CHANNOBLK}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(alt(a)){
|
||||||
|
case 0: mouse(); break;
|
||||||
|
case 1:
|
||||||
|
switch(r){
|
||||||
|
case ' ': goto out;
|
||||||
|
case Kdel: threadexitsall(nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
physstep();
|
||||||
|
rundraw();
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
workdraw();
|
||||||
|
setcursor(mc, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key(Rune r)
|
||||||
|
{
|
||||||
|
switch(r){
|
||||||
|
case Kdel:
|
||||||
|
threadexitsall(nil);
|
||||||
|
case 'w':
|
||||||
|
if(carry != nil){
|
||||||
|
carry->tab->move(carry, carry->p.x, carry->p.y, carry->θ - 15);
|
||||||
|
workdraw();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if(carry != nil){
|
||||||
|
carry->tab->move(carry, carry->p.x, carry->p.y, carry->θ + 15);
|
||||||
|
workdraw();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
run();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: %s [-s steps]\n", argv0);
|
||||||
|
threadexitsall("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
threadmain(int argc, char **argv)
|
||||||
|
{
|
||||||
|
void simpleinit(void);
|
||||||
|
Rune r;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 's':
|
||||||
|
Steps = strtol(EARGF(usage()), &s, 0);
|
||||||
|
if(*s != 0) usage();
|
||||||
|
break;
|
||||||
|
default: usage();
|
||||||
|
}ARGEND;
|
||||||
|
|
||||||
|
if(initdraw(nil, nil, nil) < 0) sysfatal("initdraw: %r");
|
||||||
|
mc = initmouse(nil, screen);
|
||||||
|
if(mc == nil) sysfatal("initmouse: %r");
|
||||||
|
kc = initkeyboard(nil);
|
||||||
|
if(kc == nil) sysfatal("initkeyboard: %r");
|
||||||
|
screeninit();
|
||||||
|
trayo.prev = trayo.next = &trayo;
|
||||||
|
worko.prev = worko.next = &worko;
|
||||||
|
runo.prev = runo.next = &runo;
|
||||||
|
simpleinit();
|
||||||
|
drawtray();
|
||||||
|
flushimage(display, 1);
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
Alt a[] = {
|
||||||
|
{mc->c, &mc->Mouse, CHANRCV},
|
||||||
|
{kc->c, &r, CHANRCV},
|
||||||
|
{nil, nil, CHANEND}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(alt(a)){
|
||||||
|
case 0: mouse(); break;
|
||||||
|
case 1: key(r); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <mouse.h>
|
||||||
|
#include <keyboard.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
Vec
|
||||||
|
vecadd(Vec a, Vec b)
|
||||||
|
{
|
||||||
|
return (Vec){a.x + b.x, a.y + b.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec
|
||||||
|
vecsub(Vec a, Vec b)
|
||||||
|
{
|
||||||
|
return (Vec){a.x - b.x, a.y - b.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec
|
||||||
|
vecmul(Vec v, double s)
|
||||||
|
{
|
||||||
|
return (Vec){v.x * s, v.y * s};
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec
|
||||||
|
vecnorm(Vec v)
|
||||||
|
{
|
||||||
|
double r;
|
||||||
|
|
||||||
|
r = hypot(v.x, v.y);
|
||||||
|
if(r == 0) return (Vec){0, 0};
|
||||||
|
v.x /= r;
|
||||||
|
v.y /= r;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
vecdist(Vec a, Vec b)
|
||||||
|
{
|
||||||
|
return hypot(a.x - b.x, a.y - b.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
vecdot(Vec a, Vec b)
|
||||||
|
{
|
||||||
|
return a.x * b.x + a.y * b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec
|
||||||
|
vecnormal(Vec n)
|
||||||
|
{
|
||||||
|
Vec m;
|
||||||
|
|
||||||
|
m.x = -n.y;
|
||||||
|
m.y = n.x;
|
||||||
|
return vecnorm(m);
|
||||||
|
}
|
Loading…
Reference in New Issue