{ * Copyright (c) 2012 Andrey Kemka * * This software is provided 'as-is', without any express or * implied warranty. In no event will the authors be held * liable for any damages arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; * you must not claim that you wrote the original software. * If you use this software in a product, an acknowledgment * in the product documentation would be appreciated but * is not required. * * 2. Altered source versions must be plainly marked as such, * and must not be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any * source distribution. } unit zglSpriteEngine; {$I zglCustomConfig.cfg} {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} interface uses {$IFDEF USE_ZENGL_STATIC} zgl_main, zgl_fx, zgl_sprite_2d, zgl_textures {$ELSE} zglHeader {$ENDIF} ; type zglCSprite2D = class; zglCSEngine2D = class; zglCSEngine2D = class protected FCount : Integer; FList : array of zglCSprite2D; procedure SortByLayer( iLo, iHi : Integer ); procedure SortByID( iLo, iHi : Integer ); function GetSprite( ID : Integer ) : zglCSprite2D; procedure SetSprite( ID : Integer; Sprite : zglCSprite2D ); public destructor Destroy; override; function AddSprite : Integer; overload; virtual; function AddSprite( Texture : zglPTexture; Layer : Integer ) : zglCSprite2D; overload; virtual; procedure AddSprite( Sprite : zglCSprite2D; Layer : Integer ); overload; virtual; procedure DelSprite( ID : Integer ); virtual; procedure ClearAll; virtual; procedure Draw; virtual; procedure Proc; virtual; property Count: Integer read FCount; property List[ID : Integer]: zglCSprite2D read GetSprite write SetSprite; end; zglCSprite2D = class protected public ID : Integer; Manager : zglCSEngine2D; Texture : zglPTexture; Kill : Boolean; Layer : Integer; X, Y : Single; W, H : Single; Angle : Single; Frame : Single; Alpha : Integer; FxFlags : LongWord; constructor Create( _Manager : zglCSEngine2D; _ID : Integer ); virtual; destructor Destroy; override; procedure OnInit( _Texture : zglPTexture; _Layer : Integer ); virtual; procedure OnDraw; virtual; procedure OnProc; virtual; procedure OnFree; virtual; end; implementation destructor zglCSEngine2D.Destroy; begin ClearAll(); end; procedure zglCSEngine2D.SortByLayer( iLo, iHi : Integer ); var lo, hi, mid : Integer; t : zglCSprite2D; begin lo := iLo; hi := iHi; mid := FList[ ( lo + hi ) shr 1 ].Layer; repeat while FList[ lo ].Layer < mid do INC( lo ); while FList[ hi ].Layer > mid do DEC( hi ); if lo <= hi then begin t := FList[ lo ]; FList[ lo ] := FList[ hi ]; FList[ hi ] := t; INC( lo ); DEC( hi ); end; until lo > hi; if hi > iLo Then SortByLayer( iLo, hi ); if lo < iHi Then SortByLayer( lo, iHi ); end; procedure zglCSEngine2D.SortByID( iLo, iHi : Integer ); var lo, hi, mid : Integer; t : zglCSprite2D; begin lo := iLo; hi := iHi; mid := FList[ ( lo + hi ) shr 1 ].ID; repeat while FList[ lo ].ID < mid do INC( lo ); while FList[ hi ].ID > mid do DEC( hi ); if Lo <= Hi then begin t := FList[ lo ]; FList[ lo ] := FList[ hi ]; FList[ hi ] := t; INC( lo ); DEC( hi ); end; until lo > hi; if hi > iLo Then SortByID( iLo, hi ); if lo < iHi Then SortByID( lo, iHi ); end; function zglCSEngine2D.GetSprite( ID : Integer ) : zglCSprite2D; begin Result := FList[ ID ]; end; procedure zglCSEngine2D.SetSprite( ID : Integer; Sprite : zglCSprite2D ); begin FList[ ID ] := Sprite; end; function zglCSEngine2D.AddSprite : Integer; begin if FCount + 1 > Length( FList ) Then SetLength( FList, FCount + 16384 ); Result := FCount; INC( FCount ); end; function zglCSEngine2D.AddSprite( Texture : zglPTexture; Layer : Integer ) : zglCSprite2D; var id : Integer; begin id := AddSprite(); FList[ id ] := zglCSprite2D.Create( Self, id ); Result := FList[ id ]; Result.OnInit( Texture, Layer ); end; procedure zglCSEngine2D.AddSprite( Sprite : zglCSprite2D; Layer : Integer ); var id : Integer; begin if not Assigned( Sprite ) Then exit; id := AddSprite(); FList[ id ] := Sprite; FList[ id ].Manager := Self; FList[ id ].ID := id; FList[ id ].OnInit( Sprite.Texture, Layer ); end; procedure zglCSEngine2D.DelSprite( ID : Integer ); var i : Integer; begin if ( ID < 0 ) or ( ID > FCount - 1 ) or ( FCount = 0 ) Then exit; FList[ ID ].Free; for i := ID to FCount - 2 do begin FList[ i ] := FList[ i + 1 ]; FList[ i ].ID := i; end; DEC( FCount ); end; procedure zglCSEngine2D.ClearAll; var i : Integer; begin for i := 0 to FCount - 1 do FList[ i ].Destroy(); SetLength( FList, 0 ); FCount := 0; end; procedure zglCSEngine2D.Draw; var i : Integer; s : zglCSprite2D; begin i := 0; while i < FCount do begin s := FList[ i ]; s.OnDraw(); if s.Kill Then DelSprite( s.ID ) else INC( i ); end; end; procedure zglCSEngine2D.Proc; var i, a, b, l : Integer; s : zglCSprite2D; begin i := 0; while i < FCount do begin s := FList[ i ]; s.OnProc(); if s.Kill Then DelSprite( s.ID ) else INC( i ); end; if FCount > 1 Then begin l := 0; for i := 0 to FCount - 1 do begin s := FList[ i ]; if s.Layer > l Then l := s.Layer; if s.Layer < l Then begin SortByLayer( 0, FCount - 1 ); // TODO: provide parameter for enabling/disabling stable sorting l := FList[ 0 ].Layer; a := 0; for b := 0 to FCount - 1 do begin s := FList[ b ]; if ( l <> s.Layer ) Then begin SortByID( a, b - 1 ); a := b; l := s.Layer; end; if b = FCount - 1 Then SortByID( a, b ); end; for a := 0 to FCount - 1 do FList[ a ].ID := a; break; end; end; end; end; constructor zglCSprite2D.Create( _Manager : zglCSEngine2D; _ID : Integer ); begin Manager := _Manager; ID := _ID; OnInit( nil, 0 ); end; destructor zglCSprite2D.Destroy; begin OnFree(); end; procedure zglCSprite2D.OnInit( _Texture : zglPTexture; _Layer : Integer ); begin Texture := _Texture; Layer := _Layer; X := 0; Y := 0; if Assigned( Texture ) Then begin W := Round( ( Texture.FramesCoord[ 1, 1 ].X - Texture.FramesCoord[ 1, 0 ].X ) * Texture.Width ); H := Round( ( Texture.FramesCoord[ 1, 0 ].Y - Texture.FramesCoord[ 1, 2 ].Y ) * Texture.Height ); end else begin W := 0; H := 0; end; Angle := 0; Frame := 1; Alpha := 255; FxFlags := FX_BLEND; end; procedure zglCSprite2D.OnDraw; begin asprite2d_Draw( Texture, X, Y, W, H, Angle, Round( Frame ), Alpha, FxFlags ); end; procedure zglCSprite2D.OnProc; begin end; procedure zglCSprite2D.OnFree; begin end; end.