Plasma

Programmation d'applications complexes
bombseb
Messages : 445
Inscription : jeu. 25/août/2005 22:59
Localisation : 974
Contact :

Plasma

Message par bombseb »

Salut, voici un plasma que je viens de faire...

je pense qu'on doit pouvoir l'optimiser en précalculant les cosinus et les sinus mais c'est chiant à faire :oops:

Code : Tout sélectionner

 InitSprite() 
 InitKeyboard() 

 If (InitSprite() And InitKeyboard() And OpenScreen(640,480,32,"Plasma")) = 1
 EndIf
  
   
  xres = 640
  yres = 480

 ;Récupère l'adresse du buffer invisible 
 StartDrawing(ScreenOutput()) 
 *AdresseEcran=DrawingBuffer() 
 Pitch=DrawingBufferPitch()/SizeOf(long) 



#PI = 3.14159

; ------ Definition de la palette --------------
Dim mapal.l(300)
For i = 0 To 300
  angle.f = angle + ((2 * #pi) / 300)
  mapal(i) = RGB (Abs (Cos (angle + (4*#pi/3))* 255),Abs (Cos (angle + #pi/2)* 255), Abs (Cos (angle)* 255))
Next
; ----------------------------------------------


; ------------------- PLASMA -------------------

Repeat
 
  a2 + 5
  a3 + 5

  StartDrawing (ScreenOutput ())
  *AdresseEcran=DrawingBuffer() 
  
  For x = 0 To xres
  
    A = Sin ((x + a2)/(300 + Sin (x/100)*100)) * 75 + 75
    For y = 0 To yres
      *ptr.Long = *AdresseEcran + (x+y*pitch) * SizeOf(Long) 
      
      A2 = Cos ((y + a3)/(300 + Cos (y/100)*100)) * 75 + 75
      
      
      coul = a + a2
      If coul > 300
        coul = coul-300
      EndIf
      coul = mapal (coul)
   
      ;Plot (x,y, coul)
      *ptr\l = coul
      
    Next
  Next
  
  StopDrawing ()
  FlipBuffers()
  ExamineKeyboard() 
Until KeyboardPushed(#PB_Key_Escape) 
  
; ----------------------------------------------
dites moi ce que vous en pensez, c'est mon premier prog en purebasic
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

Voila les modifs pour que ca fonctionne chez moi...

Code : Tout sélectionner

If (InitSprite() And InitKeyboard() And OpenScreen(640,480,32,"Plasma")) = 1
EndIf

 
xres = 640
yres = 480

;Récupère l'adresse du buffer invisible
StartDrawing(ScreenOutput())
*AdresseEcran=DrawingBuffer()
Pitch=DrawingBufferPitch()/SizeOf(long)



#PI = 3.14159

; ------ Definition de la palette --------------
Dim mapal.l(300)
For i = 0 To 300
  angle.f = angle + ((2 * #pi) / 300)
  mapal(i) = RGB (Abs (Cos (angle + (4*#pi/3))* 255),Abs (Cos (angle + #pi/2)* 255), Abs (Cos (angle)* 255))
Next
; ----------------------------------------------


; ------------------- PLASMA -------------------

Repeat
 
  a2 + 5
  a3 + 5

  If StartDrawing( ScreenOutput() )
    *AdresseEcran=DrawingBuffer()
   
    For x = 0 To xres
   
      A = Sin ((x + a2)/(300 + Sin (x/100)*100)) * 75 + 75
      For y = 0 To yres
        *ptr.Long = *AdresseEcran + (x+y*pitch) * SizeOf(Long)
       
        A2 = Cos ((y + a3)/(300 + Cos (y/100)*100)) * 75 + 75
       
       
        coul = a + a2
        If coul > 300
          coul = coul-300
        EndIf
        coul = mapal (coul)
     
        ;Plot (x,y, coul)
        *ptr\l = coul
       
      Next
    Next
   
    StopDrawing ()
  EndIf
  FlipBuffers()
  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
sympa comme tout en tou cas ^^

Dri :10:
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Message par fweil »

Pour l'optimisation des calculs de Sin() / Cos(), il y a un truc intéressant et pas trop lourd à intégrer :

- créer des tableaux pré-calculés pour les valeurs y des fonctions Sin() et Cos() variant de 0 à 2 * Pi par pas de 0.001 et travailler sur les angles * 1000 ramenés à des indices entiers.

Code : Tout sélectionner

  Dim fSin.f(8191)
  Dim fCos.f(8191)
  For i = 0 To 8191
    fSin(i) = Sin(i / 1000)
    fCos(i) = Cos(i / 1000)
  Next

  OpenConsole()
  
    NTimes = 10000000
    
    tz = ElapsedMilliseconds()
    For i = 1 To NTimes
      f.f = Sin(i / 12345)
    Next
    PrintN(Str(ElapsedMilliseconds() - tz))
    
    tz = ElapsedMilliseconds()
    For i = 1 To NTimes
      angle.f = i / 12345
      iangle * 1000
      iangle & $1FFF
      f.f = fSin(iangle)
    Next
    PrintN(Str(ElapsedMilliseconds() - tz))
    
    While Inkey() = ""
    Wend
    
  CloseConsole()
    
End
Les écarts entre les valeurs réelles et les valeurs pré-calculées sont ainsi assez faibles pour ne pas perturber le dessin en général (on a une précision ramenée à moins de un pixel près).

L'avantage de la méthode est, comme le fait ressortir le code ci-dessus, une vitesse 4 à 5 fois plus grande pour obtenir la valeur approchée.

Attention à vérifier ce code de test sans Debugger pour voir les perfs en exécutable.
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
bombseb
Messages : 445
Inscription : jeu. 25/août/2005 22:59
Localisation : 974
Contact :

Message par bombseb »

Dr dri : tu as juste rajouté le "if startdrawing ()" ? cane marchait pas chez toi sans ca ?
- créer des tableaux pré-calculés pour les valeurs y des fonctions Sin() et Cos() variant de 0 à 2 * Pi par pas de 0.001 et travailler sur les angles * 1000 ramenés à des indices entiers.
8O olala ca l'air plutot compliqué tout ca 8O
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

c'est très simple, un startdrawing peut échouer... donc il faut toujours vérifier qu'il a fonctionné...

Code : Tout sélectionner

If StartDrawing( output )
  ;dessin
  StopDrawing()
EndIf
Regarde aussi le début de ton code, il contient des InitTruc() en trop...

Ton code se lance sans le debugger, ma version corrigée se lance aussi avec ;)
(enfin bon j'ai pas regardé tout le code ^^)

Dri
bombseb
Messages : 445
Inscription : jeu. 25/août/2005 22:59
Localisation : 974
Contact :

Message par bombseb »

les initsprite et initkeyboard ?


et pourquoi ca échouerais un startdrawing ?
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

Oui ce sont ces deux initialisations... on initialise qu'une fois...

Pourquoi un StartDrawing() échourai ? parce qu'il est censé bloqué l'accès à la mémoire vidéo de l'output concernée et que ce genre d'opération peut échouer...

Dri ;)
bombseb
Messages : 445
Inscription : jeu. 25/août/2005 22:59
Localisation : 974
Contact :

Message par bombseb »

mais si le startdrawing échoue le programme plante dans cas non ?

dans le cas de ton teste, si le startdrawing échoue le programme se termine sans rien faire non ?
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

dans ton exemple plasma, si le start échoue, rien ne s'affiche à l'écran et la boucle continue juska ce que l'utilisateur quitte... si tu ne fais pas de test sur le start et que tu dessines, là tu auras un plantage séverre...

autre chose, lorsque tu dessines, n'utilise pas le debugger (Debug valeur) parce que là aussi j'ai des plantages séverres...

Dri
bombseb
Messages : 445
Inscription : jeu. 25/août/2005 22:59
Localisation : 974
Contact :

Message par bombseb »

ah bon ok je prend note merci...

bon sinon j'ai optimisé mon plasma en precalculant les sinus et cosinus mais j'ai pas l'impression que ce soit plus rapide :

Code : Tout sélectionner

;  InitSprite() 
;  InitKeyboard() 

 If (InitSprite() And InitKeyboard() And OpenScreen(640,480,32,"Plasma")) = 0
  MessageRequester("Erreur", "Erreur à l'ouverture de l'écran", #PB_MessageRequester_Ok)
  End
 EndIf
  
   
  xres = 640
  yres = 480

 ;Récupère l'adresse du buffer invisible 
 If StartDrawing(ScreenOutput()) = 0
  MessageRequester("Erreur", "Erreur à l'ouverture de l'écran", #PB_MessageRequester_Ok)
  End
 EndIf
 *AdresseEcran=DrawingBuffer() 
 Pitch=DrawingBufferPitch()/SizeOf(long) 

StopDrawing()


#PI = 3.14159

; ------ Definition de la palette --------------
Dim mapal.l(300)
For i = 0 To 300
  angle.f = angle + ((2 * #pi) / 300)
  mapal(i) = RGB (Abs (Cos (angle + (4*#pi/3))* 255),Abs (Cos (angle + #pi/2)* 255), Abs (Cos (angle)* 255))
Next
; ----------------------------------------------


;------------ Precalculation ------------

angle.f = 0
Global nb
nb = 2 * #pi * 1000

Dim costab.f(nb)
Dim sintab.f(nb)


For i = 1 To nb
  angle.f = angle + ((2 * #pi) / nb)
  costab(i) = Cos (angle)
  sintab(i) = Sin (angle)
Next


Procedure.f Getcos(angle.f) 
  
  If angle.f > 2*#pi
    angle = angle / (angle/(2*#pi))
  EndIf
  index = Int (angle * 1000)
  ProcedureReturn costab(index)
EndProcedure 

Procedure.f Getsin(angle.f) 
  
  If angle.f > 2*#pi
    angle = angle / (angle/(2*#pi))
  EndIf
  index = Int (angle * 1000)
  ProcedureReturn sintab(index)
EndProcedure 

; ----------------------------------------------
  

; ------------------- PLASMA -------------------


Repeat
 
  a2 + 5
  a3 + 5

  If StartDrawing (ScreenOutput ())
    *AdresseEcran=DrawingBuffer() 
    
    For x = 0 To xres-1
    
      A = getSin ((x + a2)/(300 + getSin (x/100)*100)) * 75 + 75
      For y = 0 To yres-1
        *ptr.Long = *AdresseEcran + (x+y*pitch) * SizeOf(Long) 
        
        A2 = getCos ((y + a3)/(300 + getCos (y/100)*100)) * 75 + 75
        
        
        coul = a + a2
        If coul > 300
          coul = coul-300
        EndIf
        coul = mapal (coul)
     
        ;Plot (x,y, coul)
        *ptr\l = coul
        
      Next
    Next
  
    StopDrawing ()
    FlipBuffers()
  EndIf
  ExamineKeyboard() 
Until KeyboardPushed(#PB_Key_Escape) 

; ----------------------------------------------

bombseb
Messages : 445
Inscription : jeu. 25/août/2005 22:59
Localisation : 974
Contact :

Message par bombseb »

je viens de m'apercevoir que mon plasma "optimisé" est carrément plus lent que l'original.... comment ce fesse ?
Répondre