PureBasic Forum
https://www.purebasic.fr/english/

how to Tint a translucent sprite?
https://www.purebasic.fr/english/viewtopic.php?f=16&t=65216
Page 1 of 1

Author:  juankprada [ Wed Mar 16, 2016 10:44 pm ]
Post subject:  how to Tint a translucent sprite?

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:
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:
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?

Author:  BasicallyPure [ Thu Mar 17, 2016 12:14 am ]
Post subject:  Re: how to Tint a translucent sprite?

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:
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

Author:  juankprada [ Thu Mar 17, 2016 3:07 pm ]
Post subject:  Re: how to Tint a translucent sprite?

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?

Author:  BasicallyPure [ Thu Mar 17, 2016 5:57 pm ]
Post subject:  Re: how to Tint a translucent sprite?

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.

Author:  Fig [ Mon Apr 25, 2016 1:07 pm ]
Post subject:  Re: how to Tint a translucent sprite?

Display your 2 sprites and use blendingmodes on your sprites. SpriteBlendingMode(ModeSource, ModeDestination).

Author:  [blendman] [ Tue Apr 26, 2016 10:02 am ]
Post subject:  Re: how to Tint a translucent sprite?

@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:
 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:
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:
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:
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

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/