Friday, 26 August 2011

Fluent Interfaces example using Delphi part I

I was introduced to Fluent interfaces when I was developing with Java using Dependency Injection and somebody told me that it could be really interesting if I post an example using Delphi and chaining method, and here I am!. I have developed a simple example that uses chaining methods to populate a THouse object with TDoors and TWindows objects with the hope it will make it easy to understand the concept. There are several examples on the net, but I couldn't find any interesting enough. So this simple example will try to introduce you to "how to develop fluent interfaces using method chaining" with the aim of writing more readable code. The overview of the architecture is the following one, using UML notation:


The Fluent Interface unit example is as follows (uFI.pas) using generics and interfaces:

// ***********************************************
// @author  jordi corbilla
// @comment Fluent interface composition example
//
// ***********************************************

unit uFI;

interface

uses
    Graphics, Contnrs, Generics.Collections, Classes;

type
    TWindow = class;

    IWindow = interface
        function SetColor(color: TColor): TWindow;
        function ToString(): string;
    end;

    TWindow = class(TInterfacedObject, IWindow)
    private
        FColor: TColor;
    public
        function SetColor(color: TColor): TWindow;
        function ToString(): string; override;
        class function New: TWindow;
    end;

    TDoor = class;

    IDoor = interface
        function SetColor(color: TColor): TDoor;
        function ToString(): string;
    end;

    TDoor = class(TInterfacedObject, IDoor)
    private
        FColor: TColor;
    public
        function SetColor(color: TColor): TDoor;
        function ToString(): string; override;
        class function New: TDoor;

    end;

    IHouse = interface
        function AddWindow(window: TWindow): IHouse;
        function AddDoor(door: TDoor): IHouse;
        function ToString(): String;
    end;

    THouseItemsList<T> = class(TObjectList)
        function ToString(): string; override;
    end;

    TDoorList = class(THouseItemsList<IDoor>)
        function ToString(): string; override;
    public

    end;

    TWindowList = class(THouseItemsList<IWindow>)
        function ToString(): string; override;
    end;

    THouse = class(TInterfacedObject, IHouse)
    private
        FDoorList: TDoorList;
        FWindowList: TWindowList;
    protected
        function AddWindow(window: TWindow): IHouse;
        function AddDoor(door: TDoor): IHouse;
    public
        property WindowList: TWindowList read FWindowList;
        property DoorList: TDoorList read FDoorList;
        class function New: IHouse;
        function ToString(): String; override;
        constructor Create();
        destructor Destroy(); override;
    end;

implementation

uses
    SysUtils;

{ THouse }

function THouse.AddDoor(door: TDoor): IHouse;
begin
    Self.FDoorList.Add(door);
    result := Self;
end;

function THouse.AddWindow(window: TWindow): IHouse;
begin
    Self.FWindowList.Add(window);
    result := Self;
end;

constructor THouse.Create;
begin
    FDoorList := TDoorList.Create;
    FWindowList := TWindowList.Create;
end;

destructor THouse.Destroy;
begin
    FreeAndNil(FDoorList);
    FreeAndNil(FWindowList);
    inherited;
end;

class function THouse.New: IHouse;
begin
    result := Create;
end;

function THouse.ToString: String;
var
    description: TStringList;
begin
    description := TStringList.Create;
    try
        description.Add(Self.FDoorList.ToString);
        description.Add(Self.FWindowList.ToString);
    finally
        result := description.Text;
        description.Free;
    end;
end;

{ TWindow }

class function TWindow.New: TWindow;
begin
    result := Create;
end;

function TWindow.SetColor(color: TColor): TWindow;
begin
    Self.FColor := color;
    result := Self;
end;

function TWindow.ToString: string;
begin
    result := 'Window color ' + ColorToString(FColor) + sLineBreak;
end;

{ TDoor }

class function TDoor.New: TDoor;
begin
    result := Create;
end;

function TDoor.SetColor(color: TColor): TDoor;
begin
    Self.FColor := color;
    result := Self;
end;

function TDoor.ToString: string;
begin
    result := 'Door color ' + ColorToString(FColor) + sLineBreak;
end;

{ THouseItemsList }

function THouseItemsList<T>.ToString: string;
var
    i: Integer;
    description: String;
begin
    for i := 0 to Self.count - 1 do
        description := description + ' ' + Self[i].ToString;
    result := description;
end;

{ TDoorList }

function TDoorList.ToString: string;
var
    description: TStringList;
begin
    description := TStringList.Create;
    try
        description.Add('Number of doors: ' + inttostr(Self.count));
        description.Add('Descriptions: ');
        description.Add( inherited ToString);
    finally
        result := description.Text;
        FreeAndNil(description);
    end;
end;

{ TWindowList }

function TWindowList.ToString: string;
var
    description: TStringList;
begin
    description := TStringList.Create;
    try
        description.Add('Number of Windows: ' + inttostr(Self.count));
        description.Add('Descriptions: ');
        description.Add( inherited ToString);
    finally
        result := description.Text;
        FreeAndNil(description);
    end;
end;

end.

Now it comes when we can use the object using FI notation in a more readable way:

var
    House: IHouse;
