News:

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

SetWorldTransform example, image/DC rotation

Started by qWord, September 18, 2011, 06:37:08 PM

Previous topic - Next topic

qWord

hi,

in the attachment an example I want to share with you. It shows how to use SetWorldTransform for rotating a bitmap.
There are three functions in the source, which could be reused directly:
QuoteRotateBitBltAtD -> copy rotated rectangle from source-DC to destination-DC; angel in degree.
RotateBitBltAtR -> same as RotateBitBltAtD, except that the angle is in radian
GdiSetRot       -> rotate DC's world transform at specified position

qWord
FPU in a trice: SmplMath
It's that simple!

xandaz

   Now... that's a very good example... What if you had some controls inside the client area, lets say buttons that control the the direction of the rotation, and you needed to reduce the screen DC's dimensions. How'd  you do that? I was trying that with SetWindow/Viewport/Org/Offset but nothing seems to work. Thanks

qWord

As I've said in your other thread, I would suggest you to use StretchBlt() for this task - see the the attachment.

qWord
FPU in a trice: SmplMath
It's that simple!

xandaz

   oops...i'm sorry for my persistance... ty

qWord

the same as previous example, but additionally allows to drag the image.
(dragging: left mouse button, zooming: with mouse wheel)
FPU in a trice: SmplMath
It's that simple!

FORTRANS

Hi,

   Very nice qWord.  Something to look at.

   On my Windows 2000 system the executable won't run (...
is not a valid Win32 application).  If I assemble it, it runs nicely.
Do you know what is happening?

Regards,

Steve N.

qWord

Quote from: FORTRANS on September 19, 2011, 12:03:32 PMIf I assemble it, it runs nicely.
Do you know what is happening?
I know that there are incompatibilities with Win2K/98, but I don't know the details ...  just curious, that you are using a 11/12 years old OS  :snooty:
Maybe someone here knows a secret linker option to break this incompatibility   :bg
(ml/link v10.xx)

regards, qWord
FPU in a trice: SmplMath
It's that simple!

xandaz

   hi there qw. I was wondering if you could explain a little better how the xform members work on rotation. This test i was coding doesnt rotate tho i've seen detailed information about it on:http://edais.mvps.org/Tutorials/GDI/DC/DCch8.html
   thanks

MichaelW

Back before I got covered up with my work work, I was working on a dialog app that would allow me to more easily experiment with the XFORM members. I'm still not finished with it, but I did finish a (crude) MASM32 in-memory dialog version of the example here.

;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================

;-----------------------------------------------------------------
; Note that the MASM32 version of the XFORM structure:
;   http://msdn.microsoft.com/en-us/library/dd145228(VS.85).aspx
; Uses ex and ey for the last two members.
;-----------------------------------------------------------------

;==============================================================================

R4TOVAR MACRO var:REQ, value:REQ
    fld4 value
    fstp var
ENDM

SAR1ADD MACRO arg1:REQ, arg2:REQ
    LOCAL lbl
    .data
        lbl dd ?
    .code
    mov eax, arg1
    sar eax, 1
    add eax, arg2
    mov lbl, eax
    EXITM <lbl>
ENDM

;==============================================================================

SCALE     equ 0
TRANSLATE equ 1
ROTATE    equ 2
SHEAR     equ 3
REFLECT   equ 4
NORMAL    equ 5

;==============================================================================
    .data
        hMenu       dd 0
        hActionMenu dd 0
    .code
;==============================================================================

