Heya.. the following procedure "should" skin a Window using the Region method.
Assumptions made are 1)that the bmp is at least as large as the window,
and 2) that the topleft (0,0) pixel contains the colorkey to be used for "transparent" pixels (IE not included in the window region).

It's not working - I end up with NO pixels in my region and my window won't display at all... can anyone see why?

SkinWindow proc hWin, hBmp
local dwWidth
local dwHeight
local CursorX
local CursorY
local MyColour
local hRgn
local hpixelrgn
local rc:RECT
local hMemDC
local hDC

mov hDC ,$invoke (GetWindowDC,hWin) ;Get DeviceContext of target Window

invoke GetWindowRect,hWin ,addr rc ;Measure target Window
m2m dwWidth, rc.right
m2m dwHeight,rc.bottom

mov hMemDC,$invoke (CreateCompatibleDC,hDC) ;Create a DC to work with
invoke SelectObject,hMemDC,hBmp ;Select the bmp into our DC

xor eax,eax
mov CursorX,eax
mov CursorY,eax
mov MyColour,$invoke (GetPixel, hMemDC,CursorX,CursorY)
xor ebx,ebx
.while ebx<dwHeight
xor ebx,ebx
.while ebx<dwWidth
invoke GetPixel, hMemDC,CursorX,CursorY
.if eax!=MyColour ;if the pixel is NOT the keyed colour
mov eax,CursorX ;create a single-pixel Region
inc eax
mov ebx,CursorY
inc ebx
mov hpixelrgn,$invoke (CreateRectRgn, CursorX, CursorY, eax, ebx)
.if eax!=0
.if hRgn==0 ;if this is the first pixelregion ever processed
m2m hRgn,hpixelrgn ;just use it as the existing region
.else ;Combine the singlepixel Region with the existing Region
invoke CombineRgn, hRgn ,hRgn, hpixelrgn , RGN_OR
invoke DeleteObject, hpixelrgn
inc CursorX
mov ebx,CursorX
inc CursorY
mov ebx,CursorY
invoke SetWindowRgn,hWin,hRgn,TRUE
invoke DeleteDC,hMemDC
invoke ReleaseDC,hWin,hDC

SkinWindow endp

for the curious, I call the procedure from here:
.elseif uMsg==WM_CREATE
mov hBmp, $invoke (LoadBitmap,hInstance,801)
invoke SkinWindow, hWin, hBmp
Posted on 2004-09-08 02:07:00 by Homer

One obvious problem before any further digging into it:

invoke GetWindowRect,hWin ,addr rc ;Measure target Window
m2m dwWidth, rc.right
m2m dwHeight,rc.bottom

rc.right is NOT your window's width and rc.bottom is NOT your window's height. Subtract rc.left and rc.top respectively.

Posted on 2004-09-08 02:18:56 by akyprian
...not related to the bug, but the routine you're using is incredibly slow. There was some other thread around here a while ago (search for putpixel) that ends up with a very fast method.
Posted on 2004-09-08 07:52:06 by f0dder
The code I used to "measure" the window was ok in this instance (only because my application window's topleft corner coincides with the screen topleft corner at the moment of creation).
You are of course correct, and I modified the code to suit.

I rewrote the proc and it now works, I'll tidy it up and repost it, but I want to implement fast getpixel first.
Posted on 2004-09-09 02:45:10 by Homer
Don't base your algorithm around GetPixel - even if you write your own fast version. Have a look at http://www.asmcommunity.net/board/index.php?topic=17519
Posted on 2004-09-09 02:59:56 by f0dder
I did - didn't I say I did?
I have written this in the past as part of a DX support class (CTexture), the only difference being I was using D3DXCreateTexture to load the image.

Does this look ok to you?

;Bmp is loaded (we have hBmp)
;pbmi from GetDIBits
;pbits from CreateDIBSection

GetPixelQuick proc uses ebx esi pbmi, pbits, pX, pY
local bitsperpixel
local bytesperpixel
xor eax,eax
mov esi,pbmi
mov ax,[esi].BITMAPINFOHEADER.biBitCount
mov bitsperpixel,eax ;bits per pixel
shr eax,3 ;bits per pixel/8 = bytes per pixel
mov bytesperpixel,eax ;bytes per pixel
mov eax, [esi].BITMAPINFOHEADER.biWidth ;eax= pixels per scanline
mul bytesperpixel ;ImageWidth (in pixels) * bytes per pixel = bytes per scanline (aka Stride)
mul pY ;Stride * Y
push eax ;preserve bytes2skip (for Y only)
mov eax, pX
mul bytesperpixel ;eax=bytes2skip in X
pop ebx ;restore bytes2skip in Y
add eax,ebx ;eax = #bytes to skip in X and Y
add eax, pbits ;+baseaddress of bitdata
return dword ptr[eax] ;fetch pixeldata and return
GetPixelQuick endp
Posted on 2004-09-09 06:46:15 by Homer
If you are referring to horizontal scan regions instead of pure pixel tests, I'm already on it... but I still need to correctly calculate pixel colour data addresses based on the basepointer and pixel X and Y coords, so I still would like to know if that code looks good or not - I'm not in a position to test the code until much later today.
Posted on 2004-09-09 06:50:15 by Homer

I did - didn't I say I did?

If you're referring to GetPixel, you said but I want to implement fast getpixel first.

Does this look ok to you?

I haven't looked at it - you shouldn't have GetPixel as a proc... you should do the bitmap setup at start of the "create_region_from_bitmap", and work directly on the pixel data from there on.

If you are referring to horizontal scan regions instead of pure pixel tests, I'm already on it...

Good, that one helps a bunch too. And rather than using CombineRgn, you should create a bunch of RECTs and using the Ext* create region thingy. It helps somewhat too, but not as measurable... stil an optimization though.
Posted on 2004-09-09 08:09:51 by f0dder
Fill a crapload of RECTs, set up a RGNDATA (and header), throw it at ExtCreateRgn thingy, gotcha. I can see how it would be faster too, since each call to CombineRgn probably internally amounts to creating two 'rects' and combining them.
Posted on 2004-09-09 08:43:27 by Homer
I threw this together earlier :)

