News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

IF Point in DWORD belongs to RECT

Started by The Svin, April 11, 2006, 01:07:23 AM

Previous topic - Next topic

The Svin

Point in DWORD means types of data that for example return in lParam of some WM_... from mouse senders.
Where low DWORD is x, high - y.
Please, look at the code I manage to write so far and tell me - if there is a way to make it smaller
(Please note bottom and right of RECT by defenition are boundry values that are not belong to RECT)

IfDwPtBelongsToRect proc dwPt,ptrRECT
mov eax,dwPt
mov edx,eax
and eax,0FFFFh ;eax=POINT.x
shr edx,16 ;edx=POINT.y
mov ecx,ptrRECT
assume ecx:ptr RECT
sub eax,[ecx].left
sub edx,[ecx].top
cmp eax,[ecx].right
sbb eax,eax
cmp edx,[ecx].bottom
sbb edx,edx
and eax,edx
;-1 if yes, 0 - no
ret

IfDwPtBelongsToRect endp

The Svin

Ooops.. I found an error in the code :)

The Svin

#2
Right way is something like that,though it's not short now :(
I forgot to say - It should be an unbranched code.

IfDwPtBelongsToRect proc uses ebx dwPt,ptrRECT
movzx eax,word ptr [dwPt]
movzx edx,word ptr [dwPt + 2]
mov ecx,ptrRECT
assume ecx:ptr RECT
mov ebx,[ecx].left
sub eax,ebx
sub ebx,[ecx].right
neg ebx
cmp eax,ebx
sbb eax,eax
mov ebx,[ecx].top
sub edx,ebx
sub ebx,[ecx].bottom
neg ebx
cmp edx,ebx
sbb edx,edx
and eax,edx
assume ecx:nothing
;-1 if yes, 0 - no
ret

IfDwPtBelongsToRect endp


Edit: First 4 lines replaced with new 2

asmfan

The Svin (sorry dont know your name),
may be cmp + cmov would be better? By the way why there shouldnt be a branching?

push   0
mov   eax, 1
...
cmp   ebx, [ecx].right
cmovae  eax, [esp]
...
add   esp, 4
ret
Russia is a weird place

The Svin

Could you give me full proc to explain what do you mean and  why it might be shorter?
Logic condition is
(dwPt(lowword) < POINT.right) & (dwPt(lowword) >=POINT.left) & (dwPt(highword) <POINT.bottom)&((dwPt(highword) >=POINT.top))
so with your approach you need to do 4 comparasions, placing somewhere results of it, then to do AND of them.
BTW. With your approach it's better to use SETCC rather than CMOVCC.


The Svin

I got IT!!! It's shame I didn't see it at once :))

IfDwPtBelongsToRect proc uses ebx dwPt,ptrRECT
movzx eax,word ptr [dwPt]
movzx edx,word ptr [dwPt + 2]
mov ecx,ptrRECT
assume ecx:ptr RECT
mov ebx,[ecx].left
sub eax,ebx
sub ebx,[ecx].right
add eax,ebx
sbb eax,eax
mov ebx,[ecx].top
sub edx,ebx
sub ebx,[ecx].bottom
add edx,ebx
sbb edx,edx
or eax,edx
assume ecx:nothing
;0 if yes, -1 - no
ret

IfDwPtBelongsToRect endp

The Svin

Another short version by leo, (I reduced the end a little bit)

IfDwPtBelongsToRect proc uses ebx dwPt,ptrRECT
  movzx eax,word ptr [dwPt]
  movzx edx,word ptr [dwPtr+2] 
  mov ecx,ptrRECT
assume ecx:ptr RECT
  mov ebx,eax
  sub eax,[ecx].left
  sub ebx,[ecx].right
  xor ebx,eax
  mov eax,edx
  sub edx,[ecx].top
  sub eax,[ecx].bottom
  xor eax,edx
  and eax,ebx
assume ecx:nothing
  ;not SF if no, SF - yes
  ret
IfDwPtBelongsToRect endp


Example of usage. Assume you create some rect with graphix, and you need to to know if mouse is over it
mygraphclientrect RECT <coordinates where you draw it>
...
.IF WM_MOUSEMOVE
invoke IfDwPtBelongsToRect,lParam,offset mygraphclientrect
.IF SIGN?
;do whatever you need when mouse over your rect
.ENDIF
.ENDIF

Or the user dblclicked your rect
WM_LBUTTONDBLCLK:
invoke IfDwPtBelongsToRect,lParam,offset mygraphclientrect
.IF SIGN?
;do whatever you need whenr your rect dblclicked

etc. Roger!

u

Uhm, the approach feels incorrect. When you have 50+ controls, that is.
For this purpose, I make a control-map: an array of some custom CTLRECT struct that has a RECT embedded. There branches are actually useful:

assume edx:ptr CTLRECT
mov edx,pCtrlMap
mov ebx,X
mov ecx,Y
sub edx,sizeof CTLRECT
@@:
add edx,sizeof CTLRECT
cmp [edx].CTLTYPE,CTLTYPE_ENDMARKER
je _ret
cmp ebx,[edx].left
jl @B
cmp ebx,[edx].right
jge @B
cmp ecx,[edx].top
jl @B
cmp ecx,[edx].bottom
jge @B

; ok, found rectangle
mov eax,edx
if FORWARD_Z_ORDER
jmp @B ; but still search for more :)
endif


assume edx:nothing



CTLRECT struct
left dd ?
top dd ?
right dd ?
bottom dd ?
CTL_ID dw ?
CTLTYPE db ?
cFlags db ?
CtlName dd ? ; (ptr to string), I use it for hints in statusbar
CTLRECT ends

You can make the RECT members from dword to word.
Ah, and now the following idea popped-up:


SRECT struct
left dw ?
right dw ?
top dw ?
bottom dw ?
SRECT ends


PX macro x
exitm <(x SHL 16) OR x>
endm

IsInside proc lParam,pRect
mov ecx,pRect
mov eax,PX(14) ; 000E000Eh
mov edx,PX(12) ; 000C000Ch
sub eax,dword ptr[ecx]
sub edx,dword ptr[ecx+4]
and eax,edx
and eax,0F000F000h
cmp eax,0F0000000h
.if ZERO?
print "inside"
.endif


ret
IsInside endp

Now, you figure how it'll be most convenient to replace the PX() macro ;)
(I'd precalculate the values, given lParam, and check all/most controls with a loop. Could be pretty damn fast? ^^)
Please use a smaller graphic in your signature.

The Svin

I asked for unbranched method.
Two people already questioned why I didn't want branched one, and nobody suggested new shorter unbranched method.
I would discuss branched vs. unbranched somewhere else.
Here I, if I may,I want a shorter unbrached one :)

u

Please re-read my post carefully, and do proper benchmarks, to compare against your own code. I gave you both a branching and a non-branching version, each of them faster than yours, when used correctly ;) (well, add an "align 16" in the first one). Also, note that the unbranched one might be shorter, too.
If you need this code for just a few rectangles, then it's a pity.

Btw, there's also a much faster method, but uses more RAM: a 2D array. You "draw" rectangles and whatever on it, and in a few cycles you can get the hit spot.
Please use a smaller graphic in your signature.

The Svin

Sorry, I missed it.
Yet I need shorter not faster :)
Thanx anyway :)