News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Rotation

Started by stefan.velicu, March 30, 2014, 06:34:45 PM

Previous topic - Next topic

stefan.velicu

Thank you very much, vertograd.

stefan.velicu

Now, that I have the .bmp's pixels in esi, how can I rotate them by a specific degree?

P.S.: I've found something like

[xo yo]=[x y]*[cos(p) sin(p); -sin(p) cos(p)]
, for Matlab
Is that ok?

Gunther

Hi Stefan,

Quote from: stefan.velicu on March 31, 2014, 01:47:11 AM
P.S.: I've found something like

[xo yo]=[x y]*[cos(p) sin(p); -sin(p) cos(p)]
, for Matlab
Is that ok?

that's okay. It's the rotation matrix. p is the angle.

Gunther
You have to know the facts before you can distort them.

jj2007

x' = x*cos(u)-y*sin(u)
y' = x*sin(u)-y*cos(u)
where : x' = is new x position, x - previous x position, u - angle in radians.

(posted yesterday in the Pelles C Forum)

Note there is an instruction called fsincos. Very useful ;-)

qWord

#19
Quote from: jj2007 on March 31, 2014, 04:00:48 AM
x' = x*cos(u)-y*sin(u)
y' = x*sin(u)-y*cos(u)
where : x' = is new x position, x - previous x position, u - angle in radians.

(posted yesterday in the Pelles C Forum)
The formula is wrong and that is the reason why that guy get deformed objects :-D
It should be y' = x*sin(u)+y*cos(u).

For the rotation it is important to transform the destination coordinates to source coordinates and not vice versa. A short example:
include \masm32\include\masm32rt.inc
.686
.mmx
.xmm
;DEBUG = 1

WndProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

IDT EQU 100

XMMPS typedef OWORD
XMMLPS typedef QWORD

WND_DATA struct
    hbmpImage   HBITMAP ?
    angle       REAl4 ?
WND_DATA ends

MATRIX2D struct
    m11 REAl4 ?
    m12 REAl4 ?
    m21 REAl4 ?
    m22 REAl4 ?
    m31 REAl4 ?
    m32 REAl4 ?
MATRIX2D ends
PMATRIX2D typedef ptr MATRIX2D

.data?
    g_hInstance HINSTANCE ?
.code
main proc
LOCAL wcex:WNDCLASSEX
LOCAL msg:MSG

    mov g_hInstance,rv(GetModuleHandle,0)
    mov wcex.hInstance,eax
    mov wcex.cbSize,SIZEOF WNDCLASSEX
    mov wcex.style, CS_HREDRAW or CS_VREDRAW
    mov wcex.lpfnWndProc, OFFSET WndProc
    mov wcex.cbClsExtra,NULL
    mov wcex.cbWndExtra,SIZEOF WND_DATA
    mov wcex.hbrBackground,0
    mov wcex.lpszMenuName,NULL
    mov wcex.lpszClassName,chr$("win32class")
    mov wcex.hIcon,rv(LoadIcon,NULL,IDI_APPLICATION)
    mov wcex.hIconSm,eax
    mov wcex.hCursor,rv(LoadCursor,NULL,IDC_ARROW)
    fn RegisterClassEx, &wcex
    fn CreateWindowEx,0,wcex.lpszClassName,"pixrot",WS_VISIBLE or WS_SYSMENU or WS_SIZEBOX or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_CLIPCHILDREN,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,g_hInstance,0

    .while 1
        .break .if !rv(GetMessage,&msg,0,0,0)
        fn TranslateMessage, &msg
        fn DispatchMessage, &msg
    .endw

    invoke ExitProcess,msg.wParam

main endp


