/*
** Usage:
** new_sprite = sprite_recolor(old_sprite, old_color, new_color,
** tran_color, htol, stol, vtol, blend);
**
** Description:
** Creates a duplicate of a sprite while replacing
** one color with a new color in all frames.
**
** Arguments:
** old_sprite sprite index
** old_color original color
** new_color replacement color
** tran_color sprite's transparency color
** htol hue tolerance, real
** stol saturation tolerance, real
** vtol value tolerance, real
** blend blend shading, true / false
**
** Returns:
** new_sprite sprite index, or
** (-1) on error
**
** Notes:
** (tran_color) must be supplied, it is the color used
** for (new_sprite)'s transparency mask.
**
** Three tolerance arguments (htol,stol,vtol) contol exactly
** which colors are replaced. A higher tolerance will match
** a broader range of hue, saturation, or value. Values
** around (htol = 20; stol = 240; vtol = 240) work well.
**
** If (blend) is set to true (recommeded), changed colors
** will retain their original shading.
**
** This function creates new sprites. It should only be
** called once per color replacement, such as the Create Event
** of an instance. You should be careful to delete created
** sprites when you are done with them. This function draws
** to the frame buffer and should NEVER be called during the
** Draw Event. Sprite colors in 16-bit color mode are not
** exact. They can shift from expected values in-game. Use
** the tolerance controls to compensate. Finally, this
** function is not fast. It is very slow with large sprites
** and/or sprites with many frames. I'm working on a better
** method.
**
** copyright (c) 2006, John Leffingwell
** www.planetxot.com
*/
var new_sprite, old_sprite, old_color, new_color, tran_color, threshold, blend;
old_sprite = argument0;
old_color = argument1;
new_color = argument2;
tran_color = argument3;
htol = argument4;
stol = argument5;
vtol = argument6;
blend = argument7;
var precise, transparent, smooth, preload, xorig, yorig, images, width, height;
var old_h, old_s, old_v, new_h, new_s, new_v, diff_h, diff_s, diff_v, i, sx, sy;
var test_color, test_h, test_s, test_v;
precise = sprite_get_precise(old_sprite);
transparent = sprite_get_transparent(old_sprite);
smooth = sprite_get_smooth(old_sprite);
preload = sprite_get_preload(old_sprite);
xorig = sprite_get_xoffset(old_sprite);
yorig = sprite_get_yoffset(old_sprite);
images = sprite_get_number(old_sprite);
width = sprite_get_width(old_sprite);
height = sprite_get_height(old_sprite);
old_h = color_get_hue(old_color);
old_s = color_get_saturation(old_color);
old_v = color_get_value(old_color);
new_h = color_get_hue(new_color);
new_s = color_get_saturation(new_color);
new_v = color_get_value(new_color);
for(i = 0; i < images; i += 1) {
draw_set_color(tran_color);
draw_rectangle(0, 0, width + 1, height + 1, false);
draw_sprite(old_sprite, i, xorig, yorig);
for(sy = 0; sy < height; sy += 1) {
for(sx = 0; sx < width; sx += 1) {
test_color = draw_getpixel(sx, sy);
test_h = color_get_hue(test_color);
test_s = color_get_saturation(test_color);
test_v = color_get_value(test_color);
diff_h = test_h - old_h;
diff_s = test_s - old_s;
diff_v = test_v - old_v;
if (abs(diff_h) > 128) diff_h = sign(diff_h) * 256 - diff_h;
if (abs(diff_h) < htol && abs(diff_s) < stol && abs(diff_v) < vtol) {
if (blend) new_color = make_color_hsv((new_h + diff_h + 256) mod 256, min(max(0, new_s + diff_s), 255), min(max(0, new_v + diff_v), 255));
draw_point_color(sx, sy, new_color);
}
}
}
if (i == 0) {
new_sprite = sprite_create_from_screen(0, 0, width, height, precise, transparent, smooth, preload, xorig, yorig);
if (new_sprite < 0) return -1;
}else{
sprite_add_from_screen(new_sprite, 0, 0, width, height);
}
}
return new_sprite;