diff --git a/code/datums/greyscale/_greyscale_config.dm b/code/datums/greyscale/_greyscale_config.dm index 674cbb3c892..393a0f901c3 100644 --- a/code/datums/greyscale/_greyscale_config.dm +++ b/code/datums/greyscale/_greyscale_config.dm @@ -231,20 +231,20 @@ fcopy(icon_output, "tmp/gags_debug_output.dmi") /// Actually create the icon and color it in, handles caching -/datum/greyscale_config/proc/Generate(color_string) +/datum/greyscale_config/proc/Generate(color_string, icon/last_external_icon) var/key = color_string var/icon/new_icon = icon_cache[key] if(new_icon) return icon(new_icon) - var/icon/icon_bundle = GenerateBundle(color_string) + var/icon/icon_bundle = GenerateBundle(color_string, last_external_icon=last_external_icon) icon_bundle = fcopy_rsc(icon_bundle) icon_cache[key] = icon_bundle var/icon/output = icon(icon_bundle) return output /// Handles the actual icon manipulation to create the spritesheet -/datum/greyscale_config/proc/GenerateBundle(list/colors, list/render_steps) +/datum/greyscale_config/proc/GenerateBundle(list/colors, list/render_steps, icon/last_external_icon) if(!istype(colors)) colors = SSgreyscale.ParseColorString(colors) if(length(colors) != expected_colors) @@ -255,7 +255,7 @@ var/list/icon_state_steps if(render_steps) icon_state_steps = render_steps[icon_state] = list() - var/icon/generated_icon = GenerateLayerGroup(colors, icon_states[icon_state], icon_state_steps) + var/icon/generated_icon = GenerateLayerGroup(colors, icon_states[icon_state], icon_state_steps, last_external_icon) // We read a pixel to force the icon to be fully generated before we let it loose into the world // I hate this generated_icon.GetPixel(1, 1) @@ -271,15 +271,15 @@ return icon_bundle /// Internal recursive proc to handle nested layer groups -/datum/greyscale_config/proc/GenerateLayerGroup(list/colors, list/group, list/render_steps) +/datum/greyscale_config/proc/GenerateLayerGroup(list/colors, list/group, list/render_steps, icon/last_external_icon) var/icon/new_icon for(var/datum/greyscale_layer/layer as anything in group) var/icon/layer_icon if(islist(layer)) - layer_icon = GenerateLayerGroup(colors, layer, render_steps) + layer_icon = GenerateLayerGroup(colors, layer, render_steps, new_icon || last_external_icon) layer = layer[1] // When there are multiple layers in a group like this we use the first one's blend mode else - layer_icon = layer.Generate(colors, render_steps) + layer_icon = layer.Generate(colors, render_steps, new_icon || last_external_icon) if(!new_icon) new_icon = layer_icon diff --git a/code/datums/greyscale/json_reader.dm b/code/datums/greyscale/json_reader.dm index 883c3993541..ffe143c28fc 100644 --- a/code/datums/greyscale/json_reader.dm +++ b/code/datums/greyscale/json_reader.dm @@ -31,6 +31,27 @@ new_values += new_value return new_values +/datum/json_reader/color_matrix/ReadJson(list/value) + if(!istype(value)) + CRASH("Expected a list but got [value]") + if(length(value) > 5 || length(value) < 4) + CRASH("Color matrix must contain 4 or 5 rows") + var/list/new_values = list() + for(var/list/row in value) + var/list/interpreted_row = list() + if(!istype(row) || length(row) != 4) + stack_trace("Expected list to contain further row lists with exactly 4 entries") + interpreted_row = list(0, 0, 0, 0) + continue + for(var/number in row) + if(!isnum(number)) + stack_trace("Each color matrix row must only contain numbers") + interpreted_row += 0 + else + interpreted_row += number + new_values += interpreted_row + return new_values + /datum/json_reader/blend_mode var/static/list/blend_modes = list( "add" = ICON_ADD, diff --git a/code/datums/greyscale/layer.dm b/code/datums/greyscale/layer.dm index ef6f358e05a..06a001c1ad8 100644 --- a/code/datums/greyscale/layer.dm +++ b/code/datums/greyscale/layer.dm @@ -66,18 +66,19 @@ /// Used to actualy create the layer using the given colors /// Do not override, use InternalGenerate instead -/datum/greyscale_layer/proc/Generate(list/colors, list/render_steps) +/datum/greyscale_layer/proc/Generate(list/colors, list/render_steps, icon/new_icon) var/list/processed_colors = list() for(var/i in color_ids) if(isnum(i)) processed_colors += colors[i] else processed_colors += i - return InternalGenerate(processed_colors, render_steps) + var/icon/copy_of_new_icon = icon(new_icon) // Layers shouldn't be modifying it directly, this is just for them to reference + return InternalGenerate(processed_colors, render_steps, copy_of_new_icon) /// Override this to implement layers. /// The colors var will only contain colors that this layer is configured to use. -/datum/greyscale_layer/proc/InternalGenerate(list/colors, list/render_steps) +/datum/greyscale_layer/proc/InternalGenerate(list/colors, list/render_steps, icon/new_icon) //////////////////////////////////////////////////////// // Subtypes @@ -103,11 +104,25 @@ . = ..() required_values[NAMEOF(src, icon_state)] = /datum/json_reader/text -/datum/greyscale_layer/icon_state/InternalGenerate(list/colors, list/render_steps) +/datum/greyscale_layer/icon_state/InternalGenerate(list/colors, list/render_steps, icon/new_icon) . = ..() - var/icon/new_icon = icon(icon) + var/icon/generated_icon = icon(icon) if(length(colors)) - new_icon.Blend(colors[1], ICON_MULTIPLY) + generated_icon.Blend(colors[1], ICON_MULTIPLY) + return generated_icon + +/// A layer to modify the previous layer's colors with a color matrix +/datum/greyscale_layer/color_matrix + layer_type = "color_matrix" + var/list/color_matrix + +/datum/greyscale_layer/color_matrix/GetExpectedValues(list/required_values, list/optional_values) + . = ..() + required_values[NAMEOF(src, color_matrix)] = /datum/json_reader/color_matrix + +/datum/greyscale_layer/color_matrix/InternalGenerate(list/colors, list/render_steps, icon/new_icon) + . = ..() + new_icon.MapColors(arglist(color_matrix)) return new_icon /// A layer created by using another greyscale icon's configuration @@ -130,12 +145,12 @@ if(!reference_type.icon_states[icon_state]) CRASH("[src] expects icon_state '[icon_state]' but referenced configuration '[reference_type]' does not have it.") -/datum/greyscale_layer/reference/InternalGenerate(list/colors, list/render_steps) +/datum/greyscale_layer/reference/InternalGenerate(list/colors, list/render_steps, icon/new_icon) var/icon/generated_icon if(render_steps) var/list/reference_data = list() - generated_icon = reference_type.GenerateBundle(colors, reference_data) + generated_icon = reference_type.GenerateBundle(colors, reference_data, new_icon) render_steps += reference_data[icon_state] else - generated_icon = reference_type.Generate(colors.Join()) + generated_icon = reference_type.Generate(colors.Join(), new_icon) return icon(generated_icon, icon_state)