mul_matrix proc pResult:PMATRIX2D,pA:PMATRIX2D,pB:PMATRIX2D
   
    mov eax,pResult
    mov ecx,pA
    mov edx,pB
   
    movups xmm3,XMMPS ptr [edx]
    movlps xmm7,XMMLPS ptr [edx+16]
    movups xmm0,XMMPS ptr [ecx]
    movlps xmm2,XMMLPS ptr [ecx+16]
    movaps xmm1,xmm0
    shufps xmm3,xmm3,11011000y
    movlhps xmm7,xmm7
    movlhps xmm0,xmm0
    movhlps xmm1,xmm1
    movlhps xmm2,xmm2
    mulps xmm0,xmm3
    mulps xmm1,xmm3
    mulps xmm2,xmm3
    movaps xmm3,xmm0
    movaps xmm4,xmm1
    movaps xmm5,xmm2
    shufps xmm3,xmm3,11110101y
    shufps xmm4,xmm4,11110101y
    shufps xmm5,xmm5,11110101y
    addps xmm0,xmm3
    addps xmm1,xmm4
    addps xmm2,xmm5
    shufps xmm0,xmm1,10001000y
    shufps xmm2,xmm2,11101000y
    addps xmm2,xmm7
    movups XMMPS ptr [eax],xmm0
    movlps XMMLPS ptr [eax+16],xmm2
   
    ret
   
mul_matrix endp


rot_matrix proc pResult:PMATRIX2D,angle:REAL4
LOCAL sincos[2]:REAl4
   
    mov eax,pResult
   
    .const
        align 16
        ps_neg1 REAL4 0.0,80000000r,0.0,0.0
    .code

    fld angle
    fsincos
    fstp sincos[0]
    fstp sincos[4]
    xorps xmm1,xmm1
    movlps xmm0,XMMLPS ptr sincos
    shufps xmm0,xmm0,00010100y
    xorps xmm0,XMMPS ptr ps_neg1
    movups XMMPS ptr [eax],xmm0
    movlps XMMLPS ptr [eax+16],xmm1
   
    ret
   
rot_matrix endp

;/**
; * Rotates the bitmap hBmp around relative point (cx_,cy) and draw
; * to hdc at postion (x,y)=upper left corner of org. bitmap.
; */
draw_image proc uses esi edi ebx hdc:HDC,hBmp:HBITMAP,x:SDWORD,y:SDWORD,cx_:SDWORD,cy:SDWORD,angle:REAl4,bkColor:DWORD
LOCAL matrix1:MATRIX2D
LOCAL matrix2:MATRIX2D
LOCAL matrix3:MATRIX2D
LOCAL hMemDC:HDC
LOCAL bmpinfo:BITMAPINFO
LOCAL bmp:BITMAP,w:SDWORD,h:SDWORD,wm:SDWORD,cr:SDWORD
LOCAL tmpBmp:HBITMAP
IFDEF DEBUG
    LOCAL cb:DWORD
