GDI+ Bildschirmschoner mit Rechtecken

  • Moin,

    Im Prinzipp sollte dieses Skript eine ganz andere Aufgabe erfüllen.
    Als ich (im Spiel) eine Hintergrundgrafik für Bildschirme erstellen wollte habe ich direkt an einen Bildschirmschoner gedacht.
    Ein Paar geänderte Zeilen und schon lief das ganze.

    Die Prozessorauslastung liegt bei mir (mit Standardeinstellungen) bei unter 3%. Es ist also je nach Einstellung langzeittauglich.
    Die Einstellungen können in den ersten Zeilen in Form von Konstanten angepasst werden.
    Dabei ergeben sich interessante Effekte. (z.B. extreme Verpixelung wenn man Quali auf 150 stellt oder Frameraten jenseits von Gut und Böse bei FPS = 0.1^^)

    Das Beste am Skript ist ein Doppelpuffer, der aber garnicht nötig ist in dem Fall :thumbup:
    Den kann man sich aber abschauen, falls man flackerfreie GDI+ Anwendungen haben will^^
    (Ein Doppelpuffer ermöglicht es z.B. beim WM_PAINT ein aktuelles Bild anzuzeigen, obwohl gerade parallel Objekte gezeichnet werden. Und das ohne Mehrbelastung für das Skript. Das einzige was man braucht sind ein Paar KB Ram für die Bitmap.)

    Hier das Skript:

    Spolier
    [autoit]

    #AutoIt3Wrapper_Run_AU3Check=N

    [/autoit] [autoit][/autoit] [autoit]

    #include <GDIPlus.au3>
    ;~ #include <Misc.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt('GUIOnEventMode', 1)

    [/autoit] [autoit][/autoit] [autoit]

    ; Je kleiner, desto höher die Auflösung, desto höher die Prozessauslastung.
    Global Const $iQuali = 5

    [/autoit] [autoit][/autoit] [autoit]

    ; Je kleiner, desto niedriger die Prozessorlast. (Kommazahlen sind erlaubt ! (z.B. 0.5))
    Global Const $nFPS = 15

    [/autoit] [autoit][/autoit] [autoit]

    ; Je größer, desto mehr Rechtecke werden gezeichnet
    Global Const $iAnzahl = 50

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global Const $iW = Int(@DesktopWidth/$iQuali), $iH = (@DesktopHeight/$iQuali), $iZoom = @DesktopWidth/$iW

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Global Const $iW = 400, $iH = Int($iW / 16 * 10), $iZoom = 2
    Global Const $sTitel = 'Bubble Wars'

    [/autoit] [autoit][/autoit] [autoit]

    Global $hDLL_GDI32 = DllOpen('GDI32.dll')

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    Global $hGUI = GUICreate($sTitel, $iW*$iZoom, $iH*$iZoom, 0, 0, 0x80000000)

    [/autoit] [autoit][/autoit] [autoit]

    Global $hDC_GUI = _WinAPI_GetDC($hGUI)

    [/autoit] [autoit][/autoit] [autoit]

    Global $hBUF_Back[2] = [_Image_Create($iW, $iH),_Image_Create($iW, $iH)]
    Global $hGFX_Back[2] = [_GDIPlus_GraphicsCreateFromHDC(DllStructGetData($hBUF_Back[0],1,1)),_GDIPlus_GraphicsCreateFromHDC(DllStructGetData($hBUF_Back[1],1,1))]
    Global $iBuf_Back = 0

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsSetSmoothingMode($hGFX_Back[0], 2)
    _GDIPlus_GraphicsSetSmoothingMode($hGFX_Back[1], 2)

    [/autoit] [autoit][/autoit] [autoit]

    Global $hDC_BUF = DllStructGetData($hBUF_Back[1], 1, 1)
    Global $hGFX_BUF = $hGFX_Back[1]

    [/autoit] [autoit][/autoit] [autoit]

    Global $aCol[6] = [0x08FF0000, 0x0700FF00, 0x0A0000FF, 0x08FFFF00, 0x07FF00FF, 0x0900FFFF]
    Global $aBru[UBound($aCol)]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($aCol)-1 Step 1
    $aBru[$i] = _GDIPlus_BrushCreateSolid($aCol[$i])
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Global $hBRU = _GDIPlus_BrushCreateSolid(0x08FF0000)
    ;~ Global $hBRU2 = _GDIPlus_BrushCreateSolid(0x0800FF00)
    ;~ Global $hBRU3 = _GDIPlus_BrushCreateSolid(0x0A0000FF)

    [/autoit] [autoit][/autoit] [autoit]

    Global $fAuslastung

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg(0xF, 'WM_PAINT')
    OnAutoItExitRegister('_Freigeben')
    GUISetOnEvent(-3, '_Event')
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Func _Main()
    While True
    $fAuslastung = _FPS($nFPS)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $iAnzahl Step 1
    _RndRect($aBru[Random(0, UBound($aBru)-1, 1)])
    ;~ _RndCirc($aBru[Random(0, UBound($aBru)-1, 1)])
    Next

    [/autoit] [autoit][/autoit] [autoit]

    DRAW()
    WEnd
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _RndCirc($hBRU)
    Switch Random(0, 1, 1)
    Case 0
    Local $x = Random(0, $iW), $y = Random(0, $iH), $b = Random(0, $iW-$x) , $h = Random(0, $iH-$y)
    Case 1
    Local $b = Random(0, $iW) , $h = Random(0, $iH), $x = Random(0, $iW-$b), $y = Random(0, $iH-$h)
    EndSwitch
    _GDIPlus_GraphicsFillEllipse($hGFX_BUF, $x, $y, $b, $h, $hBRU)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _RndRect($hBRU)
    Switch Random(0, 1, 1)
    Case 0
    Local $x = Random(0, $iW), $y = Random(0, $iH), $b = Random(0, $iW-$x) , $h = Random(0, $iH-$y)
    Case 1
    Local $b = Random(0, $iW) , $h = Random(0, $iH), $x = Random(0, $iW-$b), $y = Random(0, $iH-$h)
    EndSwitch
    DllCall($ghGDIPDll, 'int', 'GdipFillRectangleI', 'handle', $hGFX_BUF, 'handle', $hBRU, 'int', $x, 'int', $y, 'int', $b, 'int', $h)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Freigeben()

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($aCol)-1 Step 1
    _GDIPlus_BrushDispose($aBru[$i])
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ;~ _GDIPlus_BrushDispose($hBRU)
    ;~ _GDIPlus_BrushDispose($hBRU2)
    ;~ _GDIPlus_BrushDispose($hBRU3)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDispose($hGFX_Back[0])
    _GDIPlus_GraphicsDispose($hGFX_Back[1])
    _Image_Delete($hBUF_Back[0])
    _Image_Delete($hBUF_Back[1])
    _WinAPI_ReleaseDC($hGUI, $hDC_GUI)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Shutdown()
    DllClose($hDLL_GDI32)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Event()
    Switch @GUI_CtrlId
    Case -3
    Exit
    EndSwitch
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func DRAW()
    $hDC_BUF = DllStructGetData($hBUF_Back[$iBuf_Back], 1, 1)
    $hGFX_BUF = $hGFX_Back[$iBuf_Back]
    $iBUF_Back = 1-$iBUF_Back
    WM_PAINT()
    _GDIPlus_GraphicsClear($hGFX_BUF)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func SWAP(ByRef $a, ByRef $b)
    Local $c = $a
    $a = $b
    $b = $c
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_PAINT()
    Local Static $FPS, $FPS_Timer = TimerInit()
    If TimerDiff($FPS_Timer) > 1000 Then
    WinSetTitle($hGUI, '', $sTitel & ' - [ FPS: '& $FPS &' | Last: '&Round(100*$fAuslastung,0)&'% ]')
    $FPS = 0
    $FPS_Timer = TimerInit()
    EndIf
    DllCall($hDLL_GDI32, 'int', 'StretchBlt', 'hwnd', $hDC_GUI, 'int', 0, 'int', 0, 'int', $iW*$iZoom, 'int', $iH*$iZoom, 'hwnd', DllStructGetData($hBUF_Back[$iBuf_Back], 1, 1), 'int', 0, 'int', 0, 'int', $iW, 'int', $iH, 'dword', 0xCC0020)
    $FPS += 1
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _FPS($s)
    Static $z = TimerInit(), $y
    Local $x = TimerDiff($z), $w = (1000 / $s - $x)
    $y += $w
    If $y < 0 Then $y = 0
    If $w < 0 Then $w = 0
    Sleep(Int($y / 10) * 10)
    $y -= Int($y / 10) * 10
    $z = TimerInit()
    Return $x / ($x + $w)
    EndFunc ;==>C

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Create($iW, $iH)
    Local $Ptr, $hDC, $hBmp, $tBMI, $aDIB, $vStruct
    $hDC = _WinAPI_CreateCompatibleDC(0)
    $tBMI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, "Width", $iW)
    DllStructSetData($tBMI, "Height", -$iH)
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32)
    $aDIB = DllCall($hDLL_GDI32, 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hBmp = $aDIB[0]
    $Ptr = $aDIB[4]
    _WinAPI_SelectObject($hDC, $hBmp)
    $vStruct = DllStructCreate('int[5]')
    DllStructSetData($vStruct, 1, $hDC, 1)
    DllStructSetData($vStruct, 1, $iW, 2)
    DllStructSetData($vStruct, 1, $iH, 3)
    DllStructSetData($vStruct, 1, $Ptr, 4)
    DllStructSetData($vStruct, 1, $hBmp, 5)
    Return $vStruct
    EndFunc ;==>_Image_Create

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Delete(ByRef $vStruct)
    _WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
    $vStruct = 0
    EndFunc ;==>_Image_Delete

    [/autoit]


    .
    .

  • Finde ich cool! :)
    Allerdings ist's für meinen Geschmack ein bisschen zu wild (=schnell).
    Die Sache mit den Einstellungsmöglichkeiten ist auch gut, habe bei diesen Einstellungen etwa 2-4% Prozessorauslastung, allerdings anfangs 20%:

    [autoit]

    ; Je kleiner, desto höher die Auflösung, desto höher die Prozessauslastung.
    Global Const $iQuali = 5

    [/autoit][autoit][/autoit][autoit]

    ; Je kleiner, desto niedriger die Prozessorlast. (Kommazahlen sind erlaubt ! (z.B. 0.5))
    Global Const $nFPS = 20

    [/autoit][autoit][/autoit][autoit]

    ; Je größer, desto mehr Rechtecke werden gezeichnet
    Global Const $iAnzahl = 40

    [/autoit]

    Edit: Nach erneutem Test ca. 1-2%, lässt sich wohl nicht sogut nachweisen, wenn noch andere Prozesse laufen...
    Noch was: Am besten lässt du noch die Maus verschwinden

    4 Mal editiert, zuletzt von CyRoX (7. August 2012 um 22:55)

  • Hey,
    sieht ja ganz kuhl aus.
    Ich würde es eig. ganz schicker finden, wenn du den Übergang viel langsammer und vielleicht so verschwommen gestalten könntest.
    Sonst sieht es ganz gut aus.

  • Sieht echt interessant aus.
    Wäre mit grelleren und kräftigeren Farben bestimmt noch viel besser.
    Was wäre mit anderen Shapes? Kreisen, Dreiecken?
    :thumbup:

    [autoit]


    Func Ulam($n)
    Return 1
    EndFunc

    [/autoit]


    Rekursion FTW :D

  • Hi,

    Zitat

    Das Beste am Skript ist ein Doppelpuffer, der aber garnicht nötig ist in dem Fall

    made my day :thumbup:

    Zitat

    Den kann man sich aber abschauen, falls man flackerfreie GDI+ Anwendungen haben will
    (Ein Doppelpuffer ermöglicht es z.B. beim WM_PAINT ein aktuelles Bild anzuzeigen, obwohl gerade parallel Objekte gezeichnet werden. Und das ohne Mehrbelastung für das Skript. Das einzige was man braucht sind ein Paar KB Ram für die Bitmap.)

    die Idee ist nicht neu^^
    "Damals", in der 8-bit-Ära, hat man den ersten Puffer ins Ram der Grafikkarte geschrieben und während der Anzeige den 2. Puffer vollgeschrieben. Die beiden Puffer waren natürlich im RAM und man konnte einfach die Anfangsadresse in die "Grafikkarte" (CGA, EGA und wer richtig Kohle hatte, sogar HERCULES) mappen.....hach war des scheeee :rock:

    Nichtsdesto trotz wird auch heutzutage ein Schuh draus, es werden x Prozessoren und y Threads verwendet, wer das letzte bisschen Performance herauskitzeln muss, der verwendet je Thread einen Buffer 8o