diff options
Diffstat (limited to 'appl/wm/collide.b')
| -rw-r--r-- | appl/wm/collide.b | 2180 |
1 files changed, 2180 insertions, 0 deletions
diff --git a/appl/wm/collide.b b/appl/wm/collide.b new file mode 100644 index 00000000..1d8a2527 --- /dev/null +++ b/appl/wm/collide.b @@ -0,0 +1,2180 @@ +# +# initially generated by c2l +# + +implement Collide; + +include "draw.m"; + draw: Draw; + Display, Image: import draw; + +Collide: module +{ + init: fn(nil: ref Draw->Context, argl: list of string); +}; + +include "sys.m"; + sys: Sys; +include "tk.m"; + tk: Tk; + Toplevel: import tk; +include "tkclient.m"; + tkclient: Tkclient; +include "math.m"; + maths: Math; +include "rand.m"; + rand: Rand; +include "daytime.m"; + daytime: Daytime; +include "bufio.m"; +include "arg.m"; + arg: Arg; +include "math/polyhedra.m"; + polyhedra: Polyhedra; + +init(ctxt: ref Draw->Context, argl: list of string) +{ + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + tk = load Tk Tk->PATH; + tkclient = load Tkclient Tkclient->PATH; + maths = load Math Math->PATH; + rand = load Rand Rand->PATH; + arg = load Arg Arg->PATH; + daytime = load Daytime Daytime->PATH; + main(ctxt, argl); +} + +π: con Math->Pi; +∞: con real (1<<30); +ε: con 0.001; +√2: con 1.4142135623730950488016887242096980785696718753769486732; + +M1: con 1.0; +M2: con 1.0; +E: con 1.0; # coefficient of restitution/elasticity + +COLLIDE, REFLECT: con 1<<iota; + +MAXX, MAXY: con 512; + +RDisp: ref Draw->Image; +black, white, red: ref Draw->Image; +display: ref Draw->Display; +toplev: ref Toplevel; + +Vector: adt{ + x: real; + y: real; + z: real; +}; + +Line: adt{ + a: Vector; + d: Vector; # normalized +}; + +Plane: adt{ + id: int; + n: Vector; # normalized + d: real; + min: Vector; + max: Vector; + far: Vector; + v: array of Vector; +}; + +Object: adt{ + id: int; + poly: ref Polyhedra->Polyhedron; # if any + c: ref Draw->Image; # colour + cb: ref Draw->Image; # border colour + l: ref Line; # initial point and direction + p: Vector; # current position + rp: Vector; # position after reflection + cp: Vector; # any collision point + rt: real; # time to reflection + ct: real; # time to collision + plane: ref Plane; # reflecting off + pmask: int; # plane mask + obj: cyclic ref Object; # colliding with + v: real; # speed + ω: real; # speed of rotation + roll: real; # roll + pitch: real; # pitch + yaw: real; # yaw + todo: int; # work to do +}; + +planes: list of ref Plane; + +V0: con Vector(real 0, real 0, real 0); +VZ: con Vector(0.0, 0.0, 1.0); + +far: Vector; + +DOCIRCLE: con 1; +POLY, FILLPOLY, CIRCLE, FILLCIRCLE, ELLIPSE, FILLELLIPSE: con iota; + +# +# final object is centred on (0, 0, -objd) +# viewer is at origin looking along (0 0 -1) +# +maxx, maxy: int; + +SCRW: con 320; # screen width +SCRH: con 240; # screen height + +frac := 0.5; # % of screen for cube +front := 0.5; # % of cube in front of screen +hpar := 0.0; # horizontal parallax +fov := -1.0; # field of view : 0 for parallel projection, -1 for unspecified +objd := 500.0; # eye to middle of cube +cubd := 100.0; # half side of cube +icubd: real; # half side of inner cube +icubd2: real; # square of above +eyed := 32.0; # half eye to eye +trkd := 5.0; # side/diameter of object +trkd2: real; # square of above +rpy := 0; +roll := 0.0; # z +pitch := 0.0; # y +yaw := 0.0; # x + +scrd, objD, scrD: real; # screen distance +left := 0; # left or right eye +sx, sy, sz: real; # screen scale factors +sf: real; # perspective scale factor +fbpar: real; # -1 for front of cube, 1 for back +vf := 1.0; # current velocity factor + +cmin, cmax: Vector; # cube extents + +# special transformation matrix without roll, pitch, yaw +# this is needed so that spheres can be drawn as circles +mod0 := array[4] of array of real; + +stereo := 0; # stereopsis + +SPHERE, ELLIPSOID, CUBE, POLYHEDRON: con iota; +surr := CUBE; # surround + +poly := 0; # show polyhedra +flat: int; # objects in one plane +projx: int; # strange projection + +# ellipse parameters +ef: Vector = (1.0, 0.8, 1.0); +e2: Vector; + +# objects +nobjs: int; +objs: array of ref Object; +me: ref Object; + +# circle drawing +NC: con 72; +cost, sint: array of real; + +# polyhedra +polys: ref Polyhedra->Polyhedron; +npolys: int; +polyh: ref Polyhedra->Polyhedron; + +rgba(r: int, g: int, b: int, α: int): ref Image +{ + c := draw->setalpha((r<<24)|(g<<16)|(b<<8), α); + return display.newimage(((0, 0), (1, 1)), display.image.chans, 1, c); +} + +random(a: int, b: int): int +{ + return a+rand->rand(b-a+1); +} + +urand(): real +{ + M: con 1000; + return real random(0, M)/real M; +} + +randomr(a: real, b: real): real +{ + return a+urand()*(b-a); +} + +randomc(): ref Image +{ + r, g, b: int; + + do{ + r = random(0, 255); + g = random(0, 255); + b = random(0, 255); + }while(r+g+b < 384); + return rgba(r, g, b, 255); +} + +randomv(a: real, b: real): Vector +{ + x := randomr(a, b); + y := randomr(a, b); + if(flat) + return (x, y, (a+b)/2.0); + return (x, y, randomr(a, b)); +} + +randomd(): Vector +{ + M: con 1000.0; + v := randomv(-M, M); + while(vlen(v) == 0.0) + v = randomv(-M, M); + return vnorm(v); +} + +randomp(min: real, max: real): Vector +{ + case(surr){ + SPHERE => + return vmul(randomd(), max*maths->sqrt(urand())); + ELLIPSOID => + return vmul(randomd(), max*vmin(ef)*maths->sqrt(urand())); + CUBE => + return randomv(min, max); + * => + v := randomv(min, max); + while(outside3(v, cmin, cmax)) + v = randomv(min, max); + return v; + } +} + +det(a: real, b: real, c: real, d: real): real +{ + return a*d-b*c; +} + +simeq(a: real, b: real, c: real, d: real, e: real, f: real): (real, real) +{ + de := det(a, b, c, d); + return (det(e, b, f, d)/de, det(a, e, c, f)/de); +} + +cksimeq(a: real, b: real, c: real, d: real, e: real, f: real): (int, real, real) +{ + ade := de := det(a, b, c, d); + if(ade < 0.0) + ade = -ade; + if(ade < ε) + return (0, 0.0, 0.0); + return (1, det(e, b, f, d)/de, det(a, e, c, f)/de); +} + +ostring(o: ref Object): string +{ + return lstring(o.l) + "+" + vstring(o.p) + "+" + string o.v; +} + +pstring(p: ref Plane): string +{ + return vstring(p.n) + "=" + string p.d; +} + +lstring(l: ref Line): string +{ + return vstring(l.a) + "->" + vstring(l.d); +} + +vstring(v: Vector): string +{ + return "(" + string v.x + " " + string v.y + " " + string v.z + ")"; +} + +vpt(x: real, y: real, z: real): Vector +{ + p: Vector; + + p.x = x; + p.y = y; + p.z = z; + return p; +} + +vdot(v1: Vector, v2: Vector): real +{ + return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z; +} + +vcross(v1: Vector, v2: Vector): Vector +{ + v: Vector; + + v.x = v1.y*v2.z-v1.z*v2.y; + v.y = v1.z*v2.x-v1.x*v2.z; + v.z = v1.x*v2.y-v1.y*v2.x; + return v; +} + +vadd(v1: Vector, v2: Vector): Vector +{ + v: Vector; + + v.x = v1.x+v2.x; + v.y = v1.y+v2.y; + v.z = v1.z+v2.z; + return v; +} + +vsub(v1: Vector, v2: Vector): Vector +{ + v: Vector; + + v.x = v1.x-v2.x; + v.y = v1.y-v2.y; + v.z = v1.z-v2.z; + return v; +} + +vmul(v1: Vector, s: real): Vector +{ + v: Vector; + + v.x = s*v1.x; + v.y = s*v1.y; + v.z = s*v1.z; + return v; +} + +vdiv(v1: Vector, s: real): Vector +{ + v: Vector; + + v.x = v1.x/s; + v.y = v1.y/s; + v.z = v1.z/s; + return v; +} + +vlen(v: Vector): real +{ + return maths->sqrt(vdot(v, v)); +} + +vlen2(v: Vector): (real, real) +{ + d2 := vdot(v, v); + d := maths->sqrt(d2); + return (d, d2); +} + +vnorm(v: Vector): Vector +{ + d := maths->sqrt(vdot(v, v)); + if(d == 0.0) + return v; + return vmul(v, real 1/d); +} + +vnorm2(v: Vector): (real, Vector) +{ + d := maths->sqrt(vdot(v, v)); + if(d == 0.0) + return (0.0, VZ); + return (d, vmul(v, real 1/d)); +} + +clip(x: real, d: real): real +{ + if(x < -d) + x = -d; + if(x > d) + x = d; + return x; +} + +vclip(v: Vector, d: real): Vector +{ + c: Vector; + + c.x = clip(v.x, d); + c.y = clip(v.y, d); + c.z = clip(v.z, d); + return c; +} + +vout(v1: Vector, v2: Vector): int +{ + v := vsub(v2, v1); + return v.x < 0.0 || v.y < 0.0 || v.z < 0.0; +} + +vmin(v: Vector): real +{ + m := v.x; + if(v.y < m) + m = v.y; + if(v.z < m) + m = v.z; + return m; +} + +vvmul(v1: Vector, v2: Vector): Vector +{ + v: Vector; + + v.x = v1.x*v2.x; + v.y = v1.y*v2.y; + v.z = v1.z*v2.z; + return v; +} + +vvdiv(v1: Vector, v2: Vector): Vector +{ + v: Vector; + + v.x = v1.x/v2.x; + v.y = v1.y/v2.y; + v.z = v1.z/v2.z; + return v; +} + +vmuldiv(v1: Vector, v2: Vector, v3: Vector): real +{ + return vdot(vvdiv(v1, v3), v2); +} + +newp(id: int, a: real, b: real, c: real, d: real, m: real, v: array of Vector) +{ + p := ref Plane; + p.id = id; + p.n = (a, b, c); + p.d = d; + m += ε; + p.min = (-m, -m, -m); + p.max = (+m, +m, +m); + p.v = v; + if(v != nil){ + p.min = (∞, ∞, ∞); + p.max = (-∞, -∞, -∞); + for(i := 0; i < len v; i++){ + vtx := v[i]; + if(vtx.x < p.min.x) + p.min.x = vtx.x; + if(vtx.y < p.min.y) + p.min.y = vtx.y; + if(vtx.z < p.min.z) + p.min.z = vtx.z; + if(vtx.x > p.max.x) + p.max.x = vtx.x; + if(vtx.y > p.max.y) + p.max.y = vtx.y; + if(vtx.z > p.max.z) + p.max.z = vtx.z; + } + (x, y, z) := p.far = vmul(p.max, 2.0); + if(a != 0.0) + p.far.x = (d-b*y-c*z)/a; + else if(b != 0.0) + p.far.y = (d-c*z-a*x)/b; + else if(c != 0.0) + p.far.z = (d-a*x-b*y)/c; + else + fatal("null plane"); + } + planes = p :: planes; +} + +pinit() +{ + case(surr){ + SPHERE or + ELLIPSOID => + newp(0, 0.0, 0.0, 1.0, ∞, ∞, nil); + CUBE => + newp(0, 1.0, 0.0, 0.0, -icubd, icubd, nil); + newp(1, 1.0, 0.0, 0.0, +icubd, icubd, nil); + newp(2, 0.0, 1.0, 0.0, -icubd, icubd, nil); + newp(3, 0.0, 1.0, 0.0, +icubd, icubd, nil); + newp(4, 0.0, 0.0, 1.0, -icubd, icubd, nil); + newp(5, 0.0, 0.0, 1.0, +icubd, icubd, nil); + * => + p := polyh; + F := p.F; + v := p.v; + f := p.f; + fv := p.fv; + d := 0.0; + for(i := 0; i < F; i++){ + n := vnorm(f[i]); + dn := vmul(n, cubd-icubd); + fvi := fv[i]; + m := fvi[0]; + av := array[m] of Vector; + for(j := 0; j < m; j++){ + av[j] = vtx := vsub(vmul(v[fvi[j+1]], 2.0*cubd), dn); + d += vdot(n, vtx); + } + d /= real m; + newp(i, n.x, n.y, n.z, d, 0.0, av); + } + } +} + +inside(v: Vector, vmin: Vector, vmax: Vector): int +{ + return !vout(vmin, v) && !vout(v, vmax); +} + +inside2(v: Vector, p: ref Plane): int +{ + h := 0; + pt := p.far; + vs := p.v; + n := len p.v; + j := n-1; + for(i := 0; i < n; i++){ + (ok, λ, μ) := cksimeq(vs[j].x-vs[i].x, v.x-pt.x, vs[j].y-vs[i].y, v.y-pt.y, v.x-vs[i].x, v.y-vs[i].y); + if(!ok) + (ok, λ, μ) = cksimeq(vs[j].y-vs[i].y, v.y-pt.y, vs[j].z-vs[i].z, v.z-pt.z, v.y-vs[i].y, v.z-vs[i].z); + if(!ok) + (ok, λ, μ) = cksimeq(vs[j].z-vs[i].z, v.z-pt.z, vs[j].x-vs[i].x, v.x-pt.x, v.z-vs[i].z, v.x-vs[i].x); + if(ok && μ >= 0.0 && λ >= 0.0 && λ < 1.0) + h++; + j = i; + } + return h&1; +} + +inside3(v: Vector, lp: list of ref Plane): int +{ + h := 0; + l := ref Line; + l.a = v; + l.d = vnorm(vsub(far, v)); + for( ; lp != nil; lp = tl lp){ + (ok, nil, nil) := intersect(l, hd lp); + if(ok) + h++; + } + return h&1; +} + +# outside of a face +outside2(v: Vector, p: ref Plane): int +{ + if(surr == CUBE) + return vout(p.min, v) || vout(v, p.max); + else + return !inside2(v, p); +} + +# outside of a polyhedron +outside3(v: Vector, vmin: Vector, vmax: Vector): int +{ + case(surr){ + SPHERE => + return vout(vmin, v) || vout(v, vmax) || vdot(v, v) > icubd2 ; + ELLIPSOID => + return vout(vmin, v) || vout(v, vmax) || vmuldiv(v, v, e2) > 1.0; + CUBE => + return vout(vmin, v) || vout(v, vmax); + * => + return !inside3(v, planes); + } +} + +intersect(l: ref Line, p: ref Plane): (int, real, Vector) +{ + m := vdot(p.n, l.d); + if(m == real 0) + return (0, real 0, V0); + c := vdot(p.n, l.a); + λ := (p.d-c)/m; + if(λ < real 0) + return (0, λ, V0); + pt := vadd(l.a, vmul(l.d, λ)); + if(outside2(pt, p)) + return (0, λ, pt); + return (1, λ, pt); +} + +reflection(tr: ref Object, lp: list of ref Plane) +{ + ok: int; + λ: real; + + l := tr.l; + if(surr == SPHERE){ + (ok, λ) = quadratic(1.0, 2.0*vdot(l.a, l.d), vdot(l.a, l.a)-icubd2); + if(!ok || λ < 0.0) + fatal("no sphere intersections"); + tr.rp = vadd(l.a, vmul(l.d, λ)); + tr.plane = hd lp; # anything + } + else if(surr == ELLIPSOID){ + (ok, λ) = quadratic(vmuldiv(l.d, l.d, e2), 2.0*vmuldiv(l.a, l.d, e2), vmuldiv(l.a, l.a, e2)-1.0); + if(!ok || λ < 0.0) + fatal("no ellipsoid intersections"); + tr.rp = vadd(l.a, vmul(l.d, λ)); + tr.plane = hd lp; # anything + } + else{ + p: ref Plane; + pt := V0; + λ = ∞; + for( ; lp != nil; lp = tl lp){ + p0 := hd lp; + if((1<<p0.id)&tr.pmask) + continue; + (ok0, λ0, pt0) := intersect(l, p0); + if(ok0 && λ0 < λ){ + λ = λ0; + p = p0; + pt = pt0; + } + } + if(λ == ∞) + fatal("no intersections"); + tr.rp = pt; + tr.plane = p; + } + if(tr.v == 0.0) + tr.rt = ∞; + else + tr.rt = λ/tr.v; +} + +reflect(tr: ref Object) +{ + l := tr.l; + if(surr == SPHERE) + n := vdiv(tr.rp, -icubd); + else if(surr == ELLIPSOID) + n = vnorm(vdiv(vvdiv(tr.rp, e2), -1.0)); + else + n = tr.plane.n; + tr.l.a = tr.rp; + tr.l.d = vnorm(vsub(l.d, vmul(n, 2.0*vdot(n, l.d)))); +} + +impact(u2: real): (real, real) +{ + # u1 == 0 + return simeq(M1, M2, -1.0, 1.0, M2*u2, -E*u2); +} + +collision(t1: ref Object, t2: ref Object): (int, real, Vector, Vector) +{ + # stop t2 + (v3, f) := vnorm2(vsub(vmul(t1.l.d, t1.v), vmul(t2.l.d, t2.v))); + if(v3 == 0.0) + return (0, 0.0, V0, V0); + ab := vsub(t2.p, t1.p); + (d, d2) := vlen2(ab); + cos := vdot(f, ab)/d; + cos2 := cos*cos; + if(cos < 0.0 || (disc := trkd2 - d2*(1.0-cos2)) < 0.0) + return (0, 0.0, V0, V0); + s := d*cos - maths->sqrt(disc); + t := s/v3; + s1 := t1.v*t; + s2 := t2.v*t; + cp1 := vadd(t1.p, vmul(t1.l.d, s1)); + if(outside3(cp1, cmin, cmax)) + return (0, 0.0, V0, V0); + cp2 := vadd(t2.p, vmul(t2.l.d, s2)); + if(outside3(cp2, cmin, cmax)) + return (0, 0.0, V0, V0); + return (1, t, cp1, cp2); +} + +collisions(tr: ref Object) +{ + mincp1, mincp2: Vector; + + n := nobjs; + t := objs; + tr0 := tr.obj; + mint := tr.ct; + tr1: ref Object; + for(i := 0; i < n; i++){ + if((tr3 := t[i]) == tr || tr3 == tr0) + continue; + (c, tm, cp1, cp2) := collision(tr, tr3); + if(c && tm < mint && tm < tr3.ct){ + mint = tm; + tr1 = tr3; + mincp1 = cp1; + mincp2 = cp2; + } + } + if(tr1 != nil){ + tr.ct = mint; + tr1.ct = mint; + tr.obj = tr1; + tr2 := tr1.obj; + tr1.obj = tr; + tr.cp = mincp1; + tr1.cp = mincp2; + zerot(tr0, COLLIDE, 0); + zerot(tr2, COLLIDE, 0); + if(tr0 != nil && tr0 != tr2) + collisions(tr0); + if(tr2 != nil) + collisions(tr2); + } +} + +collide(t1: ref Object, t2: ref Object) +{ + # stop t2 + ov := vmul(t2.l.d, t2.v); + (v3, f) := vnorm2(vsub(vmul(t1.l.d, t1.v), ov)); + ab := vsub(t2.cp, t1.cp); + α := vdot(f, ab)/vdot(ab, ab); + abr := vsub(f, vmul(ab, α)); + (v2, v1) := impact(α*v3); + t1.l.a = t1.cp; + t2.l.a = t2.cp; + dir1 := vadd(vmul(ab, v1), vmul(abr, v3)); + dir2 := vmul(ab, v2); + # start t2 + (t1.v, t1.l.d) = vnorm2(vadd(dir1, ov)); + (t2.v, t2.l.d) = vnorm2(vadd(dir2, ov)); +} + +deg2rad(d: real): real +{ + return π*d/180.0; +} + +rad2deg(r: real): real +{ + return 180.0*r/π; +} + +rp2d(r: real, p: real): Vector +{ + r = deg2rad(r); + cr := maths->cos(r); + sr := maths->sin(r); + p = deg2rad(p); + cp := maths->cos(p); + sp := maths->sin(p); + return (cr*cp, sr*cp, sp); +} + +d2rp(v: Vector): (real, real) +{ + r := maths->atan2(v.y, v.x); + p := maths->asin(v.z); + return (rad2deg(r), rad2deg(p)); +} + +collideω(t1: ref Object, t2: ref Object) +{ + d1 := rp2d(t1.roll, t1.pitch); + d2 := rp2d(t2.roll, t2.pitch); + oω := vmul(d2, t2.ω); + (ω3, f) := vnorm2(vsub(vmul(d1, t1.ω), oω)); + ab := vsub(t2.cp, t1.cp); + α := vdot(f, ab)/vdot(ab, ab); + abr := vsub(f, vmul(ab, α)); + (ω2, ω1) := impact(α*ω3); + dir1 := vadd(vmul(ab, ω1), vmul(abr, ω3)); + dir2 := vmul(ab, ω2); + (t1.ω, d1) = vnorm2(vadd(dir1, oω)); + (t2.ω, d2) = vnorm2(vadd(dir2, oω)); + (t1.roll, t1.pitch) = d2rp(d1); + (t2.roll, t2.pitch) = d2rp(d2); +} + +plane(p1: Vector, p2: Vector, p3: Vector): (Vector, real) +{ + n := vnorm(vcross(vsub(p2, p1), vsub(p3, p1))); + d := vdot(n, p1); + return (n, d); +} + +# angle subtended by the eyes at p in minutes +angle(p: Vector): real +{ + l, r: Vector; + + # left eye at (-eyed, 0, 0) + # right eye at (+eyed, 0, 0) + # + l = p; + l.x += eyed; + r = p; + r.x -= eyed; + return real 60*(real 180*maths->acos(vdot(l, r)/(maths->sqrt(vdot(l, l))*maths->sqrt(vdot(r, r))))/π); +} + +# given coordinates relative to centre of cube +disparity(p: Vector, b: Vector): real +{ + p.z -= objd; + b.z -= objd; + return angle(p)-angle(b); +} + +# rotation about any of the axes +# rotate(theta, &x, &y, &z) for x-axis +# rotate(theta, &y, &z, &x) for y-axis +# rotate(theta, &z, &x, &y) for z-axis +# +rotate(theta: int, x: real, y: real, z: real): (real, real, real) +{ + a := π*real theta/real 180; + c := maths->cos(a); + s := maths->sin(a); + oy := y; + oz := z; + y = c*oy-s*oz; + z = c*oz+s*oy; + return (x, y, z); +} + +# solve the quadratic ax^2 + bx + c = 0, returning the larger root +# * (a > 0) +# +quadratic(a: real, b: real, c: real): (int, real) +{ + d := b*b-real 4*a*c; + if(d < real 0) + return (0, 0.0); # no real roots + x := (maths->sqrt(d)-b)/(real 2*a); + return (1, x); +} + +# calculate the values of objD, scrD given the required parallax +dopar() +{ + a := real 1; + b, c: real; + f := real 2*front-real 1; + x: real; + s: int; + w := sx*real SCRW; + ok: int; + + if(hpar == 0.0){ # natural parallax + objD = objd; + scrD = scrd; + return; + } + if(fbpar < f) + s = -1; + else + s = 1; + if(fbpar == f) + fatal("parallax value is zero at screen distance"); + b = (fbpar+f)*cubd-(fbpar-f)*w*eyed*real s*frac/hpar; + c = fbpar*f*cubd*cubd; + (ok, x) = quadratic(a, b, c); + if(ok){ + objD = x; + scrD = x+f*cubd; + if(objD > real 0 && scrD > real 0) + return; + } + fatal("unachievable parallax value"); +} + +# update graphics parameters +update(init: int) +{ + if(fov != real 0){ + if(objd == real 0) + fov = 180.0; + else + fov = real 2*(real 180*maths->atan(cubd/(frac*objd))/π); + } + scrd = objd+(real 2*front-real 1)*cubd; + if(init){ + if(objd < ε) + objd = ε; + if(fov != real 0) + sf = real (1<<2)*cubd/(objd*frac); + else + sf = cubd/frac; + } + # dopar(); + domats(); +} + +fovtodist() +{ + if(fov != real 0) + objd = cubd/(frac*maths->tan(π*(fov/real 2)/real 180)); +} + +getpolys() +{ + (n, p, b) := polyhedra->scanpolyhedra("/lib/polyhedra"); + polyhedra->getpolyhedra(p, b); + polys = p; + npolys = n; + do{ + for(i := 0; i < p.V; i++) + p.v[i] = vmul(p.v[i], 0.5); + for(i = 0; i < p.F; i++) + p.f[i] = vmul(p.f[i], 0.5); + p = p.nxt; + }while(p != polys); +} + +randpoly(p: ref Polyhedra->Polyhedron, n: int): ref Polyhedra->Polyhedron +{ + r := random(0, n-1); + for( ; --r >= 0; p = p.nxt) + ; + return p; +} + +drawpoly(p: ref Polyhedra->Polyhedron, typex: int) +{ + # V := p.V; + F := p.F; + v := p.v; + # f := p.f; + fv := p.fv; + for(i := 0; i < F; i++){ + fvi := fv[i]; + n := fvi[0]; + m_begin(typex, n); + for(j := 0; j < n; j++){ + vtx := v[fvi[j+1]]; + m_vertex(vtx.x, vtx.y, vtx.z); + } + m_end(); + } +} + +# objects with unit sides/diameter +H: con 0.5; + +square(typex: int) +{ + m_begin(typex, 4); + m_vertex(-H, -H, 0.0); + m_vertex(-H, +H, 0.0); + m_vertex(+H, +H, 0.0); + m_vertex(+H, -H, 0.0); + m_end(); +} + +diamond(typex: int) +{ + m_pushmatrix(); + m_rotatez(45.0); + square(typex); + m_popmatrix(); +} + +circleinit() +{ + i: int; + a := 0.0; + cost = array[NC] of real; + sint = array[NC] of real; + for(i = 0; i < NC; i++){ + cost[i] = H*maths->cos(a); + sint[i] = H*maths->sin(a); + a += (2.0*π)/real NC; + } +} + +circle(typex: int) +{ + i: int; + + if(DOCIRCLE){ + m_begin(typex, 2); + m_circle(0.0, 0.0, 0.0, 0.5); + m_end(); + return; + } + else{ + m_begin(typex, NC); + for(i = 0; i < NC; i++) + m_vertex(cost[i], sint[i], 0.0); + m_end(); + } +} + +ellipse(typex: int) +{ + m_begin(typex, 4); + m_ellipse(0.0, 0.0, 0.0, vmul(ef, 0.5)); + m_end(); +} + +hexahedron(typex: int) +{ + i, j, k: int; + V := array[8] of { + array[3] of { + -H, -H, -H, + }, + array[3] of { + -H, -H, +H, + }, + array[3] of { + -H, +H, -H, + }, + array[3] of { + -H, +H, +H, + }, + array[3] of { + +H, -H, -H, + }, + array[3] of { + +H, -H, +H, + }, + array[3] of { + +H, +H, -H, + }, + array[3] of { + +H, +H, +H, + }, + }; + F := array[6] of { + array[4] of { + 0, 4, 6, 2, + }, + array[4] of { + 0, 4, 5, 1, + }, + array[4] of { + 0, 1, 3, 2, + }, + array[4] of { + 1, 5, 7, 3, + }, + array[4] of { + 2, 6, 7, 3, + }, + array[4] of { + 4, 5, 7, 6, + }, + }; + + for(i = 0; i < 6; i++){ + m_begin(typex, 4); + for(j = 0; j < 4; j++){ + k = F[i][j]; + m_vertex(V[k][0], V[k][1], V[k][2]); + } + m_end(); + } +} + +zerot(tr: ref Object, zero: int, note: int) +{ + if(tr != nil){ + if(zero&REFLECT){ + tr.rt = ∞; + tr.plane = nil; + } + if(zero&COLLIDE){ + tr.ct = ∞; + tr.obj = nil; + } + if(note) + tr.todo = zero; + } +} + +newobj(t: array of ref Object, n: int, vel: int, velf: real): ref Object +{ + tr: ref Object; + p1: Vector; + again: int; + + d := icubd-1.0; + cnt := 1024; + do{ + p1 = randomp(-d, d); + again = 0; + for(i := 0; i < n; i++){ + (nil, d2) := vlen2(vsub(t[i].p, p1)); + if(d2 <= trkd2){ + again = 1; + break; + } + } + cnt--; + }while(again && cnt > 0); + if(again) + return nil; + # p2 := randomp(-d, d); + p21 := randomd(); + tr = ref Object; + tr.id = n; + tr.poly = nil; + if(poly){ + if(n == 0) + tr.poly = randpoly(polys, npolys); + else + tr.poly = t[0].poly; + } + tr.c = randomc(); + tr.cb = tr.c; # randomc(); + if(vel) + tr.v = vf*velf*randomr(0.5, 2.0); + else + tr.v = 0.0; + tr.ω = vf*randomr(1.0, 10.0); + tr.roll = randomr(0.0, 360.0); + tr.pitch = randomr(0.0, 360.0); + tr.yaw = randomr(0.0, 360.0); + tr.l = ref Line(p1, vnorm(p21)); + tr.p = p1; + tr.todo = 0; + zerot(tr, REFLECT|COLLIDE, 0); + tr.pmask = 0; + reflection(tr, planes); + return tr; +} + +objinit(m: int, v: int) +{ + velf := real m/real v; + p := nobjs; + n := p+m; + v += p; + t := array[n] of ref Object; + for(i := 0; i < p; i++) + t[i] = objs[i]; + for(i = p; i < n; i++){ + t[i] = newobj(t, i, i < v, velf); + if(t[i] == nil) + return; + } + sort(t, n); + nobjs = n; + objs = t; + for(i = p; i < n; i++) + collisions(t[i]); +} + +zobj: Object; + +newo(n: int, p: Vector, c: ref Draw->Image): ref Object +{ + o := ref Object; + *o = zobj; + o.id = n; + o.c = o.cb = c; + o.l = ref Line(p, VZ); + o.p = p; + zerot(o, REFLECT|COLLIDE, 0); + reflection(o, planes); + return o; +} + +objinits(nil: int, nil: int) +{ + n := 16; + t := array[n] of ref Object; + r := trkd/2.0; + i := 0; + yc := 0.0; + for(y := 0; y < 5; y++){ + xc := -real y*r; + for(x := 0; x <= y; x++){ + t[i] = newo(i, (xc, yc, 0.0), red); + xc += trkd; + i++; + } + yc += trkd; + } + t[i] = newo(i, (0.0, -50.0, 0.0), white); + t[i].l.d = (0.0, 1.0, 0.0); + t[i].v = 1.0; + sort(t, n); + nobjs = n; + objs = t; + for(i = 0; i < n; i++) + collisions(t[i]); +} + +initme(): ref Object +{ + t := newobj(nil, 0, 1, 1.0); + t.roll = t.pitch = t.yaw = 0.0; + t.v = t.ω = 0.0; + t.l.a = (0.0, 0.0, objd); # origin when translated + t.l.d = (0.0, 0.0, -1.0); + t.p = t.l.a; + zerot(t, REFLECT|COLLIDE, 0); + return t; +} + +retime(s: real) +{ + r := 1.0/s; + n := nobjs; + t := objs; + for(i := 0; i < n; i++){ + tr := t[i]; + tr.v *= s; + tr.ω *= s; + tr.rt *= r; + tr.ct *= r; + } + me.v *= s; + me.ω *= s; + me.rt *= r; + me.ct *= r; +} + +drawobjs() +{ + tr: ref Object; + p: Vector; + + n := nobjs; + t := objs; + + for(i := 0; i < n; i++){ + tr = t[i]; + tr.pmask = 0; + p = tr.p; + m_pushmatrix(); + if(rpy && tr.poly == nil){ + m_loadmatrix(mod0); + (p.x, p.y, p.z) = rotate(int yaw, p.x, p.y, p.z); + (p.y, p.z, p.x) = rotate(int pitch, p.y, p.z, p.x); + (p.z, p.x, p.y) = rotate(int roll, p.z, p.x, p.y); + } + m_translate(p.x, p.y, p.z); + m_scale(trkd, trkd, trkd); + if(tr.poly != nil){ + m_rotatez(tr.roll); + m_rotatey(tr.pitch); + m_rotatex(tr.yaw); + tr.yaw += tr.ω; + } + m_matmul(); + if(tr.cb != tr.c){ + m_colour(tr.cb); + if(tr.poly != nil) + drawpoly(tr.poly, POLY); + else if(DOCIRCLE) + circle(CIRCLE); + else + circle(POLY); + } + m_colour(tr.c); + if(tr.poly != nil) + drawpoly(tr.poly, FILLPOLY); + else if(DOCIRCLE) + circle(FILLCIRCLE); + else + circle(FILLPOLY); + m_popmatrix(); + } + + tm := 1.0; + do{ + δt := ∞; + + for(i = 0; i < n; i++){ + tr = t[i]; + if(tr.rt < δt) + δt = tr.rt; + if(tr.ct < δt) + δt = tr.ct; + } + + if(δt > tm) + δt = tm; + + for(i = 0; i < n; i++){ + tr = t[i]; + if(tr.rt == δt){ + tr1 := tr.obj; + reflect(tr); + tr.p = tr.rp; + if(δt > 0.0) + tr.pmask = (1<<tr.plane.id); + else + tr.pmask |= (1<<tr.plane.id); + zerot(tr, REFLECT|COLLIDE, 1); + zerot(tr1, COLLIDE, 1); + } + else if(tr.ct == δt){ + tr1 := tr.obj ; + collide(tr, tr1); + if(0 && poly) + collideω(tr, tr1); + tr.p = tr.cp; + tr1.p = tr1.cp; + tr.pmask = tr1.pmask = 0; + zerot(tr, REFLECT|COLLIDE, 1); + zerot(tr1, REFLECT|COLLIDE, 1); + } + else if(tr.todo != (REFLECT|COLLIDE)){ + tr.p = vclip(vadd(tr.p, vmul(tr.l.d, tr.v*δt)), icubd); + tr.rt -= δt; + tr.ct -= δt; + } + } + + for(i = 0; i < n; i++){ + tr = t[i]; + if(tr.todo){ + if(tr.todo&REFLECT) + reflection(tr, planes); + if(tr.todo&COLLIDE) + collisions(tr); + tr.todo = 0; + } + } + + tm -= δt; + + }while(tm > 0.0); + + sort(t, n); +} + +drawscene() +{ + m_pushmatrix(); + m_scale(real 2*cubd, real 2*cubd, real 2*cubd); + m_colour(white); + m_matmul(); + case(surr){ + SPHERE => + if(DOCIRCLE) + circle(CIRCLE); + else + circle(POLY); + ELLIPSOID => + ellipse(ELLIPSE); + CUBE => + if(flat) + square(POLY); + else + hexahedron(POLY); + * => + drawpoly(polyh, POLY); + } + m_popmatrix(); + drawobjs(); +} + +# ensure parallax doesn't alter between images +adjpar(x: array of real, y: array of real, z: array of real) +{ + zed, incr: real; + + y = nil; + if(z[0] < real 0) + zed = -z[0]; + else + zed = z[0]; + incr = eyed*zed*(real 1-scrD/(zed+objD-objd))/scrd; + if(!stereo || fov == real 0) + return; + if(left) + x[0] -= incr; + else + x[0] += incr; +} + +view() +{ + m_mode(PROJ); + m_loadidentity(); + m_scale(sx, sy, sz); + if(fov != real 0) + m_frustum(sf, real (1<<2), real (1<<20)); + else + m_ortho(sf, real (1<<2), real (1<<20)); + # m_print(); + m_mode(MODEL); +} + +model(rot: int) +{ + m_loadidentity(); + m_translate(0.0, 0.0, -objd); + if(rpy && rot){ + m_rotatez(roll); + m_rotatey(pitch); + m_rotatex(yaw); + } +} + +# store projection and modelview matrices +domats() +{ + model(0); + m_storematrix(mod0); + model(1); + view(); +} + +scale() +{ + if(maxx > maxy) + sx = real maxy/real maxx; + else + sx = 1.0; + if(maxy > maxx) + sy = real maxx/real maxy; + else + sy = 1.0; + sz = 1.0; +} + +rescale(w: int, h: int) +{ + maxx = w; + maxy = h; + scale(); + m_viewport(0, 0, maxx, maxy); +} + +grinit() +{ + for(i := 0; i < 4; i++) + mod0[i] = array[4] of real; + far = (2.0*cubd, 2.0*cubd, 2.0*cubd); + icubd = cubd-trkd/2.0; + icubd2 = icubd*icubd; + trkd2 = trkd*trkd; + cmin = vpt(-icubd, -icubd, -icubd); + cmax = vpt(+icubd, +icubd, +icubd); + maxx = MAXX; + maxy = MAXY; + e2 = vmul(vvmul(ef, ef), icubd2); + + m_init(); + pinit(); + circleinit(); + + m_viewport(0, 0, maxx, maxy); + + scale(); + if(fov > real 0) + fovtodist(); + update(1); +} + +newimage(win: ref Toplevel, init: int) +{ + maxx = int cmd(win, ".p cget -actwidth"); + maxy = int cmd(win, ".p cget -actheight"); + RDisp = display.newimage(((0, 0), (maxx, maxy)), win.image.chans, 0, Draw->Black); + tk->putimage(win, ".p", RDisp, nil); + RDisp.draw(RDisp.r, black, nil, (0, 0)); + reveal(); + rescale(maxx, maxy); + update(init); +} + +reveal() +{ + cmd(toplev, ".p dirty; update"); +} + +usage() +{ + sys->fprint(sys->fildes(2), "usage: collide [-cse] [-f] [-op] [-b num] [-v num]\n"); + exit; +} + +main(ctxt: ref Draw->Context, args: list of string) +{ + rand->init(daytime->now()); + daytime = nil; + + b := v := random(16, 32); + + arg->init(args); + while((o := arg->opt()) != 0){ + case(o){ + * => + usage(); + 's' => + surr = SPHERE; + 'e' => + surr = ELLIPSOID; + 'c' => + surr = CUBE; + 'o' => + fov = 0.0; + 'p' => + fov = -1.0; + 'f' => + flat = 1; + 'b' => + b = v = int arg->arg(); + 'v' => + v = int arg->arg(); + } + } + if(arg->argv() != nil) + usage(); + + if(b <= 0) + b = 1; + if(b > 100) + b = 100; + if(v <= 0) + v = 1; + if(v > b) + v = b; + + if(poly || surr == POLYHEDRON){ + polyhedra = load Polyhedra Polyhedra->PATH; + getpolys(); + } + if(surr == POLYHEDRON) + polyh = randpoly(polys, npolys); + + grinit(); + + tkclient->init(); + (win, wmch) := tkclient->toplevel(ctxt, "", "Collide", Tkclient->Resize | Tkclient->Hide); + toplev = win; + sys->pctl(Sys->NEWPGRP, nil); + cmdch := chan of string; + tk->namechan(win, cmdch, "cmd"); + for(i := 0; i < len winconfig; i++) + cmd(win, winconfig[i]); + cmd(win, "update"); + + tkclient->onscreen(win, nil); + tkclient->startinput(win, "kbd"::"ptr"::nil); + + display = win.image.display; + newimage(win, 1); + + black = display.color(Draw->Black); + white = display.color(Draw->White); + red = display.color(Draw->Red); + + objinit(b, v); + me = initme(); + + pid := -1; + sync := chan of int; + cmdc := chan of int; + spawn animate(sync, cmdc); + pid = <- sync; + + for(;;){ + alt{ + c := <-win.ctxt.kbd => + tk->keyboard(win, c); + c := <-win.ctxt.ptr => + tk->pointer(win, *c); + c := <-win.ctxt.ctl or + c = <-win.wreq => + tkclient->wmctl(win, c); + c := <- wmch => + case c{ + "exit" => + if(pid != -1) + kill(pid); + exit; + * => + sync <-= 0; + tkclient->wmctl(win, c); + if(c[0] == '!') + newimage(win, 0); + sync <-= 1; + } + c := <- cmdch => + case c{ + "stop" => + cmdc <-= 's'; + "zoomin" => + cmdc <-= 'z'; + "zoomout" => + cmdc <-= 'o'; + "slow" => + cmdc <-= '-'; + "fast" => + cmdc <-= '+'; + "objs" => + sync <-= 0; + b >>= 1; + if(b == 0) + b = 1; + objinit(b, b); + sync <-= 1; + } + } + } +} + +sign(r: real): real +{ + if(r < 0.0) + return -1.0; + return 1.0; +} + +abs(r: real): real +{ + if(r < 0.0) + return -r; + return r; +} + +animate(sync: chan of int, cmd: chan of int) +{ + zd := objd/250.0; + δ := θ := 0.0; + f := 8; + + sync <- = sys->pctl(0, nil); + for(;;){ + σ := 1.0; + alt{ + <- sync => + <- sync; + c := <- cmd => + case(c){ + 's' => + δ = θ = 0.0; + 'z' => + δ = zd; + 'o' => + δ = -zd; + 'r' => + θ = 1.0; + '+' => + σ = 1.25; + f++; + if(f > 16){ + f--; + σ = 1.0; + } + else + vf *= σ; + '-' => + σ = 0.8; + f--; + if(f < 0){ + f++; + σ = 1.0; + } + else + vf *= σ; + } + * => + sys->sleep(0); + } + + RDisp.draw(RDisp.r, black, nil, (0, 0)); + drawscene(); + reveal(); + + if(δ != 0.0 || θ != 0.0){ + objd -= δ; + me.l.a.z -= δ; + if(θ != 0.0){ + roll += θ; + pitch += θ; + yaw += θ; + rpy = 1; + } + update(projx); + } + if(σ != 1.0) + retime(σ); + } +} + +# usually almost sorted +sort(ts: array of ref Object, n: int) +{ + done: int; + t: ref Object; + q, p: int; + + q = n; + do{ + done = 1; + q--; + for(p = 0; p < q; p++){ + if(ts[p].p.z > ts[p+1].p.z){ + t = ts[p]; + ts[p] = ts[p+1]; + ts[p+1] = t; + done = 0; + } + } + }while(!done); +} + +kill(pid: int): int +{ + fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE); + if(fd == nil) + return -1; + if(sys->write(fd, array of byte "kill", 4) != 4) + return -1; + return 0; +} + +fatal(e: string) +{ + sys->fprint(sys->fildes(2), "%s\n", e); + raise "fatal"; +} + +cmd(top: ref Toplevel, s: string): string +{ + e := tk->cmd(top, s); + if (e != nil && e[0] == '!') + fatal(sys->sprint("tk error on '%s': %s", s, e)); + return e; +} + +winconfig := array[] of { + "frame .f", + "button .f.zoomin -text {zoomin} -command {send cmd zoomin}", + "button .f.zoomout -text {zoomout} -command {send cmd zoomout}", + "button .f.stop -text {stop} -command {send cmd stop}", + "pack .f.zoomin -side left", + "pack .f.zoomout -side right", + "pack .f.stop -side top", + + "frame .f2", + "button .f2.slow -text {slow} -command {send cmd slow}", + "button .f2.fast -text {fast} -command {send cmd fast}", + "button .f2.objs -text {objects} -command {send cmd objs}", + "pack .f2.slow -side left", + "pack .f2.fast -side right", + "pack .f2.objs -side top", + + "panel .p -width " + string MAXX + " -height " + string MAXY, + + "pack .f -side top -fill x", + "pack .f2 -side top -fill x", + "pack .p -side bottom -fill both -expand 1", + + "pack propagate . 0", + "update" +}; + +############################################################ + +# gl.b + +# +# initially generated by c2l +# + +MODEL, PROJ: con iota; + +Matrix: type array of array of real; + +Mstate: adt{ + matl: list of Matrix; + modl: list of Matrix; + prjl: list of Matrix; + mull: Matrix; + freel: list of Matrix; + vk: int; + vr: int; + vrr: int; + vc: ref Draw->Image; + ap: array of Draw->Point; + apn: int; + mx, cx, my, cy: real; + ignore: int; +}; + +ms: Mstate; + +m_new(): Matrix +{ + if(ms.freel != nil){ + m := hd ms.freel; + ms.freel = tl ms.freel; + return m; + } + m := array[4] of array of real; + for(i := 0; i < 4; i++) + m[i] = array[4] of real; + return m; +} + +m_free(m: Matrix) +{ + ms.freel = m :: ms.freel; +} + +m_init() +{ + ms.modl = m_new() :: nil; + ms.prjl = m_new() :: nil; + ms.matl = ms.modl; + ms.mull = m_new(); + ms.vk = 0; + ms.apn = 0; + ms.mx = ms.cx = ms.my = ms.cy = 0.0; + ms.ignore = 0; +} + +m_print() +{ + m := hd ms.matl; + + for(i := 0; i < 4; i++){ + for(j := 0; j < 4; j++) + sys->print("%f ", m[i][j]); + sys->print("\n"); + } + sys->print("\n"); +} + +m_mode(m: int) +{ + if(m == PROJ) + ms.matl = ms.prjl; + else + ms.matl = ms.modl; +} + +m_pushmatrix() +{ + if(ms.matl == ms.modl){ + ms.modl = m_new() :: ms.modl; + ms.matl = ms.modl; + } + else{ + ms.prjl = m_new() :: ms.prjl; + ms.matl = ms.prjl; + } + s := hd tl ms.matl; + d := hd ms.matl; + for(i := 0; i < 4; i++) + for(j := 0; j < 4; j++) + d[i][j] = s[i][j]; +} + +m_popmatrix() +{ + if(ms.matl == ms.modl){ + m_free(hd ms.modl); + ms.modl = tl ms.modl; + ms.matl = ms.modl; + } + else{ + m_free(hd ms.prjl); + ms.prjl = tl ms.prjl; + ms.matl = ms.prjl; + } +} + +m_loadidentity() +{ + i, j: int; + m := hd ms.matl; + + for(i = 0; i < 4; i++){ + for(j = 0; j < 4; j++) + m[i][j] = real 0; + m[i][i] = real 1; + } +} + +m_translate(x: real, y: real, z: real) +{ + i: int; + m := hd ms.matl; + + for(i = 0; i < 4; i++) + m[i][3] = x*m[i][0]+y*m[i][1]+z*m[i][2]+m[i][3]; +} + +m_scale(x: real, y: real, z: real) +{ + i: int; + m := hd ms.matl; + + for(i = 0; i < 4; i++){ + m[i][0] *= x; + m[i][1] *= y; + m[i][2] *= z; + } +} + +# rotate about x, y or z axes +rot(deg: real, j: int, k: int) +{ + i: int; + m := hd ms.matl; + rad := Math->Pi*deg/real 180; + s := maths->sin(rad); + c := maths->cos(rad); + a, b: real; + + for(i = 0; i < 4; i++){ + a = m[i][j]; + b = m[i][k]; + m[i][j] = c*a+s*b; + m[i][k] = c*b-s*a; + } +} + +m_rotatex(a: real) +{ + rot(a, 1, 2); +} + +m_rotatey(a: real) +{ + rot(a, 2, 0); +} + +m_rotatez(a: real) +{ + rot(a, 0, 1); +} + +# (l m n) normalized +m_rotate(deg: real, l: real, m: real, n:real) +{ + i: int; + mx := hd ms.matl; + rad := Math->Pi*deg/real 180; + s := maths->sin(rad); + c := maths->cos(rad); + f := 1.0-c; + m0, m1, m2: real; + + for(i = 0; i < 4; i++){ + m0 = mx[i][0]; + m1 = mx[i][1]; + m2 = mx[i][2]; + mx[i][0] = m0*(l*l*f+c)+m1*(l*m*f+n*s)+m2*(l*n*f-m*s); + mx[i][1] = m0*(l*m*f-n*s)+m1*(m*m*f+c)+m2*(m*n*f+l*s); + mx[i][2] = m0*(l*n*f+m*s)+m1*(m*n*f-l*s)+m2*(n*n*f+c); + } +} + +# Frustum(-l, l, -l, l, n, f) +m_frustum(l: real, n: real, f: real) +{ + i: int; + m := hd ms.matl; + r := n/l; + a, b: real; + + f = ∞; + for(i = 0; i < 4; i++){ + a = m[i][2]; + b = m[i][3]; + m[i][0] *= r; + m[i][1] *= r; + m[i][2] = a+b; + m[i][3] = 0.0; + # m[i][2] = -(a*(f+n)/(f-n)+b); + # m[i][3] = real -2*f*n*a/(f-n); + } +} + +# Ortho(-l, l, -l, l, n, f) +m_ortho(l: real, n: real, f: real) +{ + i: int; + m := hd ms.matl; + r := real 1/l; + # a: real; + + n = 0.0; + f = ∞; + for(i = 0; i < 4; i++){ + # a = m[i][2]; + m[i][0] *= r; + m[i][1] *= r; + # m[i][2] *= real -2/(f-n); + # m[i][3] -= a*(f+n)/(f-n); + } +} + +m_loadmatrix(u: array of array of real) +{ + m := hd ms.matl; + + for(i := 0; i < 4; i++) + for(j := 0; j < 4; j++) + m[i][j] = u[i][j]; +} + +m_storematrix(u: array of array of real) +{ + m := hd ms.matl; + + for(i := 0; i < 4; i++) + for(j := 0; j < 4; j++) + u[i][j] = m[i][j]; +} + +m_matmul() +{ + m, p, r: Matrix; + + m = hd ms.modl; + p = hd ms.prjl; + r = ms.mull; + for(i := 0; i < 4; i++){ + pr := p[i]; + rr := r[i]; + for(j := 0; j < 4; j++) + rr[j] = pr[0]*m[0][j]+pr[1]*m[1][j]+pr[2]*m[2][j]+pr[3]*m[3][j]; + } +} + +m_vertexo(x: real, y: real, z: real) +{ + m: Matrix; + mr: array of real; + w, x1, y1, z1: real; + + m = hd ms.modl; + mr = m[0]; x1 = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + mr = m[1]; y1 = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + mr = m[2]; z1 = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + mr = m[3]; w = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + if(w != real 1){ + x1 /= w; + y1 /= w; + z1 /= w; + } + if(z1 >= 0.0){ + ms.ignore = 1; + return; + } + m = hd ms.prjl; + mr = m[0]; x = x1*mr[0]+y1*mr[1]+z1*mr[2]+mr[3]; + mr = m[1]; y = x1*mr[0]+y1*mr[1]+z1*mr[2]+mr[3]; + mr = m[2]; z = x1*mr[0]+y1*mr[1]+z1*mr[2]+mr[3]; + mr = m[3]; w = x1*mr[0]+y1*mr[1]+z1*mr[2]+mr[3]; + if(w == real 0){ + ms.ignore = 1; + return; + } + if(w != real 1){ + x /= w; + y /= w; + # z /= w; + } + ms.ap[ms.apn++] = (int (ms.mx*x+ms.cx), int (ms.my*y+ms.cy)); +} + +m_vertex(x: real, y: real, z: real): (real, real) +{ + m: Matrix; + mr: array of real; + w, x1, y1, z1: real; + + m = ms.mull; + mr = m[0]; x1 = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + mr = m[1]; y1 = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + mr = m[2]; z1 = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + mr = m[3]; w = x*mr[0]+y*mr[1]+z*mr[2]+mr[3]; + if(w == real 0){ + ms.ignore = 1; + return (x1, y1); + } + if(w != real 1){ + x1 /= w; + y1 /= w; + # z1 /= w; + } + if(z1 >= 0.0){ + ms.ignore = 1; + return (x1, y1); + } + ms.ap[ms.apn++] = (int (ms.mx*x1+ms.cx), int (ms.my*y1+ms.cy)); + return (x1, y1); +} + +m_circle(x: real, y: real, z: real, r: real) +{ + (d, nil) := m_vertex(x, y, z); + (e, nil) := m_vertex(x+r, y, z); + d -= e; + if(d < 0.0) + d = -d; + ms.vr = int (ms.mx*d); +} + +m_ellipse(x: real, y: real, z: real, v: Vector) +{ + m_circle(x, y, z, v.x); + (nil, d) := m_vertex(x, y, z); + (nil, e) := m_vertex(x, y+v.y, z); + d -= e; + if(d < 0.0) + d = -d; + ms.vrr = int (ms.my*d); +} + +m_begin(k: int, n: int) +{ + ms.ignore = 0; + ms.vk = k; + ms.ap = array[n+1] of Draw->Point; + ms.apn = 0; +} + +m_end() +{ + if(ms.ignore) + return; + case(ms.vk){ + CIRCLE => + RDisp.ellipse(ms.ap[0], ms.vr, ms.vr, 0, ms.vc, (0, 0)); + FILLCIRCLE => + RDisp.fillellipse(ms.ap[0], ms.vr, ms.vr, ms.vc, (0, 0)); + ELLIPSE => + RDisp.ellipse(ms.ap[0], ms.vr, ms.vrr, 0, ms.vc, (0, 0)); + FILLELLIPSE => + RDisp.fillellipse(ms.ap[0], ms.vr, ms.vrr, ms.vc, (0, 0)); + POLY => + ms.ap[len ms.ap-1] = ms.ap[0]; + RDisp.poly(ms.ap, Draw->Endsquare, Draw->Endsquare, 0, ms.vc, (0, 0)); + FILLPOLY => + ms.ap[len ms.ap-1] = ms.ap[0]; + RDisp.fillpoly(ms.ap, ~0, ms.vc, (0, 0)); + } +} + +m_colour(i: ref Draw->Image) +{ + ms.vc = i; +} + +m_viewport(x1: int, y1: int, x2: int, y2: int) +{ + ms.mx = real (x2-x1)/2.0; + ms.cx = real (x2+x1)/2.0; + ms.my = real (y2-y1)/2.0; + ms.cy = real (y2+y1)/2.0; +} + +# sys->print("%d %f (%f %f %f) %s\n", ok, λ, 1.0, 2.0*vdot(l.a, l.d), vdot(l.a, l.a)-icubd2, lstring(l)); + +# sys->print("%d %f (%f %f %f) %s\n", ok, λ, vmuldiv(l.d, l.d, e2), 2.0*vmuldiv(l.a, l.d, e2), vmuldiv(l.a, l.a, e2)-1.0, lstring(l)); + +# for(lp = lp0 ; lp != nil; lp = tl lp){ +# p := hd lp; +# (ok, λ, pt) := intersect(l, p); +# sys->print("%d %x %d %f %s %s %s\n", p.id, tr.pmask, ok, λ, vstring(pt), pstring(p), lstring(l)); +# }
\ No newline at end of file |
