9 Patch

Partagez votre expérience de PureBasic avec les autres utilisateurs.
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

9 Patch

Message par boby »

Je n'en ai pas trouvé sur les forums PB, si ça peut servir (bien qu'il soit très basic, mais répond à mes besoins du moment...)

Code : Tout sélectionner

;Original code by Papala
;Modifications by Demivec to correct bug of unfreed temp images. Also did some code formatting for improved readability.

DeclareModule patch
  Enumeration 1
    #Patch_Copy     ;Repeat the sprite to the size
    #Patch_Stretch  ;Stretch the sprite to the size
  EndEnumeration
 
  Declare Image(Image, OutputWidth, OutputHeight, Corner, Flag = #Patch_Stretch) ;The imageID to 9Patch, Width & Height to reach, Corner width/height of the 9patch, Flag can be #9Patch_Copy or #9Patch_Stretch
  Declare Sprite(Image, OutputWidth, OutputHeight, Corner, Flag = #Patch_Stretch)
EndDeclareModule

Module patch
  EnableExplicit 
 
  Structure Patch
    Sprite.i
    OutputWidth.i
    OutputHeight.i
    Corner.i
    Corner2x.i
    Horizontal.i
    Vertical.i
  EndStructure
   
  Enumeration
    #OutputType_Image  ;create a new image for output
    #OutputType_Sprite ;create a new sprite for output
  EndEnumeration
 
  Procedure DrawCorner(SourceImage, *data.patch)
    Protected TempImage
    ;Draw the 4 corners of the original image with no modification
    ;Top left
    TempImage = GrabImage(SourceImage, #PB_Any, 0, 0, *data\Corner, *data\Corner)
    DrawImage(ImageID(TempImage), 0, 0):
    FreeImage(TempImage)
    ;Top right
    TempImage = GrabImage(SourceImage, #PB_Any, ImageWidth(SourceImage) - *data\Corner, 0, *data\Corner, *data\Corner)
    DrawImage(ImageID(TempImage), *data\OutputWidth - *data\Corner, 0)
    FreeImage(TempImage)
    ;Bottom left
    TempImage = GrabImage(SourceImage, #PB_Any, 0, ImageHeight(SourceImage) - *data\Corner, *data\Corner, *data\Corner)
    DrawImage(ImageID(TempImage), 0, *data\OutputHeight - *data\Corner)
    FreeImage(TempImage)
    ;Bottom right
    TempImage = GrabImage(SourceImage, #PB_Any, ImageWidth(SourceImage) - *data\Corner, ImageHeight(SourceImage) - *data\Corner, *data\Corner, *data\Corner)
    DrawImage(ImageID(TempImage), *data\OutputWidth - *data\Corner, *data\OutputHeight - *data\Corner)
    FreeImage(TempImage)
  EndProcedure
 
  Procedure Create(SourceImage, *data.patch, flag, Type)
    Protected HLoop, VLoop, TempImage, Width, Height, Hresult, VResult
   
    *data\Horizontal = ImageWidth(SourceImage)
    *data\Vertical = ImageHeight(SourceImage)
    Select Type
        Case #OutputType_Sprite: StartDrawing(SpriteOutput(*data\Sprite))
        Case #OutputType_Image: StartDrawing(ImageOutput(*data\Sprite))
    EndSelect
   
    DrawCorner(SourceImage, *data)
    Protected Width_NoCorners = *data\OutputWidth - *data\Corner2x,
              Height_NoCorners = *data\OutputHeight - *data\Corner2x
    Select flag
      Case #Patch_Copy ;Repeat the original image's pattern to the new Width and Height
        Width = *data\Horizontal - *data\Corner2x
        Height = *data\Vertical - *data\Corner2x
       
        Protected HLoop_max = (Width_NoCorners) / Width,
                  VLoop_max = (Height_NoCorners) / Height
        For HLoop = 0 To  HLoop_max
          For VLoop = 0 To VLoop_max
       
            Select VLoop
              Case 0 ;================================Top horizontal========================
                If HLoop <> HLoop_max
                  TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, 0, Width, *data\Corner)
                Else
                  TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, 0, Width_NoCorners - Width * HLoop, *data\Corner)
                EndIf
               
                If TempImage
                  DrawImage(ImageID(TempImage), *data\Corner + Width * HLoop, 0)
                  FreeImage(TempImage)
                EndIf
              Case VLoop_max ;=======================Bottom horizontal=========================
                Debug "???"
                If HLoop <> HLoop_max
                  TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, ImageHeight(SourceImage) - *data\Corner, Width, *data\Corner)
                Else
                  TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, ImageHeight(SourceImage) - *data\Corner, Width_NoCorners - Width * HLoop, *data\Corner)
                EndIf
               
                If TempImage
                  DrawImage(ImageID(TempImage), *data\Corner + Width * HLoop, *data\OutputHeight - *data\Corner)
                  FreeImage(TempImage)
                EndIf
            EndSelect
           
            Select HLoop
              Case 0 ;===================================Left vertical=================================
                If VLoop <> VLoop_max
                  TempImage = GrabImage(SourceImage, #PB_Any, 0, *data\Corner, *data\Corner, Height)
                Else
                  TempImage = GrabImage(SourceImage, #PB_Any, 0, *data\Corner, *data\Corner, Height_NoCorners - Height * VLoop)
                EndIf
               
                If TempImage
                  DrawImage(ImageID(TempImage), 0, *data\Corner + Height * VLoop)
                  FreeImage(TempImage)
                EndIf
              Case HLoop_max ;===============================right vertical=============================
                If VLoop <> VLoop_max
                  TempImage = GrabImage(SourceImage, #PB_Any, ImageWidth(SourceImage) - *data\Corner, *data\Corner, *data\Corner, Height)
                Else
                  TempImage = GrabImage(SourceImage, #PB_Any, ImageWidth(SourceImage) - *data\Corner, *data\Corner, *data\Corner, Height_NoCorners - Height * VLoop)
                EndIf
               
                If TempImage
                  DrawImage(ImageID(TempImage), *data\OutputWidth - *data\Corner, *data\Corner + Height * VLoop)
                  FreeImage(TempImage)
                EndIf
            EndSelect
           
            ;Repeat middle's patern to fill the new image with
            If HLoop <> HLoop_max
              Hresult = Width
            Else
              Hresult = Width_NoCorners - Width * HLoop
            EndIf
           
            If VLoop <> VLoop_max
              VResult = Height
            Else
              VResult = Height_NoCorners - Height * VLoop
            EndIf
           
            TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, *data\Corner, Hresult, VResult)
            If TempImage
              DrawImage(ImageID(TempImage), *data\Corner + Width * HLoop, *data\Corner + Height * VLoop)
              FreeImage(TempImage)
            EndIf
           
          Next VLoop
        Next HLoop
       
      Case #Patch_Stretch ;Stretch the original image to the new Width and Height
        ;Top horizontal
        TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, 0, ImageWidth(SourceImage) - *data\Corner2x, *data\Corner)
        DrawImage(ImageID(TempImage), *data\Corner, 0, Width_NoCorners, *data\Corner)
        FreeImage(TempImage)
        ;Bottom horizontal
        TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, ImageHeight(SourceImage) - *data\Corner, ImageWidth(SourceImage) - *data\Corner2x, *data\Corner)
        DrawImage(ImageID(TempImage), *data\Corner, *data\OutputHeight - *data\Corner, Width_NoCorners, *data\Corner)
        FreeImage(TempImage)
        ;Left vertical
        TempImage = GrabImage(SourceImage, #PB_Any, 0, *data\Corner, *data\Corner, ImageHeight(SourceImage) - *data\Corner2x)
        DrawImage(ImageID(TempImage), 0, *data\Corner, *data\Corner, Height_NoCorners)
        FreeImage(TempImage)
        ;Right vertial
        TempImage = GrabImage(SourceImage, #PB_Any, ImageWidth(SourceImage) - *data\Corner, *data\Corner, *data\Corner, ImageHeight(SourceImage) - *data\Corner2x)
        DrawImage(ImageID(TempImage), *data\OutputWidth - *data\Corner, *data\Corner, *data\Corner, Height_NoCorners)
        FreeImage(TempImage)
        ;Middle
        TempImage = GrabImage(SourceImage, #PB_Any, *data\Corner, *data\Corner, ImageWidth(SourceImage) - *data\Corner2x, ImageHeight(SourceImage) - *data\Corner2x)
        DrawImage(ImageID(TempImage), *data\Corner, *data\Corner, Width_NoCorners, Height_NoCorners)
        FreeImage(TempImage)
    EndSelect
    StopDrawing()
  EndProcedure
   
  Procedure Image(SourceImage, OutputWidth, OutputHeight, Corner, Flag = #Patch_Stretch)
    Protected Patch.patch
    Patch\OutputWidth = OutputWidth: Patch\OutputHeight = OutputHeight: Patch\Corner = Corner: Patch\Corner2x = Corner * 2
    Patch\Sprite = CreateImage(#PB_Any, OutputWidth, OutputHeight)
    If Patch\Sprite
      Create(SourceImage, @Patch, Flag, #OutputType_Image)
      ProcedureReturn Patch\Sprite
    Else
      ProcedureReturn #False
    EndIf
  EndProcedure
 
  Procedure Sprite(SourceImage, OutputWidth, OutputHeight, Corner, Flag = #Patch_Stretch)
    Protected Patch.patch
    Patch\OutputWidth = OutputWidth: Patch\OutputHeight = OutputHeight: Patch\Corner = Corner: Patch\Corner2x = Corner * 2
    Patch\Sprite = CreateSprite(#PB_Any, OutputWidth, OutputHeight, #PB_Sprite_AlphaBlending)
    If Patch\Sprite
      Create(SourceImage, @Patch, Flag, #OutputType_Sprite)
      ProcedureReturn Patch\Sprite
    Else
      ProcedureReturn #False
    EndIf
  EndProcedure
EndModule

CompilerIf #PB_Compiler_IsMainFile
  InitSprite()
 
  Define Image1,  Image2, Sprite1, Sprite2
 
  Image1 = CreateImage(#PB_Any, 20, 20)
  StartDrawing(ImageOutput(Image1))
  DrawingMode(#PB_2DDrawing_Outlined)
  Box(0, 0, 19, 19, $FF0000)
  Circle(9, 9, 5, $FFFF00)
  Line(4, 1, 6, 1, $00FF00)
  Line(10, 1, 6, 1, $0000FF)
  StopDrawing()
 
  OpenWindow(0, 0, 0, 100, 200, "9 Patch Sample", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  OpenWindowedScreen(WindowID(0), 0, 0, 100, 200)
 
  Image2 = patch::Image(Image1, 60, 60, 4, patch::#Patch_Copy)
  Sprite1 = patch::Sprite(Image1, 40, 40, 4)
  Sprite2 = patch::Sprite(Image1, 80, 30, 4, patch::#Patch_Copy)
  StartDrawing(ScreenOutput())
  DrawImage(ImageID(Image1), 10, 0) ;Original image
  DrawImage(ImageID(Image2), 10, 30)
  StopDrawing()
 
  DisplaySprite(Sprite1, 10, 100)
  DisplaySprite(Sprite2, 10, 150)
  FlipBuffers()
 
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
CompilerEndIf
PS : Merci Poshu de m'avoir parlé de cette techno.

Edit : Comme me l'a fait remarqué Demivec sur le forum anglais, j'oubliai de libérer les images temporaires que je créais, ce qui à long thermes pourrais être pas mal problèmatique.
@Falsam : Lui aussi trouvais que le code manquait un peut d'air, j'spère que cet édit te plairas ! :twisted:
Dernière modification par boby le mer. 22/août/2018 8:32, modifié 2 fois.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: 9 Patch

Message par falsam »

Merci Boby pour ce code qui me fait comprendre la technique du 9-patch.

Un plaisir de faire F5 et tout fonctionne.
Le module est pas mal mais le code de test et moche.
Le principal est que ce soit fonctionnel n'est ce pas ? :mrgreen:
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: 9 Patch

Message par Fig »

Merci de m'avoir appris que cette technique avait un nom. Je le faisais sans jamais m'etre posé la question ...
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Répondre