ENDIF
    .const
        align 16
        ps_identity REAL4 1.0,0.0,0.0,1.0
        ps_neg12    REAL4 80000000r,80000000r,0.0,0.0
        ps_mul2     REAL4 2.0,2.0,0.0,0.0
        ps_c0       REAl4 1.0,1.0,1.0,1.0
        ps_msk1     REAl4 0.0,0ffffffffr,0.0,0ffffffffr
        ps_c1       REAl4 0.0,2.0,0.0,2.0
        ps_c2       REAl4 2.0,0.0,2.0,0.0
    .code
   
    ; angle = -( angle % 2pi )
    fld1
    fldpi
    fscale
    fld angle
    fprem
    fchs
    fstp angle
    fstp st
    fstp st
   
    ;/**
    ; * Transformations:
    ; *   - translate (-cx,-cy)
    ; *   - rotate (angle)
    ; *   - translate (cx,cy)
    ; */
    fn rot_matrix,&matrix2,angle
    ;/* setup translation matrices */
    xorps xmm0,xmm0
    movaps xmm1,XMMPS ptr ps_identity
    cvtpi2ps xmm0,QWORD ptr cx_
    mulps xmm0,XMMPS ptr ps_mul2
    movaps xmm2,xmm0
    xorps xmm0,XMMPS ptr ps_neg12
    movups XMMPS ptr matrix1,xmm1
    movlps XMMLPS ptr matrix1.m31,xmm0
    movups XMMPS ptr matrix3,xmm1
    movlps XMMLPS ptr matrix3.m31,xmm2
    ;/* combine transformations */
    fn mul_matrix,&matrix1,&matrix1,&matrix2
    fn mul_matrix,&matrix1,&matrix1,&matrix3
   
    ;/* get bitmap dimensions */
    fn GetObject,hBmp,BITMAP,&bmp
    mov ecx,bmp.bmWidth
    mov edx,bmp.bmHeight
    mov eax,edx
    .if SDWORD ptr eax < 0
        neg eax
    .endif
    mov w,ecx
    mov h,eax
    lea ecx,[ecx*DWORD]
    mov wm,ecx
   
    mov bmpinfo.bmiHeader.biSize,SIZEOF BITMAPINFO.bmiHeader
    mrm bmpinfo.bmiHeader.biWidth,bmp.bmWidth
    ;/* get top-down bitmap */
    .if SDWORD ptr edx > 0
        neg edx
    .endif
    mrm bmpinfo.bmiHeader.biHeight,edx
    mov bmpinfo.bmiHeader.biPlanes,1
    mov bmpinfo.bmiHeader.biBitCount,32
    mov bmpinfo.bmiHeader.biCompression,BI_RGB
    xor eax,eax
    mov bmpinfo.bmiHeader.biSizeImage,eax
    mov bmpinfo.bmiHeader.biXPelsPerMeter,eax
    mov bmpinfo.bmiHeader.biYPelsPerMeter,eax
    mov bmpinfo.bmiHeader.biClrUsed,eax
    mov bmpinfo.bmiHeader.biClrImportant,eax
   
    mov edx,w
    imul edx,h
    lea edx,[edx*4]
    IFDEF DEBUG
        mov cb,edx
    ENDIF
    push edx
    mov edi,alloc(edx) ; destination bitmap
    pop edx
    mov esi,alloc(edx) ; source bitmap
   
    fn GetDIBits,hdc,hBmp,0,h,esi,&bmpinfo,DIB_RGB_COLORS
   
    ;/* prepare matrix for mul. with transposed vector v=(x,y,1) */
    movups xmm6,XMMPS ptr matrix1
    shufps xmm6,xmm6,11011000y
    movlps xmm7,XMMLPS ptr matrix1.m31
    shufps xmm7,xmm7,01010000y
       
    ;/* xmm0 hold the x and y coordinates (mul. by 2) */
    movaps xmm0,XMMPS ptr ps_c0 ; xmm0 = {x=1,y=1,x=1,y=1}
   
    xor eax,eax
    xor ecx,ecx
    mov cr,eax
    .while eax < h
        xor ebx,ebx
        .while ebx < w
           
            ;/**
            ; * get source coordinate from current
            ; * destination coordinate (in xmm0).
            ; * (x,y)=v*matrix1
            ; */
            movaps xmm1,xmm0
            mulps xmm1,xmm6
            movaps xmm2,xmm1
            shufps xmm2,xmm2,11110101y
            addps xmm1,xmm2
            addps xmm1,xmm7 ; xmm1 = {-,ySrc,-,xSrc}
           
            ;/**
            ; * If the source coordinate is in range of the bitmap
            ; * copy the pixel data - otherwise store background color.
            ; *
            ; *   if( 0 <= (xs=RN(xSrc)/2) < w && 0 <= (ys=RN(ySrc)/2) < h)
            ; *      dest[x+y*w] = src[xs+ys*w];
            ; *   else
            ; *      dest[x+y*w] = bkColor;
            ; *
            ; * RN() = round to nearest, ties to even.
            ; */
            movhlps xmm2,xmm1
            cvtss2si eax,xmm1
            cvtss2si edx,xmm2
            .repeat
                shr eax,1
                shr edx,1
                .if SDWORD ptr eax >= 0 && eax < w
                    .if SDWORD ptr edx >= 0 && edx < h
                        lea eax,[eax*4]
                        imul edx,wm
                        lea eax,[eax+edx]
                        IFDEF DEBUG
                            .if eax >= cb
                                int 3
                            .endif
                        ENDIF
                        mov eax,[esi+eax]
                        mov [edi+ecx],eax
                        .break
                    .endif
                .endif
                 mrm DWORD ptr [edi+ecx],bkColor
            .until 1

            addps xmm0,ps_c2    ; xmm0 = {x=x+1,y,x=x+1,y}
            add ecx,DWORD
            add ebx,1
        .endw
        andps xmm0,XMMPS ptr ps_msk1
        addps xmm0,XMMPS ptr ps_c1      ; xmm0 = {x=0,y=y+1,x=0,y=y+1}
        mov eax,cr
        add eax,1
        mov cr,eax
    .endw
   
    free esi
    fnx hMemDC = CreateCompatibleDC,hdc
    fnx tmpBmp = CreateCompatibleBitmap,hdc,w,h
    fn SetDIBits,hdc,tmpBmp,0,h,edi,&bmpinfo,DIB_RGB_COLORS
    free edi
    fnx tmpBmp = SelectObject,hMemDC,tmpBmp
    fn BitBlt,hdc,x,y,w,h,hMemDC,0,0,SRCCOPY
    fnx tmpBmp = SelectObject,hMemDC,tmpBmp
    fn DeleteDC,hMemDC
    fn DeleteObject,tmpBmp
   
    ret
   
