Page 1 sur 1

Faire onduler une image

Publié : mer. 25/nov./2009 18:29
par Octavius
J'ai chercher sur le forum et je n'ai pas trouver de code permettant de faire de jolie ondulations sur un drapeau par exemple, alors je voudrais vous proposer cette petite application que j'ai faite.

Code : Tout sélectionner

;-Decoders & initialisations
EnableExplicit
UseJPEG2000ImageDecoder()
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseTGAImageDecoder()
UseTIFFImageDecoder()
InitSprite()

; Structure SPRITE
;   ID.i
;   *Next.SPRITE
; EndStructure
Structure FLAG
  Speed.i
  Amplitude.i
  Period.i
  StepX.i
  NumOfStep.i
  Pole.b
;   *Sprite.SPRITE
EndStructure

Declare.b DisplayFlag(*Flag.FLAG)
Define Flag.FLAG,Thread.i,N.i

;-Window
OpenWindow(0,0,0,532,622,"Oscillo",#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
OpenWindowedScreen(WindowID(0),10,10,512,512,0,0,0)

TextGadget(0,10,535,60,14,"Vitesse :")
SpinGadget(1,70,532,40,20,1,999,#PB_Spin_Numeric)

TextGadget(2,10,565,60,14,"Amplitude :")
SpinGadget(3,70,562,40,20,1,999,#PB_Spin_Numeric)

TextGadget(4,10,595,60,14,"Période :")
SpinGadget(5,70,592,40,20,2,999,#PB_Spin_Numeric)

TextGadget(6,135,535,60,14,"Morcelage :")
SpinGadget(7,195,532,40,20,1,999,#PB_Spin_Numeric)

CheckBoxGadget(8,135,562,100,20,"Hampe fixe")
TextGadget(9,135,595,60,14,"Drapeau :")
ButtonGadget(10,195,592,30,20,"...")

;-Default flag
CreateImage(0,300,200,32)
If StartDrawing(ImageOutput(0))
  For N=0 To 199
    Line(0,N,300,0,RGB(32-N/8,64-N/4,255-N))
  Next N
  For N=1 To 19
    Line(0,10*N,300,0,$C0C000)
    Line(15*N,0,0,200,$C0C000)
  Next N
  DrawingMode(#PB_2DDrawing_Outlined)
  Box(0,0,300,200,$FFFFFF)
StopDrawing() : EndIf
CopyImage(0,1)
If ImageHeight(1)>ImageWidth(1)/2
  ResizeImage(1,ImageWidth(1)*80/ImageHeight(1),80)
Else
  ResizeImage(1,160,ImageHeight(1)*160/ImageWidth(1))
EndIf
Flag\Speed=150
Flag\Amplitude=8
Flag\Period=400
Flag\StepX=2
Flag\NumOfStep=ImageWidth(0)/Flag\StepX
Flag\Pole=1
SetGadgetState(1,Flag\Speed)
SetGadgetState(3,Flag\Amplitude)
SetGadgetState(5,Flag\Period)
SetGadgetState(7,Flag\StepX)
SetGadgetState(8,Flag\Pole)

ImageGadget(12,260,532,1,1,ImageID(1))

CreateSprite(0,ImageWidth(0),ImageHeight(0))
If StartDrawing(SpriteOutput(0)) : DrawImage(ImageID(0),0,0) : StopDrawing() : EndIf

Thread=CreateThread(@DisplayFlag(),@Flag)

;-Main loop

Repeat
  
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0,#WM_MOUSEMOVE
        Case 1 : Flag\Speed=GetGadgetState(1)
        Case 3 : Flag\Amplitude=GetGadgetState(3)
        Case 5 : Flag\Period=GetGadgetState(5)
        Case 7 : Flag\StepX=GetGadgetState(7) : Flag\NumOfStep=ImageWidth(0)/Flag\StepX
        Case 8 : Flag\Pole=GetGadgetState(8)
        Case 10
          If LoadImage(1,OpenFileRequester("Choisir une image",GetCurrentDirectory(),"Images|*.bmp;*.jpg;*.jpeg;*.png;*.tga;*.tiff",1))
            PauseThread(Thread)
            CopyImage(1,0)
            If ImageHeight(1)>ImageWidth(1)/2
              ResizeImage(1,ImageWidth(1)*80/ImageHeight(1),80)
            Else
              ResizeImage(1,160,ImageHeight(1)*160/ImageWidth(1))
            EndIf
            CreateSprite(0,ImageWidth(0),ImageHeight(0))
            SetGadgetState(12,ImageID(1))
            If StartDrawing(SpriteOutput(0)) : DrawImage(ImageID(0),0,0) : StopDrawing() : EndIf
            Flag\NumOfStep=ImageWidth(0)/Flag\StepX
            ResumeThread(Thread)
          EndIf
      EndSelect
    Case #PB_Event_CloseWindow : End
  EndSelect
  
ForEver

Procedure.b DisplayFlag(*Flag.FLAG)
Protected Time.i,Count.f,N.i,Y.f,DiffY.f,Point.POINT

Time=ElapsedMilliseconds()

;Screen loop
Repeat
  
  ClearScreen(0)
  Delay(10)
  
  Point\X=(512-ImageWidth(0))/2
  Point\Y=(512-ImageHeight(0))/2
  
  For N=0 To *Flag\NumOfStep
    
    Y=Sin((*Flag\Speed*Count+128*(N**Flag\StepX)/*Flag\Period)/20)
    
    ;Fixed flagpole?
    If N=0
      If *Flag\Pole
        DiffY=Y
      EndIf
    EndIf
    Y-DiffY
    
    ClipSprite(0,N**Flag\StepX,0,*Flag\StepX,ImageHeight(0))
    
    DisplaySprite(0,Point\X+N**Flag\StepX,Point\Y+*Flag\Amplitude*Y)
    
  Next N
  
  Count=(ElapsedMilliseconds()-Time)/1000
  FlipBuffers()
  
ForEver

EndProcedure
Parmi les améliorations possibles, je pense que ce serait vraiment pas mal de pouvoir sauvegarder le résultat en gif par exemple, mais je ne sais pas encore faire malheureusement.

Je pensais aussi rajouter un effet d'ombre et de lumière sur les vagues.

Re: Faire onduler une image

Publié : mer. 25/nov./2009 20:46
par kernadec
bonjour Octavius
excellent. merci

Re: Faire onduler une image

Publié : mer. 25/nov./2009 22:20
par Backup
............

Re: Faire onduler une image

Publié : mer. 25/nov./2009 22:39
par Octavius
Intéressant comme code effectivement ;)

Par ailleurs j'ai remarqué un problème avec mon propre code : de temps en temps, lorsque je choisis une nouvelle image avec le requester, le programme se bloque et ne réponds plus. Ca arrive 1 fois sur 10 environ (essayez plusieurs fois de recharger la même image, ça finira par vous arriver). Je pense que ça doit être un problème avec la gestion du thread, mais ça ne change rien si je compile avec "gestion des Threads". Vous auriez une idée d'où vient le problème ? Le débogueur ne réponds plus non plus donc je n'ai pas d'indices...

Re: Faire onduler une image

Publié : jeu. 26/nov./2009 18:20
par Le Soldat Inconnu
quand tu charges l'images, il faut bloquer le thread car il ne doit plus travailler avec les images, il faut utiliser les mutex et pas PauseThread car tu dois arrêter le thread quand il ne travaille plus avec les images

Sinon, il ne faut pas de thread

Code : Tout sélectionner

    ;-Decoders & initialisations
    EnableExplicit
    UseJPEG2000ImageDecoder()
    UseJPEGImageDecoder()
    UsePNGImageDecoder()
    UseTGAImageDecoder()
    UseTIFFImageDecoder()
    InitSprite()
		
    ; Structure SPRITE
    ;   ID.i
    ;   *Next.SPRITE
    ; EndStructure
    Structure FLAG
      Speed.i
      Amplitude.i
      Period.i
      StepX.i
      NumOfStep.i
      Pole.b
			;   *Sprite.SPRITE
		EndStructure
		
    Define Flag.FLAG,Thread.i,n.i, event.i
		Define time.i,Count.f,Y.f,DiffY.f,Point.POINT
		
    ;-Window
    OpenWindow(0,0,0,532,622,"Oscillo",#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
    OpenWindowedScreen(WindowID(0),10,10,512,512,0,0,0)
		
    TextGadget(0,10,535,60,14,"Vitesse :")
    SpinGadget(1,70,532,40,20,1,999,#PB_Spin_Numeric)
		
    TextGadget(2,10,565,60,14,"Amplitude :")
    SpinGadget(3,70,562,40,20,1,999,#PB_Spin_Numeric)
		
    TextGadget(4,10,595,60,14,"Période :")
    SpinGadget(5,70,592,40,20,2,999,#PB_Spin_Numeric)
		
    TextGadget(6,135,535,60,14,"Morcelage :")
    SpinGadget(7,195,532,40,20,1,999,#PB_Spin_Numeric)
		
    CheckBoxGadget(8,135,562,100,20,"Hampe fixe")
    TextGadget(9,135,595,60,14,"Drapeau :")
    ButtonGadget(10,195,592,30,20,"...")
		
    ;-Default flag
    CreateImage(0,300,200,32)
    If StartDrawing(ImageOutput(0))
				For n=0 To 199
					Line(0,n,300,0,RGB(32-n/8,64-n/4,255-n))
				Next n
				For n=1 To 19
					Line(0,10*n,300,0,$C0C000)
					Line(15*n,0,0,200,$C0C000)
				Next n
				DrawingMode(#PB_2DDrawing_Outlined)
				Box(0,0,300,200,$FFFFFF)
		StopDrawing() : EndIf
    CopyImage(0,1)
    If ImageHeight(1)>ImageWidth(1)/2
      ResizeImage(1,ImageWidth(1)*80/ImageHeight(1),80)
		Else
      ResizeImage(1,160,ImageHeight(1)*160/ImageWidth(1))
		EndIf
    Flag\Speed=150
    Flag\Amplitude=8
    Flag\Period=400
    Flag\StepX=2
    Flag\NumOfStep=ImageWidth(0)/Flag\StepX
    Flag\Pole=1
    SetGadgetState(1,Flag\Speed)
    SetGadgetState(3,Flag\Amplitude)
    SetGadgetState(5,Flag\Period)
    SetGadgetState(7,Flag\StepX)
    SetGadgetState(8,Flag\Pole)
		
    ImageGadget(12,260,532,1,1,ImageID(1))
		
    CreateSprite(0,ImageWidth(0),ImageHeight(0))
    If StartDrawing(SpriteOutput(0)) : DrawImage(ImageID(0),0,0) : StopDrawing() : EndIf
		
    ;-Main loop
		time=ElapsedMilliseconds()
		
    Repeat
			Repeat
				event = WindowEvent()
				Select event
					Case #PB_Event_Gadget
						Select EventGadget()
							Case 0,#WM_MOUSEMOVE
							Case 1 : Flag\Speed=GetGadgetState(1)
							Case 3 : Flag\Amplitude=GetGadgetState(3)
							Case 5 : Flag\Period=GetGadgetState(5)
							Case 7 : Flag\StepX=GetGadgetState(7) : Flag\NumOfStep=ImageWidth(0)/Flag\StepX
							Case 8 : Flag\Pole=GetGadgetState(8)
							Case 10
								If LoadImage(1,OpenFileRequester("Choisir une image",GetCurrentDirectory(),"Images|*.bmp;*.jpg;*.jpeg;*.png;*.tga;*.tiff",1))
									CopyImage(1,0)
									If ImageHeight(1)>ImageWidth(1)/2
										ResizeImage(1,ImageWidth(1)*80/ImageHeight(1),80)
									Else
										ResizeImage(1,160,ImageHeight(1)*160/ImageWidth(1))
									EndIf
									CreateSprite(0,ImageWidth(0),ImageHeight(0))
									SetGadgetState(12,ImageID(1))
									If StartDrawing(SpriteOutput(0)) : DrawImage(ImageID(0),0,0) : StopDrawing() : EndIf
									Flag\NumOfStep=ImageWidth(0)/Flag\StepX
								EndIf
						EndSelect
					Case #PB_Event_CloseWindow : End
				EndSelect
			Until event = 0
			
			ClearScreen(0)
			
			Point\X=(512-ImageWidth(0))/2
			Point\Y=(512-ImageHeight(0))/2
			
			For n=0 To Flag\NumOfStep
				
				Y=Sin((Flag\Speed*Count+128*(n*Flag\StepX)/Flag\Period)/20)
				
				;Fixed flagpole?
				If n=0
					If Flag\Pole
						DiffY=Y
					EndIf
				EndIf
				Y-DiffY
				
				ClipSprite(0,n*Flag\StepX,0,Flag\StepX,ImageHeight(0))
				
				DisplaySprite(0,Point\X+n*Flag\StepX,Point\Y+Flag\Amplitude*Y)
				
			Next n
			
			Count=(ElapsedMilliseconds()-time)/1000
			FlipBuffers()
			
		ForEver
		
		

Re: Faire onduler une image

Publié : jeu. 26/nov./2009 18:43
par Octavius
Ah OK les mutex... :| Merci Soldat Inconnu, je dois dire que c'est la première fois que je travaille avec des threads, ce petit code était l'occasion de m'initier.

Et là vous devez vous demander pourquoi j'ai mis un thread ici alors que je pouvais tout mettre dans une seule boucle. C'est essentiellement parce que je ne suis pas à l'aise avec les écrans et l'économie de temps CPU. Sans écran, WaitWindowEvent() c'est parfait. Mais avec un écran il faut utiliser WindowEvent() pour ne pas bloquer la boucle et là le problème c'est que ça fait beaucoup trop tourner le PC pour rien (bref une vraie machine à gaz provoquant une utilisation de l'UC à 60% à cause de la boucle infinie). Si je mets un Delay() directement dans la boucle principale ça ralentit la réactivité du programme et particulièrement les gadgets de la fenêtre. Alors j'ai voulu faire deux boucles en parallèle, une avec WaitWindowEvent() pour la fenêtre normale, et une avec WindowEvent()+Delay() pour l'affichage de l'écran.

Re: Faire onduler une image

Publié : ven. 27/nov./2009 5:51
par Backup
t'as essayé avec WaitWindowEvent([Minuteur]) ?

sinon en principe un windowevent()
suivi d'un delay(2) suffit la plupart du temps ;)