diff options
Diffstat (limited to 'packages/ptc/examples/mojo.pp')
-rw-r--r-- | packages/ptc/examples/mojo.pp | 815 |
1 files changed, 815 insertions, 0 deletions
diff --git a/packages/ptc/examples/mojo.pp b/packages/ptc/examples/mojo.pp new file mode 100644 index 0000000000..a6fcc285a3 --- /dev/null +++ b/packages/ptc/examples/mojo.pp @@ -0,0 +1,815 @@ +{ +Ported to FPC by Nikolay Nikolov (nickysn@users.sourceforge.net) +} + +{ +Mojo demo for OpenPTC 1.0 C++ API +Coded by Alex Evans and adapted to OpenPTC 1.0 by Glenn Fiedler + +nasty code by alex "statix" evans for ptc. (c) copyright alex evans 1998 +time... 02.00 am on 13/1/98. +have fun +it's my take on some classic light mask effect +it's raytracing through properly modelled fog with occlusion, multiple +shadow rays cast back to the light for each pixel ray, and erm, its +s l o w... but it looks nice don't it? + +oh and fresnel fall off... or something + +UNTESTED! ok? + +define inv for interesting fx (not) +} + +Program Mojo; + +{$MODE objfpc} + +Uses + ptc, SysUtils; + +{ $DEFINE INV} + +Const + SC = 12; + MINSEGSIZE = 2.5; + NSEG = 5; + frandtab_seed : Uint16 = 54; + +Var + MaskMap : PUint8; + frandtab : Array[0..65535] Of Uint16; + +Type + FVector = Object +{ Case Boolean Of + False : (X, Y, Z : Single); + True : (R, G, B : Single);} + X, Y, Z : Single; + + Constructor Init; + Constructor Init(_x, _y, _z : Single); + + Function Magnitude : Single; + Function MagnitudeSq : Single; + Procedure Normalise; + End; + FMatrix = Object + Row : Array[0..2] Of FVector; + Constructor Init; + Constructor Init(a, b, c : FVector); + Function Column0 : FVector; + Function Column1 : FVector; + Function Column2 : FVector; + Procedure MakeXRot(theta : Single); + Procedure MakeYRot(theta : Single); + Procedure MakeZRot(theta : Single); + Procedure MakeID; + Function Transpose : FMatrix; + Procedure TransposeInPlace; + Procedure Normalise; + End; + PRay = ^TRay; + TRay = Object + mPosn : FVector; + mDir : FVector; + Constructor Init(Const p, d : FVector); + End; + VLight = Class(TObject) + mAng : Single; + mPosn : FVector; + mTarget : FVector; + mAxis : FMatrix; + mCol : FVector; + + p, p2, _d : FVector; { temp space } + + Constructor Create(Const col : FVector); + Procedure Move(Const q : FVector); + Procedure MoveT(Const q : FVector); + Procedure Update; + Function Light(Const ray : TRay) : FVector; + Function CalcLight(t : Single) : Single; + End; + +Constructor FVector.Init; + +Begin +End; + +Constructor FVector.Init(_x, _y, _z : Single); + +Begin + X := _x; + Y := _y; + Z := _z; +End; + +Function FVector.Magnitude : Single; + +Begin + Magnitude := Sqrt(Sqr(X) + Sqr(Y) + Sqr(Z)); +End; + +Function FVector.MagnitudeSq : Single; + +Begin + MagnitudeSq := Sqr(X) + Sqr(Y) + Sqr(Z); +End; + +Procedure FVector.Normalise; + +Var + l : Single; + +Begin + l := 1 / Magnitude; + X *= l; + Y *= l; + Z *= l; +End; + +Operator * (a, b : FVector) res : Single; + +Begin + res := a.X * b.X + a.Y * b.Y + a.Z * b.Z; +End; + +Operator * (a : FVector; b : Single) res : FVector; + +Begin + res.X := a.X * b; + res.Y := a.Y * b; + res.Z := a.Z * b; +End; + +Operator + (a, b : FVector) res : FVector; + +Begin + res.X := a.X + b.X; + res.Y := a.Y + b.Y; + res.Z := a.Z + b.Z; +End; + +Operator - (a, b : FVector) res : FVector; + +Begin + res.X := a.X - b.X; + res.Y := a.Y - b.Y; + res.Z := a.Z - b.Z; +End; + +Operator ** (a, b : FVector) res : FVector; + +Begin + res.X := a.Y * b.Z - a.Z * b.Y; + res.Y := a.Z * b.X - a.X * b.Z; + res.Z := a.X * b.Y - a.Y * b.X; +End; + +Constructor FMatrix.Init; + +Begin +End; + +Constructor FMatrix.Init(a, b, c : FVector); + +Begin + Row[0] := a; + Row[1] := b; + Row[2] := c; +End; + +Function FMatrix.Column0 : FVector; + +Var + res : FVector; + +Begin + res.Init(Row[0].X, Row[1].X, Row[2].X); + Column0 := res; +End; + +Function FMatrix.Column1 : FVector; + +Var + res : FVector; + +Begin + res.Init(Row[0].Y, Row[1].Y, Row[2].Y); + Column1 := res; +End; + +Function FMatrix.Column2 : FVector; + +Var + res : FVector; + +Begin + res.Init(Row[0].Z, Row[1].Z, Row[2].Z); + Column2 := res; +End; + +Procedure FMatrix.MakeXRot(theta : Single); + +Var + c, s : Single; + +Begin + c := cos(theta); + s := sin(theta); + Row[1].Y := c; Row[1].Z := s; Row[1].X := 0; + Row[2].Y := -s; Row[2].Z := c; Row[2].X := 0; + Row[0].Y := 0; Row[0].Z := 0; Row[0].X := 1; +End; + +Procedure FMatrix.MakeYRot(theta : Single); + +Var + c, s : Single; + +Begin + c := cos(theta); + s := sin(theta); + Row[2].Z := c; Row[2].X := s; Row[2].Y := 0; + Row[0].Z := -s; Row[0].X := c; Row[0].Y := 0; + Row[1].Z := 0; Row[1].X := 0; Row[1].Y := 1; +End; + +Procedure FMatrix.MakeZRot(theta : Single); + +Var + c, s : Single; + +Begin + c := cos(theta); + s := sin(theta); + Row[0].X := c; Row[0].Y := s; Row[0].Z := 0; + Row[1].X := -s; Row[1].Y := c; Row[1].Z := 0; + Row[2].X := 0; Row[2].Y := 0; Row[2].Z := 1; +End; + +Procedure FMatrix.MakeID; + +Begin + Row[0].Init(1, 0, 0); + Row[1].Init(0, 1, 0); + Row[2].Init(0, 0, 1); +End; + +Function FMatrix.Transpose : FMatrix; + +Var + res : FMatrix; + +Begin + res.Init(Column0, Column1, Column2); + Transpose := res; +End; + +Procedure FMatrix.TransposeInPlace; + +Begin + Init(Column0, Column1, Column2); +End; + +Procedure FMatrix.Normalise; + +Begin + Row[2].Normalise; + Row[0] := Row[1]**Row[2]; + Row[0].Normalise; + Row[1] := Row[2]**Row[0]; + Row[1].Normalise; +End; + +Operator * (Const m : FMatrix; Const a : Single) res : FMatrix; + +Begin + res.Init(m.Row[0]*a, m.Row[1]*a, m.Row[2]*a); +End; + +Operator * (Const m, a : FMatrix) res : FMatrix; + +Var + v1, v2, v3 : FVector; + +Begin + v1.Init(m.Row[0].X*a.Row[0].X+m.Row[0].Y*a.Row[1].X+m.Row[0].Z*a.Row[2].X, + m.Row[0].X*a.Row[0].Y+m.Row[0].Y*a.Row[1].Y+m.Row[0].Z*a.Row[2].Y, + m.Row[0].X*a.Row[0].Z+m.Row[0].Y*a.Row[1].Z+m.Row[0].Z*a.Row[2].Z); + v2.Init(m.Row[1].X*a.Row[0].X+m.Row[1].Y*a.Row[1].X+m.Row[1].Z*a.Row[2].X, + m.Row[1].X*a.Row[0].Y+m.Row[1].Y*a.Row[1].Y+m.Row[1].Z*a.Row[2].Y, + m.Row[1].X*a.Row[0].Z+m.Row[1].Y*a.Row[1].Z+m.Row[1].Z*a.Row[2].Z); + v3.Init(m.Row[2].X*a.Row[0].X+m.Row[2].Y*a.Row[1].X+m.Row[2].Z*a.Row[2].X, + m.Row[2].X*a.Row[0].Y+m.Row[2].Y*a.Row[1].Y+m.Row[2].Z*a.Row[2].Y, + m.Row[2].X*a.Row[0].Z+m.Row[2].Y*a.Row[1].Z+m.Row[2].Z*a.Row[2].Z); + res.Init(v1, v2, v3); +End; + +Operator * (Const m : FMatrix; Const a : FVector) res : FVector; + +Begin + res.Init(a*m.Row[0], a*m.Row[1], a*m.Row[2]); +End; + +Operator + (Const m, a : FMatrix) res : FMatrix; + +Begin + res.Init(m.Row[0]+a.Row[0], m.Row[1]+a.Row[1], m.Row[2]+a.Row[2]); +End; + +Operator - (Const m, a : FMatrix) res : FMatrix; + +Begin + res.Init(m.Row[0]+a.Row[0], m.Row[1]+a.Row[1], m.Row[2]+a.Row[2]); +End; + +Constructor TRay.Init(Const p, d : FVector); + +Begin + mPosn := p; + mDir := d; + mDir.Normalise; +End; + +Constructor VLight.Create(Const col : FVector); + +Begin + mCol := col * 0.9; + mAng := 2.8; + mPosn.Init(0, 0, 20); + mTarget.Init(0, 0, 0.1); + mAxis.MakeID; + Update; +End; + +Procedure VLight.Move(Const q : FVector); + +Begin + mPosn := q; + Update; +End; + +Procedure VLight.MoveT(Const q : FVector); + +Begin + mTarget := q; + Update; +End; + +Procedure VLight.Update; + +Begin + mAxis.Row[2] := (mTarget - mPosn); + mAxis.Normalise; +End; + +Function VLight.Light(Const ray : TRay) : FVector; + +Var + f, A, B, C, D, t1, t2, t3, fr, l1, l2, t, h : Single; + frc, x, y, q : Integer; + pp : FVector; + res : FVector; + +Begin + f := 0; + + p2 := ray.mPosn; + p := mAxis * (ray.mPosn - mPosn); + _d := mAxis * ray.mDir; + A := (_d.X*_d.X+_d.Y*_d.Y); + B := 2*(_d.X*p.X+_d.Y*p.Y)-mAng*(_d.Z); + C := (p.X*p.X+p.Y*p.Y)-mAng*(p.Z); + D := B*B-4*A*C; + If D <= 0 Then + Begin + res.Init(0, 0, 0); + Light := res; + Exit; + End; + D := Sqrt(D); + A *= 2; + t1 := (-B-D)/A; + t2 := (-B+D)/A; + frc := 255; + t3 := -ray.mPosn.Z/ray.mDir.Z; + If t2<=0 Then + Begin + res.Init(0, 0, 0); + Light := res; + Exit; + End; + If t1<0 Then + t1 := 0; + If t3>0 Then + Begin + { clip to bitmap plane } + pp := ray.mPosn + ray.mDir*t3; + x := 160+Trunc(SC*pp.X); +{$IFNDEF INV} + If (x>=0) And (x<=319) Then + Begin + y := 100 + Trunc(SC*pp.Y); + If (y>=0) And (y<=199) Then + Begin + {res.Init(0, 0, 1); + Light := res; + Exit;} + frc := MaskMap[y*320+x]; + If frc<1 Then + Begin + If t1>t3 Then + t1 := t3; + If t2>t3 Then + t2 := t3; + End; + End + Else + t3 := t2 + End + Else + t3 := t2; +{$ELSE} + If (x >= 0) And (x <= 319) Then + Begin + y := 100 + Trunc(SC*pp.Y); + If (y >= 0) And (y <= 199) And (MaskMap[y*320 + x] < 128) Then + t3 := t2; + End; + If t1 > t3 Then + t1 := t3; + If t2 > t3 Then + t2 := t3; +{$ENDIF} + End; + If t1>=t2 Then + Begin + res.Init(0, 0, 0); + Light := res; + Exit; + End; + fr := frc/255; + l1 := CalcLight(t1); + If t1>t3 Then + l1 *= fr; + q := NSEG; + t := t1; + h := (t2-t1)/NSEG; + If h<MINSEGSIZE Then + h := MINSEGSIZE; + While (t<t3) And (q>0) And (t<t2) Do + Begin + t += h; + If (t>t2) Then + Begin + h -= t2-t; + t := t2; + q := 0; + End + Else + Dec(q); + h := (t-t1); + p += _d*h; + p2 += ray.mDir*h; + l2 := CalcLight(t); + f += (l1+l2)*h; + l1 := l2; + t1 := t; + End; + While (q>0) And (t<t2) Do + Begin + t += h; + If t>t2 Then + Begin + h -= t2-t; + t := t2; + q := 0; + End + Else + Dec(q); + p += _d*h; + p2 += ray.mDir*h; + l2 := CalcLight(t); + If t>t3 Then + l2 *= fr; + f += (l1+l2)*h; + l1 := l2; + t1 := t; + End; + Light := mCol*f; +End; + +Function VLight.CalcLight(t : Single) : Single; + +Var + f : Single; + x, y, c : Integer; + +Begin + { trace line to bitmap from mPosn to p2 } + If Not ((mPosn.Z > 0) Xor (p2.Z > 0)) Then + Begin + { fresnel fall off... } + CalcLight := p.Z / p.MagnitudeSq; + Exit; + End; + f := -(mPosn.Z)/(p2.Z - mPosn.Z); + x := 160 + Trunc(SC*((p2.X-mPosn.X)*f+mPosn.X)); +{$IFNDEF INV} + If (x < 0) Or (x > 319) Then + Begin + CalcLight := p.Z / p.MagnitudeSq; + Exit; + End; + y := 100 + Trunc(SC*((p2.Y-mPosn.Y)*f+mPosn.Y)); + If (y < 0) Or (y > 199) Then + Begin + CalcLight := p.Z / p.MagnitudeSq; + Exit; + End; + c := MaskMap[y * 320 + x]; +{$ELSE} + If (x < 0) Or (x > 319) Then + Begin + CalcLight := 0; + Exit; + End; + y := 100 + Trunc(SC*((p2.Y-mPosn.Y)*f+mPosn.Y)); + If (y < 0) Or (y > 199) Then + Begin + CalcLight := 0; + Exit; + End; + c := 255 - MaskMap[y * 320 + x]; +{$ENDIF} + If c = 0 Then + Begin + CalcLight := 0; + Exit; + End; + CalcLight := (c*(1/255))*p.Z / p.MagnitudeSq; +End; + +Function CLIPC(f : Single) : Integer; {Inline;} + +Var + a : Integer; + +Begin + a := Trunc(f * 255); + If a < 0 Then + a := 0 + Else + If a > 255 Then + a := 255; + CLIPC := a; +End; + +Procedure initfrand; + +Var + s, c1 : Integer; + +Begin + FillChar(frandtab, SizeOf(frandtab), 0); + s := 1; + For c1 := 1 To 65535 Do + Begin + frandtab[c1] := s And $FFFF; + s := (((s Shr 4) Xor (s Shr 13) Xor (s Shr 15)) And 1) + (s Shl 1); + End; +End; + +Function frand : Integer; {Inline;} + +Begin + frand := frandtab[frandtab_seed]; + frandtab_seed := (frandtab_seed + 1) And $FFFF; +End; + +Procedure VLightPart(console : TPTCConsole; surface : TPTCSurface); + +Var + vl, vl2 : VLight; + camposn : FVector; + camaxis : FMatrix; + c1, c2, c3, ti, xx, yy, zz, i, a, x, y : Integer; + idx : Array[0..(200 Div 16) - 1, 0..(320 Div 16) - 1] Of Uint8; + order : Array[0..10*19 - 1, 0..1] Of Integer; + vlightt, t, cz, camf : Single; + col : FVector; + ray : TRay; + oc, c, c2_ : Uint32; + time, delta : Single; + pitch : Integer; + screenbuf, pd : PUint8; + tmp : FVector; + F : File; + +Begin + oc := 0; + initfrand; + tmp.Init(0.1, 0.4, 1); + vl := VLight.Create(tmp); + tmp.Init(1, 0.5, 0.2); + vl2 := VLight.Create(tmp); + tmp.Init(0, 0, 20); + vl.Move(tmp); + tmp.Init(0, 6, 30); + vl2.Move(tmp); + + camposn.Init(7, 0.5, -10); + camaxis.Init; + camaxis.MakeID; + tmp.Init(0, 0, 0); + camaxis.Row[2] := tmp - camposn; + camaxis.Normalise; + camf := 100; + + MaskMap := GetMem(320 * 200); + FillChar(MaskMap^, 320 * 200, 0); + + { load mojo.raw } + ASSign(F, 'mojo.raw'); + Reset(F, 1); + BlockRead(F, MaskMap^, 320*200); + Close(F); + + { build the order of the squares } + For c1 := 0 To 10*19 - 1 Do + Begin + order[c1, 0] := c1 Mod 19; + order[c1, 1] := (c1 Div 19) + 1; + End; + + { swap them around } + For c1 := 0 To 9999 Do + Begin + c2 := Random(190); + c3 := Random(190); + ti := order[c2, 0]; order[c2, 0] := order[c3, 0]; order[c3, 0] := ti; + ti := order[c2, 1]; order[c2, 1] := order[c3, 1]; order[c3, 1] := ti; + End; + + { time settings } + time := 0; + delta := 0.01; { this controls the speed of the effect } + + { main loop } + While Not console.KeyPressed Do + Begin + { get surface data } + pitch := surface.pitch; + + { light time (makes the effect loop) } + vlightt := 320 * Abs(Sin(time/5)); + + t := 13 - 0.1822 * vlightt; + cz := 1 - 0.01 * vlightt; + {tmp.Init(Sin(t)*5, Cos(t*-0.675+4543)*5, 15); + vl.Move(tmp); + tmp.Init(0, 0, -15); + vl.Move(tmp);} + tmp.Init(t, 0, 22); + vl.Move(tmp); + tmp.Init(-t, -7, 28); + vl2.Move(tmp); + + camposn.Init(cz*4+9, cz, -t/7-13); + tmp.Init(0, 0, 0); + camaxis.Row[2] := tmp - camposn; + camaxis.Normalise; + + FillChar(idx, SizeOf(idx), 25); + + { swap them around } + For c1 := 0 To 99 Do + Begin + c2 := Random(190); + c3 := Random(190); + ti := order[c2, 0]; order[c2, 0] := order[c3, 0]; order[c3, 0] := ti; + ti := order[c2, 1]; order[c2, 1] := order[c3, 1]; order[c3, 1] := ti; + End; + For zz := 0 To 189 Do + Begin + xx := order[zz, 0]; + yy := order[zz, 1]; + i := 0; + + { lock surface } + screenbuf := surface.lock; + Try + c2 := idx[yy, xx] Shr 1; + For c1 := 0 To c2 - 1 Do + Begin + a := frand And 255; + x := xx * 16 + (a And 15) + 6 + 4; + y := yy * 16 + (a Shr 4) + 6; + + col.Init(0, 0, 0); + ray.Init(camposn, camaxis.Row[2]*camf+camaxis.Row[0]*(x-160)+camaxis.Row[1]*(y-100)); + col += vl.Light(ray); + col += vl2.Light(ray); + + c := (CLIPC(col.X) Shl 16) + (CLIPC(col.Y) Shl 8) + (CLIPC(col.Z)); + pd := screenbuf + x*4 + y*pitch; + Inc(i, Abs(Integer(c And 255)-Integer(pd[321] And 255)) + Abs(Integer(c Shr 16)-Integer(pd[321] Shr 16))); + If c1 <> 0 Then + Inc(i, Abs(Integer(c And 255)-Integer(oc And 255)) + Abs(Integer(c Shr 16)-Integer(oc Shr 16))); + oc := c; + + c2_ := (c Shr 1) And $7F7F7F; + PUint32(pd)[1] := ((PUint32(pd)[1]) Shr 1) And $7F7F7F+ c2_; + PUint32(pd)[2] := ((PUint32(pd)[2]) Shr 1) And $7F7F7F+ c2_; + Inc(pd, pitch); + PUint32(pd)[0] := ((PUint32(pd)[0]) Shr 1) And $7F7F7F+ c2_; + PUint32(pd)[1] := c; + PUint32(pd)[2] := c; + PUint32(pd)[3] := ((PUint32(pd)[3]) Shr 1) And $7F7F7F+ c2_; + Inc(pd, pitch); + PUint32(pd)[0] := ((PUint32(pd)[0]) Shr 1) And $7F7F7F+ c2_; + PUint32(pd)[1] := c; + PUint32(pd)[2] := c; + PUint32(pd)[3] := ((PUint32(pd)[3]) Shr 1) And $7F7F7F+ c2_; + Inc(pd, pitch); + PUint32(pd)[1] := ((PUint32(pd)[1]) Shr 1) And $7F7F7F+ c2_; + PUint32(pd)[2] := ((PUint32(pd)[2]) Shr 1) And $7F7F7F+ c2_; + End; + i *= 5; + i := i Div (3*idx[yy, xx]); + If i < 2 Then + i := 2; + If i > {256}255 Then + i := {256}255; + idx[yy, xx] := i; + Finally + { unlock surface } + surface.unlock; + End; + + If (zz Mod 95) = 0 Then + Begin + { copy surface to console } + surface.copy(console); + + { update console } + console.update; + End; + End; + { update time } + time += delta; + End; + FreeMem(MaskMap); + vl.Free; + vl2.Free; +End; + +Var + format : TPTCFormat; + console : TPTCConsole; + surface : TPTCSurface; + +Begin + format := Nil; + surface := Nil; + console := Nil; + Try + Try + { create format } + format := TPTCFormat.Create(32, $00FF0000, $0000FF00, $000000FF); + + { create console } + console := TPTCConsole.Create; + + { open console } + console.open('mojo by statix', 320, 200, format); + + { create main drawing surface } + surface := TPTCSurface.Create(320, 200, format); + + { do the light effect } + VLightPart(console, surface); + + Finally + { close console } + console.close; + console.Free; + surface.Free; + format.Free; + End; + + { print message to stdout } + Writeln('mojo by alex "statix" evans'); + Writeln('to be used as an example of bad coding and good ptc'); + Writeln('no responsibility taken for this!'); + Writeln('enjoy ptc! it''s great'); + Writeln; + Writeln('-statix 13/1/98'); + Except + On error : TPTCError Do + { report error } + error.report; + End; +End. |