Window Regions awfully slow

Just starting out? Need help? Post your questions and find answers here.
Kris_a
User
User
Posts: 92
Joined: Sun Feb 15, 2004 8:04 pm
Location: Manchester, UK

Window Regions awfully slow

Post by Kris_a »

Hi,

I've been messing around with changing the shape of a window. This code works just how I want it to, but it's so horribly slow (takes over a second to do a 320x240 screen.. urgh!)... any ideas why?

Code: Select all

rgn1 = createrectrgn_(0,0,320,240)

For x = 0 To 319
   For y = 0 To 239
    
      If Random(10) = 0
         rgn2 = createrectrgn_(x,y,x+1,y+1)
         combinergn_(rgn1,rgn1,rgn2,#RGN_XOR)
         deleteobject_(rgn2)
      EndIf
      
   next
Next
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

It's slow because your creating 76,800 regions and combining that many as well...
The most efficient way is to perform your calculations only once and save the region to a file...
Write some routines to load a pre-made region from a file, it'll be much faster...

I'm not exactly sure how to do this but maybe it'll point you in the right direction :)
User avatar
Mischa
Enthusiast
Enthusiast
Posts: 115
Joined: Fri Aug 15, 2003 7:43 pm

Post by Mischa »

Hi!

Code: Select all

; Creates a .pbi file in the directory of a bitmap, which should
; be used as skin/background for a window...
; The created .pbi file will contain the calculated window mask data
; as well include the converted bitmap (into .png format).
; Note: an example for using the created .pbi file can be found at
; "WindowSkin_Example.pb" !


; (transparent color will be peeked at the upper right corner of image) 

Procedure WindowCallback(WindowID, Message, lParam, wParam) 
  If Message = #WM_PAINT 
    StartDrawing(WindowOutput()) 
      DrawImage(UseImage(1), 0, 0) 
    StopDrawing() 
  EndIf 
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 

UsePNGImageEncoder() 
UsePNGImageDecoder() 

Structure myBITMAPINFO 
  bmiHeader.BITMAPINFOHEADER 
  bmiColors.RGBQUAD[1] 
EndStructure 

Structure RGB 
  v.l 
EndStructure 

