Page 3 of 3

Re: AnimatedGIFSprite

Posted: Sun Jan 22, 2023 3:50 pm
by mk-soft
Isn't it better to create an array of sprites instead of redrawing the sprite each time ?

Just an idea with DisplayGif(*Object, ...) or DisplayTransparentGif(*Object, ...)

Re: AnimatedGIFSprite

Posted: Sun Jan 22, 2023 4:08 pm
by Kamarro
Hi, thanks for your idea, but I think this should be moved to viewtopic.php?t=80564 because this is more like a sequence of post on my original Topic about Help with Animated Gifs.

Yes and No! In fact, I'm not sure if I understood what you're talking about. If I'm right you're saying what I said I was doing, decomposing the Animated Gifs into JPEGs and displaying them one by one, from a stack of images.
This is probably what I'll have to do, because it saves time and memory on a big game like mine. I can use lower resolutions, highly compressed JPGs and reduce the number of frames. The use of Animated GIFs is really looking too heavy for what I need!

It's this that you're proposing? I'd like to use the ClipSprite too, but I didn't try it yet, and I'm not sure if it works fine with Animated Gifs, as well as it works with static images. Probably I'll usee it for this as I used it for my maps...

Re: AnimatedGIFSprite

Posted: Sun Jan 22, 2023 4:31 pm
by Kamarro
Sometimes we lose time with things without any purpose, but I decided to try this little change on the main program and got a surprise: This animation of the dog running is really well done. Try this changes to see it really running. It's very good, and with only 7 frames! Nice!

Code: Select all

;
; https://www.purebasic.fr/english/viewtopic.php?p=594218
; 

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


Structure AnimatedGIFInfo_Structure
  Frames.i
  ActualFrame.i
  OrgImage.i
  Sprite.i
EndStructure

Structure AnimatedGIFSprite_Structure
  Window.i
  Map GIFInfoMap.AnimatedGIFInfo_Structure()
EndStructure


Global AnimatedGIFSprite.AnimatedGIFSprite_Structure

Define X

Procedure AnimateGIFSprites(*GIF.AnimatedGIFInfo_Structure)
  
  SetImageFrame(*GIF\OrgImage, *GIF\ActualFrame)
  ;Debug "AddWindowTimer: " + Str(AnimatedGIFSprite\Window) + " " + Str(Sprite) + " " + Str(*AnimatedGIFSprite\FrameDelay)
  AddWindowTimer(AnimatedGIFSprite\Window, *GIF\Sprite, GetImageFrameDelay(*GIF\OrgImage))
  
  If StartDrawing(SpriteOutput(*GIF\Sprite))
    DrawImage(ImageID(*GIF\OrgImage), 0, 0)
    StopDrawing()
  EndIf
  
  *GIF\ActualFrame + 1
  If *GIF\ActualFrame = *GIF\Frames
    *GIF\ActualFrame = 0
  EndIf
  
EndProcedure


Procedure AnimateGIFSpritesTimerEvent()
  
  Protected *GIF.AnimatedGIFInfo_Structure
  
  
  *GIF = FindMapElement(AnimatedGIFSprite\GIFInfoMap(), Str(EventTimer()))
  If *GIF
    RemoveWindowTimer(AnimatedGIFSprite\Window, *GIF\Sprite)
    AnimateGIFSprites(*GIF)
  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\OrgImage = Image
      *AnimatedGIFSprite\Sprite = Sprite
      *AnimatedGIFSprite\Frames = ImageFrameCount(Image)
      If StartAnimationPosition > 0 And StartAnimationPosition <= 100
        *AnimatedGIFSprite\ActualFrame = *AnimatedGIFSprite\Frames / (100 / StartAnimationPosition) - 1
      EndIf
      AnimateGIFSprites(*AnimatedGIFSprite)
    EndIf
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


