Chargement des sprites dans un Thread

Sujets variés concernant le développement en PureBasic
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Chargement des sprites dans un Thread

Message par Thyphoon »

Bonjour,

Je cherche a charger des Sprites, sans bloquer l'interface d'une application...Et que les images apparaissent au fur et a mesure du chargement.
Voici comment je procède.
A votre avis est-ce la bonne façon de faire ? ou pas ?
comment être sur que lorsque je dessine un sprite celui si n'est pas entrain d'être charger ou effacer ?
Un mutex ça utilise une variable ? peuxt'on faire un tableau de mutex ?

il vous faudra changer la variable path.s et lui donner vers un chemin comportant des images jpg !

Code : Tout sélectionner

UsePNGImageDecoder()
UseJPEGImageDecoder()

path.s="c:\Imagestest"

If InitSprite()=0
  MessageRequester("Error", "Can't Initialize DirectX Sprite", 0)
  End
EndIf
If InitKeyboard()=0
  MessageRequester("Error", "Can't Initialize DirectX input", 0)
  End
EndIf
If InitSprite3D()=0
  MessageRequester("Error", "Can't Initialize DirectX 3D", 0)
EndIf

Structure Prefs
  ScreenWidth.l
  ScreenHeight.l
  FullScreen.b
EndStructure

Define Prefs.Prefs

Prefs\ScreenWidth.l=800
Prefs\ScreenHeight.l=600
Prefs\FullScreen.b=#False

path.s="J:\Google Drive\Developpement\Purebasic Projects\FrontMedia\Video\Series\Touch"


Structure TLI
  file.s
  sprite.i
EndStructure

NewList threadList.TLI()
threadListMutex=CreateMutex()

