|
|
Delphi source code for 3D painting |
|
|
unit Unit2;
{
3D Lissajous graphics
jan. 2015, version 1.1
- changed radians to degrees
- added simple grid
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);
const f = pi/180;
begin
ca := a*f;
cb := b*f;
cc := c*f;
cd := d*f;
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.
|
|