From 6abce30cdce5e0bfa5405208770543d978e00655 Mon Sep 17 00:00:00 2001 From: Evildragon Date: Mon, 14 Aug 2023 18:16:23 +0900 Subject: [PATCH 1/4] color change --- code/__HELPERS/colors.dm | 23 +++++++++++++++++++++++ code/__HELPERS/type2type.dm | 9 --------- code/game/objects/items/crayons.dm | 4 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm index c893ab11b17cb..07d92aca80e9f 100644 --- a/code/__HELPERS/colors.dm +++ b/code/__HELPERS/colors.dm @@ -64,3 +64,26 @@ final_color += copytext(color, digit, digit + 1) return final_color + + +/// returns HSV brightness 0 to 100 by color hex +/proc/get_color_brightness_from_hex(A) + if(!A || length(A) != length_char(A)) + return 0 + var/R = hex2num(copytext(A, 2, 4)) + var/G = hex2num(copytext(A, 4, 6)) + var/B = hex2num(copytext(A, 6, 8)) + return round(max(R, G, B)/2.55, 1) + +/// returns HSV brightness 0 to 100 by color hex +/proc/get_color_saturation_from_hex(A) + if(!A || length(A) != length_char(A)) + return 0 + var/R = hex2num(copytext(A, 2, 4)) + var/G = hex2num(copytext(A, 4, 6)) + var/B = hex2num(copytext(A, 6, 8)) + var/brightness = max(R, G, B) + if(brightness == 0) + return 0 + + return round((brightness - min(R, G, B))/brightness*100, 1) diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 09fef155cba74..febb28b4887b2 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -473,15 +473,6 @@ Takes a string and a datum. The string is well, obviously the string being check if(var_source.vars.Find(A)) . += A -/// Converts a hex code to a number -/proc/color_hex2num(A) - if(!A || length(A) != length_char(A)) - return 0 - var/R = hex2num(copytext(A, 2, 4)) - var/G = hex2num(copytext(A, 4, 6)) - var/B = hex2num(copytext(A, 6, 8)) - return R+G+B - //word of warning: using a matrix like this as a color value will simplify it back to a string after being set /proc/color_hex2color_matrix(string) var/length = length(string) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 45f1329e95136..8d4f554c289ad 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -697,7 +697,7 @@ if(isobj(target) && !(target.flags_1 & UNPAINTABLE_1)) if(actually_paints) - if(color_hex2num(paint_color) < 350 && !istype(target, /obj/structure/window)) //Colors too dark are rejected + if(get_color_brightness_from_hex(paint_color) < 33 && !istype(target, /obj/structure/window)) //Colors too dark are rejected if(isclothing(target)) var/obj/item/clothing/C = target if(((C.flags_cover & HEADCOVERSEYES) || (C.flags_cover & MASKCOVERSEYES) || (C.flags_cover & GLASSESCOVERSEYES)) && !HAS_TRAIT(C, TRAIT_SPRAYPAINTED)) @@ -717,7 +717,7 @@ target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY) if(istype(target, /obj/structure/window)) - if(color_hex2num(paint_color) < 255) + if(get_color_brightness_from_hex(paint_color) < 50) target.set_opacity(255) else target.set_opacity(initial(target.opacity)) From e6e758f2d70a030236e7cfc556712a7fd3da1e95 Mon Sep 17 00:00:00 2001 From: EvilDragonfiend <87972842+EvilDragonfiend@users.noreply.github.com> Date: Mon, 14 Aug 2023 18:41:45 +0900 Subject: [PATCH 2/4] Fix comment --- code/__HELPERS/colors.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm index 07d92aca80e9f..4f13ed203eb85 100644 --- a/code/__HELPERS/colors.dm +++ b/code/__HELPERS/colors.dm @@ -75,7 +75,7 @@ var/B = hex2num(copytext(A, 6, 8)) return round(max(R, G, B)/2.55, 1) -/// returns HSV brightness 0 to 100 by color hex +/// returns HSV saturation 0 to 100 by color hex /proc/get_color_saturation_from_hex(A) if(!A || length(A) != length_char(A)) return 0 From 22330a392377f0d8b7e48488afc29e6601f2413b Mon Sep 17 00:00:00 2001 From: Evildragon Date: Thu, 21 Sep 2023 20:17:37 +0900 Subject: [PATCH 3/4] more method --- beestation.dme | 1 + code/__DEFINES/color.dm | 4 +++ code/__HELPERS/colors.dm | 50 ++++++++++++++++-------------- code/game/objects/items/crayons.dm | 4 +-- 4 files changed, 34 insertions(+), 25 deletions(-) create mode 100644 code/__DEFINES/color.dm diff --git a/beestation.dme b/beestation.dme index f2df1f8aab23f..2e43204925149 100644 --- a/beestation.dme +++ b/beestation.dme @@ -54,6 +54,7 @@ #include "code\__DEFINES\cleaning.dm" #include "code\__DEFINES\clockcult.dm" #include "code\__DEFINES\clothing.dm" +#include "code\__DEFINES\color.dm" #include "code\__DEFINES\colors.dm" #include "code\__DEFINES\combat.dm" #include "code\__DEFINES\communications.dm" diff --git a/code/__DEFINES/color.dm b/code/__DEFINES/color.dm new file mode 100644 index 0000000000000..46b434e021aab --- /dev/null +++ b/code/__DEFINES/color.dm @@ -0,0 +1,4 @@ +/// rgb2num(color, COLORSPACE_HSL) calculates saturation for brightness. This method will allow dark monocolor, while not allow darker chromatic color. +#define BRIGHTNESS_BYOND_COLOR "brightness_byond_color" +/// this is manual calculation to get only HSV brightness that brightness value is all the same regardless of saturation value. +#define BRIGHTNESS_HSV_PURE "brightness_hsv_pure" diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm index 4f13ed203eb85..57e6ccfa5ad45 100644 --- a/code/__HELPERS/colors.dm +++ b/code/__HELPERS/colors.dm @@ -48,32 +48,23 @@ /// Given a color in the format of "#RRGGBB", will return if the color /// is dark. -/proc/is_color_dark(color, threshold = 25) - var/hsl = rgb2num(color, COLORSPACE_HSL) - return hsl[3] < threshold - -/// Given a 3 character color (no hash), converts it into #RRGGBB (with hash) -/proc/expand_three_digit_color(color) - if (length_char(color) != 3) - CRASH("Invalid 3 digit color: [color]") - - var/final_color = "#" - - for (var/digit = 1 to 3) - final_color += copytext(color, digit, digit + 1) - final_color += copytext(color, digit, digit + 1) - - return final_color - +/proc/is_color_dark(hex_string, threshold = 25, method=BRIGHTNESS_BYOND_COLOR) + return get_color_brightness_from_hex(hex_string, method) < threshold /// returns HSV brightness 0 to 100 by color hex -/proc/get_color_brightness_from_hex(A) - if(!A || length(A) != length_char(A)) +/proc/get_color_brightness_from_hex(hex_string, method=BRIGHTNESS_BYOND_COLOR) + if(!hex_string || length(hex_string) != length_char(hex_string)) return 0 - var/R = hex2num(copytext(A, 2, 4)) - var/G = hex2num(copytext(A, 4, 6)) - var/B = hex2num(copytext(A, 6, 8)) - return round(max(R, G, B)/2.55, 1) + switch(method) + if(BRIGHTNESS_BYOND_COLOR) + var/hsl = rgb2num(hex_string, COLORSPACE_HSL) + return hsl[3] + if(BRIGHTNESS_HSV_PURE) + var/R = hex2num(copytext(hex_string, 2, 4)) + var/G = hex2num(copytext(hex_string, 4, 6)) + var/B = hex2num(copytext(hex_string, 6, 8)) + return round(max(R, G, B)/255, 1) // devide by 255 to make 0-100 value range. + return 0 /// returns HSV saturation 0 to 100 by color hex /proc/get_color_saturation_from_hex(A) @@ -87,3 +78,16 @@ return 0 return round((brightness - min(R, G, B))/brightness*100, 1) + +/// Given a 3 character color (no hash), converts it into #RRGGBB (with hash) +/proc/expand_three_digit_color(color) + if (length_char(color) != 3) + CRASH("Invalid 3 digit color: [color]") + + var/final_color = "#" + + for (var/digit = 1 to 3) + final_color += copytext(color, digit, digit + 1) + final_color += copytext(color, digit, digit + 1) + + return final_color diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 8d4f554c289ad..b8cf849045479 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -697,7 +697,7 @@ if(isobj(target) && !(target.flags_1 & UNPAINTABLE_1)) if(actually_paints) - if(get_color_brightness_from_hex(paint_color) < 33 && !istype(target, /obj/structure/window)) //Colors too dark are rejected + if(is_color_dark(paint_color, 33, BRIGHTNESS_HSV_PURE) && !istype(target, /obj/structure/window)) //Colors too dark are rejected if(isclothing(target)) var/obj/item/clothing/C = target if(((C.flags_cover & HEADCOVERSEYES) || (C.flags_cover & MASKCOVERSEYES) || (C.flags_cover & GLASSESCOVERSEYES)) && !HAS_TRAIT(C, TRAIT_SPRAYPAINTED)) @@ -717,7 +717,7 @@ target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY) if(istype(target, /obj/structure/window)) - if(get_color_brightness_from_hex(paint_color) < 50) + if(is_color_dark(paint_color, 50, BRIGHTNESS_HSV_PURE)) target.set_opacity(255) else target.set_opacity(initial(target.opacity)) From 8cc510948edf4ec46da45c6a53c4df5ad617bd6d Mon Sep 17 00:00:00 2001 From: Evildragon Date: Mon, 27 Nov 2023 10:40:04 +0900 Subject: [PATCH 4/4] split procs --- beestation.dme | 1 - code/__DEFINES/color.dm | 4 -- code/__HELPERS/colors.dm | 51 ++++++++++--------- code/game/objects/items/crayons.dm | 4 +- .../character/species_features/mutants.dm | 2 +- .../holoparasite/holoparasite_builder.dm | 6 +-- .../computers/item/computer_ui.dm | 2 +- 7 files changed, 33 insertions(+), 37 deletions(-) delete mode 100644 code/__DEFINES/color.dm diff --git a/beestation.dme b/beestation.dme index 4a31086c05434..56a628fe12cac 100644 --- a/beestation.dme +++ b/beestation.dme @@ -56,7 +56,6 @@ #include "code\__DEFINES\cleaning.dm" #include "code\__DEFINES\clockcult.dm" #include "code\__DEFINES\clothing.dm" -#include "code\__DEFINES\color.dm" #include "code\__DEFINES\colors.dm" #include "code\__DEFINES\combat.dm" #include "code\__DEFINES\communications.dm" diff --git a/code/__DEFINES/color.dm b/code/__DEFINES/color.dm deleted file mode 100644 index 46b434e021aab..0000000000000 --- a/code/__DEFINES/color.dm +++ /dev/null @@ -1,4 +0,0 @@ -/// rgb2num(color, COLORSPACE_HSL) calculates saturation for brightness. This method will allow dark monocolor, while not allow darker chromatic color. -#define BRIGHTNESS_BYOND_COLOR "brightness_byond_color" -/// this is manual calculation to get only HSV brightness that brightness value is all the same regardless of saturation value. -#define BRIGHTNESS_HSV_PURE "brightness_hsv_pure" diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm index 504816bc3adc4..1161092c79afc 100644 --- a/code/__HELPERS/colors.dm +++ b/code/__HELPERS/colors.dm @@ -67,37 +67,38 @@ #define RANDOM_COLOUR (rgb(rand(0,255),rand(0,255),rand(0,255))) /// Given a color in the format of "#RRGGBB", will return if the color -/// is dark. -/proc/is_color_dark(hex_string, threshold = 25, method=BRIGHTNESS_BYOND_COLOR) - return get_color_brightness_from_hex(hex_string, method) < threshold +/// is dark. Value is mixed with Saturation and Brightness from HSV. +/proc/is_color_dark_with_saturation(color, threshold = 25) + var/hsl = rgb2num(color, COLORSPACE_HSL) + return hsl[3] < threshold + +/// it checks if a color is dark, but without saturation value. +/// This uses Brightness only, without Saturation from HSV +/proc/is_color_dark_without_saturation(color, threshold = 25) + return get_color_brightness_from_hex(color) < threshold /// returns HSV brightness 0 to 100 by color hex -/proc/get_color_brightness_from_hex(hex_string, method=BRIGHTNESS_BYOND_COLOR) - if(!hex_string || length(hex_string) != length_char(hex_string)) +/proc/get_color_brightness_from_hex(A) + if(!A || length(A) != length_char(A)) return 0 - switch(method) - if(BRIGHTNESS_BYOND_COLOR) - var/hsl = rgb2num(hex_string, COLORSPACE_HSL) - return hsl[3] - if(BRIGHTNESS_HSV_PURE) - var/R = hex2num(copytext(hex_string, 2, 4)) - var/G = hex2num(copytext(hex_string, 4, 6)) - var/B = hex2num(copytext(hex_string, 6, 8)) - return round(max(R, G, B)/255, 1) // devide by 255 to make 0-100 value range. - return 0 + var/R = hex2num(copytext(A, 2, 4)) + var/G = hex2num(copytext(A, 4, 6)) + var/B = hex2num(copytext(A, 6, 8)) + return round(max(R, G, B)/2.55, 1) +// currently unused proc, but made for someone who will need it. /// returns HSV saturation 0 to 100 by color hex /proc/get_color_saturation_from_hex(A) - if(!A || length(A) != length_char(A)) - return 0 - var/R = hex2num(copytext(A, 2, 4)) - var/G = hex2num(copytext(A, 4, 6)) - var/B = hex2num(copytext(A, 6, 8)) - var/brightness = max(R, G, B) - if(brightness == 0) - return 0 - - return round((brightness - min(R, G, B))/brightness*100, 1) + if(!A || length(A) != length_char(A)) + return 0 + var/R = hex2num(copytext(A, 2, 4)) + var/G = hex2num(copytext(A, 4, 6)) + var/B = hex2num(copytext(A, 6, 8)) + var/brightness = max(R, G, B) + if(brightness == 0) + return 0 + + return round((brightness - min(R, G, B))/brightness*100, 1) /// Given a 3 character color (no hash), converts it into #RRGGBB (with hash) /proc/expand_three_digit_color(color) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index b8e7026e4b7a9..0d1ac193176ce 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -696,7 +696,7 @@ if(isobj(target) && !(target.flags_1 & UNPAINTABLE_1)) if(actually_paints) - if(is_color_dark(paint_color, 33, BRIGHTNESS_HSV_PURE) && !istype(target, /obj/structure/window)) //Colors too dark are rejected + if(is_color_dark_without_saturation(paint_color, 33) && !istype(target, /obj/structure/window)) //Colors too dark are rejected if(isclothing(target)) var/obj/item/clothing/C = target if(((C.flags_cover & HEADCOVERSEYES) || (C.flags_cover & MASKCOVERSEYES) || (C.flags_cover & GLASSESCOVERSEYES)) && !HAS_TRAIT(C, TRAIT_SPRAYPAINTED)) @@ -716,7 +716,7 @@ target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY) if(istype(target, /obj/structure/window)) - if(is_color_dark(paint_color, 50, BRIGHTNESS_HSV_PURE)) + if(is_color_dark_without_saturation(paint_color, 50)) target.set_opacity(255) else target.set_opacity(initial(target.opacity)) diff --git a/code/modules/client/preferences/entries/character/species_features/mutants.dm b/code/modules/client/preferences/entries/character/species_features/mutants.dm index 0a1897793aca9..88a5e807c924d 100644 --- a/code/modules/client/preferences/entries/character/species_features/mutants.dm +++ b/code/modules/client/preferences/entries/character/species_features/mutants.dm @@ -14,7 +14,7 @@ if (!..(value)) return FALSE - if (is_color_dark(expand_three_digit_color(value))) + if (is_color_dark_with_saturation(expand_three_digit_color(value))) return FALSE return TRUE diff --git a/code/modules/holoparasite/holoparasite_builder.dm b/code/modules/holoparasite/holoparasite_builder.dm index 4ae2b63ba9ebd..66a7cfc2e11e6 100644 --- a/code/modules/holoparasite/holoparasite_builder.dm +++ b/code/modules/holoparasite/holoparasite_builder.dm @@ -104,7 +104,7 @@ ) ), "validation" = list( - "color" = is_color_dark(accent_color, HOLOPARA_MAX_ACCENT_LIGHTNESS) ? "too dark" : "valid", + "color" = is_color_dark_with_saturation(accent_color, HOLOPARA_MAX_ACCENT_LIGHTNESS) ? "too dark" : "valid", "name" = check_name_validity(), "notes" = check_notes_validity() ) @@ -196,7 +196,7 @@ if(!istext(color) || length(color) != 7) return var/new_accent_color = sanitize_hexcolor(color, desired_format = 6, include_crunch = TRUE, default = (length(accent_color) == 7 && accent_color != initial(accent_color)) ? accent_color : pick(GLOB.color_list_blood_brothers)) - if(is_color_dark(new_accent_color, HOLOPARA_MAX_ACCENT_LIGHTNESS)) + if(is_color_dark_with_saturation(new_accent_color, HOLOPARA_MAX_ACCENT_LIGHTNESS)) to_chat(usr, "Selected accent color is too dark!") return accent_color = new_accent_color @@ -346,7 +346,7 @@ to_chat(src, "The provided notes contain forbidden words.") user.balloon_alert(user, "failed, filtered notes", show_in_chat = FALSE) return FALSE - if(is_color_dark(accent_color, HOLOPARA_MAX_ACCENT_LIGHTNESS)) + if(is_color_dark_with_saturation(accent_color, HOLOPARA_MAX_ACCENT_LIGHTNESS)) to_chat(src, "The provided accent color ([accent_color]) is too dark (lightness of [rgb2num(accent_color, COLORSPACE_HSL)[3]], must be below [HOLOPARA_MAX_ACCENT_LIGHTNESS]).") user.balloon_alert(user, "failed, accent color too dark", show_in_chat = FALSE) return FALSE diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index aac3e834347fa..e89b34bfde167 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -216,7 +216,7 @@ new_color = tgui_color_picker(user, "Choose a new color for [src]'s flashlight.", "Light Color",light_color) if(!new_color) return - if(is_color_dark(new_color, 50) ) //Colors too dark are rejected + if(is_color_dark_with_saturation(new_color, 50) ) //Colors too dark are rejected to_chat(user, "That color is too dark! Choose a lighter one.") new_color = null return set_flashlight_color(new_color)