source: trunk/Packages/bgrabitmap/bgraspritegl.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 15.4 KB
Line 
1unit BGRASpriteGL;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, BGRAOpenGLType,
9 BGRABitmapTypes;
10
11type
12 { TBGLCustomSprite }
13
14 TBGLCustomSprite = class
15 protected
16 FHandle: Pointer;
17 FTexture: IBGLTexture;
18 FFrameLoopStart: integer;
19 FFrameLoopEnd : integer;
20 procedure SetFrameLoopEnd(AValue: integer);
21 procedure SetFrameLoopStart(AValue: integer);
22 function GetHorizontalAlign: TAlignment; virtual; abstract;
23 function GetVerticalAlign: TTextLayout; virtual; abstract;
24 procedure SetHorizontalAlign(AValue: TAlignment); virtual; abstract;
25 procedure SetVerticalAlign(AValue: TTextLayout); virtual; abstract;
26 function GetAlpha: Integer; virtual; abstract;
27 function GetAngle: Single; virtual; abstract;
28 function GetColor: TBGRAPixel; virtual; abstract;
29 function GetActualFrame: Single; virtual; abstract;
30 function GetFrame: Single;
31 function GetH: Single; virtual; abstract;
32 function GetLayer: Integer; virtual; abstract;
33 function GetLocation: TPointF; virtual;
34 function GetVisible: Boolean; virtual;
35 function GetW: Single; virtual; abstract;
36 function GetX: Single; virtual; abstract;
37 function GetY: Single; virtual; abstract;
38 function GetTexture: IBGLTexture; virtual;
39 function GetHandle: Pointer; virtual;
40 procedure SetAlpha(AValue: Integer); virtual; abstract;
41 procedure SetAngle(AValue: Single); virtual; abstract;
42 procedure SetColor(AValue: TBGRAPixel); virtual; abstract;
43 procedure SetFrame(AValue: Single);
44 procedure SetActualFrame(AValue: Single); virtual; abstract;
45 procedure SetH(AValue: Single); virtual; abstract;
46 procedure SetLayer(AValue: Integer); virtual; abstract;
47 procedure SetLocation(AValue: TPointF); virtual;
48 procedure SetW(AValue: Single); virtual; abstract;
49 procedure SetVisible({%H-}AValue: boolean); virtual;
50 procedure SetX(AValue: Single); virtual; abstract;
51 procedure SetY(AValue: Single); virtual; abstract;
52 procedure CreateHandle({%H-}ATexture: IBGLTexture; {%H-}ALayer: Integer); virtual;
53 procedure OnInit; virtual;
54 public
55 constructor Create(ATexture: IBGLTexture; ALayer: integer);
56 destructor Destroy; override;
57 procedure OnDraw; virtual;
58 procedure OnElapse({%H-}AElapsedMs: integer); virtual;
59 procedure OnTimer; virtual;
60 procedure QueryDestroy; virtual; abstract;
61 property Layer : Integer read GetLayer write SetLayer;
62 property Location: TPointF read GetLocation write SetLocation;
63 property X : Single read GetX write SetX;
64 property Y : Single read GetY write SetY;
65 property W : Single read GetW write SetW;
66 property H : Single read GetH write SetH;
67 property Angle : Single read GetAngle write SetAngle;
68 property Frame : Single read GetFrame write SetFrame;
69 property FrameLoopStart : integer read FFrameLoopStart write SetFrameLoopStart;
70 property FrameLoopEnd : integer read FFrameLoopEnd write SetFrameLoopEnd;
71 property Alpha : Integer read GetAlpha write SetAlpha;
72 property Color : TBGRAPixel read GetColor write SetColor;
73 property HorizontalAlign: TAlignment read GetHorizontalAlign write SetHorizontalAlign;
74 property VerticalAlign: TTextLayout read GetVerticalAlign write SetVerticalAlign;
75 property Visible : Boolean read GetVisible write SetVisible;
76 property Texture : IBGLTexture read GetTexture;
77 property Handle : Pointer read GetHandle;
78 end;
79
80 { TBGLDefaultSprite }
81
82 TBGLDefaultSprite = class(TBGLCustomSprite)
83 protected
84 FColor : TBGRAPixel;
85 FLocation,FSize: TPointF;
86 FAngle,FFrame : single;
87 FHorizontalAlign: TAlignment;
88 FVerticalAlign: TTextLayout;
89 FQueryDestroy: boolean;
90 FLayer: integer;
91 FHidden: boolean;
92 function GetHorizontalAlign: TAlignment; override;
93 function GetVerticalAlign: TTextLayout; override;
94 procedure SetHorizontalAlign(AValue: TAlignment); override;
95 procedure SetVerticalAlign(AValue: TTextLayout); override;
96 function GetAlpha: Integer; override;
97 function GetAngle: Single; override;
98 function GetColor: TBGRAPixel; override;
99 function GetDestroy: Boolean;
100 function GetActualFrame: Single; override;
101 function GetH: Single; override;
102 function GetLayer: Integer; override;
103 function GetVisible: Boolean; override;
104 function GetW: Single; override;
105 function GetX: Single; override;
106 function GetY: Single; override;
107 procedure SetAlpha(AValue: Integer); override;
108 procedure SetAngle(AValue: Single); override;
109 procedure SetColor(AValue: TBGRAPixel); override;
110 procedure SetDestroy(AValue: Boolean);
111 procedure SetActualFrame(AValue: Single); override;
112 procedure SetH(AValue: Single); override;
113 procedure SetLayer(AValue: Integer); override;
114 procedure SetVisible(AValue: boolean); override;
115 procedure SetW(AValue: Single); override;
116 procedure SetX(AValue: Single); override;
117 procedure SetY(AValue: Single); override;
118 procedure CreateHandle({%H-}ATexture: IBGLTexture; {%H-}ALayer: Integer); override;
119 public
120 procedure QueryDestroy; override;
121 end;
122
123 { TBGLCustomSpriteEngine }
124
125 TBGLCustomSpriteEngine = class
126 protected
127 function GetSprite(AIndex: integer): TBGLCustomSprite; virtual; abstract;
128 function GetCount: integer; virtual; abstract;
129 public
130 procedure Add(ASprite: TBGLCustomSprite); virtual; abstract;
131 procedure Remove(ASprite: TBGLCustomSprite); virtual; abstract;
132 procedure OnDraw; virtual; abstract;
133 procedure OnTimer; virtual; abstract;
134 procedure OnElapse(AElapsedMs: integer); virtual; abstract;
135 procedure Clear; virtual; abstract;
136 procedure Delete(AIndex: integer); virtual; abstract;
137 property Count: Integer read GetCount;
138 property Sprite[AIndex: integer]: TBGLCustomSprite read GetSprite;
139 end;
140
141 { TBGLDefaultSpriteEngine }
142
143 TBGLDefaultSpriteEngine = class(TBGLCustomSpriteEngine)
144 protected
145 FSpriteRemoved: TBGLCustomSprite;
146 FSprites: array of TBGLDefaultSprite;
147 FSpritesCount: integer;
148 function GetSprite(AIndex: integer): TBGLCustomSprite; override;
149 function GetCount: integer; override;
150 public
151 constructor Create;
152 procedure Add(ASprite: TBGLCustomSprite); override;
153 procedure Remove(ASprite: TBGLCustomSprite); override;
154 procedure OnDraw; override;
155 procedure OnTimer; override;
156 procedure OnElapse(AElapsedMs: integer); override;
157 procedure Clear; override;
158 procedure Delete(AIndex: integer); override;
159 end;
160
161var
162 BGLSpriteEngine : TBGLCustomSpriteEngine;
163
164implementation
165
166{ TBGLDefaultSpriteEngine }
167
168function TBGLDefaultSpriteEngine.GetSprite(AIndex: integer): TBGLCustomSprite;
169begin
170 if (AIndex < 0) or (Aindex >= Count) then
171 raise ERangeError.Create('Index out of bounds');
172 result := FSprites[AIndex];
173end;
174
175function TBGLDefaultSpriteEngine.GetCount: integer;
176begin
177 result := FSpritesCount;
178end;
179
180constructor TBGLDefaultSpriteEngine.Create;
181begin
182 FSpritesCount := 0;
183end;
184
185procedure TBGLDefaultSpriteEngine.Add(ASprite: TBGLCustomSprite);
186var
187 i: Integer;
188begin
189 if ASprite = nil then exit;
190 if not (ASprite is TBGLDefaultSprite) then
191 raise exception.Create('Invalid class');
192 for i := 0 to Count-1 do
193 if FSprites[i] = ASprite then exit;
194 if Count = length(FSprites) then
195 setlength(FSprites, length(FSprites)*2 + 1);
196 FSprites[Count] := TBGLDefaultSprite(ASprite);
197 Inc(FSpritesCount);
198end;
199
200procedure TBGLDefaultSpriteEngine.Remove(ASprite: TBGLCustomSprite);
201var
202 i: Integer;
203begin
204 if ASprite = FSpriteRemoved then exit;
205 for i := 0 to Count-1 do
206 if FSprites[i] = ASprite then
207 begin
208 Delete(i);
209 exit;
210 end;
211end;
212
213procedure TBGLDefaultSpriteEngine.OnDraw;
214var i: integer;
215begin
216 for i := 0 to Count-1 do
217 FSprites[i].OnDraw;
218end;
219
220procedure TBGLDefaultSpriteEngine.OnTimer;
221var i,j,k: integer;
222 temp: TBGLDefaultSprite;
223begin
224 for i := 0 to Count-1 do
225 FSprites[i].OnTimer;
226 for i := Count-1 downto 0 do
227 if FSprites[i].FQueryDestroy then
228 Delete(i);
229 for i := 1 to Count-1 do
230 begin
231 j := i;
232 while (j > 0) and (FSprites[j-1].Layer > FSprites[i].Layer) do dec(j);
233 if j <> i then
234 begin
235 temp := FSprites[i];
236 for k := i downto j+1 do
237 FSprites[k] := FSprites[k-1];
238 FSprites[j] := temp;
239 end;
240 end;
241end;
242
243procedure TBGLDefaultSpriteEngine.OnElapse(AElapsedMs: integer);
244var i,j,k: integer;
245 temp: TBGLDefaultSprite;
246begin
247 for i := 0 to Count-1 do
248 FSprites[i].OnElapse(AElapsedMs);
249 for i := Count-1 downto 0 do
250 if FSprites[i].FQueryDestroy then
251 Delete(i);
252 for i := 1 to Count-1 do
253 begin
254 j := i;
255 while (j > 0) and (FSprites[j-1].Layer > FSprites[i].Layer) do dec(j);
256 if j <> i then
257 begin
258 temp := FSprites[i];
259 for k := i downto j+1 do
260 FSprites[k] := FSprites[k-1];
261 FSprites[j] := temp;
262 end;
263 end;
264end;
265
266procedure TBGLDefaultSpriteEngine.Clear;
267var i: integer;
268begin
269 for i := 0 to Count-1 do
270 begin
271 FSpriteRemoved := FSprites[i];
272 FSpriteRemoved.Free;
273 FSpriteRemoved := nil;
274 end;
275 FSprites := nil;
276 FSpritesCount := 0;
277end;
278
279procedure TBGLDefaultSpriteEngine.Delete(AIndex: integer);
280var i: integer;
281begin
282 if (AIndex < 0) or (AIndex >= Count) then exit;
283 FSpriteRemoved := FSprites[AIndex];
284 for i := AIndex to Count-1 do
285 FSprites[i] := FSprites[i+1];
286 dec(FSpritesCount);
287 if FSpritesCount <= length(FSprites) div 2 then
288 setlength(FSprites,FSpritesCount);
289 FSpriteRemoved.Free;
290 FSpriteRemoved := nil;
291end;
292
293{ TBGLDefaultSprite }
294
295function TBGLDefaultSprite.GetHorizontalAlign: TAlignment;
296begin
297 result := FHorizontalAlign;
298end;
299
300function TBGLDefaultSprite.GetVerticalAlign: TTextLayout;
301begin
302 result := FVerticalAlign;
303end;
304
305procedure TBGLDefaultSprite.SetHorizontalAlign(AValue: TAlignment);
306begin
307 FHorizontalAlign:= AValue;
308end;
309
310procedure TBGLDefaultSprite.SetVerticalAlign(AValue: TTextLayout);
311begin
312 FVerticalAlign := AValue;
313end;
314
315function TBGLDefaultSprite.GetAlpha: Integer;
316begin
317 result := FColor.alpha;
318end;
319
320function TBGLDefaultSprite.GetAngle: Single;
321begin
322 result := FAngle;
323end;
324
325function TBGLDefaultSprite.GetColor: TBGRAPixel;
326begin
327 result := FColor;
328end;
329
330function TBGLDefaultSprite.GetDestroy: Boolean;
331begin
332 result := FQueryDestroy;
333end;
334
335function TBGLDefaultSprite.GetActualFrame: Single;
336begin
337 result := FFrame;
338end;
339
340function TBGLDefaultSprite.GetH: Single;
341begin
342 result := FSize.Y;
343end;
344
345function TBGLDefaultSprite.GetLayer: Integer;
346begin
347 result := FLayer;
348end;
349
350function TBGLDefaultSprite.GetVisible: Boolean;
351begin
352 Result:= not FHidden;
353end;
354
355function TBGLDefaultSprite.GetW: Single;
356begin
357 result := FSize.X;
358end;
359
360function TBGLDefaultSprite.GetX: Single;
361begin
362 result := FLocation.X;
363end;
364
365function TBGLDefaultSprite.GetY: Single;
366begin
367 result := FLocation.Y;
368end;
369
370procedure TBGLDefaultSprite.SetAlpha(AValue: Integer);
371begin
372 FColor.Alpha := AValue;
373end;
374
375procedure TBGLDefaultSprite.SetAngle(AValue: Single);
376begin
377 FAngle:= AValue;
378end;
379
380procedure TBGLDefaultSprite.SetColor(AValue: TBGRAPixel);
381begin
382 FColor := AValue;
383end;
384
385procedure TBGLDefaultSprite.SetDestroy(AValue: Boolean);
386begin
387 FQueryDestroy:= AValue;
388end;
389
390procedure TBGLDefaultSprite.SetActualFrame(AValue: Single);
391begin
392 FFrame:= AValue;
393end;
394
395procedure TBGLDefaultSprite.SetH(AValue: Single);
396begin
397 FSize.Y := AValue;
398end;
399
400procedure TBGLDefaultSprite.SetLayer(AValue: Integer);
401begin
402 FLayer:= AValue;
403end;
404
405procedure TBGLDefaultSprite.SetVisible(AValue: boolean);
406begin
407 FHidden := not AValue;
408end;
409
410procedure TBGLDefaultSprite.SetW(AValue: Single);
411begin
412 FSize.X := AValue;
413end;
414
415procedure TBGLDefaultSprite.SetX(AValue: Single);
416begin
417 FLocation.X := AValue;
418end;
419
420procedure TBGLDefaultSprite.SetY(AValue: Single);
421begin
422 FLocation.Y := AValue;
423end;
424
425procedure TBGLDefaultSprite.CreateHandle(ATexture: IBGLTexture; ALayer: Integer);
426begin
427 inherited CreateHandle(ATexture, ALayer);
428 FQueryDestroy := false;
429 FLayer:= ALayer;
430end;
431
432procedure TBGLDefaultSprite.QueryDestroy;
433begin
434 SetDestroy(True);
435end;
436
437{ TBGLCustomSprite }
438
439function TBGLCustomSprite.GetTexture: IBGLTexture;
440begin
441 result := FTexture;
442end;
443
444function TBGLCustomSprite.GetHandle: Pointer;
445begin
446 result := FHandle;
447end;
448
449procedure TBGLCustomSprite.SetFrame(AValue: Single);
450var loopLength: integer;
451begin
452 if (FrameLoopEnd <> 0) and (FrameLoopStart <> 0) then
453 begin
454 loopLength := FrameLoopEnd-FrameLoopStart+1;
455 if AValue >= FrameLoopEnd+0.49 then
456 begin
457 if loopLength <= 1 then
458 AValue := FrameLoopEnd+0.49
459 else
460 begin
461 AValue -= Trunc((AValue-(FrameLoopStart-0.5))/loopLength)*loopLength;
462 if AValue > FrameLoopEnd+0.49 then AValue := FrameLoopStart-0.49;
463 if AValue < FrameLoopStart-0.49 then AValue := FrameLoopStart-0.49;
464 end;
465 end else
466 if AValue < FrameLoopStart-0.49 then
467 begin
468 if loopLength <= 1 then
469 AValue := FrameLoopStart-0.49
470 else
471 begin
472 AValue += Trunc((FrameLoopEnd+0.5-AValue)/loopLength)*loopLength;
473 if AValue > FrameLoopEnd+0.49 then AValue := FrameLoopEnd+0.49;
474 if AValue < FrameLoopStart-0.49 then AValue := FrameLoopEnd+0.49;
475 end;
476 end;
477 end;
478 SetActualFrame(AValue);
479end;
480
481procedure TBGLCustomSprite.SetFrameLoopEnd(AValue: integer);
482begin
483 FFrameLoopEnd := AValue;
484 if FFrameLoopEnd < FFrameLoopStart then
485 FFrameLoopStart := FFrameLoopEnd;
486end;
487
488procedure TBGLCustomSprite.SetFrameLoopStart(AValue: integer);
489begin
490 FFrameLoopStart := AValue;
491 if FFrameLoopStart > FFrameLoopEnd then
492 FFrameLoopEnd := FFrameLoopStart;
493end;
494
495function TBGLCustomSprite.GetFrame: Single;
496begin
497 result := GetActualFrame;
498end;
499
500function TBGLCustomSprite.GetLocation: TPointF;
501begin
502 result := PointF(X,Y);
503end;
504
505function TBGLCustomSprite.GetVisible: Boolean;
506begin
507 result := true;
508end;
509
510procedure TBGLCustomSprite.SetLocation(AValue: TPointF);
511begin
512 X := AValue.X;
513 Y := AValue.Y;
514end;
515
516procedure TBGLCustomSprite.SetVisible(AValue: boolean);
517begin
518 raise ENotImplemented.Create('Not implemented in base class');
519end;
520
521procedure TBGLCustomSprite.CreateHandle(ATexture: IBGLTexture; ALayer: Integer);
522begin
523 FHandle := nil;
524end;
525
526procedure TBGLCustomSprite.OnInit;
527begin
528 //nothing
529end;
530
531constructor TBGLCustomSprite.Create(ATexture: IBGLTexture; ALayer: integer);
532begin
533 CreateHandle(ATexture,ALayer);
534 FTexture := ATexture;
535 Layer := ALayer;
536 if ATexture = nil then
537 begin
538 W := 0;
539 H := 0;
540 end else
541 begin
542 W := ATexture.FrameWidth;
543 H := ATexture.FrameHeight;
544 end;
545 HorizontalAlign := taLeftJustify;
546 VerticalAlign:= tlTop;
547 Color := BGRAWhite;
548 FrameLoopStart := 1;
549 FrameLoopEnd := 0;
550 OnInit;
551 BGLSpriteEngine.Add(self);
552end;
553
554destructor TBGLCustomSprite.Destroy;
555begin
556 if Assigned(BGLSpriteEngine) then
557 BGLSpriteEngine.Remove(self);
558 inherited Destroy;
559end;
560
561procedure TBGLCustomSprite.OnDraw;
562var NumFrame: integer;
563begin
564 if Visible and (Texture <> nil) then
565 begin
566 NumFrame := Trunc(Frame+0.5);
567 if Angle <> 0 then
568 Texture.Frame[NumFrame].StretchDrawAngle(X,Y,W,H,Angle,HorizontalAlign,VerticalAlign, Color)
569 else
570 Texture.Frame[NumFrame].StretchDraw(X,Y,W,H,HorizontalAlign,VerticalAlign, Color)
571 end;
572end;
573
574procedure TBGLCustomSprite.OnElapse(AElapsedMs: integer);
575begin
576 //override if you want to handle time as continuous flow. It is recommended to use floating point positions in this case.
577end;
578
579procedure TBGLCustomSprite.OnTimer;
580begin
581 //override if you want to handle time as discrete frames with fixed time interval
582end;
583
584end.
585
Note: See TracBrowser for help on using the repository browser.