DisplayTransparentSprite & AlphaKanal-Problem

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
KTX82
Beiträge: 95
Registriert: 31.08.2004 00:11
Wohnort: Mannheim
Kontaktdaten:

DisplayTransparentSprite & AlphaKanal-Problem

Beitrag von KTX82 »

Hi Leute!

ich steh sehr gewaltig auf dem Schlauch.
Ich erstelle ein Image mit Transparenz-Flag, erstelle ein Sprite mit AlphaBlending-Flag.
Auf das Image zeichne ich mit Vector-Funktionen ein wenig zum testen, zeichne das Image mit DrawAlphaImage auf das Sprite und lasse es mit DisplayTransparentSprite überlappend anzeigen.

Leider klappt es mit der Transparenz nicht, wie ich mir das vorstelle.
Lasse ich das Flag #PB_Sprite_AlphaBlending bei der Sprite-Erstellung weg, hat es nur einen Pseudo-Effekt. In diesem Moment wird nur Schwarz als Transparent angesehen, was aber nicht zweck der Übung ist.
Kann mir irgendwer auf die Sprünge helfen, wie ich die 2 Sprites unter Berücksichtigung des Alphakanals korrekt übereinander gelegt bekomme, sodass beide gerundeten Rechtecke korrekt und mit sauberer Kontur zu sehen sind und die 2 roten Flächen an der Stelle der Überlappung kräftiger werden (also wie normal zu erwarten)?

