Source     Discussion     Modifier     Historique     Forums     Salon IRC

Source:TachesMartin.pb

Un article de Games Creators Network.


Et allez voir aussi à cette adresse filperj avait bien bossé le sujet :)

;*----------------------------------------------------*
;* http://purebasic.hmt-forum.com/viewtopic.php?t=938 *
;*----------------------------------------------------*
;
; Petit TUT ASM
;
; F.Weil 20040617
;
;================================================================================
; Ce listing a pour but de montrer comment étudier la transposition en ASM de certaines parties de code.
; Rien d'exhaustif mais une prise en main qui peut donner de bonnes bases.
;
; Reprise du principe des taches de Martin
;
; Là j'ai mis l'accent sur la gestion directe du DrawingBuffer
;
; L'algorithme proposé est de même principe que celui d'origine pour les taches de Martin, c'est à dire
; pour chaque point P(X, Y) on associe une couleur calculée à partir de la moyenne des couleurs des 4 points
; voisins + 1
; Soit couleur(P(X, Y)) = (couleur(P1(X, Y - 1)) + couleur(P2(X - 1, Y)) + couleur(P3(X + 1, Y)) + couleur(P4(X, Y + 1))) / 4 + 1
;
; Pour rendre l'effet escompté on doit travailler dans une palette limitée.
;
; Pour faire les choses sans passer par un screen en 8 bits ou autre chose, je prends le mode par défaut de l'écran en 32 bits, et
; je convertis en recalculant couleur
;
; couleur = couleur % 64 + 192
; couleur = couleur << 10 + couleur
;
; Le but de cette démonstration ne consiste pas à montrer des carences de PureBasic, bien au contraire. Il ressort que l'utilisation de l'ASM
; n'apporte que peu d'améliorations si le codage PureBasic est bien conçu par le développeur.
;
; Pour une meilleure expérimentation des méthodes ici, il est possible de naviguer sur les différents types de code en utilisant les
; flèches gauche / droite du clavier et de changer la taille de la zone de dessin avec les touches 4 / 6 du clavier numérique.
;
; Un affichage temps réel de l'algorithme utilisé, du nombre de trames par seconde et de la taille du dessin est effectué.
;

;
; Cette énumération est mise en place pour rendre l'accès aux différents algorithmes plus aisés.
; Les noms des codes à exécuter sont également placés dans un tableau de chaînes pour l'affichage des stats.

;
; Voici un tableau des résultats expérimentaux (en FPS) obtenus sur mon PC de développement
;
; FlipBuffers(1)                        128x128    256x256    320x240    480x360    640x480    800x600
; PureBasic_Regular_Code             4              2               1              -                -              -
; PureBasic_Better_Code             60             30             30            21              10             8
; PureBasic_Optimized_Code       60             30             30            22              10             8
; PureBasic_LowLevel_Code        60             30             30            22              10             8
; PureBasic_Chewed_Code          60             30             30            19                9             7
; ASM_Code                               60             30             30            23              10             8
; PureBasic_LowLevel_Code2       60             59             59            45              20           15
; ASM_LowLevel_Code2              60             60             59             50              22           16
;       
; FlipBuffers(0)                        128x128    256x256    320x240    480x360    640x480    800x600
; PureBasic_Regular_Code             5              2               1              -                -              -
; PureBasic_Better_Code            260            55             46            21              12              8
; PureBasic_Optimized_Code       251            50             49           22               11              8
; PureBasic_LowLevel_Code        251            50             49           22               11              8
; PureBasic_Chewed_Code         216            44             42            19              10              7
; ASM_Code                              255            55             52            23              12              9
; PureBasic_LowLevel_Code2      604          126            100           45              27             17
; ASM_LowLevel_Code2              627          143            113           51              30             20
;
; Résultats mesurés sur mon PC 1,2GHz / Graphique 32MO
;

