Tint colour of sprite

dan444

Member
I'm looking to slightly tint the colors of a sprite. Meaning that white and black stay the same but other colours change so the overall saturation stays the same, similar to the 'color' blend mode in photoshop. The intention is to change this multiple times, so creating different versions of the sprites is not an option. I've done a lot of searching, but most posts are dead ends and nothing has worked so far.

This is what I currently have, it's kind of working but not very well. I'm surprised there isn't a built in function like draw_set_tint(c_blue, 0.5) as it it seems like it would be a very obvious/useful feature?
GML:
draw_self();

gpu_set_blendmode_ext(bm_src_alpha, bm_one);
image_alpha = 0.9;
image_blend = c_blue;

draw_self();

gpu_set_blendmode(bm_normal);
image_alpha = 1
image_blend = -1;
 

curato

Member
you don't want to draw_self you need to replace it with a command to draw and tint your sprite

GML:
draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha);
 

dan444

Member
you don't want to draw_self you need to replace it with a command to draw and tint your sprite

GML:
draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha);
Using image_blend changes the white colors as well. I need the lightness of each pixel to stay the same.
 

curato

Member
sounds like you wandering into shader territory if you want to change some pixels but not others.

Edit: About the only other thing I can remotely figure if you are trying to avoid shaders would would be creative with the sprites. Drop the alpha on the parts you wan to change color then you have a all white version of the sprite you drop first and tint then drop the on the version of the sprite with the alpha on top.
 

dan444

Member
Sooo I ended up learning a bit on shaders and came up with this for anyone else looking for a solution.

Basically you can change the Target variables and the shader will find out how far away the current pixels colour is from the target colour. Then moves the current colour towards the target colour based on how light/dark the pixel is. You can change the buffer variable to change how strong the tint is. Still not perfect, but it's good enough for now.

GML:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 OriginalColour = texture2D( gm_BaseTexture, v_vTexcoord );
  
  
    float Red = OriginalColour.r;
    float Green = OriginalColour.g;
    float Blue = OriginalColour.b;
    float Alpha = OriginalColour.a;
  
    float buffer = 0.5;
    float lightness = ((Red + Green + Blue) / 3.0);
  
    float multiplier = 1.0 - 2.0 * abs(lightness - 0.5);
  
    multiplier = multiplier * buffer;


  
    float TargetR = 0.0;
    float TargetG = 1.0;
    float TargetB = 0.0;
  
    float RDistance = (Red - TargetR) * multiplier;
    float GDistance = (Green - TargetG) * multiplier;
    float BDistance = (Blue - TargetB) * multiplier;
  
    vec4 Color = vec4(Red - RDistance, Green - GDistance, Blue - BDistance, Alpha);
  
    gl_FragColor = Color;
}
 
I've been trying to find a solution that matches the photoshop colour blend mode exactly.

So far I've found this, which seems to be pretty close:
Translated into GLSL ES:
Code:
    varying vec2 v_vTexcoord;
    varying vec4 v_vColour;
    const vec3 luma_coefficients = vec3(0.3,0.59,0.11);
    vec3 SetLum (vec3 bottom, vec3 top) {
        vec3 R = top + dot(bottom-top,luma_coefficients);
        float L = dot(R,luma_coefficients);
        float cMin = min(min(R.r,R.g),R.b);
        float cMax = max(max(R.r,R.g),R.b); 
        R = mix(R,L+(R - L)*L/(L - cMin),float(cMin < 0.0));
        R = mix(R,L+(R - L)*(1.0 - L)/(cMax - L),float(cMax > 1.0));
        return R;
    }
    void main() {
        vec4 base = texture2D( gm_BaseTexture, v_vTexcoord );
        gl_FragColor = vec4(SetLum(base.rgb,v_vColour.rgb),base.a);
    }
The top blend color is in "image_blend" or the colour argument to a draw function. And that colour is the v_vColour.rgb varying variable in the fragment shader.

You can try to mess around with the luma_coefficients to see if you can get results that match more exactly what you're expecting.
 
Last edited:
Top