how to Tint a translucent sprite?

Advanced game related topics
juankprada
User
User
Posts: 62
Joined: Tue Mar 18, 2014 4:25 pm
Location: Bogotá, Colombia

how to Tint a translucent sprite?

Post by juankprada »

Hi all,

I am working on a particles engine, and I need to tint the particles (sprites) with a specific color (may be random or pre-set). The default behaviour of DisplayTransparentSprite when you pass a color does not work as expected as it changes avery pixel of the image that is non transparent to that specific color instead of "tinging" it.

So Looking at the forums for a solution, the suggested method to do so is to display twice the same sprite, one with the original color, and one with a translucent color as shown in the code bellow:

Code: Select all

DisplayTransparentSprite(spriteId, x, y)
DisplayTransparentSprite(spriteId, x, y, alphaValue, desiredColor)
This however has a problem when you need to display the colored sprite with a specific translucency and at the same time tinted with a color.

What I thought on doing was

Code: Select all

alphaValue = 150/2
DisplayTransparentSprite(spriteId, x, y, alphaValue)
DisplayTransparentSprite(spriteId, x, y, alphaValue, desiredColor)
But this solution makes the colored sprite almost invisible so not sure if that should be the right way to do it.

Do you guys have ideas?
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: how to Tint a translucent sprite?

Post by BasicallyPure »

Hi,
I think you must apply the tint to the sprite before you display it.

Here is a procedure that I have used to tint an image, grayscale or full color.
I have modified the procedure to work with sprites and hopefully the alpha channel will work properly.
This procedure assumes the transparent color is black.
I must caution you that I have not tested it in this modified form.
I hope it works for you.

Code: Select all

Procedure TINT_SPRITE(sprite.i, color.i)
   Protected c, i, x, y, xMax, yMax
   Protected.d r, g, b

   r = Red(color)   / 1785
   g = Green(color) / 1785
   b = Blue(color)  / 1785
   
   If IsSprite(sprite)
      
      StartDrawing(SpriteOutput(sprite))
         xMax = OutputWidth()  - 1
         yMax = OutputHeight() - 1
         
         For y = 0 To yMax
            For x = 0 To xMax
               c = Point(x, y)
               
               i = (c & $FF) << 1 : c >> 8
               i + (C & $FF) << 2 : c >> 8
               i + (c & $FF)      : c >> 8
               
               Plot(x, y, RGBA(r*i, g*i, b*i, c))
            Next x
         Next y
      StopDrawing()
      
   EndIf 
EndProcedure
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
juankprada
User
User
Posts: 62
Joined: Tue Mar 18, 2014 4:25 pm
Location: Bogotá, Colombia

Re: how to Tint a translucent sprite?

Post by juankprada »

Will try that out, thanks.

My only concern is the use of the StartDrawing()/StopDrawing(). It is not that fast and efficient for it to be run during a game loop (at least not in my test but please feel free to share your experience). For my use case I would be generating particles all the time each with a random color, so this procedure would be called hundreds of times in a single game update.

I havent tested it yet as right now I dont have access to my PB compiler and source code, but will give it a try as soon as possible. In the mean time are there any other options?
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: how to Tint a translucent sprite?

Post by BasicallyPure »

juankprada wrote:My only concern is the use of the StartDrawing()/StopDrawing(). It is not that fast and efficient for it to be run during a game loop
Correct. It would not be good to use inside of your game loop.
I don't know how big your sprites are.
If they are small maybe you could create many sprites, each with a different tint.
Choose from them randomly inside your loop.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
Fig
Enthusiast
Enthusiast
Posts: 348
Joined: Thu Apr 30, 2009 5:23 pm
Location: Côtes d'Azur, France

Re: how to Tint a translucent sprite?

Post by Fig »

Display your 2 sprites and use blendingmodes on your sprites. SpriteBlendingMode(ModeSource, ModeDestination).
There are 2 methods to program bugless.
But only the third works fine.

