9 Patch

Share your advanced PureBasic knowledge/code with the community.
Papala
User
User
Posts: 38
Joined: Wed Sep 12, 2012 5:09 pm

9 Patch

Post by Papala »

I needed one (pretty basic but enouth for what i need) so if it can be usefull fore someone...

Code: Select all

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

Module patch
  EnableExplicit  
  Structure Patch
    Sprite.i
    Width.i
    Height.i
    Corner.i
    Horizontal.i
    Vertical.i
  EndStructure
  Declare Create(Image,*data.patch,flag,Type)
  Declare DrawCorner(Image,*data.patch)
  
  Procedure Image(Image,Width,Height,Corner,Flag = #Patch_Stretch)
    Protected Patch.patch
    Patch\Width = Width : Patch\Height = Height : Patch\Corner = Corner
    Patch\Sprite = CreateImage(#PB_Any,Width,Height)
    If Patch\Sprite
      Create(Image,@Patch,Flag,0)
      ProcedureReturn Patch\Sprite
    Else
      ProcedureReturn #False
    EndIf
  EndProcedure
  
  Procedure Sprite(Image,Width,Height,Corner,Flag = #Patch_Stretch)
    Protected Patch.patch
    Patch\Width = Width : Patch\Height = Height : Patch\Corner = Corner
    Patch\Sprite = CreateSprite(#PB_Any,Width,Height,#PB_Sprite_AlphaBlending)
    If Patch\Sprite
      Create(Image,@Patch,Flag,1)
      ProcedureReturn Patch\Sprite
    Else
      ProcedureReturn #False
    EndIf
  EndProcedure

  Procedure Create(Image,*data.patch,flag,Type)
    Protected HLoop=1, VLoop=1, TempImage, Width, Heigt, Hresult, VResult
    *data\Horizontal = ImageWidth(Image)
    *data\Vertical = ImageHeight(Image)
    If Type
      StartDrawing(SpriteOutput(*data\Sprite))
    Else
      StartDrawing(ImageOutput(*data\Sprite))
    EndIf
    DrawCorner(Image,*data)
    Select flag
      Case #Patch_Copy ;Repeat the original image's patern to the new Width and Height
        width = ImageWidth(Image)-*data\Corner*2
        Heigt = ImageHeight(Image)-*data\Corner*2
        For HLoop = 0 To  (*data\Width - *data\Corner*2) / Width
          For VLoop = 0 To (*data\Height - *data\Corner*2) / Heigt
            Select VLoop
              Case 0 ;================================Top horizontal========================
                If HLoop - (*data\Width - *data\Corner*2) / Width
                  TempImage = GrabImage(Image,#PB_Any,*data\Corner,0,Width,*data\Corner)
                Else
                  TempImage = GrabImage(Image,#PB_Any,*data\Corner,0,*data\Width -*data\Corner*2 - Width * HLoop,*data\Corner)
                EndIf
                If TempImage
                  DrawImage(ImageID(TempImage),*data\Corner+Width*HLoop,0)
                EndIf
              Case (*data\Height - *data\Corner*2) / Width ;=======================Bottom horizontal=========================
                If HLoop - (*data\Width - *data\Corner*2) / Width
                  TempImage = GrabImage(Image,#PB_Any,*data\Corner,ImageHeight(Image)-*data\Corner,Width,*data\Corner) 
                Else
                  TempImage = GrabImage(Image,#PB_Any,*data\Corner,ImageHeight(Image)-*data\Corner,*data\Width -*data\Corner*2 - Width * HLoop,*data\Corner)
                EndIf
                If TempImage
                  DrawImage(ImageID(TempImage),*data\Corner+Width*HLoop,*data\Height-*data\Corner)     
                EndIf
            EndSelect
            Select HLoop
              Case 0 ;===================================Left vertical=================================
                If VLoop - (*data\Height - *data\Corner*2) / Heigt
                  TempImage = GrabImage(Image,#PB_Any,0,*data\Corner,*data\Corner,Heigt)
                Else
                  TempImage = GrabImage(Image,#PB_Any,0,*data\Corner,*data\Corner,*data\Height -*data\Corner*2 - Heigt * VLoop)
                EndIf
                If TempImage
                  DrawImage(ImageID(TempImage),0,*data\Corner+Heigt*VLoop)  
                EndIf
              Case (*data\Width - *data\Corner*2) / Width ;===============================right vertical=============================
                If VLoop - (*data\Height - *data\Corner*2) / Heigt
                  TempImage = GrabImage(Image,#PB_Any,ImageWidth(Image)-*data\Corner,*data\Corner,*data\Corner,Heigt)
                Else
                  TempImage = GrabImage(Image,#PB_Any,ImageWidth(Image)-*data\Corner,*data\Corner,*data\Corner,*data\Height -*data\Corner*2 - Heigt * VLoop)
                EndIf
                If TempImage
                  DrawImage(ImageID(TempImage),*data\Width-*data\Corner,*data\Corner+Heigt*VLoop)   
                EndIf
            EndSelect
            ;Repeat middle's patern to fill the new image with
            If HLoop - (*data\Width - *data\Corner*2) / Width
              Hresult = Width
            Else
              Hresult = *data\Width -*data\Corner*2 - Width * HLoop
            EndIf
            If VLoop - (*data\Height - *data\Corner*2) / Heigt
              VResult = Heigt
            Else
              VResult = *data\Height -*data\Corner*2 - Heigt * VLoop
            EndIf
            TempImage = GrabImage(Image,#PB_Any,*data\Corner,*data\Corner,Hresult,VResult)
            If TempImage
              DrawImage(ImageID(TempImage),*data\Corner+Width*HLoop,*data\Corner+Heigt*VLoop)
            EndIf
          Next VLoop
        Next HLoop
        
      Case #Patch_Stretch ;Stretch the original image to the new Width and Height
        TempImage = GrabImage(Image,#PB_Any,*data\Corner,0,ImageWidth(Image)-*data\Corner*2,*data\Corner) ;Top horizontal
        DrawImage(ImageID(TempImage),*data\Corner,0,*data\Width-*data\Corner*2,*data\Corner)
        TempImage = GrabImage(Image,#PB_Any,*data\Corner,ImageHeight(Image)-*data\Corner,ImageWidth(Image)-*data\Corner*2,*data\Corner) ;Bottom horizontal
        DrawImage(ImageID(TempImage),*data\Corner,*data\Height-*data\Corner,*data\Width-*data\Corner*2,*data\Corner)
        TempImage = GrabImage(Image,#PB_Any,0,*data\Corner,*data\Corner,ImageHeight(Image)-*data\Corner*2) ;Left vertical
        DrawImage(ImageID(TempImage),0,*data\Corner,*data\Corner,*data\Height-*data\Corner*2)
        TempImage = GrabImage(Image,#PB_Any,ImageWidth(Image)-*data\Corner,*data\Corner,*data\Corner,ImageHeight(Image)-*data\Corner*2) ;Right vertial
        DrawImage(ImageID(TempImage),*data\Width-*data\Corner,*data\Corner,*data\Corner,*data\Height-*data\Corner*2)
        TempImage = GrabImage(Image,#PB_Any,*data\Corner,*data\Corner,ImageWidth(Image)-*data\Corner*2,ImageHeight(Image)-*data\Corner*2) ;Middle
        DrawImage(ImageID(TempImage),*data\Corner,*data\Corner,*data\Width-*data\Corner*2,*data\Height-*data\Corner*2)
    EndSelect
    StopDrawing()
  EndProcedure
  
  Procedure DrawCorner(Image,*data.patch)
    Protected TempImage
    ;Draw the 4 corners of the original image with no modification
    TempImage = GrabImage(Image,#PB_Any,0,0,*data\Corner,*data\Corner) ;Top left
    DrawImage(ImageID(TempImage),0,0)
    TempImage = GrabImage(Image,#PB_Any,ImageWidth(Image)-*data\Corner,0,*data\Corner,*data\Corner) ;Top right
    DrawImage(ImageID(TempImage),*data\Width-*data\Corner,0)
    TempImage = GrabImage(Image,#PB_Any,0,ImageHeight(Image)-*data\Corner,*data\Corner,*data\Corner) ;Bottom left
    DrawImage(ImageID(TempImage),0,*data\Height-*data\Corner)
    TempImage = GrabImage(Image,#PB_Any,ImageWidth(Image)-*data\Corner,ImageHeight(Image)-*data\Corner,*data\Corner,*data\Corner) ;Bottom right
    DrawImage(ImageID(TempImage),*data\Width-*data\Corner,*data\Height-*data\Corner)
  EndProcedure
  
EndModule
  CompilerIf #PB_Compiler_IsMainFile
    InitSprite()
    Global 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
User avatar
Demivec
Addict
Addict
Posts: 4086
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: 9 Patch

Post by Demivec »

Thanks for the code. I noticed a bug that will cause many problems if left uncorrected. Temporary images are not freed. With your sample code that displays 4 images, 90 temporary images are left unfreed.

I made corrections to the code to remove this bug and in the process did some simple formatting changes and some slight enhancements that were mostly for readability.

Here is the new code:

Code: Select all

;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 HLoop_max ;=======================Bottom horizontal=========================
                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 VLoop_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
Papala
User
User
Posts: 38
Joined: Wed Sep 12, 2012 5:09 pm

Re: 9 Patch

Post by Papala »

Demivec wrote:Temporary images are not freed. With your sample code that displays 4 images, 90 temporary images are left unfreed.
Wow how can i forgot about that.. Thx a lot for this fix Demivec ! Thank for the enhancements too :wink:

My turn to fix a bug in your code :

Code: Select all

;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
(Bug fix :"Select VLoop : Case 0 : Case HLoopMax" ===> "Select VLoop : Case 0 : Case VLoopMax")
User avatar
Demivec
Addict
Addict
Posts: 4086
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: 9 Patch

Post by Demivec »

Papala wrote:My turn to fix a bug in your code
Thanks for catching that. :)
Post Reply