begin
    House := THouse.New.AddWindow(TWindow.New.SetColor(clFuchsia)).AddDoor(TDoor.New.SetColor(clWhite))
        .AddWindow(TWindow.New.SetColor(clRed)).AddDoor(TDoor.New.SetColor(clGreen));
    Memo1.Lines.Add(House.ToString);
    House := nil;

    House := THouse.New;
    House.AddWindow(TWindow.New.SetColor(clRed)).AddWindow(TWindow.New.SetColor(clBlue)).AddWindow(TWindow.New.SetColor(clGreen));
    House.AddDoor(TDoor.New.SetColor(clRed)).AddDoor(TDoor.New.SetColor(clBlue)).AddDoor(TDoor.New.SetColor(clGreen));
    Memo1.Lines.Add(House.ToString);
    House := nil;

Notice that now, we can chain our objects, composing the structure of the House by using the AddWindow and AddDoor method. To display the result I'm using the ToString method that will do the job for my purpose.

And the result of the previous execution:


Number of doors: 2
Descriptions: 
 Door color clWhite
 Door color clGreen


Number of Windows: 2
Descriptions: 
 Window color clFuchsia
 Window color clRed


Number of doors: 3
Descriptions: 
 Door color clRed
 Door color clBlue
 Door color clGreen


Number of Windows: 3
Descriptions: 
 Window color clRed
 Window color clBlue
 Window color clGreen


Just play with it and you'll experience the powerfulness of this method. I hope you like it.

I'm looking forward to your comments.
Jordi

Monday, 22 August 2011

Building my own Delphi Physics Engine part IX

I'm quite familiar with GDI, the graphics provided under Microsoft and which is widely used in Windows applications. TDPE is now ready to use Direct2D as now it's fully supported by Delphi 2010 and XE. According to MSDN, Direct2D is: a hardware-accelerated, immediate-mode, 2-D graphics API that provides high performance and high quality rendering for 2-D geometry, bitmaps, and text. The Direct2D API is designed to interoperate well with GDI, GDI+, and Direct3D.
As I'm testing this under Windows Vista, I've had to upgrade my windows version to Service Pack 2 and then I've installed the following update (KB971512 - The Windows Graphics, Imaging, and XPS Library contain the latest advancements in modern graphics technologies for gaming, multimedia, imaging and printing applications.). Direct2D is already installed in Windows 7.

We can use the same methods from TCanvas for our TDirect2DCanvas as they derive from the same ancestor TCustomCanvas. But you need to check the documentation for differences in the way they work.

A simple way to use Direct2D is as follows:

uses
    Direct2D, D2D1;

procedure Paint();
begin
    if TDirect2DCanvas.Supported then
    begin
        d2dCanvas := TDirect2DCanvas.Create(Canvas, ClientRect);
        try
            d2dCanvas.RenderTarget.beginDraw;
            d2dCanvas.RenderTarget.Clear(D2D1ColorF(clBlack));
            d2dCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
            // drawing goes here
            Paint(d2dCanvas);
            d2dCanvas.RenderTarget.EndDraw;
        finally
            FreeAndNil(d2dCanvas);
        end;
    end;
end;

Here is the result of the Physics Engine using a Direct2D Render and a GDI Render:





You will see the difference when switching from GDI to Direct2D as the performance is quite different. When it comes to Direct2D, my computer is getting quite slower as my graphic card is not powerful at all and we can see that it takes a while to render the image.


GDI uses Pixel graphics but Direct2D can supports vector graphics as well, in which mathematical formulas are used to draw the lines and curves. Vector graphics provides high quality rendering independent of resolution of the device, while the pixelated graphics has dependency with resolution which may results in choppy graphics.

Most of the GDI APIs are not using anti-aliasing and transparency. Ofcrouse there are functions to do so but always there’s programming cost for taking advantage of these features. Also if we apply transparency and anti-aliasing, the computations are done using CPU. Direct2D can take advantage of graphics hardware and delegate the computationally intensive tasks to GPU


Get the latest version here: ThundaxBallDemo v1.584.
Interaction:
'd' will drop a box with a random colour and a constant angular velocity.
'f' will drop a circle with a random colour and a constant angular velocity.
'mouse interaction' mouse is able to grab items.
'q' Enable/Disable GDI or Direct2D rendering.

Note: You need to have installed Direct2D to run the app using Direct2D, otherwise GDI will be used.

Related links:

Wednesday, 10 August 2011

Building my own Delphi Physics Engine part VIII

TDPE is almost ready and it will not take long to release the first stable library!. I am eager to continue working on the project trying to sort out different physic scenarios  to make my dynamic engine even more realistic. Do not hesitate to give it a try as you will find the experience quite interesting. I am still working on the n-edge object and the cutting tool and trying to refactor all the code to cope with a layer architecture. Using this concept, I want to structure my system in a way that every component works using a certain level of abstraction. As you see in the next figure, every object is allocated in the screen while there is another layer which is responsible for the collision detection and another one for the forces interaction. You will notice in the video that there are still little issues to tackle regarding the object interaction as sometimes we can experience overlapping.


In the figure above, you can see that now the items are not rigid and they interact with each other as they were real items. Notice that the square item will go through the round shape of the circle.



Enjoy the video!.

Get the latest executable here: ThundaxBallDemo v1.504.
Interaction:
'd' will drop a box with a random color and a constant angular velocity
'f' will drop a circle with a random color and a constant angular velocity
'mouse interaction' mouse is able to grab items

Related links: