Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //******************************************************************************
- //
- // BrainEngine
- // Copyright © 2008 - 2010 Patryk Nusbaum.
- // All rights reserved.
- //
- // Last modified: 24.03.2010
- // Mail: patrick.nusbaum@gmail.com
- // WWW: www.pateman.net76.net
- //
- // License
- // -------------------
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the distribution.
- // * Neither the name of Patryk Nusbaum nor the names of his contributors
- // may be used to endorse or promote products derived from this software
- // without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- //******************************************************************************
- unit BrainCamera;
- interface
- uses
- Math, Classes,
- // --
- dglOpenGL, BrainObject, BrainMath;
- type
- { .: TBrainCameraProjectionType :. }
- TBrainCameraProjectionType = (ptPerspective, ptOrthogonal);
- { .: TBrainCameraType :. }
- TBrainCameraType = (ctFree, ctFirstPerson, ctThirdPerson);
- { .: TBrainCamera :. }
- TBrainCamera = class sealed(TBrainObject)
- private
- { Private declarations }
- FWidth: Integer;
- FProjMat: TBrainMatrix;
- FHeight: Integer;
- FFOV: Single;
- FFar: Single;
- FNear: Single;
- FProjType: TBrainCameraProjectionType;
- FMouseSmooth: Single;
- FMaxAngle: Single;
- FMinAngle: Single;
- FInvert: Boolean;
- FCamType: TBrainCameraType;
- FTarget: TBrainObject;
- FDist: TBrainVector;
- procedure SetViewport(const Index, Value: Integer);
- procedure SetProjType(const Value: TBrainCameraProjectionType);
- protected
- { Protected declarations }
- CenterX, CenterY: Integer;
- ViewMat: TBrainMatrix;
- procedure UpdateThirdPersonMatrix();
- function GetMatrix(): TBrainMatrix; override;
- public
- { Public declarations }
- constructor Create(const AObjName: String; const AViewportWidth,
- AViewportHeight: Integer);
- destructor Destroy(); override;
- procedure Assign(const Source: TBrainObject); override;
- procedure LoadFromStream(const S: TStream); override;
- procedure SaveToStream(const S: TStream); override;
- procedure Move(const AFactor: Single); override;
- procedure Strafe(const AFactor: Single); override;
- procedure Turn(const ADegrees: Single); override;
- procedure Pitch(const ADegrees: Single); override;
- procedure Roll(const ADegrees: Single); override;
- procedure MouseLook(const CursorX, CursorY: Integer);
- procedure UpdateViewport();
- property ProjectionMatrix: TBrainMatrix read FProjMat;
- property ProjectionType: TBrainCameraProjectionType read FProjType
- write SetProjType;
- property ViewportWidth: Integer index 0 read FWidth write SetViewport;
- property ViewportHeight: Integer index 1 read FHeight write SetViewport;
- property FieldOfView: Single read FFOV write FFOV;
- property NearPlane: Single read FNear write FNear;
- property FarPlane: Single read FFar write FFar;
- property CameraType: TBrainCameraType read FCamType write FCamType;
- property InvertAxis: Boolean read FInvert write FInvert;
- property MouseSmoothing: Single read FMouseSmooth write FMouseSmooth;
- property MaxAngle: Single read FMaxAngle write FMaxAngle;
- property MinAngle: Single read FMinAngle write FMinAngle;
- property Target: TBrainObject read FTarget write FTarget;
- property DistanceFromTarget: TBrainVector read FDist write FDist;
- end;
- implementation
- uses
- Windows, BrainLogger, SysUtils;
- { TBrainCamera }
- procedure TBrainCamera.Assign(const Source: TBrainObject);
- begin
- inherited Assign(Source);
- if (Assigned(Source)) and (Source is TBrainCamera) then
- begin
- FWidth := TBrainCamera(Source).ViewportWidth;
- FHeight := TBrainCamera(Source).ViewportHeight;
- CenterX := TBrainCamera(Source).CenterX;
- CenterY := TBrainCamera(Source).CenterY;
- FFOV := TBrainCamera(Source).FieldOfView;
- FNear := TBrainCamera(Source).NearPlane;
- FFar := TBrainCamera(Source).FarPlane;
- FCamType := TBrainCamera(Source).CameraType;
- FInvert := TBrainCamera(Source).InvertAxis;
- FMouseSmooth := TBrainCamera(Source).MouseSmoothing;
- FMaxAngle := TBrainCamera(Source).MaxAngle;
- FMinAngle := TBrainCamera(Source).MinAngle;
- FTarget := TBrainCamera(Source).Target;
- FDist := TBrainCamera(Source).DistanceFromTarget;
- Self.SetProjType(TBrainCamera(Source).ProjectionType);
- end;
- end;
- constructor TBrainCamera.Create(const AObjName: String; const AViewportWidth,
- AViewportHeight: Integer);
- begin
- inherited Create(AObjName);
- FWidth := AViewportWidth;
- FHeight := AViewportHeight;
- if (FHeight <= 0) then
- FHeight := 1;
- CenterX := FWidth div 2;
- CenterY := FHeight div 2;
- FFOV := 60.0;
- FNear := 0.1;
- FFar := 100.0;
- FCamType := ctFree;
- FInvert := False;
- FMouseSmooth := 0.25;
- FMaxAngle := 69.0;
- FMinAngle := -69.0;
- FTarget := nil;
- FDist := Vec3(0.0, 0.0, 5.0);
- FProjType := ptOrthogonal;
- SetProjType(ptPerspective);
- end;
- destructor TBrainCamera.Destroy;
- begin
- FTarget := nil;
- inherited Destroy();
- end;
- function TBrainCamera.GetMatrix: TBrainMatrix;
- // Thanks to User137 for these two!
- // ("[...] LookAt function has to use CreateMatrix2 that uses opposite
- // row direction [...]")
- { .: CreateMatrix2 :. }
- function CreateMatrix2(const x, y, z: TBrainVector): TBrainMatrix;
- begin
- Result.M[0, 0] := x.x;
- Result.M[1, 0] := x.y;
- Result.M[2, 0] := x.z;
- Result.M[3, 0] := 0.0;
- Result.M[0, 1] := y.x;
- Result.M[1, 1] := y.y;
- Result.M[2, 1] := y.z;
- Result.M[3, 1] := 0.0;
- Result.M[0, 2] := z.x;
- Result.M[1, 2] := z.y;
- Result.M[2, 2] := z.z;
- Result.M[3, 2] := 0.0;
- Result.M[0, 3] := 0.0;
- Result.M[1, 3] := 0.0;
- Result.M[2, 3] := 0.0;
- Result.M[3, 3] := 1.0;
- end;
- { .: LookAt :. }
- function LookAt(const eye, target, up: TBrainVector): TBrainMatrix;
- var
- x, y, z: TBrainVector;
- begin
- z := Vec3Normalize(Vec3Subtract(eye, target));
- x := Vec3Normalize(Vec3CrossProduct(up, z));
- y := Vec3Normalize(Vec3CrossProduct(z, x));
- Result := CreateMatrix2(x, y, z);
- Result := Mat4Translate(Result, Vec3(-Vec3DotProduct(eye, x),
- -Vec3DotProduct(eye, y), -Vec3DotProduct(eye, z)));
- end;
- begin
- if UpdateNeeded then
- begin
- case FCamType of
- ctFree, ctFirstPerson:
- CachedMatrix := LookAt(Position, Vec3Add(Position, Vec3Negate(Direction)),
- Up);
- ctThirdPerson:
- if (not Assigned(FTarget)) then
- CachedMatrix := Mat4Identity()
- else
- begin
- UpdateThirdPersonMatrix();
- CachedMatrix := ViewMat;
- end;
- end;
- UpdateNeeded := False;
- end;
- Result := CachedMatrix;
- end;
- procedure TBrainCamera.LoadFromStream(const S: TStream);
- begin
- inherited LoadFromStream(S);
- if Assigned(S) then
- begin
- S.Read(FWidth, SizeOf(Integer));
- S.Read(FHeight, SizeOf(Integer));
- CenterX := FWidth div 2;
- CenterY := FHeight div 2;
- S.Read(FFOV, SizeOf(Single));
- S.Read(FNear, SizeOf(Single));
- S.Read(FFar, SizeOf(Single));
- S.Read(FProjType, SizeOf(TBrainCameraProjectionType));
- Self.SetProjType(FProjType);
- S.Read(FCamType, SizeOf(TBrainCameraType));
- S.Read(FInvert, SizeOf(Boolean));
- S.Read(FMouseSmooth, SizeOf(Single));
- S.Read(FMaxAngle, SizeOf(Single));
- S.Read(FMinAngle, SizeOf(Single));
- S.Read(FDist, SizeOf(TBrainVector));
- end;
- end;
- procedure TBrainCamera.MouseLook(const CursorX, CursorY: Integer);
- var
- DeltaX, DeltaY: Single;
- R: TBrainEuler;
- begin
- if (CursorX = CenterX) and (CursorY = CenterY) then
- exit;
- DeltaX := CenterX - CursorX;
- DeltaY := CenterY - CursorY;
- R := Rotation; // for convenience
- R.Yaw := R.Yaw - DeltaX * FMouseSmooth;
- if FInvert then
- begin
- if (FCamType <> ctThirdPerson) then
- R.Pitch := R.Pitch - DeltaY * FMouseSmooth
- else
- R.Pitch := R.Pitch + DeltaY * FMouseSmooth;
- end else
- if (FCamType <> ctThirdPerson) then
- R.Pitch := R.Pitch + DeltaY * FMouseSmooth
- else
- R.Pitch := R.Pitch - DeltaY * FMouseSmooth;
- if (R.Pitch < FMinAngle) then
- R.Pitch := FMinAngle;
- if (R.Pitch > FMaxAngle) then
- R.Pitch := FMaxAngle;
- Rotation := R;
- if (FCamType = ctThirdPerson) and (Assigned(FTarget)) then
- FTarget.Rotation := Euler(FTarget.Rotation.Pitch, -R.Yaw,
- FTarget.Rotation.Roll);
- SetCursorPos(CenterX, CenterY);
- UpdateNeeded := True;
- UpdateInvNeeded := True;
- end;
- procedure TBrainCamera.Move(const AFactor: Single);
- begin
- if (AFactor <> 0.0) then
- begin
- case FCamType of
- ctFree:
- inherited Move(AFactor);
- ctFirstPerson:
- Position := Vec3(Position.X + (Direction.X * -AFactor),
- Position.Y, Position.Z + (Direction.Z * -AFactor));
- ctThirdPerson:
- if Assigned(FTarget) then
- FTarget.Move(AFactor);
- end;
- UpdateNeeded := True;
- UpdateInvNeeded := True;
- end;
- end;
- procedure TBrainCamera.Pitch(const ADegrees: Single);
- begin
- if (FCamType <> ctThirdPerson) then
- inherited Pitch(ADegrees)
- else
- inherited Pitch(-ADegrees);
- end;
- procedure TBrainCamera.Roll(const ADegrees: Single);
- begin
- if (FCamType <> ctThirdPerson) then
- inherited Roll(ADegrees)
- else
- inherited Roll(-ADegrees);
- end;
- procedure TBrainCamera.SaveToStream(const S: TStream);
- begin
- inherited SaveToStream(S);
- if Assigned(S) then
- begin
- S.Write(FWidth, SizeOf(Integer));
- S.Write(FHeight, SizeOf(Integer));
- S.Write(FFOV, SizeOf(Single));
- S.Write(FNear, SizeOf(Single));
- S.Write(FFar, SizeOf(Single));
- S.Write(FProjType, SizeOf(TBrainCameraProjectionType));
- S.Write(FCamType, SizeOf(TBrainCameraType));
- S.Write(FInvert, SizeOf(Boolean));
- S.Write(FMouseSmooth, SizeOf(Single));
- S.Write(FMaxAngle, SizeOf(Single));
- S.Write(FMinAngle, SizeOf(Single));
- S.Write(FDist, SizeOf(TBrainVector));
- end;
- end;
- procedure TBrainCamera.SetProjType(const Value: TBrainCameraProjectionType);
- begin
- if (Value <> FProjType) then
- begin
- FProjType := Value;
- case FProjType of
- ptPerspective:
- FProjMat := Mat4CreatePerspective(FFOV, FWidth / FHeight, FNear, FFar);
- ptOrthogonal:
- FProjMat := Mat4CreateOrtho(-FWidth / 2.0, FWidth / 2.0, -FHeight / 2.0,
- FHeight / 2.0, FNear, FFar);
- end;
- end;
- end;
- procedure TBrainCamera.SetViewport(const Index, Value: Integer);
- begin
- case Index of
- 0:
- FWidth := Value;
- 1:
- begin
- FHeight := Value;
- if (FHeight <= 0) then
- FHeight := 1;
- end;
- end;
- CenterX := FWidth div 2;
- CenterY := FHeight div 2;
- end;
- procedure TBrainCamera.Strafe(const AFactor: Single);
- begin
- if (AFactor <> 0.0) then
- begin
- if (FCamType <> ctThirdPerson) then
- inherited Strafe(AFactor)
- else
- if Assigned(FTarget) then
- FTarget.Strafe(-AFactor);
- UpdateNeeded := True;
- UpdateInvNeeded := True;
- end;
- end;
- procedure TBrainCamera.Turn(const ADegrees: Single);
- begin
- if (ADegrees <> 0.0) then
- begin
- if (FCamType <> ctThirdPerson) then
- inherited Turn(ADegrees)
- else
- if Assigned(FTarget) then
- begin
- FTarget.Turn(-ADegrees);
- inherited Turn(ADegrees);
- end;
- UpdateNeeded := True;
- UpdateInvNeeded := True;
- end;
- end;
- procedure TBrainCamera.UpdateThirdPersonMatrix;
- var
- X, Y, Z, Eye: TBrainVector;
- begin
- // Based on the code by dhpoware.
- ViewMat := Mat4Transpose(QuaternionToMatrix(QuaternionFromEuler(Rotation)));
- X := Vec3Normalize(Vec3(-ViewMat.M[0, 0], -ViewMat.M[1, 0], -ViewMat.M[2, 0]));
- Y := Vec3Normalize(Vec3(ViewMat.M[0, 1], ViewMat.M[1, 1], ViewMat.M[2, 1]));
- Z := Vec3Normalize(Vec3(ViewMat.M[0, 2], ViewMat.M[1, 2], ViewMat.M[2, 2]));
- Eye := Vec3Add(Vec3Negate(FTarget.Position), Z);
- ViewMat := Mat4Identity();
- ViewMat.M[0][0] := X.X;
- ViewMat.M[1][0] := X.Y;
- ViewMat.M[2][0] := X.Z;
- ViewMat.M[3][0] := -Vec3DotProduct(X, Eye) - FDist.X;
- ViewMat.M[0][1] := Y.X;
- ViewMat.M[1][1] := Y.Y;
- ViewMat.M[2][1] := Y.Z;
- ViewMat.M[3][1] := -Vec3DotProduct(Y, Eye) - FDist.Y;
- ViewMat.M[0][2] := Z.X;
- ViewMat.M[1][2] := Z.Y;
- ViewMat.M[2][2] := Z.Z;
- ViewMat.M[3][2] := -Vec3DotProduct(Z, Eye) - FDist.Z;
- end;
- procedure TBrainCamera.UpdateViewport;
- begin
- glViewport(0, 0, FWidth, FHeight);
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement