GMLscripts.com

sprite_replace_color_blend

WARNING: This script is already slow but a possible bug in GameMaker may make it unusable. When last tested, the sprite below took 46 minutes to process compared to an expected 30 seconds. The alteration suggested in the linked bug report should resolve the problem but it is not yet implemented.

sprite_replace_color_blend()

This script can replace one range of colors with another while preserving overall shading. It is slow. VERY SLOW. It is only suitable for small sprites with few frames. It is probably far too slow to be used in your game. But it does have its uses.

This same functionality can be performed in real-time with a shader. This shader has not yet been posted here but you can see the shader at the GMC.

NOTE: A much faster script for color replacement (without color blending) is sprite_replace_color().

sprite_replace_color_blend(sprite,oldcolor,newcolor,htol,stol,vtol,blend)
Replaces one range of colors of a given sprite with another.
COPY
  1. /// sprite_replace_color_blend(sprite,oldcolor,newcolor,htol,stol,vtol,blend)
  2. //
  3. // Replaces one range of colors of a given sprite with another.
  4. // No new sprites are created, the original sprite is changed.
  5. // Color is matched and replaced using tolerances and blending
  6. // in order to preserve the shading of the original sprite.
  7. //
  8. // sprite sprite index, real
  9. // oldcolor original color, real
  10. // newcolor replacement color, real
  11. // htol hue tolerance, real
  12. // stol saturation tolerance, real
  13. // vtol value tolerance, real
  14. // blend blend shading, true/false
  15. //
  16. //
  17. // Notes:
  18. // This script is extremely slow, especially with large sprites
  19. // or sprites with many frames.
  20. //
  21. // Three tolerance arguments (htol,stol,vtol) contol exactly
  22. // which colors are replaced. A higher tolerance will match
  23. // a broader range of hue, saturation, or value. Values
  24. // around (htol = 20; stol = 240; vtol = 240) work well.
  25. //
  26. // If (blend) is set to true (recommeded), changed colors
  27. // will retain their original shading.
  28. //
  29. /// GMLscripts.com/license
  30. {
  31. var sprite,oldcolor,newcolor,trancolor,htol,stol,vtol,blend;
  32. sprite = argument0;
  33. oldcolor = argument1;
  34. newcolor = argument2;
  35. htol = argument3;
  36. stol = argument4;
  37. vtol = argument5;
  38. blend = argument6;
  39.  
  40. var xo,yo,n,w,h,oh,os,ov,nh,ns,nv;
  41. var surf,i,sx,sy,color,th,ts,tv,dh,ds,dv,hue,sat,val,newsprite;
  42. xo = sprite_get_xoffset(sprite);
  43. yo = sprite_get_yoffset(sprite);
  44. n = sprite_get_number(sprite);
  45. w = sprite_get_width(sprite);
  46. h = sprite_get_height(sprite);
  47. oh = color_get_hue(oldcolor);
  48. os = color_get_saturation(oldcolor);
  49. ov = color_get_value(oldcolor);
  50. nh = color_get_hue(newcolor);
  51. ns = color_get_saturation(newcolor);
  52. nv = color_get_value(newcolor);
  53.  
  54. // Create surf for sprite editing.
  55. surf = surface_create(w,h);
  56. surface_set_target(surf);
  57.  
  58. // Process each frame of the original sprite.
  59. for(i=0; i<n; i+=1) {
  60. draw_clear_alpha(c_black,1);
  61. draw_set_blend_mode_ext(bm_one,bm_zero);
  62. draw_sprite(sprite,i,xo,yo);
  63.  
  64. // Check each pixel and change it if within HSV color thresholds.
  65. for(sx=0; sx<w; sx+=1) {
  66. for(sy=0; sy<h; sy+=1) {
  67. color = surface_getpixel(surf,sx,sy);
  68. th = color_get_hue(color);
  69. ts = color_get_saturation(color);
  70. tv = color_get_value(color);
  71. dh = th-oh;
  72. ds = ts-os;
  73. dv = tv-ov;
  74. if (abs(dh)>128) dh = sign(dh)*256-dh;
  75. if (abs(dh)<htol && abs(ds)<stol && abs(dv)<vtol) {
  76. if (blend) {
  77. hue = (nh+dh+256) mod 256;
  78. sat = min(max(0,ns+ds),255);
  79. val = min(max(0,nv+dv),255);
  80. draw_point_color(sx,sy,make_color_hsv(hue,sat,val));
  81. }
  82. }
  83. }
  84. }
  85.  
  86. // Add current frame to new sprite.
  87. if (i == 0) {
  88. newsprite = sprite_create_from_surface(surf,0,0,w,h,false,false,xo,yo);
  89. if (newsprite < 0) return -1;
  90. }else{
  91. sprite_add_from_surface(newsprite,surf,0,0,w,h,false,false);
  92. }
  93.  
  94. // Copy alpha channel from original sprite to alpha sprite.
  95. draw_clear_alpha(c_white,1);
  96. draw_set_blend_mode_ext(bm_zero,bm_src_alpha);
  97. draw_sprite(sprite,i,xo,yo);
  98. if (i == 0) {
  99. alphasprite = sprite_create_from_surface(surf,0,0,w,h,false,false,xo,yo);
  100. if (alphasprite < 0) {
  101. sprite_delete(newsprite);
  102. return -1;
  103. }
  104. }else{
  105. sprite_add_from_surface(alphasprite,surf,0,0,w,h,false,false);
  106. }
  107. }
  108.  
  109. // Replace original sprite with new sprite.
  110. sprite_assign(sprite,newsprite);
  111.  
  112. // Apply original sprite alpha channel to new sprite.
  113. sprite_set_alpha_from_sprite(sprite,alphasprite);
  114.  
  115. // Clean up.
  116. draw_set_blend_mode(bm_normal);
  117. surface_reset_target();
  118. sprite_delete(newsprite);
  119. sprite_delete(alphasprite);
  120. surface_free(surf);
  121. return 0;
  122. }

Contributors: xot

GitHub: View · Commits · Blame · Raw