Procedure CreateMask() 
  hDC = StartDrawing(ImageOutput()) 
    main  = CreateRectRgn_(0,0,0,0) 
    picl_X = ImageWidth() 
    picl_Y = ImageHeight() 
    mem = AllocateMemory(1,picl_X*picl_Y*4,0) 
    bmi.myBITMAPINFO 
    bmi\bmiHeader\biSize   = SizeOf(BITMAPINFOHEADER) 
    bmi\bmiHeader\biWidth  = picl_X 
    bmi\bmiHeader\biHeight = picl_Y 
    bmi\bmiHeader\biPlanes = 1 
    bmi\bmiHeader\biBitCount = 32 
    bmi\bmiHeader\biCompression = #BI_RGB 
    GetDIBits_(hDC,ImageID(),1,picl_Y-1,mem,bmi,#DIB_RGB_COLORS) 
    *pixel.RGB = mem 
    trans.RGB 
    trans\v = *pixel\v 
    For ay=0 To picl_Y-2 
      For ax=0 To picl_X-1 
        If *pixel\v <> trans\v 
          sub = CreateRectRgn_(ax,picl_Y-ay-1,ax+1,picl_Y-ay-2) 
          CombineRgn_(main,main,sub,#RGN_OR) 
          DeleteObject_(sub) 
        EndIf 
        *pixel + 4 
      Next ax 
    Next ay 
  StopDrawing() 
  ProcedureReturn main 
EndProcedure 

file.s=OpenFileRequester("Open Bitmap","","Bitmap|*.bmp;*.png",0) 
If file 
  image=LoadImage(1,file) 
  w=ImageWidth():h=ImageHeight() 
  screenx=GetSystemMetrics_(#SM_CXSCREEN) 
  screeny=GetSystemMetrics_(#SM_CYSCREEN) 
  hwnd=OpenWindow(0,screenx,screeny,w,h,#WS_POPUP,"Mask-Image") 
  mask=CreateMask() 
  oldsize= GetRegionData_(mask,0,0) 
  *source= AllocateMemory(0,oldsize,0) 
  GetRegionData_(mask,oldsize,*source) 
  *target = AllocateMemory(1,oldsize+8,0) 
  newsize = PackMemory(*source,*target,oldsize,9) 
  newfile.s = ReplaceString(file,GetExtensionPart(file),"png") 
  SaveImage(1,newfile,#PB_ImagePlugin_PNG) 
  rest = newsize % 4 

  If CreateFile(0,ReplaceString(ReplaceString(file,GetFilePart(file),"MaskWindow_"+GetFilePart(file)),GetExtensionPart(file),"pbi")) 
    WriteStringN("UsePNGImageDecoder()")  
    WriteStringN("Procedure OpenMaskedWindow_"+Left(GetFilePart(file),Len(GetFilePart(file))-4)+"(winID,x,y,title.s,imID)") 
    WriteStringN("  hwnd=OpenWindow(winID,GetSystemMetrics_(#SM_CXSCREEN),y,"+Str(w)+","+Str(h)+",#WS_POPUP,title)") 
    WriteStringN("  memhandle=GlobalAlloc_(#GMEM_MOVEABLE,"+Str(oldsize+8)+")") 
    WriteStringN("  *mem=GlobalLock_(memhandle)") 
    WriteStringN("  UnpackMemory(?"+Left(GetFilePart(file),Len(GetFilePart(file))-4)+"_mask,*mem)") 
    WriteStringN("  region=ExtCreateRegion_(0,"+Str(oldsize)+",*mem)") 
    WriteStringN("  SetWindowRgn_(hwnd,region,#True)") 
    WriteStringN("  pic=CatchImage(imID,?"+Left(GetFilePart(file),Len(GetFilePart(file))-4)+")") 
    WriteStringN("  brush=CreatePatternBrush_(pic)") 
    WriteStringN("  SetClassLong_(hwnd,#GCL_HBRBACKGROUND,brush)")  
    WriteStringN("  MoveWindow(x,y)") 
    WriteStringN("  GlobalUnlock_(memhandle)") 
    WriteStringN("  GlobalFree_(memhandle)") 
    WriteStringN("  DeleteObject_(region)") 
    WriteStringN("  ProcedureReturn hwnd") 
    WriteStringN("  DataSection") 
    WriteStringN("  "+Left(GetFilePart(file),Len(GetFilePart(file))-4)+":") 
    WriteStringN("    IncludeBinary "+Chr(34)+GetFilePart(newfile)+Chr(34)) 
    WriteStringN("  "+Left(GetFilePart(file),Len(GetFilePart(file))-4)+"_mask:") 
    string.s="    Data.l " 
    For i=0 To newsize-4-rest Step 4 
      string+"$"+LSet(Hex(PeekL(*target+i)),8," ") 
      count+1 
      If count=10 
        count=0 
        WriteStringN(string) 
        string="    Data.l " 
      Else 
        string+"," 
      EndIf 
    Next i 
    If count 
      string=Left(string,Len(string)-1) 
      WriteStringN(string) 
    EndIf 
    If rest 
      string="    Data.b " 
      For i=newsize-rest To newsize-1 
        string+"$"+Hex(PeekB(*target+i))+"," 
      Next i 
      string=Left(string,Len(string)-1) 
      WriteStringN(string) 
    EndIf 
    WriteStringN("  EndDataSection") 
    WriteStringN("EndProcedure") 
    CloseFile(0) 
    MessageRequester(".pbi file created!","Press right mousekey to leave.",0) 
  Else 
    MessageRequester("Error!","Can't create '"+ReplaceString(ReplaceString(file,GetFilePart(file),"MaskWindow_"+GetFilePart(file)),GetExtensionPart(file),"pbi'"),0) 
  EndIf 

  SetWindowRgn_(hwnd,mask,#True) 
  MoveWindow((screenx-w)/2,(screeny-h)/2) 
  SetWindowCallback(@WindowCallback()) 
    
  Repeat 
    Select WaitWindowEvent() 
      Case #WM_LBUTTONDOWN 
        SendMessage_(hwnd,#WM_NCLBUTTONDOWN, #HTCAPTION,0) 
      Case #WM_RBUTTONDOWN 
        Quit=1 
    EndSelect 
  Until Quit=1 
  DeleteObject_(mask) 
EndIf 

Code: Select all

; Example for including the Include-file created by "WindowSkin_Generator.pb".
; You must change the 'name' at IncludeFile and OpenMaskedWindow_xxx to the 
; right image/file name!



IncludeFile "MaskWindow_name.pbi" 

hwnd=OpenMaskedWindow_name(0,50,50,"Test",0) 
;OpenMaskedWindow_hiername(WindowID,x,y,title,ImageID) 

Repeat 
  Select WaitWindowEvent() 
    Case #WM_LBUTTONDOWN 
      SendMessage_(hwnd,#WM_NCLBUTTONDOWN, #HTCAPTION,0) 
    Case #WM_RBUTTONDOWN ;right mousekey -> end 
      Quit=1 
  EndSelect 
Until Quit=1 
regards,
Mischa
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Window Regions awfully slow

Post by Kwai chang caine »

I have try to translate this code in 5.11.
That works, but i have just a part of the picture in the PBI created, and i not understand why :shock:
If someone can help me :cry:
Thanks in advance 8)

Code: Select all

Procedure WindowCallBack(WindowId, Message, lParam, wParam) 
 
 If Message = #WM_PAINT 
  StartDrawing(WindowOutput(0)) 
  DrawImage(ImageID(1), 0, 0) 
  StopDrawing() 
 EndIf 
 
 ProcedureReturn #PB_ProcessPureBasicEvents 

EndProcedure 

UsePNGImageEncoder() 
UsePNGImageDecoder()
UseJPEGImageDecoder()
UseJPEGImageEncoder()
UseBriefLZPacker()

Structure myBITMAPINFO 
 bmiHeader.BITMAPINFOHEADER 
 bmiColors.RGBQUAD[1] 
EndStructure 

Structure RGB 
 v.l 
EndStructure 

Procedure CreateMask() 

 hDC = StartDrawing(ImageOutput(1)) 
 main  = CreateRectRgn_(0,0,0,0) 
 picl_X = ImageWidth(1) 
 picl_Y = ImageHeight(1) 
 mem = AllocateMemory(picl_X*picl_Y*4) 
 bmi.myBITMAPINFO 
 bmi\bmiHeader\biSize   = SizeOf(BITMAPINFOHEADER) 
 bmi\bmiHeader\biWidth  = picl_X 
 bmi\bmiHeader\biHeight = picl_Y 
 bmi\bmiHeader\biPlanes = 1 
 bmi\bmiHeader\biBitCount = 32 
 bmi\bmiHeader\biCompression = #BI_RGB 
 GetDIBits_(hDC,ImageID(1),1,picl_Y-1,mem,bmi,#DIB_RGB_COLORS) 
 *pixel.RGB = mem 
 trans.RGB 
 trans\v = *pixel\v 
 
 If Blue (trans\v)=255 And Green (trans\v)=0 And Red (trans\v)=0 : messag$= " -> Rouge" 
 ElseIf Blue (trans\v)=0 And Green (trans\v)=255 And Red (trans\v)=0 : messag$= " -> Vert" 
 ElseIf Blue (trans\v)=0 And Green (trans\v)=0 And Red (trans\v)=255 : messag$= " -> Bleu" 
 ElseIf Blue (trans\v)=255 And Green (trans\v)=255 And Red (trans\v)=255 : messag$= " -> Blanc" 
 ElseIf Blue (trans\v)=0 And Green (trans\v)=0 And Red (trans\v)=0 : messag$= " -> Noir" 
 EndIf 
 coulon = MessageRequester ( "Sélection de la couleur du masque" , "Couleur détectée : " + "Rouge : " + Str ( Blue (trans\v))+ " ; Vert : " + Str ( Green (trans\v))+ " ; Bleu : " + Str ( Red (trans\v))+messag$+ Chr (13)+ Chr (13)+ "Acceptez-vous cette couleur? (Oui : Utiliser la couleur ; Non : Ouvrir la palette de couleur)" , #PB_MessageRequester_YesNo ) 
 If coulon<>6 
 trans\v = ColorRequester () 
 trans\v = RGB ( Blue (trans\v), Green (trans\v), Red (trans\v)) 
 EndIf 
 
 For ay=0 To picl_Y-2 
 
  For ax=0 To picl_X-1 
 
   If *pixel\v <> trans\v 
    sub = CreateRectRgn_(ax,picl_Y-ay-1,ax+1,picl_Y-ay-2) 
    CombineRgn_(main,main,sub,#RGN_OR) 
    DeleteObject_(sub) 
   EndIf 
 
   *pixel + 4 
 
  Next ax 
 
 Next ay 
 
 StopDrawing() 
 ProcedureReturn main 
 
EndProcedure 

File.s = OpenFileRequester("Open Bitmap","","Bitmap|*.bmp;*.png",0) 

If File 

 Image = LoadImage(1, File) 
 w = ImageWidth(1)
 h = ImageHeight(1) 
 ScreenX = GetSystemMetrics_(#SM_CXSCREEN) 
 ScreenY = GetSystemMetrics_(#SM_CYSCREEN) 
 HWnd = OpenWindow(0, screenx, screeny, w, h, "Mask-Image", #WS_POPUP) 
 Mask = CreateMask() 
 Oldsize = GetRegionData_(Mask, 0, 0) 
 *Source = AllocateMemory(Oldsize) 
 GetRegionData_(mask,oldsize,*Source) 
 *Target = AllocateMemory(Oldsize + 8) 
 ;Newsize = PackMemory(*Source,*Target,Oldsize,9)
 Newsize = CompressMemory(*Source, Oldsize, *Target, Oldsize + 8, #PB_Packer_BriefLZ)
 Newfile.s = ReplaceString(GetFilePart(File), GetExtensionPart(File),"png") 
 SaveImage(1, Newfile, #PB_ImagePlugin_PNG) 
 Rest = Newsize % 4 
 NomFenetre.s = Left(GetFilePart(File),Len(GetFilePart(File)) - 4)
 File = ReplaceString(GetFilePart(File),GetExtensionPart(File),"pbi")
 
 If CreateFile(0, File) 
 
  WriteStringN(0,"UsePNGImageDecoder()")
  WriteStringN(0,"UseBriefLZPacker()")
  WriteStringN(0,"") 
  WriteStringN(0,"Procedure OpenMaskedWindow_" + NomFenetre + "(WinID, x, y, Title.s, imID)") 
  WriteStringN(0,"") 
  WriteStringN(0," Hwnd" + NomFenetre + " = OpenWindow(winID, GetSystemMetrics_(#SM_CXSCREEN), y, " + Str(w) + ", " + Str(h) + ", Title, #WS_POPUP)") 
  WriteStringN(0," Memhandle = GlobalAlloc_(#GMEM_MOVEABLE," + Str(Oldsize + 8) + ")") 
  WriteStringN(0," *Mem = GlobalLock_(Memhandle)") 
  ;WriteStringN(0," UnpackMemory(?" + NomFenetre + "_Mask, *Mem)") 
  WriteStringN(0," UncompressMemory(?" + NomFenetre + "_Mask, " + Trim(Str(Newsize)) + ", *Mem," + Trim(Str(Oldsize)) + ")") 
  WriteStringN(0," Region = ExtCreateRegion_(0," + Str(Oldsize) + ", *Mem)") 
  WriteStringN(0," SetWindowRgn_(Hwnd" + NomFenetre + ", Region, #True)") 
  WriteStringN(0," Pic = CatchImage(imID,?" + NomFenetre +")") 
  WriteStringN(0," Brush = CreatePatternBrush_(Pic)") 
  WriteStringN(0," SetClassLong_(Hwnd" + NomFenetre + ", #GCL_HBRBACKGROUND, Brush)")  
  WriteStringN(0," ResizeWindow(WinID, x, y, #PB_Ignore, #PB_Ignore)") 
  WriteStringN(0," GlobalUnlock_(Memhandle)") 
  WriteStringN(0," GlobalFree_(Memhandle)") 
  WriteStringN(0," DeleteObject_(Region)") 
  WriteStringN(0," ProcedureReturn Hwnd" + NomFenetre) 
  WriteStringN(0,"") 
  WriteStringN(0," DataSection") 
  WriteStringN(0,"") 
  WriteStringN(0,"  " + Left(GetFilePart(File),Len(GetFilePart(File)) - 4)+":") 
  WriteStringN(0,"  ;***********") 
  WriteStringN(0,"") 
  WriteStringN(0,"  IncludeBinary " + Chr(34) + GetFilePart(Newfile) + Chr(34)) 
  WriteStringN(0,"") 
  WriteStringN(0,"  " + Left(GetFilePart(File),Len(GetFilePart(File)) - 4) + "_Mask:")
  WriteStringN(0,"  ;***********")  
  WriteStringN(0,"") 
  String.s = "  Data.l " 
 
  For i = 0 To Newsize - 4 - Rest Step 4 
  
   String + "$" + LSet(Hex(PeekL(*Target + i)),8," ") 
   Count + 1 
 
   If Count = 10 
    Count = 0 
    WriteStringN(0, String) 
    String = "  Data.l " 
   Else 
    String + "," 
   EndIf 
 
  Next i 
  
  If Count 
   String = Left(String, Len(String) - 1) 
   WriteStringN(0, String) 
  EndIf 
  
  WriteStringN(0,"") 
  WriteStringN(0," EndDataSection") 
  WriteStringN(0,"") 
  WriteStringN(0,"EndProcedure")
  WriteStringN(0,"")
  WriteStringN(0,"OpenMaskedWindow_PicText(WinID, x, y, Title.s, imID)")
  WriteStringN(0,"MessageRequester(" + Chr(34) + Chr(34) + ", " + Chr(34) + "Escape pour sortir" + Chr(34) + ")")
  WriteStringN(0,"Repeat : Evenement = WaitWindowEvent() :Until GetAsyncKeyState_(#VK_ESCAPE)")
  CloseFile(0) 
  MessageRequester("Fichier .pbi créé!","Cliquez droit pour sortir.",0) 
 
 Else 
 
  MessageRequester("Error!", "Can't create '"+ ReplaceString(ReplaceString(file, GetFilePart(file),"MaskWindow_" + GetFilePart(file)),GetExtensionPart(file),"pbi'"),0) 
 
 EndIf 

 SetWindowRgn_(hwnd, mask, #True) 
 ResizeWindow(0,(screenx - w) / 2,(screeny - h) / 2, #PB_Ignore, #PB_Ignore) 
 SetWindowCallback(@WindowCallback()) 
    
 Repeat 
 
  Select WaitWindowEvent() 
   Case #WM_LBUTTONDOWN 
    SendMessage_(hwnd,#WM_NCLBUTTONDOWN, #HTCAPTION,0) 
   Case #WM_RBUTTONDOWN 
    Quit=1 
  EndSelect 
  
 Until Quit=1 
 
 DeleteObject_(mask) 
 
EndIf  

End
ImageThe happiness is a road...
Not a destination
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Window Regions awfully slow

Post by netmaestro »

Here's a procedure to create a region from a bitmap, it's very quick. Use a 32bit PNG for this version of the routine or you can modify it easily to use a transparent color instead:

Code: Select all

ProcedureDLL GrabRegion(ImageID) ; HBITMAP ImageID

  ;=======================================================
  ;                                                      =
  ;      Very fast bitmap -> region creator              =
  ;                                                      =
  ;      By netmaestro                                   =
  ;                                                      =
  ;      Contributors: eesau, nico, flype                =
  ;                                                      =
  ;      June 26, 2007                                   =
  ;                                                      =
  ;=======================================================
 
  Structure RECTARRAY
    rect.RECT[0]
  EndStructure

  GetObject_(ImageID, SizeOf(BITMAP), @bmp.BITMAP)
 
  Protected width       = bmp\bmWidth
  Protected height      = bmp\bmHeight
  Protected hVisibleRgn = CreateRectRgn_(0, 0, width, height)
 
  BmiInfo.BITMAPINFOHEADER
  With BmiInfo
    \biSize         = SizeOf(BITMAPINFOHEADER)
    \biWidth        = width
    \biHeight       = -height
    \biPlanes       = 1
    \biBitCount     = 32
    \biCompression  = #BI_RGB
  EndWith   
 
  rowbytes =  SizeOf(LONG)*width

  *ColorBits = AllocateMemory(rowbytes*height)
 
  hDC   = GetWindowDC_(#Null)
  iRes  = GetDIBits_(hDC, ImageID, 0, height, *ColorBits, @bmiInfo, #DIB_RGB_COLORS)
  ReleaseDC_(#Null, hDC)
 
  Structure_Max=(width*height*SizeOf(RECT))+SizeOf(RGNDATAHEADER)
  *Buffer.RGNDATAHEADER=AllocateMemory(Structure_Max)
  *rd.RECTARRAY=*Buffer+SizeOf(RGNDATAHEADER)

  rectcount = 0
  For y=0 To height-1
    pxcount=0
    For x=0 To rowbytes-1 Step 4
      *px.RGBQUAD = *ColorBits + rowbytes * y + x
      If *px\rgbReserved = 0 
        transcount = 1 : firsttrans = pxcount
        x+SizeOf(LONG) : *px.RGBQUAD = *ColorBits + rowbytes * y + x
        While *px\rgbReserved = 0 And x <= rowbytes-1
          transcount+1 : pxcount+1 : x+SizeOf(LONG)
          *px = *ColorBits + rowbytes * y + x
        Wend
        x-SizeOf(LONG) : *px.RGBQUAD = *ColorBits + rowbytes * y + x
        *rd\rect[rectcount]\left   = firsttrans           
        *rd\rect[rectcount]\top    = y                     
        *rd\rect[rectcount]\right  = firsttrans+transcount
        *rd\rect[rectcount]\bottom = y+1     
        rectcount+1
      EndIf
      pxcount+1
    Next
  Next
 
  With *Buffer
    \dwSize         = SizeOf(RGNDATAHEADER)
    \iType          = #RDH_RECTANGLES
    \nCount         = rectcount
    \nRgnSize       = rectcount * SizeOf(RECT)
    \rcBound\left   = 0
    \rcBound\top    = 0
    \rcBound\right  = width
    \rcBound\bottom = height
  EndWith
 
  RegionSize=SizeOf(RGNDATAHEADER)+(rectcount * SizeOf(RECT))
  hTransparentRgn = ExtCreateRegion_(0, RegionSize, *Buffer)
  CombineRgn_(hVisibleRgn, hVisibleRgn, hTransparentRgn, #RGN_XOR)
   
  FreeMemory(*Buffer)
  FreeMemory(*ColorBits)
  DeleteObject_(hTransparentRgn)
 
  ProcedureReturn hVisibleRgn
 
EndProcedure 
BERESHEIT
User avatar
em_uk
Enthusiast
Enthusiast
Posts: 366
Joined: Sun Aug 08, 2010 3:32 pm
Location: Manchester UK

Re: Window Regions awfully slow

Post by em_uk »

Hey nice to see a fellow Mancunian on here :)

KCC, change line 96 to :

Code: Select all

Newsize = CompressMemory(*Source, Oldsize, *Target, Oldsize + 8, #PB_PackerPlugin_BriefLZ)
----

R Tape loading error, 0:1
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Window Regions awfully slow

Post by Kwai chang caine »

@Netmaestro
Thanks a lot For your code, i use it start To now 8)

So i try To recompile an old big code, that i have create there are some years.
And With the new lib it's impossible :cry:

It's more "simple" for me, to just translate the old code, if it's possible obviously....so when i say "simple", it's not really the good word..because nothing is really simple with KCC :oops:

@em_uk
Thanks To your line...I have not see the #PB_PackerPlugin_BriefLZ exist, just the #PB_Packer_BriefLZ is in the doc, even in the 5.20 :shock:
The problem is with the PBI created by the code after run it
When you run the code the picture appears correctly, that works 8)
But, when you run the PBI who use the PNG created by the code, it's here the problem, the "NameOfPicture.pbi" not works :cry:

Thanks again at you two, for your help 8)
ImageThe happiness is a road...
Not a destination
Post Reply