Win10, Pb x64 5.71 LTS
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 285
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: how to Tint a translucent sprite?

Post by [blendman] »

@Basicallypure : thanks for your procedure ;).

I have added some lines, to not tint with a white color, which change the sprite in grey level ^^. And I think it's interesting to draw again the originale image to not tint over the last color, but with a new color each time :

Code: Select all

 If IsSprite(SpriteId)
     
       StartDrawing(SpriteOutput(Sprite))
       
       ; erase first the sprite
       DrawingMode(#PB_2DDrawing_AllChannels)
       Box(0,0,OutputWidth(),OutputHeight(),RGBA(0,0,0,0))
       ; draw the original image, you need to know what is the sprite image
       DrawingMode(#PB_2DDrawing_AlphaBlend)
       DrawAlphaImage(ImageID(SpriteImg),0,0)
       
       ; then tint the sprite, only if color isn't white.
       If color <> RGB(255,255,255)
           xMax = OutputWidth()  - 1
           yMax = OutputHeight() - 1
           
           For y = 0 To yMax
               For x = 0 To xMax
                   c = Point(x, y)
                   
                   i = (c & $FF) << 1 : c >> 8
                   i + (c & $FF) << 2 : c >> 8
                   i + (c & $FF)      : c >> 8
                   
                   Plot(x, y, RGBA(r*i, g*i, b*i, c))
               Next x
           Next y
       EndIf
       
      StopDrawing()
     
   EndIf
I guess for faster transformation, we could use DrawingBuffer() ;)

Edit :

Other ways, faster :D !

Code: Select all

If IsSprite(SpriteId)
     
       StartDrawing(SpriteOutput(Sprite))
       
       ; erase first the sprite
       DrawingMode(#PB_2DDrawing_AllChannels)
       Box(0,0,OutputWidth(),OutputHeight(),RGBA(0,0,0,0))
       ; draw the original image, you need to know what is the sprite image
       DrawingMode(#PB_2DDrawing_AlphaBlend)
       DrawAlphaImage(ImageID(SpriteImg),0,0)
       
       ; then tint the sprite, only if color isn't white.
       If color <> RGB(255,255,255)
           DrawingMode(#PB_2DDrawing_AlphaClip)
           ; you can change the alpha of the rgba color, to get the effect you want.
           Box(0,0,OutputWidth(),OutputHeight(),RGBA(Red(color),Green(color),Blue(color),120))
       EndIf
       
       StopDrawing()
     
EndIf


With a custom filter (you can use a multiply, add, screen, overlay... custom filter for interesting effect ;)):

The custom filter multiply :

Code: Select all

Procedure bm_multiply(x, y, SourceColor, TargetColor)
  ProcedureReturn RGBA((Red(SourceColor)*Red(TargetColor))/255,(Green(SourceColor)*Green(TargetColor))/255,(Blue(SourceColor)*Blue(TargetColor))/255, Alpha(TargetColor)*Alpha(TargetColor)/255)
EndProcedure

Code: Select all

If IsSprite(SpriteId)
     
       StartDrawing(SpriteOutput(Sprite))
       
       ; erase first the sprite
       DrawingMode(#PB_2DDrawing_AllChannels)
       Box(0,0,OutputWidth(),OutputHeight(),RGBA(0,0,0,0))
       ; draw the original image, you need to know what is the sprite image
       DrawingMode(#PB_2DDrawing_AlphaBlend)
       DrawAlphaImage(ImageID(SpriteImg),0,0)
       
       ; then tint the sprite, only if color isn't white.
       If color <> RGB(255,255,255)
           DrawingMode(#PB_2DDrawing_CustomFilter)      
           CustomFilterCallback(@bm_multiply())
           Box(0,0,OutputWidth(),OutputHeight(),Color)
       EndIf
       
       StopDrawing()
     
EndIf
Post Reply