Partielles Update eines ImageGadgets?

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Beitrag von Kurzer »

Nein, das läuft alles in dem Haupthread der Exe.
Ich habe erwartet, daß die Messages von Windows aber asynchron dazu abgearbeitet werden. -> Ein Trugschluß

Was (fast) funktioniert ist das InvalidateRect_(), um die neu zu zeichenende Rasterline zu markieren und ein darauffolgendes UpdateWindow_(). Das sendet eine WM_PAINT Message direkt an das Fenster, also unter Umgehung der Message-Warteschlange.

Hier der betreffende Code, der die Daten kopiert und das Gadget aktualisiert:

Code: Alles auswählen

		For i = 0 To ImageSettings_Destination\dsBitmap\bmHeight - 1
			For j = 0 To ImageSettings_Destination\dsBitmap\bmWidth - 1

				Pixel = PeekL(ImageSettings_Original\dsBitmap\bmBits + j * (ImageSettings_Original\dsBitmap\bmBitsPixel / 8) + ImageSettings_Original\dsBitmap\bmWidthBytes * i) & $00FFFFFF

				; Do some Pixelmanipulations here
				[...]

				PokeB(ImageSettings_Destination\dsBitmap\bmBits + j * (ImageSettings_Destination\dsBitmap\bmBitsPixel / 8) + 0 + ImageSettings_Destination\dsBitmap\bmWidthBytes * i, (Pixel & $FF)          ) ; blau
				PokeB(ImageSettings_Destination\dsBitmap\bmBits + j * (ImageSettings_Destination\dsBitmap\bmBitsPixel / 8) + 1 + ImageSettings_Destination\dsBitmap\bmWidthBytes * i, (Pixel & $FF00)   >> 8 ) ; grün
				PokeB(ImageSettings_Destination\dsBitmap\bmBits + j * (ImageSettings_Destination\dsBitmap\bmBitsPixel / 8) + 2 + ImageSettings_Destination\dsBitmap\bmWidthBytes * i, (Pixel & $FF0000) >> 16) ; rot

			Next j
			If ProgramSettings\Preview And i % 1 = 0
				IvRect\left = 0
				IvRect\top = i
				IvRect\right = ImageSettings_Destination\dsBitmap\bmWidth
				IvRect\bottom = i+1
				InvalidateRect_(GadgetID(#ImageGadget_Destination), @IvRect, #True)
				UpdateWindow_(GadgetID(#ImageGadget_Destination))
 			EndIf
		Next i
Allerdings auch hier wieder der Effekt, daß nur die erste Hälfte des Bitmaps redrawed wird.

EDIT: Ich raff jetzt gar nichts mehr! Das RECT für InvalidateRect sieht jetzt so aus:

Code: Alles auswählen

				rcInvalidate\left = 0
				rcInvalidate\top = 0
				rcInvalidate\right = ImageSettings_Destination\dsBitmap\bmWidth - 1
				rcInvalidate\bottom = i+1
				InvalidateRect_(GadgetID(#ImageGadget_Destination), @rcInvalidate, #True)
				UpdateWindow_(GadgetID(#ImageGadget_Destination))
Die Zählschleife für i geht von 0 bis bis Bildhöhe - 1. Das Invalidtae-Rect geht jetzt von 0,0 bis Bildbreite, Aktuelle Zeile +1.

Aber: Das Bild wird jetzt von der Mitte(!) ausgehend gleichzeitig nach unten und oben gezeichnet. Das ist völlig unlogisch. Ich erwarte, das das Bild zeilenweise von oben nach unten gezeichnet wird. Evtl. noch von unten nach oben, je nach Speicherorganisation des Bitmaps.
Aber von der Mitte je immer eine Zeile nach unten und(!) nach oben gehend kann doch eigentlich nicht sein?

In etwa so baut sich das dann auf:

Code: Alles auswählen

+----------------+
|                |
|                |
|                |
|----------------|
|                |
|                |
|                |
+----------------+

+----------------+
|                |
|                |
|----------------|
|----------------|
|----------------|
|                |
|                |
+----------------+

+----------------+
|                |
|----------------|
|----------------|
|----------------|
|----------------|
|----------------|
|                |
+----------------+

+----------------+
|----------------|
|----------------|
|----------------|
|----------------|
|----------------|
|----------------|
|----------------|
+----------------+
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.12 x64, OS: Win 11 24H2 x64, Desktopscaling: 150%, CPU: I7 12700 H, RAM: 32 GB, GPU: Intel(R) Iris(R) Xe Graphics | NVIDIA GeForce RTX 3070
Useralter in 2025: 57 Jahre.
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Beitrag von PMV »

Du kommst um das aufrufen von (Wait)WindowEvent() nicht drumrum.
Wenn du das ganze in einem Fenster zur Laufzeit sichtbar machen willst
und das dort auch abbrechbar sein soll.

Eine alternative ... sofern die Schleife nicht all zu lange braucht pro
durchlauf, wäre wenn du dort

Code: Alles auswählen

While WindowEvent() : Wend
hinzufügst. Im prinzip könnteste auch dann in dieser Schleife noch
etweilige Events abfragen wie klicken auf das X oder einen Button. So
sparst dir natürlich den Thread :wink:

Ein einzellnes WindowEvent() bringt nie 100% etwas.

Code: Alles auswählen

         If ProgramSettings\Preview And i % 1 = 0
äh i % 1 = 0? ... dann dürfte es ja klar sein, warum nur jedes 2. genutzt
wird.

MFG PMV
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Beitrag von Kurzer »

Das ich bei langen Rechenoperationen die GUI nicht bedienen kann, darum geht es mir noch gar nicht.
Das mit dem Redraw des Gadgets scheint ja unter Umgehung der Message Queue zu funktionieren. Jedenfalls wird im Gadget jetzt jede neue Zeile sofort angezeigt.
Ich verstehe gerade nur nicht wieso das von der Mitte ausgeht.
Vielleicht ist die RECT Struktur auch anders zu verstehen oder Windows geht von einem unüblichen Koordinatensystem aus..? Ich weiß es nicht, würde es aber gern wissen, weil ich die Ausgabe im Imagegadget beim besten Willen nicht nachvollziehen kann.

Edit: Nein es wird nicht jedes zweite genutzt. Wenn alle Zeilen bearbeitet sind, dann ist das Bild auch vollständig zu sehen. Kein Jalousien-Effekt.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.12 x64, OS: Win 11 24H2 x64, Desktopscaling: 150%, CPU: I7 12700 H, RAM: 32 GB, GPU: Intel(R) Iris(R) Xe Graphics | NVIDIA GeForce RTX 3070
Useralter in 2025: 57 Jahre.
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Beitrag von PMV »

Ja ok ... du schickst jetzt immer von 0 bis zur aktuellen Zeile nen
priorisiertes #WM_Paint. Warum das jetzt Zentriert gemalt wird, kann ich
dir nicht sagen. Mich stört aber weiterhin, dass du nur UpdateWindow_()
aufrufst, ohne ne vernünftige WindowEvent()-Schleife. Aber egal, das was
ich jetzt von dir weis würde ich mal behaupten, es liegt nicht an deinem
RECT.

MFG PMV
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Beitrag von Kurzer »

Das Programm hat eine vernünftige Eventschleife.

Ich habe das Preview-Fenster jetzt mal isoliert und den Code dafür lauffähig gemacht (inkl. prima Eventschleife ;-) ).
Es wird ein Fenster geöffnet und zwei ImageGadgets nebeneinander angezeigt. Mit Klick auf den Button Start werden die Pixel des linken Images in das Image rechts kopiert. Dabei wird der Helligkeitswert halbiert.

Dieser Code demonstriert einwandfrei das Problem, da die Schleife von 0 bis 300 zählt, aber das validieren und anzeigen der Zeilen von der Mitte ausgeht. Damit man es verfolgen kann, habe ich noch ein Delay(1) eingebaut.

Probiert es selbst.

Code: Alles auswählen

Enumeration
  #ImageGadget_Original
  #ImageGadget_Destination
  #Button_Go
EndEnumeration

Enumeration
  #ImageID_Original
  #ImageID_Destination
EndEnumeration

Structure Image
	dsBitmap.BITMAP					; Bitmapstruktur des Images
; 	LONG   bmType; 		
;   LONG   bmWidth; 
;   LONG   bmHeight; 
;   LONG   bmWidthBytes;	; tatsächliche Breite der Bitplane
;   WORD   bmPlanes; 
;   WORD   bmBitsPixel;		; Bittiefe der Bitplane 
;   LPVOID bmBits; 				; Zeiger auf den memorybereich
EndStructure

Global ImageSettings_Original.Image
Global ImageSettings_Destination.Image

OpenWindow(0, 2, 42, 106, 20, "Preview", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_TitleBar)
CreateGadgetList(WindowID(0))
ImageGadget(#ImageGadget_Original, 5, 5, 10, 10, 0)
ImageGadget(#ImageGadget_Destination, 20, 5, 10, 10, 0)
ButtonGadget(#Button_Go, 10, 3, 80, 15, "Start")

CreateImage(#ImageID_Original, 300, 300, 24) 
CreateImage(#ImageID_Destination, 300, 300, 24)

GetObject_(ImageID(#ImageID_Original), SizeOf(BITMAP), @ImageSettings_Original\dsBitmap)
GetObject_(ImageID(#ImageID_Destination), SizeOf(BITMAP), @ImageSettings_Destination\dsBitmap)

hDC = StartDrawing(ImageOutput(#ImageID_Original))		
	Box(0, 0, ImageSettings_Original\dsBitmap\bmWidth, ImageSettings_Destination\dsBitmap\bmHeight, RGB($aa, $aa, $aa))
StopDrawing()

hDC = StartDrawing(ImageOutput(#ImageID_Destination))		
	Box(0, 0, ImageSettings_Destination\dsBitmap\bmWidth, ImageSettings_Destination\dsBitmap\bmHeight, RGB($aa, $aa, $aa))
StopDrawing()

ResizeWindow(0, #PB_Ignore, #PB_Ignore, 30 + ImageSettings_Original\dsBitmap\bmWidth * 2, 30 + ImageSettings_Original\dsBitmap\bmHeight)
SetGadgetState(#ImageGadget_Original, ImageID(#ImageID_Original))
ResizeGadget(#ImageGadget_Original, 10, 20, ImageSettings_Original\dsBitmap\bmWidth, ImageSettings_Original\dsBitmap\bmHeight)

SetGadgetState(#ImageGadget_Destination, ImageID(#ImageID_Destination))
ResizeGadget(#ImageGadget_Destination, 320, 20, ImageSettings_Destination\dsBitmap\bmWidth, ImageSettings_Destination\dsBitmap\bmHeight)


Procedure Kopieren()
	Protected hDC.l, X.l, Y.l, W.l, H.l, D.l, Pixel.l, rcInvalidate.RECT

	hDC = StartDrawing(ImageOutput(#ImageID_Destination))		
		Box(0, 0, ImageSettings_Destination\dsBitmap\bmWidth, ImageSettings_Destination\dsBitmap\bmHeight, RGB($aa, $aa, $aa))
	StopDrawing()
	SetGadgetState(#ImageGadget_Destination, ImageID(#ImageID_Destination))
	
		For i = 0 To ImageSettings_Destination\dsBitmap\bmHeight - 1
			For j = 0 To ImageSettings_Destination\dsBitmap\bmWidth - 1

				Pixel = PeekL(ImageSettings_Original\dsBitmap\bmBits + j * (ImageSettings_Original\dsBitmap\bmBitsPixel / 8) + ImageSettings_Original\dsBitmap\bmWidthBytes * i) & $00FFFFFF
			
				; ... hier werden die Pixel dunkler gemacht (/2) und kopiert...
				Pixel / 2

				PokeB(ImageSettings_Destination\dsBitmap\bmBits + j * (ImageSettings_Destination\dsBitmap\bmBitsPixel / 8) + 0 + ImageSettings_Destination\dsBitmap\bmWidthBytes * i, (Pixel & $FF)          ) ; blau
				PokeB(ImageSettings_Destination\dsBitmap\bmBits + j * (ImageSettings_Destination\dsBitmap\bmBitsPixel / 8) + 1 + ImageSettings_Destination\dsBitmap\bmWidthBytes * i, (Pixel & $FF00)   >> 8 ) ; grün
				PokeB(ImageSettings_Destination\dsBitmap\bmBits + j * (ImageSettings_Destination\dsBitmap\bmBitsPixel / 8) + 2 + ImageSettings_Destination\dsBitmap\bmWidthBytes * i, (Pixel & $FF0000) >> 16) ; rot

			Next j

			; HIERRUM GEHTS
			rcInvalidate\left = 0
			rcInvalidate\top = 0
			rcInvalidate\right = ImageSettings_Destination\dsBitmap\bmWidth
			rcInvalidate\bottom = i
			InvalidateRect_(GadgetID(#ImageGadget_Destination), @rcInvalidate, #True)
			UpdateWindow_(GadgetID(#ImageGadget_Destination))

			; Eigentlich korrekt wäre das hier, aber das funzt nur bis zur Hlfte des Images
; 			rcInvalidate\left = 0
; 			rcInvalidate\top = i
; 			rcInvalidate\right = ImageSettings_Destination\dsBitmap\bmWidth
; 			rcInvalidate\bottom = i+1
; 			InvalidateRect_(GadgetID(#ImageGadget_Destination), @rcInvalidate, #True)
; 			UpdateWindow_(GadgetID(#ImageGadget_Destination))
			; HIERRUM GEHTS

			Delay (1)
		Next i

EndProcedure


Repeat

  Event       = WaitWindowEvent(25)
  EventGadget = EventGadget()
  
  Select Event
    Case #PB_Event_Gadget
      Select EventGadget
        Case #Button_Go
        	Kopieren()
      EndSelect
  EndSelect

Until Event = #PB_Event_CloseWindow
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.12 x64, OS: Win 11 24H2 x64, Desktopscaling: 150%, CPU: I7 12700 H, RAM: 32 GB, GPU: Intel(R) Iris(R) Xe Graphics | NVIDIA GeForce RTX 3070
Useralter in 2025: 57 Jahre.
Benutzeravatar
Deluxe0321
Beiträge: 336
Registriert: 19.05.2006 00:31
Kontaktdaten:

Beitrag von Deluxe0321 »

Hab mal ein wenig gespielt, kenne mich mit dem Zeug eigentlich überhaupt nicht aus ^^
In dieser Form zeichnet er von unten nach oben..

Code: Alles auswählen

          ;Eigentlich korrekt wäre das hier, aber das funzt nur bis zur Hlfte des Images
          Debug ImageSettings_Destination\dsBitmap\bmHeight - i
          rcInvalidate\left = 0
          rcInvalidate\top = 0
          rcInvalidate\right = ImageSettings_Destination\dsBitmap\bmWidth
          rcInvalidate\bottom = ImageSettings_Destination\dsBitmap\bmHeight - i
          InvalidateRect_(GadgetID(#ImageGadget_Destination), @rcInvalidate, #True)
          UpdateWindow_(GadgetID(#ImageGadget_Destination))
         ; HIERRUM GEHTS
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Beitrag von Kurzer »

Deluxe0321, mein Goldjunge! :allright: Das war der entscheidende Hinweis.

Wenn die Ursache auch diese besch%&§ Intel Speicher-Architektur ist, dann fange ich langsam an sie zu hassen.

Der Speicherbereich von Bitmaps scheint unten rechts zu beginnen und nach oben links heraufzuzählen. Ich bin es gewohnt, daß der Speicherbereich von Bildern oben links beginnt und bis unten recht raufgezählt wird.

Byte1, Byte2, Byte3, Byte4,
Byte5, Byte6, Byte7, Byte8,
Byte9, Byte10, Byte11, Byte12
usw.

Also habe ich die ganze Zeit die Bitmap entgegengesetzt refresht, wie ich die Daten kopiert habe. Ahhhhhrg!

So ist es jetzt richtig:

Code: Alles auswählen

			rcInvalidate\left = 0
			rcInvalidate\top = ImageSettings_Destination\dsBitmap\bmHeight - i - 1
			rcInvalidate\right = ImageSettings_Destination\dsBitmap\bmWidth
			rcInvalidate\bottom = ImageSettings_Destination\dsBitmap\bmHeight - i
			InvalidateRect_(GadgetID(#ImageGadget_Destination), @rcInvalidate, #True)
			UpdateWindow_(GadgetID(#ImageGadget_Destination))
Nochmal danke für den Denkanstoß.

btw: Kann mir jemand erklären, ob das nur eine Eigenart von Bitmaps ist oder ob ich diesen Krampf bei jeder Art von Speicherzugriff auf nem Intel-System habe? (bin Ex-Amiganer)
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.12 x64, OS: Win 11 24H2 x64, Desktopscaling: 150%, CPU: I7 12700 H, RAM: 32 GB, GPU: Intel(R) Iris(R) Xe Graphics | NVIDIA GeForce RTX 3070
Useralter in 2025: 57 Jahre.
Benutzeravatar
dige
Beiträge: 1239
Registriert: 08.09.2004 08:53

Beitrag von dige »

Die Bitmap ist nicht von rechts unten nach oben links im Speicher,
sondern Zeilenweise (von links nach rechts) von unten nach oben aufgebaut.
Das hat imho nichts mit Intel zu tun, das ist eine Windows-Eigenheit, oder?

Du kannst das auch visualisieren, indem Du Dir einen Zeiger auf die DIB
Sektion holst, inkrementell Zufallswerte hinweinschreibst und Dir das Bild
erneut anzeigen lässt.
"Papa, ich laufe schneller - dann ist es nicht so weit."
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Das hat imho nichts mit Intel zu tun, das ist eine Windows-Eigenheit, oder?
Ja, ist es. Wieder so ein spezielles "feature"...
Windows 10 Pro, 64-Bit / Outtakes | Derek
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

hab ich auch nicht gewusst... hätt ich auch gestutzt...

aber wieder typisch Billy... der Arsch des Jahrhunderts...
Herr, lass es Torten regnen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Antworten