一个真正的3D图形,用鼠标拖动......,请用ml6.15以上版本编译. By ham(于2007-10-30发表)

;简单的的3D图形,用鼠标拖动变换。
;制作人:ham
;算法100原创
        .386
        .xmm
        .model flat,stdcall
        option casemap:none
include        windows.inc
include        gdi32.inc
includelib    gdi32.lib
include        user32.inc
includelib    user32.lib
include        kernel32.inc
includelib    kernel32.lib
        .data?
VectorR        db    16 dup(?)
VectorL        db    16 dup(?)
VectorT        db    16 dup(?)
VectorA        db    16 dup(?)
VectorB        db    16 dup(?)
MoveX        dd        ?
MoveY        dd        ?
Move1X        dd        ?
Move1Y        dd        ?
shield        dd        ?
DownJh        dd        ?
hInstance    dd        ?
hWinMain    dd        ?
lpBmp        dd        ?
hdc        dd        ?

        .data
VectorU        dd    1.0,  0.0,  0.0,  0;屏幕x轴参考向量
VectorV        dd    0.0,  1.0,  0.0,  0;屏幕y轴参考向量
x        dd        -100.0;马鞍函数x轴变量
y        dd        -100.0;马鞍函数y轴变量
z        dd        ?;马鞍函数z轴变量
        dd        ?
        
        .const
add4        dd    4.0
szClassName    db    'My 3D',0
szCaptionMain    db    '3D Graph(鼠标左键按下拖动改变方向)',0

        .code
Projection    proc    lpVectorU,lpVectorV,lpVectorR
;此函数用来求VectorU向量在VectorV上的投影向量VectorR
        mov    esi,lpVectorU
        mov    edi,lpVectorV
        mov    ebx,lpVectorR
        movaps    XMM0,[esi]
        movaps    XMM1,[edi]
        movaps    XMM6,[edi]
        mulps    XMM0,XMM1
        mulps    XMM1,XMM1
        pshufd    XMM2,XMM0,1
        pshufd    XMM3,XMM0,2
        pshufd    XMM4,XMM1,1
        pshufd    XMM5,XMM1,2
        addss    XMM0,XMM2
        addss    XMM1,XMM4
        addss    XMM0,XMM3
        addss    XMM1,XMM5
        divss    XMM0,XMM1
        pshufd    XMM1,XMM0,0
        mulps    XMM6,XMM1
        movaps    [ebx],XMM6
        ret
Projection    endp

VectorAbs    proc    lpVector
;此函数用来求向量的模长,返回在eax中
        local    @ABS
        mov    esi,lpVector
        movaps    XMM0,[esi]
        mulps    XMM0,XMM0
        pshufd    XMM2,XMM0,1
        pshufd    XMM3,XMM0,2
        addss    XMM0,XMM2
        addss    XMM0,XMM3
        movd    @ABS,XMM0
        finit
        fld    @ABS
        fsqrt
        fst    @ABS
        mov    eax,@ABS
        ret
VectorAbs    endp

VecMul        proc    lpVectorU,lpVectorV,lpVectorR
;此函数用来求向量VectorU与向量VectorV的叉乘,结果放入lpVectorR指定的内存中
        mov    esi,lpVectorU
        mov    edi,lpVectorV
        mov    ebx,lpVectorR
        pshufd    XMM0,[esi],10000110b
        pshufd    XMM1,[edi],00101001b
        pshufd    XMM2,[esi],0001b
        pshufd    XMM3,[edi],0100b
        mulps    XMM0,XMM1
        mulps    XMM2,XMM3
        movapd    XMM4,XMM0
        shufps    XMM4,XMM2,011101b
        shufps    XMM0,XMM2,001000b
        subps    XMM4,XMM0
        movaps    [ebx],XMM4
        ret
VecMul        endp

SetBmpPixel    proc    lpBitMap,_x,_y
;把指定的点坐标设置到位图中
        mov    edi,lpBitMap
        mov    eax,dword ptr[edi+4]
        mov    ebx,_x
        mov    ecx,_y
        mul    ecx
        add    eax,ebx
        shl    eax,2
        mov    dword ptr[edi+eax+40],0
        ret
SetBmpPixel    endp

Function    proc    lpVector
;马鞍函数或者自行编辑空间函数
        mov    edi,lpVector
        finit
        fld    dword ptr[edi+4]
        fld    dword ptr[edi]
        fmul    st(0),st(0)
        fxch
        fmul    st(0),st(0)
        fsub
        fdiv    div100
        fst    dword ptr[edi+8]
        ret