Enumeration
  #PureBasic_Regular_Code
  #PureBasic_Better_Code
  #PureBasic_Optimized_Code
  #PureBasic_LowLevel_Code
  #PureBasic_Chewed_Code
  #ASM_Code
  #PureBasic_LowLevel_Code2
  #ASM_LowLevel_Code2
EndEnumeration

#LastCode = #ASM_LowLevel_Code2

Global tz.l, FPS.l, NFrames.l, AFrames.l, TFrames.l ; Stats

;
; ResetAll permet d'effacer les buffers et de remettre les tableaux utilisés à zéro.
Procedure ResetAll()
  FlipBuffers(1)
  ClearScreen(0, 0, 0)
  FlipBuffers(1)
  ClearScreen(0, 0, 0)
  Dim DrawingArray.l(1024, 768)
  Dim DrawingArea.l(1024 * 768)
  tz = ElapsedMilliseconds()
  FPS = 0
  NFrames = 0
  AFrames = 0
  TFrames = 0
EndProcedure

ExecuteCode = #ASM_Code

Dim CodeType.s(10)
Dim DrawingWidth.l(10)
Dim DrawingHeight.l(10)

; Une liste des noms des parties du code est placée en DataSection.
For i = 0 To #LastCode
  Read CodeType(i)
  CodeType(i) + Space(40 - Len(CodeType(i)))
Next

LastSize = 5
WidthHeight = 3

; Une liste des tailles de zone de dessin est donnée en DataSection
For i = 0 To LastSize
  Read DrawingWidth(i)
  Read DrawingHeight(i)
Next
;
; DrawinArray est un tableau à 2 dimensions utilisé pour mémoriser les pixels x, y de l'écran dans certaines parties du programme
; DrawingArea est un tableau à une seule dimension utilisé dans le même but, mais dans d'autres parties.
;
Dim DrawingArray.l(1024, 768)
Dim DrawingArea.l(1024 * 768)

