Page 1 of 2

Waiting Screen with transparent background

Posted: Mon Feb 05, 2024 4:35 pm
by tatanas
Hi,

I would like to make an animated waiting screen with transparent background with 2D drawing functions.
Here is what I was able to achieve :

Code: Select all

Procedure Rotate(*oldPos.Point, *RotationCenter.Point, angle.f, *newPos.Point)
	Protected xM, yM
	angle = angle * #PI / 180
	xM = *oldPos\x - *RotationCenter\x
	yM = *oldPos\y - *RotationCenter\y
	*newPos\x = Round(xM * Cos(angle) + yM * Sin(angle) + *RotationCenter\x, #PB_Round_Nearest)
	*newPos\y = Round(- xM * Sin(angle) + yM * Cos(angle) + *RotationCenter\y, #PB_Round_Nearest)
EndProcedure


If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window_BorderLess|#PB_Window_ScreenCentered)

	SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, GetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE)|#WS_EX_LAYERED);|#WS_EX_TOOLWINDOW)

	Define RotationCenter.Point : RotationCenter\x = 100 : RotationCenter\y = 100
	Define startingPos.Point : startingPos\x = 180 : startingPos\y = 100
	Define angle.f = 0
	Define newpos_red.Point, newpos_green.Point
	
	CreateImage(0, 200, 200, 32, #PB_Image_Transparent)
	
	Define sz.SIZE
	sz\cx = ImageWidth(0)
	sz\cy = ImageHeight(0)
	Define BlendMode.BLENDFUNCTION
	BlendMode\SourceConstantAlpha = 255 
	BlendMode\AlphaFormat = #ULW_COLORKEY

	StartDrawing(ImageOutput(0))
	DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Transparent)
	For i = 1 To 8
		Rotate(startingPos, RotationCenter, angle, newpos_red)

		Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 0, 0, 255))
		If angle = 315
			angle = 0
		Else
			angle = angle + 45
		EndIf
	Next	
	StopDrawing()

	Repeat
		event = WindowEvent()
		hDC = StartDrawing(ImageOutput(0))
		If hDC
			DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Transparent)
			Rotate(startingPos, RotationCenter, angle, newpos_red)
			Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 0, 0, 255))
			If angle = 315
				angle = 0
			Else
				angle = angle + 45
			EndIf


			Rotate(startingPos, RotationCenter, angle, newpos_green)
			Circle(newpos_green\x, newpos_green\y, 10, RGBA(0, 255, 0, 255))
	
			UpdateLayeredWindow_(WindowID(0), 0, 0, @sz, hDC, @pptSrc.POINT, 0, @BlendMode, 2)
			StopDrawing()
		EndIf
		Delay(200)
	Until event = #PB_Event_CloseWindow

EndIf
As you can see, the transparency also apply to my drawing.
What should I change to apply fully opaque draws ?

Thanks for your time.

EDIT : Code updated

Re: Waiting Screen with transparent background

Posted: Mon Feb 05, 2024 7:30 pm
by Olli

Code: Select all

SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, GetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE)&~#WS_EX_LAYERED)

Re: Waiting Screen with transparent background

Posted: Mon Feb 05, 2024 8:11 pm
by ChrisR
Looks good by adding "DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Transparent)" after the 2 StartDrawing.
The result is nice :)

Re: Waiting Screen with transparent background

Posted: Tue Feb 06, 2024 6:48 am
by jacdelad
What is supposed to happen? I just get a greyish/whiteish window in the middle of the screen.

Re: Waiting Screen with transparent background

Posted: Tue Feb 06, 2024 9:29 am
by Mesa
Like that:

Code: Select all

