#include #include #include #include #include #ifndef __NetBSD__ #define sinf(x) sin(x) #define cosf(x) cos(x) #define rintf(x) rint(x) #endif extern const char *__progname; #include "gl-int.h" #include "sounds.h" int TICKS_PER_SEC; int XMAXSCREEN; int YMAXSCREEN; double PIXELSCALE; extern IDEV idev_sun4; extern IDEV idev_sun3; extern IDEV idev_none; static IDEV *idevs[] = { &idev_sun4, &idev_sun3, &idev_none, 0 }; static IDEV *idev = 0; static const char *idevpath = 0; extern ODEV odev_smallbwtwo; extern ODEV odev_bwtwo; extern ODEV odev_cgthree; extern ODEV odev_cgsix; static ODEV *odevs[] = { &odev_bwtwo, &odev_smallbwtwo, &odev_cgthree, &odev_cgsix, 0 }; static ODEV *odev = 0; static const char *odevpath = 0; typedef struct mstack MSTACK; typedef struct ssfn SSFN; typedef struct dsfn DSFN; struct mstack { MSTACK *link; Matrix mat; } ; struct ssfn { SSFN *link; void (*fn)(fd_set *, fd_set *, fd_set *, struct timeval *, struct timeval *); } ; struct dsfn { DSFN *link; int (*fn)(fd_set *, fd_set *, fd_set *); } ; #define QSIZE 256 FILTER devqueued; static Matrix curmatrix; static MSTACK *mstack; static int timernoise[3]; static int timercount[3]; static int closedline_x0; static int closedline_y0; static int linelast_x; static int linelast_y; static int curmode; #define M_NONE 0 #define M_POINT 1 #define M_LINE_A 2 #define M_LINE_B 3 #define M_CLOSEDLINE_A 4 #define M_CLOSEDLINE_B 5 static long int q_dev[QSIZE]; static short int q_val[QSIZE]; static int qfill; static int qptr; static struct timeval next_timer; static unsigned int timer_inc; static unsigned long int nowsec; static SSFN *ssfns = 0; static DSFN *dsfns = 0; inline static int tvless(struct timeval tv1, struct timeval tv2) { if (tv1.tv_sec < tv2.tv_sec) return(1); if (tv1.tv_sec > tv2.tv_sec) return(0); if (tv1.tv_usec < tv2.tv_usec) return(1); return(0); } inline static struct timeval tvsub(struct timeval tv1, struct timeval tv2) { if (tv1.tv_usec >= tv2.tv_usec) { tv1.tv_usec -= tv2.tv_usec; tv1.tv_sec -= tv2.tv_sec; } else { tv1.tv_usec += 1000000 - tv2.tv_usec; tv1.tv_sec -= tv2.tv_sec + 1; } return(tv1); } static void inc_timer(void) { next_timer.tv_usec += timer_inc; if (next_timer.tv_usec >= 1000000) { next_timer.tv_usec -= 1000000; next_timer.tv_sec ++; } } static void qrefill(int blocking) { struct fd_set rfds; struct fd_set wfds; struct fd_set xfds; struct timeval now; struct timeval delay; SSFN *s; DSFN *d; if (qptr >= qfill) { qptr = 0; qfill = 0; } top:; while (1) { gettimeofday(&now,0); nowsec = now.tv_sec; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); delay.tv_sec = 0; delay.tv_usec = 0; for (s=ssfns;s;s=s->link) (*s->fn)(&rfds,&wfds,&xfds,&now,&delay); select(FD_SETSIZE,&rfds,&wfds,&xfds,&delay); for (d=dsfns;d;d=d->link) if ((*d->fn)(&rfds,&wfds,&xfds)) goto top; q_timers(&now); if (!blocking || (qfill > 0)) return; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); delay = tvsub(next_timer,now); for (s=ssfns;s;s=s->link) (*s->fn)(&rfds,&wfds,&xfds,&now,&delay); select(FD_SETSIZE,&rfds,&wfds,&xfds,&delay); } } static void qping(void) { static int count = 0; if (count < 1) { qrefill(0); count = 20; } else { count --; } } static void vtx(float xarg, float yarg) { int x; int y; x = rintf((xarg * curmatrix.v[0][0]) + (yarg * curmatrix.v[1][0]) + curmatrix.v[2][0]); y = rintf((xarg * curmatrix.v[0][1]) + (yarg * curmatrix.v[1][1]) + curmatrix.v[2][1]); switch (curmode) { case M_NONE: fprintf(stderr,"%s: invalid vertex\n",__progname); abort(); break; case M_POINT: #ifdef TRACE_ODEV fprintf(stderr,"[point (%d,%d)]\n",x,y); #endif (*odev->point)(x,y); qping(); break; case M_LINE_B: #ifdef TRACE_ODEV fprintf(stderr,"[line (%d,%d)-(%d,%d)]\n",linelast_x,linelast_y,x,y); #endif (*odev->line)(linelast_x,linelast_y,x,y); qping(); if (0) { case M_LINE_A: curmode = M_LINE_B; } linelast_x = x; linelast_y = y; break; case M_CLOSEDLINE_B: #ifdef TRACE_ODEV fprintf(stderr,"[line (%d,%d)-(%d,%d)]\n",linelast_x,linelast_y,x,y); #endif (*odev->line)(linelast_x,linelast_y,x,y); qping(); if (0) { case M_CLOSEDLINE_A: curmode = M_CLOSEDLINE_B; closedline_x0 = x; closedline_y0 = y; } linelast_x = x; linelast_y = y; break; default: fprintf(stderr,"%s: invalid curmode\n",__progname); abort(); break; } } void makeqentry(long int dev, short int val) { static int backoff = 1; static int bcnt = 0; if (qfill >= QSIZE-1) { if (qptr > 0) { bcopy(&q_dev[qptr],&q_dev[0],(qfill-qptr)*sizeof(q_dev[0])); bcopy(&q_val[qptr],&q_val[0],(qfill-qptr)*sizeof(q_val[0])); qfill -= qptr; qptr = 0; } else { if (bcnt == 0) { fprintf(stderr,"makeqentry: entry lost, queue full (%ld %d)\n",dev,val); } bcnt ++; if (bcnt >= backoff) { backoff += (backoff >> 1) + 1; if (backoff > 50) exit(0); bcnt = 0; } return; } } if (bcnt > 0) { bcnt --; } else if (backoff > 1) { backoff --; } q_dev[qfill] = dev; q_val[qfill] = val; qfill ++; } void q_timers(struct timeval *when) { if (when->tv_sec > next_timer.tv_sec+10) abort(); while (tvless(next_timer,*when)) { int i; static int timerdevs[3] = { TIMER0, TIMER1, TIMER2 }; for (i=0;i<3;i++) { if (++timercount[i] >= timernoise[i]) { timercount[i] -= timernoise[i]; makeqentry(timerdevs[i],0); } } inc_timer(); } } unsigned long int cursec(void) { return(nowsec); } #define U(x) x __attribute__((__unused__)) void foreground(void) { } void prefposition(U(long int a), U(long int b), U(long int c), U(long int d)) { } void winopen(U(const char *a)) { } void fullscrn(void) { } void RGBmode(void) { } void doublebuffer(void) { } void viewport(U(Screencoord a), U(Screencoord b), U(Screencoord c), U(Screencoord d)) { } void ortho2(U(Coord a), U(Coord b), U(Coord c), U(Coord d)) { } void cursoff(void) { } void cpack(U(unsigned long int a)) { } #undef U void gconfig(void) { int i; if (idev) { if (! (*idev->setup)(idevpath)) { fprintf(stderr,"%s: can't use keyboard module `%s'",__progname,idev->name); if (idevpath) fprintf(stderr," (path %s)",idevpath); fprintf(stderr,"\n"); exit(1); } } else { for (i=0;;i++) { idev = idevs[i]; if (idev == 0) { fprintf(stderr,"%s: can't find a keyboard to use",__progname); if (idevpath) fprintf(stderr," (path %s)",idevpath); fprintf(stderr,"\n"); exit(1); } if ((*idev->probe)(idevpath)) break; } } if (odev) { if (! (*odev->setup)(odevpath)) { fprintf(stderr,"%s: can't use screen module `%s'",__progname,odev->name); if (odevpath) fprintf(stderr," (path %s)",odevpath); fprintf(stderr,"\n"); exit(1); } } else { for (i=0;;i++) { odev = odevs[i]; if (odev == 0) { fprintf(stderr,"%s: can't find a screen to use",__progname); if (odevpath) fprintf(stderr," (path %s)",odevpath); fprintf(stderr,"\n"); exit(1); } if ((*odev->probe)(odevpath)) break; } } gettimeofday(&next_timer,0); timer_inc = 1000000 / TICKS_PER_SEC; next_timer.tv_sec ++; curmatrix.v[0][0] = 1; curmatrix.v[1][0] = 0; curmatrix.v[2][0] = 0; curmatrix.v[0][1] = 0; curmatrix.v[1][1] = -1; curmatrix.v[2][1] = YMAXSCREEN - 1; mstack = 0; curmode = M_NONE; timernoise[0] = 1; timernoise[1] = 1; timernoise[2] = 1; timercount[0] = 0; timercount[1] = 0; timercount[2] = 0; qfill = 0; qptr = 0; } void closegl(void) { (*idev->shutdown)(); #ifdef TRACE_ODEV fprintf(stderr,"[shutdown]\n"); #endif (*odev->shutdown)(); } void qdevice(int dev) { SETBIT(devqueued,dev); } void unqdevice(int dev) { CLRBIT(devqueued,dev); } void popmatrix(void) { if (mstack) { MSTACK *m; curmatrix = mstack->mat; m = mstack->link; free(mstack); mstack = m; } else { fprintf(stderr,"%s: unmatched popmatrix\n",__progname); abort(); } } void pushmatrix(void) { MSTACK *m; m = malloc(sizeof(MSTACK)); m->mat = curmatrix; m->link = mstack; mstack = m; } void clear(void) { #ifdef TRACE_ODEV fprintf(stderr,"[clear]\n"); #endif (*odev->clear)(); qping(); } void swapbuffers(void) { #ifdef TRACE_ODEV fprintf(stderr,"[swap]\n"); #endif (*odev->swap)(); qping(); } void bgnclosedline(void) { if (curmode != M_NONE) { fprintf(stderr,"%s: invalid bgnclosedline\n",__progname); abort(); } curmode = M_CLOSEDLINE_A; } void bgnline(void) { if (curmode != M_NONE) { fprintf(stderr,"%s: invalid bgnline\n",__progname); abort(); } curmode = M_LINE_A; } void bgnpoint(void) { if (curmode != M_NONE) { fprintf(stderr,"%s: invalid bgnpoint\n",__progname); abort(); } curmode = M_POINT; } void endclosedline(void) { switch (curmode) { case M_CLOSEDLINE_A: break; case M_CLOSEDLINE_B: #ifdef TRACE_ODEV fprintf(stderr,"[line (%d,%d)-(%d,%d)]\n",linelast_x,linelast_y,closedline_x0,closedline_y0); #endif (*odev->line)(linelast_x,linelast_y,closedline_x0,closedline_y0); qping(); break; default: fprintf(stderr,"%s: invalid endclosedline\n",__progname); abort(); } curmode = M_NONE; } void endline(void) { if ((curmode != M_LINE_A) && (curmode != M_LINE_B)) { fprintf(stderr,"%s: invalid endline\n",__progname); abort(); } curmode = M_NONE; } void endpoint(void) { if (curmode != M_POINT) { fprintf(stderr,"%s: invalid endpoint\n",__progname); abort(); } curmode = M_NONE; } void loadmatrix(Matrix m) { curmatrix = m; } Matrix getmatrix_(void) { return(curmatrix); } void scale(float x, float y, float z __attribute__((__unused__))) { curmatrix.v[0][0] *= x; curmatrix.v[0][1] *= x; curmatrix.v[1][0] *= y; curmatrix.v[1][1] *= y; } void translate(Coord x, Coord y, Coord z __attribute__((__unused__))) { curmatrix.v[2][0] += (curmatrix.v[0][0] * x) + (curmatrix.v[1][0] * y); curmatrix.v[2][1] += (curmatrix.v[0][1] * x) + (curmatrix.v[1][1] * y); } void rot(float angle, char axis __attribute__((__unused__))) { float c; float s; float t; angle *= M_PI / 180; s = sinf(angle); c = cosf(angle); t = curmatrix.v[0][0]; curmatrix.v[0][0] = (t * c) + (curmatrix.v[1][0] * s); curmatrix.v[1][0] = (t * -s) + (curmatrix.v[1][0] * c); t = curmatrix.v[0][1]; curmatrix.v[0][1] = (t * c) + (curmatrix.v[1][1] * s); curmatrix.v[1][1] = (t * -s) + (curmatrix.v[1][1] * c); } void v2f(const float *v) { vtx(v[0],v[1]); } void v2i(const long int *v) { vtx(v[0],v[1]); } void noise(int dev, int noise) { switch (dev) { case TIMER0: timernoise[0] = noise; break; case TIMER1: timernoise[1] = noise; break; case TIMER2: timernoise[2] = noise; break; } } long int qread(short int *valp) { if (qptr >= qfill) qrefill(1); *valp = q_val[qptr]; return(q_dev[qptr++]); } void qreset(void) { do { qrefill(0); } while (qptr < qfill); } int qtest(void) { if (qptr >= qfill) qrefill(0); return(qptrname) == nlen) && !bcmp(idevs[i]->name,name,nlen) ) { idev = idevs[i]; idevpath = colon ? colon+1 : 0; return(0); } } return(1); } int setodev(const char *name) { int i; const char *colon; int nlen; nlen = strlen(name); colon = index(name,':'); if (colon) { nlen = colon - name; if (nlen == 0) { odev = 0; odevpath = colon + 1; return(0); } } for (i=0;odevs[i];i++) { if ( (strlen(odevs[i]->name) == nlen) && !bcmp(odevs[i]->name,name,nlen) ) { odev = odevs[i]; odevpath = colon ? colon+1 : 0; return(0); } } return(1); } void listidev(void (*fn)(const char *, const char *)) { int i; for (i=0;idevs[i];i++) (*fn)(idevs[i]->name,idevs[i]->desc); } void listodev(void (*fn)(const char *, const char *)) { int i; for (i=0;odevs[i];i++) (*fn)(odevs[i]->name,odevs[i]->desc); } const char *keyname(int key) { return((*idev->keyname)(key)); } void register_setselect(void (*fn)(fd_set *, fd_set *, fd_set *, struct timeval *, struct timeval *)) { SSFN *s; s = malloc(sizeof(SSFN)); s->fn = fn; s->link = ssfns; ssfns = s; } void register_doselect(int (*fn)(fd_set *, fd_set *, fd_set *)) { DSFN *d; d = malloc(sizeof(DSFN)); d->fn = fn; d->link = dsfns; dsfns = d; }