News:

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

Falling snow effect

Started by hfheatherfox07, August 03, 2011, 11:19:53 PM

Previous topic - Next topic

zekyr

Quote from: slovach on August 09, 2011, 03:04:22 AM
I always liked starfields, very cool effect and simple, I've written both 3d and 2d versions of it, can post the source if anyone is interested... just be warned it's in C. The 3d one is interesting because it shows off 3d transformation, can use it as a base to a 3d software renderer.

That sounds really cool slovach! I personally would love to see the source to those if you wrote them with gdi :)

slovach

Here's a 2d starfield, code isn't structured, just thrown together as an example, have to add the typedefs yourself for the types since I forgot to include it and I'm too lazy to reupload it. If you have any questions as to what exactly is going on anywhere, just ask. It should be fairly simple to follow.

typedefs
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned __int64 u64;
typedef char s8;
typedef short s16;
typedef int s32;
typedef __int64 s64;
typedef float f32;
typedef double f64;


If you're observant you'll notice that the stars don't overlap nicely, there is no proper alpha blending here, I just dim the color instead of blending it. It's easy to fix, but it's most noticeable in the 3d version since you can use alpha blending as a trick to simulate the stars coming out of the darkness.

You get this: http://dl.dropbox.com/u/10565193/sf_2d.rar


3d is a little more involved and I apparently lost my source so I'll just rewrite it, I'll try to explain the 3d transformation while I'm at it.

I still have the exe though somehow, so count it as a preview:
http://dl.dropbox.com/u/10565193/sf3d.rar

Siekmanski

Just found some ancient demo routines I did on the Amiga.
Converted them to run on the PC ( PMODE ).
It's not complete but you can have a look at the routines.
It has some nice 3D-star effects.

You can use the star routine for a nice snow effect.....


GregL

Siekmanski,

Just to let you know, those programs won't run on Win Vista and Win 7 because they use full screen mode.

slovach

Quote from: GregL on August 11, 2011, 01:18:20 AM
Siekmanski,

Just to let you know, those programs won't run on Win Vista and Win 7 because they use full screen mode.

When in doubt, use DOSBOX :)

hfheatherfox07


MichaelW

#21
This is crude and GDI only, but I think it produces a reasonable effect.

Edit:

Cleaned up the code somewhat. Also increased the update rate and decreased the mean Y increment for smoother motion at the expense of a higher CPU usage.

Edit2:

Updated the code again to add a frame-rate display. If I eliminate the update delay by setting UPDATE_DELAY to zero, with SET_PIXEL = 1 I get a frame rate of ~53, and with SET_PIXEL = 0 I get a frame rate of ~878. So almost all of the update loop time is spent in the calls to SetPixel.

Edit3:

Updated the code again, partly to fix flaws, but mostly to add a faster set pixel procedure.


;==============================================================================
    include \masm32\include\masm32rt.inc
    .686        ; required for fcomip
;==============================================================================

FLAKE_COUNT       equ 2000
UPDATE_DELAY      equ 0
USE_FASTSETPIXEL  equ 1

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

FPU_RC_NEAREST  equ 0
FPU_RC_DOWN     equ 400h
FPU_RC_UP       equ 800h
FPU_RC_TRUNCATE equ 0c00h

;--------------------------------------------------------------------
; This macro sets the rounding control bits in the FPU Control Word.
;--------------------------------------------------------------------

FPU_SETRC MACRO rc
    push eax
    fstcw [esp]
    pop eax
    and eax, NOT 0c00h
    or eax, rc
    push eax
    fldcw [esp]
    pop eax
ENDM

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

FLAKE STRUCT
    ix  DWORD ?
    iy  DWORD ?
    fi  REAL4 ?
    fy  REAL4 ?
FLAKE  ENDS

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

    .data

        hInst       dd  0
        hDlg        dd  0
        hdcDDB      dd  0
        hdcClient   dd  0
        hDDB        dd  0
        hPrevBmp    dd  0
        clientW     dd  0
        clientH     dd  0

        pFlakeData  dd  0
        pBMI        dd  0
        pDIBits     dd  0

        frameCount  dd  0

        ps          PAINTSTRUCT <>
        rc          RECT        <>
        msg         MSG         <>

    .code
;==============================================================================

;------------------------------------------------------------------------
; This is Abel's version of a Park-Miller-Carta generator, details here:
;   http://www.masm32.com/board/index.php?topic=6558.0
; Modified to return a floating-point value in the interval [0,1) at
; the top of the FPU stack in ST(0), as per the normal convention.
;
; The period of the core generator is 2147483646 (tested), and it runs
; in 23 cycles on a P3, including the call overhead and a fstp to store
; the result to memory. Note that in my tests setting frnd_divider to
; the period instead of to a power of 2 caused a ~2x slowdown.
;------------------------------------------------------------------------

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

