raytrace-retro/turbo-pascal/rayt4.pas
2026-04-08 21:02:41 -07:00

302 lines
No EOL
6.9 KiB
ObjectPascal

program RayTracingWithUltraRayTr;
{$X+}
uses Crt,Vga13h,RayTr;
type
TgaHeader = record { 18 bytes total }
who_knows: array[1..12] of Byte;
Width: Word;
Height: Word;
BitsPerPixel: Byte;
who_knows2: Byte;
end;
const
DefaultHeader: TgaHeader = (
who_knows: (0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Width: 320;
Height: 200;
BitsPerPixel: 24;
who_knows2: 32
);
var
tf: File of byte;
ttf: File absolute tf;
procedure StartTga(s: String);
begin
Assign(tf,s);
Rewrite(tf);
BlockWrite(ttf,DefaultHeader,18);
end;
procedure EndTga;
begin
Close(tf);
end;
procedure TgaDot(r,g,b: Integer);
begin
if r > 255 then r := 255;
if g > 255 then g := 255;
if b > 255 then b := 255;
if r < 0 then r := 0;
if g < 0 then g := 0;
if b < 0 then b := 0;
Write(tf,Byte(b),Byte(g),Byte(r));
end;
{ r,g,b:0-255 }
function Rgb(r,g,b: Integer): Integer;
begin
if r > 255 then r := 255;
if g > 255 then g := 255;
if b > 255 then b := 255;
if r < 0 then r := 0;
if g < 0 then g := 0;
if b < 0 then b := 0;
Rgb := (b shr 6) or ((g shr 3) and $1c) or (r and $e0);
end;
procedure RgbDot(x,y,r,g,b: Integer);
var
r1,g1,b1,r2,g2,b2,c1,c2: Integer;
begin
if r > 255 then r := 255;
if g > 255 then g := 255;
if b > 255 then b := 255;
if r < 0 then r := 0;
if g < 0 then g := 0;
if b < 0 then b := 0;
r1 := r and $e0; g1 := g and $e0; b1 := b and $c0;
r2 := r1 + (r mod 32)+16;
g2 := g1 + (g mod 32)+16;
b2 := b1 + (b mod 64)+32;
c1 := Rgb(r1,g1,b1); c2 := Rgb(r2,g2,b2);
if (x mod 2) = (y mod 2) then PutPixel(x,y,c1) else PutPixel(x,y,c2);
end;
procedure SetUpRgb;
var
Clrs: array[0..255,0..2] of Byte;
i: Integer;
begin
for i := 0 to 255 do begin
Clrs[i,0] := (i and $e0) shr 2;
Clrs[i,1] := (i and $1c) shl 1;
Clrs[i,2] := (i and 3) shl 4;
case Clrs[i,2] of
15..31: Inc(Clrs[i,2],4);
32..63: Inc(Clrs[i,2],8);
end;
end;
SetColorBlock(0,256,Clrs);
end;
procedure Save(var u: TUniverse; st: String);
var
x,y: Integer;
c: RgbTriple;
r,g,b: Integer;
begin
StartTga(st);
x := 0;
for y := 0 to u.ScrHeight-1 do
for x := 0 to u.ScrWidth-1 do begin
u.TracePoint(x,y,c);
r := Trunc(c.r*255);
g := Trunc(c.g*255);
b := Trunc(c.b*255);
RgbDot(x,u.ScrHeight-1-y,r,g,b);
TgaDot(r,g,b);
end;
EndTga;
end;
procedure Draw(var u: TUniverse);
var
x,y: Integer;
c: RgbTriple;
r,g,b: Integer;
begin
x := 0;
while (x < u.ScrWidth) and (not KeyPressed) do begin
for y := 0 to u.ScrHeight-1 do begin
u.TracePoint(x,u.ScrHeight-1-y,c);
r := Trunc(c.r*255);
g := Trunc(c.g*255);
b := Trunc(c.b*255);
RgbDot(x,y,r,g,b);
end;
Inc(x);
end;
end;
procedure Qwik(var u: TUniverse);
var
x,y: Integer;
c: RgbTriple;
r,g,b: Integer;
begin
x := 0;
while (x < (u.ScrWidth div 2)) and (not KeyPressed) do begin
for y := 0 to (u.ScrHeight div 2)-1 do begin
u.TracePoint(x*2,u.ScrHeight-1-(y*2),c);
r := Trunc(c.r*255);
g := Trunc(c.g*255);
b := Trunc(c.b*255);
RgbDot(x*2,y*2,r,g,b); RgbDot(x*2+1,y*2,r,g,b);
RgbDot(x*2+1,y*2+1,r,g,b); RgbDot(x*2,y*2+1,r,g,b);
end;
Inc(x);
end;
end;
procedure Zoom(var u: TUniverse);
var
x,y,i,j: Integer;
c: RgbTriple;
r,g,b: Integer;
begin
x := 0;
while (x < (u.ScrWidth div 4)) and (not KeyPressed) do begin
for y := 0 to (u.ScrHeight div 4)-1 do begin
u.TracePoint(x*4,u.ScrHeight-1-(y*4),c);
r := Trunc(c.r*255);
g := Trunc(c.g*255);
b := Trunc(c.b*255);
for i := 0 to 3 do
for j := 0 to 3 do
RgbDot(x*4+i,y*4+j,r,g,b);
end;
Inc(x);
end;
end;
procedure Beep;
begin
Sound(220); { Beep }
Delay(200); { For 200 ms }
NoSound; { Relief! }
end;
type
TSphere2 = object(TSphere)
procedure GetInfo(Ray: TRay; var Inf: TRayInfo); virtual;
end;
TPlane2 = object(TPlane)
procedure GetInfo(Ray: TRay; var Inf: TRayInfo); virtual;
end;
procedure TSphere2.GetInfo(Ray: TRay; var Inf: TRayInfo);
var
a, b, c, t1, t2, t3, close, farther: real;
p1,p2: TPoint3d;
begin
a := ray.d.x * ray.d.x + ray.d.y * ray.d.y + ray.d.z * ray.d.z;
close := -1.0;
farther := -1.0;
if a <> 0 then begin
b := 2.0 * ((ray.o.x - Pos.x) * ray.d.x
+ (ray.o.y - Pos.y) * ray.d.y
+ (ray.o.z - Pos.z) * ray.d.z);
c := (ray.o.x - Pos.x) * (ray.o.x - Pos.x)
+ (ray.o.y - Pos.y) * (ray.o.y - Pos.y)
+ (ray.o.z - Pos.z) * (ray.o.z - Pos.z) - r2;
t1 := b * b - 4.0 * a * c;
if t1 > 0 then begin
t2 := sqrt(t1);
t3 := 2.0 * a;
close := -(b + t2) / t3;
farther := -(b - t2) / t3;
end;
end;
p1.SetTo(
ray.o.x+ray.d.x*close,
ray.o.y+ray.d.y*close,
ray.o.z+ray.d.z*close);
p2.SetTo(
ray.o.x+ray.d.x*farther,
ray.o.y+ray.d.y*farther,
ray.o.z+ray.d.z*farther);
if (p1.z-Pos.z) < -(r * 0.85) then close := -1;
if (p2.z-Pos.z) < -(r * 0.85) then farther := -1;
if (close <= 0.001) and (farther > 0.001) then begin
Inf.Time := farther; Inf.GoingIn := False;
end else
if (close > 0.001) and (farther <= 0.001) then begin
Inf.Time := close; Inf.GoingIn := False;
end else begin
Inf.GoingIn := True;
if close < farther then
Inf.Time := close
else
Inf.Time := farther;
end;
Inf.Hit := (Inf.Time > 0.001);
if not Inf.Hit then Exit;
Inf.Pos.SetTo(
ray.o.x+ray.d.x*Inf.Time,
ray.o.y+ray.d.y*Inf.Time,
ray.o.z+ray.d.z*Inf.Time);
Inf.Normal := Inf.Pos;
Inf.Normal.Sub(Pos);
if not Inf.GoingIn then Inf.Normal.Scale(-1);
Inf.Brightness := 1;
Inf.IndexRefraction := 0.95;
MakeTrip(1,1,1,Inf.Opacity);
MakeTrip(0,0,0,Inf.Reflectivity);
Inf.SpecularN := 200;
MakeTrip(0.8,0.8,0.8,Inf.Color);
end;
procedure TPlane2.GetInfo(Ray: TRay; var Inf: TRayInfo);
begin
TPlane.GetInfo(Ray,Inf);
MakeTrip(0,0,0,Inf.Reflectivity);
Inf.SpecularN := 1;
MakeTrip(0.9,0.9,0.9,Inf.Color);
end;
procedure TraceIt;
var
u: TUniverse;
l1,l2: TLightSource;
p1: TPlane2;
s1: TSphere2;
s2,s3,s4: TSphere;
begin
u.Init(320,200,10, 0,1,0, 0,0,1, 0,1,0, 1, 40,30, 0.2,0.2,0.2, 0,0,0);
u.Specular := False;
l1.Init(0,-1.7,25, 500,500,500);
l2.Init(20,60,20, 30,30,30);
u.InsertLight(@l1);
u.InsertLight(@l2);
p1.Init(0,-2,0, 0,1,0);
s1.Init(0,2,25,10);
s2.Init(0,-1,15,1);
s3.Init(-2.25,-1,15.5,1);
s4.Init(2.25,-1,15.5,1);
u.Insert(@p1);
u.Insert(@s1);
u.Insert(@s2);
u.Insert(@s3);
u.Insert(@s4);
{Zoom(u);}
Save(u,'brooke9.tga');
Beep;
u.DeleteAll;
u.Done;
end;
begin
Set13h;
SetUpRgb;
TraceIt;
ReadKey;
BiosMode(3);
end.