unit Unit2; { 3D Lissajous graphics jan. 2015, version 1.0 data, procedures for 3D Lissajous painting painting in map [x,y] dimensions 800 * 800 coordinates (0,0,0) at [385,385] pen dimensions 31*31 pixels pen position (0,0) at left top z axis at 45 degrees, scale 0.7:1 positive towards front Xpix = X - 0.5Z Ypix = Y + 0.5Z } interface uses windows,extctrls,graphics,types; procedure setconstants(a,b,c,d : single); procedure setsmooth(sm : boolean); procedure setstepcount(sc : word); procedure makepen(pNr:byte; col:dword); procedure drawPen(pb:Tpaintbox); procedure makedrawing(formula : byte); function FSign(v : single) : single; function Isign(a : smallInt) : smallInt; procedure clearmap; function swapRB(c : dword) : dword; var map : TBitmap; //global map for image p0,pstep : dword; //p0:scanline[0] pstep:line step pointer difference implementation type Tpixels = array[0..30,0..30] of dword; //pen image TZ = array[0..30,0..30] of smallInt; //pixel Z height PDW = ^dword; const center = 385; var Zbuffer : array[0..799,0..799] of smallInt; SPixels : TPixels; SZ : TZ; pencolor : dword; penNr :byte; smooth : boolean; stepcount : word; ca,cb,cc,cd : single; //formula constants procedure setconstants(a,b,c,d : single); begin ca := a; cb := b; cc := c; cd := d; end; procedure setsmooth(sm : boolean); begin smooth := sm; end; procedure setstepcount(sc : word); begin stepcount := sc; end; procedure drawPen(pb : Tpaintbox); //copy pen in paintbox pb 31*31 var i,j : byte; begin for j := 0 to 30 do for i := 0 to 30 do pb.Canvas.Pixels[i,j] := swapRB(Spixels[i,j]); end; function swapRB(c : dword) : dword; //swap red & blue fields begin result := (c and $0000ff00) or (c shr 16) or ((c and $ff) shl 16); end; function FSign(v : single) : single; //return 1 for +, -1 for - begin result := 0; if v > 0 then result := 1; if v < 0 then result := -1; end; function Isign(a : smallInt) : smallInt; begin if a < 0 then result := -1 else if a > 0 then result:= 1 else result := 0; end; function Strunc(f : single) : smallInt; //round f to nearest integer begin if f >= 0 then result := trunc(f+0.5) else result := trunc(f-0.5); end; procedure clearPen; var i,j : byte; begin for j := 0 to 30 do //clear all for i := 0 to 30 do begin SZ[i,j] := -1000; SPixels[i,j] := $ffffff; end; end; procedure makeSPHcolors; //make sphere pen var i,j : byte; r,g,b : byte; vr,vg,vb : byte; d : single; begin clearPen; vb := pencolor shr 16; vg := pencolor shr 8 and $ff; vr := pencolor and $ff; for j := 0 to 30 do for i := 0 to 30 do begin d := 229 - sqr(j-15) - sqr(i-15); if d >= 0 then begin SZ[i,j] := trunc(0.5*sqrt(d)+0.5); if (abs(i) < 4) and (abs(j) < 4) then d := 1 else d := 1 - sqrt(sqr(i-10) + sqr(j-10)+0.5)*0.04; r := trunc(vr*d); g := trunc(vg*d); b := trunc(vb*d); Spixels[i,j] := r + (g shl 8) + (b shl 16); end; end; end; procedure makeSQRcolors; //make cube pen var i,j : byte; d : dword; begin d := pencolor; clearPen; for j := 10 to 30 do //front edge for i := 0 to 20 do begin SZ[i,j] := 10; SPixels[i,j] := d; end; d := d and $b0b0b0; for j := 0 to 9 do //top edge for i := 10-j to 30-j do begin SZ[i,j] := trunc(0.88*j + 1); SPixels[i,j] := d; end; d := d and $707070; for i := 21 to 30 do //right edge for j := 31-i to 50-i do begin SZ[i,j] := trunc(0.88*(31.5-i)); SPixels[i,j] := d; end; end; procedure makeRectColors; //flat square pen var i,j : byte; d,d1,d2,d3 : dword; begin clearPen; d := pencolor; d1 := d and $c0c0c0; d2 := d and $808080; d3 := d and $606060; for i := 0 to 1 do for j := i to 30-i do //left begin SPixels[i,j] := d; SZ[i,j] := 0; end; for i := 29 to 30 do //right for j := 31-i to i do begin Spixels[i,j] := d3; SZ[i,j] := 0; end; for j := 0 to 1 do //top for i := j to 30-j do begin Spixels[i,j] := d1; SZ[i,j] := 0; end; for j := 29 to 30 do //bottom for i := 31-j to j-1 do begin SPixels[i,j] := d2; SZ[i,j] := 0; end; end; procedure makeCircle; //make circle pen var i,j : byte; r,g,b : byte; vr,vg,vb : byte; w : word; d : single; begin clearPen; vb := pencolor shr 16; vg := pencolor shr 8 and $ff; vr := pencolor and $ff; for j := 0 to 30 do for i := 0to 30 do begin w := sqr(j-15) + sqr(i-15); if (w < 240) and (w > 170) then begin SZ[i,j] := trunc(sqrt(240-sqr(15-i)-sqr(15-j))); d := 1 - sqrt(sqr(i-10) + sqr(j-10)+0.5)*0.04; r := trunc(vr*d); g := trunc(vg*d); b := trunc(vb*d); Spixels[i,j] := r + (g shl 8) + (b shl 16); SZ[i,j] := 0; end; end;//for end; procedure makePen(pNr : byte; col:dword); begin if (pencolor <> col) or (penNr <> pNr) then begin pencolor := col; penNr := pNr; case pNr of 1 : makeSPHcolors; 2 : makeSQRcolors; 3 : makeRectColors; 4 : makeCircle; end; end; end; procedure clearmap; var i,j : word; begin with map do with canvas do begin brush.Color := $ffffff; brush.Style := bsSolid; fillrect(rect(0,0,width,height)); end; for j := 0 to 799 do for i := 0 to 799 do Zbuffer[i,j] := -400; end; procedure paintImage(x,y,z : smallInt); //x,y are left-top coordinates of pen //paint pen at x,y,z var p,p1 : dword; px,py : word; Zsph : smallInt; i,j : byte; begin with map do begin for j := 0 to 30 do begin py := y + j; p1 := p0 - py*pStep; for i := 0 to 30 do begin px := x + i; Zsph := z + SZ[i,j]; if (Zsph > ZBuffer[px,py]) then begin p := p1 + (px shl 2); ZBuffer[px,py] := Zsph; PDW(p)^ := SPixels[i,j]; end; end;//for i end;//for j end;//with end; procedure makeDrawing(formula:byte); //fm:formula# var i,n,t : word; x,y,z : single; //calculated px1,py1,pz1,px2,py2,pz2 : smallInt; //integer positions dx,dy,dz : single; //differences sx,sy,sz : smallInt; //screen coordinates code : byte; begin clearmap; n := 0; px1 := 0; py1 := 0; pz1 := 0; for t := 0 to stepcount do begin case formula of 1 : begin z := 125*sin(cc*t); x := trunc(250*cos(ca*t)); y := trunc(250*sin(cb*t)); end; 2 : begin z := 125*sin(cd*t); x := 250*sin(ca*t)*cos(cb*t); y := 250*sin(ca*t)*sin(cc*t); end; 3 : begin z := 125*sin(cd*t); x := 125*(cos(ca*t) + cos(cb*t)); y := 125*(sin(ca*t) + sin(cc*t)); end; else begin x:=0; y:=0; z:=0; end; end;//case if (t = 0) or (smooth=false) then begin pz1 := Strunc(z); px1 := Strunc(x) - pz1 + center; //3D & screen corrections py1 := Strunc(y) + pz1 + center; paintImage(px1,py1,pz1); end else begin pz2 := Strunc(z); px2 := Strunc(x) - pz2 + center; py2 := Strunc(y) + pz2 + center; dx := px2 - px1; dy := py2 - py1; dz := pz2 - pz1; if abs(dx) < 0.5 then code := 0 else code := 1; if abs(dy) >= 0.5 then code := code or $2; case code of 0 : begin if dz <= 0 then n := 0 else n := 1; dx := 0; dy := 0; end; 1 : begin n := abs(trunc(dx)); dx := Fsign(dx); dz := dz/n; end; 2 : begin n := abs(trunc(dy)); dy := Fsign(dy); dz := dz/n; end; 3 : begin if abs(dx) >= abs(dy) then begin n := abs(trunc(dx)); dx := Fsign(dx); dy := dy/n; dz := dz/n; end else begin n := abs(trunc(dy)); dy := Fsign(dy); dx := dx/n; dz := dz/n; end; end; end;//case if code <> 0 then for i := 1 to n do begin sx := Strunc(px1+i*dx); sy := Strunc(py1+i*dy); sz := Strunc(pz1+i*dz); paintimage(sx,sy,sz); end; px1 := px2; py1 := py2; pz1 := pz2; end;//else end;//for t end; initialization map := TBitmap.Create; with map do begin width := 800; height := 800; pixelformat := pf32bit; p0 := dword(scanline[0]); pstep := p0 - dword(scanline[1]); end; finalization map.Free; end.