align 4
frnd proc

    .data
        align 8
        frnd_divider   dq 2147483648
        abel_rand_seed dd 1
    .code

    mov eax, abel_rand_seed
    mov ecx, 16807              ; a = 7^5
    mul ecx                     ; edx:eax == a*seed == D:A
    mov ecx, 7fffffffh          ; ecx = m

    add edx, edx                ; edx = 2*D
    cmp eax, ecx                ; eax = A
    jna @F
    sub eax, ecx                ; if A>m, A = A - m
  @@:
    add eax, edx                ; eax = A + 2*D
    jns @F
    sub eax, ecx                ; If (A + 2*D)>m
  @@:
    mov abel_rand_seed, eax     ; save new seed
    fild abel_rand_seed
    fild frnd_divider
    fdiv
    ret

frnd  endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

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

;---------------------------------------------------------
; To keep it simple, this procedure supports 32-bpp only.
;---------------------------------------------------------

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

align 4
FastSetPixel proc x:DWORD, y:DWORD, color:DWORD

    mov ecx, [esp+8]
    mov eax, clientW
    mul ecx
    mov ecx, eax
    mov edx, pDIBits
    mov eax, [esp+4]
    add ecx, eax
    mov eax, [esp+12]
    mov [edx+ecx*4], eax

    ret 12

FastSetPixel  endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

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

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

    SWITCH uMsg

        CASE WM_INITDIALOG

            invoke GetClientRect, hwndDlg, addr rc
            mov eax, rc.right
            inc eax
            mov clientW, eax
            mov eax, rc.bottom
            inc eax
            mov clientH, eax

            ;-------------------------------------------
            ; Allocate memory for the flake data array.
            ;-------------------------------------------

            mov eax, FLAKE_COUNT
            shl eax, 4
            mov pFlakeData, alloc(eax)

            ;-------------------------------------------------------------
            ; Get a DC for the client area and create a compatible memory
            ; DC and compatible bitmap (DDB). The compatible bitmap is
            ; used as a drawing surface for the API SetPixel function and
            ; to receive the bitmap bits from the device-independent
            ; bitmap (DIB) that the FastSetPixel procedure draws on.
            ;-------------------------------------------------------------

            invoke GetDC, hwndDlg
            mov hdcClient, eax
            invoke CreateCompatibleDC, hdcClient
            mov hdcDDB, eax
            invoke CreateCompatibleBitmap, hdcClient, clientW, clientH
            mov hDDB, eax

            ;----------------------------------------------------
            ; Select the bitmap into the memory DC and save the
            ; previously selected object.
            ;
            ; The bitmap, by default, will be filled with black.
            ;----------------------------------------------------

            invoke SelectObject, hdcDDB, hDDB
            mov hPrevBmp, eax

            push ebx
            push esi

            ;-------------------------------------------------------------
            ; Allocate memory to store the BITMAPINFO structure for our
            ; DIB and set the biSize member to the size of the structure.
            ;-------------------------------------------------------------

            mov esi, alloc(SIZEOF BITMAPINFO)
            mov pBMI, esi
            mov [esi].BITMAPINFO.bmiHeader.biSize, SIZEOF BITMAPINFO

            ;--------------------------------------------------------
            ; Call the GetDIBits function with the lpvBits parameter
            ; set to NULL, so the function will pass the dimensions
            ; and format of the bitmap to the BITMAPINFO structure.
            ;--------------------------------------------------------

            invoke GetDIBits, hdcClient, hDDB, 0, 0, NULL, pBMI, DIB_RGB_COLORS

            ;------------------------------------
            ; Ensure that the display bpp is 32.
            ;------------------------------------

            movzx eax, [esi].BITMAPINFO.bmiHeader.biBitCount
            cmp eax, 32
            je  @F
            invoke MessageBox, hwndDlg, chr$("Display bpp must be 32 "), 0, 0
            call destroy
          @@:

            ;----------------------------------------------------------------
            ; To keep access to the DIB bits simple, specify an uncompressed
            ; format and a negative height, so we get a top-down DIB instead
            ; of the normal bottom-up DIB.
            ;----------------------------------------------------------------

            mov [esi].BITMAPINFO.bmiHeader.biCompression, BI_RGB
            neg [esi].BITMAPINFO.bmiHeader.biHeight

            ;---------------------------------------------------------
            ; Allocate a buffer to store the bitmap bits for our DIB.
            ; Note that the alloc macro fills the buffer with zeros,
            ; effectively providing a black background for the DIB.
            ; The FastSetPixel procedure draws to this buffer.
            ;---------------------------------------------------------

            mov eax, [esi].BITMAPINFO.bmiHeader.biSizeImage
            mov pDIBits, alloc(eax)

            pop esi
            pop ebx

            invoke ReleaseDC, NULL, hdcClient

            ;-----------------------------------------------------
            ; Initialize the flake data array with random X and Y
            ; coordinates, and Y increment values spread over a
            ; small random range (~0.425 to ~0.575)
            ;-----------------------------------------------------

            push ebx
            push edi
            xor ebx, ebx
            mov edi, pFlakeData
            mov ecx, FLAKE_COUNT
            .WHILE ecx
                push ecx
                call frnd
                fild clientW
                fmul
                fistp [edi+ebx].FLAKE.ix
                call frnd
                fild clientH
                fmul
                fstp [edi+ebx].FLAKE.fy
                call frnd
                fld8 0.15
                fmul
                fld8 0.075
                fsub
                fld8 0.5
                fadd
                fstp [edi+ebx].FLAKE.fi
                add ebx, SIZEOF FLAKE
                pop ecx
                dec ecx
            .ENDW
            pop edi
            pop ebx

            ;-----------------------------------------------------------
            ; Create a timer to provide a time base for the frame rate.
            ;-----------------------------------------------------------

            invoke SetTimer, hwndDlg, 1, 1000, NULL

        CASE WM_PAINT

            ;------------------------------------------------
            ; Display the DDB by copying it to the paint DC.
            ;------------------------------------------------

            invoke BeginPaint, hwndDlg, ADDR ps
            invoke CreateCompatibleBitmap, ps.hdc, clientW, clientH
            push eax
            invoke SelectObject, ps.hdc, eax
            push eax
            invoke BitBlt, ps.hdc, 0, 0, clientW, clientH, hdcDDB, 0, 0, SRCCOPY
            pop eax
            invoke SelectObject, ps.hdc, eax
            pop eax
            invoke DeleteObject, eax
            invoke EndPaint, hwndDlg, ADDR ps

        CASE WM_ERASEBKGND

            ;----------------------------------------------------------
            ; This effectively disables the background erase when the
            ; client area is redrawn, reducing flicker when the window
            ; is moved.
            ;----------------------------------------------------------

            return 1

        CASE WM_TIMER

            ;------------------------
            ; Update the frame rate.
            ;------------------------

            invoke SetWindowText, hwndDlg, str$(frameCount)
            mov frameCount, 0

        CASE WM_COMMAND

            SWITCH wParam

                CASE IDCANCEL

                    call destroy

            ENDSW

        CASE WM_CLOSE

            call destroy

        CASE WM_DESTROY

            invoke PostQuitMessage, NULL

    ENDSW

    xor eax, eax
    ret

  destroy:

    invoke KillTimer, hwndDlg, 1
    invoke SelectObject, hdcDDB, hPrevBmp
    invoke ReleaseDC, NULL, hdcDDB
    free pFlakeData
    free pBMI
    free pDIBits
    invoke DestroyWindow, hwndDlg
    retn