Procedure Rotate(*oldPos.Point, *RotationCenter.Point, angle.f, *newPos.Point)
	Protected xM, yM
	angle = angle * #PI / 180
	xM = *oldPos\x - *RotationCenter\x
	yM = *oldPos\y - *RotationCenter\y
	*newPos\x = Round(xM * Cos(angle) + yM * Sin(angle) + *RotationCenter\x, #PB_Round_Nearest)
	*newPos\y = Round(- xM * Sin(angle) + yM * Cos(angle) + *RotationCenter\y, #PB_Round_Nearest)
EndProcedure


If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window_BorderLess|#PB_Window_ScreenCentered)
	
	; 	SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, GetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE)|#WS_EX_LAYERED);|#WS_EX_TOOLWINDOW)
	
	Define RotationCenter.Point : RotationCenter\x = 100 : RotationCenter\y = 100
	Define startingPos.Point : startingPos\x = 180 : startingPos\y = 100
	Define angle.f = 0
	Define newpos_red.Point, newpos_green.Point
	
	CreateImage(0, 200, 200, 32, #PB_Image_Transparent)
	; 	
	; 	Define sz.SIZE
	; 	sz\cx = ImageWidth(0)
	; 	sz\cy = ImageHeight(0)
	; 	Define BlendMode.BLENDFUNCTION
	; 	BlendMode\SourceConstantAlpha = 255 
	; 	BlendMode\AlphaFormat = #ULW_COLORKEY
	; 
	StartDrawing(ImageOutput(0))
	DrawingMode(#PB_2DDrawing_AlphaBlend )
	For i = 1 To 8
		Rotate(startingPos, RotationCenter, angle, newpos_red)
		Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 0, 0, 255))
		If angle = 315
			angle = 0
		Else
			angle = angle + 45
		EndIf
	Next	
	StopDrawing()
	
	StartDrawing(WindowOutput(0))
	DrawAlphaImage(ImageID(0),0,0)
	StopDrawing()
	
	
	Repeat
		event = WindowEvent()
		hDC = StartDrawing(ImageOutput(0))
		If hDC
			
			Rotate(startingPos, RotationCenter, angle, newpos_red)
			Circle(newpos_red\x, newpos_red\y, 10, RGBA(Random(255,0), 0, 0, 255))
			; 			Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 0, 0, 255))
			If angle = 315
				angle = 0
			Else
				angle = angle + 45
			EndIf
			
			
			Rotate(startingPos, RotationCenter, angle, newpos_green)
			Circle(newpos_green\x, newpos_green\y, 10, RGBA(Random(255,0), 255, 0, 255))
			; 			Circle(newpos_green\x, newpos_green\y, 10, RGBA(255, 255, 0, 255))
			
			; 		UpdateLayeredWindow_(WindowID(0), 0, 0, @sz, hDC, @pptSrc.POINT, 0, @BlendMode, 2)
			
			StopDrawing()
			StartDrawing(WindowOutput(0))
			DrawAlphaImage(ImageID(0),0,0)
			StopDrawing()
			
		EndIf
		Delay(200)
	Until event = #PB_Event_CloseWindow
	
EndIf
Drawing directly on a window is not a good idea if your project become more complex, use a, imagegadget or a canvas to display images.
You can also use a thread to compute the rotation, etc.

M.

Re: Waiting Screen with transparent background

Posted: Tue Feb 06, 2024 12:12 pm
by Blue
jacdelad wrote: Tue Feb 06, 2024 6:48 am What is supposed to happen? I just get a greyish/whiteish window in the middle of the screen.
If you hover your mouse pointer over the app's icon on the taskbar, you should see rotating color circles.
Otherwise, everything is transparent, so, of course, you see nothing.
Therein lies the problem...

Re: Waiting Screen with transparent background

Posted: Tue Feb 06, 2024 12:19 pm
by jacdelad
Oh now! Thx!

Re: Waiting Screen with transparent background

Posted: Tue Feb 06, 2024 12:38 pm
by Blue
Very well done, tatanas
tatanas wrote: Mon Feb 05, 2024 4:35 pm Hi,

I would like to make an animated waiting screen with transparent background with 2D drawing functions.
Here is what I was able to achieve :

Code: Select all

Procedure Rotate(*oldPos.Point, *RotationCenter.Point, angle.f, *newPos.Point)
	etc
EndProcedure
If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window_BorderLess|#PB_Window_ScreenCentered)
   etc
EndIf
As you can see, the transparency also apply to my drawing.
:D Ahhh... but that's just the problem : we can't see a thing !! :D

Apart from that, very good idea and smart coding.
I'll be borrowing your code, for sure.

--------------------------------------------------------------------------------------
SUGGESTION :
when you include code in your post, use [code-pb] .. [/code-pb] to delimit your chef-d'oeuvre.
It will display in glorious syntactic coloring, as in...

Code: Select all

;| Sample code
; ------------------------------------
Procedure Rotate(*old, *new)
   ; some code
EndProcedure
CreateImage(0, 22, 33, 44, #PB_Image)
If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window)
   ; some code
EndIf 
; some code
; ------------------------------------
instead of simply [code] .. [/code] which outputs this

Code: Select all

;| Sample code
; ------------------------------------
Procedure Rotate(*old, *new)
   ; some code
EndProcedure
CreateImage(0, 22, 33, 44, #PB_Image)
If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window)
   ; some code
EndIf 
; some code
; ------------------------------------[/code-pb]

Re: Waiting Screen with transparent background

Posted: Tue Feb 06, 2024 1:03 pm
by Blue
jacdelad wrote: Tue Feb 06, 2024 12:19 pm Oh now! Thx!
You're up early...

