PDA

View Full Version : SpriteSheet class



Eric
13-04-2012, 08:54 AM
For classic tiled sprite sheets.

Currently supports drawing a tile with rotation or scaling.

Fully hardware-accelerated on Chrome, IE9, iOS & (AFAIK) OSX Safari (but not Windows Safari)


unit SpriteSheet;

interface

uses w3ctrls, w3graphics, w3system;

type

TW3SpriteSheet = Class(TObject)
private
FImage : TW3Image;
FRows, FColumns : Integer;
FTotal : Integer;
FWidth, FHeight : Integer;
FHalfWidth, FHalfHeight : Integer;
FReady : Boolean;
FOnReady : TNotifyEvent;

procedure HandleImageReady(sender : TObject);
Procedure setWidth(aValue : Integer);
procedure setheight(aValue : Integer);
Procedure ReCalcInfo;

protected

class var vSinCosReady : Boolean;
class var vCosTable : array of Float;
class var vSinTable : array of Float;
class procedure InitSinCos;

public
Constructor Create;virtual;
destructor Destroy;Override;

procedure LoadImage(aUrl : String); overload;
procedure LoadImage(aUrl : String; aSpriteWidth, aSpriteHeight : Integer); overload;

// top left anchored
Procedure Draw(Canvas : TW3Canvas; dx,dy : Integer; FrameIndex : Integer); overload;
Procedure Draw(Canvas : TW3Canvas; dx,dy : Integer; FrameIndex : Integer;
rotationDegrees : Integer); overload;

// center anchored
procedure DrawScaled(canvas : TW3Canvas; dx,dy : Float; FrameIndex : Integer;
scale : Float); overload;

Property SpriteWidth:Integer read FWidth write setWidth;
Property SpriteHeight:Integer read FHeight write setHeight;
property SpriteHalfWidth : Integer read FHalfWidth;
property SpriteHalfHeight : Integer read FHalfHeight;
property Rows : Integer read FRows;
property Columns : Integer read FColumns;
property NbFrames : Integer read FTotal;

Property Ready : Boolean read FReady;
property OnReady : TNotifyEvent read FOnReady write FOnReady;
End;

implementation

Constructor TW3SpriteSheet.Create;
Begin
inherited Create;
FImage:=TW3Image.Create(NIL);
FImage.OnLoad:=HandleImageReady;
FWidth:=32;
FHeight:=32;
InitSinCos;
end;

destructor TW3SpriteSheet.Destroy;
Begin
FImage.onLoad:=NIL;
FImage.free;
inherited;
end;

class procedure TW3SpriteSheet.InitSinCos;
var
i : Integer;
begin
if vSinCosReady then Exit;

vSinCosReady:=True;

for i:=0 to 359 do begin
var a := DegToRad(i);
vCosTable.Add(Cos(a));
vSinTable.Add(Sin(a));
end;
end;

Procedure TW3SpriteSheet.setWidth(aValue:Integer);
Begin
FWidth:=Max(aValue,4);
ReCalcInfo;
end;

procedure TW3SpriteSheet.setheight(aValue:Integer);
Begin
FHeight:=Max(aValue,4);
ReCalcInfo;
end;

Procedure TW3SpriteSheet.ReCalcInfo;
var
img : Variant;
Begin
if FReady then Begin
img:=ObjToVariant(FImage.TagRef);
FColumns:=(img.width+1) div FWidth;
FRows:=(img.height+1) div FHeight;
FTotal:=FColumns * FRows;
end else Begin
FColumns:=0;
FRows:=0;
FTotal:=0;
end;
FHalfHeight:=FWidth shr 1;
FHalfWidth:=FHalfHeight shr 1;
end;

procedure TW3SpriteSheet.HandleImageReady(sender:TObject);
Begin
FReady:=True;
ReCalcInfo;
if Assigned(FOnReady) then
FOnReady(Self);
end;

Procedure TW3SpriteSheet.LoadImage(aUrl:String);
Begin
FReady:=False;
ReCalcInfo;
FImage.LoadFromUrl(aUrl);
end;

procedure TW3SpriteSheet.LoadImage(aUrl : String; aSpriteWidth, aSpriteHeight : Integer);
begin
LoadImage(aURL);
SpriteWidth:=aSpriteWidth;
SpriteHeight:=aSpriteHeight;
end;

Procedure TW3SpriteSheet.Draw(Canvas:TW3Canvas;
dx,dy:Integer;FrameIndex:Integer);
var
sx,sy: Integer;
Begin
if FReady then Begin
sy:=FrameIndex div FColumns;
sx:=FrameIndex-sy*FColumns;
Canvas.DrawImageF(ObjToVariant(FImage.TagRef),
sx*SpriteWidth, sy*SpriteHeight,
SpriteWidth, SpriteHeight,
dx, dy, SpriteWidth, SpriteHeight);
end;
end;

Procedure TW3SpriteSheet.Draw(Canvas:TW3Canvas;
dx,dy:Integer;FrameIndex:Integer; rotationDegrees : Integer);
var
sx,sy: Integer;
begin
if rotationDegrees=0 then begin
Draw(Canvas, dx, dy, FrameIndex);
exit;
end;
if FReady then begin
sy:=FrameIndex div FColumns;
sx:=FrameIndex-sy*FColumns;
Canvas.Save;
case rotationDegrees of
0 : Canvas.Translate(dx, dy);
90 : Canvas.Transform(0, -1, 1, 0, dx, dy+SpriteHeight);
180 : Canvas.Transform(-1, 0, 0, -1, dx+SpriteWidth, dy+SpriteHeight);
270 : Canvas.Transform(0, 1, -1, 0, dx+SpriteWidth, dy);
else
while rotationDegrees<0 do
rotationDegrees+=360;
while rotationDegrees>=360 do
rotationDegrees-=360;
var c := vCosTable[rotationDegrees];
var s := vSinTable[rotationDegrees];
if rotationDegrees>=360-45 then
rotationDegrees+=45-360
else rotationDegrees+=45;
var c2 := vCosTable[rotationDegrees];
var s2 := vSinTable[rotationDegrees];
const r2 = Sqrt(2)/2;
Canvas.Transform(c, -s, s, c, dx+SpriteWidth*(0.5-r2*s2), dy+SpriteHeight*(0.5-r2*c2));
end;
Canvas.DrawImageF(ObjToVariant(FImage.TagRef),
sx*SpriteWidth, sy*SpriteHeight,
SpriteWidth, SpriteHeight,
0, 0, SpriteWidth, SpriteHeight);
Canvas.Restore;
end;
end;

procedure TW3SpriteSheet.DrawScaled(canvas : TW3Canvas; dx, dy : Float; frameIndex : Integer;
scale : Float);
var
sx, sy : Integer;
sw, sh : Float;
begin
if FReady then Begin
sy:=FrameIndex div FColumns;
sx:=FrameIndex-sy*FColumns;
sw:=SpriteWidth*scale;
sh:=SpriteHeight*scale;

Canvas.DrawImageF(ObjToVariant(FImage.TagRef),
sx*SpriteWidth, sy*SpriteHeight,
SpriteWidth, SpriteHeight,
dx-sw*0.5, dy-sh*0.5, sw, sh);
end;
end;

czar
30-05-2012, 08:51 PM
Hi

Is there a sample in Smart Mobile Studio that uses the sprite sheet?