;-Demo
CompilerIf #PB_Compiler_IsMainFile
  
  Define.i Width, Height, Depth, ScreenReady, AnySprite
  Define GIFFilename$
  
  UseGIFImageDecoder()
  
  If InitSprite() = 0 Or InitKeyboard() = 0
    MessageRequester("Error", "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("Error", "Screen modes can't be detected")
    End
  EndIf
  
  If MessageRequester("Choose screen mode", "Use OpenScreen()?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
    If OpenScreen(Width, Height, Depth, "")
      ScreenReady = #True
    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 = #True
      EndIf
    EndIf
  EndIf
  
  If ScreenReady
    GIFFilename$ = GetUserDirectory(#PB_Directory_Downloads) + "animated-dog-image-0175.gif"
    
    ReceiveHTTPFile("https://www.animatedimages.org/data/media/202/animated-dog-image-0175.gif", GIFFilename$)
    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, X, 100)
      Delay(150)
      If X<1500 : X+30 : Else : X=100 : EndIf
      
      ExamineKeyboard()
    Until KeyboardPushed(#PB_Key_Escape)
    
    If FileSize(GIFFilename$) > 0
      DeleteFile(GIFFilename$)
    EndIf
  EndIf
  
CompilerEndIf

Re: AnimatedGIFSprite

Posted: Sun Jan 22, 2023 5:56 pm
by infratec
mk-soft variant:

Code: Select all

;
; https://www.purebasic.fr/english/viewtopic.php?p=594218
; 

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

Structure SpriteList_Structure
  Sprite.i
  Delay.i
EndStructure

Structure AnimatedGIFInfo_Structure
  List SpriteList.SpriteList_Structure()
EndStructure

Structure AnimatedGIFSprite_Structure
  Window.i
  Map GIFInfoMap.AnimatedGIFInfo_Structure()
EndStructure


Global AnimatedGIFSprite.AnimatedGIFSprite_Structure


Procedure AnimateGIFSpritesTimerEvent()
  
  Protected *AnimatedGIFSprite.AnimatedGIFInfo_Structure, Sprite.i
  
  
  Sprite = EventTimer()
  *AnimatedGIFSprite = FindMapElement(AnimatedGIFSprite\GIFInfoMap(), Str(Sprite))
  If *AnimatedGIFSprite
    RemoveWindowTimer(AnimatedGIFSprite\Window, Sprite)
    
    If Not NextElement(*AnimatedGIFSprite\SpriteList())
      FirstElement(*AnimatedGIFSprite\SpriteList())
    EndIf
    
    ;Debug "AddWindowTimer: " + Str(Sprite) + " " + Str(*AnimatedGIFSprite\SpriteList()\Delay) + " " + Str(ListIndex(*AnimatedGIFSprite\SpriteList()))
    AddWindowTimer(AnimatedGIFSprite\Window, Sprite, *AnimatedGIFSprite\SpriteList()\Delay)
    
  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, Frame.i, ActualFrame
  
  
  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))
      
      AddElement(*AnimatedGIFSprite\SpriteList())
      SetImageFrame(Image, 0)
      *AnimatedGIFSprite\SpriteList()\Delay = GetImageFrameDelay(Image)
      *AnimatedGIFSprite\SpriteList()\Sprite = Sprite
      If StartDrawing(SpriteOutput(*AnimatedGIFSprite\SpriteList()\Sprite))
        DrawImage(ImageID(Image), 0, 0)
        StopDrawing()
      EndIf
      
      For Frame = 1 To ImageFrameCount(Image) - 1
        AddElement(*AnimatedGIFSprite\SpriteList())
        SetImageFrame(Image, Frame)
        *AnimatedGIFSprite\SpriteList()\Delay = GetImageFrameDelay(Image)
        *AnimatedGIFSprite\SpriteList()\Sprite = CreateSprite(#PB_Any, ImageWidth(Image), ImageHeight(Image), Mode)
        If StartDrawing(SpriteOutput(*AnimatedGIFSprite\SpriteList()\Sprite))
          DrawImage(ImageID(Image), 0, 0)
          StopDrawing()
        EndIf
      Next Frame
      
      If StartAnimationPosition > 0 And StartAnimationPosition <= 100
        ActualFrame = Frame / (100 / StartAnimationPosition) - 1
        If ActualFrame < 0
          ActualFrame = 0
        EndIf
      EndIf
      SelectElement(*AnimatedGIFSprite\SpriteList(), ActualFrame)
      AddWindowTimer(AnimatedGIFSprite\Window, Sprite, *AnimatedGIFSprite\SpriteList()\Delay)
    EndIf
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


Procedure DisplayAnimatedSprite(Sprite.i, x.i, y.i)
  
  Protected *AnimatedGIFSprite.AnimatedGIFInfo_Structure
  
  
  *AnimatedGIFSprite = FindMapElement(AnimatedGIFSprite\GIFInfoMap(), Str(Sprite))
  If *AnimatedGIFSprite
    DisplaySprite(*AnimatedGIFSprite\SpriteList()\Sprite, x, y)
  EndIf
  
EndProcedure


Procedure DisplayAnimatedTransparentSprite(Sprite.i, x.i, y.i, Intensity.i=255, Color.i=#PB_Ignore)
  
  Protected *AnimatedGIFSprite.AnimatedGIFInfo_Structure
  
  
  *AnimatedGIFSprite = FindMapElement(AnimatedGIFSprite\GIFInfoMap(), Str(Sprite))
  If *AnimatedGIFSprite
    If Color.i = #PB_Ignore
      DisplayTransparentSprite(*AnimatedGIFSprite\SpriteList()\Sprite, x, y, Intensity)
    Else
      DisplayTransparentSprite(*AnimatedGIFSprite\SpriteList()\Sprite, x, y, Intensity, Color)
    EndIf
  EndIf
  
EndProcedure


;-Demo
CompilerIf #PB_Compiler_IsMainFile
  
  Define.i Width, Height, Depth, ScreenReady, AnySprite
  Define GIFFilename$
  
  UseGIFImageDecoder()
  
  If InitSprite() = 0 Or InitKeyboard() = 0
    MessageRequester("Error", "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("Error", "Screen modes can't be detected")
    End
  EndIf
  
  If MessageRequester("Choose screen mode", "Use OpenScreen()?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
    If OpenScreen(Width, Height, Depth, "")
      ScreenReady = #True
    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 = #True
      EndIf
    EndIf
  EndIf
  
  If ScreenReady
    GIFFilename$ = GetUserDirectory(#PB_Directory_Downloads) + "animated-dog-image-0175.gif"
    
    ReceiveHTTPFile("https://www.animatedimages.org/data/media/202/animated-dog-image-0175.gif", GIFFilename$)
    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))
      
      DisplayAnimatedSprite(1, 100, 100)
      DisplayAnimatedTransparentSprite(AnySprite, 300, 300)
      
      ExamineKeyboard()
    Until KeyboardPushed(#PB_Key_Escape)
    
    If FileSize(GIFFilename$) > 0
      DeleteFile(GIFFilename$)
    EndIf
  EndIf
  
CompilerEndIf

Re: AnimatedGIFSprite

Posted: Mon Jan 23, 2023 1:27 am
by Kamarro
mk-soft wrote: Sun Jan 22, 2023 3:50 pm Isn't it better to create an array of sprites instead of redrawing the sprite each time ?

Just an idea with DisplayGif(*Object, ...) or DisplayTransparentGif(*Object, ...)
My God, I'm getting really older, distracted, or very tired. I didn't realise that you were talking about infratec's source and not my other question.
Sorry for my misunderstanding. Now I can see why I didn't understood your suggestion.

And yes, of course you're right. An array is a better option and probably a bit faster and portable if we intend to export the results.

Sorry again for my mistake.
Cheers!

Re: AnimatedGIFSprite

Posted: Tue Jan 24, 2023 12:30 pm
by infratec
Changed the code in first post:

added a FinishAnimatedGIFSprites() procedure.

Also added a version from mk-soft which don't use a hidden window and events.