TransformAndDraw proc uses ebx hWnd:DWORD, transform:DWORD

    LOCAL hDC:DWORD, xForm:XFORM, rc:RECT

    invoke GetDC, hWnd
    mov hDC, eax
    print str$(hDC),13,10
    invoke SetGraphicsMode, hDC, GM_ADVANCED
    print str$(eax),13,10

    invoke SetMapMode,hDC, MM_LOENGLISH
    print str$(eax),13,10
    SWITCH transform
        CASE SCALE
            ; Scale to 1/2 of the original size.
            R4TOVAR xForm.eM11, 0.5
            R4TOVAR xForm.eM12, 0.0
            R4TOVAR xForm.eM21, 0.0
            R4TOVAR xForm.eM22, 0.5
            R4TOVAR xForm.ex, 0.0
            R4TOVAR xForm.ey, 0.0
            invoke SetWorldTransform, hDC, ADDR xForm
            print str$(eax),13,10
        CASE TRANSLATE
            ; Translate right by 3/4 inch.
            R4TOVAR xForm.eM11, 1.0
            R4TOVAR xForm.eM12, 0.0
            R4TOVAR xForm.eM21, 0.0
            R4TOVAR xForm.eM22, 1.0
            R4TOVAR xForm.ex, 75.0
            R4TOVAR xForm.ey, 0.0
            invoke SetWorldTransform, hDC, ADDR xForm
        CASE ROTATE
            ; Rotate 30 degrees counterclockwise.
            R4TOVAR xForm.eM11, 0.8660
            R4TOVAR xForm.eM12, 0.5000
            R4TOVAR xForm.eM21, -0.5000
            R4TOVAR xForm.eM22, 0.8660
            R4TOVAR xForm.ex, 0.0
            R4TOVAR xForm.ey, 0.0
            invoke SetWorldTransform, hDC, ADDR xForm
        CASE SHEAR
            ; Shear along the x-axis with a proportionality constant of 1.0.
            R4TOVAR xForm.eM11, 1.0
            R4TOVAR xForm.eM12, 1.0
            R4TOVAR xForm.eM21, 0.0
            R4TOVAR xForm.eM22, 1.0
            R4TOVAR xForm.ex, 0.0
            R4TOVAR xForm.ey, 0.0
            invoke SetWorldTransform, hDC, ADDR xForm
        CASE REFLECT
            ;  Reflect about a horizontal axis.
            R4TOVAR xForm.eM11, 1.0
            R4TOVAR xForm.eM12, 0.0
            R4TOVAR xForm.eM21, 0.0
            R4TOVAR xForm.eM22, -1.0
            R4TOVAR xForm.ex, 0.0
            R4TOVAR xForm.ey, 0.0
            invoke SetWorldTransform, hDC, ADDR xForm
        CASE NORMAL
            ; Set the unity transformation.
            R4TOVAR xForm.eM11, 1.0
            R4TOVAR xForm.eM12, 0.0
            R4TOVAR xForm.eM21, 0.0
            R4TOVAR xForm.eM22, 1.0
            R4TOVAR xForm.ex, 0.0
            R4TOVAR xForm.ey, 0.0
            invoke SetWorldTransform, hDC, ADDR xForm
    ENDSW

    ; Find the midpoint of the client area.

    invoke GetClientRect, hWnd, ADDR rc
    invoke DPtoLP, hDC, ADDR rc, 2

    ; Select a hollow brush.

    invoke GetStockObject, HOLLOW_BRUSH
    invoke SelectObject, hDC, eax

    ; Draw the exterior circle.

    invoke Ellipse, hDC, SAR1ADD(rc.right, -100),
                         SAR1ADD(rc.bottom, 100),
                         SAR1ADD(rc.right, 100),
                         SAR1ADD(rc.bottom, -100)

    ; Draw the interior circle.

    invoke Ellipse, hDC, SAR1ADD(rc.right, -94),
                         SAR1ADD(rc.bottom, 94),
                         SAR1ADD(rc.right, 94),
                         SAR1ADD(rc.bottom, -94)

    ; Draw the key.

    invoke Rectangle, hDC, SAR1ADD(rc.right, -13),
                           SAR1ADD(rc.bottom, 113),
                           SAR1ADD(rc.right, 13),
                           SAR1ADD(rc.bottom, 50)

    invoke Rectangle, hDC, SAR1ADD(rc.right, -13),
                           SAR1ADD(rc.bottom, 96),
                           SAR1ADD(rc.right, 13),
                           SAR1ADD(rc.bottom, 50)

    ; Draw the horizontal lines.

    invoke MoveToEx, hDC, SAR1ADD(rc.right, -150),
                          SAR1ADD(rc.bottom, 0), NULL
    invoke LineTo, hDC, SAR1ADD(rc.right, -16),
                        SAR1ADD(rc.bottom, 0)
    invoke MoveToEx, hDC, SAR1ADD(rc.right, -13),
                          SAR1ADD(rc.bottom, 0), NULL
    invoke LineTo, hDC, SAR1ADD(rc.right, 13),
                        SAR1ADD(rc.bottom, 0)
    invoke MoveToEx, hDC, SAR1ADD(rc.right, 16),
                          SAR1ADD(rc.bottom, 0), NULL
    invoke LineTo, hDC, SAR1ADD(rc.right, 150),
                        SAR1ADD(rc.bottom, 0)

    ; Draw the vertical lines.

    invoke MoveToEx, hDC, SAR1ADD(rc.right, 0),
                          SAR1ADD(rc.bottom, -150), NULL
    invoke LineTo, hDC, SAR1ADD(rc.right, 0),
                        SAR1ADD(rc.bottom, -16)
    invoke MoveToEx, hDC, SAR1ADD(rc.right, 0),
                          SAR1ADD(rc.bottom, -13), NULL
    invoke LineTo, hDC, SAR1ADD(rc.right, 0),
                        SAR1ADD(rc.bottom, 13)
    invoke MoveToEx, hDC, SAR1ADD(rc.right, 0),
                          SAR1ADD(rc.bottom, 16), NULL
    invoke LineTo, hDC, SAR1ADD(rc.right, 0),
                        SAR1ADD(rc.bottom, 150)

    invoke ReleaseDC, hWnd, hDC

    ret

