Seite 2 von 3

Verfasst: 18.03.2008 22:14
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

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

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

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

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

Verfasst: 18.03.2008 22:58
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

Verfasst: 18.03.2008 23:08
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.

Verfasst: 18.03.2008 23:35
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

Verfasst: 18.03.2008 23:59
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

Verfasst: 19.03.2008 20:34
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

Verfasst: 19.03.2008 22:43
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)

Verfasst: 20.03.2008 15:27
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.

Verfasst: 20.03.2008 16:14
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"...

Verfasst: 20.03.2008 16:25
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.