;---------------------------------------;
;    DDRAW Plasma Demo                  ;
;                                       ;
;    Author :         X-Calibre         ;
;    ASM version :    Ewald Snel        ;
;    Copyright (C) 1999, Diamond Crew   ;
;                                       ;
;    http://here.is/diamond/            ;
;---------------------------------------;

    TITLE WIN32ASM EXAMPLE
    .486
    .MODEL FLAT, STDCALL
    option casemap :none

;-----------------------------------------------------------;
;                WIN32ASM / DDRAW PLASMA DEMO               ;
;-----------------------------------------------------------;

    INCLUDE \masm32\include\windows.inc

  ; -----------------------------------
  ; Note that the following is the
  ; include file written by Ewald Snel.
  ; -----------------------------------
    INCLUDE \masm32\include\ddraw.inc

    INCLUDE \masm32\include\gdi32.inc
    INCLUDE \masm32\include\kernel32.inc
    INCLUDE \masm32\include\user32.inc

    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\ddraw.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\user32.lib


    WinMain    PROTO :DWORD,:DWORD,:DWORD,:DWORD 
    WndProc    PROTO :DWORD,:DWORD,:DWORD,:DWORD 
    nextFrame  PROTO
    initPlasma PROTO

RETURN MACRO arg
    IFNB <arg>
        mov            eax, arg 
    ENDIF
    ret 
ENDM

LRETURN MACRO arg 
    IFNB <arg>
        mov            eax, arg 
    ENDIF
    leave
    ret 
ENDM

FATAL MACRO msg
    LOCAL @@msg
    .DATA
    @@msg        db        msg, 0
    .CODE

    INVOKE MessageBox, hWnd, ADDR @@msg, ADDR szDisplayName, MB_OK
    INVOKE ExitProcess, 0
ENDM


.DATA?

hWnd            HWND                ?        ; surface window
lpDD            LPDIRECTDRAW        ?        ; DDraw object
lpDDSPrimary    LPDIRECTDRAWSURFACE ?        ; DDraw primary surface
ddsd            DDSURFACEDESC       <?>      ; DDraw surface descriptor
ddscaps         DDSCAPS             <?>      ; DDraw capabilities


palette            dd        256 dup (?)
table              dd        512 dup (?)
lpDDPalette        dd        ?


.DATA

ddwidth            EQU        320                ; display mode width
ddheight           EQU        200                ; display mode height
ddbpp              EQU        8                  ; display mode color depth

phaseA             dd         0
phaseB             dd         0

factor1            EQU        -2
factor2            EQU        -1
factor3            EQU         1
factor4            EQU        -2

red                dd        500.0
green              dd        320.0
blue               dd        372.0

scale1             dd        2.0
scale2             dd        128.0
scale3             dd        256.0
scale4             dd        127.0

szClassName        db            "DDRAW Plasma Demo", 0    ; class name
szDisplayName      EQU            <szClassName>            ; window name
color              dd            0

wc                WNDCLASSEX    < SIZEOF WNDCLASSEX, CS_HREDRAW OR CS_VREDRAW, OFFSET WndProc, 0, 0, , 0, 0, , 0, OFFSET szClassName, 0 >

.CODE

start:

    INVOKE GetModuleHandle, NULL
    INVOKE WinMain, eax, NULL, NULL, SW_SHOWDEFAULT
    INVOKE ExitProcess, eax



;-----------------------------------------------------------;
;                Calculate Next Plasma Frame                ;
;-----------------------------------------------------------;

nextFrame    PROC
    push        ebx
    push        esi
    push        edi

    mov            ecx , ddheight                ; # of scanlines
    mov            edi , [ddsd.lpSurface]        ; pixel output

@@scanline:
    push        ecx
    push        edi

    mov            esi , [phaseA]
    mov            edx , [phaseB]
    sub            esi , ecx
    and            edx , 0ffH
    and            esi , 0ffH
    mov            edx , [table][4*edx][256*4]
    mov            esi , [table][4*esi]        ; [x]  +  table0[a + y]
    sub            edx , ecx                    ; [y]  +  table1[b]
    mov            ecx , ddwidth                ; [x] --> pixel counter