TransformAndDraw endp

;==============================================================================
DialogProc proc hwndDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

    SWITCH uMsg
        CASE WM_INITDIALOG
            invoke CreateMenu
            mov hMenu, eax
            invoke CreateMenu
            mov hActionMenu, eax
            invoke AppendMenu, hMenu, MF_POPUP, hActionMenu, chr$("Action")
            invoke AppendMenu, hActionMenu, MF_STRING, 1000, chr$("SCALE")
            invoke AppendMenu, hActionMenu, MF_STRING, 1001, chr$("TRANSLATE")
            invoke AppendMenu, hActionMenu, MF_STRING, 1002, chr$("ROTATE")
            invoke AppendMenu, hActionMenu, MF_STRING, 1003, chr$("SHEAR")
            invoke AppendMenu, hActionMenu, MF_STRING, 1004, chr$("REFLECT")
            invoke AppendMenu, hActionMenu, MF_STRING, 1005, chr$("NORMAL")
            invoke AppendMenu, hActionMenu, MF_STRING, 1006, chr$("Clear")
            invoke SetMenu, hwndDlg, hMenu
        CASE WM_CTLCOLORDLG
            invoke GetStockObject, WHITE_BRUSH
            ret
        CASE WM_COMMAND
            SWITCH wParam
                CASE 1000
                    invoke TransformAndDraw, hwndDlg, SCALE
                CASE 1001
                    invoke TransformAndDraw, hwndDlg, TRANSLATE
                CASE 1002
                    invoke TransformAndDraw, hwndDlg, ROTATE
                CASE 1003
                    invoke TransformAndDraw, hwndDlg, SHEAR
                CASE 1004
                    invoke TransformAndDraw, hwndDlg, REFLECT
                CASE 1005
                    invoke TransformAndDraw, hwndDlg, NORMAL
                CASE 1006
                    invoke InvalidateRect, hwndDlg, NULL, TRUE
                CASE IDCANCEL
                    invoke EndDialog, hwndDlg, NULL
            ENDSW
        CASE WM_CLOSE
            invoke EndDialog, hwndDlg, NULL
    ENDSW

    return 0

DialogProc endp
;==============================================================================
start:
;==============================================================================
    Dialog "Test", \
           "MS Sans Serif",10, \
            WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
            0, \
            0,0,200,200, \
            1024
    invoke GetModuleHandle, NULL
    CallModalDialog eax, 0, DialogProc, NULL
    exit
;==============================================================================
end start

eschew obfuscation

qWord

There are some errors:
- think about usage of hBackDC and hMemDC
- SetTimer is used incorrect: invoke  SetTimer,hWnd,SOME_ID,20,0
- the transformation must applied to the destination-DC
- the FPU only knows radian values

Quote from: xandaz on December 04, 2011, 11:20:03 PMI was wondering if you could explain a little better how the xform members work on rotation.
A good explanation of the members in context to the transformations can be found here.
If you want to rotate around a specific point (=rotation center), three steps are required:
1. move the rotation center into the point of origin (0|0) -> translation matrix
2. rotate around point of origin -> this is what a rotation matrix does
3. move the the rotation center back to it home position -> translation matrix

Each of the above steps is described by matrix:
      1   0  0
A =   0   1  0
    -dx -dy  1
   
     cos(a)   sin(a)  0
B =  -sin(a)  cos(a)  0
       0      0      1
   
     1  0  0
C =  0  1  0
    dx dy  1


If you combine these matrices using matrix multiplication, you get the needed matrix:
M = A*B*C
You can do this numerical, by declaring the three matrices and then multiply them using CombineTransform() (the order of multiplications is importend: first mul. A with B and the intermediate result with C!).
The folowing matrix is the result of the symbolic computation:
                       cos(a)                  sin(a)  0
M =                   -sin(a)                  cos(a)  0
    (dx-cos(a)*dx+sin(a)*dy) (dy-cos(a)*dy-sin(a)*dx)  1

The corresponding XFORM:
xform.eM11 =  cos(a)
xform.eM12 =  sin(a)
xform.eM21 = -sin(a)
xform.eM22 =  cos(a)
xform.ex = dx-cos(a)*dx+sin(a)*dy
xform.ey = dy-cos(a)*dy-sin(a)*dx
FPU in a trice: SmplMath
It's that simple!