[GDI+] Einfaches Laden und Anzeigen von Animationen

  • Moin,

    Es ist nur ein sehr kleines Skript, kann aber sicherlich vielerorts gebraucht werden.
    Das Prinzip habe ich aus CreepTD abgeschaut. (Dort werden Gegner und Tower mit dieser Methode animiert)

    Funktionsweise:
    Man erstellt ein mit GDI+ kompatibeles Bild (z.B. png) welches nebeneinander gereiht sämtliche Frames enthält. Das resultierende Bild ist ein Pixel höher als eigentlich nötig und die obere Zeile ist vollkommen transparent. Zu Beginn jedes Frames setzt man oben links (also außerhalb des angezeigten Bereichs) einen Pixel mit der Hexadezimalen Darstellung der Framedauer. (z.B. 0xFF0000FF = 255 ms).

    Ist ein Bild so präpariert kann man es direkt laden und animiert anzeigen lassen.
    Ähnliche Skripte gibt es schon (auch für gif), aber ich denke dieses hier ist sehr einfach (selbst für völlige Laien) verständlich und leicht zu benutzen.

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>

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

    Global $hGUI, $hGFX, $hBMP, $hBUF, $hANI

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

    _GDIPlus_Startup()

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

    $hGUI = GUICreate('Test', 300, 300)
    $hGFX = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBMP = _GDIPlus_BitmapCreateFromGraphics(300, 300, $hGFX)
    $hBUF = _GDIPlus_ImageGetGraphicsContext($hBMP)
    $hANI = _GDIPlus_AnimationCreateFromFile('Test.png')

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

    _GDIPlus_GraphicsSetInterpolationMode($hBUF, 5)
    _GDIPlus_GraphicsSetPixelOffsetMode($hBUF, 2)

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

    GUISetState()

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

    While GUIGetMsg() <> -3
    _GDIPlus_GraphicsClear($hBUF, 0xFF808080)
    _GDIPlus_GraphicsDrawAnimationRect($hBUF, $hANI, 50, 50, 200, 200)
    _GDIPlus_GraphicsDrawImage($hGFX, $hBMP, 0, 0)
    WEnd

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

    _GDIPlus_AnimationDispose($hANI)
    _GDIPlus_GraphicsDispose($hBUF)
    _GDIPlus_BitmapDispose($hBMP)
    _GDIPlus_GraphicsDispose($hGFX)
    _GDIPlus_Shutdown()

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

    Func _GDIPlus_AnimationCreateFromFile($sPath)
    Local $aRET[8] ; 0 - ImageHandle, 1 - Breite, 2 - Höhe, 3 - Anzahl, 4 - Timer, 5 - Aktuelles Bild, 6 - TimeArray
    $aRET[0] = _GDIPlus_ImageLoadFromFile($sPath)
    If @error Then Return SetError(@error, 0, 0)
    $aRET[2] = _GDIPlus_ImageGetHeight($aRET[0]) - 1
    Local $iW = _GDIPlus_ImageGetWidth($aRET[0])
    For $i = 1 To $iW - 1 Step 1
    If Not _GDIPlus_BitmapGetPixel($aRET[0], $i, 0) = 0 Then ExitLoop
    Next
    $aRET[3] = Int(Round($iW / $i, 0))
    $aRET[1] = $i
    Local $aTIME[$aRET[3]]
    For $i = 0 To $aRET[3] - 1 Step 1
    $aTIME[$i] = BitAND(0xFFFFFF, _GDIPlus_BitmapGetPixel($aRET[0], $i * $aRET[2], 0))
    Next
    $aRET[4] = TimerInit()
    $aRET[5] = 0
    $aRET[6] = $aTIME
    Return $aRET
    EndFunc

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

    Func _GDIPlus_GraphicsDrawAnimationRect($hGFX, ByRef $hANI, $iX, $iY, $iW, $iH)
    Local $aTIME = $hANI[6]
    If TimerDiff($hANI[4]) > $aTIME[$hANI[5]] Then
    $hANI[4] = TimerInit()
    $hANI[5] += 1
    If $hANI[5] = $hANI[3] Then $hANI[5] = 0
    EndIf
    ToolTip(Int(TimerDiff($hANI[4])) & '/' & $aTIME[$hANI[5]]) ; Nur zur demonstration, daher später unbedingt auskommentieren !
    _GDIPlus_GraphicsDrawImageRectRect($hGFX, $hANI[0], $hANI[1] * $hANI[5], 1, $hANI[1], $hANI[2], $iX, $iY, $iW, $iH)
    EndFunc

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

    Func _GDIPlus_AnimationDispose(ByRef $hANI)
    _GDIPlus_ImageDispose($hANI[0])
    $hANI = 0
    EndFunc

    [/autoit]


    PS: Da ImageDrawRectRect benutzt wird ist ggf ein Pixeloffset zu setzen (wie im Beispiel), da ansonsten die Ränder falsch angezeigt werden. Der Interpolationmode ist nur optischer Schnickschnack, weil das Bild 16x16 Px groß ist.

    [Fix]: Grober Schnitzer in der Annahme jedes Bild wäre 16px breit :D

    lg
    M