Page 1 of 1

how to Tint a translucent sprite?

Posted: Wed Mar 16, 2016 10:44 pm
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?

Re: how to Tint a translucent sprite?

Posted: Thu Mar 17, 2016 12:14 am
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

Re: how to Tint a translucent sprite?

Posted: Thu Mar 17, 2016 3:07 pm
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?

Re: how to Tint a translucent sprite?

Posted: Thu Mar 17, 2016 5:57 pm
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.

Re: how to Tint a translucent sprite?

Posted: Mon Apr 25, 2016 1:07 pm
by Fig
Display your 2 sprites and use blendingmodes on your sprites. SpriteBlendingMode(ModeSource, ModeDestination).

Re: how to Tint a translucent sprite?

Posted: Tue Apr 26, 2016 10:02 am
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