DialogProc endp

;==============================================================================
start:
;==============================================================================
    invoke GetModuleHandle, NULL
    mov hInst, eax

    Dialog 0, \
           "MS Sans Serif",10, \
           WS_VISIBLE or WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           0, \
           0,0,160,160, \
           1024

    CallModelessDialog hInst, 0, DialogProc, NULL
    mov hDlg, eax

    ;-----------------------------------------------------------
    ; Set the FPU to round down, to avoid in the flake-position
    ; update code below, having the default rounding (nearest)
    ; round the integer y-position up an invalid value.
    ;-----------------------------------------------------------

    FPU_SETRC FPU_RC_DOWN

  msgLoop:

    invoke PeekMessage, ADDR msg, NULL, 0, 0, PM_REMOVE
    .IF eax != 0
        .IF msg.message == WM_QUIT
            invoke ExitProcess, 0
        .ENDIF
        invoke IsDialogMessage, hDlg, addr msg
        .IF eax == 0
            invoke TranslateMessage, addr msg
            invoke DispatchMessage, addr msg
        .ENDIF
    .ELSE

        ;---------------------------------------------------------
        ; This code runs whenever there is no message to process.
        ;---------------------------------------------------------

        push ebx
        push edi
        xor ebx, ebx
        mov edi, pFlakeData
        mov ecx, FLAKE_COUNT
        .WHILE ecx

            push ecx

            ;----------------------------------------
            ; "Erase" the flake at the old position.
            ;----------------------------------------

            IF USE_FASTSETPIXEL EQ 1

                invoke FastSetPixel, [edi+ebx].FLAKE.ix,
                                     [edi+ebx].FLAKE.iy, 0

            ELSE

                invoke SetPixel, hdcDDB, [edi+ebx].FLAKE.ix,
                                         [edi+ebx].FLAKE.iy, 0

            ENDIF

            ;-------------------------------------------------------
            ; Update the flake position, wrapping to the top of the
            ; window when the flake reaches the bottom.
            ;-------------------------------------------------------

            fld [edi+ebx].FLAKE.fy      ; st(0)=fy
            fadd [edi+ebx].FLAKE.fi     ; st(0)=updated_fy
            fild clientH                ; st(0)=clientH,st(1)=updated_fy
            fcomip st(0),st(1)          ; st(0)=updated_fy
            ja  @F                      ; jump if st(0) > st(1)
            fstp st(0)                  ; discard st(0)
            fld1                        ; st(0)=1
          @@:
            fst [edi+ebx].FLAKE.fy      ; fy=updated_fy,st(0)=updated_fy
            fistp [edi+ebx].FLAKE.iy    ; iy=st(0),st(0)-st(7) now empty

            ;-----------------------------------------
            ; Draw the flake at the updated position.
            ;-----------------------------------------

            IF USE_FASTSETPIXEL EQ 1

                invoke FastSetPixel, [edi+ebx].FLAKE.ix,
                                     [edi+ebx].FLAKE.iy, 0ffffffh

            ELSE

                invoke SetPixel, hdcDDB, [edi+ebx].FLAKE.ix,
                                         [edi+ebx].FLAKE.iy, 0ffffffh

            ENDIF

            add ebx, SIZEOF FLAKE
            pop ecx
            dec ecx

        .ENDW
        pop edi
        pop ebx

        ;-----------------------------------------------
        ; If using the FastSetPixel procedure, copy the
        ; bitmap bits from the DIB to the DDB.
        ;-----------------------------------------------

        IF USE_FASTSETPIXEL EQ 1

            invoke SetDIBits,0,hDDB,0,clientH,pDIBits,pBMI,DIB_RGB_COLORS

        ENDIF

        ;-------------------------------------
        ; Force a repaint of the client area.
        ;-------------------------------------

        invoke InvalidateRect, hDlg, 0, 0

        ;------------------------------------------------------------
        ; Delay to control the update rate and thus the flake speed.
        ;------------------------------------------------------------

        invoke Sleep, UPDATE_DELAY

        inc frameCount

    .ENDIF
    jmp msgLoop
