home *** CD-ROM | disk | FTP | other *** search
- /* > Tessera
- * David McQuillan Aug 83
- */
-
- /* #define TRACE */
- /* #define TIMING */
-
- #include <setjmp.h>
- #include <signal.h>
- #include <math.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- #ifdef TIMING
- #include <time.h>
- #endif
-
- #include "swis.h"
- #include "kernel.h"
- #include "ploth.h"
-
- typedef enum{FALSE, TRUE} bool;
- typedef unsigned char small;
-
- static small v1[48] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 0, 0, 0, 0, 3, 3, 3, 3,
- 5, 5, 5, 5, 6, 6, 6, 6,
- 9, 9, 9, 9, 10, 10, 10, 10,
- 12, 12, 12, 12, 15, 15, 15, 15};
-
- static small v2[48] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 1, 2, 4, 8, 1, 2, 7, 11,
- 4, 7, 1, 13, 7, 4, 2, 14,
- 8, 11, 13, 1, 11, 8, 14, 2,
- 13, 14, 8, 4, 14, 13, 11, 7};
-
- static small p2[4] = {1, 2, 4, 8};
-
- static small dimcol[4][2] = {{8,6},{9,14},{10,13},{11,12}};
-
- static unsigned colour[16];
-
- typedef int ifloat;
-
- #define ISCALE 30
- #define IMULT (1<<ISCALE)
-
- #define ICONV(x) ((ifloat)(IMULT * (x)))
- #define ITIMES(x,y) MulScale(x, y, ISCALE)
- #define IDIV(x,y) DivScale(x, y, ISCALE)
- #define ITIMES0(x,y) ((x)>>(ISCALE/2))*((y)>>(ISCALE/2))
-
- typedef int ffloat;
-
- #define FSCALE 20
- #define FMULT (1<<FSCALE)
-
- #define FCONV(x) ((ffloat)(FMULT * (x)))
- #define FTIMES(x,y) MulScale(x, y, FSCALE)
- #define FTIMES0(x,y) (((x)*(y)) >> FSCALE)
-
- #define ITOF(x) ((x) >> (ISCALE-FSCALE))
-
- #define R2 1.414213962373095
- #define PI 3.141592653589793
-
- #define FPI2 (ffloat)(2*PI*FMULT + 0.5)
- #define FPI (ffloat)(PI*FMULT + 0.5)
-
- #define QSCALE 8
- #define QMULT (1 << QSCALE)
- #define QSIZE (int)(PI/2*QMULT + 2)
-
- static ifloat icos1[QSIZE], icos2[QMULT];
- static ifloat isin1[QSIZE], isin2[QMULT];
-
- static ffloat recip[1000];
-
- static ifloat t[4][4] = {
- IMULT, 0, 0, 0,
- 0, IMULT, 0, 0,
- 0, 0, IMULT, 0,
- 0, 0, 0, IMULT};
-
- #define SIZE 512
- #define EPS 0.1
-
- static void isincos(ffloat t, ifloat *s, ifloat *c);
- static ifloat iasin(ifloat x);
- static void ptor(int x, int y, ffloat *t, int *r);
- static double max_width(double hd, double rd);
- static void rot(int a, int b, ifloat s, ifloat c);
-
-
- /*
- * interrupt
- */
-
- typedef struct
- {
- jmp_buf js;
- } jmp_struct;
-
- static jmp_struct err_jmp;
-
- static void interrupt(int type)
- {
- switch (type)
- {
- case SIGINT:
- fprintf(stderr, "\nEscape pressed\n");
- break;
- default:
- fprintf(stderr, "\nSignal type %d\n", type);
- }
- longjmp(err_jmp.js, 1);
- }
-
- static void vdu(int c)
- {
- _kernel_oswrch(c);
- }
-
- static void palette(int l, int p, int r, int g, int b)
- {
- vdu(19);
- vdu(l);
- vdu(p);
- vdu(r);
- vdu(g);
- vdu(b);
- }
-
- #define SolidBoth 0x00
- #define TriangleFill 0x50
- #define Circle 0x90
- #define CircleFill 0x98
- #define DrawRelFore 1
- #define MoveCursorAbs 4
- #define DrawAbsFore 5
-
- static void mouse(int *x, int *y, int *b)
- {
- _kernel_swi_regs regs;
-
- _kernel_swi(OS_Mouse, ®s, ®s);
- *x = regs.r[0];
- *y = regs.r[1];
- *b = regs.r[2];
- }
-
-
- int main(void)
- {
- int i, j, k;
- bool reveal = FALSE;
- double fact = 1;
- double hd = 4;
- double rd = 6;
- double scmax;
- double scmult;
- ffloat ihd;
- ffloat ird;
- ffloat iscmult;
- int old_x, old_y;
- ffloat r1, t1;
- ifloat st1, ct1;
- ifloat sr1, cr1;
- bool bp[16];
- ffloat p[16][4];
- int ff[16], px[16], py[16];
- int pz[48];
- small seq[48];
-
- #ifdef TIMING
- clock_t clockval;
- int iter = 0;
- #endif
-
- if (setjmp(err_jmp.js))
- {
- plot_end();
- exit(0);
- }
- signal(SIGINT, *interrupt);
-
- /* set up trig values */
-
- for (i=0; i < QSIZE; ++i)
- {
- double qi = i*1.0 / (1 << QSCALE);
-
- isin1[i] = ICONV(sin(qi));
- icos1[i] = ICONV(cos(qi));
- }
-
- for (i=0; i < QMULT; ++i)
- {
- double qi = i*1.0 / (1 << (2*QSCALE));
-
- isin2[i] = ICONV(sin(qi));
- icos2[i] = ICONV(cos(qi));
- }
-
- recip[0] = FMULT;
- for (i=1; i < 999; i++)
- {
- recip[i] = FMULT/i;
- }
-
- /* Set up Screen */
- /* two banks */
- /* origin at centre */
- /* mouse on */
-
- if (plot_init() != 0)
- {
- plot_end();
- return 0;
- }
-
- /* Set up initial conditions */
-
- scmax = fact * max_width(hd, rd);
- scmult = 1 / scmax;
- ihd = FCONV(hd);
- ird = FCONV(rd);
- iscmult = FCONV(scmult);
-
- /* Set up colours */
-
- palette( 0, 16, 180, 221, 221); /* centre of lines */
- palette( 1, 16, 221, 221, 221); /* light background circle */
- palette( 2, 16, 255, 255, 255); /* background colour */
- palette( 7, 16, 0, 0, 0);
-
- palette( 6, 16, 80, 80, 80);
- palette( 8, 16, 255, 0, 0);
- palette( 9, 16, 0, 255, 0);
- palette(10, 16, 0, 0, 255);
- palette(11, 16, 0, 0, 0);
- palette(12, 16, 255, 255, 255);
- palette(13, 16, 80, 80, 80);
- palette(14, 16, 80, 80, 80);
-
- palette(15, 16, 80, 0, 0); /* outside of lines */
-
- for (i = 0; i <= 15; i++)
- {
- unsigned col = 0;
-
- for (j = 0; j <= 3; j++)
- {
- col |= dimcol[j][(i & (1<<j)) ? 1 : 0] << (4*j);
- }
- col = ((col & 0xFF00) << 8) | (col & 0xFF);
- colour[i] = col | (col << 8);
- }
-
- for (i = 0; i <= 47; i++)
- {
- seq[i] = i;
- }
-
- /* Set up Initial Position */
-
- for (i = 0; i <= 5; i++)
- {
- ifloat s, c;
-
- s = ICONV(sin(0.1));
- c = ICONV(cos(0.1));
-
- for (j = 1; j <= 3; j++)
- {
- rot(j, 0, s, c);
- }
- }
-
- /* button is pressed on entry ! */
-
- {
- int b;
-
- mouse(&old_x, &old_y, &b);
-
- ptor(old_x, old_y, &r1, &t1);
- r1 = r1 * FCONV(PI/800);
-
- isincos(r1, &sr1, &cr1);
- isincos(t1, &st1, &ct1);
- }
-
- #ifdef TIMING
- /* init timer */
-
- clockval = clock();
- #endif
-
- /* Loop Displaying Tesseract */
-
- do
- {
- /* Get mouse input */
-
- {
- int b, x, y;
- ffloat r2, t2;
- ifloat st2, ct2;
- ifloat sr2, cr2;
-
- mouse(&x, &y, &b);
- b &= 7;
-
- ptor(x, y, &r2, &t2);
- r2 = r2 * FCONV(PI/800);
-
- isincos(t2, &st2, &ct2);
- isincos(r2, &sr2, &cr2);
-
- if (b == 6)
- {
- reveal = TRUE;
- }
- else if (b == 3)
- {
- reveal = FALSE;
- }
- else if ((b == 1 || b == 2 || b == 4)
- && (x != old_x || y != old_y))
- {
- ffloat r3, t3;
- ifloat x2, y2, z2;
- ifloat x3, y3, z3;
- bool in_out = ((b & 2) != 0);
- ifloat st3, ct3;
- ifloat sr3, cr3;
-
- /* turn 1 on z axis till on xz plane */
-
- x2 = ITIMES0(sr2, ITIMES0(ct2, ct1) + ITIMES0(st2, st1));
- y2 = ITIMES0(sr2, ITIMES0(st2, ct1) - ITIMES0(ct2, st1));
- z2 = cr2;
-
- /* turn 1 on y axis till z == 1 */
-
- x3 = ITIMES0(x2, cr1) - ITIMES0(z2, sr1);
- y3 = y2;
- z3 = ITIMES0(x2, sr1) + ITIMES0(z2, cr1);
-
- /* turn 2 on z axis till y == 0 */
-
- ptor(x3, y3, &r3, &t3);
-
- /* turn till 1 goes to 2 on y axis */
-
- r3 = ITOF(iasin(r3));
-
- isincos(t3, &st3, &ct3);
- isincos(r3, &sr3, &cr3);
-
- if (in_out)
- {
- double nfact, nhd, nrd;
- double lmax;
-
- nfact = fact * (1 + EPS*ct1/IMULT*ct3/IMULT*r3/FMULT);
- nhd = hd * (1 - EPS*st1/IMULT*ct3/IMULT*r3/FMULT);
- nrd = rd * (1 - EPS*r1/FMULT*st3/IMULT*r3/FMULT);
-
- lmax = nfact * max_width(nhd, nrd);
-
- if (lmax < scmax && lmax > scmax/100)
- {
- fact = nfact;
- hd = nhd;
- rd = nrd;
-
- scmult = fact / scmax;
-
- ihd = FCONV(hd);
- ird = FCONV(rd);
- iscmult = FCONV(scmult);
- }
- }
- else
- {
- bool hyper = ((b & 4) != 0);
-
- /* position as described above */
-
- rot(1, 2, -st1, ct1);
-
- rot(3, 1, -sr1, cr1);
-
- rot(1, 2, -st3, ct3);
-
- /* if hyper then cross-product to x axis */
-
- if (hyper)
- rot(1, 0, -sr3, cr3);
- else
- rot(3, 1, sr3, cr3);
-
- /* reverse manipulations */
-
- rot(1, 2, st3, ct3);
-
- rot(3, 1, sr1, cr1);
-
- rot(1, 2, st1, ct1);
- }
- }
-
- old_x = x;
- old_y = y;
- t1 = t2;
- r1 = r2;
- ct1 = ct2;
- st1 = st2;
- cr1 = cr2;
- sr1 = sr2;
- }
-
- /* Generate Vertices */
-
- for (j = 0; j <= 3; j++)
- {
- p[0][j] = ITOF(t[0][j]) + ITOF(t[1][j])
- + ITOF(t[2][j]) + ITOF(t[3][j]);
-
- for (k = 0; k <= 3; k++)
- {
- ffloat x = p2[k];
- ffloat r = 2 * ITOF(t[k][j]);
-
- for (i=0; i < x; i++)
- p[x+i][j] = p[i][j] - r;
- }
- }
-
- /* See which cubes and so which vertices are visible */
-
- {
- int vism = 0;
- int posm = 0;
-
- if (reveal)
- {
- for (j = 0; j <= 15; j++)
- {
- bp[j] = TRUE;
- }
- }
- else
- {
- for (k = 0; k <= 3; k++)
- {
- ffloat tk0 = ITOF(t[k][0]);
-
- if (FTIMES((tk0 > 0 ? tk0 : -tk0), ihd) > FMULT)
- vism |= p2[k];
-
- if (tk0 > 0)
- posm |= p2[k];
- }
-
- for (j = 0; j <= 15; j++)
- {
- bp[j] = (((j ^ posm) & vism) != 0);
- }
- }
- }
-
- /* Generate X Perspective */
-
- {
- for (k = 0; k <= 15; k++)
- {
- int g = iscmult /
- ((FTIMES(ihd-p[k][0], ird) - p[k][3]) / SIZE);
-
- ff[k] = g / 4;
- px[k] = FTIMES0(g, p[k][1]);
- py[k] = FTIMES0(g, p[k][2]);
- pz[k] = FTIMES0(g, p[k][3]);
- }
- }
-
- /*
- * Order vertices and lines by distance
- * Not perfect 3D but seems to work okay mostly
- * Should be almost in order already
- */
-
- {
- small *pv1 = v1;
- small *pv2 = v2;
- int *ppz = pz;
-
- for (i = 16; i <= 47; i++ )
- ppz[i] = (ppz[pv1[i]] + ppz[pv2[i]]) >> 1;
- }
-
- {
- int *ppz = pz;
- small *pseq = seq;
- int sk = pseq[0];
- int pzk = ppz[sk];
-
- for (k = 1; k <= 47; k++)
- {
- int sn;
- int pzn;
-
- if (pzk > (pzn = ppz[sn = pseq[k]]))
- {
- int n = k;
-
- do
- {
- pseq[n] = sk;
- n --;
- } while (n >= 1 && ppz[sk = pseq[n-1]] > pzn);
-
- pseq[n] = sn;
-
- sn = pseq[k];
- pzn = ppz[sn];
- }
-
- sk = sn;
- pzk = pzn;
- }
- }
-
- /* Start New Screen */
-
- plot_begin();
-
- #ifdef TIMING
- if (iter == 100)
- {
- clock_t oldclock = clockval;
-
- vdu(31);
- vdu(0);
- vdu(0);
- clockval = clock();
-
- printf("%4d\n", (100*CLOCKS_PER_SEC)/(clockval-oldclock));
- iter=0;
- }
- iter++;
- #endif
-
- /* Draw Vertex Spheres and lines */
-
- {
- for (k = 0; k <= 47; k++)
- {
- int i = seq[k];
-
- if (i <= 15 && bp[i])
- {
- plot_circlefill(px[i], py[i], ff[i], colour[i]);
- }
- else if (i > 15 && bp[v1[i]] && bp[v2[i]])
- {
- int a = v1[i];
- int b = v2[i];
- int xa = px[a];
- int xb = px[b];
- int ya = py[a];
- int yb = py[b];
- int za = pz[a];
- int zb = pz[b];
- int fa = ff[a];
- int fb = ff[b];
- int dx = xb - xa;
- int dy = yb - ya;
- int dz = zb - za;
-
- int dr2 = dx * dx + dy * dy;
- int ds2 = dr2 + dz * dz;
- int ds;
- int w1, w2;
-
- ffloat ids;
-
- ds = 4 * (fa + fb);
- ds = ((ds + FTIMES0(ds2, recip[ds])) >> 1);
- ds = ((ds + FTIMES0(ds2, recip[ds])) >> 1);
-
- ids = recip[ds+7];
- w1 = fa*ids;
- w2 = fb*ids;
- xa += FTIMES0(dx, w1);
- ya += FTIMES0(dy, w1);
- xb -= FTIMES0(dx, w2);
- yb -= FTIMES0(dy, w2);
-
- plot_line(xa, ya, xb, yb);
- /*
- {
- int dr;
- int qxa, qya, qxb, qyb;
- ffloat idr;
-
- dr = dx * dx + dy * dy;
- dr = (dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy) + 1;
- dr = (dr + dr2*recip[dr]/FMULT) >> 1;
- idr = recip[dr];
-
- qxa = fa*dy*idr/FMULT >> 3;
- qya = -fa*dx*idr/FMULT >> 3;
- qxb = fb*dy*idr/FMULT >> 3;
- qyb = -fb*dx*idr/FMULT >> 3;
-
- gcol(0, 5);
- plot(MoveCursorAbs, xa+qxa, ya+qya);
- plot(MoveCursorAbs, xa-qxa, ya-qya);
- plot(DrawAbsFore+TriangleFill, xb+qxb, yb+qyb);
- plot(DrawAbsFore+TriangleFill, xb-qxb, yb-qyb);
-
- gcol(0, 2);
- plot(MoveCursorAbs, xa, ya);
- plot(DrawAbsFore+SolidBoth, xb, yb);
- }
- */
- }
- }
- }
-
- /* screen done - display it */
- /* escape pressed if 1 returned */
- }
- while (plot_show() == 0);
-
- plot_end();
-
- return 0;
- }
-
- /*
- * Max width of Tesseract
- * so all checks can be removed
- * that points are on screen if
- * desired.
- */
-
- static double max_width(double hd, double rd)
- {
- double r1 = 2.25; /* diagonal plus ball */
- double r2 = r1 / sqrt(hd*hd - r1*r1);
- double r3 = r2 / sqrt(rd*rd - r2*r2);
-
- return r3;
- }
-
- /*
- * Move on hypersphere
- * Parallel displacement X, Y or Z
- * or Rotation X, Y or Z
- */
-
- static void rot(int a, int b, ifloat s, ifloat c)
- {
- int i;
-
- for (i = 0; i <= 3; i++)
- {
- /*
- ifloat w0 = t[i][b];
- ifloat w1 = t[i][a];
-
- t[i][b] = ITIMES(c, w0) + ITIMES(s, w1);
- t[i][a] = -ITIMES(s, w0) + ITIMES(c, w1);
- */
- CrossMul(s, c, &t[i][b], &t[i][a]);
- }
- }
-
- /* sin and cos of angle */
-
- static void isincos(ffloat t, ifloat *s, ifloat *c)
- {
- ffloat tp, tq, t1, t2;
- ifloat s1, c1, s2, c2, ss, cc;
-
- while (t <= -FPI) t += FPI2;
- while (t > FPI) t -= FPI2;
-
- tp = (t >= 0 ? t : -t);
- tq = (tp >= (FPI/2) ? FPI-tp : tp);
-
- #if (FSCALE > 2*QSCALE)
- t1 = tq >> (FSCALE - 2*QSCALE);
- #else
- t1 = tq << (2*QSCALE - FSCALE);
- #endif
-
- t2 = t1 & (QMULT-1);
- t1 = t1 >> QSCALE;
-
- s1 = isin1[t1];
- c1 = icos1[t1];
- s2 = isin2[t2];
- c2 = icos2[t2];
- ss = ITIMES(s1, c2) + ITIMES(c1, s2);
- cc = ITIMES(c1, c2) - ITIMES(s1, s2);
- if (t < 0) ss = -ss;
- if (tp >= (FPI/2)) cc = -cc;
- *s = ss;
- *c = cc;
- }
-
-
- static ifloat sqrt2[] = {
- ICONV( 0.00098843065718),
- ICONV( 0.00079479950957),
- ICONV(-0.0035890535377),
- ICONV( 0.011028809744),
- ICONV(-0.044195203560),
- ICONV( 0.35355338194),
- ICONV( 1.41421356237)
- };
-
- static ifloat sqrt1[] = {
- ICONV( 0.0135199291026),
- ICONV(-0.0226657767832),
- ICONV( 0.0278720776889),
- ICONV(-0.0389582788321),
- ICONV( 0.0624811144548),
- ICONV(-0.125001503933),
- ICONV( 0.5),
- ICONV( 1.0)
- };
-
- static ifloat atn[] = {
- ICONV( 0.0805374449538),
- ICONV(-0.138776856032),
- ICONV( 0.199777106478),
- ICONV(-0.333329491539),
- ICONV( 1.0)
- };
-
- static ifloat asn[] = {
- ICONV( 0.042163199048),
- ICONV( 0.024181311049),
- ICONV( 0.045470025998),
- ICONV( 0.074953002686),
- ICONV( 0.16666752422),
- ICONV( 1.0)
- };
-
- /* Low precision polynomial evaluate */
-
- static ifloat i0polevl(ifloat x, ifloat *coef, int N)
- {
- ifloat ans = *coef++;
-
- do
- ans = ITIMES0(ans, x) + *coef++;
- while (--N);
-
- return ans;
- }
-
- /* low precision asin */
-
- static ifloat iasin(ifloat x)
- {
- ifloat x2 = ITIMES0(x, x);
-
- return ITIMES(x, i0polevl(x2, asn, 5));
- }
-
- /* low precision polar to rect */
-
- static void ptor(int x, int y, int *r, ffloat *t)
- {
- int w;
- ifloat d, r2, t1;
- int code = 0;
-
- if (x < 0)
- {
- code = 2;
- x = -x;
- }
-
- if (y < 0)
- {
- code |= 1;
- y = -y;
- }
-
- if (x == 0)
- {
- *r = y;
-
- if (code & 1)
- *t = FCONV(-PI/2);
- else if (y == 0)
- *t = 0;
- else
- *t = FCONV(PI/2);
-
- return;
- }
-
- if (y == 0)
- {
- *r = x;
-
- if (code & 2)
- *t = FCONV(PI);
- else
- *t = 0;
-
- return;
- }
-
- if (x < y)
- {
- code |= 4;
- w = y;
- y = x;
- x = w;
- }
-
- d = IDIV(y, x);
- r2 = ITIMES0(d, d);
-
- if (r2 > ICONV(R2-1))
- {
- r2 = r2 - IMULT;
- *r = ITIMES(x, i0polevl(r2, sqrt2, 6));
-
- code |= 8;
- d = IDIV(d-IMULT, d+IMULT);
- r2 = ITIMES0(d, d);
- }
- else
- {
- *r = ITIMES(x, i0polevl(r2, sqrt1, 7));
- }
-
- t1 = ITOF(ITIMES(d, i0polevl(r2, atn, 4)));
-
- if (code & 8) t1 += FCONV(PI/4);
- if (code & 4) t1 = FCONV(PI/2) - t1;
- if (code & 2) t1 = FCONV(PI) - t1;
- if (code & 1) t1 = -t1;
-
- *t = t1;
- }
-