Procedure ThreadLoadImage(*truc)
  Shared threadList.TLI(),threadListMutex
  Protected info.TLI
  Repeat
  Repeat
  Delay(500)  
  Until ListSize(threadList())>0
  
  LockMutex(threadListMutex)
  FirstElement(threadList())
  info\file=threadList()\file
  info\sprite=threadList()\sprite
  UnlockMutex(threadListMutex)
  If IsSprite3D(info\sprite)
    FreeSprite3D(info\sprite)
  EndIf
  If IsSprite(info\sprite)
    FreeSprite(info\sprite)
  EndIf
  Debug FileSize(info\file)
  If LoadSprite(info\sprite,info\file,#PB_Sprite_Texture)
    CreateSprite3D(info\sprite,info\sprite)
  EndIf
  LockMutex(threadListMutex)
  FirstElement(threadList())
  DeleteElement(threadList())
  UnlockMutex(threadListMutex)
  ForEver
EndProcedure

Procedure addImage(file.s,sprite.i)
  Shared threadList.TLI(),threadListMutex
  LockMutex(threadListMutex)
  AddElement(threadList())
  threadList()\file=file
  threadList()\sprite=sprite
  UnlockMutex(threadListMutex)
EndProcedure

If ExamineDirectory(0, path, "*.*")  
  While NextDirectoryEntry(0)
    If DirectoryEntryType(0) = #PB_DirectoryEntry_File
      If GetExtensionPart(DirectoryEntryName(0))="jpg"
        NbSprite+1
        addImage(path+"\"+DirectoryEntryName(0),NbSprite)
        Debug DirectoryEntryName(0)
      EndIf
    EndIf
  Wend
  FinishDirectory(0)
EndIf

CreateThread(@ThreadLoadImage(),0)


Select Prefs\FullScreen
  Case #True ; Ouverture en plein ecran
    OpenScreen(Prefs\ScreenWidth, Prefs\ScreenHeight,32,"test")
  Case #False ; Ouverture dans une Fenêtre
    #W_Screen=0
    OpenWindow(#W_Screen, 0, 0, Prefs\ScreenWidth, Prefs\ScreenHeight, "test", #PB_Window_ScreenCentered)
    OpenWindowedScreen(WindowID(#W_Screen), 0, 0, Prefs\ScreenWidth, Prefs\ScreenHeight, 1, 0, 0)
EndSelect

Repeat
  
  ;Si nous somme dans une fenêtre il faut traiter tout les elements    
  If Prefs\FullScreen=#False
    Repeat
      Event = WindowEvent()
      Select Event 
        Case #PB_Event_CloseWindow
          End 
      EndSelect
    Until Event = 0  
  EndIf
  
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Right)
    A=A+1
  EndIf
  
  If KeyboardPushed(#PB_Key_Left)
     A=A-1
  EndIf
  
  If KeyboardPushed(#PB_Key_Space)
  EndIf
  
  
  If KeyboardPushed(#PB_Key_Escape)
    End
  EndIf
  
  If KeyboardPushed(#PB_Key_Up) 
  EndIf
  
  If KeyboardPushed(#PB_Key_Down) 
  EndIf
  
  
  FlipBuffers() 
  ClearScreen(0)
  Start3D()
  For z=1 To NbSprite
    If IsSprite3D(z)
      DisplaySprite3D(z,z*50,z*50)
    EndIf
    
  Next
  Stop3D()
  StartDrawing(ScreenOutput())
  DrawText(400,400,Str(A))
  StopDrawing()
  
  Delay(1)
ForEver
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: Chargement des sprites dans un Thread

Message par Thyphoon »

voilà un code plus aboutis... mais j'ai des plantages...
il vous faut 2 repertoires avec 4 ou 5 images jpg dedans et paramétrer les variables pathA et pathB
au depart il charge les images de pathA et a tout moment vous pouvez charger les images de pathB
et avec les flêches vous pouvez faire varier une variable... c'est juste pour verifier que le chargement des images de plante pas l'interface

si quelqu'un a une idée de pourquoi ça plante ... je suis intéressé ...

Code : Tout sélectionner

UsePNGImageDecoder()
UseJPEGImageDecoder()

If InitSprite()=0
  MessageRequester("Error", "Can't Initialize DirectX Sprite", 0)
  End
EndIf
If InitKeyboard()=0
  MessageRequester("Error", "Can't Initialize DirectX input", 0)
  End
EndIf
If InitSprite3D()=0
  MessageRequester("Error", "Can't Initialize DirectX 3D", 0)
EndIf

NbSprite.i=0

Structure Prefs
  ScreenWidth.l
  ScreenHeight.l
  FullScreen.b
EndStructure

Define Prefs.Prefs

Prefs\ScreenWidth.l=800
Prefs\ScreenHeight.l=600
Prefs\FullScreen.b=#False

pathA.s="J:\ImageA"
pathB.s="J:\ImageB"

NewMap Mutex.i()

Mutex("ThreadList")=CreateMutex() ;Pour bloquer lorsqu'on accède a la liste d'image a charger par le Thread
Mutex("ThreadListAll")=CreateMutex();Pour bloquer lorsqu'on traite un element de la liste a charger par le Thread

;pour simplifier le test je créer des Mutexs pour tout les sprites qui risque de charger des sprites
For z=0 To 100
  Mutex(Str(z))=CreateMutex()
Next

;Creation de liste d'image a charger
Structure TLI
  file.s ; le chemin vers l'image a charger
  sprite.i ; le n° du sprite a utiliser
EndStructure

NewList threadList.TLI()

Procedure ThreadLoadImage(*truc)
  Shared Mutex()
  Shared threadList.TLI()
  Protected info.TLI
  Repeat
    ;On attend d'avoir des choses a traiter sinon on attend
    Repeat
      Delay(500)  
    Until ListSize(threadList())>0
    If TryLockMutex(Mutex("ThreadListAll")) ;Si la liste est encour d'effacement alors on fait rien
      LockMutex(Mutex("ThreadList")); Pour eviter qu'on touche a la liste pendant qu'on prend les données
      FirstElement(threadList())
      info\file=threadList()\file
      info\sprite=threadList()\sprite
      UnlockMutex(Mutex("ThreadList"))
      LockMutex(Mutex(Str(sprite))) ; Pour eviter qu'on affiche le sprite pendant qu'on travaille dessus
      If IsSprite3D(info\sprite)
        FreeSprite3D(info\sprite)
      EndIf
      If IsSprite(info\sprite)
        FreeSprite(info\sprite)
      EndIf
      Debug FileSize(info\file)
      If LoadSprite(info\sprite,info\file,#PB_Sprite_Texture)
        CreateSprite3D(info\sprite,info\sprite)
      EndIf
      UnlockMutex(Mutex(Str(sprite)))
      LockMutex(Mutex("ThreadList")); Pour eviter qu'on touche a la liste pendant qu'on efface de la liste l'image traité
      FirstElement(threadList())
      DeleteElement(threadList())
      UnlockMutex(Mutex("ThreadList"))
      UnlockMutex(Mutex("ThreadListAll"))
    EndIf
  ForEver
EndProcedure

Procedure DisplaySprite3DThreaded(sprite.i,x.i,y.i,a.i=255)
  Shared Mutex()
  If TryLockMutex(Mutex(Str(sprite)))
    If IsSprite3D(sprite)
      DisplaySprite3D(sprite,x,y,a)
    EndIf
    UnlockMutex(Mutex(Str(sprite)))
  Else
    Debug"Sprite utilisé"
  EndIf
EndProcedure

Procedure addImage(file.s,sprite.i)
  Shared threadList.TLI()
  Shared Mutex()
  LockMutex(Mutex("ThreadList"))
  AddElement(threadList())
  threadList()\file=file
  threadList()\sprite=sprite
  UnlockMutex(Mutex("ThreadList"))
EndProcedure

Procedure Newpath(path.s)
  Shared NbSprite
  If ExamineDirectory(0, path, "*.*")  
    While NextDirectoryEntry(0)
      If DirectoryEntryType(0) = #PB_DirectoryEntry_File
        If GetExtensionPart(DirectoryEntryName(0))="jpg"
          NbSprite+1
          addImage(path+"\"+DirectoryEntryName(0),NbSprite)
          Debug DirectoryEntryName(0)
        EndIf
      EndIf
    Wend
    FinishDirectory(0)
  EndIf
EndProcedure

Newpath(pathA)
CreateThread(@ThreadLoadImage(),0)


Select Prefs\FullScreen
  Case #True ; Ouverture en plein ecran
    OpenScreen(Prefs\ScreenWidth, Prefs\ScreenHeight,32,"test")
  Case #False ; Ouverture dans une Fenêtre
    #W_Screen=0
    OpenWindow(#W_Screen, 0, 0, Prefs\ScreenWidth, Prefs\ScreenHeight, "test", #PB_Window_ScreenCentered)
    OpenWindowedScreen(WindowID(#W_Screen), 0, 0, Prefs\ScreenWidth, Prefs\ScreenHeight, 1, 0, 0)
EndSelect

Repeat
  
  ;Si nous somme dans une fenêtre il faut traiter tout les elements    
  If Prefs\FullScreen=#False
    Repeat
      Event = WindowEvent()
      Select Event 
        Case #PB_Event_CloseWindow
          End 
      EndSelect
    Until Event = 0  
  EndIf
  
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Right)
    A=A+1
  EndIf
  
  If KeyboardPushed(#PB_Key_Left)
    A=A-1
  EndIf
  
  If KeyboardPushed(#PB_Key_Space)
    NbSprite=0
    LockMutex(Mutex("ThreadListAll"))
    ClearList(threadList())
    UnlockMutex(Mutex("ThreadListAll"))
    Newpath(pathB)
    
  EndIf
  
  
  If KeyboardPushed(#PB_Key_Escape)
    End
  EndIf

  FlipBuffers() 
  ClearScreen(0)
  Start3D()
  For z=1 To 100
   DisplaySprite3DThreaded(z,z*50,z*50)
  Next
  Stop3D()
  StartDrawing(ScreenOutput())
  DrawText(400,400,Str(A))
  StopDrawing()
  
  Delay(1)
ForEver
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Chargement des sprites dans un Thread

Message par G-Rom »

pas de plantage ici, tu as activé la gestion des threads dans le compilateur ?
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: Chargement des sprites dans un Thread

Message par Thyphoon »

G-Rom a écrit :pas de plantage ici, tu as activé la gestion des threads dans le compilateur ?
Merci Effectivement j'avais pas pensé a ça ... :oP quelques mois sans utilisé PB et on perd certain réflexe.
c'est déjà mieux ... mais j'ai toujours un ralentissement puis blocage si j'appuie plusieurs fois sur la barre espace (rechargement) :?
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Chargement des sprites dans un Thread

Message par G-Rom »

Met un flag sur ta barre d'espace déjà. ;)

Code : Tout sélectionner

If KeyboardPushed(#PB_Key_Space)<>#Null And space_key_flag = 0
  space_key_flag = 1 ; on désactive la barre d'espace.
  ;
  ; programme à executé
  ;
EndIf 

If KeyboardPushed(#PB_Key_Space)=#Null And space_key_flag = 1
  space_key_flag = 0 ; la barre d'espace est relaché , on la
                     ; réactive.
EndIf 
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: Chargement des sprites dans un Thread

Message par Thyphoon »

merci, c'est ce que je viens de faire en un peu différent car je désactive la touche 500ms
et si j'appuie 3 fois sur la bar espace ça finit par se figer... :-/
Mon but est au final de naviguer dans des répertoires contenant des images..et d'afficher les images sans que ça gène la navigation...
je n'arrive pas trop a voir quoi bloc car quand je met en pause le compilateur c'est toujours dans la procedure Threader.

Code : Tout sélectionner

UsePNGImageDecoder()
UseJPEGImageDecoder()

If InitSprite()=0
  MessageRequester("Error", "Can't Initialize DirectX Sprite", 0)
  End
EndIf
If InitKeyboard()=0
  MessageRequester("Error", "Can't Initialize DirectX input", 0)
  End
EndIf
If InitSprite3D()=0
  MessageRequester("Error", "Can't Initialize DirectX 3D", 0)
EndIf

NbSprite.i=0

Structure Prefs
  ScreenWidth.l
  ScreenHeight.l
  FullScreen.b
EndStructure

Define Prefs.Prefs

Prefs\ScreenWidth.l=800
Prefs\ScreenHeight.l=600
Prefs\FullScreen.b=#False

pathA.s="J:\ImageA"
pathB.s="J:\ImageB"

NewMap Mutex.i()

Mutex("ThreadList")=CreateMutex() ;Pour bloquer lorsqu'on accède a la liste d'image a charger par le Thread
Mutex("ThreadListAll")=CreateMutex();Pour bloquer lorsqu'on traite un element de la liste a charger par le Thread

;pour simplifier le test je créer des Mutexs pour tout les sprites qui risque de charger des sprites
For z=0 To 100
  Mutex(Str(z))=CreateMutex()
Next

;Creation de liste d'image a charger
Structure TLI
  file.s ; le chemin vers l'image a charger
  sprite.i ; le n° du sprite a utiliser
EndStructure

NewList threadList.TLI()

Procedure ThreadLoadImage(*truc)
  Shared Mutex()
  Shared threadList.TLI()
  Protected info.TLI
  Repeat
    ;On attend d'avoir des choses a traiter sinon on attend
    Repeat
      Delay(500)  
    Until ListSize(threadList())>0
    If TryLockMutex(Mutex("ThreadListAll")) ;Si la liste est encour d'effacement alors on fait rien
      LockMutex(Mutex("ThreadList")); Pour eviter qu'on touche a la liste pendant qu'on prend les données
      FirstElement(threadList())
      info\file=threadList()\file
      info\sprite=threadList()\sprite
      UnlockMutex(Mutex("ThreadList"))
      LockMutex(Mutex(Str(sprite))) ; Pour eviter qu'on affiche le sprite pendant qu'on travaille dessus
      If IsSprite3D(info\sprite)
        FreeSprite3D(info\sprite)
      EndIf
      If IsSprite(info\sprite)
        FreeSprite(info\sprite)
      EndIf
      Debug FileSize(info\file)
      If LoadSprite(info\sprite,info\file,#PB_Sprite_Texture)
        CreateSprite3D(info\sprite,info\sprite)
      EndIf
      UnlockMutex(Mutex(Str(sprite)))
      LockMutex(Mutex("ThreadList")); Pour eviter qu'on touche a la liste pendant qu'on efface de la liste l'image traité
      FirstElement(threadList())
      DeleteElement(threadList())
      UnlockMutex(Mutex("ThreadList"))
      UnlockMutex(Mutex("ThreadListAll"))
    EndIf
  ForEver
EndProcedure

Procedure DisplaySprite3DThreaded(sprite.i,x.i,y.i,a.i=255)
  Shared Mutex()
  If TryLockMutex(Mutex(Str(sprite)))
    If IsSprite3D(sprite)
      DisplaySprite3D(sprite,x,y,a)
    EndIf
    UnlockMutex(Mutex(Str(sprite)))
  Else
    Debug"Sprite utilisé"
  EndIf
EndProcedure

Procedure addImage(file.s,sprite.i)
  Shared threadList.TLI()
  Shared Mutex()
  LockMutex(Mutex("ThreadList"))
  AddElement(threadList())
  threadList()\file=file
  threadList()\sprite=sprite
  UnlockMutex(Mutex("ThreadList"))
EndProcedure

Procedure Newpath(path.s)
  Shared NbSprite
  If ExamineDirectory(0, path, "*.*")  
    While NextDirectoryEntry(0)
      If DirectoryEntryType(0) = #PB_DirectoryEntry_File
        If GetExtensionPart(DirectoryEntryName(0))="jpg"
          NbSprite+1
          addImage(path+"\"+DirectoryEntryName(0),NbSprite)
          Debug DirectoryEntryName(0)
        EndIf
      EndIf
    Wend
    FinishDirectory(0)
  EndIf
EndProcedure

Newpath(pathA)
CreateThread(@ThreadLoadImage(),0)


Select Prefs\FullScreen
  Case #True ; Ouverture en plein ecran
    OpenScreen(Prefs\ScreenWidth, Prefs\ScreenHeight,32,"test")
  Case #False ; Ouverture dans une Fenêtre
    #W_Screen=0
    OpenWindow(#W_Screen, 0, 0, Prefs\ScreenWidth, Prefs\ScreenHeight, "test", #PB_Window_ScreenCentered)
    OpenWindowedScreen(WindowID(#W_Screen), 0, 0, Prefs\ScreenWidth, Prefs\ScreenHeight, 1, 0, 0)
EndSelect

Repeat
  
  ;Si nous somme dans une fenêtre il faut traiter tout les elements    
  If Prefs\FullScreen=#False
    Repeat
      Event = WindowEvent()
      Select Event 
        Case #PB_Event_CloseWindow
          End 
      EndSelect
    Until Event = 0  
  EndIf
  
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Right)
    A=A+1
  EndIf
  
  If KeyboardPushed(#PB_Key_Left)
    A=A-1
  EndIf
  
  If KeyboardPushed(#PB_Key_Space) And space_key_flag = 0
    NbSprite=0
    LockMutex(Mutex("ThreadListAll"))
    ClearList(threadList())
    UnlockMutex(Mutex("ThreadListAll"))
    Newpath(pathB)
    space_key_flag = ElapsedMilliseconds()+500
  EndIf
  If space_key_flag<>0 And ElapsedMilliseconds()>space_key_flag
     space_key_flag = 0
  EndIf
  
  If KeyboardPushed(#PB_Key_Escape)
    End
  EndIf
  
  
  
  FlipBuffers() 
  ClearScreen(0)
  Start3D()
  For z=1 To 100
   DisplaySprite3DThreaded(z,z*50,z*50)
  Next
  Stop3D()
  StartDrawing(ScreenOutput())
  DrawText(400,400,Str(A))
  StopDrawing()
  
  Delay(1)
ForEver
Fred
Site Admin
Messages : 2808
Inscription : mer. 21/janv./2004 11:03

Re: Chargement des sprites dans un Thread

Message par Fred »

Regarde l'exemple sur les semaphore, ca evite de boucler pour attendre qu'un element soit dans la liste:

http://www.purebasic.com/documentation/ ... phore.html
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: Chargement des sprites dans un Thread

Message par Thyphoon »

Fred a écrit :Regarde l'exemple sur les semaphore, ca evite de boucler pour attendre qu'un element soit dans la liste:

http://www.purebasic.com/documentation/ ... phore.html
j'avais regardé ... mais j'avais pas tres bien compris, je vais m'attarder dessus
Merci beaucoup :mrgreen:
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Chargement des sprites dans un Thread

Message par Golfy »

Comme souvent, le problème de Purebasic, ce n'est pas son manque d'instructions mais le notre (manque d'instruction sur son utilisation) :roll:

Heureusement que les forums apportent de nombreux exemples complémentaires 8)
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
Répondre