;==============================================================================
end start

eschew obfuscation

hfheatherfox07

#22
That is so cool , it would be nice if we can get the snow to accumulate on the bottom like the attachment posted by Magnum in the previous page :U

FORTRANS

Quote from: MichaelW on August 17, 2011, 06:49:21 PM
This is crude and GDI only, but I think it produces a reasonable effect.

Hi,

   It is quite nice on my machine, thanks.  Thought there
was some "noise" but that was dust on my monitor!.  Pilot
error here.  Fixed size and no full screen are the only real
comments for consideration.

Regards,

Steve N.

Magnum

hfheatherfox07,

Here are some progs that would look good in Win32.

The match and fire are my favorite.
Have a great day,
                         Andy

dedndave

Quote from: FORTRANS on August 18, 2011, 12:30:37 PM
Thought there was some "noise" but that was dust on my monitor! Pilot error here.


hfheatherfox07

Quote from: Magnum on August 18, 2011, 01:18:32 PM
hfheatherfox07,

Here are some progs that would look good in Win32.

The match and fire are my favorite.

LOL you keep posting stuff with no source.....

anyways I have those.... There are all in TASM which I don't know

hfheatherfox07

Found all the TASM sources...useless to me.... maybe someone wants them..... ::)


Magnum

Take a chill pill.

I did not post the sources since you don't use Tasm and 16 bit source code would be of no use to someone
making a 32 bit program.

You didn't find the match source code.

Tasm is almost identical to masm.



Have a great day,
                         Andy

Twister

Well, I am trying to write an application that mimics falling snow like you all are discussing about in this thread. I am writing it to use the SDL library, but I am having a problem. I am having to translate the C header files to an assembler include file. I just don't know what to put for the header. The SDL library is licensed under The GNU Lesser General Public License (Version 2.1), which can be found here for reading: (http://www.gnu.org/licenses/lgpl-2.1.txt; plaintext)

As far as I can see, I just need to go by Section 1. I just need to include the GNU LGPL V2.1 along with the program. Is there anything else I am missing?

;    SDL Library binding for assembler
;
;    SDL - Simple DirectMedia Layer
;    Copyright (C) 1997-2009 Sam Lantinga
;
;    This library is free software; you can redistribute it and/or
;    modify it under the terms of the GNU Lesser General Public
;    License as published by the Free Software Foundation; either
;    version 2.1 of the License, or (at your option) any later version.
;
;    This library is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;    Lesser General Public License for more details.