div100        dd    100.0
Function    endp

IntstAngle    proc    lpVectorU,lpVectorV
;用来求两条向量夹角的余弦值
        local    @ls
        local    @ls1
        local    @ls2
        mov    esi,lpVectorU
        mov    edi,lpVectorV
        invoke    VectorAbs,esi
        mov    ebx,eax
        invoke    VectorAbs,edi
        mov    esi,lpVectorU
        movd    XMM4,ebx
        movd    XMM5,eax
        movaps    XMM0,[esi]
        mulps    XMM0,[edi]
        pshufd    XMM1,XMM0,1
        pshufd    XMM2,XMM0,2
        mulss    XMM4,XMM5
        addss    XMM0,XMM2
        addss    XMM0,XMM1
        divss    XMM0,XMM4
        movd    eax,XMM0
        ret
IntstAngle    endp

Circumgyrate    proc
;对参考平面(屏幕)进行变换坐标
        local    ls
        local    ls1
        mov    shield,1
        mov    eax,Move1X
        mov    ebx,Move1Y
        sub    eax,MoveX
        sub    ebx,MoveY
        mov    ls,eax
        mov    ls1,ebx
        finit
        fild    ls
        fld    rad
        fdiv
        fsincos
        fld    dword ptr VectorU
        fld    dword ptr VectorU+4
        fld    dword ptr VectorU+8
        fmul    st(0),st(3)
        fstp    dword ptr VectorA+8
        fmul    st(0),st(2)
        fstp    dword ptr VectorA+4
        fmul
        fstp    dword ptr VectorA
        fld    dword ptr VectorR
        fld    dword ptr VectorR+4
        fld    dword ptr VectorR+8
        fmul    st(0),st(3)
        fstp    dword ptr VectorB+8
        fmul    st(0),st(2)
        fstp    dword ptr VectorB+4
        fmul
        fstp    dword ptr VectorB
        movaps    XMM0,VectorA
        addps    XMM0,VectorB
        movaps    VectorU,XMM0
        invoke    VecMul,addr VectorU,addr VectorV,addr VectorR;计算屏幕法向量
        finit
        fild    ls1
        fld    rad
        fdiv
        fsincos
        fld    dword ptr VectorV
        fld    dword ptr VectorV+4
        fld    dword ptr VectorV+8
        fmul    st(0),st(3)
        fstp    dword ptr VectorA+8
        fmul    st(0),st(2)
        fstp    dword ptr VectorA+4
        fmul
        fstp    dword ptr VectorA
        fld    dword ptr VectorR
        fld    dword ptr VectorR+4
        fld    dword ptr VectorR+8
        fmul    st(0),st(3)
        fstp    dword ptr VectorB+8
        fmul    st(0),st(2)
        fstp    dword ptr VectorB+4
        fmul
        fstp    dword ptr VectorB
        movaps    XMM0,VectorA
        addps    XMM0,VectorB
        movaps    VectorV,XMM0
        invoke    VecMul,addr VectorU,addr VectorV,addr VectorR;计算屏幕法向量
        mov    shield,0
        ret
rad        dd        100.0
Circumgyrate    endp

