Page 3 of 3 FirstFirst 123
Results 21 to 25 of 25

Thread: A Simple OpenGL Framework - Your input required...

  1. #21

    A Simple OpenGL Framework - Your input required...

    Appologies for the delay, RL has been busy... After looking at a few camera class implementations, I decided to split it into 2 classes. I genric Camera class, and one more specific GameCamera class. As mentioned all feedback, constructive critisism welcome.

    So this is what it looks like so far...

    [pascal]
    unit camera;

    interface

    uses
    vector;

    type
    TCamera = class
    private

    protected

    public
    CameraPosition : TVector; // position of camera
    CameraVelocity : TVector; // velocity of camera
    CameraAcceleration : TVector; // acceleration of camera
    CameraLookAt : TVector; // lookat vector

    // up, forward, right vectors
    CameraUp : TVector;
    CameraForward : TVector;
    CameraRight : TVector;

    // yaw and pitch angles
    CameraYaw : TScalar;
    CameraPitch : TScalar;

    ScreenWidth, ScreenHeight : integer;
    ScreenCenterX, ScreenCenterY : integer;

    constructor Create; overload; virtual;
    constructor Create( aLook : TVector ); overload; virtual;
    constructor Create( aPosition : TVector; aLook : TVector ); overload; virtual;
    destructor Destroy; override;

    procedure LookAt( aX : TScalar; aY : TScalar; aZ : TScalar ); overload;
    procedure LookAt( aLook : TVector ); overload;
    procedure MoveTo( aX : TScalar; aY : TScalar; aZ : TScalar ); overload;
    procedure MoveTo( aPosition : TVector ); overload;

    // right rotation along y-axis (yaw)
    procedure RotateYaw( aRadians : TScalar );
    procedure RotatePitch( aRadians : TScalar );
    procedure RotateRoll( aRadians : TScalar );
    procedure RotatePYR( aPitch : TScalar; aYaw : TScalar; aRoll : TScalar );
    end;

    implementation

    { TCamera }

    constructor TCamera.Create;
    begin
    inherited;
    CameraPosition := TVector.Create( 0.0, 0.0, 0.0 );
    CameraLookAt := TVector.Create( 0.0, 0.0, 1.0 );

    CameraForward := CameraLookAt;
    CameraUp := TVector.Create( 0.0, 1.0, 0.0 );
    CameraRight := TVector.Create( 1.0, 0.0, 0.0 );

    CameraVelocity := TVector.Create( 0.0, 0.0, 0.0 );
    CameraAcceleration := TVector.Create( 0.0, 0.0, 0.0 );

    CameraYaw := 0.0;
    CameraPitch := 0.0;
    end;

    constructor TCamera.Create( aPosition, aLook : TVector );
    begin
    inherited Create;
    CameraPosition := aPosition;
    CameraLookAt := aLook.UnitVector;

    CameraForward := CameraLookAt;
    CameraUp := TVector.Create( 0.0, 1.0, 0.0 );
    CameraRight := TVector.Create( 1.0, 0.0, 0.0 );

    CameraVelocity := TVector.Create( 0.0, 0.0, 0.0 );
    CameraAcceleration := TVector.Create( 0.0, 0.0, 0.0 );

    CameraYaw := 0.0;
    CameraPitch := 0.0;
    end;

    constructor TCamera.Create( aLook : TVector );
    begin
    inherited Create;
    CameraPosition := TVector.Create( 0.0, 0.0, 0.0 );
    CameraLookAt := aLook.UnitVector;

    CameraForward := CameralookAt;
    CameraUp := TVector.Create( 0.0, 1.0, 0.0 );
    CameraForward.CrossProduct( CameraUp, CameraRight );

    CameraVelocity := TVector.Create( 0.0, 0.0, 0.0 );
    CameraAcceleration := TVector.Create( 0.0, 0.0, 0.0 );

    CameraYaw := 0.0;
    CameraPitch := 0.0;
    end;

    destructor TCamera.Destroy;
    begin
    if CameraPosition <> nil then
    CameraPosition.Free;
    if CameraLookAt <> nil then
    CameraLookAt.Free;

    if CameraForward <> nil then
    CameraForward.Free;
    if CameraUp <> nil then
    CameraUp.Free;
    if CameraRight <> nil then
    CameraRight.Free;

    if CameraVelocity <> nil then
    CameraVelocity.Free;
    if CameraAcceleration <> nil then
    CameraAcceleration.Free;
    inherited;
    end;

    procedure TCamera.LookAt( aX, aY, aZ : TScalar );
    begin
    CameraLookAt.x := aX;
    CameraLookAt.y := aY;
    CameraLookAt.y := aZ;
    end;

    procedure TCamera.LookAt( aLook : TVector );
    begin
    CameraLookAt.Assign( aLook );
    end;

    procedure TCamera.MoveTo( aX, aY, aZ : TScalar );
    begin
    CameraPosition.x := aX;
    CameraPosition.y := aY;
    CameraPosition.z := aZ;
    end;

    procedure TCamera.MoveTo( aPosition : TVector );
    begin
    CameraPosition.Assign( aPosition );
    end;

    procedure TCamera.RotatePitch( aRadians : TScalar );
    var
    sine, cosine : TScalar;
    begin
    sine := sin( aRadians );
    cosine := cos( aRadians );

    CameraUp.y := cosine * CameraUp.Length;
    CameraUp.z := sine * CameraUp.Length;

    CameraForward.y := -sine * CameraForward.Length;
    CameraForward.z := cosine * CameraForward.Length;
    {* x y z p
    | 1 0 0 0 |
    M = | 0 cos(A) -sin(A) 0 |
    | 0 sin(A) cos(A) 0 |
    | 0 0 0 1 |
    *}
    end;

    procedure TCamera.RotatePYR(aPitch, aYaw, aRoll: TScalar);
    begin
    RotatePitch( aPitch );
    RotateYaw( aYaw );
    RotateRoll( aRoll );
    end;

    procedure TCamera.RotateRoll( aRadians : TScalar );
    var
    sine, cosine : TScalar;
    begin
    sine := sin( aRadians );
    cosine := cos( aRadians );

    CameraRight.x := cosine * CameraRight.Length;
    CameraRight.y := sine * CameraRight.Length;

    CameraUp.x := -sine * CameraForward.Length;
    CameraUp.y := cosine * CameraForward.Length;
    {*
    | cos(A) -sin(A) 0 0 |
    M = | sin(A) cos(A) 0 0 |
    | 0 0 1 0 |
    | 0 0 0 1 |
    *}
    end;

    procedure TCamera.RotateYaw( aRadians : TScalar );
    var
    sine, cosine : TScalar;
    begin
    sine := sin( aRadians );
    cosine := cos( aRadians );

    CameraRight.x := cosine * CameraRight.Length;
    CameraRight.z := sine * CameraRight.Length;

    CameraForward.x := -sine * CameraForward.Length;
    CameraForward.z := cosine * CameraForward.Length;

    {* x y z p
    | cos(A) 0 -sin(A) 0 |
    M = | 0 1 0 0 |
    | sin(A) 0 cos(A) 0 |
    | 0 0 0 1 |
    *}
    end;

    end.
    [/pascal]

    And a more game specific one looks like this....

    [pascal]
    unit gamecamera;

    interface

    uses
    gl,
    glu,
    vector,
    camera,
    gameobject;

    type
    TGameCamera = class( TCamera )
    private
    CalcVector : TVector; // A sort of cached dummry vector used in Update methods.
    protected
    // these are used for moving and changing camera orientation
    // through the MoveTo/LookTo methods
    initPosition, finalPosition : TVector;
    initLookAt, finalLookAt : TVector;

    LookAtVelocity : TVector; // velocity for looking at objects
    LookAtAcceleration : TVector; // acceleration for looking at objects

    procedure UpdateLookAt;
    procedure UpdateMoveTo;
    public
    constructor Create; override;
    constructor Create( aLook : TVector ); override;
    constructor Create( aPosition : TVector; aLook : TVector ); override;
    destructor Destroy; override;

    procedure LookAtGameObject( aGameobject : TGameObject );
    procedure LookAtGameObjectNow( aGameobject : TGameObject );
    procedure MoveToGameObject( aGameobject : TGameObject );
    procedure MoveToGameObjectNow( aGameobject : TGameObject );

    // do animation/collision/ai/physics calculations
    procedure Update( aDeltaTime : TScalar );
    end;

    implementation

    { TGameCamera }

    procedure TGameCamera.Update( aDeltaTime : TScalar );
    var
    cosYaw, sinYaw, sinPitch, cosPitch, speed, strafeSpeed : single;
    begin
    if ( ( CameraYaw >= 360.0 ) or ( CameraYaw <= -360.0 ) ) then
    CameraYaw := 0.0;

    // Set boundaries for pitch
    if ( CameraPitch > 60.0 ) then
    CameraPitch := 60.0;
    if ( CameraPitch < -60.0 ) then
    CameraPitch := -60.0;

    cosYaw := cos( DegreesToRadian( CameraYaw ) );
    sinYaw := sin( DegreesToRadian( CameraYaw ) );
    sinPitch := sin( DegreesToRadian( CameraPitch ) );

    cosPitch := cos( DegreesToRadian( CameraPitch ) );

    speed := CameraVelocity.z * aDeltaTime;
    strafeSpeed := CameraVelocity.x * aDeltaTime;

    if ( speed > 15.0 ) then
    speed := 15.0;
    if ( strafeSpeed > 15.0 ) then
    strafeSpeed := 15.0;
    if ( speed < -15.0 ) then
    speed := -15.0;
    if ( strafeSpeed < -15.0 ) then
    strafeSpeed := -15.0;

    if ( CameraVelocity.Length > 0.0 ) then
    begin
    CameraVelocity.Negative( CameraAcceleration );
    CameraAcceleration.Scale( 1.5 );
    end;

    CameraVelocity.Add( CameraAcceleration.Scale( aDeltaTime ), CameraVelocity );

    CameraPosition.x := CameraPosition.x + cos( DegreesToRadian( CameraYaw + 90.0 ) ) * strafeSpeed;
    CameraPosition.z := CameraPosition.z + sin( DegreesToRadian( CameraYaw + 90.0 ) ) * strafeSpeed;
    CameraPosition.x := CameraPosition.x + cosYaw * speed;
    CameraPosition.z := CameraPosition.z + sinYaw * speed;

    // added *cosPitch
    CameraLookAt.x := CameraPosition.x + ( cosYaw * cosPitch );
    CameraLookAt.y := CameraPosition.y + sinPitch;
    CameraLookAt.z := CameraPosition.z + ( sinYaw * cosPitch );

    gluLookAt( CameraPosition.x, CameraPosition.y, CameraPosition.z,
    CameraLookAt.x, CameraLookAt.y, CameraLookAt.z,
    0.0, 1.0, 0.0 );
    end;

    constructor TGameCamera.Create;
    begin
    inherited;
    CalcVector := TVector.Create( 0.0, 0.0, 0.0 );
    end;

    constructor TGameCamera.Create(aLook: TVector);
    begin
    inherited;
    CalcVector := TVector.Create( 0.0, 0.0, 0.0 );
    end;

    constructor TGameCamera.Create(aPosition, aLook: TVector);
    begin
    inherited;
    CalcVector := TVector.Create( 0.0, 0.0, 0.0 );
    end;

    destructor TGameCamera.Destroy;
    begin
    if CalcVector <> nil then
    CalcVector.Free;
    inherited;
    end;

    procedure TGameCamera.LookAtGameObject( aGameobject : TGameObject );
    begin
    initLookAt.Assign( CameraLookAt );
    finalLookAt.Assign( aGameobject.Position );

    CameraLookAt.Scale( 0.25 ).Negative( LookAtAcceleration );

    UpdateLookAt;
    end;

    procedure TGameCamera.LookAtGameObjectNow( aGameobject : TGameObject );
    begin
    CameralookAt.Assign( aGameobject.Position );
    end;

    procedure TGameCamera.MoveToGameObject( aGameobject : TGameObject );
    begin
    initPosition.Assign( CameraPosition );
    finalPosition.Assign( aGameobject.Position );

    CameraPosition.Scale( 0.25 ).Negative( CameraAcceleration );

    UpdateMoveTo;
    end;

    procedure TGameCamera.MoveToGameObjectNow( aGameobject : TGameObject );
    begin
    CameraPosition.Assign( aGameobject.Position );
    end;

    procedure TGameCamera.UpdateLookAt;
    begin
    CalcVector.Assign( finalLookAt.x - CameralookAt.x,
    finalLookAt.y - CameralookAt.y,
    finalLookAt.z - CameralookAt.z );

    LookAtVelocity.Assign( CalcVector.Scale( 0.5 ) );
    end;

    procedure TGameCamera.UpdateMoveTo;
    begin
    CalcVector.Assign( finalPosition.x - Cameraposition.x,
    finalPosition.y - Cameraposition.y,
    finalPosition.z - Cameraposition.z );

    CameraVelocity.Assign( CalcVector.Scale( 0.5 ) );
    end;

    end.
    [/pascal]

    Once these have been picked apart I'll post the proposed gamenode and gameobject classes.
    <br /><br />There are a lot of people who are dead while they are still alive. I want to be alive until the day I die.<br />-= Paulo Coelho =-

  2. #22

    A Simple OpenGL Framework - Your input required...

    That's not too bad. I'm still not a fan of TVector as a class from a memory and efficiency point of view, but you are at least using it consistently.

    When calling Free on a class instance, you do not need to check that the class instance is not nil first. Free does that already.

    System.pas
    Code:
    procedure TObject.Free;
    begin
      if Self <> nil then
        Destroy;
    end;
    Not much else to comment on really. The class design seems to be pretty good.

  3. #23

    A Simple OpenGL Framework - Your input required...

    Thanks for the quick feedback Steve. I am sure in older versions of Delphi if you called Free without checking for nil, it would AV. Hence an old habit dieing hard. I will check Delphi 4 later today to see if System.pas in there checked for nil in it's Free method.
    <br /><br />There are a lot of people who are dead while they are still alive. I want to be alive until the day I die.<br />-= Paulo Coelho =-

  4. #24

    A Simple OpenGL Framework - Your input required...

    I couldn't wait, I just checked Delphi 4's Free method and it looks like this...
    [pascal]
    procedure TObject.Free;
    asm
    TEST EAX, EAX
    JE @@exit
    MOV ECX, [EAX]
    MOV DL, 1
    CALL dword ptr [ECX], vmtDestroy
    @@exit:
    end;
    [/pascal]

    I am not familiar with assembler at all, so someone will need to tell me if the TEST EAX, EAX is the same as if Self <> nil.
    <br /><br />There are a lot of people who are dead while they are still alive. I want to be alive until the day I die.<br />-= Paulo Coelho =-

  5. #25

    A Simple OpenGL Framework - Your input required...

    yup, it does exactlly that

Page 3 of 3 FirstFirst 123

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •