From 42aa91d6f28ab7a7ba7df34537bb2bb0633d1675 Mon Sep 17 00:00:00 2001 From: Uristqwerty Date: Wed, 30 May 2012 17:54:33 -0400 Subject: [PATCH] Adding some (currently unused) icon generation stuff Basically, a more generalized version of the rune code, split into more reusable procs. Plus one that generates a version of an icon that has a neat bluespace effect applied. --- code/modules/icon generation/Bluespaced.dm | 243 ++++++++++++++++ .../icon generation/Icon_color_animation.dm | 96 +++++++ code/modules/icon generation/Uristrunes.dm | 268 ++++++++++++++++++ 3 files changed, 607 insertions(+) create mode 100644 code/modules/icon generation/Bluespaced.dm create mode 100644 code/modules/icon generation/Icon_color_animation.dm create mode 100644 code/modules/icon generation/Uristrunes.dm diff --git a/code/modules/icon generation/Bluespaced.dm b/code/modules/icon generation/Bluespaced.dm new file mode 100644 index 0000000000..697b9e9719 --- /dev/null +++ b/code/modules/icon generation/Bluespaced.dm @@ -0,0 +1,243 @@ +/proc/bsi_cast_ray(icon/I, list/start, list/end) + + if(abs(start[1] - end[1]) > abs(start[2] - end[2])) + var/dist = abs(start[1] - end[1]) * 2 + + for(var/i = 1, i <= dist, i++) + var/x = round((start[1] * i / dist) + (end[1] * (1 - i / dist))) + var/y = round((start[2] * i / dist) + (end[2] * (1 - i / dist))) + + if(I.GetPixel(x, y) != null) + return list(x, y) + + else + var/dist = abs(start[2] - end[2]) * 2 + + for(var/i = 1, i <= dist, i++) + var/x = round((start[1] * i / dist) + (end[1] * (1 - i / dist))) + var/y = round((start[2] * i / dist) + (end[2] * (1 - i / dist))) + + if(I.GetPixel(x, y) != null) + return list(x, y) + + return null + +/proc/bsi_split_colors(color) + if(color == null) + return list(0, 0, 0, 0) + + var/list/colors = list(0, 0, 0, 0) + colors[1] = hex2num(copytext(color, 2, 4)) + colors[2] = hex2num(copytext(color, 4, 6)) + colors[3] = hex2num(copytext(color, 6, 8)) + colors[4] = (length(color) > 7)? hex2num(copytext(color, 8, 10)) : 255 + + return colors + +/proc/bsi_spread(icon/I, list/start_point) + var/list/queue = list() + queue[++queue.len] = start_point + + var/i = 0 + + while(i++ < length(queue)) + var/x = queue[i][1] + var/y = queue[i][2] + + var/list/pixel = bsi_split_colors(I.GetPixel(x, y)) + if(pixel[4] == 0) + continue + + var/list/n = (y < I.Height())? bsi_split_colors(I.GetPixel(x, y + 1)) : list(0, 0, 0, 0) + var/list/s = (y > 1)? bsi_split_colors(I.GetPixel(x, y - 1)) : list(0, 0, 0, 0) + var/list/e = (x < I.Width())? bsi_split_colors(I.GetPixel(x + 1, y)) : list(0, 0, 0, 0) + var/list/w = (x > 1)? bsi_split_colors(I.GetPixel(x - 1, y)) : list(0, 0, 0, 0) + + var/value = (i == 1)? 16 : max(n[1] - 1, e[1] - 1, s[1] - 1, w[1] - 1) + + if(prob(50)) + value = max(0, value - 1) + + if(prob(50)) + value = max(0, value - 1) + + if(prob(50)) + value = max(0, value - 1) + + if(value <= pixel[1]) + continue + + var/v2 = 256 - ((16 - value) * (16 - value)) + + I.DrawBox(rgb(value, v2, pixel[4] - v2, pixel[4]), x, y) + + if(n[4] != 0 && n[1] < value - 1) + queue[++queue.len] = list(x, y + 1) + + if(s[4] != 0 && s[1] < value - 1) + queue[++queue.len] = list(x, y - 1) + + if(e[4] != 0 && e[1] < value - 1) + queue[++queue.len] = list(x + 1, y) + + if(w[4] != 0 && w[1] < value - 1) + queue[++queue.len] = list(x - 1, y) + + + + + +/proc/bsi_generate_mask(icon/source, state) + var/icon/mask = icon(source, state) + + mask.MapColors( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 1, + 0, 0, 0, 0) + + var/hits = 0 + + for(var/i = 1, i <= 10, i++) + var/point1 + var/point2 + + if(prob(50)) + if(prob(50)) + point1 = list(rand(1, mask.Width()), mask.Height()) + point2 = list(rand(1, mask.Width()), 1) + + else + point2 = list(rand(1, mask.Width()), mask.Height()) + point1 = list(rand(1, mask.Width()), 1) + + else + if(prob(50)) + point1 = list(mask.Width(), rand(1, mask.Height())) + point2 = list(1, rand(1, mask.Height())) + + else + point2 = list(mask.Width(), rand(1, mask.Height())) + point1 = list(1, rand(1, mask.Height())) + + var/hit = bsi_cast_ray(mask, point1, point2) + + if(hit == null) + continue + + hits++ + + bsi_spread(mask, hit) + + if(prob(20 + hits * 20)) + break + + if(hits == 0) + return null + + else + return mask + +/proc/generate_bluespace_icon(icon/source, state) + + var/icon/mask = bsi_generate_mask(source, state) + + if(mask == null) + return source + + var/icon/unaffected = icon(mask) + unaffected.MapColors( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0, + 255, 255, 255, 0) + + var/icon/temp = icon(source, state) //Mask already contains the original alpha values, avoid squaring them + temp.MapColors( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 0, + 0, 0, 0, 255) + + unaffected.Blend(temp, ICON_MULTIPLY) + + var/icon/bluespaced = icon(mask) + bluespaced.MapColors( + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 0) + + bluespaced.Blend(icon(source, state), ICON_MULTIPLY) + + var/list/frames = list( + list(0.000,20), + list(0.020, 5), + list(0.050, 4), + list(0.080, 5), + list(0.100,10), + list(0.080, 5), + list(0.050, 4), + list(0.020, 5), + + list(0.000,20), + list(0.020, 5), + list(0.050, 4), + list(0.080, 5), + list(0.100,10), + list(0.080, 5), + list(0.050, 4), + list(0.020, 5), + + list(0.000,20), + list(0.020, 5), + list(0.050, 4), + list(0.080, 5), + list(0.100,10), + list(0.080, 5), + list(0.050, 4), + list(0.020, 5), + ) + + var/list/colors = list( + list( 75, 75, 75, 0), + list( 25, 25, 25, 0), + list( 75, 75, 75, 0), + list( 25, 25, 75, 0), + list( 75, 75, 300, 0), + list( 25, 25, 300, 0), + list(255, 255, 255, 0), + list( 0, 0, 0, 255), + list( 0, 0, 0, 0), + list( 0, 0, 0, 0), + ) + + for(var/i = 1, i <= rand(1, 5), i++) + var/f = rand(1, length(frames)) + + if(frames[f][2] > 1) + frames[f][2]-- + frames.Insert(f, 0) + + frames[f] = list(0.8, 1) + + var/icon/result = generate_color_animation(bluespaced, colors, frames) + result.Blend(unaffected, ICON_UNDERLAY) + + return result + + + +/atom/verb/test() + set src in view() + src.icon = generate_bluespace_icon(src.icon, src.icon_state) + +/mob/verb/bluespam() + for(var/turf/t in view(5)) + var/obj/s = new /obj/square(t) + s.icon = generate_bluespace_icon(s.icon, s.icon_state) + diff --git a/code/modules/icon generation/Icon_color_animation.dm b/code/modules/icon generation/Icon_color_animation.dm new file mode 100644 index 0000000000..9681722fcb --- /dev/null +++ b/code/modules/icon generation/Icon_color_animation.dm @@ -0,0 +1,96 @@ +//---------------------------------------- +// +// Return a copy of the provided icon, +// after calling MapColors on it. The +// color values are linearily interpolated +// between the pairs provided, based on +// the ratio argument. +// +//---------------------------------------- + +/proc/MapColors_interpolate(icon/input, ratio, + rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, + gr1, gg1, gb1, ga1, gr2, gg2, gb2, ga2, + br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, + ar1, ag1, ab1, aa1, ar2, ag2, ab2, aa2, + zr1, zg1, zb1, za1, zr2, zg2, zb2, za2) + var/r = ratio + var/i = 1 - ratio + var/icon/I = icon(input) + + I.MapColors( + (rr1 * r + rr2 * i) / 255.0, (rg1 * r + rg2 * i) / 255.0, (rb1 * r + rb2 * i) / 255.0, (ra1 * r + ra2 * i) / 255.0, + (gr1 * r + gr2 * i) / 255.0, (gg1 * r + gg2 * i) / 255.0, (gb1 * r + gb2 * i) / 255.0, (ga1 * r + ga2 * i) / 255.0, + (br1 * r + br2 * i) / 255.0, (bg1 * r + bg2 * i) / 255.0, (bb1 * r + bb2 * i) / 255.0, (ba1 * r + ba2 * i) / 255.0, + (ar1 * r + ar2 * i) / 255.0, (ag1 * r + ag2 * i) / 255.0, (ab1 * r + ab2 * i) / 255.0, (aa1 * r + aa2 * i) / 255.0, + (zr1 * r + zr2 * i) / 255.0, (zg1 * r + zg2 * i) / 255.0, (zb1 * r + zb2 * i) / 255.0, (za1 * r + za2 * i) / 255.0) + + return I + + + + +//---------------------------------------- +// +// Extension of the above that takes a +// list of lists of color values, rather +// than a large number of arguments. +// +//---------------------------------------- + +/proc/MapColors_interpolate_list(icon/I, ratio, list/colors) + var/list/c[10] + + //Provide default values for any missing colors (without altering the original list + for(var/i = 1, i <= 10, i++) + c[i] = list(0, 0, 0, (i == 7 || i == 8)? 255 : 0) + + if(istype(colors[i], /list)) + for(var/j = 1, j <= 4, j++) + if(j <= length(colors[i]) && isnum(colors[i][j])) + c[i][j] = colors[i][j] + + return MapColors_interpolate(I, ratio, + colors[ 1][1], colors[ 1][2], colors[ 1][3], colors[ 1][4], // Red 1 + colors[ 2][1], colors[ 2][2], colors[ 2][3], colors[ 2][4], // Red 2 + colors[ 3][1], colors[ 3][2], colors[ 3][3], colors[ 3][4], // Green 1 + colors[ 4][1], colors[ 4][2], colors[ 4][3], colors[ 4][4], // Green 2 + colors[ 5][1], colors[ 5][2], colors[ 5][3], colors[ 5][4], // Blue 1 + colors[ 6][1], colors[ 6][2], colors[ 6][3], colors[ 6][4], // Blue 2 + colors[ 7][1], colors[ 7][2], colors[ 7][3], colors[ 7][4], // Alpha 1 + colors[ 8][1], colors[ 8][2], colors[ 8][3], colors[ 8][4], // Alpha 2 + colors[ 9][1], colors[ 9][2], colors[ 9][3], colors[ 9][4], // Added 1 + colors[10][1], colors[10][2], colors[10][3], colors[10][4]) // Added 2 + + + + + +//---------------------------------------- +// +// Take the source image, and return an animated +// version, that transitions between the provided +// color mappings, according to the provided +// pattern. +// +// Colors should be in a format suitable for +// MapColors_interpolate_list, and frames should +// be a list of 'frames', where each frame is itself +// a list, element 1 being the ratio of the first +// color to the second, and element 2 being how +// long the frame lasts, in tenths of a second. +// +//---------------------------------------- + +/proc/generate_color_animation(icon/icon, list/colors, list/frames) + var/icon/out = icon('uristrunes.dmi', "") + var/frame_num = 1 + + for(var/frame in frames) + var/icon/I = MapColors_interpolate_list(icon, frame[1], colors) + out.Insert(I, "", 2, frame_num++, 0, frame[2]) + + return out + + + diff --git a/code/modules/icon generation/Uristrunes.dm b/code/modules/icon generation/Uristrunes.dm new file mode 100644 index 0000000000..3f33f8fed5 --- /dev/null +++ b/code/modules/icon generation/Uristrunes.dm @@ -0,0 +1,268 @@ +//---------------------------------------- +// +// Take a source icon, convert into a mask, +// then create a border around it. +// +// The output then uses the colors and +// alpha values provided. +// +//---------------------------------------- + +/proc/create_border_image(icon/input, border_color = "#000000", fill_color = "#000000", border_alpha = 255, fill_alpha = 255) + var/icon/I = icon('uristrunes.dmi', "blank") + I.Blend(input, ICON_OVERLAY) + + //Discard the image + I.MapColors(0, 0, 0, 0, //-\ Ignore + 0, 0, 0, 0, //--> The + 0, 0, 0, 0, //-/ Colors + 0,255, 0, 1, //Keep alpha channel, any pixel with non-zero alpha gets max green channel + 0, 0, 0, 0) + + //Loop over the image, calculating the border value, and storing it in the red channel + //Store border's alpha in the blue channel + for(var/x = 1, x <= 32, x++) + for(var/y = 1, y <= 32, y++) + var/p = I.GetPixel(x, y) + + if(p == null) + var/n = I.GetPixel(x, y + 1) + var/s = I.GetPixel(x, y - 1) + var/e = I.GetPixel(x + 1, y) + var/w = I.GetPixel(x - 1, y) + var/ne = I.GetPixel(x + 1, y + 1) + var/se = I.GetPixel(x + 1, y - 1) + var/nw = I.GetPixel(x - 1, y + 1) + var/sw = I.GetPixel(x - 1, y - 1) + + var/sum_adj = ((n == "#00ff00"? 1 : 0) \ + + (s == "#00ff00"? 1 : 0) \ + + (e == "#00ff00"? 1 : 0) \ + + (w == "#00ff00"? 1 : 0)) + + var/sum_diag = ((ne == "#00ff00"? 1 : 0) \ + + (se == "#00ff00"? 1 : 0) \ + + (nw == "#00ff00"? 1 : 0) \ + + (sw == "#00ff00"? 1 : 0)) + + + if(sum_adj) + I.DrawBox(rgb(255, 0, 200, 0), x, y) + + else if(sum_diag) + I.DrawBox(rgb(255, 0, 100, 0), x, y) + + else + I.DrawBox(rgb(0, 0, 0, 0), x, y) + + else if(p != "#00ff00") + var/a = 255 + + if(length(p) == 9) // "#rrggbbaa", we want the aa + a = hex2num(copytext(p, 8)) + + I.DrawBox(rgb(255 - a, a, 255 - a, a), x, y) + + //Map the red and green channels to the desired output colors + I.MapColors(border_color, fill_color, rgb(0, 0, 0, border_alpha), rgb(0, 0, 0, fill_alpha), "#00000000") + + return I + + + + +//---------------------------------------- +// +// Take a source icon, convert into a mask, +// and border. Color them according to args, +// and animate. +// +//---------------------------------------- + +/proc/animate_rune_full(icon/input, rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, ar1, ag1, ab1, aa1, ar2, ag2, ab2, aa2, or1, og1, ob1, oa1, or2, og2, ob2, oa2, frames) + + var/list/colors[10] + colors[ 1] = list(rr1, rg1, rb1, ra1) //Rune color 1 + colors[ 2] = list(rr2, rg2, rb2, ra2) //Rune color 2 + colors[ 3] = list(br1, bg1, bb1, ba1) //Border color 1 + colors[ 4] = list(br2, bg2, bb2, ba2) //Border color 2 + colors[ 5] = list( 0, 0, 0, 0) //Unused + colors[ 6] = list( 0, 0, 0, 0) //Unused + colors[ 7] = list(ar1, ag1, ab1, aa1) //Alpha color 1 + colors[ 8] = list(ar2, ag2, ab2, aa2) //Alpha color 2 + colors[ 9] = list(or1, og1, ob1, oa1) //Added color 1 + colors[10] = list(or2, og2, ob2, oa2) //Added color 2 + + var/icon/base = create_border_image(input, "#00ff0000", "#ff000000") + + return generate_color_animation(base, colors, frames) + + + + +//---------------------------------------- +// +// Calls the above, but accepts colors in +// the form of "#RRGGBBAA", and provides +// default values. +// +// Main limit is that it doesn't accept +// negative values, which you probably +// don't need anyway. Also missing a few +// color inputs, which would also be rarely +// used. +// +//---------------------------------------- + + +/proc/animate_rune(icon/input, rune_color = "#00000000", border_color = "#c8000000", rune_color2 = "#00000000", border_color2 = "#d8380000", alpha = 255, alpha2 = 255, frames = rune_animation) + var/rr1 = hex2num(copytext(rune_color, 2, 4)) + var/rg1 = hex2num(copytext(rune_color, 4, 6)) + var/rb1 = hex2num(copytext(rune_color, 6, 8)) + var/ra1 = hex2num(copytext(rune_color, 8, 10)) + var/rr2 = hex2num(copytext(rune_color2, 2, 4)) + var/rg2 = hex2num(copytext(rune_color2, 4, 6)) + var/rb2 = hex2num(copytext(rune_color2, 6, 8)) + var/ra2 = hex2num(copytext(rune_color2, 8, 10)) + var/br1 = hex2num(copytext(border_color, 2, 4)) + var/bg1 = hex2num(copytext(border_color, 4, 6)) + var/bb1 = hex2num(copytext(border_color, 6, 8)) + var/ba1 = hex2num(copytext(border_color, 8, 10)) + var/br2 = hex2num(copytext(border_color2, 2, 4)) + var/bg2 = hex2num(copytext(border_color2, 4, 6)) + var/bb2 = hex2num(copytext(border_color2, 6, 8)) + var/ba2 = hex2num(copytext(border_color2, 8, 10)) + + return animate_rune_full(input, rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, 0, 0, 0, alpha, 0, 0, 0, alpha2, 0, 0, 0, 0, 0, 0, 0, 0, frames) + + +/proc/inanimate_rune(icon/input, rune_color = "#00000000", border_color = "#c8000000") + var/icon/base = create_border_image(input, "#00ff0000", "#ff000000") + + base.MapColors(rune_color, border_color, "#00000000", "#000000ff", "#00000000") + + return base + +var/list/rune_animation = list( + list(0.000, 5), + list(0.020, 1), + list(0.050, 1), + list(0.090, 1), + list(0.140, 1), + list(0.200, 1), + list(0.270, 1), + list(0.340, 1), + list(0.420, 1), + list(0.500, 1), + list(0.590, 1), + list(0.675, 1), + list(0.750, 1), + list(0.900, 1), + list(1.000, 6), + list(0.875, 1), + list(0.750, 1), + list(0.625, 1), + list(0.500, 1), + list(0.375, 1), + list(0.250, 1), + list(0.125, 1), + ) + +/var/list/rune_cache = list() + +/proc/get_rune(rune_bits, animated = 0) + var/lookup = "[rune_bits]-[animated]" + + if(lookup in rune_cache) + return rune_cache[lookup] + + var/icon/base = icon('uristrunes.dmi', "") + + for(var/i = 0, i < 10, i++) + if(rune_bits & (1 << i)) + base.Blend(icon('uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) + + var/icon/result + + if(animated == 1) + result = animate_rune(base) + + else + result = inanimate_rune(base) + + rune_cache[lookup] = result + return result + + + + + +// Testing procs and Fun procs + + + + +/mob/verb/create_rune() + var/obj/o = new(locate(x, y, z)) + o.icon = get_rune(rand(1, 1023), 1) + +/mob/verb/runes_15x15() + for(var/turf/t in range(7)) + var/obj/o = new /obj(t) + o.icon = get_rune(rand(1, 1023), 1) + + +/* +/mob/verb/create_rune_custom(rune as num, color1 as color, border1 as color, color2 as color, border2 as color, alpha1 as num, alpha2 as num) + var/icon/I = icon('uristrunes.dmi', "blank") + + for(var/i = 0, i < 10, i++) + if(rune & (1 << i)) + I.Blend(icon('uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) + + var/obj/o = new(locate(x, y, z)) + o.icon = animate_rune(I, color1, border1, color2, border2, alpha1, alpha2) + +/mob/verb/spam() + for(var/turf/t in range(4)) + var/icon/I = icon('uristrunes.dmi', "blank") + + var/rune = rand(1, 1023) + for(var/i = 0, i < 10, i++) + if(rune & (1 << i)) + I.Blend(icon('uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) + + var/obj/o = new(t) + o.icon = animate_rune_full(I, rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), + rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), + rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), + rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), + 0, 0, 0, rand(0, 255), + 0, 0, 0, rand(0, 255), + 0, 0, 0, 0, + 0, 0, 0, 0, + list( + list(0.000, 5), + list(0.020, 1), + list(0.050, 1), + list(0.090, 1), + list(0.140, 1), + list(0.200, 1), + list(0.270, 1), + list(0.340, 1), + list(0.420, 1), + list(0.500, 1), + list(0.590, 1), + list(0.675, 1), + list(0.750, 1), + list(0.900, 1), + list(1.000, 6), + list(0.875, 1), + list(0.750, 1), + list(0.625, 1), + list(0.500, 1), + list(0.375, 1), + list(0.250, 1), + list(0.125, 1), + )) +*/ \ No newline at end of file