The following code is my version of the ExtCreateRegion thingy skinning method.I use a BufferManager object to help with the RGNDATA struct

RGNDATA struct
Buffer BYTE ? ;<--Buffer is meant to hold an array of RECT structs.

I'll cheat by shoving a RGNDATAHEADER struct into my cool magic buffer and then just shove each RECT into the buffer after it.
hehehe instant RGNDATA ready for the call to ExtCreateRegion 8)

@f0dder : The BufferManager is an oop object that wraps the paged HeapAlloc / HeapReAlloc functionality you have mentioned elsewhere.

;Returns hRegion or NULL=failed
MakeRegionList proc hBmp
local rgndatahdr:REGIONDATAHEADER
local pManager
local BoundingRect:RECT
set pManager as BufferManager
mov pManager, new (BufferManager)
mov rgndatahdr.dwSize,sizeof rgndatahdr
mov rgndatahdr.iType, RDH_RECTANGLES
xor eax,eax
mov rgndatahdr.nCount, eax ;<-- copy the #rects here later !!!
mov rgndatahdr.nRgnSize,eax ;<-- copy sizeof rects buffer here later !!!
mov rgndatahdr.rcBound.left,eax ;<-- copy Bounding Rect here later !!!
mov rgndatahdr.rcBound.right,eax
mov rgndatahdr.rcBound.top,eax
mov rgndatahdr.rcBound.bottom,eax
pcall pManager.Store, addr rgndatahdr, sizeof rgndatahdr ;store the header in the buffer
invoke EnlistRects, pManager, hBmp, addr BoundingRect ;returns #rects and BoundingRect
mov ebx,pManager
mov ecx,[ebx].BufferManager.pBuffer ;baseptr of buffer
mov [ecx].REGIONDATAHEADER.nCount, eax ;store #rects as returned from EnlistRects
mov eax,[ebx].BufferManager.dwWrite ;sizeof header+rects array
sub eax,sizeof REGIONDATAHEADER ;minus sizeof header
mov [ecx].REGIONDATAHEADER.nRgnSize, eax ;= sizeof rects array
m2m [ecx].REGIONDATAHEADER.rcBound.left, BoundingRect.left
m2m [ecx].REGIONDATAHEADER.rcBound.right, BoundingRect.right
m2m [ecx].REGIONDATAHEADER.rcBound.top, BoundingRect.top
m2m [ecx].REGIONDATAHEADER.rcBound.bottom, BoundingRect.bottom
invoke ExtCreateRegion,NULL,[ebx].BufferManager.dwWrite,[ebx].BufferManager.pBuffer
push eax
delete pManager
pop eax
MakeRegionList endp

Note to Hiro: can you please add .INC to the attachable filetypes? Thanks.
Posted on 2004-09-09 09:26:24 by Homer
and now I'm home I've also put this together.
(I'll finish it up later, it's been a long day)

EnlistRects proc pManager, hBmp, pBoundingRect ,MyColour
local numRects
local pBits
local CurrentX
local CurrentY
local dwWidth
local dwHeight
local Scanning
local Stride
local MyColour
local rc:RECT
set pManager as BufferManager

;get bmp width and height
mov pBits,eax
;calculate Stride

xor ebx,ebx
mov CurrentY,ebx
mov numRects,ebx
.while ebx<dwHeight
mov CurrentX,0
mov Scanning,FALSE
xor ebx,ebx
.while ebx<dwWidth
mov eax,CurrentY
mul Stride
push eax
mov eax,CurrentX
mul bpp
shr eax,3
add eax,pBits
pop ebx
add eax,ebx
.if dword ptr[eax]!=MyColour
.if Scanning==FALSE
mov Scanning,TRUE
mov eax,CurrentY
mov rc.top, eax
inc eax
mov rc.bottom, eax
m2m rc.left, CurrentX
.if Scanning==TRUE
mov Scanning,FALSE
m2m rc.right,CurrentX
pcall pManager.Store, addr rc, sizeof rc
inc numRects
inc CurrentX
mov ebx,CurrentX
inc CurrentY
mov ebx,CurrentY
return numRects
EnlistRects endp
Posted on 2004-09-09 10:02:55 by Homer
Just following this thread for the first time and throwing my 2 cents in.

By manually scanning the raw bitmap color bytes and creating a "group" of RECTs and using the ExtCreateRegion is by far the fastest method I have found.

I'll attach a few ASM files that I have made during the last six months or so that does what you are looking for. These are optimized routines for creating a HRGN.

To use these two ASM files, call the 'CreateRegionFromHBITMAP' function and pass it the HBITMAP, width, height, transparent color (should be NULL if you pass TRUE for UseFirstPixel) and wether to use the first pixel color or not (TRUE/FALSE).

Let me know if you have any questions about my code.

Posted on 2004-09-09 18:16:52 by Relvinian
Your code is practically the same as f0dder's, but interesting nonetheless. The pseudocode I posted yesterday is missing a stall for the end of each horizontal line, obviously I wrote it at a whim.
I'll push on with my variant and make it work :)
Posted on 2004-09-09 22:28:22 by Homer
I think it's cool how much alike mine and Relvinians code are :)
Posted on 2004-09-10 07:15:28 by f0dder