System: Windows XP SP1, Pentium D 805 2,66 GHz 2 GB RAM, GeForce 7600 GS
Compiler/IDE: Delphi 2007
Libraries/API: JEDI-SDL
---
Hello again.

This time I've got a different problem. I want to make a camera class for my engine. So far, I've got this:
[pascal]

type
{ .: TCoordinates :. }
TCoordinates = class(TPersistent)
private
{ Private declarations }
FVec: TAffineVector;
function GetVecAsString(): String;
public
{ Public declarations }
constructor Create();
procedure Assign(Source: TPersistent); override;

property X: Single read FVec[0] write FVec[0];
property Y: Single read FVec[1] write FVec[1];
property Z: Single read FVec[2] write FVec[2];

property AsVector: TAffineVector read FVec;
property AsString: String read GetVecAsString;
end;

{ .: TCamera :. }
TCamera = class(TPersistent)
private
{ Private declarations }
FRight: TCoordinates;
FViewDir: TCoordinates;
FUp: TCoordinates;
FPos: TCoordinates;
procedure SetPos(const Value: TCoordinates);
procedure SetRight(const Value: TCoordinates);
procedure SetUp(const Value: TCoordinates);
procedure SetViewDir(const Value: TCoordinates);
protected
{ Protected declarations }
RotatedX, RotatedY, RotatedZ: Single;
public
{ Public declarations }
constructor Create();
destructor Destroy(); override;

procedure Assign(Source: TPersistent); override;

procedure Move(const ADirection: TAffineVector);
procedure RotateX(const ARotAngle: Single);
procedure RotateY(const ARotAngle: Single);
procedure RotateZ(const ARotAngle: Single);
procedure MoveForward(const ADistance: Single);
procedure MoveUpward(const ADistance: Single);
procedure StrafeRight(const ADistance: Single);

procedure Render();

property Position: TCoordinates read FPos write SetPos;
property ViewDirection: TCoordinates read FViewDir write SetViewDir;
property Right: TCoordinates read FRight write SetRight;
property Up: TCoordinates read FUp write SetUp;
end;

{ TCamera }

procedure TCamera.Assign(Source: TPersistent);
begin
if (Source is TCamera) then
begin
FPos.Assign(TCamera(Source).Position);
FViewDir.Assign(TCamera(Source).ViewDirection);
FRight.Assign(TCamera(Source).Right);
FUp.Assign(TCamera(Source).Up);
end else
inherited;
end;

constructor TCamera.Create;
begin
inherited Create();

FPos := TCoordinates.Create();
FViewDir := TCoordinates.Create();
FViewDir.Z := -1.0;
FRight := TCoordinates.Create();
FRight.X := 1.0;
FUp := TCoordinates.Create();
FUp.Y := 1.0;

RotatedX := 0.0;
RotatedY := 0.0;
RotatedZ := 0.0;
end;

destructor TCamera.Destroy;
begin
FPos.Free();
FViewDir.Free();
FRight.Free();
FUp.Free();

inherited Destroy();
end;

procedure TCamera.Move(const ADirection: TAffineVector);
begin
with FPos do
begin
X := X + ADirection[0];
Y := Y + ADirection[1];
Z := Z + ADirection[2];
end;
end;

procedure TCamera.MoveForward(const ADistance: Single);
var
V: TAffineVector;
begin
V := FPos.AsVector;
V := VectorAdd(V, VectorScale(FViewDir.AsVector, -ADistance));
FPos.X := V[0];
FPos.Y := V[1];
FPos.Z := V[2];
end;

procedure TCamera.MoveUpward(const ADistance: Single);
var
V: TAffineVector;
begin
V := FPos.AsVector;
V := VectorAdd(V, VectorScale(FUp.AsVector, ADistance));
FPos.X := V[0];
FPos.Y := V[1];
FPos.Z := V[2];
end;

procedure TCamera.Render;
var
V: TAffineVector;
begin
V := VectorAdd(FPos.AsVector, FViewDir.AsVector);

gluLookAt(FPos.X, FPos.Y, FPos.Z, V[0], V[1], V[2], FUp.X, FUp.Y, FUp.Z);
end;

procedure TCamera.RotateX(const ARotAngle: Single);
var
V, V1, V2: TAffineVector;
begin
RotatedX := RotatedX + ARotAngle;

V := FViewDir.AsVector;
V1 := FUp.AsVector;
V := VectorScale(V, Cos(ARotAngle * PIDIV180));
V1 := VectorScale(V1, Sin(ARotAngle * PIDIV180));
V := VectorNormalize(VectorAdd(V, V1));

V2 := VectorCrossProduct(V, FRight.AsVector);
V2 := VectorScale(V2, -1.0);

FViewDir.X := V[0];
FViewDir.Y := V[1];
FViewDir.Z := V[2];

FUp.X := V2[0];
FUp.Y := V2[1];
FUp.Z := V2[2];
end;

procedure TCamera.RotateY(const ARotAngle: Single);
var
V, V1, V2: TAffineVector;
begin
RotatedY := RotatedY + ARotAngle;

V := FViewDir.AsVector;
V1 := FRight.AsVector;
V := VectorScale(V, Cos(ARotAngle * PIDIV180));
V1 := VectorScale(V1, Sin(ARotAngle * PIDIV180));
V := VectorNormalize(VectorSubtract(V, V1));

V2 := VectorCrossProduct(V, FUp.AsVector);

FViewDir.X := V[0];
FViewDir.Y := V[1];
FViewDir.Z := V[2];

FRight.X := V2[0];
FRight.Y := V2[1];
FRight.Z := V2[2];
end;

procedure TCamera.RotateZ(const ARotAngle: Single);
var
V, V1, V2: TAffineVector;
begin
RotatedZ := RotatedZ + ARotAngle;

V := FRight.AsVector;
V1 := FUp.AsVector;
V := VectorScale(V, Cos(ARotAngle * PIDIV180));
V1 := VectorScale(V1, Sin(ARotAngle * PIDIV180));
V := VectorNormalize(VectorAdd(V, V1));

V2 := VectorCrossProduct(FViewDir.AsVector, V);
V2 := VectorScale(V2, -1.0);

FRight.X := V[0];
FRight.Y := V[1];
FRight.Z := V[2];

FUp.X := V2[0];
FUp.Y := V2[1];
FUp.Z := V2[2];
end;

procedure TCamera.SetPos(const Value: TCoordinates);
begin
FPos := Value;
end;

procedure TCamera.SetRight(const Value: TCoordinates);
begin
FRight := Value;
end;

procedure TCamera.SetUp(const Value: TCoordinates);
begin
FUp := Value;
end;

procedure TCamera.SetViewDir(const Value: TCoordinates);
begin
FViewDir := Value;
end;

procedure TCamera.StrafeRight(const ADistance: Single);
var
V: TAffineVector;
begin
V := FPos.AsVector;
V := VectorAdd(V, VectorScale(FRight.AsVector, ADistance));
FPos.X := V[0];
FPos.Y := V[1];
FPos.Z := V[2];
end;
[/pascal]

But this class is working wrong for me. Could you fix it for me, please? Or maybe you know other solutions of the problem? :? I've heard that a quaternion-based camera system is good and the most efficient. Is that true?

Thank you in advance