-Incorporating 2D elements-
All the 3D scenes rendered, are quite unusable without a decent interface to present to the user. True, the interface itself could be a 3D scene, but I am talking about the norms, and not about changing convention. One of the most basic 2D elements is text. One could use wglUseFontBitmaps, but it is rather slow. One of the fastest ways to draw text onscreen is to use the 3D rasterizer to display texturemapped quads, each quad of which has a different character mapped onto it. An excellent tutorial on the subject is on NeHe's website. If you want to check it out, click here. In this tutorial, I will describe an architecture for rendering interface elements (and using them).
First off, we all need a base class that all UI objects will use. I have called this not quite surprisingly, TUIElement. The declaration is given below.
    TUIClickEvent=procedure (Sender:TUIElement) of object;
    TUIElement=class
                    private
                    //Top,Left, Width and Height of the element
                    fX,fY,fWidth,fHeight:integer;
                    //Is the mouse over it?
                    fHighlighted:boolean;
                    //Frame Update stuff
                    fFrameInterval,fLastTickCount:cardinal;
                    //Enabled/Disabled
                    fEnabled:boolean;
                    //Click Event
                    fOnClick:TUIClickEvent;
                    //The name of the object
                    fName:string;
                    public
                    constructor Create;
                    //Desscendants can override Update to perform
                    //Time keyed animation or whatever
                    function Update(TickCount:cardinal):boolean;virtual;
                    //All descendants MUST render themselves
                    procedure Render;virtual;abstract;
                    //Call this if you want to simulate
                    //a click on the button
                    procedure DoClick;virtual;
                    //DUH!!
                    property Name:string
                             read fName
                             write fName;
                    property X:integer
                             read fX
                             write fX;
                    property Y:integer
                             read fY
                             write fY;
                    property Width:integer
                             read fWidth
                             write fWidth;
                    property Height:integer
                             read fHeight
                             write fHeight;
                    property Highlighted:boolean
                             read fHighLighted
                             write fHighlighted;
                    property Enabled:boolean
                             read fEnabled
                             write fEnabled;
                    property OnClick:TUIClickEvent
                             read fOnClick
                             write fOnClick;
    end;
Two methods merit description. One is the Update method, and the other is DoClick.
procedure TUIElement.DoClick;
begin
     //If the click event handler is assigned,
     //then it is invoked 
     if assigned(fOnClick) then fOnClick(Self);
end;function TUIElement.Update(TickCount: cardinal): boolean;
begin
     //Set result to false initially
     result:=false;
     //If the object is disabled, then dont update.
     //This means successors will also not Update since
     //all of them should check inherited result before
     //proceeding with their Update
     if not fEnabled then exit;
     if (TickCount-fLastTickCount)>=fFrameInterval then
     begin
          //fFrameInterval ticks have passed since the lase Update
          //Updation can now take place
          fLastTickCount:=TickCount;
          result:=true;
     end;
end;
Now that we are done with the base class, lets see how a basic rollover is implemented as a descendant. Basically, a rollover must do two things. Determine whether the mouse is on itself, and change the image accordingly, and respond to a click in its client area. Here comes the declaration.
    TRollOverImage=class(TUIElement)
                        private
                        //The texture that is not highlighted
                        fBackTex,
                        //The highlight texture
                        fForeTex:TTexture;
                        public
                        constructor Create;
                        destructor Destroy;override;
                        procedure Render;override;
                        property BackTex:TTexture
                                 read fBackTex
                                 write fBackTex;
                        property ForeTex:TTexture
                                 read fForeTex
                                 write fForeTex;
    end;
Looks pretty simple, since almost all the properties/methods required have been taken from the base class. We shall take a look at the Render method implementation as well, since to write subsequent classes we require knowlodge of how this is rendered. All this method does is to render the background quad, and if the Hilighted property is set, then it renders another quad on top of this one, using the foreground texture Alpha channel information to blend the two together. That translates to a TTexture.Transparency call or a glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) call. Take a look at the code now.
     fBackTex.Enable;
     fBackTex.Opaque;
     DrawQuad(fX,fY,fWidth,fHeight);     if fHighlighted then
     begin
          fForeTex.Enable;
          fForeTex.Transparency;
          DrawQuad(fX,fY,fWidth,fHeight);
     end;
From here, we can go anywhere. Take a look at TRolloverButton.Render. It's almost exactly the same as TRolloverImage. Pretty darn simple to modify, wouldnt you say!
     if Enabled then
        inherited Render
     else
     begin
          fDisabledTex.Enable;
          fDisabledTex.Opaque;
          DrawQuad(X,Y,Width,Height);
     end;
I'm not going to explain TRolloverCheckBox. I leave that as an excercise to the reader. What I will do, however, is to explain another class that is crucial to the entire setup.
Alright, we now have some interface elements. If we are going update each element separately whenever the mouse moved, or was clicked, then we'd have some extremely painful code on our hands. So, what we do is write another class called TUIManager. This class will be responsible for managing the objects once added. So, the mouse events have only to be given to the manger, and this will make sure it gets filtered to the element on which the event occurred. Another declaration?
    TUIManager=class
                    private
                    //The elements are maintained as a TList                    fElements:TList;
                    public
                    constructor Create;
                    destructor Destroy;override;
                    //Mouse move should be called when the mouse moves
                    procedure MouseMove(X,Y:integer);
//When the mouse button is clicked, you must call this procedure MouseClick(X,Y:integer;Button:TMouseButton);
//No points for guessing this one procedure Render; property Elements:TList read fElements write fElements; end;
That was pretty small, was'nt it? There! We're done. Now we can show some stuff on the screen so the user can make choices. Lucifer will have a lot more input classes, I just wanted to keep the tutorial simple. The tut sample is very spartan, so I'll sxplain it a bit. There are two interface elements, a button and a checkox (yeah, the round thingy). Checking the checkbox, disables the button and vice versa. Clicking on the button invokes a dialog. simple, huh! Its really late. I'm off to bed. Good thing todays Sunday. I ca nsleep all day! :) ZZZZZZZ
>>Download the tutorial source
You'll also need, in case you dont have it already
>>Download the Lucifer units (required)