#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cg6.h" extern const char *__progname; static const char *fbpath = "/dev/cgsix0"; static const char *kbpath = "/dev/kbd1"; static int fbfd; static volatile struct cg6fb *fb; static volatile struct brooktree *bt; static volatile unsigned char *vram; static struct fbcmap oldcm; static unsigned char oldcm_r[256]; static unsigned char oldcm_g[256]; static unsigned char oldcm_b[256]; static int drawbit; static unsigned char map[16][3] = { { 0, 0, 0 }, #define C_BLACK 0 { 128, 128, 128 }, #define C_GREY 1 { 255, 0, 0 }, #define C_RED 2 { 0, 255, 0 }, #define C_GREEN 3 { 255, 255, 0 }, #define C_YELLOW 4 { 0, 0, 255 }, #define C_BLUE 5 { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 255 }, #define C_WHITE 15 }; #define NSP 150 typedef struct r3 R3; typedef struct r2 R2; typedef struct line LINE; typedef struct obj OBJ; typedef struct arobj AROBJ; typedef struct pic PIC; struct r3 { double x; double y; double z; } ; struct line { R3 a; R3 b; } ; struct r2 { double x; double y; } ; struct obj { OBJ *link; unsigned char type; #define OT_POINT 1 #define OT_LINE 2 unsigned char color; union { R3 pt; LINE l; } u; OBJ *other; PIC *pic; } ; struct arobj { AROBJ *link; R3 at; PIC *pic; OBJ *pretrans; } ; struct pic { int scroff_x; int scroff_y; R3 up; R3 out; R3 rt; R3 lea; R3 ler; R3 rea; R3 rer; OBJ *objs; AROBJ *arobjs; OBJ *eobjs; } ; static PIC pic_earth; static PIC pic_sky; static R3 local_n; static R3 local_e; static R3 local_p; static R3 overhead; static R3 east; static R3 north; static OBJ *rarc; static OBJ *ascendant; static OBJ *descendant; static OBJ *zenith; static OBJ *nadir; static OBJ *zlines[12]; static R3 zlines_m[12]; static R3 zlines_p[12]; static AROBJ *signs[12]; static double asc_theta; static double zen_sinphi; static double zen_cosphi; static int no_sky; static unsigned int llflags; #define LL_LAT 0x00000001 #define LL_LONG 0x00000002 static double ll_lat; /* radians north */ static double ll_long; /* radians east */ static R3 axis; /* geographic north, in ecliptic coordinates */ static double earthrot; static void (*drawsigns[12])(void (*)(double, double, double, double, double, double)); static OBJ *signobjs[12]; static int kbdfd; #define EVQ_SIZE 64 /* must be a power of two */ static int evq[EVQ_SIZE]; static int evqh; static int evqt; #define EV_TYPE 0x000f0000 #define EVT_NIL 0x00000000 #define EVT_KBD 0x00010000 #define EVK_CODE 0x0000007f /* must be low bits */ #define EVK_UPDN 0x00000080 #define EVK_UP 0x00000080 #define EVK_DN 0x00000000 #define EVT_TICK 0x00020000 static int curtime; static volatile int rawtime; static int timerunning; static const R3 r3_0 = { 0, 0, 0 }; static PIC *cpic; static double ed; static double es; static double ipd; static int kbbits; #define KB_SL 0x00000001 #define KB_SR 0x00000002 #define KB_S (KB_SL|KB_SR) static int mvbits; #define MV_UP 0x00000001 #define MV_LF 0x00000002 #define MV_RT 0x00000004 #define MV_DN 0x00000008 #define MV_CW 0x00000010 #define MV_CCW 0x00000020 #define MV_IN 0x00000040 #define MV_OUT 0x00000080 #define MV_AP 0x00000100 #define MV_TG 0x00000200 #define MV_ZI 0x00000400 #define MV_ZO 0x00000800 #define MV_EE 0x00001000 #define MV_EW 0x00002000 #define MV_3D 0x00004000 #define MV_SKY 0x00008000 static int wantrender; static void savecmap(void) { oldcm.index = 0; oldcm.count = 256; oldcm.red = &oldcm_r[0]; oldcm.green = &oldcm_g[0]; oldcm.blue = &oldcm_b[0]; if (ioctl(fbfd,FBIOGETCMAP,&oldcm) < 0) { fprintf(stderr,"%s: FBIOGETCMAP: %s\n",__progname,strerror(errno)); exit(1); } } static void setcmap(int bit) { int i; int v; bt->addr = 0; for (i=0;i<256;i++) { v = bit ? (i >> 4) : (i & 15); bt->cmap = map[v][0] * 0x01000000; bt->cmap = map[v][1] * 0x01000000; bt->cmap = map[v][2] * 0x01000000; } } static void initfb(void) { void *mrv; struct fbgattr a; fbfd = open(fbpath,O_RDWR,0); if (fbfd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } if ( (ioctl(fbfd,FBIOGATTR,&a) < 0) || (a.fbtype.fb_type != FBTYPE_SUNFAST_COLOR) || (a.fbtype.fb_width != 1152) || (a.fbtype.fb_height != 900) || (a.fbtype.fb_depth != 8) ) { fprintf(stderr,"%s: %s isn't an 1152x900 cgsix\n",__progname,fbpath); exit(1); } savecmap(); mrv = mmap(0,0x16000+a.fbtype.fb_size,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0x70000000); if (mrv == MAP_FAILED) { fprintf(stderr,"%s: can't mmap %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } fb = mrv; bt = (void *)(0x2000+(unsigned char *)mrv); vram = 0x16000 + (unsigned char *)mrv; setcmap(1); drawbit = 0; fb->bg = 0; fb->pixelm = ~0; fb->s = 0; fb->alu = 0xc0000000 /* GX_PLANE_MASK */ | 0x20000000 /* GX_PIXEL_ONES */ | 0x00800000 /* GX_ATTR_SUPP (?) */ | 0x00000000 /* GX_RAST_BOOL (?) */ | 0x00000000 /* GX_PLOT_PLOT (?) */ | 0x08000000 /* GX_PATTERN_ONES */ | 0x01000000 /* GX_POLYG_OVERLAP */ | 0x0000ff00 /* ALU = set to fg color */ ; /* ALU */ fb->clip = 0; fb->offx = 0; fb->offy = 0; fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; fb->fg = 0; fb->pm = ~0; fb->arecty = 0; fb->arectx = 0; fb->arecty = 900; fb->arectx = 1152; while (fb->s & 0x10000000) ; fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; fb->pm = 0x0f; } static void initkbd(void) { int type; int mode; kbdfd = open(kbpath,O_RDWR,0); if (kbdfd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,kbpath,strerror(errno)); exit(1); } if ( (ioctl(kbdfd,KIOCTYPE,&type) < 0) || (type != KB_SUN3) ) { close(kbdfd); fprintf(stderr,"%s: %s isn't a type-3\n",__progname,kbpath); exit(1); } mode = 1; ioctl(kbdfd,KIOCSDIRECT,&mode); mode = TR_UNTRANS_EVENT; ioctl(kbdfd,KIOCTRANS,&mode); mode = 1; ioctl(kbdfd,FIONBIO,&mode); } static void initevq(void) { evqh = 0; evqt = 0; } static void raw_tick(int sig __attribute__((__unused__))) { rawtime ++; } static void starttiming(void) { struct itimerval itv; if (timerunning) return; timerunning = 1; itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 10000; itv.it_interval = itv.it_value; setitimer(ITIMER_REAL,&itv,0); } static void stoptiming(void) { struct itimerval itv; if (! timerunning) return; timerunning = 0; itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 0; itv.it_interval = itv.it_value; setitimer(ITIMER_REAL,&itv,0); } static void inittiming(void) { struct sigaction sa; curtime = 0; rawtime = 0; sa.sa_handler = raw_tick; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGALRM,&sa,0); timerunning = 1; stoptiming(); } static void queue_event(int ev) { if (((evqh-evqt) & (EVQ_SIZE-1)) == (EVQ_SIZE-1)) { write(1,"evq full\n",9); } else { evq[evqh] = ev; evqh = (evqh+1) & (EVQ_SIZE-1); } } static int dequeue_event(void) { int ev; if (evqh == evqt) return(EVT_NIL); ev = evq[evqt]; evqt = (evqt+1) & (EVQ_SIZE-1); return(ev); } static int checktick(void) { int now; now = rawtime; if (curtime != now) { queue_event(EVT_TICK); curtime ++; return(1); } return(0); } static void fbline(int x1, int y1, int x2, int y2, int z) { fb->fg = z * 0x11; fb->aliney = y1; fb->alinex = x1; fb->aliney = y2; fb->alinex = x2; while ((fb->draw & 0xa0000000) == 0xa0000000) ; } static void fbpoint(int x, int y, int z) { unsigned char p; int vx; if ((x < 0) || (y < 0) || (x > 1151) || (y > 899)) return; vx = x + (y * 1152); p = vram[vx]; if (drawbit) p = (p & 0x0f) | (z << 4); else p = (p & 0xf0) | z; vram[vx] = p; } static double len3(R3 v) { return(hypot(hypot(v.x,v.y),v.z)); } static R3 norm(R3 v) { double l; l = len3(v); if (l < 1e-20) return(r3_0); v.x /= l; v.y /= l; v.z /= l; return(v); } static R3 normcross(R3 a, R3 b) { R3 c; c.x = (a.y * b.z) - (a.z * b.y); c.y = (a.z * b.x) - (a.x * b.z); c.z = (a.x * b.y) - (a.y * b.x); return(norm(c)); } static R3 cross(R3 a, R3 b) { return((R3) { .x = (a.y * b.z) - (a.z * b.y), .y = (a.z * b.x) - (a.x * b.z), .z = (a.x * b.y) - (a.y * b.x) }); } static double dot(R3 a, R3 b) { return((a.x*b.x)+(a.y*b.y)+(a.z*b.z)); } static R3 r3scale(R3 v, double s) { v.x *= s; v.y *= s; v.z *= s; return(v); } static R3 r3sub(R3 a, R3 b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; return(a); } static R3 r3add(R3 a, R3 b) { a.x += b.x; a.y += b.y; a.z += b.z; return(a); } /* assumes v is a unit vector */ static R3 rotunit(R3 v, R3 axis, double angle) { return(r3add(r3scale(v,cos(angle)),r3scale(normcross(axis,v),sin(angle)))); } /* assumes axis is a unit vector */ static R3 rot(R3 v, R3 axis, double angle) { R3 proj; R3 perp; R3 c; double nc; c = cross(v,axis); nc = len3(c); if (nc < 1e-20) return(v); c = r3scale(c,1/nc); proj = r3scale(axis,dot(v,axis)); perp = r3sub(v,proj); return(r3add(proj,r3add(r3scale(perp,cos(angle)),r3scale(c,len3(perp)*sin(angle))))); } static R2 project(PIC *pic, R3 p, R3 ea, R3 er) { double d; p = r3sub(p,ea); d = dot(p,norm(ea)); return((R2){ .x = dot(p,er) / d, .y = dot(p,pic->up) / d }); } static void draw3line(R3 p1, R3 p2, R3 ea, R3 er, int xo, int yo, int c) { R2 p1s; R2 p2s; p1s = project(p1,ea,er); p2s = project(p2,ea,er); fbline( xo+(p1s.x*es), yo-(p1s.y*es), xo+(p2s.x*es), yo-(p2s.y*es), c); } static void draw3point(R3 p, R3 ea, R3 er, int xo, int yo, int c) { R2 ps; ps = project(p,ea,er); fbpoint(xo+(ps.x*es),yo-(ps.y*es),c); } static void drawobj(OBJ *o, R3 ea, R3 er, int xo, int yo, int accel) { switch (o->type) { case OT_POINT: if (! accel) draw3point(o->u.pt,ea,er,xo,yo,o->color); break; case OT_LINE: if (accel) draw3line(o->u.l.a,o->u.l.b,ea,er,xo,yo,o->color); break; } } static R3 arpt(AROBJ *a, R3 p) { return(r3add( r3add( a->at, r3scale(a->pic->rt,-p.x) ), r3add( r3scale(a->pic->up,-p.y), r3scale(a->pic->out,-p.z) ) )); } static void rot_arobjs(PIC *p) { AROBJ *a; OBJ *l; OBJ *o; for (a=p->arobjs;a;a=a->link) { for (l=a->pretrans;l;l=l->link) { o = l->other; switch (l->type) { case OT_POINT: o->u.pt = arpt(a,l->u.pt); break; case OT_LINE: o->u.l.a = arpt(a,l->u.l.a); o->u.l.b = arpt(a,l->u.l.b); break; } } } } static void draw_3d(PIC *p) { OBJ *o; rot_arobjs(p); for (o=p->objs;o;o=o->link) { drawobj(o,p->lea,p->ler,p->scroff_x,scroff_y,0); drawobj(o,p->rea,p->rer,p->scroff_x+450,p->scroff_y,0); } for (o=p->objs;o;o=o->link) { drawobj(o,p->lea,p->ler,p->scroff_x,p->scroff_y,1); drawobj(o,p->rea,p->rer,p->scroff_x+450,p->scroff_y,1); } } static void skyline(double x1, double y1, double x2, double y2, int c) { fbline(scroff_sky_x+x1,scroff_sky_y+y1,scroff_sky_x+x2,scroff_sky_y+y2,c); fbline(scroff_sky_x+x1+450,scroff_sky_y+y1,scroff_sky_x+x2+450,scroff_sky_y+y2,c); } static int skypt(R3 pt3, R2 *pt2p) { R3 sv; sv.z = dot(pt3,overhead); if (pt2p) { sv.x = - dot(pt3,east); sv.y = - dot(pt3,north); sv = norm(sv); *pt2p = (R2){sv.x*200,sv.y*200}; } return(sv.z>=0); } static void draw_sky(void) { int i; double lx; double ly; double x; double y; double sat; double cat; lx = 200; ly = 0; for (i=1;i<36;i++) { x = 200 * cos(i*M_PI/18); y = 200 * sin(i*M_PI/18); skyline(lx,ly,x,y,C_GREY); lx = x; ly = y; } skyline(lx,ly,200,0,C_GREY); skyline(-180,-10,-190,-10,C_GREY); skyline(-190,-10,-190, 10,C_GREY); skyline(-190, 10,-180, 10,C_GREY); skyline(-190, 0,-184, 0,C_GREY); skyline(-5,-170,-5,-190,C_GREY); skyline(-5,-190, 5,-170,C_GREY); skyline( 5,-170, 5,-190,C_GREY); skyline(180,-10,180, 10,C_GREY); skyline(180, 10,185, 5,C_GREY); skyline(185, 5,190, 10,C_GREY); skyline(190, 10,190,-10,C_GREY); skyline( 5,172, 3,170,C_GREY); skyline( 3,170,-3,170,C_GREY); skyline(-3,170,-5,172,C_GREY); skyline(-5,172,-5,178,C_GREY); skyline(-5,178,-3,180,C_GREY); skyline(-3,180, 3,180,C_GREY); skyline( 3,180, 5,182,C_GREY); skyline( 5,182, 5,188,C_GREY); skyline( 5,188, 3,190,C_GREY); skyline( 3,190,-3,190,C_GREY); skyline(-3,190,-5,188,C_GREY); if (no_sky) return; sat = sin(asc_theta); cat = - cos(asc_theta); for (i=0;i<=36;i++) { double phi; double s; double c; phi = i * M_PI / 18; s = sin(phi); c = cos(phi); x = ((c * cat) - (s * sat * zen_sinphi)) * 200; y = ((c * sat) + (s * cat * zen_sinphi)) * 200; if (i) skyline(lx,ly,x,y,(i<=18)?C_BLUE:C_GREY); lx = x; ly = y; } for (i=0;i<12;i++) { R2 onscr; int above; OBJ *o; above = skypt(signs[i]->at,&onscr); for (o=signobjs[i];o;o=o->link) { skyline( onscr.x+(o->u.l.a.x/10), onscr.y-(o->u.l.a.y/10), onscr.x+(o->u.l.b.x/10), onscr.y-(o->u.l.b.y/10), above?C_WHITE:C_GREY ); } if (skypt(zlines[i]->u.l.a,&onscr)) { R2 onscr_m; R2 onscr_p; if (skypt(zlines_m[i],&onscr_m) && skypt(zlines_p[i],&onscr_p)) { double dx; double dy; double h; dx = onscr_p.x - onscr_m.x; dy = onscr_p.y - onscr_m.y; h = hypot(dx,dy); dx *= 5 / h; dy *= 5 / h; skyline(onscr.x+dy,onscr.y-dx,onscr.x-dy,onscr.y+dx,C_WHITE); } } } } static void drawmodel(void) { static int x; fbline(0,0,x++&31,31,15); draw_3d(); draw_sky(); } static void mayberender(void) { if (! wantrender) return; wantrender = 0; while (fb->s & 0x10000000) ; fb->fg = C_BLACK * 0x11; fb->arecty = 0; fb->arectx = 0; fb->arecty = 900; fb->arectx = 1152; while ((fb->draw & 0xa0000000) == 0xa0000000) ; rt = normcross(up,out); rea = r3add(r3scale(out,ed),r3scale(rt,ipd/2)); rer = normcross(up,rea); lea = r3add(r3scale(out,ed),r3scale(rt,-ipd/2)); ler = normcross(up,lea); drawmodel(); setcmap(drawbit); drawbit = ! drawbit; while (fb->s & 0x10000000) ; fb->pm = drawbit ? 0xf0 : 0x0f; } static int checkkbd(void) { struct firm_event ev; int r; r = read(kbdfd,&ev,sizeof(ev)); if (r == sizeof(ev)) { queue_event(EVT_KBD|(ev.id&0x7f)|((ev.value==VKEY_UP)?EVK_UP:EVK_DN)); return(1); } return(0); } static void resethw(void) { fb->bg = 0; fb->pixelm = ~0; fb->s = 0; fb->alu = 0xc0000000 /* GX_PLANE_MASK */ | 0x20000000 /* GX_PIXEL_ONES */ | 0x00800000 /* GX_ATTR_SUPP (?) */ | 0x00000000 /* GX_RAST_BOOL (?) */ | 0x00000000 /* GX_PLOT_PLOT (?) */ | 0x08000000 /* GX_PATTERN_ONES */ | 0x01000000 /* GX_POLYG_OVERLAP */ | 0x0000ff00 /* ALU = set to fg color */ ; /* ALU */ fb->clip = 0; fb->offx = 0; fb->offy = 0; fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; fb->fg = 0; fb->pm = ~0; } static R3 erp(R3 ep) { return(rot(ep,axis,earthrot)); } static void setlineOO(OBJ *o) { if (o->type != OT_LINE) abort(); o->u.l.a = r3_0; o->u.l.b = r3_0; } static void setzl(int a, int b, int lit) { int i; double r; int c; r = lit ? .875 : .95; c = lit ? C_WHITE : C_GREY; for (i=a;i!=b;i=(i>=11)?0:(i+1)) { zlines[i]->color = c; zlines[i]->u.l.b = r3scale(zlines[i]->u.l.a,r); } } static void set_ar_color(AROBJ *a, int c) { OBJ *o; for (o=a->pretrans;o;o=o->link) o->other->color = c; } static void setzs(int a, int b, int lit) { int i; int c; c = lit ? C_WHITE : C_GREY; for (i=a;i!=b;i=(i>=11)?0:(i+1)) set_ar_color(signs[i],c); } static void update_earth(void) { OBJ *eo; OBJ *o; for (eo=eobjs;eo;eo=eo->link) { o = eo->other; switch (eo->type) { case OT_POINT: o->u.pt = erp(eo->u.pt); break; case OT_LINE: o->u.l.a = erp(eo->u.l.a); o->u.l.b = erp(eo->u.l.b); break; } } overhead = erp(local_p); east = erp(local_e); north = erp(local_n); if (hypot(overhead.x,overhead.y) < 1e-10) { no_sky = 1; setlineOO(ascendant); setlineOO(descendant); setlineOO(zenith); setlineOO(nadir); setzl(0,6,0); setzl(6,0,0); setzs(0,6,0); setzs(6,0,0); } else { R3 z; R3 a; int ax; no_sky = 0; z = norm((R3){.x=overhead.x,.y=overhead.y,.z=0}); a = normcross((R3){.x=0,.y=0,.z=1},z); zenith->u.l.a = z; zenith->u.l.b = r3scale(z,2); nadir->u.l.a = r3scale(z,-1); nadir->u.l.b = r3scale(z,-2); ascendant->u.l.a = a; ascendant->u.l.b = r3scale(a,2); descendant->u.l.a = r3scale(a,-1); descendant->u.l.b = r3scale(a,-2); ax = (atan2(a.y,a.x) * 6 / M_PI) + 13; setzl(ax%12,(ax+6)%12,0); setzl((ax+6)%12,ax%12,1); ax = (atan2(a.y,a.x) * 6 / M_PI) + 12.5; setzs(ax%12,(ax+6)%12,0); setzs((ax+6)%12,ax%12,1); for (eo=rarc;eo;eo=eo->link) { o = eo->other; o->u.l.a.x = z.x * eo->u.l.a.x; o->u.l.a.y = z.y * eo->u.l.a.x; o->u.l.a.z = eo->u.l.a.z; o->u.l.b.x = z.x * eo->u.l.b.x; o->u.l.b.y = z.y * eo->u.l.b.x; o->u.l.b.z = eo->u.l.b.z; } asc_theta = atan2(dot(a,north),-dot(a,east)); zen_cosphi = hypot(overhead.x,overhead.y); zen_sinphi = overhead.z; } } static void mv_adjust_offsets(void) { int dx; int dy; int f; dx = 0; dy = 0; f = (kbbits & KB_S) ? 5 : 1; switch (mvbits & (MV_LF|MV_RT)) { case MV_LF: dx = -f; break; case MV_RT: dx = f; break; } switch (mvbits & (MV_UP|MV_DN)) { case MV_UP: dy = -f; break; case MV_DN: dy = f; break; } if (mvbits & MV_3D) { scroff_3d_x += dx; scroff_3d_y += dy; wantrender = 1; } if (mvbits & MV_SKY) { scroff_sky_x += dx; scroff_sky_y += dy; wantrender = 1; } } static void mv_normal(void) { double s; s = (kbbits & KB_S) ? 5 : 1; switch (mvbits & (MV_LF|MV_RT)) { case MV_RT: out = rotunit(out,up,s*.01); wantrender = 1; break; case MV_LF: out = rotunit(out,up,-s*.01); wantrender = 1; break; } switch (mvbits & (MV_UP|MV_DN)) { case MV_DN: rt = normcross(up,out); up = rotunit(up,rt,s*.01); out = normcross(rt,up); wantrender = 1; break; case MV_UP: rt = normcross(up,out); up = rotunit(up,rt,-s*.01); out = normcross(rt,up); wantrender = 1; break; } switch (mvbits & (MV_CW|MV_CCW)) { case MV_CW: rt = normcross(up,out); up = rotunit(up,out,s*.01); wantrender = 1; break; case MV_CCW: rt = normcross(up,out); up = rotunit(up,out,-s*.01); wantrender = 1; break; } switch (mvbits & (MV_IN|MV_OUT)) { case MV_IN: ed -= s * .02; wantrender = 1; break; case MV_OUT: ed += s * .02; wantrender = 1; break; } switch (mvbits & (MV_AP|MV_TG)) { case MV_AP: ipd += s * .002; wantrender = 1; break; case MV_TG: ipd -= s * .002; wantrender = 1; break; } switch (mvbits & (MV_ZI|MV_ZO)) { case MV_ZI: es += s; wantrender = 1; break; case MV_ZO: es -= s; wantrender = 1; break; } switch (mvbits & (MV_EE|MV_EW)) { case MV_EE: earthrot += s * .01; if (earthrot > M_PI) earthrot -= 2 * M_PI; update_earth(); wantrender = 1; break; case MV_EW: earthrot -= s * .01; if (earthrot < -M_PI) earthrot += 2 * M_PI; update_earth(); wantrender = 1; break; } } static void process_evq(void) { int ev; while (1) { ev = dequeue_event(); switch (ev & EV_TYPE) { case EVT_NIL: return; break; case EVT_KBD: switch (ev & (EVK_CODE|EVK_UPDN)) { default: printf("kbd: %d ",ev&EVK_CODE); switch (ev & EVK_UPDN) { case EVK_UP: printf("up\n"); break; case EVK_DN: printf("dn\n"); break; } break; case 1|EVK_DN: mvbits |= MV_IN; break; /* L1 */ case 1|EVK_UP: mvbits &=~MV_IN; break; case 3|EVK_DN: mvbits |= MV_OUT; break; /* L2 */ case 3|EVK_UP: mvbits &=~MV_OUT; break; case 16|EVK_DN: resethw(); break; /* F7 */ case 16|EVK_UP: break; case 25|EVK_DN: mvbits |= MV_AP; break; /* L3 */ case 25|EVK_UP: mvbits &=~MV_AP; break; case 26|EVK_DN: mvbits |= MV_TG; break; /* L4 */ case 26|EVK_UP: mvbits &=~MV_TG; break; case 29|EVK_DN: break; /* ESC */ case 29|EVK_UP: exit(0); break; case 49|EVK_DN: mvbits |= MV_ZI; break; /* L5 */ case 49|EVK_UP: mvbits &=~MV_ZI; break; case 51|EVK_DN: mvbits |= MV_ZO; break; /* L6 */ case 51|EVK_UP: mvbits &=~MV_ZO; break; case 68|EVK_DN: mvbits |= MV_CCW; break; /* R7 */ case 68|EVK_UP: mvbits &=~MV_CCW; break; case 69|EVK_DN: mvbits |= MV_UP; break; /* R8 */ case 69|EVK_UP: mvbits &=~MV_UP; break; case 70|EVK_DN: mvbits |= MV_CW; break; /* R9 */ case 70|EVK_UP: mvbits &=~MV_CW; break; case 72|EVK_DN: break; /* L7 */ case 72|EVK_UP: break; case 73|EVK_DN: break; /* L8 */ case 73|EVK_UP: break; case 91|EVK_DN: mvbits |= MV_LF; break; /* R10 */ case 91|EVK_UP: mvbits &=~MV_LF; break; case 93|EVK_DN: mvbits |= MV_RT; break; /* R12 */ case 93|EVK_UP: mvbits &=~MV_RT; break; case 95|EVK_DN: mvbits |= MV_EE; break; /* L9 */ case 95|EVK_UP: mvbits &=~MV_EE; break; case 97|EVK_DN: mvbits |= MV_EW; break; /* L10 */ case 97|EVK_UP: mvbits &=~MV_EW; break; case 99|EVK_DN: kbbits |= KB_SL; break; /* Left Shift */ case 99|EVK_UP: kbbits &=~KB_SL; break; case 110|EVK_DN: kbbits |= KB_SR; break; /* Right Shift */ case 110|EVK_UP: kbbits &=~KB_SR; break; case 113|EVK_DN: mvbits |= MV_DN; break; /* R14 */ case 113|EVK_UP: mvbits &=~MV_DN; break; case 119|EVK_DN: mvbits |= MV_3D; break; /* Caps */ case 119|EVK_UP: mvbits &=~MV_3D; break; case 120|EVK_DN: mvbits |= MV_SKY; break; /* Left */ case 120|EVK_UP: mvbits &=~MV_SKY; break; } break; case EVT_TICK: if (mvbits & (MV_3D|MV_SKY)) { mv_adjust_offsets(); } else { mv_normal(); } break; } } } static void initsim(void) { up.x = 0; up.y = 0; up.z = -1; out.x = 1; out.y = .2; out.z = .3; out = norm(out); rt = normcross(up,out); up = normcross(out,rt); ed = 10; es = 1000; ipd = 1; mvbits = 0; scroff_3d_x = 288; scroff_3d_y = 675; scroff_sky_x = 288; scroff_sky_y = 225; } static void run(void) { struct pollfd pfd; process_evq(); mayberender(); if (checkkbd()) return; if (mvbits) starttiming(); else stoptiming(); if (checktick()) return; pfd.fd = kbdfd; pfd.events = POLLIN | POLLRDNORM; if (poll(&pfd,1,INFTIM) < 0) { if (errno == EINTR) return; fprintf(stderr,"%s: poll: %s\n",__progname,strerror(errno)); exit(1); } } static void usage(void) { fprintf(stderr,"Usage: %s [-fb fbdev] [-kb|-kbd kbdev] lat long\n",__progname); } static int llarg(const char *arg) { char *s; char *e; char c; int neg; double v; int gotdot; int bit; double *loc; const char *what; s = strdup(arg); gotdot = 0; for (e=s;*e;e++) { switch (*e) { case '.': gotdot = 1; /* fall through */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': continue; break; } break; } if ((e == s) || (gotdot && (e == s+1))) { fprintf(stderr,"%s: %s: missing number\n",__progname,s); exit(1); } else if (! *e) { fprintf(stderr,"%s: %s: missing direction\n",__progname,s); exit(1); } switch (*e) { case 'n': case 'N': neg = 0; loc = &ll_lat; what = "latitude"; bit = LL_LAT; break; case 's': case 'S': neg = 1; loc = &ll_lat; what = "latitude"; bit = LL_LAT; break; case 'e': case 'E': neg = 0; loc = &ll_long; what = "longitude"; bit = LL_LONG; break; case 'w': case 'W': neg = 1; loc = &ll_long; what = "longitude"; bit = LL_LONG; break; default: fprintf(stderr,"%s: %s: invalid direction\n",__progname,s); exit(1); break; } if (gotdot) { if (e[1]) { fprintf(stderr,"%s: %s: junk after %s\n",__progname,s,what); exit(1); } c = *e; *e = '\0'; v = atof(s); *e = c; } else { c = *e; *e = '\0'; v = atoi(s); *e = c; v += atof(e+1) / 60; } v *= M_PI / 180; *loc = neg ? -v : v; llflags |= bit; free(s); return(1); } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { if (llarg(*av)) { } else { fprintf(stderr,"%s: extra argument `%s'\n",__progname,*av); errs ++; } continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-fb")) { WANTARG(); fbpath = av[skip]; continue; } if (!strcmp(*av,"-kb") || !strcmp(*av,"-kbd")) { WANTARG(); kbpath = av[skip]; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if ((llflags & (LL_LAT|LL_LONG)) != (LL_LAT|LL_LONG)) { usage(); errs ++; } if (errs) exit(1); } static OBJ *addline(LINE l, int c) { OBJ *o; o = malloc(sizeof(OBJ)); o->type = OT_LINE; o->color = c; o->u.l = l; o->link = objs; objs = o; return(o); } static OBJ *addpoint(R3 p, int c) { OBJ *o; o = malloc(sizeof(OBJ)); o->type = OT_POINT; o->color = c; o->u.pt = p; o->link = objs; objs = o; return(o); } static LINE makeline(double x1, double y1, double z1, double x2, double y2, double z2) { return((LINE){ .a = { .x = x1, .y = y1, .z = z1 }, .b = { .x = x2, .y = y2, .z = z2 } }); } static LINE makel2p(R3 a, R3 b) { return((LINE){ .a = a, .b = b }); } static double rand01(void) { double rval; int i; for (i=1;ilink) { o = malloc(sizeof(OBJ)); *o = *l; o->link = objs; objs = o; l->other = o; } } static void draw_aries(void (*line)(double, double, double, double, double, double)) { double s; s = sqrt(.5) * 25; (*line)( -50, 40, 0, -25-s, 40+s, 0 ); (*line)( 50, 40, 0, 25+s, 40+s, 0 ); (*line)( -25-s, 40+s, 0, -25, 65, 0 ); (*line)( 25+s, 40+s, 0, 25, 65, 0 ); (*line)( -25, 65, 0, -25+s, 40+s, 0 ); (*line)( 25, 65, 0, 25-s, 40+s, 0 ); (*line)( -25+s, 40+s, 0, 0, 40, 0 ); (*line)( 25-s, 40+s, 0, 0, 40, 0 ); (*line)( 0, 40, 0, 0, -65, 0 ); } static void draw_taurus(void (*line)(double, double, double, double, double, double)) { double s; s = sqrt(.5) * 45; (*line)( 45, -20, 0, s, -20+s, 0 ); (*line)( s, -20+s, 0, 0, 25, 0 ); (*line)( 0, 25, 0, -s, -20+s, 0 ); (*line)( -s, -20+s, 0, -45, -20, 0 ); (*line)( -45, -20, 0, -s, -20-s, 0 ); (*line)( -s, -20-s, 0, 0, -65, 0 ); (*line)( 0, -65, 0, s, -20-s, 0 ); (*line)( s, -20-s, 0, 45, -20, 0 ); s = sqrt(.5) * 40; (*line)( -40, 65, 0, -s, 65-s, 0 ); (*line)( -s, 65-s, 0, 0, 25, 0 ); (*line)( 0, 25, 0, s, 65-s, 0 ); (*line)( s, 65-s, 0, 40, 65, 0 ); } static void draw_gemini(void (*line)(double, double, double, double, double, double)) { (*line)( -20, -55, 0, -20, 55, 0 ); (*line)( 20, -55, 0, 20, 55, 0 ); (*line)( -20, -55, 0, 20, -55, 0 ); (*line)( -20, 55, 0, 20, 55, 0 ); (*line)( -20, -55, 0, -50, -65, 0 ); (*line)( 20, -55, 0, 50, -65, 0 ); (*line)( -20, 55, 0, -50, 65, 0 ); (*line)( 20, 55, 0, 50, 65, 0 ); } static void draw_cancer(void (*line)(double, double, double, double, double, double)) { double s; s = sqrt(.5) * 25; (*line)( -15, 10, 0, -40+s, 10+s, 0 ); (*line)( -40+s, 10+s, 0, -40, 35, 0 ); (*line)( -40, 35, 0, -40-s, 10+s, 0 ); (*line)( -40-s, 10+s, 0, -65, 10, 0 ); (*line)( -65, 10, 0, -40-s, 10-s, 0 ); (*line)( -40-s, 10-s, 0, -40, -15, 0 ); (*line)( -40, -15, 0, -40+s, 10-s, 0 ); (*line)( -40+s, 10-s, 0, -15, 10, 0 ); (*line)( -40, 35, 0, 0, 45, 0 ); (*line)( 0, 45, 0, 40, 45, 0 ); (*line)( 15, -10, 0, 40-s, -10-s, 0 ); (*line)( 40-s, -10-s, 0, 40, -35, 0 ); (*line)( 40, -35, 0, 40+s, -10-s, 0 ); (*line)( 40+s, -10-s, 0, 65, -10, 0 ); (*line)( 65, -10, 0, 40+s, -10+s, 0 ); (*line)( 40+s, -10+s, 0, 40, 15, 0 ); (*line)( 40, 15, 0, 40-s, -10+s, 0 ); (*line)( 40-s, -10+s, 0, 15, -10, 0 ); (*line)( 40, -35, 0, 0, -45, 0 ); (*line)( 0, -45, 0, -40, -45, 0 ); } static void draw_leo(void (*line)(double, double, double, double, double, double)) { double s; double cy; double r; double lx; double ly; double x; double y; int i; s = sqrt(3) * 10; (*line)( -35, -45+s, 0, -55, -45+s, 0 ); (*line)( -55, -45+s, 0, -65, -45, 0 ); (*line)( -65, -45, 0, -55, -45-s, 0 ); (*line)( -55, -45-s, 0, -35, -45-s, 0 ); (*line)( -35, -45-s, 0, -25, -45, 0 ); (*line)( -25, -45, 0, -55, -45+(3*s), 0 ); (*line)( 65, -45, 0, 55, -45-s, 0 ); (*line)( 55, -45-s, 0, 35, -45-s, 0 ); (*line)( 35, -45-s, 0, 25, -45, 0 ); (*line)( 25, -45, 0, 55, -45+(3*s), 0 ); r = 55 / cos(M_PI/12); cy = -45 + (3 * s) + (r * sin(M_PI/12)); for (i=0;i<8;i++) { x = r * cos((i+i-1)*(M_PI/12)); y = cy + (r * sin((i+i-1)*(M_PI/12))); if (i) (*line)(lx,ly,0,x,y,0); lx = x; ly = y; } /* (*line)( -55, -45+(3*s), 0, -25, -45+(6*s), 0 ); (*line)( 55, -45+(3*s), 0, 25, -45+(6*s), 0 ); (*line)( -25, -45+(6*s), 0, 25, -45+(6*s), 0 ); */ } static void draw_virgo(void (*line)(double, double, double, double, double, double)) { (*line)( -60, 40, 0, -45, 55, 0 ); (*line)( -45, 55, 0, -30, 40, 0 ); (*line)( -30, 40, 0, -30, -55, 0 ); (*line)( -30, 40, 0, -15, 55, 0 ); (*line)( -15, 55, 0, 0, 40, 0 ); (*line)( 0, 40, 0, 0, -55, 0 ); (*line)( 0, 40, 0, 15, 55, 0 ); (*line)( 15, 55, 0, 30, 40, 0 ); (*line)( 30, 40, 0, 30, -55, 0 ); (*line)( 30, 40, 0, 45, 55, 0 ); (*line)( 45, 55, 0, 60, 40, 0 ); (*line)( 60, 40, 0, 60, 25, 0 ); (*line)( 60, 25, 0, 15, -40, 0 ); (*line)( 15, -40, 0, 15, -55, 0 ); } static void draw_libra(void (*line)(double, double, double, double, double, double)) { double s; s = sqrt(.5) * 25; (*line)( -60, -25, 0, 60, -25, 0 ); (*line)( -60, 0, 0, -25, 0, 0 ); (*line)( -25, 0, 0, -s, s, 0 ); (*line)( -s, s, 0, 0, 25, 0 ); (*line)( 0, 25, 0, s, s, 0 ); (*line)( s, s, 0, 25, 0, 0 ); (*line)( 25, 0, 0, 60, 0, 0 ); } static void draw_scorpio(void (*line)(double, double, double, double, double, double)) { (*line)( -60, 40, 0, -45, 55, 0 ); (*line)( -45, 55, 0, -30, 40, 0 ); (*line)( -30, 40, 0, -30, -45, 0 ); (*line)( -30, 40, 0, -15, 55, 0 ); (*line)( -15, 55, 0, 0, 40, 0 ); (*line)( 0, 40, 0, 0, -45, 0 ); (*line)( 0, 40, 0, 15, 55, 0 ); (*line)( 15, 55, 0, 30, 40, 0 ); (*line)( 30, 40, 0, 30, -45, 0 ); (*line)( 30, -45, 0, 45, -60, 0 ); (*line)( 45, -60, 0, 60, -45, 0 ); } static void draw_sagittarius(void (*line)(double, double, double, double, double, double)) { (*line)( -65, -65, 0, 65, 65, 0 ); (*line)( 65, 65, 0, 35, 65, 0 ); (*line)( 65, 65, 0, 65, 35, 0 ); (*line)( 15, -35, 0, -35, 15, 0 ); } static void draw_capricorn(void (*line)(double, double, double, double, double, double)) { R3 d; R3 p; R3 p2; R3 c1; R3 c2; int i; double a; (*line)( -65, 65, 0, -40, 65, 0 ); (*line)( -40, 65, 0, -40, -5, 0 ); (*line)( -40, -5, 0, -5, 55, 0 ); (*line)( -5, 55, 0, 30, 30, 0 ); d = r3scale(norm((R3){.x=1,.y=1,.z=0}),15); p = (R3){.x=30,.y=30,.z=0}; c1 = r3add(p,d); for (i=0;i<3;i++) { p2 = p; p = r3add(p2,d); d = (R3){.x=-d.y,.y=d.x,.z=0}; (*line)(p2.x,p2.y,p2.z,p.x,p.y,p.z); } c1 = r3scale(r3add(c1,p),.5); c2 = r3add(c1,r3scale((R3){.x=d.y,.y=-d.x,.z=0},4)); a = atan2(c1.y-c2.y,c1.x-c2.x); for (i=0;i<4;i++) { p2 = p; a -= M_PI / 4; p = r3add(c2,(R3){.x=cos(a)*45,.y=sin(a)*45,.z=0}); (*line)(p2.x,p2.y,p2.z,p.x,p.y,p.z); } } static void draw_aquarus(void (*line)(double, double, double, double, double, double)) { int i; for (i=0;i<120;i+=40) { (*line)(-60+i, 10,0,-40+i, 30,0); (*line)(-40+i, 30,0,-20+i, 10,0); (*line)(-60+i,-30,0,-40+i,-10,0); (*line)(-40+i,-10,0,-20+i,-30,0); } } static void draw_pisces(void (*line)(double, double, double, double, double, double)) { double a0; double da; double r; int i; R2 last; R2 p; (*line)(-60,0,0,60,0,0); a0 = atan2(6.5,9); da = - (2 * a0) / 3; r = hypot(90,65); for (i=0;i<4;i++) { p = (R2){.x=-140+(r*cos(a0+(i*da))),.y=r*sin(a0+(i*da))}; if (i) { (*line)(last.x,last.y,0,p.x,p.y,0); (*line)(-last.x,last.y,0,-p.x,p.y,0); } last = p; } } static void (*drawsigns[12])(void (*)(double, double, double, double, double, double)) = { draw_aries, draw_taurus, draw_gemini, draw_cancer, draw_leo, draw_virgo, draw_libra, draw_scorpio, draw_sagittarius, draw_capricorn, draw_aquarus, draw_pisces }; static AROBJ *add_arobj(double x, double y, double z, OBJ *objlist) { OBJ *l; OBJ *o; AROBJ *a; a = malloc(sizeof(AROBJ)); a->at = (R3){.x=x,.y=y,.z=z}; a->pretrans = 0; for (l=objlist;l;l=l->link) { o = malloc(sizeof(OBJ)); o->type = l->type; switch (o->type) { case OT_POINT: o->u.pt = r3scale(l->u.pt,.001); break; case OT_LINE: o->u.l.a = r3scale(l->u.l.a,.001); o->u.l.b = r3scale(l->u.l.b,.001); break; } o->link = a->pretrans; a->pretrans = o; } for (l=a->pretrans;l;l=l->link) { o = malloc(sizeof(OBJ)); *o = *l; o->link = objs; objs = o; l->other = o; } a->link = arobjs; arobjs = a; return(a); } static void signline(double x1, double y1, double z1, double x2, double y2, double z2) { addline(makeline(x1,y1,z1,x2,y2,z2),0); } static void initmodel(void) { int i; R3 eeast; objs = 0; arobjs = 0; srandom(time(0)); axis = (R3){.x=0,.y=sin((23*M_PI)/180),.z=cos((23*M_PI)/180)}; eeast = normcross(axis,(R3){.x=0,.y=0,.z=1}); if (ll_lat > M_PI*.999) { local_e = eeast; local_n = normcross(local_e,axis); local_p = axis; } else if (ll_lat < -M_PI*.999) { local_e = eeast; local_n = normcross(local_e,axis); local_p = r3scale(axis,-1); } else { double x; double y; double z; R3 up; R3 prev; R3 pt; double phi; up = normcross(eeast,axis); x = cos(ll_lat) * cos(ll_long); y = cos(ll_lat) * sin(ll_long); z = sin(ll_lat); local_p = r3add(r3scale(axis,z),r3add(r3scale(eeast,x),r3scale(up,y))); local_e = normcross(axis,local_p); local_n = normcross(local_p,local_e); prev = (R3){.x=0,.y=0,.z=1}; for (i=5;i>=0;i--) { phi = (M_PI * i) / 12; pt = (R3){.x=cos(phi),.y=0,.z=sin(phi)}; addline(makel2p(prev,pt),C_GREY); prev = pt; } } rarc = objs; objs = 0; for (i=NSP;i>0;i--) addpoint(pt_on_sphere(),C_WHITE); addline(makel2p(r3_0,axis),C_RED); addline(makel2p(local_p,r3scale(local_p,1.1)),C_RED); for (i=0;i<5;i++) { addline(makel2p( r3add( local_p, r3add( r3scale(local_e,-1), r3scale(local_n,(i-2)*.5) ) ), r3add( local_p, r3add( r3scale(local_e,1), r3scale(local_n,(i-2)*.5) ) ) ), C_GREY); addline(makel2p( r3add( local_p, r3add( r3scale(local_n,-1), r3scale(local_e,(i-2)*.5) ) ), r3add( local_p, r3add( r3scale(local_n,1), r3scale(local_e,(i-2)*.5) ) ) ), C_GREY); } eobjs = objs; objs = 0; for (i=0;i<12;i++) { (*drawsigns[i])(signline); signobjs[i] = objs; objs = 0; } ascendant = addline(makeline(0,0,0,0,0,0),C_GREEN); descendant = addline(makeline(0,0,0,0,0,0),C_GREEN); zenith = addline(makeline(0,0,0,0,0,0),C_YELLOW); nadir = addline(makeline(0,0,0,0,0,0),C_BLUE); earthrot = 0; shadow_objs(eobjs); shadow_objs(rarc); for (i=0;i<12;i++) { double s; double c; double a; a = i * M_PI / 6; s = sin(a); c = cos(a); zlines[i] = addline(makeline(2*c,2*s,0,1.8*c,1.8*s,0),C_WHITE); zlines_m[i] = (R3){.x=cos(a-.01),.y=sin(a-.01),.z=0}; zlines_p[i] = (R3){.x=cos(a+.01),.y=sin(a+.01),.z=0}; s = sin((i+i+1)*M_PI/12); c = cos((i+i+1)*M_PI/12); signs[i] = add_arobj(2*c,2*s,0,signobjs[i]); } addline(makeline(0,0,-2,0,0,2),C_GREY); update_earth(); } int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); initmodel(); initsim(); initevq(); initfb(); initkbd(); inittiming(); wantrender = 1; while (1) run(); }