Seite 1 von 2

Zeitkritische Routine optimieren

Verfasst: 27.03.2010 01:49
von mpz
Hallo Leute,

ich arbeite gerade mit Images und Texturen und habe eine Routine geschrieben die ich aus Zeitgründen optimieren möchte. Vielleicht hat jemand einen Tipp (speziell Windows)? Die folgende Routine lädt ein Image in den Arbeitsspeicher und die drei Farben und der Alpha Wert werden aktiv verändert. Dazu benötigt mein Rechner allerdings 38,5 Sekunden...

die spezielle zeitkritische Routine

Code: Alles auswählen

 ;---------------------------------------- Zeitkritische Routine
 ;CheckVal = Ausnamefarbe die nicht geändert werden darf
 
 max =  *Pointer + ImageWidth(Image) * ImageHeight(Image) << 2
 *Pointer + color
 While *Pointer < max

     If PeekB(*Pointer) <> CheckVal
        PokeB( *Pointer , ColorVal )
     EndIf
     *Pointer + 4 ; Vier Sprünge weiter da der RGBA Wert ein .l Wert ist
           
 Wend 
;-----------------------------------------
 


Kompletter Beispielcode

Code: Alles auswählen

  
ImageW = 375
ImageH = 350

Global *Memory = AllocateMemory(ImageW * ImageH << 2 )

Procedure CopyImageToMemory(ImageNumber, Memory)

   Protected TemporaryDC.L, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO

    TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
    
    GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
       
    TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
    TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
    TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
    TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
    TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
    TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB

    GetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)

    DeleteDC_(TemporaryDC)
    
EndProcedure

Procedure CopyMemoryToImage(Memory, ImageNumber)
  
     Protected TemporaryDC.L, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
  
    TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
    
    GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)

    TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
    TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
    TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
    TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
    TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
    TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
   
    SetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
    
    DeleteDC_(TemporaryDC)
  
EndProcedure


Procedure MP_ImageSetColor (Image, Color, ColorVal, CheckVal) ;  Verändert destruktiv eine ARGB Farbe um einen FestenWert, mit Ausnamecheck 
 *Pointer = *Memory 
 CopyImageToMemory(Image, *Memory) 
 ;---------------------------------------- Zeitkritische Routine
 ;CheckVal = Ausnamefarbe die nicht geändert werden darf
 
 max =  *Pointer + ImageWidth(Image) * ImageHeight(Image) << 2
 *Pointer + color
 While *Pointer < max

     If PeekB(*Pointer) <> CheckVal
        PokeB( *Pointer , ColorVal )
     EndIf
     *Pointer + 4 ; Vier Sprünge weiter
           
 Wend 
;-----------------------------------------
 CopyMemoryToImage(*Memory, 0)

EndProcedure




;
; ------------------------------------------------------------
;
;   PureBasic - 2D Drawing example file (alpha channel demo)
;
;    (c) 2009 - Fantaisie Software
;
; ------------------------------------------------------------
;



If OpenWindow(0, 0, 0, 375, 350, "Alphachannel demo", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
 
  
  If CreateImage(0, ImageW, ImageH, 32) And StartDrawing(ImageOutput(0))
 
    ; Make the whole image transparent

    ;
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, 375, 350, $00000000)
   
    ; The classic Circle-thing :)
    ;
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    Circle( 187,  225, 100, RGBA(255,   0,   0, 128))

    Circle(250,  125, 100, RGBA(  0, 255,   0, 128))

    Circle(125, 125, 100, RGBA(  0,   0, 255, 128))
   
    StopDrawing()
  EndIf
 
  If CreateImage(1, ImageW, ImageH, 32)
  EndIf
 
 ; Hier mein Code zum speichern und neu laden


 #box_size = 7
 
  StartTime = ElapsedMilliseconds()             ; ermittelt den aktuellen Wert
 
  Repeat

    a + 1
    
    If a > 255
       a = 1
       b+1
    EndIf   
    If b > 3

        ElapsedTime = ElapsedMilliseconds()-StartTime
        MessageRequester("Zeitmessung", "Dauer = "+Str(ElapsedTime))
        StartTime = ElapsedMilliseconds()
        b = 0
        
    EndIf   
        
    MP_ImageSetColor (0, b, a, 0)
    
    ; Mal Image
    StartDrawing(ImageOutput(1))
        Box(0, 0, 375, 350, $FFFFFF)
        For y = 0 To 350 Step #box_size*2
         For x = 0 To 375 Step #box_size*2
           Box(x, y, #box_size, #box_size, $C0C0C0)
           Box(x+#box_size, y+#box_size, #box_size, #box_size, $C0C0C0)
         Next x
        Next y 
        DrawAlphaImage(ImageID(0), 0, 0)
    StopDrawing()
      
    
    StartDrawing(WindowOutput(0))
        DrawAlphaImage(ImageID(1), 0, 0)
    StopDrawing()

 
  Until WindowEvent() = #PB_Event_CloseWindow
EndIf




Gruß Michael

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 02:17
von gnasen
Ohne den großen Batzen genauer angeschaut zu haben, den kleinen müsstest du etwas schneller machen können, indem du
auf das peeken und poken verzichtest:

Code: Alles auswählen

Structure sbyte
  b.b
EndStructure

Define *pointer.sbyte
Define test.b = 5

*pointer = @test
*pointer\b = 3

Debug test
Ob das viel ausmacht kann ich nicht sagen, aber ist mir gerade spontan dazu eingefallen. Habe gerade einen Speedtest mit vielen vielen vielen solcher Memory schreibereien gemacht, und die direkte Variante ohne peek/poke ist bei mir ca. 20% schneller. Immerhin ein Anfang ;)

Edit:
Kann es sein, dass du im großen Batzen, neben der vllt schnellen Veränderung des Alpha Wertes, elendig lahme Draw-Blöcke hast? Genau genommen spreche ich von diesem hier:

Code: Alles auswählen

StartDrawing(ImageOutput(1))
      Box(0, 0, 375, 350, $FFFFFF)
      For y = 0 To 350 Step #box_size*2
        For x = 0 To 375 Step #box_size*2
          Box(x, y, #box_size, #box_size, $C0C0C0)
          Box(x+#box_size, y+#box_size, #box_size, #box_size, $C0C0C0)
        Next x
      Next y 
      DrawAlphaImage(ImageID(0), 0, 0)
    StopDrawing()
    
    
    StartDrawing(WindowOutput(0))
      DrawAlphaImage(ImageID(1), 0, 0)
    StopDrawing()
Der wird in jedem Schritt gemacht, oder nicht?

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 02:27
von STARGÅTE
hmm, habe zwar kein richtigen Plan davon was du eigentlich willst, aber in PB kannst du seit kurzem eine vielzahl von Effekten in PB selber benutzen:
- CustomFilterCallback()

vorallem kannst du das auch ohne API und kopiererei des Momorys vorgehen,
dafür gibs ja auch DrawingBuffer()
("Mit ImageOutput() ermöglicht dieser Befehl direkten Zugriff auf die Pixel des Ziel-Bildes.")

Wenn du noch mal "Die folgende Routine lädt ein Image in den Arbeitsspeicher und die drei Farben und der Alpha Wert werden aktiv verändert." genauer erklären könntest, könnte ich dir n beispielcode schrieben

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 02:32
von gnasen

Code: Alles auswählen

ImageW = 375
ImageH = 350

Global *Memory = AllocateMemory(ImageW * ImageH << 2 )

Procedure CopyImageToMemory(ImageNumber, Memory)
  
  Protected TemporaryDC.L, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
  
  TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
  
  GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
  
  TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
  TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
  TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
  TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
  TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
  
  GetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
  
  DeleteDC_(TemporaryDC)
  
EndProcedure

Procedure CopyMemoryToImage(Memory, ImageNumber)
  
  Protected TemporaryDC.L, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
  
  TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
  
  GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
  
  TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
  TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
  TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
  TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
  TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
  
  SetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
  
  DeleteDC_(TemporaryDC)
  
EndProcedure

Procedure MP_ImageSetColor (image, color, ColorVal, CheckVal) ;  Verändert destruktiv eine ARGB Farbe um einen FestenWert, mit Ausnamecheck 
  *Pointer = *Memory 
  CopyImageToMemory(image, *Memory) 
  ;---------------------------------------- Zeitkritische Routine
  ;CheckVal = Ausnamefarbe die nicht geändert werden darf
  
  max =  *Pointer + ImageWidth(image) * ImageHeight(image) << 2
  *Pointer + color
  While *Pointer < max
    
    If PeekB(*Pointer) <> CheckVal
      PokeB( *Pointer , ColorVal )
    EndIf
    *Pointer + 4 ; Vier Sprünge weiter
    
  Wend 
  ;-----------------------------------------
  CopyMemoryToImage(*Memory, 0)
  
EndProcedure




;
; ------------------------------------------------------------
;
;   PureBasic - 2D Drawing example file (alpha channel demo)
;
;    (c) 2009 - Fantaisie Software
;
; ------------------------------------------------------------
;



If OpenWindow(0, 0, 0, 375, 350, "Alphachannel demo", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  
  
  If CreateImage(0, ImageW, ImageH, 32) And StartDrawing(ImageOutput(0))
      
      ; Make the whole image transparent
      
      ;
      DrawingMode(#PB_2DDrawing_AlphaChannel)
      Box(0, 0, 375, 350, $00000000)
      
      ; The classic Circle-thing :)
      ;
      DrawingMode(#PB_2DDrawing_AlphaBlend)
      Circle( 187,  225, 100, RGBA(255,   0,   0, 128))
      
      Circle(250,  125, 100, RGBA(  0, 255,   0, 128))
      
      Circle(125, 125, 100, RGBA(  0,   0, 255, 128))
      
    StopDrawing()
  EndIf
  
  If CreateImage(1, ImageW, ImageH, 32)
  EndIf
  
  ; Hier mein Code zum speichern und neu laden
  
  
  #box_size = 7
  
  StartTime = ElapsedMilliseconds()             ; ermittelt den aktuellen Wert
  
  ; Mal Image
  StartDrawing(ImageOutput(1))
    Box(0, 0, 375, 350, $FFFFFF)
    For y = 0 To 350 Step #box_size*2
      For x = 0 To 375 Step #box_size*2
        Box(x, y, #box_size, #box_size, $C0C0C0)
        Box(x+#box_size, y+#box_size, #box_size, #box_size, $C0C0C0)
      Next x
    Next y 
    DrawAlphaImage(ImageID(0), 0, 0)
  StopDrawing()
  
  Repeat
    
    a + 1
    
    If a > 255
      a = 1
      b+1
    EndIf   
    If b > 3
      
      ElapsedTime = ElapsedMilliseconds()-StartTime
      MessageRequester("Zeitmessung", "Dauer = "+Str(ElapsedTime))
      StartTime = ElapsedMilliseconds()
      b = 0
      
    EndIf   
    
    MP_ImageSetColor (0, b, a, 0)
    
    StartDrawing(ImageOutput(1))
      DrawAlphaImage(ImageID(0), 0, 0)
    StopDrawing()
    
    StartDrawing(WindowOutput(0))
      DrawAlphaImage(ImageID(1), 0, 0)
    StopDrawing()
    
    
  Until WindowEvent() = #PB_Event_CloseWindow
EndIf
So brauchts bei mir noch 5 Sekunden, aber dennoch scheint mir das etwas viel Aufwand. Das kopieren des Images von A nach B und zurück, sowie diverse Drawing-Blöcke scheinen sehr Ressourcenlastig zu sein. Da ich mich aber nur wenig bis gar nicht mit dem auskenne, was du da treibst, fragste besser den Stargate ;)

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 02:34
von ts-soft
was gnasen im ersten Beitrag meinte:

Code: Alles auswählen

Procedure MP_ImageSetColor (Image, Color, ColorVal, CheckVal) ;  Verändert destruktiv eine ARGB Farbe um einen FestenWert, mit Ausnamecheck
  *Pointer.byte = *Memory
  CopyImageToMemory(Image, *Memory)
  ;---------------------------------------- Zeitkritische Routine
  ;CheckVal = Ausnamefarbe die nicht geändert werden darf

  max =  *Pointer + ImageWidth(Image) * ImageHeight(Image) << 2
  *Pointer + color
  While *Pointer < max

    ;      If PeekB(*Pointer) <> CheckVal
    ;         PokeB( *Pointer , ColorVal )
    ;      EndIf
    If *Pointer\b <> CheckVal
      *Pointer\b = ColorVal
    EndIf
    *Pointer + 4 ; Vier Sprünge weiter

  Wend
  ;-----------------------------------------
  CopyMemoryToImage(*Memory, 0)

EndProcedure
Bringt aber in diesem Falle eigentlich garnichts, da die meiste Zeit in den Copyroutinen rumgemurkst wird.
siehe Posting von STARGÅTE

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 02:42
von Little John
gnasen hat geschrieben:Ohne den großen Batzen genauer angeschaut zu haben, den kleinen müsstest du etwas schneller machen können, indem du
auf das peeken und poken verzichtest:

Code: Alles auswählen

Structure sbyte
  b.b
EndStructure

Define *pointer.sbyte
Define test.b = 5

*pointer = @test
*pointer\b = 3

Debug test
Das würe ich auch machen.

Es geht allerdings noch etwas einfacher, da es in PureBasic für jeden elementaren Datentyp eine entspr. vordefinierte Struktur gibt (siehe Strukturverzeichnis):

Code: Alles auswählen

Define *pointer.Byte
Define test.b = 5

*pointer = @test
*pointer\b = 3

Debug test
Gruß, Little John

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 03:05
von STARGÅTE
Also hier nun erst mal die verbesserte variante mit dem DrawingBuffer()

Code: Alles auswählen

  
ImageW = 375
ImageH = 350



Procedure MP_ImageSetColor (Image, Color, ColorVal.a, CheckVal.a) ;  Verändert destruktiv eine ARGB Farbe um einen FestenWert, mit Ausnamecheck 
  StartDrawing(ImageOutput(Image))
    *Mem.Ascii = DrawingBuffer() 
    *max = *Mem + ImageWidth(Image) * ImageHeight(Image) << 2
    *Mem + color
    While *Mem < *max
      If *Mem\a <> CheckVal
       *Mem\a = ColorVal
      EndIf
      *Mem + 4 ; Vier Sprünge weiter
    Wend 
  StopDrawing() 
EndProcedure




;
; ------------------------------------------------------------
;
;   PureBasic - 2D Drawing example file (alpha channel demo)
;
;    (c) 2009 - Fantaisie Software
;
; ------------------------------------------------------------
;

#box_size = 7

 
CreateImage(4, ImageW, ImageH)
StartDrawing(ImageOutput(4))
        Box(0, 0, 375, 350, $FFFFFF)
        For y = 0 To 350 Step #box_size*2
         For x = 0 To 375 Step #box_size*2
           Box(x, y, #box_size, #box_size, $C0C0C0)
           Box(x+#box_size, y+#box_size, #box_size, #box_size, $C0C0C0)
         Next x
        Next y 
StopDrawing()


If OpenWindow(0, 0, 0, 375, 350, "Alphachannel demo", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

  
  If CreateImage(0, ImageW, ImageH, 32) And StartDrawing(ImageOutput(0))

    ; Make the whole image transparent

    ;
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, 375, 350, $00000000)
   
    ; The classic Circle-thing :)
    ;
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    Circle( 187,  225, 100, RGBA(255,   0,   0, 128))

    Circle(250,  125, 100, RGBA(  0, 255,   0, 128))

    Circle(125, 125, 100, RGBA(  0,   0, 255, 128))
   
    StopDrawing()
  EndIf

  If CreateImage(1, ImageW, ImageH, 32)
  EndIf

; Hier mein Code zum speichern und neu laden

 StartTime = ElapsedMilliseconds()             ; ermittelt den aktuellen Wert

  Repeat

    a + 1
    
    If a > 255
       a = 1
       b+1
    EndIf   
    If b > 3

        ElapsedTime = ElapsedMilliseconds()-StartTime
        MessageRequester("Zeitmessung", "Dauer = "+Str(ElapsedTime))
        StartTime = ElapsedMilliseconds()
        b = 0
        
    EndIf   
    
    
    MP_ImageSetColor (0, b, a, 0)
    
    ; Mal Image
    StartDrawing(ImageOutput(1))
        DrawImage(ImageID(4), 0, 0)
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        DrawImage(ImageID(0), 0, 0)
    StopDrawing()
      
    
    StartDrawing(WindowOutput(0))
        DrawAlphaImage(ImageID(1), 0, 0)
    StopDrawing()


  Until WindowEvent() = #PB_Event_CloseWindow
EndIf

Da habe ich ohne debugger 5s, bei deinem code hatte ich 7

Kommentiert man jedoch die "eigentliche" Funktion aus MP_ImageSetColor (0, b, a, 0)

passiert zwar nix, aber der Code braucht immer noch fast 5s !

eigentlich langsamme ist hier also das StartDrawing(WindowOutput(0)) an sich !
bzw das Alphablending des Image 0 !

die FarbänderungsProcedure ist also schnell genug !

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 03:10
von mpz
Hi,

ich habe versucht ein kleines Demo nachzubilden. Das mit den Image in den Speicher laden soll nur bewirken das ich nicht Point und Plot machen muss, sondern direkt in die Image Datei schreiben und lesen kann. Ich bin damit in der Lage die Alphatransparenz (durchsichtigkeit) von Körpern und auch Farbveränderungen "on the fly" vorzunehmen. Die "zeitkritische Routine" für meine DX9 Textur sind quasi dieselbe, wobei ich aber direkt in den memorybereich der Textur schreibe (nichts mit Memorygemurkse :))

http://em.q-soft.ch/files/get/PA1MslNELz/alphatest.exe


Das mit

Code: Alles auswählen

*Pointer.byte = *Memory
...
 If *Pointer\b <> CheckVal
    *Pointer\b = ColorVal
 EndIf
baue ich schon mal ein...

Gruß Michael

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 06:17
von STARGÅTE
Das mit den Image in den Speicher laden soll nur bewirken das ich nicht Point und Plot machen muss, sondern direkt in die Image Datei schreiben und lesen kann
hää?

Das Image ist doch im Speicher (wo auch sonst :? ) ... und ich benutze auch kein Point und Plot >_< ... sonden den DrawingBuffer() womit ich "on the fly" einen Pixel ändern kann ...
Die "zeitkritische Routine" für meine DX9 Textur sind quasi dieselbe, wobei ich aber direkt in den memorybereich der Textur schreibe (nichts mit Memorygemurkse )
Von Texturen war hier in den Codes nie die rede, denn da fällt StartDrawing und co weg, da es kein OutputTexture() mehr gibt ...

Trotz alle dem, ist die oben gepostete Variante zum Messen der Zeit total falsch, weil dort eben die andere Befehle das ganze langsam machen. Dort müsstest du die Zeit wirklich nur von der Procedure selber messen.

Re: Zeitkritische Routine optimieren

Verfasst: 27.03.2010 10:53
von mpz
Hi Stargate,

vielleicht habe ich mich etwas umständlich ausgedrückt. Ich möchte "einfach" nur eine optimale Routine haben um Speicherbereiche zu manipulieren und damit die Farbe von Images und Texturen. Ob man invertiert, heller macht, mehr Kontrast etc. ist ja nur eine Manipulation von den "FarbBytes" über +, - , * und / ...

Meine Idee mit dem MemoryCopy ist schneller als Point und Plot. Was ich aber nicht wusste ist die Möglichkeit des direkten manipulieren des DrawBuffers. Hier ein vielleicht einfacheres Beispiel: Ein Image wird einfach nur 400 mal invertiert. Wer kann diese Routine noch mehr optimieren (zeitlich gesehen!). Vermutlich ist eine ASM Routine schneller oder API Call ?!?

Dauer mit Point und Plot = 3219
Dauer mit Memory = 2031
Dauer mit Buffer = 1547

Diese Routine noch schneller ?!?

Code: Alles auswählen

While *Pointer < max

     *Pointer\b = 255-*Pointer\b
     *Pointer + 1 
           
 Wend

Gruß Michael

Democode

Code: Alles auswählen


DisableDebugger

ImageW = 375
ImageH = 350

Global *Memory = AllocateMemory(ImageW * ImageH << 2 )

Procedure CopyImageToMemory(ImageNumber, Memory)

   Protected TemporaryDC.L, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO

    TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
    
    GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
       
    TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
    TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
    TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
    TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
    TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
    TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB

    GetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)

    DeleteDC_(TemporaryDC)
    
EndProcedure

Procedure CopyMemoryToImage(Memory, ImageNumber)
  
     Protected TemporaryDC.L, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
  
    TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
    
    GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)

    TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
    TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
    TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
    TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
    TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
    TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
   
    SetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
    
    DeleteDC_(TemporaryDC)
  
EndProcedure

Procedure ImageInvert(image)    
       
   Protected color.i, red.i, green.i, blue.i 
   Protected x.i, y.i 

    
   StartDrawing(ImageOutput(image)) 
      For x = 0 To ImageWidth(image) - 1 
         For y = 0 To ImageHeight(image) - 1 
            
            
            color    = Point(x, y) 
            red    = Red(color) 
            green    = Green(color) 
            blue    = Blue(color) 
            alpha   = Alpha(color) 
             
            Plot(x, y, RGBA(255-red, 255-green, 255-blue, 255-alpha) ) 
             
         Next 
      Next        
   StopDrawing() 
    
EndProcedure 

Procedure MP_ImageInvert(Image) ;  
 *Pointer.Byte = *Memory 
 CopyImageToMemory(Image, *Memory) 

 ;---------------------------------------- Zeitkritische Routine
 max =  *Pointer + ImageWidth(Image) * ImageHeight(Image) << 2
 While *Pointer < max

     *Pointer\b = 255-*Pointer\b
     *Pointer + 1 
           
 Wend 
;-----------------------------------------
 CopyMemoryToImage(*Memory, 0)

EndProcedure


Procedure MP_ImageInvertBuffer(Image) ; 
 
 StartDrawing(ImageOutput(Image))
 *Pointer.Byte = DrawingBuffer()
 max =  *Pointer + ImageWidth(Image) * ImageHeight(Image) << 2
 While *Pointer < max

     *Pointer\b = 255-*Pointer\b
     *Pointer + 1 
           
 Wend 
 StopDrawing() 

EndProcedure


If OpenWindow(0, 0, 0, 375, 350, "Image Inverter", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

  ; Alphachannel output image
  ;
    If CreateImage(0, ImageW, ImageH, 32) And StartDrawing(ImageOutput(0))
 
    ; Make the whole image transparent

    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, 375, 350, $00000000)
   
    ; The classic Circle-thing :)
    ;
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    Circle( 187,  225, 100, RGBA(255,   0,   0, 128))
    Circle(250,  125, 100, RGBA(  0, 255,   0, 128))
    Circle(125, 125, 100, RGBA(  0,   0, 255, 128))
   
    StopDrawing()
  EndIf

  StartTime = ElapsedMilliseconds()

  For n = 0 To 400
     ImageInvert(0)
  Next n
   
  ElapsedTime1 = ElapsedMilliseconds()-StartTime
  Debug "First"
  StartTime = ElapsedMilliseconds()
  
  For n = 0 To 400
     MP_ImageInvert(0)
  Next n
  ElapsedTime2 = ElapsedMilliseconds()-StartTime
  
  Debug "Second"
  StartTime = ElapsedMilliseconds()
  
  For n = 0 To 400
     MP_ImageInvertBuffer(0)
  Next n
  ElapsedTime3 = ElapsedMilliseconds()-StartTime
  
  ImageGadget(0, 0, 0, 0, 0, ImageID(0))
  
  MessageRequester("Zeitmessung InvImage", "Dauer mit Point und Plot = "+Str(ElapsedTime1)+Chr(10)+"Dauer mit Memory = "+Str(ElapsedTime2)+Chr(10)+"Dauer mit Buffer = "+Str(ElapsedTime3))
  
  Repeat
  Until WindowEvent() = #PB_Event_CloseWindow
 
EndIf