Advertisement
Guest User

BrainCamera.pas

a guest
Mar 26th, 2010
260
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 13.82 KB | None | 0 0
  1. //******************************************************************************
  2. //
  3. //    BrainEngine
  4. //    Copyright © 2008 - 2010 Patryk Nusbaum.
  5. //    All rights reserved.
  6. //
  7. //    Last modified: 24.03.2010
  8. //    Mail: patrick.nusbaum@gmail.com
  9. //    WWW: www.pateman.net76.net
  10. //
  11. //    License
  12. //    -------------------
  13. //    Redistribution and use in source and binary forms, with or without
  14. //    modification, are permitted provided that the following conditions are
  15. //    met:
  16. //
  17. //      * Redistributions of source code must retain the above copyright notice,
  18. //        this list of conditions and the following disclaimer.
  19. //      * Redistributions in binary form must reproduce the above copyright
  20. //        notice, this list of conditions and the following disclaimer in the
  21. //        documentation and/or other materials provided with the distribution.
  22. //      * Neither the name of Patryk Nusbaum nor the names of his contributors
  23. //        may be used to endorse or promote products derived from this software
  24. //        without specific prior written permission.
  25. //
  26. //    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  27. //    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  28. //    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29. //    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  30. //    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31. //    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32. //    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  33. //    OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  34. //    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  35. //    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  36. //    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37. //******************************************************************************
  38. unit BrainCamera;
  39.  
  40. interface
  41.  
  42. uses
  43.   Math, Classes,
  44.   // --
  45.   dglOpenGL, BrainObject, BrainMath;
  46.  
  47. type
  48.   { .: TBrainCameraProjectionType :. }
  49.   TBrainCameraProjectionType = (ptPerspective, ptOrthogonal);
  50.  
  51.   { .: TBrainCameraType :. }
  52.   TBrainCameraType = (ctFree, ctFirstPerson, ctThirdPerson);
  53.  
  54.   { .: TBrainCamera :. }
  55.   TBrainCamera = class sealed(TBrainObject)
  56.   private
  57.     { Private declarations }
  58.     FWidth: Integer;
  59.     FProjMat: TBrainMatrix;
  60.     FHeight: Integer;
  61.     FFOV: Single;
  62.     FFar: Single;
  63.     FNear: Single;
  64.     FProjType: TBrainCameraProjectionType;
  65.     FMouseSmooth: Single;
  66.     FMaxAngle: Single;
  67.     FMinAngle: Single;
  68.     FInvert: Boolean;
  69.     FCamType: TBrainCameraType;
  70.     FTarget: TBrainObject;
  71.     FDist: TBrainVector;
  72.     procedure SetViewport(const Index, Value: Integer);
  73.     procedure SetProjType(const Value: TBrainCameraProjectionType);
  74.   protected
  75.     { Protected declarations }
  76.     CenterX, CenterY: Integer;
  77.     ViewMat: TBrainMatrix;
  78.     procedure UpdateThirdPersonMatrix();
  79.     function GetMatrix(): TBrainMatrix; override;
  80.   public
  81.     { Public declarations }
  82.     constructor Create(const AObjName: String; const AViewportWidth,
  83.       AViewportHeight: Integer);
  84.     destructor Destroy(); override;
  85.  
  86.     procedure Assign(const Source: TBrainObject); override;
  87.     procedure LoadFromStream(const S: TStream); override;
  88.     procedure SaveToStream(const S: TStream); override;
  89.  
  90.     procedure Move(const AFactor: Single); override;
  91.     procedure Strafe(const AFactor: Single); override;
  92.     procedure Turn(const ADegrees: Single); override;
  93.     procedure Pitch(const ADegrees: Single); override;
  94.     procedure Roll(const ADegrees: Single); override;
  95.     procedure MouseLook(const CursorX, CursorY: Integer);
  96.  
  97.     procedure UpdateViewport();
  98.  
  99.     property ProjectionMatrix: TBrainMatrix read FProjMat;
  100.     property ProjectionType: TBrainCameraProjectionType read FProjType
  101.       write SetProjType;
  102.  
  103.     property ViewportWidth: Integer index 0 read FWidth write SetViewport;
  104.     property ViewportHeight: Integer index 1 read FHeight write SetViewport;
  105.  
  106.     property FieldOfView: Single read FFOV write FFOV;
  107.     property NearPlane: Single read FNear write FNear;
  108.     property FarPlane: Single read FFar write FFar;
  109.  
  110.     property CameraType: TBrainCameraType read FCamType write FCamType;
  111.     property InvertAxis: Boolean read FInvert write FInvert;
  112.     property MouseSmoothing: Single read FMouseSmooth write FMouseSmooth;
  113.     property MaxAngle: Single read FMaxAngle write FMaxAngle;
  114.     property MinAngle: Single read FMinAngle write FMinAngle;
  115.     property Target: TBrainObject read FTarget write FTarget;
  116.     property DistanceFromTarget: TBrainVector read FDist write FDist;
  117.   end;
  118.  
  119. implementation
  120.  
  121. uses
  122.   Windows, BrainLogger, SysUtils;
  123.  
  124. { TBrainCamera }
  125.  
  126. procedure TBrainCamera.Assign(const Source: TBrainObject);
  127. begin
  128.   inherited Assign(Source);
  129.  
  130.   if (Assigned(Source)) and (Source is TBrainCamera) then
  131.   begin
  132.     FWidth := TBrainCamera(Source).ViewportWidth;
  133.     FHeight := TBrainCamera(Source).ViewportHeight;
  134.     CenterX := TBrainCamera(Source).CenterX;
  135.     CenterY := TBrainCamera(Source).CenterY;
  136.  
  137.     FFOV := TBrainCamera(Source).FieldOfView;
  138.     FNear := TBrainCamera(Source).NearPlane;
  139.     FFar := TBrainCamera(Source).FarPlane;
  140.  
  141.     FCamType := TBrainCamera(Source).CameraType;
  142.     FInvert := TBrainCamera(Source).InvertAxis;
  143.     FMouseSmooth := TBrainCamera(Source).MouseSmoothing;
  144.     FMaxAngle := TBrainCamera(Source).MaxAngle;
  145.     FMinAngle := TBrainCamera(Source).MinAngle;
  146.     FTarget := TBrainCamera(Source).Target;
  147.     FDist := TBrainCamera(Source).DistanceFromTarget;
  148.  
  149.     Self.SetProjType(TBrainCamera(Source).ProjectionType);
  150.   end;
  151. end;
  152.  
  153. constructor TBrainCamera.Create(const AObjName: String; const AViewportWidth,
  154.   AViewportHeight: Integer);
  155. begin
  156.   inherited Create(AObjName);
  157.  
  158.   FWidth := AViewportWidth;
  159.   FHeight := AViewportHeight;
  160.   if (FHeight <= 0) then
  161.     FHeight := 1;
  162.   CenterX := FWidth div 2;
  163.   CenterY := FHeight div 2;
  164.  
  165.   FFOV := 60.0;
  166.   FNear := 0.1;
  167.   FFar := 100.0;
  168.  
  169.   FCamType := ctFree;
  170.   FInvert := False;
  171.   FMouseSmooth := 0.25;
  172.   FMaxAngle := 69.0;
  173.   FMinAngle := -69.0;
  174.  
  175.   FTarget := nil;
  176.   FDist := Vec3(0.0, 0.0, 5.0);
  177.  
  178.   FProjType := ptOrthogonal;
  179.   SetProjType(ptPerspective);
  180. end;
  181.  
  182. destructor TBrainCamera.Destroy;
  183. begin
  184.   FTarget := nil;
  185.  
  186.   inherited Destroy();
  187. end;
  188.  
  189. function TBrainCamera.GetMatrix: TBrainMatrix;
  190.  
  191.   //  Thanks to User137 for these two!
  192.   //  ("[...] LookAt function has to use CreateMatrix2 that uses opposite
  193.   //  row direction [...]")
  194.   { .: CreateMatrix2 :. }
  195.   function CreateMatrix2(const x, y, z: TBrainVector): TBrainMatrix;
  196.   begin
  197.     Result.M[0, 0] := x.x;
  198.     Result.M[1, 0] := x.y;
  199.     Result.M[2, 0] := x.z;
  200.     Result.M[3, 0] := 0.0;
  201.     Result.M[0, 1] := y.x;
  202.     Result.M[1, 1] := y.y;
  203.     Result.M[2, 1] := y.z;
  204.     Result.M[3, 1] := 0.0;
  205.     Result.M[0, 2] := z.x;
  206.     Result.M[1, 2] := z.y;
  207.     Result.M[2, 2] := z.z;
  208.     Result.M[3, 2] := 0.0;
  209.     Result.M[0, 3] := 0.0;
  210.     Result.M[1, 3] := 0.0;
  211.     Result.M[2, 3] := 0.0;
  212.     Result.M[3, 3] := 1.0;
  213.   end;
  214.  
  215.   { .: LookAt :. }
  216.   function LookAt(const eye, target, up: TBrainVector): TBrainMatrix;
  217.   var
  218.     x, y, z: TBrainVector;
  219.   begin
  220.     z := Vec3Normalize(Vec3Subtract(eye, target));
  221.     x := Vec3Normalize(Vec3CrossProduct(up, z));
  222.     y := Vec3Normalize(Vec3CrossProduct(z, x));
  223.     Result := CreateMatrix2(x, y, z);
  224.     Result := Mat4Translate(Result, Vec3(-Vec3DotProduct(eye, x),
  225.       -Vec3DotProduct(eye, y), -Vec3DotProduct(eye, z)));
  226.   end;
  227.  
  228. begin
  229.   if UpdateNeeded then
  230.   begin
  231.     case FCamType of
  232.       ctFree, ctFirstPerson:
  233.         CachedMatrix := LookAt(Position, Vec3Add(Position, Vec3Negate(Direction)),
  234.           Up);
  235.       ctThirdPerson:
  236.           if (not Assigned(FTarget)) then
  237.             CachedMatrix := Mat4Identity()
  238.           else
  239.           begin
  240.             UpdateThirdPersonMatrix();
  241.             CachedMatrix := ViewMat;
  242.           end;
  243.     end;
  244.  
  245.     UpdateNeeded := False;
  246.   end;
  247.   Result := CachedMatrix;
  248. end;
  249.  
  250. procedure TBrainCamera.LoadFromStream(const S: TStream);
  251. begin
  252.   inherited LoadFromStream(S);
  253.  
  254.   if Assigned(S) then
  255.   begin
  256.     S.Read(FWidth, SizeOf(Integer));
  257.     S.Read(FHeight, SizeOf(Integer));
  258.     CenterX := FWidth div 2;
  259.     CenterY := FHeight div 2;
  260.  
  261.     S.Read(FFOV, SizeOf(Single));
  262.     S.Read(FNear, SizeOf(Single));
  263.     S.Read(FFar, SizeOf(Single));
  264.  
  265.     S.Read(FProjType, SizeOf(TBrainCameraProjectionType));
  266.     Self.SetProjType(FProjType);
  267.  
  268.     S.Read(FCamType, SizeOf(TBrainCameraType));
  269.     S.Read(FInvert, SizeOf(Boolean));
  270.     S.Read(FMouseSmooth, SizeOf(Single));
  271.     S.Read(FMaxAngle, SizeOf(Single));
  272.     S.Read(FMinAngle, SizeOf(Single));
  273.  
  274.     S.Read(FDist, SizeOf(TBrainVector));
  275.   end;
  276. end;
  277.  
  278. procedure TBrainCamera.MouseLook(const CursorX, CursorY: Integer);
  279. var
  280.   DeltaX, DeltaY: Single;
  281.   R: TBrainEuler;
  282. begin
  283.   if (CursorX = CenterX) and (CursorY = CenterY) then
  284.     exit;
  285.  
  286.   DeltaX := CenterX - CursorX;
  287.   DeltaY := CenterY - CursorY;
  288.  
  289.   R := Rotation;  //  for convenience
  290.   R.Yaw := R.Yaw - DeltaX * FMouseSmooth;
  291.  
  292.   if FInvert then
  293.   begin
  294.     if (FCamType <> ctThirdPerson) then
  295.       R.Pitch := R.Pitch - DeltaY * FMouseSmooth
  296.     else
  297.       R.Pitch := R.Pitch + DeltaY * FMouseSmooth;
  298.   end else
  299.     if (FCamType <> ctThirdPerson) then
  300.       R.Pitch := R.Pitch + DeltaY * FMouseSmooth
  301.     else
  302.       R.Pitch := R.Pitch - DeltaY * FMouseSmooth;
  303.  
  304.   if (R.Pitch < FMinAngle) then
  305.     R.Pitch := FMinAngle;
  306.   if (R.Pitch > FMaxAngle) then
  307.     R.Pitch := FMaxAngle;
  308.  
  309.   Rotation := R;
  310.  
  311.   if (FCamType = ctThirdPerson) and (Assigned(FTarget)) then
  312.     FTarget.Rotation := Euler(FTarget.Rotation.Pitch, -R.Yaw,
  313.       FTarget.Rotation.Roll);
  314.  
  315.   SetCursorPos(CenterX, CenterY);
  316.  
  317.   UpdateNeeded := True;
  318.   UpdateInvNeeded := True;
  319. end;
  320.  
  321. procedure TBrainCamera.Move(const AFactor: Single);
  322. begin
  323.   if (AFactor <> 0.0) then
  324.   begin
  325.     case FCamType of
  326.       ctFree:
  327.         inherited Move(AFactor);
  328.       ctFirstPerson:
  329.         Position := Vec3(Position.X + (Direction.X * -AFactor),
  330.           Position.Y, Position.Z + (Direction.Z * -AFactor));
  331.       ctThirdPerson:
  332.         if Assigned(FTarget) then
  333.           FTarget.Move(AFactor);
  334.     end;
  335.  
  336.     UpdateNeeded := True;
  337.     UpdateInvNeeded := True;
  338.   end;
  339. end;
  340.  
  341. procedure TBrainCamera.Pitch(const ADegrees: Single);
  342. begin
  343.   if (FCamType <> ctThirdPerson) then
  344.     inherited Pitch(ADegrees)
  345.   else
  346.     inherited Pitch(-ADegrees);
  347. end;
  348.  
  349. procedure TBrainCamera.Roll(const ADegrees: Single);
  350. begin
  351.   if (FCamType <> ctThirdPerson) then
  352.     inherited Roll(ADegrees)
  353.   else
  354.     inherited Roll(-ADegrees);
  355. end;
  356.  
  357. procedure TBrainCamera.SaveToStream(const S: TStream);
  358. begin
  359.   inherited SaveToStream(S);
  360.  
  361.   if Assigned(S) then
  362.   begin
  363.     S.Write(FWidth, SizeOf(Integer));
  364.     S.Write(FHeight, SizeOf(Integer));
  365.  
  366.     S.Write(FFOV, SizeOf(Single));
  367.     S.Write(FNear, SizeOf(Single));
  368.     S.Write(FFar, SizeOf(Single));
  369.  
  370.     S.Write(FProjType, SizeOf(TBrainCameraProjectionType));
  371.  
  372.     S.Write(FCamType, SizeOf(TBrainCameraType));
  373.     S.Write(FInvert, SizeOf(Boolean));
  374.     S.Write(FMouseSmooth, SizeOf(Single));
  375.     S.Write(FMaxAngle, SizeOf(Single));
  376.     S.Write(FMinAngle, SizeOf(Single));
  377.  
  378.     S.Write(FDist, SizeOf(TBrainVector));
  379.   end;
  380. end;
  381.  
  382. procedure TBrainCamera.SetProjType(const Value: TBrainCameraProjectionType);
  383. begin
  384.   if (Value <> FProjType) then
  385.   begin
  386.     FProjType := Value;
  387.  
  388.     case FProjType of
  389.       ptPerspective:
  390.         FProjMat := Mat4CreatePerspective(FFOV, FWidth / FHeight, FNear, FFar);
  391.       ptOrthogonal:
  392.         FProjMat := Mat4CreateOrtho(-FWidth / 2.0, FWidth / 2.0, -FHeight / 2.0,
  393.           FHeight / 2.0, FNear, FFar);
  394.     end;
  395.   end;
  396. end;
  397.  
  398. procedure TBrainCamera.SetViewport(const Index, Value: Integer);
  399. begin
  400.   case Index of
  401.     0:
  402.       FWidth := Value;
  403.     1:
  404.       begin
  405.         FHeight := Value;
  406.         if (FHeight <= 0) then
  407.           FHeight := 1;
  408.       end;
  409.   end;
  410.   CenterX := FWidth div 2;
  411.   CenterY := FHeight div 2;
  412. end;
  413.  
  414. procedure TBrainCamera.Strafe(const AFactor: Single);
  415. begin
  416.   if (AFactor <> 0.0) then
  417.   begin
  418.     if (FCamType <> ctThirdPerson) then
  419.       inherited Strafe(AFactor)
  420.     else
  421.       if Assigned(FTarget) then
  422.         FTarget.Strafe(-AFactor);
  423.  
  424.     UpdateNeeded := True;
  425.     UpdateInvNeeded := True;
  426.   end;
  427. end;
  428.  
  429. procedure TBrainCamera.Turn(const ADegrees: Single);
  430. begin
  431.   if (ADegrees <> 0.0) then
  432.   begin
  433.     if (FCamType <> ctThirdPerson) then
  434.       inherited Turn(ADegrees)
  435.     else
  436.       if Assigned(FTarget) then
  437.       begin
  438.         FTarget.Turn(-ADegrees);
  439.         inherited Turn(ADegrees);
  440.       end;
  441.  
  442.     UpdateNeeded := True;
  443.     UpdateInvNeeded := True;
  444.   end;
  445. end;
  446.  
  447. procedure TBrainCamera.UpdateThirdPersonMatrix;
  448. var
  449.   X, Y, Z, Eye: TBrainVector;
  450. begin
  451.   //  Based on the code by dhpoware.
  452.   ViewMat := Mat4Transpose(QuaternionToMatrix(QuaternionFromEuler(Rotation)));
  453.  
  454.   X := Vec3Normalize(Vec3(-ViewMat.M[0, 0], -ViewMat.M[1, 0], -ViewMat.M[2, 0]));
  455.   Y := Vec3Normalize(Vec3(ViewMat.M[0, 1], ViewMat.M[1, 1], ViewMat.M[2, 1]));
  456.   Z := Vec3Normalize(Vec3(ViewMat.M[0, 2], ViewMat.M[1, 2], ViewMat.M[2, 2]));
  457.   Eye := Vec3Add(Vec3Negate(FTarget.Position), Z);
  458.  
  459.   ViewMat := Mat4Identity();
  460.   ViewMat.M[0][0] := X.X;
  461.   ViewMat.M[1][0] := X.Y;
  462.   ViewMat.M[2][0] := X.Z;
  463.   ViewMat.M[3][0] := -Vec3DotProduct(X, Eye) - FDist.X;
  464.  
  465.   ViewMat.M[0][1] := Y.X;
  466.   ViewMat.M[1][1] := Y.Y;
  467.   ViewMat.M[2][1] := Y.Z;
  468.   ViewMat.M[3][1] := -Vec3DotProduct(Y, Eye) - FDist.Y;
  469.  
  470.   ViewMat.M[0][2] := Z.X;
  471.   ViewMat.M[1][2] := Z.Y;
  472.   ViewMat.M[2][2] := Z.Z;
  473.   ViewMat.M[3][2] := -Vec3DotProduct(Z, Eye) - FDist.Z;
  474. end;
  475.  
  476. procedure TBrainCamera.UpdateViewport;
  477. begin
  478.   glViewport(0, 0, FWidth, FHeight);
  479. end;
  480.  
  481. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement