mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 21:48:39 +01:00
Improved color matrix helpers
Better comments explaining the purpose of everything Better name scheme: color_matrix_foo() instead of just color_foo() Contrast was completely wrong. Total derpage, formula is now right A few examples of interesting and useful matrices. And by "a few" I mean 3, but whatever Addition and multiplication Single-axis rotations color_matrix2color_hex and color_hex2color_matrix in case anybody wants to convert back and forth for whatever reason All values within the matrix are rounded to the thousandths place to cut down on floating point error and 1.000000001 type values
This commit is contained in:
@@ -528,3 +528,8 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
#define MIN_NTNET_LOGS 10
|
||||
//TODO Move to a pref
|
||||
#define STATION_GOAL_BUDGET 1
|
||||
|
||||
//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
|
||||
#define LUMA_R 0.213
|
||||
#define LUMA_G 0.715
|
||||
#define LUMA_B 0.072
|
||||
+82
-77
@@ -63,91 +63,96 @@
|
||||
|
||||
// Color matrices:
|
||||
|
||||
//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
|
||||
#define LUMR 0.2126
|
||||
#define LUMG 0.7152
|
||||
#define LUMB 0.0722
|
||||
/* Documenting a couple of potentially useful color matrices here to inspire ideas
|
||||
// Greyscale - indentical to saturation @ 0
|
||||
list(LUMA_R,LUMA_R,LUMA_R,0, LUMA_G,LUMA_G,LUMA_G,0, LUMA_B,LUMA_B,LUMA_B,0, 0,0,0,1, 0,0,0,0)
|
||||
|
||||
//Still need color matrix addition, negation, and multiplication.
|
||||
// Color inversion
|
||||
list(-1,0,0,0, 0,-1,0,0, 0,0,-1,0, 0,0,0,1, 1,1,1,0)
|
||||
|
||||
//Returns an identity color matrix which does nothing
|
||||
/proc/color_identity()
|
||||
return list(1,0,0, 0,1,0, 0,0,1)
|
||||
// Sepiatone
|
||||
list(0.393,0.349,0.272,0, 0.769,0.686,0.534,0, 0.189,0.168,0.131,0, 0,0,0,1, 0,0,0,0)
|
||||
*/
|
||||
|
||||
//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting whites
|
||||
//TODO: Need a version that only affects one color (ie shift red to blue but leave greens and blues alone)
|
||||
/proc/color_rotation(angle)
|
||||
if(angle == 0)
|
||||
return color_identity()
|
||||
angle = Clamp(angle, -180, 180)
|
||||
var/cos = cos(angle)
|
||||
//Does nothing
|
||||
/proc/color_matrix_identity()
|
||||
return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0)
|
||||
|
||||
//Adds/subtracts overall lightness
|
||||
//0 is identity, 1 makes everything white, -1 makes everything black
|
||||
/proc/color_matrix_lightness(power)
|
||||
return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, power,power,power,0)
|
||||
|
||||
//Changes distance hues have from grey while maintaining the overall lightness. Greys are unaffected.
|
||||
//1 is identity, 0 is greyscale, >1 oversaturates colors
|
||||
/proc/color_matrix_saturation(value)
|
||||
var/inv = 1 - value
|
||||
var/R = round(LUMA_R * inv, 0.001)
|
||||
var/G = round(LUMA_G * inv, 0.001)
|
||||
var/B = round(LUMA_B * inv, 0.001)
|
||||
|
||||
return list(R + value,R,R,0, G,G + value,G,0, B,B,B + value,0, 0,0,0,1, 0,0,0,0)
|
||||
|
||||
//Changes distance colors have from rgb(127,127,127) grey
|
||||
//1 is identity. 0 makes everything grey >1 blows out colors and greys
|
||||
/proc/color_matrix_contrast(value)
|
||||
var/add = (1 - value) / 2
|
||||
return list(value,0,0,0, 0,value,0,0, 0,0,value,0, 0,0,0,1, add,add,add,0)
|
||||
|
||||
//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting greys
|
||||
//0 is identity, 120 moves reds to greens, 240 moves reds to blues
|
||||
/proc/color_matrix_rotate_hue(angle)
|
||||
var/sin = sin(angle)
|
||||
|
||||
var/constA = 0.143
|
||||
var/constB = 0.140
|
||||
var/constC = -0.283
|
||||
var/cos = cos(angle)
|
||||
var/cos_inv_third = 0.333*(1-cos)
|
||||
var/sqrt3_sin = sqrt(3)*sin
|
||||
return list(
|
||||
LUMR + cos * (1-LUMR) + sin * -LUMR, LUMR + cos * -LUMR + sin * constA, LUMR + cos * -LUMR + sin * -(1-LUMR),
|
||||
LUMG + cos * -LUMG + sin * -LUMG, LUMG + cos * (1-LUMG) + sin * constB, LUMG + cos * -LUMG + sin * LUMG,
|
||||
LUMB + cos * -LUMB + sin * (1-LUMB), LUMB + cos * -LUMB + sin * constC, LUMB + cos * (1-LUMB) + sin * LUMB
|
||||
)
|
||||
round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), 0,
|
||||
round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), 0,
|
||||
round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), 0,
|
||||
0,0,0,1,
|
||||
0,0,0,0)
|
||||
|
||||
//Makes everything brighter or darker without regard to existing color or brightness
|
||||
/proc/color_brightness(power)
|
||||
power = Clamp(power, -255, 255)
|
||||
power = power/255
|
||||
//These next three rotate values about one axis only
|
||||
//x is the red axis, y is the green axis, z is the blue axis.
|
||||
/proc/color_matrix_rotate_x(angle)
|
||||
var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
|
||||
return list(1,0,0,0, 0,cosval,sinval,0, 0,-sinval,cosval,0, 0,0,0,1, 0,0,0,0)
|
||||
|
||||
return list(1,0,0, 0,1,0, 0,0,1, power,power,power)
|
||||
/proc/color_matrix_rotate_y(angle)
|
||||
var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
|
||||
return list(cosval,0,-sinval,0, 0,1,0,0, sinval,0,cosval,0, 0,0,0,1, 0,0,0,0)
|
||||
|
||||
/var/list/delta_index = list(
|
||||
0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
|
||||
0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
|
||||
0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
|
||||
0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
|
||||
0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
|
||||
1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
|
||||
1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
|
||||
2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
|
||||
4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
|
||||
7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
|
||||
10.0)
|
||||
/proc/color_matrix_rotate_z(angle)
|
||||
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)
|
||||
|
||||
//Exxagerates or removes brightness
|
||||
/proc/color_contrast(value)
|
||||
value = Clamp(value, -100, 100)
|
||||
if(value == 0)
|
||||
return color_identity()
|
||||
|
||||
var/x = 0
|
||||
if (value < 0)
|
||||
x = 127 + value / 100 * 127;
|
||||
else
|
||||
x = value % 1
|
||||
if(x == 0)
|
||||
x = delta_index[value]
|
||||
else
|
||||
x = delta_index[value] * (1-x) + delta_index[value+1] * x//use linear interpolation for more granularity.
|
||||
x = x * 127 + 127
|
||||
//Returns a matrix addition of A with B
|
||||
/proc/color_matrix_add(list/A, list/B)
|
||||
if(!istype(A) || !istype(B))
|
||||
return color_matrix_identity()
|
||||
if(A.len != 20 || B.len != 20)
|
||||
return color_matrix_identity()
|
||||
var/list/output = list()
|
||||
output.len = 20
|
||||
for(var/value in 1 to 20)
|
||||
output[value] = A[value] + B[value]
|
||||
return output
|
||||
|
||||
var/mult = x / 127
|
||||
var/add = 0.5 * (127-x) / 255
|
||||
return list(mult,0,0, 0,mult,0, 0,0,mult, add,add,add)
|
||||
|
||||
//Exxagerates or removes colors
|
||||
/proc/color_saturation(value as num)
|
||||
if(value == 0)
|
||||
return color_identity()
|
||||
value = Clamp(value, -100, 100)
|
||||
if(value > 0)
|
||||
value *= 3
|
||||
var/x = 1 + value / 100
|
||||
var/inv = 1 - x
|
||||
var/R = LUMR * inv
|
||||
var/G = LUMG * inv
|
||||
var/B = LUMB * inv
|
||||
|
||||
return list(R + x,R,R, G,G + x,G, B,B,B + x)
|
||||
|
||||
#undef LUMR
|
||||
#undef LUMG
|
||||
#undef LUMB
|
||||
//Returns a matrix multiplication of A with B
|
||||
/proc/color_matrix_multiply(list/A, list/B)
|
||||
if(!istype(A) || !istype(B))
|
||||
return color_matrix_identity()
|
||||
if(A.len != 20 || B.len != 20)
|
||||
return color_matrix_identity()
|
||||
var/list/output = list()
|
||||
output.len = 20
|
||||
var/x = 1
|
||||
var/y = 1
|
||||
var/offset = 0
|
||||
for(y in 1 to 5)
|
||||
offset = (y-1)*4
|
||||
for(x in 1 to 4)
|
||||
output[offset+x] = round(A[offset+1]*B[x] + A[offset+2]*B[x+4] + A[offset+3]*B[x+8] + A[offset+4]*B[x+12]+(y==5?B[x+16]:0), 0.001)
|
||||
return output
|
||||
@@ -572,4 +572,25 @@ for(var/t in test_times)
|
||||
var/R = hex2num(copytext(A,2,4))
|
||||
var/G = hex2num(copytext(A,4,6))
|
||||
var/B = hex2num(copytext(A,6,0))
|
||||
return R+G+B
|
||||
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)
|
||||
if(length != 7 && length != 9)
|
||||
return color_matrix_identity()
|
||||
var/r = hex2num(copytext(string, 2, 4))/255
|
||||
var/g = hex2num(copytext(string, 4, 6))/255
|
||||
var/b = hex2num(copytext(string, 6, 8))/255
|
||||
var/a = 1
|
||||
if(length == 9)
|
||||
a = hex2num(copytext(string, 8, 10))/255
|
||||
if(!isnum(r) || !isnum(g) || !isnum(b) || !isnum(a))
|
||||
return color_matrix_identity()
|
||||
return list(r,0,0,0, 0,g,0,0, 0,0,b,0, 0,0,0,a, 0,0,0,0)
|
||||
|
||||
//will drop all values not on the diagonal
|
||||
/proc/color_matrix2color_hex(list/the_matrix)
|
||||
if(!istype(the_matrix) || the_matrix.len != 20)
|
||||
return "#ffffffff"
|
||||
return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255)
|
||||
Reference in New Issue
Block a user