From fa24f1bd3aa4ecd9637975ac0dcc614719187f8f Mon Sep 17 00:00:00 2001 From: deathride58 Date: Tue, 7 Jun 2022 16:36:10 -0400 Subject: [PATCH 1/3] user-friendly colormates - adds HSV coloration to colormates! --- code/__HELPERS/matrices/color_matrix.dm | 19 +++ code/game/machinery/colormate.dm | 163 ++++++++++++--------- tgui/packages/tgui/interfaces/Colormate.js | 163 ++++++++++++++++----- 3 files changed, 239 insertions(+), 106 deletions(-) diff --git a/code/__HELPERS/matrices/color_matrix.dm b/code/__HELPERS/matrices/color_matrix.dm index e4a4a9bb48..bcc48b45f5 100644 --- a/code/__HELPERS/matrices/color_matrix.dm +++ b/code/__HELPERS/matrices/color_matrix.dm @@ -138,6 +138,25 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001) return list(cosval,sinval,0,0, -sinval,cosval,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0) +/** + * Builds a color matrix that transforms the hue, saturation, and value, all in one operation. + */ +/proc/color_matrix_hsv(hue, saturation, value) + hue = clamp(360 - hue, 0, 360) + + // This is very much a rough approximation of hueshifting. This carries some artifacting, such as negative values that simply shouldn't exist, but it does get the job done, and that's what matters. + var/cos_a = cos(hue) // These have to be inverted from 360, otherwise the hue's inverted + var/sin_a = sin(hue) + var/rot_x = cos_a + (1 - cos_a) / 3 + var/rot_y = (1 - cos_a) / 3 - 0.5774 * sin_a // 0.5774 is sqrt(1/3) + var/rot_z = (1 - cos_a) / 3 + 0.5774 * sin_a + + return list( + round((((1-saturation) * LUMA_R) + (rot_x * saturation)) * value, 0.01), round((((1-saturation) * LUMA_R) + (rot_y * saturation)) * value, 0.01), round((((1-saturation) * LUMA_R) + (rot_z * saturation)) * value, 0.01), + round((((1-saturation) * LUMA_G) + (rot_z * saturation)) * value, 0.01), round((((1-saturation) * LUMA_G) + (rot_x * saturation)) * value, 0.01), round((((1-saturation) * LUMA_G) + (rot_y * saturation)) * value, 0.01), + round((((1-saturation) * LUMA_B) + (rot_y * saturation)) * value, 0.01), round((((1-saturation) * LUMA_B) + (rot_z * saturation)) * value, 0.01), round((((1-saturation) * LUMA_B) + (rot_x * saturation)) * value, 0.01), + 0, 0, 0 + ) //Returns a matrix addition of A with B /proc/color_matrix_add(list/A, list/B) diff --git a/code/game/machinery/colormate.dm b/code/game/machinery/colormate.dm index 1528142a3b..c3c7860553 100644 --- a/code/game/machinery/colormate.dm +++ b/code/game/machinery/colormate.dm @@ -1,6 +1,10 @@ +#define COLORMATE_TINT 1 +#define COLORMATE_HSV 2 +#define COLORMATE_MATRIX 3 + /obj/machinery/gear_painter name = "\improper Color Mate" - desc = "A machine to give your apparel a fresh new color! Recommended to use with white items for best results." + desc = "A machine to give your apparel a fresh new color!" icon = 'icons/obj/vending.dmi' icon_state = "colormate" // light_mask = "colormate-light-mask" @@ -10,7 +14,11 @@ var/atom/movable/inserted var/activecolor = "#FFFFFF" var/list/color_matrix_last - var/matrix_mode = FALSE + var/active_mode = COLORMATE_HSV + + var/build_hue = 0 + var/build_sat = 1 + var/build_val = 1 /// Allow holder'd mobs var/allow_mobs = TRUE /// Minimum lightness for normal mode @@ -71,8 +79,9 @@ return if(!QDELETED(H)) H.release() + user.visible_message("[user] stuffs [I] into [src]'s receptable! Oh dear.") + insert_mob(victim, user) - temp = "[victim] has been inserted." SStgui.update_uis(src) if(is_type_in_list(I, allowed_types) && is_operational()) @@ -85,7 +94,6 @@ inserted = I update_icon() - temp = "[I] has been inserted." SStgui.update_uis(src) else @@ -134,7 +142,7 @@ /obj/machinery/gear_painter/ui_data(mob/user) . = list() - .["matrixactive"] = matrix_mode + .["activemode"] = active_mode .["matrixcolors"] = list( "rr" = color_matrix_last[1], "rg" = color_matrix_last[2], @@ -149,6 +157,9 @@ "cg" = color_matrix_last[11], "cb" = color_matrix_last[12] ) + .["buildhue"] = build_hue + .["buildsat"] = build_sat + .["buildval"] = build_val if(temp) .["temp"] = temp if(inserted) @@ -166,7 +177,7 @@ if(inserted) switch(action) if("switch_modes") - matrix_mode = text2num(params["mode"]) + active_mode = text2num(params["mode"]) return TRUE if("choose_color") var/chosen_color = input(usr, "Choose a color: ", "Colormate color picking", activecolor) as color|null @@ -174,14 +185,11 @@ activecolor = chosen_color return TRUE if("paint") - if(!check_valid_color(activecolor, usr)) - return TRUE - inserted.add_atom_colour(activecolor, FIXED_COLOUR_PRIORITY) - playsound(src, 'sound/effects/spray3.ogg', 50, 1) + do_paint(usr) temp = "Painted Successfully!" return TRUE if("drop") - temp = "Ejected \the [inserted]!" + temp = "" drop_item() return TRUE if("clear") @@ -192,76 +200,95 @@ if("set_matrix_color") color_matrix_last[params["color"]] = params["value"] return TRUE - if("matrix_paint") - var/list/cm = rgb_construct_color_matrix( - text2num(color_matrix_last[1]), - text2num(color_matrix_last[2]), - text2num(color_matrix_last[3]), - text2num(color_matrix_last[4]), - text2num(color_matrix_last[5]), - text2num(color_matrix_last[6]), - text2num(color_matrix_last[7]), - text2num(color_matrix_last[8]), - text2num(color_matrix_last[9]), - text2num(color_matrix_last[10]), - text2num(color_matrix_last[11]), - text2num(color_matrix_last[12]) - ) - if(!check_valid_color(cm, usr)) - return TRUE - inserted.add_atom_colour(cm, FIXED_COLOUR_PRIORITY) - playsound(src, 'sound/effects/spray3.ogg', 50, 1) - temp = "Matrix Painted Successfully!" + if("set_hue") + build_hue = clamp(text2num(params["buildhue"]), 0, 360) return TRUE + if("set_sat") + build_sat = clamp(text2num(params["buildsat"]), -10, 10) + return TRUE + if("set_val") + build_val = clamp(text2num(params["buildval"]), -10, 10) + return TRUE + + +/obj/machinery/gear_painter/proc/do_paint(mob/user) + var/color_to_use + switch(active_mode) + if(COLORMATE_TINT) + color_to_use = activecolor + if(COLORMATE_MATRIX) + color_to_use = rgb_construct_color_matrix( + text2num(color_matrix_last[1]), + text2num(color_matrix_last[2]), + text2num(color_matrix_last[3]), + text2num(color_matrix_last[4]), + text2num(color_matrix_last[5]), + text2num(color_matrix_last[6]), + text2num(color_matrix_last[7]), + text2num(color_matrix_last[8]), + text2num(color_matrix_last[9]), + text2num(color_matrix_last[10]), + text2num(color_matrix_last[11]), + text2num(color_matrix_last[12]) + ) + if(COLORMATE_HSV) + color_to_use = color_matrix_hsv(build_hue, build_sat, build_val) + color_matrix_last = color_to_use + if(!color_to_use || !check_valid_color(color_to_use, user)) + to_chat(user, "Invalid color.") + return FALSE + inserted.add_atom_colour(color_to_use, FIXED_COLOUR_PRIORITY) + playsound(src, 'sound/effects/spray3.ogg', 50, 1) + return TRUE + /// Produces the preview image of the item, used in the UI, the way the color is not stacking is a sin. /obj/machinery/gear_painter/proc/build_preview() if(inserted) //sanity - if(matrix_mode) - var/list/cm = rgb_construct_color_matrix( - text2num(color_matrix_last[1]), - text2num(color_matrix_last[2]), - text2num(color_matrix_last[3]), - text2num(color_matrix_last[4]), - text2num(color_matrix_last[5]), - text2num(color_matrix_last[6]), - text2num(color_matrix_last[7]), - text2num(color_matrix_last[8]), - text2num(color_matrix_last[9]), - text2num(color_matrix_last[10]), - text2num(color_matrix_last[11]), - text2num(color_matrix_last[12]) - ) - if(!check_valid_color(cm, usr)) - temp = "Failed to generate preview: Invalid color!" - return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) + var/list/cm + switch(active_mode) + if(COLORMATE_MATRIX) + cm = rgb_construct_color_matrix( + text2num(color_matrix_last[1]), + text2num(color_matrix_last[2]), + text2num(color_matrix_last[3]), + text2num(color_matrix_last[4]), + text2num(color_matrix_last[5]), + text2num(color_matrix_last[6]), + text2num(color_matrix_last[7]), + text2num(color_matrix_last[8]), + text2num(color_matrix_last[9]), + text2num(color_matrix_last[10]), + text2num(color_matrix_last[11]), + text2num(color_matrix_last[12]) + ) + if(!check_valid_color(cm, usr)) + return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) - var/cur_color = inserted.color - inserted.color = null - inserted.color = cm - var/icon/preview = getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) - inserted.color = cur_color + if(COLORMATE_TINT) + if(!check_valid_color(activecolor, usr)) + return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) - . = preview + if(COLORMATE_HSV) + cm = color_matrix_hsv(build_hue, build_sat, build_val) + color_matrix_last = cm + if(!check_valid_color(cm, usr)) + return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) - else - if(!check_valid_color(activecolor, usr)) - temp = "Failed to generate preview: Invalid color!" - return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) + var/cur_color = inserted.color + inserted.color = null + inserted.color = (active_mode == COLORMATE_TINT ? activecolor : cm) + var/icon/preview = getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) + inserted.color = cur_color + temp = "" - var/cur_color = inserted.color - inserted.color = null - inserted.color = activecolor - var/icon/preview = getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE) - inserted.color = cur_color - - . = preview + . = preview /obj/machinery/gear_painter/proc/check_valid_color(list/cm, mob/user) if(!islist(cm)) // normal var/list/HSV = ReadHSV(RGBtoHSV(cm)) if(HSV[3] < minimum_normal_lightness) - temp = "[cm] is far too dark (min lightness [minimum_normal_lightness]!" + temp = "[cm] is too dark (Minimum lightness: [minimum_normal_lightness])" return FALSE return TRUE else // matrix @@ -275,6 +302,6 @@ COLORTEST("FFFFFF", cm) #undef COLORTEST if(passed < minimum_matrix_tests) - temp = "[english_list(color)] is not allowed (passed [passed] out of 4, minimum [minimum_matrix_tests], minimum lightness [minimum_matrix_lightness])." + temp = "Matrix is too dark. (passed [passed] out of [minimum_matrix_tests] required tests. Minimum lightness: [minimum_matrix_lightness])." return FALSE return TRUE diff --git a/tgui/packages/tgui/interfaces/Colormate.js b/tgui/packages/tgui/interfaces/Colormate.js index f376547102..79bc3543e9 100644 --- a/tgui/packages/tgui/interfaces/Colormate.js +++ b/tgui/packages/tgui/interfaces/Colormate.js @@ -4,7 +4,7 @@ import { Window } from '../layouts'; export const Colormate = (props, context) => { const { act, data } = useBackend(context); - const { matrixactive, temp } = data; + const { activemode, temp } = data; const item = data.item || []; return ( @@ -39,33 +39,48 @@ export const Colormate = (props, context) => {
act('switch_modes', { - mode: "0", + mode: 1, })} > - Regular coloring + Tint coloring (Simple) act('switch_modes', { - mode: "1", + mode: 2, })} > - Matrixed coloring + HSV coloring (Normal) + + act('switch_modes', { + mode: 3, + })} > + Matrix coloring (Advanced) - {matrixactive ? ( + {} + {activemode === 3 ? ( <>
Coloring: {item.name}
- ) : ( + ) : activemode === 2 ? ( <>
Coloring: {item.name}
- + - )} + ) + : ( + <> +
Coloring: {item.name}
+ + + )}
) : ( @@ -140,8 +155,9 @@ export const ColormateMatrix = (props, context) => { RR: act('set_matrix_color', { color: 1, @@ -151,8 +167,9 @@ export const ColormateMatrix = (props, context) => { GR: act('set_matrix_color', { color: 4, @@ -162,8 +179,9 @@ export const ColormateMatrix = (props, context) => { BR: act('set_matrix_color', { color: 7, @@ -175,8 +193,9 @@ export const ColormateMatrix = (props, context) => { RG: act('set_matrix_color', { color: 2, @@ -186,8 +205,9 @@ export const ColormateMatrix = (props, context) => { GG: act('set_matrix_color', { color: 5, @@ -197,8 +217,9 @@ export const ColormateMatrix = (props, context) => { BG: act('set_matrix_color', { color: 8, @@ -210,8 +231,9 @@ export const ColormateMatrix = (props, context) => { RB: act('set_matrix_color', { color: 3, @@ -221,8 +243,9 @@ export const ColormateMatrix = (props, context) => { GB: act('set_matrix_color', { color: 6, @@ -232,8 +255,9 @@ export const ColormateMatrix = (props, context) => { BB: act('set_matrix_color', { color: 9, @@ -245,8 +269,9 @@ export const ColormateMatrix = (props, context) => { CR: act('set_matrix_color', { color: 10, @@ -256,8 +281,9 @@ export const ColormateMatrix = (props, context) => { CG: act('set_matrix_color', { color: 11, @@ -267,8 +293,9 @@ export const ColormateMatrix = (props, context) => { CB: act('set_matrix_color', { color: 12, @@ -278,9 +305,69 @@ export const ColormateMatrix = (props, context) => { RG means red will become this much green.
- CR means that red will have this much constrast applied to it. + CR means this much red will be added.
); }; + +export const ColormateHSL = (props, context) => { + const { act, data } = useBackend(context); + const { buildhue, buildsat, buildval } = data; + return ( +
+ + +
+ ); +}; \ No newline at end of file From ecb4ebafc5977fcbdcf741608f447e402e39cbd5 Mon Sep 17 00:00:00 2001 From: deathride58 Date: Tue, 7 Jun 2022 17:11:24 -0400 Subject: [PATCH 2/3] oop - there was already a message for this! --- code/game/machinery/colormate.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/game/machinery/colormate.dm b/code/game/machinery/colormate.dm index c3c7860553..a208fc0bd2 100644 --- a/code/game/machinery/colormate.dm +++ b/code/game/machinery/colormate.dm @@ -79,7 +79,6 @@ return if(!QDELETED(H)) H.release() - user.visible_message("[user] stuffs [I] into [src]'s receptable! Oh dear.") insert_mob(victim, user) SStgui.update_uis(src) From c6950fc8d527462c6ca57cea171437f4aadc7543 Mon Sep 17 00:00:00 2001 From: SandPoot Date: Tue, 7 Jun 2022 21:08:15 -0300 Subject: [PATCH 3/3] some tweaks! --- tgui/packages/tgui/interfaces/Colormate.js | 589 ++++++++++----------- 1 file changed, 274 insertions(+), 315 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Colormate.js b/tgui/packages/tgui/interfaces/Colormate.js index 79bc3543e9..02810f2943 100644 --- a/tgui/packages/tgui/interfaces/Colormate.js +++ b/tgui/packages/tgui/interfaces/Colormate.js @@ -1,5 +1,5 @@ import { useBackend } from '../backend'; -import { Button, Flex, Icon, NoticeBox, NumberInput, Section, Tabs } from '../components'; +import { Button, Icon, NoticeBox, NumberInput, Section, Table, Tabs, Slider } from '../components'; import { Window } from '../layouts'; export const Colormate = (props, context) => { @@ -9,34 +9,38 @@ export const Colormate = (props, context) => { return ( - {temp ? ( - {temp} - ) : (null)} - {Object.keys(item).length ? ( - <> - -
-
Item:
- -
-
-
Preview:
- -
-
-
+
+ {temp ? ( + {temp} + ) : (null)} + {Object.keys(item).length ? ( + <> + + +
+
Item:
+ +
+
+ +
+
Preview:
+ +
+
+
{ Matrix coloring (Advanced) - {} - {activemode === 3 ? ( - <> -
Coloring: {item.name}
- - - ) : activemode === 2 ? ( - <> -
Coloring: {item.name}
- - - ) - : ( - <> -
Coloring: {item.name}
- - - )} -
- - ) : ( -
+
Coloring: {item.name}
+ + +
+ + ) : (
No item inserted.
-
- )} + )} +
); }; -export const ColormateNoMatrix = (props, context) => { +export const ColormateTint = (props, context) => { const { act, data } = useBackend(context); return ( -
- - -
+