program RaylibTest;
uses
SysUtils, Math,
raylib, raymath;
const
screenWidth = 1280;
screenHeight = 720;
type
TVector4 = record
x, y, z, w: Single;
end;
PModel = ^TModel;
TObj = record
index: Integer;
pos: TVector3;
proj: TVector4;
m: PModel;
end;
function Project(pos: TVector3; matView, matPerps: TMatrix): TVector4;
var
temp: TVector4;
begin
temp.x := matView.m0*pos.x + matView.m4*pos.y + matView.m8*pos.z + matView.m12;
temp.y := matView.m1*pos.x + matView.m5*pos.y + matView.m9*pos.z + matView.m13;
temp.z := matView.m2*pos.x + matView.m6*pos.y + matView.m10*pos.z + matView.m14;
temp.w := matView.m3*pos.x + matView.m7*pos.y + matView.m11*pos.z + matView.m15;
Result.x := matPerps.m0*temp.x + matPerps.m4*temp.y + matPerps.m8*temp.z + matPerps.m12*temp.w;
Result.y := matPerps.m1*temp.x + matPerps.m5*temp.y + matPerps.m9*temp.z + matPerps.m13*temp.w;
Result.z := matPerps.m2*temp.x + matPerps.m6*temp.y + matPerps.m10*temp.z + matPerps.m14*temp.w;
Result.w := -temp.z;
if Result.w <> 0.0 then
begin
Result.w := (1.0/Result.w)/0.75; // TODO fudge of .75 WHY???
Result.x := Result.x * Result.w;
Result.y := Result.y * Result.w;
Result.z := Result.z * Result.w;
end;
end;
var
camera: TCamera;
models: array[0..3] of TModel;
objs: array[0..7] of TObj;
basePos: array[0..7] of TVector3;
labels: array[0..7] of string;
mesh: TMesh;
//shader: TShader;
tex: TTexture;
frame: Integer;
ang: TVector3;
togglePos, toggleRadar: Boolean;
view, perps: TMatrix;
aspect: Single;
i: Integer;
xi, mi: Single;
p: TVector3;
sorted: Boolean;
tmp: TObj;
hsw, hsh: Single;
l: Integer;
ft: string;
GenImage: TImage;
begin
// Initialization
InitWindow(screenWidth, screenHeight, 'raylib - test');
// Define the camera
camera.position := Vector3Create(0.0, 1.0, 0.0);
camera.target := Vector3Create(0.0, 0.0, 4.0);
camera.up := Vector3Create(0.0, 1.0, 0.0);
camera.fovy := 45.0;
camera.projection := CAMERA_PERSPECTIVE;
// Initialize objects
for i := 0 to 7 do
begin
objs[i].pos := Vector3Create(Cos(0.7853982*i)*4.0, 0, Sin(0.7853982*i)*4.0);
if (i = 2) or (i = 6) then
objs[i].pos.y := objs[i].pos.y - 0.5;
basePos[i] := objs[i].pos;
objs[i].index := i;
end;
// Labels
labels[0] := 'torus 1'; labels[1] := 'cube 1'; labels[2] := 'cylinder 1'; labels[3] := 'sphere 1';
labels[4] := 'torus 2'; labels[5] := 'cube 2'; labels[6] := 'cylinder 2'; labels[7] := 'sphere 2';
// Create models
mesh := GenMeshTorus(0.3, 1, 16, 32);
models[0] := LoadModelFromMesh(mesh);
mesh := GenMeshCube(1, 1, 1);
models[1] := LoadModelFromMesh(mesh);
mesh := GenMeshCylinder(0.5, 1, 32);
models[2] := LoadModelFromMesh(mesh);
mesh := GenMeshSphere(0.5, 16, 32);
models[3] := LoadModelFromMesh(mesh);
// Assign models to objects
objs[0].m := @models[0]; objs[4].m := @models[0];
objs[1].m := @models[1]; objs[5].m := @models[1];
objs[2].m := @models[2]; objs[6].m := @models[2];
objs[3].m := @models[3]; objs[7].m := @models[3];
GenImage := GenImageChecked(2, 2, 1, 1, RED, GREEN);
tex := LoadTextureFromImage(GenImage);
UnloadImage(GenImage);
for i := 0 to 3 do
begin
models[i].materials[0].maps[MATERIAL_MAP_DIFFUSE].texture := tex;
end;
// Initialize variables
frame := 0;
ang := Vector3Zero();
togglePos := True;
toggleRadar := False;
SetTargetFPS(60);
// Main game loop
while not WindowShouldClose() do
begin
// Update
frame := frame + 1;
ang.x := ang.x + 0.01;
ang.y := ang.y + 0.005;
ang.z := ang.z - 0.0025;
// Rotate model
models[0].transform := MatrixRotateXYZ(ang);
UpdateCamera(@camera, CAMERA_FIRST_PERSON);
// Get matrices for projection
view := MatrixLookAt(camera.position, camera.target, camera.up);
aspect := screenWidth / screenHeight;
perps := MatrixPerspective(camera.fovy, aspect, 0.01, 1000.0);
if IsKeyPressed(KEY_SPACE) then togglePos := not togglePos;
if IsKeyPressed(KEY_R) then toggleRadar := not toggleRadar;
// Update object positions and projections
for i := 0 to 7 do
begin
objs[i].pos := basePos[objs[i].index];
xi := frame / 100.0;
if (objs[i].index mod 2) = 1 then xi := -xi;
mi := 0.25;
if objs[i].index = 0 then mi := 8;
objs[i].pos.x := objs[i].pos.x + Cos(xi) * mi;
objs[i].pos.z := objs[i].pos.z + Sin(xi) * mi;
p := objs[i].pos;
if togglePos then p.y := 1.0 else p.y := 0.0;
objs[i].proj := Project(p, view, perps);
end;
// Sort objects by depth
sorted := False;
while not sorted do
begin
sorted := True;
for i := 0 to 6 do
begin
if objs[i].proj.w > objs[i+1].proj.w then
begin
sorted := False;
tmp := objs[i];
objs[i] := objs[i+1];
objs[i+1] := tmp;
end;
end;
end;
// Draw
BeginDrawing();
ClearBackground(BLACK);
BeginMode3D(camera);
// Draw models
for i := 0 to 7 do
begin
DrawModel(objs[i].m^, objs[i].pos, 1.0, WHITE);
end;
DrawGrid(10, 1.0);
EndMode3D();
DrawFPS(10, 10);
DrawText('Space : toggle label position, R : toggle 3d radar', 140, 10, 20, DARKGREEN);
hsw := screenWidth / 2.0;
hsh := screenHeight / 2.0;
for i := 0 to 7 do
begin
if objs[i].proj.w > 0 then
begin
// Draw label
l := MeasureText(Pchar(labels[objs[i].index]), 24);
DrawRectangle(Round(hsw + objs[i].proj.x * hsw - 4 - l/2),
Round(hsh - objs[i].proj.y * hsh - 4),
l + 8, 27, BLUE);
DrawText(PChar(labels[objs[i].index]),
Round(hsw + objs[i].proj.x * hsw - l/2),
Round(hsh - objs[i].proj.y * hsh), 24, WHITE);
// Draw coordinates
ft := Format('%2.3f %2.3f', [objs[i].pos.x, objs[i].pos.z]);
l := MeasureText(PChar(ft), 24);
DrawRectangle(Round(hsw + objs[i].proj.x * hsw - 4 - l/2),
Round(hsh - objs[i].proj.y * hsh - 4 + 27),
l + 8, 27, BLUE);
DrawText(PChar(ft),
Round(hsw + objs[i].proj.x * hsw - l/2),
Round(hsh - objs[i].proj.y * hsh + 27), 24, WHITE);
end;
if toggleRadar then
begin
// Draw radar
DrawCircle(Round(hsw + (objs[i].proj.x / objs[i].proj.w) * (hsw/32)),
Round(screenHeight - (hsh/3) - (objs[i].proj.y / objs[i].proj.w) * (hsh/32)),
3, RED);
end;
end;
// Draw frame counter
ft := Format('Frame %d', [frame]);
l := MeasureText(PChar(ft), 20);
DrawRectangle(16, 698, l + 8, 42, BLUE);
DrawText(PChar(ft), 20, 700, 20, WHITE);
EndDrawing();
end;
// Cleanup
for i := 0 to 3 do
UnloadModel(models[i]);
UnloadTexture(tex);
CloseWindow();
end.