Code:
//******************************************************************************
//
// BrainEngine
// Copyright © 2008 - 2010 Patryk Nusbaum.
// All rights reserved.
//
// Last modified: 30.01.2010
// Mail: patrick.nusbaum@gmail.com
// WWW: www.pateman.net76.net
//
// Based on code by Luuk van Venrooij.
//
// 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
Windows, dglOpenGL, BrainMath;
type
{ .: TBrainCamera :. }
TBrainCamera = class(TObject)
private
{ Private declarations }
FDir: TAffineVector;
FFOV: Single;
FFar: Single;
FRot: TAffineVector;
FNear: Single;
FInvert: Boolean;
FScreenHeight: Integer;
FSmooth: Single;
FUp: TAffineVector;
FPos: TAffineVector;
FScreenWidth: Integer;
procedure SetScreenHeight(const Value: Integer);
procedure SetScreenWidth(const Value: Integer);
protected
{ Protected declarations }
ProjectionLocation, ModelViewLocation: Integer;
ProjectionMatrix, ModelViewMatrix: TMatrix;
ScreenCenterX, ScreenCenterY: Integer;
public
{ Public declarations }
constructor Create(const AScreenWidth, AScreenHeight: Integer;
const ProjMatUniform, ModelViewUniform: Integer);
procedure ApplyPerspective();
procedure ApplyTransform(); virtual;
procedure Move(const ASpeed: Single); virtual; abstract;
procedure Strafe(const ASpeed: Single); virtual; abstract;
procedure MouseLook(); virtual; abstract;
property ScreenWidth: Integer read FScreenWidth write SetScreenWidth;
property ScreenHeight: Integer read FScreenHeight write SetScreenHeight;
property Position: TAffineVector read FPos write FPos;
property Direction: TAffineVector read FDir write FDir;
property Rotation: TAffineVector read FRot write FRot;
property Up: TAffineVector read FUp write FUp;
property FieldOfView: Single read FFOV write FFOV;
property NearPlane: Single read FNear write FNear;
property FarPlane: Single read FFar write FFar;
property MouseSmooth: Single read FSmooth write FSmooth;
property InvertMouse: Boolean read FInvert write FInvert;
end;
{ .: TBrainFreeCamera :. }
TBrainFreeCamera = class sealed(TBrainCamera)
private
{ Private declarations }
FMaxAngle: Single;
FMinAngle: Single;
protected
{ Protected declarations }
function MakeRotationMatrix(const V: TAffineVector): TMatrix;
public
{ Public declarations }
constructor Create(const AScreenWidth, AScreenHeight: Integer;
const ProjMatUniform, ModelViewUniform: Integer);
procedure ApplyTransform(); override;
procedure Move(const ASpeed: Single); override;
procedure Strafe(const ASpeed: Single); override;
procedure MouseLook(); override;
property MaxAngle: Single read FMaxAngle write FMaxAngle;
property MinAngle: Single read FMinAngle write FMinAngle;
end;
implementation
{ TBrainCamera }
procedure TBrainCamera.ApplyPerspective;
begin
if (FScreenHeight <= 0) then
FScreenHeight := 1;
glViewport(0, 0, FScreenWidth, FScreenHeight);
ProjectionMatrix := CalcPerspectiveMatrix(FFOV, FScreenWidth / FScreenHeight,
FNear, FFar);
glUniformMatrix4fv(ProjectionLocation, 1, False, @ProjectionMatrix);
end;
procedure TBrainCamera.ApplyTransform;
begin
// --
end;
constructor TBrainCamera.Create(const AScreenWidth, AScreenHeight,
ProjMatUniform, ModelViewUniform: Integer);
begin
inherited Create();
if (AScreenWidth <= 0) then
FScreenWidth := 1
else
FScreenWidth := AScreenWidth;
if (AScreenHeight <= 0) then
FScreenHeight := 1
else
FScreenHeight := AScreenHeight;
ScreenCenterX := FScreenWidth div 2;
ScreenCenterY := FScreenHeight div 2;
ProjectionLocation := ProjMatUniform;
ModelViewLocation := ModelViewUniform;
ApplyTransform();
FPos := NullVector;
FUp := YVector;
FDir := MinusZVector;
FRot := NullVector;
FInvert := False;
FSmooth := 0.25;
FFOV := 40.0;
FNear := 0.1;
FFar := 1000.0;
end;
procedure TBrainCamera.SetScreenHeight(const Value: Integer);
begin
if (Value <= 0) then
FScreenHeight := 1
else
FScreenHeight := Value;
ScreenCenterY := FScreenHeight div 2;
end;
procedure TBrainCamera.SetScreenWidth(const Value: Integer);
begin
FScreenWidth := Value;
ScreenCenterX := FScreenWidth div 2;
end;
{ TBrainFreeCamera }
procedure TBrainFreeCamera.ApplyTransform;
begin
ModelViewMatrix := LookAt(FPos, AffineVectorMake(FPos.V[0] + FDir.V[0],
FPos.V[1] + FDir.V[1], FPos.V[2] + FDir.V[2]), FUp);
glUniformMatrix4fv(ModelViewLocation, 1, False, @ModelViewMatrix);
end;
constructor TBrainFreeCamera.Create(const AScreenWidth, AScreenHeight,
ProjMatUniform, ModelViewUniform: Integer);
begin
inherited Create(AScreenWidth, AScreenHeight, ProjMatUniform, ModelViewUniform);
FMaxAngle := 89.0;
FMinAngle := -89.0;
end;
function TBrainFreeCamera.MakeRotationMatrix(const V: TAffineVector): TMatrix;
var
M, mX, mY, mZ: TMatrix;
begin
mX := CreateRotationMatrixX(DegToRad(V.V[0]));
mY := CreateRotationMatrixY(DegToRad(V.V[1]));
mZ := CreateRotationMatrixZ(DegToRad(V.V[2]));
M := MatrixMultiply(mZ, mY);
Result := MatrixMultiply(mX, M);
end;
procedure TBrainFreeCamera.MouseLook;
var
Pos, Delta: TPoint;
M: TMatrix;
begin
GetCursorPos(Pos);
SetCursorPos(ScreenCenterX, ScreenCenterY);
Delta.X := ScreenCenterX - Pos.X;
Delta.Y := ScreenCenterY - Pos.Y;
FRot.V[1] := FRot.V[1] + Delta.X * FSmooth;
if FInvert then
FRot.V[0] := FRot.V[0] - Delta.Y * FSmooth
else
FRot.V[0] := FRot.V[0] + Delta.Y * FSmooth;
if (FRot.V[0] < FMinAngle) then
FRot.V[0] := FMinAngle;
if (FRot.V[0] > FMaxAngle) then
FRot.V[0] := FMaxAngle;
M := MakeRotationMatrix(FRot);
FDir := VectorTransform(MinusZVector, M);
end;
procedure TBrainFreeCamera.Move(const ASpeed: Single);
var
M: TMatrix;
begin
M := MakeRotationMatrix(FRot);
FDir := VectorTransform(MinusZVector, M);
FPos.V[0] := FPos.V[0] + (FDir.V[0] * -ASpeed);
FPos.V[1] := FPos.V[1] + (FDir.V[1] * -ASpeed);
FPos.V[2] := FPos.V[2] + (FDir.V[2] * -ASpeed);
end;
procedure TBrainFreeCamera.Strafe(const ASpeed: Single);
var
M: TMatrix;
begin
M := MakeRotationMatrix(FRot);
FDir := VectorTransform(MinusZVector, M);
FPos.V[0] := FPos.V[0] + (FDir.V[2] * -ASpeed);
FPos.V[2] := FPos.V[2] + (-FDir.V[0] * -ASpeed);
end;
end.
I don't know why, but the code produces weird pespective dissonance when I move my mouse:
Bookmarks