Für mein eigentliches Programm bin ich auf die Vector-Befehle angewiesen um zur Laufzeit Grafiken für die Sprites zu erstellen - allerdings ohne funktionierendes Alpha stehe ich jetzt vor einer Wand :-(
Danke euch schon mal riesig für einen kleinen Denkanstoß und hoffentlich einen guten Schlag gegen den Kopf.

Hier der Beispielcode zum aufzeigen meines Problems und wie ich es aktuell dachte zu lösen.
Zu erkennen, dass ich auch schon etwas mit DrawingMode und weglassen des Flags bei CreateSprite getestet habe, leider ohne Erfolg.

PS: Nicht wundern in der Procedure über sizeX und sizeY - bin kein Freund der Bezeichnungen width und heigth

Code: Alles auswählen

Procedure AddPathBoxRounded(x, y, sizeX, sizeY, radius, flags = #PB_Path_Default)
	MovePathCursor(x + radius, y, flags)
	AddPathArc(sizeX-radius, 0, sizeX-radius, radius, radius, #PB_Path_Relative)
	AddPathArc(0, sizeY-radius, -radius, sizeY-radius, radius, #PB_Path_Relative)
	AddPathArc(-sizeX+radius, 0, -sizeX+radius, -radius, radius, #PB_Path_Relative)
	AddPathArc(0, -sizeY+radius, radius, -sizeY+radius, radius, #PB_Path_Relative)
EndProcedure

If InitSprite() = 0
	MessageRequester("Error", "Can't open screen & sprite environment!", 0)
	End
EndIf

OpenWindow(0, 0, 0, 400, 300, "Test", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0), 0, 0, 400, 300, 0, 0, 0, #PB_Screen_WaitSynchronization)

tempimg = CreateImage(#PB_Any, 100, 100, 32, #PB_Image_Transparent)
spr = CreateSprite(#PB_Any, 100, 100, #PB_Sprite_AlphaBlending)
;spr = CreateSprite(#PB_Any, 100, 100)

If StartVectorDrawing(ImageVectorOutput(tempimg, #PB_Unit_Pixel))
	AddPathBoxRounded(1, 1, 98, 98, 40)
	VectorSourceColor(RGBA(255, 255, 255, 255))
	StrokePath(1, #PB_Path_Default)
	AddPathBox(40, 40, 20, 20)
	VectorSourceColor(RGBA(255, 0, 0, 100))
	FillPath()
	StopVectorDrawing()
EndIf

StartDrawing(SpriteOutput(spr))
	;DrawingMode(#PB_2DDrawing_AlphaBlend)
	DrawAlphaImage(ImageID(tempimg), 0, 0)
StopDrawing()


Repeat
	Repeat
		event = WindowEvent()
		Select event
			Case #PB_Event_CloseWindow : End
		EndSelect
	Until event = 0
	
	FlipBuffers()
	ClearScreen(RGB(127, 127, 127))
	DisplayTransparentSprite(spr, 0, 0)
	DisplayTransparentSprite(spr, 10, 10)
	Delay(2)
ForEver
Pharmacie populaire www.viagrasansordonnancefr.com aide aux malades
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: DisplayTransparentSprite & AlphaKanal-Problem

Beitrag von STARGÅTE »

Hallo KTX82,

StartDrawing() unterstützt bei SpriteOutput() leider nicht (offiziell) den Alpha-Kanal.
Ich sage deswegen offiziell, weil du theoretisch mit DrawingBuffer() das Sprite auch im Alpha-Kanal ändern könntest.

Die Einfachste Methode ist jedoch, einfach das Image mit EncodeImage speichern und dann mit CatchSprite wieder einlesen:

Code: Alles auswählen

Procedure CreateSpriteFromImage(Sprite.i, Image.i)
	Protected *Buffer, Result.i
	*Buffer = EncodeImage(Image, #PB_ImagePlugin_PNG)
	Result = CatchSprite(Sprite, *Buffer, #PB_Sprite_AlphaBlending)
	FreeMemory(*Buffer)
	ProcedureReturn Result
EndProcedure
Du brauchst dafür aber UsePNGImageDecoder() und UsePNGImageEncoder()
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
Derren
Beiträge: 557
Registriert: 23.07.2011 02:08

Re: DisplayTransparentSprite & AlphaKanal-Problem

Beitrag von Derren »

STARGÅTE hat geschrieben: StartDrawing() unterstützt bei SpriteOutput() leider nicht (offiziell) den Alpha-Kanal.
Ich sage deswegen offiziell, weil du theoretisch mit DrawingBuffer() das Sprite auch im Alpha-Kanal ändern könntest.

Die Einfachste Methode ist jedoch, einfach das Image mit EncodeImage speichern und dann mit CatchSprite wieder einlesen:
D'oh /:->

Das hat mich auch schon jede Menge Nerven gekostet. Danke für DEN Hinweis :praise:
Signatur und so
KTX82
Beiträge: 95
Registriert: 31.08.2004 00:11
Wohnort: Mannheim
Kontaktdaten:

Re: DisplayTransparentSprite & AlphaKanal-Problem

Beitrag von KTX82 »

Hallo STARGÅTE :)

Danke für die super Antwort. Als ich im Forum zuvor wegen diesem Problem recherchiert habe, habe ich zwar ein wenig gefunden, aber nichts, was zu 100% dieses Verhalten erklärt. Und zusätzlich danke für die einfache Lösung.

Ich werde meine Riecher aber mal nach der Variante mit DrawingBuffer() ausstrecken und ein paar Versuche wagen, da der Umweg über den PNG En-/Decoder zwar in der Tat sehr einfach ist, jedoch denke ich massig Performance schluckt wenn es darum geht sehr viele Sprites (100+) in kaum wahrnehmbarer Zeit zu erstellen.

Da ich mangels Erfahrung und früher nie damit beschäftigt, nicht so firm im Umgang mit Pointern bin, was ja, wie ich überall lese sehr gute Performanceverbesserungen bewirken soll, werde ich nach Erfolg hier hoffentlich trotzdem eine Procedere posten können, mit der man ein Image mit Alpha-Kanal dann in ein Sprite setzt. Sollte es dann natürlich einen einfachen Code in irgendeinem Post schon hierfür geben, wäre ich auch da über einen kleinen Hinweis dankbar, werde aber trotzdem versuchen erst mal selbst diesen Teil gelöst zu bekommen.
Pharmacie populaire www.viagrasansordonnancefr.com aide aux malades
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: DisplayTransparentSprite & AlphaKanal-Problem

Beitrag von STARGÅTE »

Der Beitrag hier ist zwar etwas älter, sollte aber noch funktionieren (wobei ja heute kein Sprite3D mehr nötig ist):
viewtopic.php?p=281008#p281008
(Funktioniert aber nur, wenn Image und Sprite im 32-Bit-Format vorliegen, weil der Fall sein sollte, wenn beides mit AlphaKanal erzeugt wird)
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
KTX82
Beiträge: 95
Registriert: 31.08.2004 00:11
Wohnort: Mannheim
Kontaktdaten:

Re: DisplayTransparentSprite & AlphaKanal-Problem

Beitrag von KTX82 »

Klasse! Der Code funktioniert in der Tat immer noch einwandfrei.
Ich habe mir erlaubt die Procedure nur minimal anzupassen, da zumindest für den Verwendungszweck mit dem Alphakanal eh immer #PB_Sprite_AlphaBlending benötigt wird und nur wahlweise #PB_Sprite_PixelCollision hinzukommt. So wird im Normalfall die Angabe des Flags bei Aufruf der Procedure nicht benötigt.

Mit dieser Procedure muss man zwar den gewünschten Sprite-Inhalt zuvor "vollständig" auf einem Image zeichnen und kann nicht diverse Images an verschiedenen Positionen ins Sprite nach und nach setzen, aber so wie es jetzt ist, ist exakt was ich benötige :-)
Und der Geschwindigkeitsvorteil + wesentlich weniger CPU-Last im Vergleich zur Variante mit dem Umweg über den PNG En-/Decoder ist gewaltig.

Schade, dass es so eine Funktion nicht in hoch optimierter Form schon mit den Bordmitteln gibt - irgendwie fast nicht nachvollziehbar für mich, da es für mich wie eine essentielle Grundlage wirkt.... hmmmm....
Hier jetzt aber noch der lauffähige Code mit der leicht angepassten Procedure:

Code: Alles auswählen

Procedure AddPathBoxRounded(x, y, sizeX, sizeY, radius, flags = #PB_Path_Default)
	MovePathCursor(x + radius, y, flags)
	AddPathArc(sizeX - radius, 0, sizeX - radius, radius, radius, #PB_Path_Relative)    ;oben
	AddPathArc(0, sizeY - radius, -radius, sizeY - radius, radius, #PB_Path_Relative)    ;rechts
	AddPathArc(-sizeX + radius, 0, -sizeX + radius, -radius, radius, #PB_Path_Relative)    ;unten
	AddPathArc(0, -sizeY + radius, radius, -sizeY + radius, radius, #PB_Path_Relative)	;links
EndProcedure

Procedure CreateSpriteFromAlphaImage(sprite, image, flags = #PB_Sprite_AlphaBlending)
	Protected row
	Protected imageHeight = ImageHeight(image)
	Protected imageWidth  = ImageWidth(image)
	Protected *ReadBuffer,  readPitch,  readFormat
	Protected *WriteBuffer, writePitch, writeFormat
	If flags = #PB_Sprite_PixelCollision
		flags | #PB_Sprite_AlphaBlending
	EndIf
	StartDrawing(ImageOutput(image))
		*ReadBuffer = DrawingBuffer()
		readPitch = DrawingBufferPitch()
		readFormat = DrawingBufferPixelFormat()
	StopDrawing()
	If sprite = #PB_Any
		sprite = CreateSprite(#PB_Any, imageWidth, imageHeight, flags)
	Else
		CreateSprite(sprite, imageWidth, imageHeight, flags)
	EndIf
	StartDrawing(SpriteOutput(sprite))
		*WriteBuffer = DrawingBuffer()
		writePitch = DrawingBufferPitch()
		writeFormat = DrawingBufferPixelFormat()
		If readFormat & #PB_PixelFormat_ReversedY XOr writeFormat & #PB_PixelFormat_ReversedY
			For row = 0 To imageHeight - 1
				CopyMemory(*ReadBuffer + (imageHeight - 1 - row) * readPitch, *WriteBuffer + row * writePitch, imageWidth * SizeOf(Long))
			Next
		Else
			For row = 0 To imageHeight - 1
				CopyMemory(*ReadBuffer + row * readPitch, *WriteBuffer + row * writePitch, imageWidth * SizeOf(Long))
			Next
		EndIf
	StopDrawing()
	ProcedureReturn sprite
EndProcedure

If InitSprite() = 0
	MessageRequester("Error", "Can't open screen & sprite environment!", 0)
	End
EndIf

OpenWindow(0, 0, 0, 400, 300, "Test", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0), 0, 0, 400, 300, 0, 0, 0, #PB_Screen_WaitSynchronization)

tempimg = CreateImage(#PB_Any, 100, 100, 32, #PB_Image_Transparent)
If StartVectorDrawing(ImageVectorOutput(tempimg, #PB_Unit_Pixel))
	AddPathBoxRounded(1, 1, 98, 98, 40)
	VectorSourceColor(RGBA(255, 255, 255, 255))
	StrokePath(2, #PB_Path_Default)
	AddPathBox(40, 40, 20, 20)
	VectorSourceColor(RGBA(255, 0, 0, 100))
	FillPath()
	StopVectorDrawing()
EndIf
spr = CreateSpriteFromAlphaImage(#PB_Any, tempimg)

Repeat
	Repeat
		event = WindowEvent()
		Select event
			Case #PB_Event_CloseWindow : End
		EndSelect
	Until event = 0
	
	FlipBuffers()
	ClearScreen(RGB(0, 0, 0))
	DisplayTransparentSprite(spr, 0, 0)
	DisplayTransparentSprite(spr, 10, 10)
	Delay(2)
ForEver
Pharmacie populaire www.viagrasansordonnancefr.com aide aux malades
Antworten