;coded by UEZ 2009
#include <GDIplus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global Const $width = @DesktopWidth / 2
Global Const $height = @DesktopHeight / 2
Global Const $pi_div_180 = 4 * ATan(1) / 180
Opt("GUIOnEventMode", 1)
Global $hwnd = GUICreate("Border Collision with Hatch Brushes!", $width, $height, -1, -1, Default, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW))
GUISetOnEvent($GUI_EVENT_CLOSE, "Close") ;$GUI_EVENT_CLOSE = -3
GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "Move") ;move main window
GUISetState()

_GDIPlus_Startup()
Global $graphics = _GDIPlus_GraphicsCreateFromHWND($hwnd)
Global $bitmap = _GDIPlus_BitmapCreateFromGraphics($width, $height, $graphics)
Global $backbuffer = _GDIPlus_ImageGetGraphicsContext($bitmap)
_GDIPlus_GraphicsClear($backbuffer)
_GDIPlus_GraphicsSetSmoothingMode($backbuffer, 4)

Global $max_dots = 20
Global $max_speed = 5
Global $iWidth = 100
Global $iHeight = 100
Dim $coordinates[$max_dots][5], $angle
Dim $brush[$max_dots]
Global $hImage[$max_dots]
Global $hContext
Global $hBrush
Global $sleep = 40

Initialize()

GUIRegisterMsg($WM_TIMER, "Draw") ;$WM_TIMER = 0x0113

DllCall("User32.dll", "int", "SetTimer", "hwnd", $hwnd, "int", 0, "int", $sleep, "int", 0)
;~ $hCallBack = DllCallbackRegister("Draw", "none", "") ;crashing on exit
;~ DllCall("User32.dll", "int", "SetTimer", "hwnd", $hwnd, "int", 0, "int", $sleep, "ptr", DllCallbackGetPtr($hCallBack))

Do
Until False * Not Sleep(1000)

Func Move() ;move whole window when pressed lmb and hold continuing drawing of window content
	DllCall("user32.dll", "int", "SendMessage", "hWnd", $hwnd, "int", $WM_NCLBUTTONDOWN, "int", 2, "int", 0) ;$WM_NCLBUTTONDOWN = 0x00A1
EndFunc

Func Draw()
	_GDIPlus_GraphicsClear($backbuffer, 0xFF000000)
	Draw_Dots()
	Calculate_New_Position()
	_GDIPlus_GraphicsDrawImageRect($graphics, $bitmap, 0, 0, $width, $height)
EndFunc

Func Initialize()
    For $k = 0 To $max_dots - 1
        $hImage[$k] = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
        $hBrush = _GDIPlus_HatchBrushCreate(Random(0, 52, 1), "0xD0" & Hex(Random(0x400000, 0xFFFFFF, 1), 6), 0xFFFFFFFF)
        $hContext = _GDIPlus_ImageGetGraphicsContext($hImage[$k])
        _GDIPlus_GraphicsFillEllipse($hContext, 0, 0, $iWidth, $iWidth, $hBrush)
        _GDIPlus_GraphicsDispose($hContext)
        _GDIPlus_BrushDispose($hBrush)
        New_Coordinates($k)
    Next
EndFunc ;==>Initialize

Func Draw_Dots()
    Local $i, $temp_x, $temp_y
    For $i = 0 To $max_dots - 1
        _GDIPlus_GraphicsDrawImageRect($backbuffer, $hImage[$i], $coordinates[$i][0], $coordinates[$i][1], $iWidth, $iHeight)
    Next
EndFunc ;==>Draw_Dots

Func New_Coordinates($k)
    $coordinates[$k][0] = $width / 2 ;Random($width / 20, $width - $width / 20, 1);start x position
    $coordinates[$k][1] = $height / 2 ;Random($height / 20, $height - $height / 20, 1) ;start y position
    $coordinates[$k][2] = Random(1, $max_speed, 1) ;speed of pixel
    $angle = Random(0, 359, 1)
;~ ConsoleWrite("Angle: " & $angle & "°" & @CRLF)
    $coordinates[$k][3] = $coordinates[$k][2] * Cos($angle * $pi_div_180)
    $coordinates[$k][4] = $coordinates[$k][2] * Sin($angle * $pi_div_180)
EndFunc ;==>New_Coordinates

Func Calculate_New_Position()
    Local $k
    For $k = 0 To $max_dots - 1
        $coordinates[$k][0] += $coordinates[$k][3] ;increase x coordinate with appropriate slope
        $coordinates[$k][1] += $coordinates[$k][4] ;increase y coordinate with appropriate slope
        If $coordinates[$k][0] <= 0 Then ;border collision x left
            $coordinates[$k][0] = 1
            $coordinates[$k][3] *= -1
        ElseIf $coordinates[$k][0] >= $width - $iWidth Then ;border collision x right
            $coordinates[$k][0] = $width - ($iWidth + 1)
            $coordinates[$k][3] *= -1
        EndIf
        If $coordinates[$k][1] <= 0 Then ;border collision y top
            $coordinates[$k][1] = 1
            $coordinates[$k][4] *= -1
        ElseIf $coordinates[$k][1] >= $height - $iHeight Then ;border collision y bottom
            $coordinates[$k][1] = $height - ($iHeight + 1)
            $coordinates[$k][4] *= -1
        EndIf
    Next
EndFunc ;==>Calculate_New_Position

Func _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iStride = 0, $iPixelFormat = 0x0026200A, $pScan0 = 0)
	Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", $iStride, "int", $iPixelFormat, "ptr", $pScan0, "int*", 0)

	If @error Then Return SetError(@error, @extended, 0)
	$GDIP_STATUS = $aResult[0]
	Return $aResult[6]
EndFunc   ;==>_GDIPlus_BitmapCreateFromScan0

Func _GDIPlus_HatchBrushCreate($iHatchStyle = 0, $iARGBForeground = 0xFFFFFFFF, $iARGBBackground = 0xFFFFFFFF)
	Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateHatchBrush", "int", $iHatchStyle, "uint", $iARGBForeground, "uint", $iARGBBackground, "int*", 0)

	If @error Then Return SetError(@error, @extended, 0)
	$GDIP_STATUS = $aResult[0]
	Return $aResult[4]
EndFunc   ;==>_GDIPlus_HatchBrushCreate

Func close()
	GUIRegisterMsg($WM_TIMER, "")
	GUIRegisterMsg($WM_TIMER, "")
;~ 	DllCallbackFree($hCallBack)
    For $k = 0 To $max_dots-1
        _GDIPlus_ImageDispose($hImage[$k])
    Next
    _GDIPlus_BitmapDispose($bitmap)
    _GDIPlus_GraphicsDispose($graphics)
    _GDIPlus_GraphicsDispose($backbuffer)
    _GDIPlus_Shutdown()
    Exit
EndFunc ;==>close