@@pixel:
    and            esi , 0ffH
    and            edx , 0ffH
    mov            eax , [table][4*esi]
    mov            ebx , [table][4*edx][256*4]
    add            eax , ebx
    add            esi , factor3
    shr            eax , 1
    inc            edi
    add            edx , factor4
    dec            ecx
    mov            [edi][-1] , al
    jnz            @@pixel

    pop            edi
    pop            ecx
    add            edi , [ddsd.lPitch]            ; inc. display position
    dec            ecx
    jnz            @@scanline

    add            [phaseA] , factor1
    add            [phaseB] , factor2

    pop            edi
    pop            esi
    pop            ebx

    ret
nextFrame    ENDP


;-----------------------------------------------------------;
;                Initalize Plasma Tables                        ;
;-----------------------------------------------------------;

initPlasma    PROC

    LOCAL @@i :DWORD
    LOCAL @@r :DWORD
    LOCAL @@g :DWORD
    LOCAL @@b :DWORD
    LOCAL temp :DWORD


    mov            [@@i] , 0

    .WHILE @@i < 256

        mov            edx , [@@i]

; Calculate table0 value

        fldpi
        fimul        DWORD PTR [@@i]
        fmul        REAL4 PTR [scale1]
        fdiv        REAL4 PTR [scale3]
        fsin
        fmul        REAL4 PTR [scale4]
        fadd        REAL4 PTR [scale2]
        fistp        DWORD PTR [table][4*edx]

; Calculate table1 value

        fldpi
        fimul        DWORD PTR [@@i]
        fmul        REAL4 PTR [scale1]
        fdiv        REAL4 PTR [scale3]
        fcos
        fmul        REAL4 PTR [scale2]
        fadd        REAL4 PTR [scale2]
        fldpi
        fmulp        st(1), st
        fmul        REAL4 PTR [scale1]
        fdiv        REAL4 PTR [scale3]
        fsin
        fmul        REAL4 PTR [scale4]
        fadd        REAL4 PTR [scale2]
        fistp        DWORD PTR [table][4*edx][4*256]

; Calculate palette value

        xor            eax , eax

        FOR comp, <red, green, blue>
            fldpi
            fimul        DWORD PTR [@@i]
            fmul        REAL4 PTR [scale1]
            fdiv        REAL4 PTR [comp]
            fcos
            fmul        REAL4 PTR [scale4]
            fadd        REAL4 PTR [scale2]
            fistp        DWORD PTR [temp]
            shl            eax , 8
            or            eax , [temp]
        ENDM

        bswap          eax
        shr            eax, 8
        mov            [palette][4*edx] , eax
        inc            [@@i]

    .ENDW

	 ; Set palette
	 DDINVOKE        CreatePalette, lpDD, DDPCAPS_8BIT or DDPCAPS_ALLOW256, ADDR palette, ADDR lpDDPalette, NULL
	.IF eax != DD_OK
		FATAL "Couldn't create palette"
	.ENDIF
	
	DDSINVOKE       SetPalette, lpDDSPrimary, lpDDPalette
	.IF eax != DD_OK
		FATAL "Couldn't set palette"
	.ENDIF

    ret

initPlasma    ENDP



;-----------------------------------------------------------;
;                WinMain  ( entry point )                   ;
;-----------------------------------------------------------;

WinMain PROC hInst     :DWORD,
             hPrevInst :DWORD,
             CmdLine   :DWORD,
             CmdShow   :DWORD

    LOCAL msg  :MSG

; Fill WNDCLASSEX structure with required variables

    mov            eax , [hInst]
    mov            [wc.hInstance] , eax
    INVOKE         GetStockObject , BLACK_BRUSH
    mov            [wc.hbrBackground] , eax

    INVOKE RegisterClassEx, ADDR wc