draw_image endp

WndProc proc uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL ps:PAINTSTRUCT
LOCAL bmp:BITMAP
LOCAL angle:REAL4
LOCAL rect:RECT
LOCAL hdc:HDC,hBmp:HBITMAP

    .if uMsg == WM_CLOSE
        invoke DestroyWindow,hWnd
    .elseif uMsg == WM_DESTROY
        invoke DeleteObject,rv(GetWindowLong,hWnd,WND_DATA.hbmpImage)
        invoke PostQuitMessage,NULL
    .elseif uMsg == WM_CREATE
        .if rvx(ebx=LoadImage,0,"image.bmp",IMAGE_BITMAP,0,0,LR_DEFAULTSIZE or LR_LOADFROMFILE)
            invoke SetWindowLong,hWnd,WND_DATA.hbmpImage,ebx
            invoke SetTimer,hWnd,IDT,60,0
            xor eax,eax
        .else
            or eax,-1
        .endif
    .elseif uMsg == WM_TIMER && wParam == IDT
        invoke InvalidateRect,hWnd,0,0
        fnx angle = GetWindowLong,hWnd,WND_DATA.angle
        movss xmm0,angle
        addss xmm0,FP4(0.01)
        movss angle,xmm0
        fn SetWindowLong,hWnd,WND_DATA.angle,angle
        xor eax,eax
    .elseif uMsg == WM_PAINT
        fn GetClientRect,hWnd,&rect
        fn BeginPaint,hWnd,&ps
        fnx ebx = GetWindowLong,hWnd,WND_DATA.hbmpImage
        fnx angle = GetWindowLong,hWnd,WND_DATA.angle
       
        ;/* create offscreen buffer */
        fnx hBmp = CreateCompatibleBitmap,ps.hdc,rect.right,rect.bottom
        fnx hdc = CreateCompatibleDC,ps.hdc
        fnx hBmp = SelectObject,hdc,hBmp
       
        ;/* fill background */
        fn BitBlt,hdc,0,0,rect.right,rect.bottom,ps.hdc,0,0,PATCOPY
       
        fn GetObject,ebx,BITMAP,&bmp
        mov edx,bmp.bmHeight
        .if SDWORD ptr edx < 0
            neg edx
        .endif
        mov ecx,bmp.bmWidth
        shr edx,1
        shr ecx,1
       
        ;/* draw image */
        fn draw_image,hdc,ebx,10,10,ecx,edx,angle,0
       
        ;/* buffer -> screen-DC */
        invoke BitBlt,ps.hdc,0,0,rect.right,rect.bottom,hdc,0,0,SRCCOPY
       
        ;/* delete buffer */
        fnx hBmp = SelectObject,hdc,hBmp
        fn DeleteObject,hBmp
        fn DeleteDC,hdc
       
        fn EndPaint,hWnd,&ps
        xor eax,eax
    .else
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
    .endif
    ret