Re: Waiting Screen with transparent background

Posted: Tue Feb 06, 2024 1:38 pm
by Mindphazer

Re: Waiting Screen with transparent background

Posted: Wed Feb 07, 2024 8:18 am
by tatanas
Thank you for taking the time to reply.

Oli, sorry this change gives me a grey background and no animation visible.
Mesa, I tried your fix but I've got the same problem as Oli above.
Thanks you Blue for your tip (code-pb). I didn't know this.

ChrisR is right. Adding this line fixes my problem. I updated the first post.

Re: Waiting Screen with transparent background

Posted: Wed Feb 07, 2024 11:10 am
by Mesa
Maybe like that, windows only + api.

I think you can use a gif too.

Code: Select all


Procedure.l SetLayeredWindow(WindowID) ; Mettre l'attribut WS_EX_LAYERED à la fenêtre
	SetWindowLong_(WindowID, #GWL_EXSTYLE, GetWindowLong_(WindowID, #GWL_EXSTYLE) | #WS_EX_LAYERED) ; Mettre l'attribut WS_EX_LAYERED à la fenêtre
EndProcedure

Procedure.l AlphaImageWindow(WindowID, ImageID) ; Mettre une image PNG comme fond d'une fenêtre
	Protected Image_HDC.i, Image_Bitmap.BITMAP, Image_BitmapInfo.BITMAPINFO, ContextOffset.POINT, Blend.BLENDFUNCTION
	Protected Image_Ancienne.i ,xx, yy, x, y, Rouge.l, Vert.l, Bleu.l, AlphaChannel.l
	
	; Précalcul
	Protected Dim Echelle.f($FF)
	For x = 0 To $FF
		Echelle(x) = x / $FF
	Next
	
	; Chargement du HDC
	Image_HDC = CreateCompatibleDC_(#Null)
	Image_Ancienne = SelectObject_(Image_HDC, ImageID)
	
	
	; Dimension de l'image
	GetObject_(ImageID, SizeOf(BITMAP), @Image_Bitmap)
	Image_BitmapInfo\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
	Image_BitmapInfo\bmiHeader\biWidth = Image_Bitmap\bmWidth
	Image_BitmapInfo\bmiHeader\biHeight = Image_Bitmap\bmHeight
	Image_BitmapInfo\bmiHeader\biPlanes = 1
	Image_BitmapInfo\bmiHeader\biBitCount = 32
	
	; Zone mémoire pour copier l'image
	xx = Image_Bitmap\bmWidth - 1
	yy = Image_Bitmap\bmHeight - 1
	Protected Dim Image.l(xx, yy)
	
	; Copie de l'image en mémoire
	GetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
	
	; Modification de l'image en mémoire
	For x = 0 To xx
		For y = 0 To yy
			Couleur = Image(x, y)
			AlphaChannel = Couleur >> 24 & $FF
			If AlphaChannel < $FF
				Rouge = (Couleur & $FF) * Echelle(AlphaChannel)
				Vert = (Couleur >> 8 & $FF) * Echelle(AlphaChannel)
				Bleu = (Couleur >> 16 & $FF) * Echelle(AlphaChannel)
				Image(x, y) = Rouge | Vert << 8 | Bleu << 16 | AlphaChannel << 24
			EndIf
		Next
	Next
	
	; Transfert de la mémoire dans la l'image de base
	SetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
	
	; L'image est mise en skin de la fenêtre
	Blend\SourceConstantAlpha = 255 ; niveau de transparence
	Blend\AlphaFormat = 1						; Support de la couche alpha
	Blend\BlendOp = 0
	Blend\BlendFlags = 0
	UpdateLayeredWindow_(WindowID, 0, 0, @Image_BitmapInfo + 4, Image_HDC, @ContextOffset, 0, @Blend, 2)
	
	; Fermeture du HDC
	SelectObject_(Image_HDC, Image_Ancienne)
	DeleteDC_(Image_HDC)
	
EndProcedure

Procedure Rotate(*oldPos.Point, *RotationCenter.Point, angle.f, *newPos.Point)
	Protected xM, yM
	angle = angle * #PI / 180
	xM = *oldPos\x - *RotationCenter\x
	yM = *oldPos\y - *RotationCenter\y
	*newPos\x = Round(xM * Cos(angle) + yM * Sin(angle) + *RotationCenter\x, #PB_Round_Nearest)
	*newPos\y = Round(- xM * Sin(angle) + yM * Cos(angle) + *RotationCenter\y, #PB_Round_Nearest)
EndProcedure


If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window_BorderLess|#PB_Window_ScreenCentered)
	
	SetLayeredWindow(WindowID(0))
	
	Define RotationCenter.Point : RotationCenter\x = 100 : RotationCenter\y = 100
	Define startingPos.Point : startingPos\x = 180 : startingPos\y = 100
	Define angle.f = 0
	Define newpos_red.Point, newpos_green.Point
	
	CreateImage(0, 200, 200, 32, #PB_Image_Transparent)
	
	StartDrawing(ImageOutput(0))
	DrawingMode(#PB_2DDrawing_AlphaBlend )
	For i = 1 To 8
		Rotate(startingPos, RotationCenter, angle, newpos_red)
		Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 0, 0, 255))
		If angle = 315
			angle = 0
		Else
			angle = angle + 45
		EndIf
	Next	
	StopDrawing()
	
	StickyWindow(0, 1)
	
	Repeat
		event = WindowEvent()
		hDC = StartDrawing(ImageOutput(0))
		If hDC
			
			Rotate(startingPos, RotationCenter, angle, newpos_red)
			Circle(newpos_red\x, newpos_red\y, 10, RGBA(Random(255,0), 0, 0, 255))
			; 			Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 0, 0, 255))
			If angle = 315
				angle = 0
			Else
				angle = angle + 45
			EndIf
			
			
			Rotate(startingPos, RotationCenter, angle, newpos_green)
			Circle(newpos_green\x, newpos_green\y, 10, RGBA(Random(255,0), 255, 0, 255))
			; 			Circle(newpos_green\x, newpos_green\y, 10, RGBA(255, 255, 0, 255))
			
			StopDrawing()
			
			
			AlphaImageWindow(WindowID(0), ImageID(0))
		EndIf
		
		Delay(200)
		
	Until event = #PB_Event_CloseWindow
	
EndIf


M.

Re: Waiting Screen with transparent background

Posted: Wed Feb 07, 2024 4:16 pm
by tatanas
Very Nice Mesa !

It works fine, thanks.

Re: Waiting Screen with transparent background

Posted: Thu Feb 08, 2024 10:13 am
by tatanas
Out of curiosity I replaced 2D drawings by vector drawings.
And I've got a strange result. Try the code below, you will see a black outline circle instead of fully yellow.

Code: Select all

Procedure.l SetLayeredWindow(WindowID) ; Mettre l'attribut WS_EX_LAYERED à la fenêtre
	SetWindowLong_(WindowID, #GWL_EXSTYLE, GetWindowLong_(WindowID, #GWL_EXSTYLE) | #WS_EX_LAYERED) ; Mettre l'attribut WS_EX_LAYERED à la fenêtre
EndProcedure

Procedure.l AlphaImageWindow(WindowID, ImageID) ; Mettre une image PNG comme fond d'une fenêtre
	Protected Image_HDC.i, Image_Bitmap.BITMAP, Image_BitmapInfo.BITMAPINFO, ContextOffset.POINT, Blend.BLENDFUNCTION
	Protected Image_Ancienne.i ,xx, yy, x, y, Rouge.l, Vert.l, Bleu.l, AlphaChannel.l
	
	; Précalcul
	Protected Dim Echelle.f($FF)
	For x = 0 To $FF
		Echelle(x) = x / $FF
	Next
	
	; Chargement du HDC
	Image_HDC = CreateCompatibleDC_(#Null)
	Image_Ancienne = SelectObject_(Image_HDC, ImageID)
	
	
	; Dimension de l'image
	GetObject_(ImageID, SizeOf(BITMAP), @Image_Bitmap)
	Image_BitmapInfo\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
	Image_BitmapInfo\bmiHeader\biWidth = Image_Bitmap\bmWidth
	Image_BitmapInfo\bmiHeader\biHeight = Image_Bitmap\bmHeight
	Image_BitmapInfo\bmiHeader\biPlanes = 1
	Image_BitmapInfo\bmiHeader\biBitCount = 32
	
	; Zone mémoire pour copier l'image
	xx = Image_Bitmap\bmWidth - 1
	yy = Image_Bitmap\bmHeight - 1
	Protected Dim Image.l(xx, yy)
	
	; Copie de l'image en mémoire
	GetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
	
	; Modification de l'image en mémoire
	For x = 0 To xx
		For y = 0 To yy
			Couleur = Image(x, y)
			AlphaChannel = Couleur >> 24 & $FF
			If AlphaChannel < $FF
				Rouge = (Couleur & $FF) * Echelle(AlphaChannel)
				Vert = (Couleur >> 8 & $FF) * Echelle(AlphaChannel)
				Bleu = (Couleur >> 16 & $FF) * Echelle(AlphaChannel)
				Image(x, y) = Rouge | Vert << 8 | Bleu << 16 | AlphaChannel << 24
			EndIf
		Next
	Next
	
	; Transfert de la mémoire dans la l'image de base
	SetDIBits_(Image_HDC, ImageID, 0, Image_Bitmap\bmHeight, @Image(), @Image_BitmapInfo, #DIB_RGB_COLORS)
	
	; L'image est mise en skin de la fenêtre
	Blend\SourceConstantAlpha = 255 ; niveau de transparence
	Blend\AlphaFormat = 1			  ; Support de la couche alpha
	Blend\BlendOp = 0
	Blend\BlendFlags = 0
	UpdateLayeredWindow_(WindowID, 0, 0, @Image_BitmapInfo + 4, Image_HDC, @ContextOffset, 0, @Blend, 2)
	
	; Fermeture du HDC
	SelectObject_(Image_HDC, Image_Ancienne)
	DeleteDC_(Image_HDC)
	
EndProcedure

Procedure Rotate(*oldPos.Point, *RotationCenter.Point, angle.f, *newPos.Point)
	Protected xM, yM
	angle = angle * #PI / 180
	xM = *oldPos\x - *RotationCenter\x
	yM = *oldPos\y - *RotationCenter\y
	*newPos\x = Round(xM * Cos(angle) + yM * Sin(angle) + *RotationCenter\x, #PB_Round_Nearest)
	*newPos\y = Round(- xM * Sin(angle) + yM * Cos(angle) + *RotationCenter\y, #PB_Round_Nearest)
EndProcedure


If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window_BorderLess|#PB_Window_ScreenCentered)
	
	SetLayeredWindow(WindowID(0))
	
	Define RotationCenter.Point : RotationCenter\x = 100 : RotationCenter\y = 100
	Define startingPos.Point : startingPos\x = 180 : startingPos\y = 100
	Define angle.f = 0
	Define newpos_red.Point, newpos_green.Point
	
	CreateImage(0, 200, 200, 32, #PB_Image_Transparent)
	
	AddWindowTimer(0, 123, 200)

; 	StartDrawing(ImageOutput(0))
; 	DrawingMode(#PB_2DDrawing_AlphaBlend )
; 	For i = 1 To 8
; 		Rotate(startingPos, RotationCenter, angle, newpos_red)
; 		Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 0, 0, 255))
; 		If angle = 315 : angle = 0 : Else : angle = angle + 45 : EndIf
; 	Next	
; 	StopDrawing()


	StartVectorDrawing(ImageVectorOutput(0))
	For i = 1 To 8
		Rotate(startingPos, RotationCenter, angle, newpos_red)
		AddPathCircle(newpos_red\x, newpos_red\y, 10, 0, 360) : VectorSourceColor(RGBA(255, 255, 0, 255)) : FillPath()
		If angle = 315 : angle = 0 : Else : angle = angle + 45 : EndIf
	Next
	StopVectorDrawing()
	
	AlphaImageWindow(WindowID(0), ImageID(0))
	StickyWindow(0, 1)
	
	Repeat
		event = WaitWindowEvent()

		If event = #PB_Event_Timer And EventTimer() = 123
; 			StartDrawing(ImageOutput(0))
; 			
; 			Rotate(startingPos, RotationCenter, angle, newpos_red)
; 			DrawingMode(#PB_2DDrawing_Outlined) : Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 255, 255, 255))
; 			DrawingMode(#PB_2DDrawing_Default)  : Circle(newpos_red\x, newpos_red\y, 9, RGBA(255, 0, 0, 255))
; 			
; 			If angle = 315 : angle = 0 : Else : angle = angle + 45 : EndIf
; 			
; 			Rotate(startingPos, RotationCenter, angle, newpos_green)
; 			DrawingMode(#PB_2DDrawing_Outlined) : Circle(newpos_red\x, newpos_red\y, 10, RGBA(255, 255, 255, 255))
; 			DrawingMode(#PB_2DDrawing_Default)  : Circle(newpos_green\x, newpos_green\y, 9, RGBA(0, 255, 0, 255))
; 			
; 			StopDrawing()	
			
			AlphaImageWindow(WindowID(0), ImageID(0))
		EndIf

	Until event = #PB_Event_CloseWindow
	
EndIf
Do you know why ?

Re: Waiting Screen with transparent background

Posted: Thu Feb 08, 2024 12:05 pm
by jacdelad
Can't help you with the black border, but you can put FillPath() outside the loop. This way all circles are drawn in one go, not 8 times separately.