Problem with TransparentSpriteColor?

Advanced game related topics
User avatar
Samuel
Enthusiast
Enthusiast
Posts: 751
Joined: Sun Jul 29, 2012 10:33 pm
Location: United States

Problem with TransparentSpriteColor?

Post by Samuel »

I may have found a bug with TransparentSpriteColor. It seems that if you draw directly onto a sprite more then once the transparency will still be linked to the original version.
In my example below I create a sprite and fill it completely green, and then I draw a red circle with a diameter of the box.
The green is set to transparent, and this all works fine. The sprite is displayed as it should be.
When I draw to the sprite a second time just like I did to the first except I make the red circle smaller. The result is a large green circle with a smaller red circle inside it.

The problem seems to be caused by TransparentSpriteColor. If I call TransparentSpriteColor only after the second draw the result is correct and I only see a small red circle. If I call it after each draw then I get the large green and small red circles.

I'm using PB 5.5 (x64) on Windows 7 and have tested it on both DirectX and OpenGL.

Code: Select all

EnableExplicit

If InitSprite() = 0
  MessageRequester("Error!", "Failed to init the sprite system.", #PB_MessageRequester_Ok)
  End
EndIf

Define.i Event
Define.i WinW = 800
Define.i WinH = 600

If OpenWindow(0, 0, 0, WinW, WinH, "Transparent Sprite Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If OpenWindowedScreen(WindowID(0), 0, 0, WinW, WinH) = 0
    MessageRequester("Error!", "Failed to open the screened window.", #PB_MessageRequester_Ok)
    End
  EndIf
  
  CreateSprite(1, 256, 256, #PB_Sprite_AlphaBlending)
  StartDrawing(SpriteOutput(1))
    DrawingMode(#PB_2DDrawing_Default)
    Box(0, 0, 256, 256, RGB(0,255,0)) ;Fill the entire sprite with a green background
    Circle(128, 128, 128, RGB(255,0,0)) ;Draw a large red circle
  StopDrawing()
  
  ;####
  ;Comment out the below TransparentSpriteColor() and everthing works correctly
  TransparentSpriteColor(1, RGB(0,255,0))
  ;####
  
  StartDrawing(SpriteOutput(1))
    DrawingMode(#PB_2DDrawing_Default)
    Box(0, 0, 256, 256, RGB(0,255,0)) ;Fill the entire sprite with a green background
    Circle(128, 128, 64, RGB(255,0,0)) ;Draw a small red circle
  StopDrawing()
  
  TransparentSpriteColor(1, RGB(0,255,0))
  
  Repeat
    
    DisplayTransparentSprite(1, 200, 200)
    FlipBuffers()

  Until WindowEvent() = #PB_Event_CloseWindow
  
EndIf
End
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: Problem with TransparentSpriteColor?

Post by heartbone »

Same behavior exists in PB 5.43 LTS x64 Linux.
Keep it BASIC.
#NULL
Addict
Addict
Posts: 1337
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Problem with TransparentSpriteColor?

Post by #NULL »

i have some other code here i used to clarify for my self some time ago:

without modification (no TransparentSpriteColor() used) the code works as expected:
a black sprite and within is one transparent box 1, a black box 2 and a red box 4.
only box 1 is transparent, due to the alpha used.

when commenting in the first TransparentSpriteColor():
- the default BG color of $ff000000 is reported by Point() as $00000000, even with alpha in the drawing mode.
thought the alpha is reported correctly for box 2 and 3 after drawing.
..or the default BG color actually changed with using TransparentSpriteColor()?
- transparency is still only affected by the alpha channel (box 2 with $ff000000 is still not transparent)

Code: Select all

InitSprite()
InitMouse()
InitKeyboard()

ww=800
wh=600
style | #PB_Window_ScreenCentered
style | #PB_Window_SystemMenu
style | #PB_Window_MinimizeGadget

If 01
  win=OpenWindow(#PB_Any, 50,100, ww,wh, "", style) :: AddKeyboardShortcut(win, #PB_Shortcut_Escape, 10)
  OpenWindowedScreen(WindowID(win), 0,0, ww/3,wh/3, 1,0,0)
Else
  OpenScreen(ww,wh,32,"", #PB_Screen_NoSynchronization)
  SetFrameRate(9999)
EndIf

Procedure debugColorP(text.s, x,y)
  Debug text + ": " + Red(Point(x,y)) + ","+Green(Point(x,y))+","+Blue(Point(x,y))+","+Alpha(Point(x,y))
EndProcedure

; only background sprite
w = ScreenWidth()
h = ScreenHeight()
sprBG = CreateSprite(#PB_Any, w, h, #PB_Sprite_AlphaBlending)
StartDrawing(SpriteOutput(sprBG))
  DrawingMode(#PB_2DDrawing_AllChannels)
  Box(0, 0, w, h, $ffaaaaaa)
  Box(50, 50, 50, 50, $ff00ff00)
  DrawingMode(#PB_2DDrawing_AllChannels | #PB_2DDrawing_Outlined)
  For i=0 To 200
    Circle(Random(w), Random(h), Random(50), RGBA(Random(255), Random(255), Random(255), Random(255)))
  Next
StopDrawing()

w = 100
h = 100
spr1 = CreateSprite(#PB_Any, w, h, #PB_Sprite_AlphaBlending)

; this would make the default BG of $ff000000 transparent, but not the Box(.., $ff000000) area!
; also the alpha will not be reported by Point() for the default color, but for the Box() with the same color.
;TransparentSpriteColor(spr1, RGB(0,0,0))

; this behaves exactly like the previous one
;TransparentSpriteColor(spr1, RGBA(0,0,0,255))

; ..so don't use TransparentSpriteColor() at all with alpha channels

StartDrawing(SpriteOutput(spr1))
  debugColorP("default (RGB) ", 0, 0)
  DrawingMode(#PB_2DDrawing_AllChannels)
  debugColorP("default (RGBA)", 0, 0)
  
  Box(10, 10, 20, 20, $00000000)
  debugColorP("in box 1      ", 10, 10)
  
  Box(40, 10, 20, 20, $ff000000)
  debugColorP("in box 2      ", 40, 10)
  
  Box(60, 10, 20, 20, $ff0000ff)
  debugColorP("in box 3      ", 60, 10)
  
  DrawingMode(#PB_2DDrawing_AllChannels | #PB_2DDrawing_Outlined)
  For i=0 To 50
    Circle(Random(w), Random(h), Random(50), RGBA(Random(255), Random(255), Random(255), Random(255)))
  Next
StopDrawing()

Repeat
  ExamineMouse()
  ExamineKeyboard()
  
  If IsWindow(win) ;{
    Repeat
      event = WindowEvent()
      em = EventMenu()
      Select event
        Case #PB_Event_CloseWindow
          quit = #True
        Case #PB_Event_Menu
          Select em
          Case 10
            quit = #True
          EndSelect
      EndSelect
    Until Not event
    ;}
  EndIf
  
  DisplayTransparentSprite(sprBG, 0, 0)
  DisplayTransparentSprite(spr1, MouseX(), MouseY())
  
  StartDrawing(ScreenOutput())
    DrawingMode(#PB_2DDrawing_Transparent)
    Circle(MouseX(), MouseY(), 1)
  StopDrawing()
  
  FlipBuffers()
  ClearScreen($333333)
  If IsWindow(win)
    Delay(10)
  EndIf
Until quit Or KeyboardPushed(#PB_Key_Escape)
so my guess is that alpha channel and TransparentSpriteColor() is not meant to be used together, especially since the command is older than the alpha channel support, and it does not accept and RGBA value, at least it doesn't use the the alpha component.
also it doesn't make a color transparent if the color does not have alpha 0 anyway.
..but it your case the green actually becomes transparent without alpha ..i'm still a bit confused.
User avatar
Samuel
Enthusiast
Enthusiast
Posts: 751
Joined: Sun Jul 29, 2012 10:33 pm
Location: United States

Re: Problem with TransparentSpriteColor?

Post by Samuel »

I changed the box to blue instead of green in the second drawing block, and then updated TransparentSpriteColor() to blue also which makes everything work correctly.

This is just a guess, but I bet when TransparentSpriteColor() is called Purebasic tests to see if the current transparent sprite color is the same as the newly requested color. If they are the same it backs out and doesn't complete the process. Which results in incorrect transparent areas when the sprite has been redrawn.

Here's the working code with the two different TransparentSpriteColor()s.

Code: Select all

EnableExplicit

If InitSprite() = 0
  MessageRequester("Error!", "Failed to init the sprite system.", #PB_MessageRequester_Ok)
  End
EndIf

Define.i Event
Define.i WinW = 800
Define.i WinH = 600

If OpenWindow(0, 0, 0, WinW, WinH, "Transparent Sprite Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If OpenWindowedScreen(WindowID(0), 0, 0, WinW, WinH) = 0
    MessageRequester("Error!", "Failed to open the screened window.", #PB_MessageRequester_Ok)
    End
  EndIf
  
  CreateSprite(1, 256, 256, #PB_Sprite_AlphaBlending)
  StartDrawing(SpriteOutput(1))
    DrawingMode(#PB_2DDrawing_Default)
    Box(0, 0, 256, 256, RGB(0,255,0)) ;Fill the entire sprite with a green background
    Circle(128, 128, 128, RGB(255,0,0)) ;Draw a large red circle
  StopDrawing()
  
  TransparentSpriteColor(1, RGB(0,255,0))

  
  StartDrawing(SpriteOutput(1))
   DrawingMode(#PB_2DDrawing_Default)
   Box(0, 0, 256, 256, RGB(0,0,255)) ;Fill the entire sprite with a blue background
   Circle(128, 128, 64, RGB(255,0,0)) ;Draw a small red circle
  StopDrawing()
  
  TransparentSpriteColor(1, RGB(0,0,255))
  
  Repeat
    
    DisplayTransparentSprite(1, 200, 200)
    FlipBuffers()

  Until WindowEvent() = #PB_Event_CloseWindow
  
EndIf
End
Post Reply