ref: e85e9a78a8b587d6b7a8bd84f70dbde33e7de904
dir: /sys/src/games/galaxy/body.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <bio.h>
#include "galaxy.h"
void
glxyinit(void)
{
glxy.a = calloc(5, sizeof(Body));
if(glxy.a == nil)
sysfatal("could not allocate glxy: %r");
glxy.nb = 0;
glxy.max = 5;
}
Body*
body(void)
{
Body *b;
if(glxy.nb == glxy.max) {
glxy.max *= 2;
glxy.a = realloc(glxy.a, sizeof(Body) * glxy.max);
if(glxy.a == nil)
sysfatal("could not realloc glxy: %r");
}
b = glxy.a + glxy.nb++;
*b = ZB;
return b;
}
Point
topoint(Vector v)
{
Point p;
p.x = v.x/scale + orig.x;
p.y = v.y/scale + orig.y;
return p;
}
void
drawbody(Body *b)
{
Point pos, v;
int s;
pos = topoint(b->Vector);
s = b->size/scale;
fillellipse(screen, pos, s, s, b->col, ZP);
v.x = b->v.x/scale*10;
v.y = b->v.y/scale*10;
if(v.x != 0 || v.y != 0)
line(screen, pos, addpt(pos, v), Enddisc, Endarrow, 0, b->col, ZP);
flushimage(display, 1);
}
Vector
center(void)
{
Body *b;
Vector gc, gcv;
double mass;
if(glxy.nb == 0)
return (Vector){0, 0};
gc.x = gc.y = gcv.x = gcv.y = mass = 0;
for(b = glxy.a; b < glxy.a+glxy.nb; b++) {
gc.x += b->x * b->mass;
gc.y += b->y * b->mass;
gcv.x += b->v.x * b->mass;
gcv.y += b->v.y * b->mass;
mass += b->mass;
}
gc.x /= mass;
gc.y /= mass;
gcv.x /= mass;
gcv.y /= mass;
for(b = glxy.a; b < glxy.a+glxy.nb; b++) {
b->x -= gc.x;
b->y -= gc.y;
b->v.x -= gcv.x;
b->v.y -= gcv.y;
}
return gc;
}
int
Bfmt(Fmt *f)
{
Body *b;
int r;
b = va_arg(f->args, Body*);
r = fmtprint(f, "MKBODY %g %g ", b->x, b->y);
if(r < 0)
return -1;
r = fmtprint(f, "%g %g ", b->v.x, b->v.y);
if(r < 0)
return -1;
return fmtprint(f, "%g", b->size);
}
enum {
MKBODY,
ORIG,
DT,
SCALE,
GRAV,
NOCMD,
};
int
getcmd(char *l)
{
static char *cmds[] = {
[MKBODY] "MKBODY",
[ORIG] "ORIG",
[DT] "DT",
[SCALE] "SCALE",
[GRAV] "GRAV",
};
int cmd;
for(cmd = 0; cmd < nelem(cmds); cmd++) {
if(strcmp(l, cmds[cmd]) == 0)
return cmd;
}
sysfatal("getcmd: no such command %s", l);
return NOCMD;
}
void
readglxy(int fd)
{
static Biobuf bin;
char *line;
double f;
int cmd, len;
Body *b;
glxy.nb = 0;
Binit(&bin, fd, OREAD);
for(;;) {
line = Brdline(&bin, ' ');
len = Blinelen(&bin);
if(line == nil) {
if(len == 0)
break;
sysfatal("load: malformed command");
}
line[len-1] = '\0';
cmd = getcmd(line);
line = Brdline(&bin, '\n');
if(line == nil) {
if(len == 0)
sysfatal("load: malformed command");
sysfatal("load: read error: %r");
}
len = Blinelen(&bin);
line[len-1] = '\0';
switch(cmd) {
case MKBODY:
b = body();
b->x = strtod(line, &line);
b->y = strtod(line, &line);
b->v.x = strtod(line, &line);
b->v.y = strtod(line, &line);
b->size = strtod(line, nil);
b->mass = b->size*b->size*b->size;
b->col = randcol();
CHECKLIM(b, f);
break;
case ORIG:
orig.x = strtol(line, &line, 10);
orig.y = strtol(line, nil, 10);
break;
case DT:
dt = strtod(line, nil);
dt² = dt*dt;
break;
case SCALE:
scale = strtod(line, nil);
break;
case GRAV:
G = strtod(line, nil);
break;
}
}
Bterm(&bin);
}
void
writeglxy(int fd)
{
static Biobuf bout;
Body *b;
Binit(&bout, fd, OWRITE);
Bprint(&bout, "ORIG %d %d\n", orig.x, orig.y);
Bprint(&bout, "SCALE %g\n", scale);
Bprint(&bout, "DT %g\n", dt);
Bprint(&bout, "GRAV %g\n", G);
for(b = glxy.a; b < glxy.a + glxy.nb; b++)
Bprint(&bout, "%B\n", b);
Bterm(&bout);
}