; La largeur et la hauteur courante pour le dessin sont initalisées ainsi que les limites xTop, yTop, xBottom, yBottom
DrawingWidth = DrawingWidth(WidthHeight)
DrawingHeight = DrawingHeight(WidthHeight)
ScreenXSize = GetSystemMetrics_(#SM_CXSCREEN)
ScreenYSize = GetSystemMetrics_(#SM_CYSCREEN)
xTop = (ScreenXSize - DrawingWidth) / 2 + 1
yTop = (ScreenYSize - DrawingHeight) / 2 + 1
xBottom = xTop + DrawingWidth - 2
yBottom = yTop + DrawingHeight - 2

;
;
;
If InitKeyboard() And InitSprite() And OpenScreen(ScreenXSize, ScreenYSize, 32, "Taches de Matin")
  StartDrawing(ScreenOutput())
  DrawingFont(LoadFont(23, "Verdana", 8, #PB_Font_HighQuality | #PB_Font_Bold))
  StopDrawing()
  Repeat
    ;
    ;=========================================================================
    ; On utilise la commande FlipBuffers(0) (sans synchronisation plus rapide mais qui peut produire des scintillements
    ; ou FlipBuffers(1) qui attend que le buffer soit prêt avant affichage.
    ;
    ; Le changement de mode se fait en appuyant les flèches haut ou bas.
    ;
    FlipBuffers(FlipBuffers)
    StartDrawing(ScreenOutput())
    Select ExecuteCode
      ;
      ;=====================================================================================
      ; Pour commencer voici dans une écriture conventionnelle le code correspondant à la spécification donnée en commentaire ci-dessus.
      ;
      ; Pour l'ensemble des points à traiter, on calcule la somme des valeurs des 4 points adjacents que l'on injecte dans une formule.
      ;
      ; Le point courant est ensuite simplement dessiné à la position voulue.
      ;
      Case #PureBasic_Regular_Code
        For x = 1 To DrawingWidth - 1
          For y = 1 To DrawingHeight - 1
            Value = ((Point(x + xTop, y + yTop - 1) + Point(x + xTop, y + yTop + 1) + Point(x + xTop + 1, y + yTop) + Point(x + xTop - 1, y + yTop)) / 4 + 1) % 64 + 192
            Color = Value << 10 + Value
            Plot(x + xTop, y + yTop, Color)
          Next
        Next
        ;
        ;=======================================================================================
        ; Dans la version #PureBasic_Better_Code on ne va plus utiliser la fonction Point(x, y) mais un tableau qui permet de mémoriser les
        ; valeurs des points.
        ;
        ; Ce tableau est à deux dimensions et chaque élément x, y du tableau représente fidèlement un point de l'écran
        ;
        ; Par contre le tracé du point courant est fait avec la fonction Plot, dont les performances restent assez bonnes.
        ;
        ; De là l'écriture est encore assez lisible ... et les performances très différentes
        ;
      Case #PureBasic_Better_Code
        For x = 1 To DrawingWidth - 1
          For y = 1 To DrawingHeight - 1
            Value = ((DrawingArray(x, y - 1) + DrawingArray(x, y + 1) + DrawingArray(x - 1, y) + DrawingArray(x + 1, y)) / 4 + 1) & 63 + 192
            Color = Value << 10 + Value
            DrawingArray(x, y) = Color
            Plot(x + xTop, y + yTop, Color)
          Next
        Next
        ;
        ;=============================================================================
        ; Dans la version #PureBasic_Optimized_Code on utilise un tableau linéaire et non plus une matrice à deux dimensions.
        ;
        ; L'écriture du code est sensiblement plus lourde mais permettra d'aborder la phase d'optimisation suivante lus aisément.
        ;
      Case #PureBasic_Optimized_Code
        For x = 1 To DrawingWidth - 1
          For y = 1 To DrawingHeight - 1
            xy = y * DrawingWidth + x
            Value = ((DrawingArea(xy - DrawingWidth) + DrawingArea(xy + DrawingWidth) + DrawingArea(xy - 1) + DrawingArea(xy + 1)) / 4 + 1) & 63 + 192
            Color = Value << 10 + Value
            DrawingArea(xy) = Color
            Plot(x + xTop, y + yTop, Color)
          Next
        Next
        ;
        ;====================================================================================
        ; Dans #PureBasic_LowLevel_Code, on va utiliser simultanément un tableau pour mémoriser les points et un calcul de l'adresse des
        ; points dans le buffer d'écran.
        ;
        ; Ce calcul n'apportera pas directement d'améliorations de performances, mais permettra de maîtriser la copie directe d'une valeur du tableau sur l'écran.
        ;
      Case #PureBasic_LowLevel_Code
        DrawingBuffer = DrawingBuffer()
        DrawingBufferPitch = DrawingBufferPitch()
        For x = 1 To DrawingWidth - 1
          X4 = DrawingBuffer + (x + xTop) << 2
          For y = 1 To DrawingHeight - 1
            xy = y * DrawingWidth + x
            Value = ((DrawingArea(xy - DrawingWidth) + DrawingArea(xy + DrawingWidth) + DrawingArea(xy - 1) + DrawingArea(xy + 1)) / 4 + 1) & 63 + 192
            Color = Value << 10 + Value
            DrawingArea(xy) = Color
            Color = (Color & $FF0000) >> 16 + (Color & $00FF00) + (Color & $0000FF) << 16
            Address = DrawingBufferPitch * (y + yTop) + X4
            PokeL(Address, Color)
          Next
        Next
        ;
        ;===========================================================================
        ; Le but du code développé ici est de se rapprocher le plus possible des instructions les plus élémentaires.
        ;
        ; On essaye de proscrire toute écriture qui consiste à cumuler plusieurs opérations sur une même ligne
        ;
        ; Pour y parvenir il suffit d'ajouter des variables temporaires lorsque c'est nécessaire.
        ;
        ; Dans ce style d'écriture on utilisera de préférence la notation unaire de PureBasic, c'est à dire par exemple :
        ;
        ; a + 1 au lieu de a = a + 1
        ; a + b au lieu de a = a + b
        ;
        ; etc
        ;
        ; On s'interdit également d'utiliser trois variables sur une même ligne :
        ;
        ; c = a + b sera donc déployé en 2 lignes
        ; c = a
        ; c + b
        ;
        ; Cette écriture donnera un code très rapide, même si il n'est pas tout à fait aussi rapide que le modèle #PureBasic_LowLevel_Code précédent
        ;
        ; Cette étape est une manière réaliste de passer de l'optimisation langage évolué à l'optimisation assembleur. La tentative de traduire
        ; directement le code #PureBasic_Optimized_Code est généralement vouée à de malheureuses déconvenues et n'apporte jamais de meilleurs résultats
        ; que le code généré par le compilateur.
        ;
      Case #PureBasic_Chewed_Code
        DrawingBuffer = DrawingBuffer()
        DrawingBufferPitch = DrawingBufferPitch()
        For x = 1 To DrawingWidth - 1
          X4 = x
          X4 + xTop
          X4 << 2
          X4 + DrawingBuffer
          For y = 1 To DrawingHeight - 1
            xy = DrawingWidth
            xy * y
            xy + x
            a = xy
            a - DrawingWidth
            Value = DrawingArea(a)
            a = xy
            a + DrawingWidth
            Value + DrawingArea(a)
            a = xy
            a - 1
            Value + DrawingArea(a)
            a = xy
            a + 1
            Value + DrawingArea(a)
            Value >> 2
            Value + 1
            Value & 63
            Value + 192
            Color = Value
            Color << 10
            Color + Value
            DrawingArea(xy) = Color
            Color1 = Color
            Color1 & $FF0000
            Color1 >> 16
            Color2 = Color
            Color2 & $00FF00
            Color3 = Color
            Color3 & $0000FF
            Color3 << 16
            Color = Color1
            Color + Color2
            Color + Color3
            Address = y
            Address + yTop
            Address * DrawingBufferPitch
            Address + X4
            PokeL(Address, Color)
          Next
        Next
        ;
        ;=========================================================================================
        ; Le code #ASM_Code est la reprise du code #PureBasic_Chewed_Code avec quelques optimisations
        ;
        ; On s'attache en particulier à éliminer le report de valeurs de registres dans des variables temporaires.
        ;
        ; La limitation en nombre de registres oblige bien entendu à être très soigneux dans le choix des variables temporaires éliminées.
        ;
        ; On peut considérer pratiquement que les registres sont des variables, mais en conservant à l'esprit que l'exécution
        ; de toute instruction langage évolué remet en question l'état de tous les registres CPU.
        ;
        ; Il faut par conséquent rester en assembleur le plus longtemps possible pour éviter de risquer de perdre la valeur d'un registre en cours de route,
        ; ou inversement d'être contraint de sauvegarder tel ou tel registre dans une variable mémoire ce qui diminuerait la qualité d'optimisation.
        ;
      Case #ASM_Code
        DrawingBuffer = DrawingBuffer()
        DrawingBufferPitch = DrawingBufferPitch()
        X4.l
        xy.l
        For x = 1 To DrawingWidth - 1
          !  MOV     eax, dword[v_x]                                     ; eax = x
          !  ADD     eax, dword[v_xTop]                               ; eax + xTop
          !  SAL      eax, 2                                                    ; eax << 2
          !  ADD     eax, dword[v_DrawingBuffer]                  ; eax + DrawingBuffer
          !  MOV     dword[v_X4], eax                                   ; X4 = eax
          For y = 1 To DrawingHeight - 1
            !  MOV     eax, dword[v_DrawingWidth]                           ; eax = DrawingWidth
            !  IMUL    eax, dword[v_y]                                    ; eax * y
            !  ADD     eax, dword[v_x]                                   ; eax + x
            
            !  MOV     ebp, dword[a_DrawingArea]                   ; ebp = @DrawingArea()
            !  MOV     ecx, eax                                               ; ecx = eax
            !  SUB      ecx, dword[v_DrawingWidth]                           ; ecx - DrawingWidth
            !  SAL      ecx, 2                                                   ; ecx * 4
            !  MOV     edi, dword[ebp+ecx]                              ; edi = PeekL(ebp + ecx)
            
            !  MOV     ecx, eax                                                ; ecx = eax
            !  ADD     ecx, dword[v_DrawingWidth]                            ; ecx + DrawingWidth
            !  SAL      ecx, 2                                                   ; ecx * 4
            !  ADD     edi, dword[ebp+ecx]                              ; edi + PeekL(ebp + ecx)
            
            !  MOV     ecx, eax                                                ; ecx = eax
            !  DEC     ecx                                                        ; ecx - 1
            !  SAL      ecx, 2                                                    ; ecx * 4
            !  ADD     edi, dword[ebp+ecx]                               ; edi + PeekL(ebp+ecx)
            
            !  ADD     ecx, 8                                                    ; ecx + 8 (soit ecx = ((eax - 1) + 2) * 4
            !  ADD     edi, dword[ebp+ecx]                               ; edi + PeekL(ebp + ecx)
            
            !  SAR     edi, 2                                                     ; edi >> 2
            !  INC      edi                                                        ; edi + 1
            !  And     edi, 63                                                   ; edi & 63
            !  ADD     edi, 192                                                  ; edi + 192
            
            !  MOV     edx, edi                                                 ; edx = edi
            !  MOV     ebx, edx                                                ; ebx = edx
            !  SAL      edx, 10                                                  ; eax = edx << 10
            !  ADD     edx, ebx                                                ; edx = ebx
            
            !  MOV      ecx, eax                                                ; ecx = eax
            !  SAL       ecx, 2                                                   ; ecx * 4
            !  MOV      [ebp+ecx], edx                                      ; PokeL(ebp+ecx, edx)
            
            !  MOV      ecx, dword[v_y]                                  ; ecx = y
            !  ADD      ecx, dword[v_yTop]                            ; ecx + yTop
            !  IMUL     ecx, dword[v_DrawingBufferPitch]         ; ecx * DrawingBufferPitch
            !  ADD      ecx, dword[v_X4]                                ; ecx + X4
            !  BSWAP  edx                                                     ; edx (00RRGGBB) => (BBGGRR00)
            !  SAR       edx, 8                                                 ; edx(BBGGRR00) => (00BBGGRR)
            !  MOV      [ecx], edx                                           ; PokeL(ecx, edx)
          Next
        Next
        ;
        ;=====================================================================
        ; Dans la version #PureBasic_LowLevel_Code2 on reprend le même principe mais on a linéarisé l'adressage
        ; Ici le buffer de l'écran est adressé avec une seule variable d'adresse qui est incrémentée de 4 octets pour passer
        ; point suivant et d'une ligne moins la DrawingWidth de tracé pour passer à la ligne suivante.
        ;
        ; Cette méthode permet d'adresser le pixel à tracer au plus vite.
        ;
        ; Dans le même temps les valeurs des points sont toujours stockées dans un tableau qui lui est adressé
        ; à partir de deux variables x et y en recalculant l'indice unaire du tableau pour éviter le double calcul d'adresse.
        ;
        ; La méthode paraît peu différente à priori, mais les résultats n'ont rien à voir.
        ;
        ; Pour amener à une meilleure optimisation ultérieure en assembleur, les boucles For / Next ont été remplacées par des Repeat / Until
        ;
        ; Le calcul de valeur d'un pixel reste inchangé.
        ;
      Case #PureBasic_LowLevel_Code2
        DrawingBuffer = DrawingBuffer()
        DrawingBufferPitch = DrawingBufferPitch()
        BufferAddress = DrawingBuffer + 4 * (xTop + 1) + yTop * DrawingBufferPitch
        ArrayAddress = DrawingWidth + 1
        y = 1
        Repeat
          x = 1
          Repeat
            Value = ((DrawingArea(ArrayAddress - DrawingWidth) + DrawingArea(ArrayAddress + DrawingWidth) + DrawingArea(ArrayAddress - 1) + DrawingArea(ArrayAddress + 1)) / 4 + 1) & 63 + 192
            Color = Value << 10 + Value
            DrawingArea(ArrayAddress) = Color
            Color = (Color & $FF0000) >> 16 + (Color & $00FF00) + (Color & $0000FF) << 16
            PokeL(BufferAddress, Color)
            BufferAddress + 4
            ArrayAddress + 1
            x + 1
          Until  x > DrawingWidth - 1
          ArrayAddress + 1
          BufferAddress + DrawingBufferPitch - 4 * (DrawingWidth - 1)
          y + 1
        Until y > DrawingHeight - 1
        ;
        ;======================================================
        ; Voici une version assembleur optimisée pour le code #PureBasic_LowLevel_Code2
        ;
      Case #ASM_LowLevel_Code2
        DrawingBuffer = DrawingBuffer()
        DrawingBufferPitch = DrawingBufferPitch()
        !  MOV    ebx, dword[v_DrawingBuffer]                      ; ebx = DrawingBuffer
        !  MOV    edi, dword[v_xTop]                                     ; edi = xTop
        !  INC     edi                                                             ; edi + 1
        !  SAL     edi, 2                                                         ; edi * 4
        !  ADD    ebx, edi                                                      ; ebx + edi
        !  MOV    edi, dword[v_yTop]                                     ; edi = yTop
        !  IMUL   edi, dword[v_DrawingBufferPitch]                 ; edi * DrawingBufferPitch
        !  ADD    ebx, edi                                                     ; ebx + edi
        !  MOV    dword[v_BufferAddress], ebx                       ; BufferAddress = ebx
        !  MOV    ebx, dword[v_DrawingWidth]                       ; ebx = DrawingWidth
        !  INC     ebx                                                            ; ebx + 1
        !  MOV    dword[v_ArrayAddress], ebx                        ; ArrayAddress = ebx
        !  MOV    dword[v_y], 1                                             ; y = 1
        !_RepeatBN21:                                                         ; Repeat / Until return label
        !  MOV    dword[v_x], 1                                           ; x = 1
        !_RepeatBN22:                                                       ; Repeat / Until return label
        !  MOV      ebp, dword[a_DrawingArea]                     ; ebp = DrawingArea
        !  MOV      ecx, dword[v_ArrayAddress]                    ; ecx = @ArrayAddress
        !  MOV      eax, ecx                                                 ; eax = ecx
        !  SUB      eax, dword[v_DrawingWidth]                    ; eax - DrawingWidth
        !  SAL       eax, 2                                                    ; eax * 4
        !  MOV      edi, dword[ebp+eax]                               ; edi = PeekL(ebp+eax]
        
        !  MOV      eax, ecx                                                 ; eax = ecx
        !  ADD      eax, dword[v_DrawingWidth]                    ; eax - DrawingWidth
        !  SAL       eax, 2                                                    ; eax * 4
        !  ADD      edi, dword[ebp+eax]                               ; edi = PeekL(ebp+eax]
        
        !  MOV      eax, ecx                                                 ; eax = ecx
        !  DEC      eax                                                        ; eax - 1
        !  SAL       eax, 2                                                    ; eax * 4
        !  ADD      edi, dword[ebp+eax]                               ; edi = PeekL(ebp+eax]
        
        !  ADD      eax, 8                                                    ; eax + 8
        !  ADD      edi, dword[ebp+eax]                               ; edi = PeekL(ebp+eax]
        
        !  SAR      edi, 2                                                      ; edi / 4
        !  INC       edi                                                         ; edi + 1
        !  And      edi, 63                                                    ; edi & 63
        !  ADD      edi, 192                                                  ; edi + 192
        !  MOV      ebx, edi                                                  ; ebx = edi
        
        !  SAL       ebx, 10                                                   ; ebx << 10
        !  ADD      ebx, edi                                                  ; ebx + edi
        
        !  MOV      eax, ecx                                                  ; eax = ecx
        !  SAL       eax, 2                                                     ; eax * 4
        !  MOV      dword[ebp+eax], ebx                               ; PokeL(ebp+eax, ebx)
        
        !  BSWAP  ebx                                                         ; ebx (00RRGGBB) => (BBGGRR00)
        !  SAR       ebx, 8                                                     ; ebx(BBGGRR00) => (00BBGGRR)
        
        !  MOV      eax,dword[v_BufferAddress]                     ; eax = @BufferAddress
        !  MOV      [eax], ebx                                               ; PokeL(eax, ebx)
        
        !  ADD      dword[v_BufferAddress], 4                        ; BufferAddress + 4
        !  INC       dword[v_ArrayAddress]                             ; ArrayAddress + 1
        !  INC       dword[v_x]                                               ; x + 1
        !  MOV      ebx, dword[v_x]                                        ; ebx = x
        !  MOV      edi, dword[v_DrawingWidth]                       ; edi = DrawingWidth
        !  DEC      edi                                                           ; edi - 1
        !  CMP      ebx, edi                                                    ; if ebx <= edi
        !  JLE        _RepeatBN22                                            ; Goto RepeatBN22
        
        !  INC     dword[v_ArrayAddress]                                   ; ArrayAddress + 1
        !  MOV    ebx, dword[v_DrawingWidth]                           ; ebx = DrawingWidth
        !  DEC    ebx                                                                ; ebx - 1
        !  SAL     ebx, 2                                                            ; ebx / 4
        !  NEG    ebx                                                                 ; -ebx
        !  ADD    ebx, dword[v_DrawingBufferPitch]                    ; ebx + DrawingBufferPitch
        !  ADD    dword[v_BufferAddress], ebx                           ; BufferAddress + ebx
        !  INC     dword[v_y]                                                     ; y + 1
        !  MOV    edi, dword[v_DrawingHeight]                            ; edi = DrawingHeight
        !  ADD    edi, -1                                                            ; edi - 1
        !  MOV    ebx, dword[v_y]                                              ; ebx = y
        !  CMP    ebx, edi                                                          ; if ebx <= edi
        !  JLE      _RepeatBN21                                                  ; Goto RepeatBN21
    EndSelect
    
    ;
    ; Keyboard events part
    ;============================
    ; Section de gestion des évènements clavier
    ;
    ExamineKeyboard()
    ; Change the code part to execute
    ; Modifie la section de code à exécuter
    If KeyboardPushed(#PB_Key_Left)
      ResetAll()
      ExecuteCode - 1
      If ExecuteCode < 0
        ExecuteCode = 0
      EndIf
      Repeat
        ExamineKeyboard()
      Until KeyboardReleased(#PB_Key_Left)
    EndIf
    If KeyboardPushed(#PB_Key_Right)
      ResetAll()
      ExecuteCode + 1
      If ExecuteCode > #LastCode
        ExecuteCode = #LastCode
      EndIf
      Repeat
        ExamineKeyboard()
      Until KeyboardReleased(#PB_Key_Right)
    EndIf
    ; Set / Unset the buffers synchronization
    ; Valide / invalide la synchronisation des buffers
    If KeyboardPushed(#PB_Key_Up)
      ResetAll()
      FlipBuffers = 1 - FlipBuffers
      Repeat
        ExamineKeyboard()
      Until KeyboardReleased(#PB_Key_Up)
    EndIf
    If KeyboardPushed(#PB_Key_Down)
      ResetAll()
      FlipBuffers = 1 - FlipBuffers
      Repeat
        ExamineKeyboard()
      Until KeyboardReleased(#PB_Key_Down)
    EndIf
    ; Change the drawing area size
    ; Modifie la taille de la zone de dessin
    If KeyboardPushed(#PB_Key_Pad4)
      ResetAll()
      WidthHeight - 1
      If WidthHeight < 0
        WidthHeight = 0
      EndIf
      Repeat
        ExamineKeyboard()
      Until KeyboardReleased(#PB_Key_Pad4)
      DrawingWidth = DrawingWidth(WidthHeight)
      DrawingHeight = DrawingHeight(WidthHeight)
      xTop = (ScreenXSize - DrawingWidth) / 2 + 1
      yTop = (ScreenYSize - DrawingHeight) / 2 + 1
      xBottom = xTop + DrawingWidth - 2
      yBottom = yTop + DrawingHeight - 2
    EndIf
    If KeyboardPushed(#PB_Key_Pad6)
      ResetAll()
      WidthHeight + 1
      If WidthHeight > LastSize
        WidthHeight = LastSize
      EndIf
      Repeat
        ExamineKeyboard()
      Until KeyboardReleased(#PB_Key_Pad6)
      DrawingWidth = DrawingWidth(WidthHeight)
      DrawingHeight = DrawingHeight(WidthHeight)
      xTop = (ScreenXSize - DrawingWidth) / 2 + 1
      yTop = (ScreenYSize - DrawingHeight) / 2 + 1
      xBottom = xTop + DrawingWidth - 2
      yBottom = yTop + DrawingHeight - 2
    EndIf
    ; Control the elapsed time since the last integer second
    ; Contrôle le temps écoulé depuis la dernière seconde entière
    If ElapsedMilliseconds() - tz => 1000
      tz = ElapsedMilliseconds()
      FPS = NFrames
      TFrames + FPS
      NFrames = 0
      AFrames + 1
    EndIf
    NFrames + 1
    ; Display statistics and parameters
    ; Affiche les statistiques et les paramètres
    BackColor(0, 0, 0)
    FrontColor(255, 255, 255)
    Locate(10, 40)
    DrawText("FPS " + Str(FPS) + "      Average : " + StrF(TFrames / AFrames, 2))
    Locate(10, 60)
    DrawText(CodeType(ExecuteCode) + "            ")
    Locate(10, 80)
    DrawText("FlipBuffers(" + Str(FlipBuffers) + ")")
    Locate(10, 100)
    DrawText(Str(DrawingWidth) + "x" + Str(DrawingHeight))
    StopDrawing()
  Until KeyboardReleased(#PB_Key_Escape)
EndIf
End

DataSection
Data.s "#PureBasic_Regular_Code", "#PureBasic_Better_Code", "#PureBasic_Optimized_Code", "#PureBasic_LowLevel_Code"
Data.s "#PureBasic_Chewed_Code", "#ASM_Code", "#PureBasic_LowLevel_Code2", "#ASM_LowLevel_Code2"
Data.l 128, 128
Data.l 256, 256
Data.l 320, 240
Data.l 480, 360
Data.l 640, 480
Data.l 800, 600
EndDataSection

 

Rechercher
Installer l'extension de recherche Plus d'informations

 

Comprendre
Tu me dis, j'oublie. Tu m'enseignes, je me souviens. Tu m'impliques, j'apprends. - Benjamin Franklin

 

Partager
La connaissance est la seule chose qui s'accroit lorsqu'on la partage. - Sacha Boudjema

 

Créer
L'imagination est plus importante que la connaissance. - Albert Einstein

 

 

Le wiki en images Le wiki en images Image du mois: «Snowball: un prototype de jeu développé avec NeL.