Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: First try at OOP oriented OpenGL

  1. #1

    First try at OOP oriented OpenGL

    I got sick of rewritting everything for lighting so I wrote a unit to save me time. For usage rights check the embedded readme/license/terms etc. It's a simple controller for the OpenGL lights and is quite versital. I'd like your critique.

    This was written in Delphi 6 with the current DOT Toolkit.

    [pascal]{
    This unit was written by Robert Kosek. (C) December 2004, All rights reserved.
    Use at your own risk/inconvenience. The author is not responsible for any
    problems, instability, stress or weight gain caused by the use of this unit.

    This unit, OOLights.pas, is freely usable in commercial/shareware applications
    so long as the filename is unchanged and the Author (Robert Kosek) is credited.

    Any modifications should be submitted to me via PM at the http://www.dgdev.tk
    forums.

    ** TAKEN FROM THE REDBOOK CHAPTER 6 **
    http://fly.cc.fer.hr/~unreal/theredbook/chapter06.html

    Parameter Name Default Value Meaning
    GL_AMBIENT (0.0, 0.0, 0.0, 1.0) ambient RGBA intensity of light
    GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) diffuse RGBA intensity of light
    GL_SPECULAR (1.0, 1.0, 1.0, 1.0) specular RGBA intensity of light
    GL_POSITION (0.0, 0.0, 1.0, 0.0) (x, y, z, w) position of light
    GL_SPOT_DIRECTION (0.0, 0.0, -1.0) (x, y, z) direction of spotlight
    GL_SPOT_EXPONENT 0.0 spotlight exponent
    GL_SPOT_CUTOFF 180.0 spotlight cutoff angle
    GL_CONSTANT_ATTENUATION 1.0 constant attenuation factor
    GL_LINEAR_ATTENUATION 0.0 linear attenuation factor
    GL_QUADRATIC_ATTENUATION 0.0 quadratic attenuation factor
    }

    unit OOLights;

    interface

    uses
    Windows, SysUtils, Classes, GL, GLu, DotMath;

    type
    TLightItem = class(TCollectionItem)
    private
    FLightNumber: GLUint;
    FAmbient,FDiffuse,FSpecular,FPosition: TDotVector4;
    FSpotDirection: TDotVector3;
    FSpotExponent: GLFloat;
    FSpotCutOff: GLFloat;
    FConstantAttenuation: GLfloat;
    FLinearAttenuation: GLfloat;
    FQuadraticAttenuation: GLfloat;
    public
    property LightNumber: GLUint read FLightNumber write FLightNumber;
    property Ambient: TDotVector4 read FAmbient write FAmbient;
    property Diffuse: TDotVector4 read FDiffuse write FDiffuse;
    property Specular: TDotVector4 read FSpecular write FSpecular;
    property Position: TDotVector4 read FPosition write FPosition;
    property SpotDirection: TDotVector3 read FSpotDirection write FSpotDirection;
    property SpotExponent: GLfloat read FSpotExponent write FSpotExponent;
    property SpotCutOff: GLfloat read FSpotCutOff write FSpotCutOff;
    property ConstantAttenuation: GLfloat read FConstantAttenuation write FConstantAttenuation;
    property LinearAttenuation: GLfloat read FLinearAttenuation write FLinearAttenuation;
    property QuadraticAttenuation: GLfloat read FQuadraticAttenuation write FQuadraticAttenuation;
    constructor Create(Collection: TCollection); override;
    procedure UpdateGL(visible: boolean);
    end;

    TLightSystem = class(TCollection)
    private
    function GetItem(Index: integer): TLightItem;
    procedure SetItem(Index: integer; const Value: TLightItem);
    public
    property Items[Index: Integer]: TLightItem read GetItem write
    SetItem; default;
    constructor Create(ItemClass: TCollectionItemClass);
    function AddNewLight: TLightItem;
    end;

    implementation

    { TLightSystem }

    function TLightSystem.AddNewLight: TLightItem;
    begin
    if Count < 8 then
    result := TLightItem.Create(Self)
    else
    result := nil;
    end;

    constructor TLightSystem.Create(ItemClass: TCollectionItemClass);
    begin
    inherited;
    glEnable(GL_LIGHTING);
    end;

    function TLightSystem.GetItem(Index: Integer): TLightItem;
    begin
    Result := TLightItem(inherited GetItem(Index));
    end;

    procedure TLightSystem.SetItem(Index: Integer;
    const Value: TLightItem);
    begin
    inherited SetItem(Index, Value);
    end;

    { TLightItem }

    { tracks the lighting var and sets the default parameters }
    constructor TLightItem.Create(Collection: TCollection);
    const gll: array[0..7] of GLUInt = (
    GL_LIGHT0,GL_LIGHT1,GL_LIGHT2,GL_LIGHT3,GL_LIGHT4,
    GL_LIGHT5,GL_LIGHT6,GL_LIGHT7
    );
    begin
    inherited Create(Collection);

    if Collection.Count-1 > 7 then raise EInvalidOperation.CreateFmt('Cannot have more than 8 light definitions. Count: %d',[Collection.Count]);
    FLightNumber := gll[Collection.Count-1];
    glEnable(FLightNumber);

    FAmbient := dotVector4(0.0,0.0,0.0,1.0);
    FDiffuse := dotVector4(1.0,1.0,1.0,1.0);
    FSpecular := dotVector4(1.0,1.0,1.0,1.0);
    FPosition := dotVector4(0.0,0.0,0.0,0.0);

    FSpotDirection := dotVector3(0.0,0.0,-1.0);

    FSpotExponent := 0.0;
    FSpotCutOff := 180.0;

    FConstantAttenuation := 1.0;
    FLinearAttenuation := 0.0;
    FQuadraticAttenuation := 1.0;
    end;

    { Updates the light's vars and show/hides should it be needed }
    procedure TLightItem.UpdateGL(visible: boolean);
    begin
    if visible then begin
    glEnable(FLightNumber);

    glLightfv(FLightNumber, GL_AMBIENT, @FAmbient.xyzw);
    glLightfv(FLightNumber, GL_DIFFUSE, @FDiffuse.xyzw);
    glLightfv(FLightNumber, GL_SPECULAR, @FSpecular.xyzw);
    glLightfv(FLightNumber, GL_POSITION, @FPosition.xyzw);
    glLightfv(FLightNumber, GL_SPOT_DIRECTION, @FSpotDirection.xyz);
    glLightf( FLightNumber, GL_SPOT_EXPONENT, FSpotExponent);
    glLightf( FLightNumber, GL_SPOT_CUTOFF, FSpotCutOff);
    glLightf( FLightNumber, GL_CONSTANT_ATTENUATION, FConstantAttenuation);
    glLightf( FLightNumber, GL_LINEAR_ATTENUATION, FLinearAttenuation);
    glLightf( FLightNumber, GL_QUADRATIC_ATTENUATION, FQuadraticAttenuation);

    end else glDisable(FLightNumber);
    end;

    end.[/pascal]

  2. #2

    First try at OOP oriented OpenGL

    Here's a texture manager I did. So far it's entirely flawless. Based off the textures.pas from Sulaco. Would someone please critique these?? I'd like to know how well I'm doing on the Object Orientation side of things.

    [pascal]{
    This unit was written by Robert Kosek. (C) December 2004, All rights reserved.
    Use at your own risk/inconvenience. The author is not responsible for any
    problems, instability, stress or weight gain caused by the use of this unit.

    This unit, OOTextures.pas, is freely usable in commercial/shareware applications
    so long as the filename is unchanged and the Author (Robert Kosek) is credited.

    Any modifications should be submitted to me via PM at the http://www.dgdev.tk
    forums.
    }

    unit OOTextures;

    interface

    uses
    Windows, SysUtils, Classes, GL, {GLu, }Textures;

    type
    TTextureItem = class(TCollectionItem)
    private
    FTexture: GLuint;
    FTexId: string;
    public
    property Texture: GLuint read FTexture write FTexture;
    property TexId: string read FTexId write FTexId;
    constructor Create(Collection: TCollection; Filename: string); overload;
    end;

    TTextureSystem = class(TCollection)
    private
    function GetItem(Index: integer): TTextureItem;
    procedure SetItem(Index: integer; const Value: TTextureItem);
    function FindItem(TexID: string): TTextureItem;
    public
    property Items[Index: Integer]: TTextureItem read GetItem write
    SetItem; default;
    function AddTexture(filename: string): integer;
    end;

    implementation

    { TTextureSystem }

    function TTextureSystem.AddTexture(filename: string): integer;
    var item: TTextureItem;
    begin
    item := TTextureItem.Create(Self,filename);
    item := nil;
    result := Count-1;
    end;

    function TTextureSystem.FindItem(TexID: string): TTextureItem;
    var i: integer;
    begin
    for i := 0 to count-1 do
    if Items[i].TexId = TexID then begin
    result := Items[i];
    break;
    end;
    end;

    function TTextureSystem.GetItem(Index: Integer): TTextureItem;
    begin
    Result := TTextureItem(inherited GetItem(Index));
    end;

    procedure TTextureSystem.SetItem(Index: Integer;
    const Value: TTextureItem);
    begin
    inherited SetItem(Index, Value);
    end;

    { TTextureItem }

    constructor TTextureItem.Create(Collection: TCollection; Filename: string);
    begin
    inherited Create(Collection);
    LoadTexture(filename,ftexture,false);
    FTexID := filename;
    end;

    end.[/pascal]

  3. #3

    First try at OOP oriented OpenGL

    I guess problems would surface only when these are actually used, but from what I can see it looks pretty good.
    I'm not entirely sure if its really needed, but I suppose when you have a constructor in there a destructor would be necessary as welll.

    Also I noticed the default keyword, but without a value assigned to it. Why is that? And why use it at all? In the book Mastering Delph 5, the author says default values for published properties help reduce the dfm filesize and ultimately the exe filesize.

  4. #4

    First try at OOP oriented OpenGL

    I guess problems would surface only when these are actually used, but from what I can see it looks pretty good.
    I'm using the texture one without a hitch, but I haven't tested the lighting one. I just got sick of the constant rewriting of code. Just so you know, this isn't a component you drop on the form ... it's all runtime.

    OpenGL in it's texture system automatically free's the textures ... though the vectors may need to be freed. I'll look into that.

  5. #5

    First try at OOP oriented OpenGL

    Quote Originally Posted by Traveler
    Also I noticed the default keyword, but without a value assigned to it. Why is that? And why use it at all? In the book Mastering Delph 5, the author says default values for published properties help reduce the dfm filesize and ultimately the exe filesize.
    When default is used in this context with an array property, it allows you to access that property without explicitly naming it, but just using square brackets after the class name, i.e. instead of:
    [pascal]LightSystem.Items[i][/pascal]
    you can use:
    [pascal]LightSystem[i][/pascal]
    Obviously, only one default property may be used per class.
    [size=10px][ Join us in #pgd on irc.freenode.net ] [ Sign the Petition for a Software Patent Free Europe ][/size]

  6. #6

    First try at OOP oriented OpenGL

    True. I've been using:

    [pascal]glBindTexture(GL_TEXTURE_2D,Textures[0].Texture);[/pascal]Without a hitch. It works smoothly and quickly. I'm getting an average of 2000fps with a simple scene (I bought a Radeon 9800 XT recently).

  7. #7

    First try at OOP oriented OpenGL

    Thanks for clearing that up!

  8. #8

    First try at OOP oriented OpenGL

    Both look very good. My only suggestion is related to cross-platform portability, and possibly speed.

    TCollection and TCollectionItem are ideal if you plan to stream the object as it inherits from TPerstent. I would be inclined to write a more specific streaming code and would suggest doing something like...

    [pascal]
    TLightItem = class( TObject )
    public
    // All your other properties here
    procedure Initialise;
    end;

    TLightSystem = class( TObjectList )
    private
    function GetItems( aIndex : Integer ) : TLightItem;
    procedure SetItems( aIndex : Integer; const aLightItem : TLightItem );
    public
    function Add( aLightItem : TLightItem ) : Integer;
    function Extract( aLightItem : TLightItem ) : TLightItem;
    function Remove( aLightItem : TLightItem ) : Integer;
    function IndexOf( aLightItem : TLightItem ) : Integer;
    function First : TLightItem;
    function Last : TLightItem;
    procedure Insert( aIndex : Integer; aLightItem : TLightItem );
    property Items[ Index : Integer ] : TLightItem read GetItems write SetItems; default;
    end;
    ...
    implementation

    { TLightSystem }

    function TLightSystem.Add(aLightItem : TLightItem): Integer;
    begin
    result := inherited Add( aLightItem);
    end;

    function TLightSystem.Extract(aLightItem : TLightItem): TLightItem;
    begin
    result := TLightItem( inherited Extract( aLightItem) );
    end;

    function TLightSystem.First: TLightItem;
    begin
    result := TLightItem( inherited First );
    end;

    function TLightSystem.GetItems(aIndex: Integer): TLightItem;
    begin
    result := TLightItem( inherited Items[ aIndex ] );
    end;


    function TLightSystem.IndexOf(aLightItem : TLightItem): Integer;
    begin
    result := inherited IndexOf( aLightItem);
    end;

    procedure TLightSystem.Insert(aIndex: Integer; aLightItem : TLightItem);
    begin
    inherited Insert( aIndex, aLightItem);
    end;

    function TLightSystem.Last: TLightItem;
    begin
    result := TLightItem( inherited Last );
    end;

    function TLightSystem.Remove(aLightItem : TLightItem): Integer;
    begin
    result := inherited Remove( aLightItem);
    end;

    procedure TLightSystem.SetItems(aIndex: Integer; const aLightItem : TLightItem);
    begin
    inherited Items[ aIndex ] := aLightItem;
    end;

    [/pascal]

    This should give you a lighter and thus faster ( though I would suggest benchmarking things like Add and Remove to be sure ) class hierachy and should also be portable to FreePascal should you want to port your code later on. The you could add specific Load and Save Methods to the TLightSytem class to handle your streaming.

    Anyway it is just a thought.
    <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 =-

  9. #9

    First try at OOP oriented OpenGL

    Good I missed that. I'll check it out, and maybe even get a few extra milliseconds back.

  10. #10

    First try at OOP oriented OpenGL

    Quote Originally Posted by Robert Kosek
    [pascal]
    function TTextureSystem.FindItem(TexID: string): TTextureItem;
    var i: integer;
    begin
    for i := 0 to count-1 do
    if Items[i].TexId = TexID then begin
    result := Items[i];
    break;
    end;
    end;
    [/pascal]
    Doesn't this give you a warning? result may be undefined if you pass a string that you don't have.
    Also, i suggest too to pass to TList (or TObjectList), and what about removing that Windows unit uses that it's probably unuseful ?

    Bye!
    If you save your data in a proprietary format, the owner of the format owns your data.
    <br /><A href="http://msx80.blogspot.com">http://msx80.blogspot.com</A>

Page 1 of 2 12 LastLast

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
  •