This is the final installment of our graphics programming overview. If you havent read the previous articles they can be found here:
In this final installment on graphics programming, we will be looking at Sprite3d. This is a very popular graphics library for HTML5 and javascript development which uses the latest hardware acelerated CSS technologies. In fact we found it so useful that we decided not to wrap it – but rather create a full implementation in object pascal from scratch.
Sprite3d
I never thought I would see the day when moving a html div section around the screen would outperform classical methods like drawing sprites to a canvas. But with Sprite3d and GPU powered CSS, that day has actually arrived. In short, what sprite3d does is to manipulate the CSS positioning and 3d capabilities that modern browsers have – which means you can move, spin, rotate, tween and make your sprite3d elements fly around the screen with very little effort.
If this sounds very “game” oriented then I beg to differ. Sprite3d can, if used prudently, help spice up an otherwise boring business application. Dialogs and panels can be made to appear and move with more vigour, forms can change with more dramatic effect, your company logo can do a spin as it enters – and your loading forms and “please wait” messageboxes can have exciting animations attached to them. The uses are endless.
Setting up sprite3d
So how do you start using this amazing library? It’s actually extremely simple. Create a new visual project (or pick one you want to mess around with), add w3sprite3d.pas to your mainform’s uses list and open the unit to have a look. It’s a nice habit to examine the code before you start using it – and you will discover that sprite3d is really a very, very small library.
The unit contains a single class called TW3Sprite which inherits from TW3MovableControl. It’s actualy a very lightweight control. If you examine the unit w3components you will find that TW3CustomControl inherits from the same base. The reason we isolated the sprite3d engine like this – is because it provides a lightweight alternative to TW3Customcontrol which brings in a more heavy infrastructure.
To create your own sprite3d object, we begin by inheriting from TW3Sprite:
TMyLogo = class(TW3Sprite) end;
Now, depending on how you want to update the movement of your sprite3d object – there are two ways you can go: you can either update the x, y, z and other properties of the object and then call Update3d (which must be called for each change). Or, alternatively – you can override the updatebehavior method and implement the behavior there – and then call Update3d.
In this first example we are going to create a spinning logo, we I’ll opt for the latter technique:
TMyLogo = Class(TW3Sprite) public procedure UpdateBehavior(const TimeId: Integer);override; End;
And our very humble behavior:
procedure TMyLogo.UpdateBehavior(const TimeId: Integer); Begin RotateY(2.2); end;
Now to make our logo container come to life. Start by adding your logo (i just downloaded the google chrome logo) to the project. Right click on resources in the project overview and select “add resource file(s)”, then select a web friendly logo picture.
Next, we need to add a timer to our form where we call the update methods and also initialize our sprite object and load in the picture. Remember to add w3time to the uses list to get access to the TW3Timer component. So we modify the form code to:
TForm1=class(TW3form) private { Private methods } {$I 'Form1:intf'} FLogo: TMyLogo; FTimer: TW3Timer; protected { Protected methods } procedure InitializeObject; override; procedure FinalizeObject; override; procedure StyleTagObject; reintroduce; virtual; procedure Resize; override; end;
And the implementation to:
procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} FLogo:=TMyLogo.Create(self); FLogo.background.fromURL('res/chrome.png'); FLogo.width:=128; FLogo.height:=128; FLogo.setTransformFlags(CNT_USE_POS or CNT_USE_ROTX or CNT_USE_ROTY or CNT_USE_ROTZ); FTimer:=TW3Timer.Create; FTimer.delay:=10; FTimer.onTime:=Procedure (sender:TObject) Begin FLogo.updatebehavior(0); FLogo.update3d; end; FTimer.enabled:=true; end;
The first line that might seem a bit alien is the setTransformFlags call. In short all it does is to tell Sprite3d the features you are going to use. In this case i have enabled positioning, rotation around x,y and z axis – which means that sprite3d will apply those values. If we excluded CNT_USE_ROTY from the mix, nothing would happen because sprite3d would not apply your changes to the HTML element.
The timer is an object we all know from Delphi, so it should be fairly self explanatory. We call the updatebehavior to adjust the values, then we apply the changes to the object by calling update3d – thats pretty much it. The parameter for updatebehavior is up to you to populate. A typical use would be to issue a time-code or some flag value that makes sense to your behavioral code. But since we dont use anything fancy in this example, we just pass zero.
So, what does our result look like? like this: