Universal Pointer für Pixelzugriff

Für allgemeine Fragen zur Programmierung mit PureBasic.
SMaag
Beiträge: 150
Registriert: 08.05.2022 12:58

Universal Pointer für Pixelzugriff

Beitrag von SMaag »

Beim Studium des Source-Codes der PB-IDE bin ich auf eine Trick mit einem sog. Univeral-Pointer gestossen.
Dabei wird eine Union Structure verwendet, um Pointer auf virtuelle Arrays zu generieren. Das kann man verwenden, um Zeichenweise
durch Strings zu steppen oder wenn man das noch etwas weiter treibt, kann man Bitmaps Pixel für Pixel in einer Schleife durchlaufen und hat direkten Zugriff auf den 32Bit-Farbwert sowie auf die einzelnen R,G,B,Alpha Werte. Ohne dabei weiter mit Pointern und Peek, Poke auf Adressen zu hantieren.
Ich hab das erst gerade eben probiert! Es geht tatsächlich.

Hier das Beispiel für die Colors

Code: Alles auswählen

 
  
  CompilerIf #False  ; Maybe in any circumstance for future use
    ; ----------------------------------------------------------------------
    ; This is the Exception Alpha first
    ; ----------------------------------------------------------------------
    
    #idxRed   = 3  ; ByteIndex for RED     TColor\c[idxRed]
    #idxGreen = 2  ; ByteIndex for Green   TColor\c[idxGreen]
    #idxBlue  = 1  ; ByteIndex for Blue    TColor\c[idxBlue]
    #idxAlpha = 0  ; ByteIndex for Alpha   TColor\c[idxAlpha]
    #AlphaMask = $FF  ; BitMask for Alpha in Byte 0
    
  CompilerElse  ; x86, x64; ARM32; ARM64
    ; ----------------------------------------------------------------------
    ; This is the Standard Windows Alignment RED=LoByte .. Alpha=HiByte
    ; In Memory RGBA but in Processor Register ABGR  
    ; ----------------------------------------------------------------------
   
    #idxRed   = 0  ; ByteIndex for RED     TColor\c[idxRed]
    #idxGreen = 1  ; ByteIndex for Green   TColor\c[idxGreen]
    #idxBlue  = 2  ; ByteIndex for Blue    TColor\c[idxBlue]
    #idxAlpha = 3  ; ByteIndex for Alpha   TColor\c[idxAlpha]
    #AlphaMask = $FF000000  ; BitMask for Alpha in Byte 3
                            ; COLOR | AlphaMask sets the Alpha value To 255 (=$FF)
  CompilerEndIf
  
  ; Stadard Colors   
  #Black       = 0            ; RGB(0,0,0)
  #Blue        = 16711680     ; RGB(0,0,255)
  #Gray        = 8421504      ; RGB(128,128,128)
  #Green       = 65280        ; RGB(0,255,0)
  #Magenta     = 16711935     ; RGB(255,0,255) 
  #Orange      = 42495        ; RGB(255,165,0) 
  #OrangeRed   = 17919        ; RGB(255,69,0)
  #Pink        = 13353215     ; RGB(255,192,203)
  #Purple      = 8388736      ; RGB(128,0,128) 
  #Red         = 255          ; RGB(255,0,0)
  #White       = 16777215     ; RGB(255,255,255)
  #Violet      = 15631086     ; RGB(238,130,238)
  #Yellow      = 65535        ; RGB(255,255,0) 
  #YellowGreen = 3329434      ; RGB(154,205,50)
  
  #DarkBlue    = 9109504      ; RGB(0,0,139) 
  #DarkGray    = 11119017     ; RGB(169,169,169) 
  #DarkGreen   = 25600        ; RGB(0,100,0)
  #DarkMagenta = 9109643      ; RGB(139,0,139) 
  #DarkOrange  = 36095        ; RGB(255,140,0) 
  #DarkRed     = 139          ; RGB(139,0,0) 
  #DarkViolet  = 13828244     ; RGB(148,0,211) 
  #DeepPink    = 9639167      ; RGB(255,20,147) 
  
  #LightBlue   = 15128749     ; RGB(173,216,230)
  #LightGreen  = 9498256      ; RGB(144,238,144) 
  #LightGray   = 13882323     ; RGB(211,211,211) 
  #LightPink   = 12695295     ; RGB(255,182,193) 
  #LightYellow = 14745599     ; RGB(255,255,224)

  ; ----------------------------------------------------------------------
  ; TColor Union Structure! Use TColor to handle Colors instead of 
  ;                         a Standard 32Bit Value
  ; ----------------------------------------------------------------------
  Structure TColor
    StructureUnion
     Color.l      ; Access as 32Bit Long
     c.a[4]       ; Access as Array 4Bytes [0..3]
     ; c.a[4] defines a fixed 4Byte Array[0..3] for ASCI Bytes 0..255
    EndStructureUnion
  EndStructure
  
  ; das ist der Trick, man packt nun den TColor Typ in ein virtuelles Array der Länge 0
  ; Achtung! Das darf man nur als Pointer verwenden
  Structure pColor   ; univeral Pointer to a 32Bit color
    col.TColor[0]  
  EndStructure
  
  Define *pCol.pColor   ; hier erstellen wir nun unseren Poiinter auf ein virtuelle Array von TColor
  Dim MyColors.l(24)
  
  MyColors(0) = #Black
  MyColors(1) = #Blue
  MyColors(2) = #Gray
  MyColors(3) = #Green
  MyColors(4) = #Magenta
  MyColors(5) = #Orange
  MyColors(6) = #OrangeRed
  MyColors(7) = #Pink
  MyColors(8) = #Purple
  MyColors(9) = #Red
  MyColors(10) = #Violet
  MyColors(11) = #Yellow
  MyColors(12) = #YellowGreen
  MyColors(13) = #DarkGray
  MyColors(14) = #DarkGreen
  MyColors(15) = #DarkMagenta
  MyColors(16) = #DarkOrange
  MyColors(17) = #DarkRed
  MyColors(18) = #DarkViolet
  MyColors(19) = #DeepPink
  MyColors(20) = #LightBlue
  MyColors(21) = #LightGreen
  MyColors(22) = #LightGray
  MyColors(23) = #LightPink
  MyColors(24) = #LightYellow
  
  ; mit dem Pointer als virtuels TColor-Array, können wir nun Bitmaps in einer Schleife durchlaufen
  ; und haben bei jedem Pixel direkten Zugriff als 32Bit Color-Wert oder als einzelne Farbwerte R,G,B,A
  *pCol = @MyColors(0)    ; Set the universal color Pointer to first Array Entry =Black
  
  For I = 0 To 24
    With *pcol
      dbg$ = "Color = " + Str(\col[I]\Color) + #TAB$    ; Zugriff auf den 32Bit Farbwert
      dbg$ + " : R = " + \col[I]\c[#idxRed]             ; Zugriff auf den Rot-Wert
      dbg$ + " : G = " + \col[I]\c[#idxGreen]           ; Zugriff auf den Grün-Wert
      dbg$ + " : B = " + \col[I]\c[#idxBlue]            ; Zugriff auf den Grün-Wert
      Debug dbg$
    EndWith
  Next
  

Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Universal Pointer für Pixelzugriff

Beitrag von STARGÅTE »

Ja, StructureUnion und das universal-array [0] sind ein sehr mächtiges Feature.
Mann kann sogar negative Indizes übergeben um zum Beispiel das hinzufügen eines Offsets zu sparen:

Code: Alles auswählen

Structure Beispiel
	Buffer0.b[128] ; Speicherplatz für -128 bis -1
	Value.b[0]
	Buffer1.b[128] ; Speicherplatz für 0 bis 127
EndStructure

Define Beispiel.Beispiel

Beispiel\Value[-64] = 1
Beispiel\Value[32] = 2
Debug Beispiel\Value[-64]
Debug Beispiel\Value[32] 
Ein anderes Beispiel wäre der Umgang mit Fix-Strings, um Sub-Strings ohne viel Aufwand zu extrahieren:

Code: Alles auswählen

Structure ColorHTML
	StructureUnion
		String.s{6}
		Color.s{2}[3]
	EndStructureUnion
EndStructure

Define ColorHTML.ColorHTML
ColorHTML\String = "FFA050"

Debug ColorHTML\Color[0]
Debug ColorHTML\Color[1]
Debug ColorHTML\Color[2]
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Universal Pointer für Pixelzugriff

Beitrag von mk-soft »

Structure Innerhalt von StructureUnion ...

Code: Alles auswählen


Structure sRGBA
  Red.a
  Green.a
  Blue.a
  Alpha.a
EndStructure

Structure TColor
  StructureUnion
    Color.l      ; Access as 32Bit Long
    c.a[4]       ; Access as Array 4Bytes [0..3]
                 ; c.a[4] defines a fixed 4Byte Array[0..3] for ASCI Bytes 0..255
    Component.sRGBA
  EndStructureUnion
EndStructure

col.TColor
col\Color = RGBA(1,2,3,100)

Debug col\Component\Red
Debug col\Component\Green
Debug col\Component\Blue
Debug col\Component\Alpha
Denk daran das Intel Prozessoren eine Low High Byte Notation verwendet. Das heisst das im Speicher erst das Low Byte und dann das High Byte steht. (LittleEndian)
Das gilt auch bei ARM Prozessoren als Standard (Hier gibt es aber Ausnahmen und Einstellungen um die Notation zu ändern)
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
SMaag
Beiträge: 150
Registriert: 08.05.2022 12:58

Re: Universal Pointer für Pixelzugriff

Beitrag von SMaag »

Was da alles Möglich ist mit den richtigen Tricks!
Hat das schon mal jemand als Tutorial zusammengefasst?
Ein PureBasic for 'RunAways'?
Benubi
Beiträge: 186
Registriert: 22.10.2004 17:51
Wohnort: Berlin, Wedding

Re: Universal Pointer für Pixelzugriff

Beitrag von Benubi »

Und die 16/15bit im Structure bitte nicht vergessen ;)
Es geht schneller ein Word (.w) zu kopieren oder Farbwerte extrahieren/konvertieren als über zwei einzelne Bytes bei diesen Formaten.
Ich habe auch ein bissel mit 8-bit Bitmaps experimentiert, im Zusammenhang mit Erstellung von Zufallskarten, das wäre dann schon mit c[0] abgedeckt - 8bit Pixel können auch mal erscheinen. Und beim Pixelformat kann man auf jeweils BGR und RGB stoßen und das nuß man eben beachten oder die PB Funktionen RGB/RGBA benutzen welche das automatisch tun. Und oft stehen die Bilder auch auf dem Kopf. Wenn man sich die Mühe machen will kann man viele kleine optimierte Funktionen schreiben, oder eine welche alles benötigte auf einmal händelt.

Ich glaube es lassen sich auch 4bit und 1bit Bitmaps laden, und diese werden dann zu 8bit intern konvertiert aber das müsste man wieder mal testen.

Gut zu wissen, daß ARM und x86 das gleiche Byte-Order benutzen, ich dachte es wäre anders rum und sah das schon als Hindernis für Interoperabilität. Juti, juti. :)
SMaag
Beiträge: 150
Registriert: 08.05.2022 12:58

Re: Universal Pointer für Pixelzugriff

Beitrag von SMaag »

hab das mal so geändert!

Code: Alles auswählen

  Structure TColor
    StructureUnion
     Color.l      ; Access as 32Bit Long
     c.a[4]       ; Access as Array 4Bytes [0..3]                 
     w.u[2]       ; Access for 16/15 Bit Colors w As unsigned WORD (unicode)
    EndStructureUnion
  EndStructure

Antworten