GDI+ - Skript beschleunigen und Linien abrunden

  • Hi,
    ich habe dank UEZ's Vorlagen ein Skript erstellen können, dass die Mausbewegung nachzeichnet und nach einer bestimmten Zeitspanne nach und nach ausblendet.
    Leider sind die nachgezeichneten Linien nicht wirklich rund bzw. 'flüssig' und meine Mathekenntnisse sind beschränkt, da ich wohl sonst sowas wie Splines probieren würde.
    Wie kann man die beabsichtigten Kurven wirklich rund machen?
    Zudem komme ich beim Ausführen auf genau 85 gezeichnete Linien, kann man das noch beschleunigen, sodass da noch mehr geht?
    Die Anzahl der Linien wird im Titel angezeigt, bzw. in $time[0] gespeichert.

    Hier das Skript:

    Spoiler anzeigen
    [autoit]

    #include <GuiConstantsEx.au3>
    #include <GDIPlus.au3>
    #include <Array.au3>
    Opt("MustDeclareVars", 1)
    Opt("GUIOnEventMode", 1)

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

    Global Const $Width = 700
    Global Const $Height = 700
    Global $hGUI, $hWnd, $hGraphic, $ParticleBitmap, $ParticleBuffer, $Pen

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

    Global $ParticlesX[1]
    Global $ParticlesY[1]
    $ParticlesX[0] = 0
    $ParticlesY[0] = 0
    Global $Time[1], $Pos

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

    ; Create GUI
    $hGUI = GUICreate("Fading Polygon by XovoxKingdom - #Polygon = 0", $Width, $Height)
    $hWnd = WinGetHandle($hGUI)
    GUISetState()

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

    _GDIPlus_Startup()
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)
    $ParticleBitmap = _GDIPlus_BitmapCreateFromGraphics($Width, $Height, $hGraphic)
    $ParticleBuffer = _GDIPlus_ImageGetGraphicsContext($ParticleBitmap)
    _GDIPlus_GraphicsSetSmoothingMode($ParticleBuffer,4)

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

    _GDIPlus_GraphicsClear($ParticleBuffer) ;clear buffer
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

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

    ; Loop until user exits
    Do
    _GDIPlus_GraphicsClear($ParticleBuffer, 0xCF000000) ;clear buffer

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

    $Pos = GUIGetCursorInfo()
    If IsArray($Pos) Then
    _ArrayAdd($ParticlesX, $Pos[0])
    _ArrayAdd($ParticlesY, $Pos[1])
    _ArrayAdd($Time, 255)
    $Time[0] += 1
    EndIf

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

    For $i = $Time[0] To 1 Step -1
    If $Time[$i] = 0 Then
    _ArrayDelete($Time, $i)
    _ArrayDelete($ParticlesX, $i)
    _ArrayDelete($ParticlesY, $i)
    $Time[0] -= 1
    EndIf
    Next

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

    For $i = 1 To $Time[0]
    $Pen = _GDIPlus_PenCreate("0x" & Hex($Time[$i], 2) & "FFFFFF", 1)
    If $Time[0] = 1 Then
    _GDIPlus_GraphicsDrawRect($ParticleBuffer, $ParticlesX[$i], $ParticlesY[$i], 1, 1, $Pen)
    ElseIf $i < $Time[0] Then
    _GDIPlus_GraphicsDrawLine($ParticleBuffer, $ParticlesX[$i], $ParticlesY[$i], $ParticlesX[$i + 1], $ParticlesY[$i + 1], $Pen)
    Else
    _GDIPlus_GraphicsDrawRect($ParticleBuffer, $ParticlesX[$i], $ParticlesY[$i], 1, 1, $Pen)
    EndIf
    _GDIPlus_PenDispose($Pen)
    $Time[$i] -= 3
    Next

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

    _GDIPlus_GraphicsDrawImageRect($hGraphic, $ParticleBitmap, 0, 0, $Width, $Height) ;copy to bitmap

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

    WinSetTitle($hGUI, "", "Fading Polygon by XovoxKingdom - #Polygon = " & $Time[0])

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

    Until Not True

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

    Func _Exit()
    ; Clean up resources
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_BitmapDispose($ParticleBitmap)
    _GDIPlus_GraphicsDispose($ParticleBuffer)
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit]

    Wer immer nur das tut, was er bereits kann - wird auch immer nur das bleiben, was er bereits ist!

    Einmal editiert, zuletzt von XovoxKingdom (3. April 2013 um 11:34)

  • 1. Arrayfunktionen sind immer relativ langsam (je größer das Array, desto langsamer)
    Das liegt daran, dass Arrays einen festen Peicherplatz belegen. Bei jeder Größenänderung mit Redim (in Add und Delete vorhanden) wird das komplette Array kopiert.
    2. DrawImageRect langsamer als DrawImage langsamer als BitBlt (erfordert einige Umstellung im Skript)
    3. Pencreate + Pendispose langsamer als PenSetCol (lieber nur einen Pen nutzen un den immer färben, statt andauernd neue zu erstellen und zu löschen)

  • Hi,
    Arrayfunktionen reichen von der Geschwindigkeit her locker aus.
    Wenn man das Script mal ausstoppt, stellt man fest, dass DrawImageRect() ca. 100-200ms braucht, in dieser Zeit holt und schreibt man Millionenmal ein Array^^
    Also geht es darum, das schreiben in den Grafikspeicher zu beschleunigen, da bietet sich natürlich bitblt() an:

    Spoiler anzeigen
    [autoit]

    #include <GuiConstantsEx.au3>
    #include <GDIPlus.au3>
    #include <Array.au3>
    ;Opt("MustDeclareVars", 1)
    Opt("GUIOnEventMode", 1)

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

    Global Const $W = 700
    Global Const $H = 700
    Global $hGUI, $hWnd, $hGraphic, $ParticleBitmap, $ParticleBuffer, $Pen, $pen2, $anz

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

    Global $ParticlesX[110]
    Global $ParticlesY[110]
    Global $Time[1], $Pos, $t, $m

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

    ; Create GUI
    $GUI = GUICreate("Fading Polygon by XovoxKingdom - #Polygon = 0", $W, $H)
    $hWnd = WinGetHandle($hGUI)
    GUISetState()

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

    _GDIPlus_Startup()
    $IMG = _Image_Create($W, $H)
    $BUF = DllStructGetData($IMG, 1)
    $DC = _WinAPI_GetDC($GUI)
    $GFX = _GDIPlus_GraphicsCreateFromHDC($BUF)

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

    _GDIPlus_GraphicsClear($ParticleBuffer) ;clear buffer
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

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

    ; Loop until user exits
    Do
    _GDIPlus_GraphicsClear($GFX, 0xCF000000) ;clear buffer

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

    ;$Pen = _GDIPlus_PenCreate("0xFFFFFFFF", 1)
    $Pos = GUIGetCursorInfo()
    Sleep(10)
    If IsArray($Pos) Then
    $ParticlesX[$anz] = $Pos[0]
    $ParticlesY[$anz] = $Pos[1]
    $anz += 1

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

    $t = TimerInit()
    For $i = 3 To $anz - 4 Step 3
    $Pen = _GDIPlus_PenCreate("0x" & Hex($i * 2, 2) & "FFFFFF", 1)
    _GDIPlus_GraphicsDrawBezier($GFX, $ParticlesX[$i], $ParticlesY[$i], $ParticlesX[$i + 1], $ParticlesY[$i + 1], $ParticlesX[$i + 2], $ParticlesY[$i + 2], $ParticlesX[$i + 3], $ParticlesY[$i + 3], $Pen)
    Next
    $m = TimerDiff($t)
    _WinAPI_BitBlt($DC, 0, 0, $W, $H, $BUF, 0, 0, 0xCC0020)
    If $anz > 100 Then ;maximum erreicht
    For $t = 1 To $anz ;bögen löschen
    $ParticlesX[$t] = $ParticlesX[$t + 3]
    $ParticlesY[$t] = $ParticlesY[$t + 3]
    Next
    $anz -=4
    EndIf
    EndIf

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

    Until Not True

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

    Func _Exit()
    ; Clean up resources
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_BitmapDispose($ParticleBitmap)
    _GDIPlus_GraphicsDispose($ParticleBuffer)
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit] [autoit][/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('GDI32.DLL', '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][/autoit]

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (2. April 2013 um 16:48)

  • Vielen Dank Andy!
    Ich werde mir bitblt wohl nochmal genauer angucken müssen, damit ich das komplett nachvollziehen kann.

    Wer immer nur das tut, was er bereits kann - wird auch immer nur das bleiben, was er bereits ist!

  • Hi,
    das Gerödel mit _GDIPlus_GraphicsDrawBezier() kann man imho weglassen. Ich würde nur Linien zeichnen, durch die extrem schnelle Abfrage (es ist jetzt schon ein Sleep() im Script! ) wird der Linienzug "fast" zum Bogen^^