Since it seams to work, at least in windows, I placed in in Tricks 'n' Tips.
Save it as AnimatedGIFSprite.pbi
And please wait a short time after starting the code, because it tries to download a free GIF file from internet.
Code: Select all
;
; https://www.purebasic.fr/english/viewtopic.php?p=594218
;
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
Structure AnimatedGIFInfo_Structure
Image.i
Frames.i
ActualFrame.i
Sprite.i
EndStructure
Structure AnimatedGIFSprite_Structure
Window.i
Map GIFInfoMap.AnimatedGIFInfo_Structure()
EndStructure
Global AnimatedGIFSprite.AnimatedGIFSprite_Structure
Procedure AnimateGIFSpritesTimerEvent()
Protected *AnimatedGIFSprite.AnimatedGIFInfo_Structure
*AnimatedGIFSprite = FindMapElement(AnimatedGIFSprite\GIFInfoMap(), Str(EventTimer()))
If *AnimatedGIFSprite
RemoveWindowTimer(AnimatedGIFSprite\Window, *AnimatedGIFSprite\Sprite)
SetImageFrame(*AnimatedGIFSprite\Image, *AnimatedGIFSprite\ActualFrame)
;Debug "AddWindowTimer: " + Str(AnimatedGIFSprite\Window) + " " + Str(Sprite) + " " + Str(*AnimatedGIFSprite\FrameDelay)
AddWindowTimer(AnimatedGIFSprite\Window, *AnimatedGIFSprite\Sprite, GetImageFrameDelay(*AnimatedGIFSprite\Image))
If StartDrawing(SpriteOutput(*AnimatedGIFSprite\Sprite))
DrawImage(ImageID(*AnimatedGIFSprite\Image), 0, 0)
StopDrawing()
EndIf
*AnimatedGIFSprite\ActualFrame + 1
If *AnimatedGIFSprite\ActualFrame >= *AnimatedGIFSprite\Frames
*AnimatedGIFSprite\ActualFrame = 0
EndIf
EndIf
EndProcedure
Procedure AnimateGIFSpritesUpdate(EventLoop=#False)
If Not EventLoop
While WindowEvent() : Wend
EndIf
EndProcedure
Procedure.i LoadAnimatedGIFSprite(Sprite.i, Filename$, Mode.i=0, StartAnimationPosition.i=0)
Protected Image.i, Result.i, *AnimatedGIFSprite.AnimatedGIFInfo_Structure
If AnimatedGIFSprite\Window = 0
AnimatedGIFSprite\Window = OpenWindow(#PB_Any, 0, 0, 0, 0, "", #PB_Window_Invisible)
BindEvent(#PB_Event_Timer, @AnimateGIFSpritesTimerEvent(), AnimatedGIFSprite\Window)
EndIf
Image = LoadImage(#PB_Any, Filename$)
If Image
If Sprite = #PB_Any
Sprite = CreateSprite(#PB_Any, ImageWidth(Image), ImageHeight(Image), Mode)
Result = Sprite
Else
Result = CreateSprite(Sprite, ImageWidth(Image), ImageHeight(Image), Mode)
EndIf
If Result
*AnimatedGIFSprite = AddMapElement(AnimatedGIFSprite\GIFInfoMap(), Str(Sprite))
*AnimatedGIFSprite\Image = Image
*AnimatedGIFSprite\Sprite = Sprite
*AnimatedGIFSprite\Frames = ImageFrameCount(Image)
If StartAnimationPosition > 0 And StartAnimationPosition <= 100
*AnimatedGIFSprite\ActualFrame = *AnimatedGIFSprite\Frames / (100 / StartAnimationPosition) - 1
If *AnimatedGIFSprite\ActualFrame < 0
*AnimatedGIFSprite\ActualFrame = 0
EndIf
EndIf
AddWindowTimer(AnimatedGIFSprite\Window, *AnimatedGIFSprite\Sprite, 1) ; to show it immediately
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure FinishAnimatedGIFSprites()
UnbindEvent(#PB_Event_Timer, @AnimateGIFSpritesTimerEvent(), AnimatedGIFSprite\Window)
ForEach AnimatedGIFSprite\GIFInfoMap()
FreeImage(AnimatedGIFSprite\GIFInfoMap()\Image)
FreeSprite(AnimatedGIFSprite\GIFInfoMap()\Sprite)
Next
EndProcedure
;-Demo
CompilerIf #PB_Compiler_IsMainFile
Define.i Width, Height, Depth, ScreenReady, AnySprite
Define GIFFilename$
UseGIFImageDecoder()
If InitSprite() = 0 Or InitKeyboard() = 0
MessageRequester("AnimatedGIFSprite", "Sprite system can't be initialized")
End
EndIf
If ExamineScreenModes()
While NextScreenMode()
Width = ScreenModeWidth()
If Width >= 800
Height = ScreenModeHeight()
Depth = ScreenModeDepth()
;Debug Str(Width) + "x" + Str(Height) + "," + Str(Depth)
Break
EndIf
Wend
Else
MessageRequester("AnimatedGIFSprite", "Screen modes can't be detected")
End
EndIf
If MessageRequester("AnimatedGIFSprite", "Use OpenScreen()?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
If OpenScreen(Width, Height, Depth, "")
ScreenReady = 1
EndIf
Else
If OpenWindow(0, 0, 0, Width, Height, "Press ESC for exit", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
If OpenWindowedScreen(WindowID(0), 0, 0, Width, Height)
ScreenReady = 2
EndIf
EndIf
EndIf
If ScreenReady
GIFFilename$ = GetUserDirectory(#PB_Directory_Downloads) + "animated-dog-image-0175.gif"
If FileSize(GIFFilename$) < 0
ReceiveHTTPFile("https://www.animatedimages.org/data/media/202/animated-dog-image-0175.gif", GIFFilename$)
EndIf
If FileSize(GIFFilename$) > 0
LoadAnimatedGIFSprite(1, GIFFilename$)
AnySprite = LoadAnimatedGIFSprite(#PB_Any, GIFFilename$, 0, 50)
Else
LoadAnimatedGIFSprite(1, #PB_Compiler_Home + "Examples/Sources/Data/PureBasicLogo.gif")
AnySprite = LoadAnimatedGIFSprite(#PB_Any, #PB_Compiler_Home + "Examples/Sources/Data/PureBasicLogo.gif", 0, 50)
EndIf
Repeat
FlipBuffers()
AnimateGIFSpritesUpdate() ; !!! only needed if no windows event loop is available !!!
ClearScreen(RGB(0, 128, 0))
DisplaySprite(1, 100, 100)
DisplayTransparentSprite(AnySprite, 300, 300)
ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
FinishAnimatedGIFSprites()
CloseScreen()
If ScreenReady = 2
CloseWindow(0)
EndIf
If FileSize(GIFFilename$) > 0
If MessageRequester("AnimatedGIFSprite", "Remove the downloaded GIF?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
DeleteFile(GIFFilename$)
EndIf
EndIf
EndIf
CompilerEndIf
mk-soft provided a second version without the hidden window and event stuff.
Maybe a disadvantage: you need variables to store the identifier and extra procedures to display the sprites.
Code: Select all
;
; https://www.purebasic.fr/english/viewtopic.php?p=594218
;
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
Structure AnimatedGIFSpriteInfo_Structure
Sprite.i
Delay.i
EndStructure
Structure AnimatedGIFSprite_Structure
NextTime.i
List SpriteList.AnimatedGIFSpriteInfo_Structure()
EndStructure
Procedure.i LoadAnimatedGIFSprite(Filename$, Mode.i=0, StartAnimationPosition.i=0)
Protected Image.i, cnt.i, index,i, *AnimatedGIFSprite.AnimatedGIFSprite_Structure, ActualFrame.i
Image = LoadImage(#PB_Any, Filename$)
If Image
*AnimatedGIFSprite = AllocateStructure(AnimatedGIFSprite_Structure)
If *AnimatedGIFSprite
cnt = ImageFrameCount(Image) - 1
For index = 0 To cnt
AddElement(*AnimatedGIFSprite\SpriteList())
SetImageFrame(Image, index)
*AnimatedGIFSprite\SpriteList()\Sprite = CreateSprite(#PB_Any, ImageWidth(Image), ImageHeight(Image), Mode)
*AnimatedGIFSprite\SpriteList()\Delay = GetImageFrameDelay(Image)
If StartDrawing(SpriteOutput(*AnimatedGIFSprite\SpriteList()\Sprite))
DrawImage(ImageID(Image), 0, 0)
StopDrawing()
EndIf
Next
If StartAnimationPosition > 0 And StartAnimationPosition <= 100
ActualFrame = cnt / (100 / StartAnimationPosition) - 1
If ActualFrame < 0
ActualFrame = 0
EndIf
EndIf
SelectElement(*AnimatedGIFSprite\SpriteList(), ActualFrame)
*AnimatedGIFSprite\NextTime = ElapsedMilliseconds() + *AnimatedGIFSprite\SpriteList()\Delay
EndIf
FreeImage(Image)
EndIf
ProcedureReturn *AnimatedGIFSprite
EndProcedure
Procedure DisplayAnimatedGifSprite(*AnimatedGIFSprite.AnimatedGIFSprite_Structure, x, y)
Protected time.i
With *AnimatedGIFSprite
DisplaySprite(\SpriteList()\Sprite, x, y)
time = ElapsedMilliseconds()
If time - \NextTime >= 0
If Not NextElement(\SpriteList())
FirstElement(\SpriteList())
EndIf
;\NextTime + \SpriteList()\Delay
\NextTime = time + \SpriteList()\Delay
EndIf
EndWith
EndProcedure
Procedure DisplayAnimatedGifTransparentSprite(*AnimatedGIFSprite.AnimatedGIFSprite_Structure, x, y, Intensity=255, Color.q=-1)
Protected time.i
With *AnimatedGIFSprite
If Color = -1
DisplayTransparentSprite(\SpriteList()\Sprite, x, y, Intensity)
Else
DisplayTransparentSprite(\SpriteList()\Sprite, x, y, Intensity, Color)
EndIf
time = ElapsedMilliseconds()
If time - \NextTime >= 0
If Not NextElement(\SpriteList())
FirstElement(\SpriteList())
EndIf
;\NextTime + \SpriteList()\Delay
\NextTime = time + \SpriteList()\Delay
EndIf
EndWith
EndProcedure
;-Demo
CompilerIf #PB_Compiler_IsMainFile
Define.i Width, Height, Depth, ScreenReady
Define *AnySprite, *AnySprite2
Define GIFFilename$
UseGIFImageDecoder()
If InitSprite() = 0 Or InitKeyboard() = 0
MessageRequester("AnimatedGIFSprite", "Sprite system can't be initialized")
End
EndIf
If ExamineScreenModes()
While NextScreenMode()
Width = ScreenModeWidth()
If Width >= 800
Height = ScreenModeHeight()
Depth = ScreenModeDepth()
;Debug Str(Width) + "x" + Str(Height) + "," + Str(Depth)
Break
EndIf
Wend
Else
MessageRequester("AnimatedGIFSprite", "Screen modes can't be detected")
End
EndIf
If MessageRequester("AnimatedGIFSprite", "Use OpenScreen()?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
If OpenScreen(Width, Height, Depth, "")
ScreenReady = 1
EndIf
Else
If OpenWindow(0, 0, 0, 800, 600, "Press ESC for exit", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
If OpenWindowedScreen(WindowID(0), 0, 0, 800, 600)
ScreenReady = 2
EndIf
EndIf
EndIf
If ScreenReady > 0
GIFFilename$ = GetUserDirectory(#PB_Directory_Downloads) + "animated-dog-image-0175.gif"
If FileSize(GIFFilename$) < 0
ReceiveHTTPFile("https://www.animatedimages.org/data/media/202/animated-dog-image-0175.gif", GIFFilename$)
EndIf
If FileSize(GIFFilename$) > 0
*AnySprite = LoadAnimatedGIFSprite(GIFFilename$)
*AnySprite2 = LoadAnimatedGIFSprite(GIFFilename$, 0, 50)
Else
*AnySprite = LoadAnimatedGIFSprite(#PB_Compiler_Home + "Examples/Sources/Data/PureBasicLogo.gif")
*AnySprite2 = LoadAnimatedGIFSprite(#PB_Compiler_Home + "Examples/Sources/Data/PureBasicLogo.gif", 0, 50)
EndIf
Repeat
; else I get an inresponsible window if I click with mouse
If ScreenReady = 2
While WindowEvent() : Wend
EndIf
FlipBuffers()
ClearScreen(RGB(0, 128, 0))
DisplayAnimatedGifSprite(*AnySprite, 100, 100)
DisplayAnimatedGifTransparentSprite(*AnySprite2, 300, 300)
ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
CloseScreen()
If ScreenReady = 2
CloseWindow(0)
EndIf
If FileSize(GIFFilename$) > 0
If MessageRequester("AnimatedGIFSprite", "Remove the downloaded GIF?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
DeleteFile(GIFFilename$)
EndIf
EndIf
EndIf
CompilerEndIf