_ProcWinMain    proc    uses ebx edi esi hWnd,uMsg,wParam,lParam
        local    ls
        local    ls1
        local    ls2
        mov    eax,uMsg
        .if    eax ==    WM_TIMER
            cmp    shield,0
            jnz    exit
            push    y
            mov    ebx,50
            lp:
            push    ebx
            push    x
            mov    ecx,50
            @@:
            push    ecx
            invoke    Function,addr x;设置函数的z轴坐标
            invoke    VecMul,addr x,addr VectorR,addr VectorL
            invoke    VecMul,addr VectorL,addr VectorR,addr VectorT
            invoke    Projection,addr x,addr VectorT,addr VectorT
            ;=============================================================
            invoke    VectorAbs,addr VectorT
            mov    ls,eax
            invoke    IntstAngle,addr VectorT,addr VectorU
            mov    ls1,eax
            invoke    IntstAngle,addr VectorT,addr VectorV
            mov    ls2,eax
            finit
            fld    ls
            fld    ls1
            fld    ls
            fld    ls2
            fmul
            fistp    ls2
            fmul
            fistp    ls1
            add    ls2,300
            add    ls1,300
            ;此时ls1是屏幕x轴坐标,ls2是屏幕y轴坐标
            invoke    SetBmpPixel,lpBmp,ls1,ls2;把计算好的象素坐标设置到32bit位图中
            ;=============================================================
            finit
            fld    x
            fadd    add4
            fst    x
            pop    ecx
            dec    ecx
            jnz    @b
            pop    x
            finit
            fld    y
            fadd    add4
            fst    y
            pop    ebx
            dec    ebx
            jnz    lp
            pop    y
            mov    edi,lpBmp
            mov    ecx,lpBmp
            mov    edx,lpBmp
            add    ecx,40
            invoke    SetDIBitsToDevice,hdc,0,0,dword ptr[edi+4],dword ptr[edi+8],0,0,0,\
                dword ptr[edi+8],ecx,edx,DIB_RGB_COLORS
            mov    edi,lpBmp
            mov    ecx,600*600
            mov    eax,-1
            add    edi,40
            rep    stosd
            exit:
        .elseif    eax ==    WM_MOUSEMOVE
            cmp    DownJh,0
            jz    @f
            mov    eax,lParam
            mov    edx,lParam
            and    eax,0ffffh
            shr    edx,16
            mov    MoveX,eax
            mov    MoveY,edx
            push    eax
            push    edx
            invoke    Circumgyrate
            pop    Move1Y
            pop    Move1X
            @@:
        .elseif    eax ==    WM_LBUTTONDOWN
            invoke    SetTimer,hWnd,1,1,0
            mov    DownJh,1
            mov    eax,lParam
            mov    edx,lParam
            and    eax,0ffffh
            shr    edx,16
            mov    Move1X,eax
            mov    Move1Y,edx
        .elseif    eax ==    WM_LBUTTONUP
            invoke    KillTimer,hWnd,1
            mov    DownJh,0
        .elseif    eax ==    WM_NCMOUSEMOVE
            invoke    KillTimer,hWnd,1
            mov    DownJh,0
        .elseif    eax ==    WM_CREATE
            invoke    VecMul,addr VectorU,addr VectorV,addr VectorR;计算屏幕法向量
            invoke    SetTimer,hWnd,1,1,0
            invoke    GetDC,hWnd
            mov    hdc,eax
        .elseif    eax ==    WM_CLOSE
            invoke    DestroyWindow,hWinMain
            invoke    PostQuitMessage,NULL
        .else
            invoke    DefWindowProc,hWnd,uMsg,wParam,lParam
            ret
        .endif
        xor    eax,eax
        ret

_ProcWinMain    endp
_WinMain    proc
        local    @stWndClass:WNDCLASSEX
        local    @stMsg:MSG

        invoke    GetModuleHandle,NULL
        mov    hInstance,eax
        invoke    RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
        invoke    LoadCursor,0,IDC_ARROW
        mov    @stWndClass.hCursor,eax
        push    hInstance
        pop    @stWndClass.hInstance
        mov    @stWndClass.cbSize,sizeof WNDCLASSEX
        mov    @stWndClass.style,CS_HREDRAW or CS_VREDRAW
        mov    @stWndClass.lpfnWndProc,offset _ProcWinMain
        mov    @stWndClass.hbrBackground,COLOR_WINDOW + 1
        mov    @stWndClass.lpszClassName,offset szClassName
        invoke    RegisterClassEx,addr @stWndClass
        invoke    CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,\
            WS_SYSMENU,\
            0,0,625,650,\
            NULL,NULL,hInstance,NULL
        mov    hWinMain,eax
        invoke    ShowWindow,hWinMain,SW_SHOWNORMAL
        invoke    UpdateWindow,hWinMain
        .while    TRUE
            invoke    GetMessage,addr @stMsg,NULL,0,0
            .break    .if eax    == 0
            invoke    TranslateMessage,addr @stMsg
            invoke    DispatchMessage,addr @stMsg
        .endw
        ret

_WinMain    endp
start:
        invoke    GlobalAlloc,0,4*600*600+40
        mov    lpBmp,eax
        mov    edi,eax
        mov    dword ptr[edi],40
        mov    dword ptr[edi+4],600
        mov    dword ptr[edi+8],600
        mov    dword ptr[edi+12],200001h
        mov    ecx,600*600
        mov    eax,-1
        add    edi,40
        rep    stosd
        call    _WinMain
        invoke    GlobalFree,lpBmp
        invoke    ExitProcess,NULL
        end    start

并不是所有的贴子都是原创,此时作者均指发表的人而不是文章的作者,作者会说明是否是转贴