; Create window at following size

    INVOKE CreateWindowEx, 0,
                            ADDR szClassName,
                            ADDR szDisplayName,
                            WS_POPUP,
                            0, 0, ddwidth, ddheight,
                            NULL, NULL,
                            hInst, NULL
    mov            [hWnd] , eax

    INVOKE ShowWindow, hWnd, SW_MAXIMIZE
    INVOKE SetFocus, hWnd
    INVOKE ShowCursor, 0


; Initialize display

    INVOKE DirectDrawCreate, NULL, ADDR lpDD, NULL
    .IF eax != DD_OK
        FATAL "Couldn't init DirectDraw"
    .ENDIF

    DDINVOKE SetCooperativeLevel, lpDD, hWnd, DDSCL_EXCLUSIVE OR DDSCL_FULLSCREEN
    .IF eax != DD_OK
        FATAL "Couldn't set DirectDraw cooperative level"
    .ENDIF

    DDINVOKE SetDisplayMode, lpDD, ddwidth, ddheight, ddbpp
    .IF eax != DD_OK
        FATAL "Couldn't set display mode"
    .ENDIF

    mov            [ddsd.dwSize] , SIZEOF DDSURFACEDESC
    mov            [ddsd.dwFlags] , DDSD_CAPS
    mov            [ddsd.ddsCaps.dwCaps] , DDSCAPS_PRIMARYSURFACE
    DDINVOKE CreateSurface, lpDD, ADDR ddsd, ADDR lpDDSPrimary, NULL
    .IF eax != DD_OK
    FATAL "Couldn't create primary surface"
    .ENDIF


    call        initPlasma

; Loop until PostQuitMessage is sent

    .WHILE 1

        INVOKE PeekMessage, ADDR msg, NULL, 0, 0, PM_REMOVE

        .IF eax != 0
            .IF msg.message == WM_QUIT
                INVOKE PostQuitMessage, msg.wParam
                .BREAK
            .ELSE
                INVOKE TranslateMessage, ADDR msg
                INVOKE DispatchMessage, ADDR msg
            .ENDIF
        .ELSE
            INVOKE GetFocus

            .IF eax == hWnd

                mov            [ddsd.dwSize] , SIZEOF DDSURFACEDESC
                mov            [ddsd.dwFlags] , DDSD_PITCH

                .WHILE 1
                    DDSINVOKE mLock, lpDDSPrimary, NULL, ADDR ddsd, DDLOCK_WAIT, NULL

                    .BREAK .IF eax == DD_OK

                    .IF eax == DDERR_SURFACELOST
                        DDSINVOKE Restore, lpDDSPrimary
                    .ELSE
                        FATAL "Couldn't lock surface"
                    .ENDIF
                .ENDW

                DDINVOKE WaitForVerticalBlank, lpDD, DDWAITVB_BLOCKBEGIN, NULL

                call        nextFrame

                DDSINVOKE Unlock, lpDDSPrimary, ddsd.lpSurface

            .ENDIF
        .ENDIF
    .ENDW

    .IF lpDD != NULL

          .IF lpDDSPrimary != NULL
            DDSINVOKE Release, lpDDSPrimary
            mov            [lpDDSPrimary] , NULL
        .ENDIF

         DDINVOKE Release, lpDD
        mov            [lpDD] , NULL

    .ENDIF

    LRETURN msg.wParam

WinMain ENDP


;-----------------------------------------------------------;
;                Window Proc  ( handle events )                ;
;-----------------------------------------------------------;

WndProc PROC hWin   :DWORD,
             uMsg   :DWORD,
             wParam :DWORD,
             lParam :DWORD

    .IF uMsg == WM_KEYDOWN
        .IF wParam == VK_ESCAPE
            INVOKE PostQuitMessage, NULL
            RETURN 0 
        .ENDIF
    .ELSEIF uMsg == WM_DESTROY
        INVOKE PostQuitMessage, NULL
        RETURN 0 
    .ENDIF

    INVOKE DefWindowProc, hWin, uMsg, wParam, lParam

    ret

WndProc ENDP

END start