WndProc endp
end main


EDIT: fix a +-1 bug and rounding issues.
MREAL macros - when you need floating point arithmetic while assembling!

nevraxSMD

qWord  :t you just  made my life a whole lot easier :D :t

jj2007

Quote from: qWord on March 31, 2014, 04:37:49 AM
Quote from: jj2007 on March 31, 2014, 04:00:48 AM
x' = x*cos(u)-y*sin(u)
y' = x*sin(u)-y*cos(u)
where : x' = is new x position, x - previous x position, u - angle in radians.

(posted yesterday in the Pelles C Forum)
The formula is wrong and that is the reason why that guy get deformed objects :-D
It should be y' = x*sin(u)+y*cos(u).

I didn't check that - I was just surprised that exactly the same topic pops up at the same time in two different forums. Maybe half of the class had to do it in C, the other in Asm ;-)

Gunther

Hi Jochen,

Quote from: jj2007 on March 31, 2014, 05:02:59 AM
I didn't check that ...

but qWord did and he's right.

Quote from: jj2007 on March 31, 2014, 05:02:59 AM
I was just surprised that exactly the same topic pops up at the same time in two different forums. Maybe half of the class had to do it in C, the other in Asm ;-)

that could be the reason. By the way, the right formula was already written in post #16 and 17. It's co-ordinate style.

The background of the entire thing is the rotation matrix:



cos (u)  -sin (u)
sin (u)   cos (u)
It lets your point with the co-ordinates (x;y) rotate by the angle u into the counter-clockwise direction. The following matrix:



cos (u)  sin (u)
-sin (u)   cos (u)
lets the same point rotate by the angle u into the clockwise direction. So you could do for the mathematical positive direction:

x' = x*cos(u) - y*sin(u)
y' = x*sin(u) + y*cos(u)

or for the clockwise direction:

x' = x*cos(u) + y*sin(u)
y' = -x*sin(u) + y*cos(u)


Both formulae are sometimes useful.

Gunther
You have to know the facts before you can distort them.

stefan.velicu

Thank you qWord. Sorry, but is a hard time for me to understand the program :D. Please, could you tell me how could I stop the rotation when reaching the proper angle?

Again, thank you very much, cheers!

RuiLoureiro

#24
Hi
we may use The calculator to see the results:

Point= (1,2)
Angle= 90 degrees

vetA=[ 1.0 ; 2.0];
matR=[ cosd(90), -sind(90); sind(90), cosd(90)];
matS=[ cosd(90), sind(90); -sind(90), cosd(90)];

vetB=matR*vetA;
vetC=matS*vetA;

we get:
            vetB=[ -2.0 ;1.0];
            vetC=[2.0   ; -1.0];

We may use complex numbers also.

qWord

If upload new code above that fix rounding issues and a bug that cause read access outside the BMP data.
Quote from: stefan.velicu on April 01, 2014, 05:34:41 AM
Thank you qWord. Sorry, but is a hard time for me to understand the program :D
Actual the algorithm is very simple:
for each row in destination bitmap
{
    for each pixel (x,y) in current row
    {
        transform (x,y) to source coordinate (xs,ys);
        if( 0 <= xs < bmpWidth && 0 <= ys < bmpHeight )
             dest[x+bmpWidth*h] = src[xs+bmpWidth*hs];
        else
             dest[x+bmpWidth*h] = background color;
    }
}

For coordinates the pixel centers are used and not the upper left corner - means e.g. that the upper left pixel in the bitmap has the coordinate (0.5,0.5). Remarks that the new uploaded code does scale all coordinates by 2, to avoid rounding problems due to the limited precision.
For the XMM instruction see Iintel's and/or AMD's documentation.

Quote from: stefan.velicu on April 01, 2014, 05:34:41 AMPlease, could you tell me how could I stop the rotation when reaching the proper angle?
just call the function with the wished angle-parameter.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: qWord on April 01, 2014, 08:55:59 AM
Quote from: stefan.velicu on April 01, 2014, 05:34:41 AMPlease, could you tell me how could I stop the rotation when reaching the proper angle?
just call the function with the wished angle-parameter.

Search the source for SetTimer, and have a look at line 345:

addss xmm0, FP4(0.01)  ; FP4 is a macro: Add Single precision xmm0, 0.01


Very nicely done, qWord :t

Farabi

Hi, if you wanted to do manual rotation it is simle

x=sin(x)*witdhFromCenter
y=cos(x)*widthFromCenter

But I think you can use GPU for this so the computation will be very very fast.
http://farabidatacenter.url.ph/MySoftware/
My 3D Game Engine Demo.

Contact me at Whatsapp: 6283818314165

RuiLoureiro

#28
Quote from: jj2007 on March 31, 2014, 04:00:48 AM
x' = x*cos(u)-y*sin(u)
y' = x*sin(u)-y*cos(u)
where : x' = is new x position, x - previous x position, u - angle in radians.

(posted yesterday in the Pelles C Forum)

Note there is an instruction called fsincos. Very useful ;-)

:biggrin:
Hi Jochen,

When we want to rotate a complex number z
we need only to multiply it by e^ia
where 'a' is the rotation angle.

One point (x,y) may be seen as z=x+iy.

If 'a' is positive, we rotate it in the positive sense
(to the left); If 'a' is negative, we rotate it
in the negative sense (to the right).

Let be

    1. z=x+i
    2. r=e^ia = cos(a)+i sin(a)
    3. w=x'+iy' is the rotated complex number

To rotate z, we multiply it by r:

       w= (x+iy)*[cos(a)+i sin(a)]                   (i^2=-1)
        =
          [x*cos(a)-y*sin(a)]+i[x*sin(a)+y*cos(a)]

So, we get the following equation system
(the real part of w must be equal to the real part
and the imaginary part of w must be equal to the imaginary part)

     x'= x*cos(a)-y*sin(a)                 ( Equation system A )

     y'= x*sin(a)+y*cos(a)

In matricial form, we have this:

   | x' | = | cos(a)    -sin(a) | * | x |
   |    |    |                           |    |   |
   | y' |    | sin(a)     cos(a) |    | y |
   
To rotate in the negative sense, use '-a':

     x'= x*cos(-a)-y*sin(-a)       (note that cos(-a)=cos(a)
                                                          and sin(-a)=-sin(a))
     y'= x*sin(-a)+y*cos(-a)         

<=>

     x'= x*cos(a)+y*sin(a)                 ( Equation system A' )

     y'=-x*sin(a)+y*cos(a)
:t

RuiLoureiro

#29
Hi
    something more about rotation
   
So, when we want to transform (x,y) into (u,v),
we use

     x*cos(a)-y*sin(a) = u      ( Equation system A )

     x*sin(a)+y*cos(a) = v

Inverting this equation system, we have

     u*cos(a)+v*sin(a) = x      ( Equation system B )

    -u*sin(a)+v*cos(a) = y

which is, of course, «Equation system A'».
(we may get it from Equation system A changing x by u, y by v and a by -a)

It means this:

    if we start from a point (x,y)=(1,2)
    and we want to rotate it 90 degrees (a=90)
    to the left, using «Equation system A»
    we get the point (u,v)=(-2,1).
   
    Now, if we start from this last point (x,y)=(-2,1)
    and we want to rotate it -90 degrees (a=-90)
    to the left (we go to the right ), using
    «Equation system A» we get the first point (x,y)=(1,2).

    In the same way, if we use «Equation system B»
    with the same a=90 and the last point (u,v)=(-2,1)
    we get (x,y)=(1,2).