Code for finding the colors of C# types, translated from the Resonite source code.
Function | Purpose | Example |
---|---|---|
get_impulse_color_css |
Gets the color of an impulse | {{#invoke:ProtoFlux_Type_Color|get_impulse_color_css|Continuation}}
|
get_type_color_css |
Gets the color of a data type | {{#invoke:ProtoFlux_Type_Color|get_type_color_css|User}}
|
get_color_css |
First attempts to interpret the type as an impulse | {{#invoke:ProtoFlux_Type_Color|get_color_css|int}}
|
The following functions are exported, but not invokable by Media Wiki.
Function | Purpose | Example |
---|---|---|
get_impulse_color |
Gets the color of an impulse | get_impulse_color("Continuation")
|
get_type_color |
Gets the color of a data type | get_type_color("User")
|
color_from_crc |
Derives a color from the given CRC32 checksum | color_from_crc(0x9CD97842)
|
How exactly these invokations may be used can be seen by inspecting the source of this wiki and related templates.
Examples
Continuation
Call
AsyncCall
SyncResumption
AsyncResumption
Types
Values and String
Signed |
|
Unsigned |
|
Decimal |
|
String |
|
Non-Values
A |
|
B |
|
C |
|
D |
|
E |
|
F |
|
G |
|
H |
|
I |
|
J |
|
K | |
L |
|
M | |
N |
|
O |
|
P |
|
Q | |
R |
|
S |
|
T |
|
U |
|
V | |
W |
|
XYZ |
-- Code for finding the colors of C# types, translated from the Resonite source code
-- Source: FrooxEngine.ProtoFlux.DatatypeColorHelper (decompiled with ILSpy)
-- Binary found at Resonite_Data/Managed/FrooxEngine.dll
local p = {}
local checksum = require("Module:CRC_32_ISO_HDLC")
local bit32 = require("bit32")
local colors = {
CONTINUATION = {r=1, g=1, b=0.7},
SYNC_FLOW = {r=0.7, g=1, b=1},
ASYNC_FLOW = {r=0.8, g=0.7, b=1},
SYNC_RESUMPTION = {r=0.7, g=0.7, b=1},
ASYNC_RESUMPTION = {r=1, g=0.7, b=0.7},
INPUT_LABEL = {r=0.8, g=0.9, b=1},
OUTPUT_LABEL = {r=0.9, g=0.8, b=1},
COLOR_BASE = {r=1, g=1, b=0},
COLORX_BASE = {r=1, g=0.5, b=0},
SIGNED_INT_BASE = {r=0, g=1, b=0},
UNSIGNED_INT_BASE = {r=0, g=1, b=0.5},
FLOAT_BASE = {r=0, g=1, b=1},
QUATERNION_BASE = {r=0, g=0.5, b=1},
DECIMAL_BASE = {r=0, g=0, b=1},
BOOL_BASE = {r=0.3, g=0.3, b=0.3},
CHAR_BASE = {r=0.6392157, g=37/85, b=7/85},
STRING_BASE = {r=0.6392157, g=7/85, b=7/85},
SLOT_BASE = {r=0.75, g=1, b=0.5},
USER_BASE = {r=1, g=0.5, b=1},
DUMMY = {r=1, g=0, b=1},
}
local primitive_class = {
bool="boolean",
char="char",
String="string",
byte="unsigned_integer",
ushort="unsigned_integer",
uint="unsigned_integer",
ulong="unsigned_integer",
sbyte="signed_integer",
short="signed_integer",
int="signed_integer",
long="signed_integer",
float="floating_point",
double="floating_point",
decimal="floating_point",
}
local primitive_class_rank = {
byte=0,
sbyte=0,
float=0,
ushort=1,
short=1,
double=1,
uint=2,
int=2,
ulong=3,
long=3,
}
local max_primitive_class_rank = {
boolean=0,
string=0,
char=0,
floating_point=1,
signed_integer=3,
unsigned_integer=3,
}
local primitive_class_base_color = {
signed_integer=colors.SIGNED_INT_BASE,
unsigned_integer=colors.UNSIGNED_INT_BASE,
floating_point=colors.FLOAT_BASE,
}
function p.get_impulse_color(type_str)
if type_str == "Continuation" then return colors.CONTINUATION
elseif type_str == "Call" then return colors.SYNC_FLOW
elseif type_str == "AsyncCall" then return colors.ASYNC_FLOW
elseif type_str == "SyncResumption" then return colors.SYNC_RESUMPTION
elseif type_str == "AsyncResumption" then return colors.ASYNC_RESUMPTION
end
end
function p.get_type_color(type_str, rec_limit)
if rec_limit == 0 then error("Recursion limit reached")
elseif rec_limit == nil then rec_limit = 4
end
local btype = get_base_type(type_str)
if btype == "bool" then return colors.BOOL_BASE
elseif btype == "char" then return colors.CHAR_BASE
elseif btype == "String" then return colors.STRING_BASE
elseif btype == "Dummy" then return colors.DUMMY
elseif btype == "color" then return colors.COLOR_BASE
elseif btype == "colorX" then return colors.COLORX_BASE
elseif btype == "decimal" then return colors.DECIMAL_BASE
elseif btype == "Slot" then return colors.SLOT_BASE
elseif btype == "User" then return colors.USER_BASE
elseif p.get_impulse_color(btype) then return p.get_impulse_color(btype)
end
local prim_cls = primitive_class[btype]
if prim_cls ~= nil then
local rank = primitive_class_rank[btype]
local max_rank = max_primitive_class_rank[prim_cls]
local rank_lerp = inverse_lerp(0, max_rank, rank)
local base_color = primitive_class_base_color[prim_cls]
if base_color == nul then error("Invalid primitive class: "..prim_cls) end
return lerp_primitive_color(base_color, rank_lerp)
end
-- Vector or Matrix (eg. float3, float3x3)
if btype:match("^%a+%d$") ~= nil or btype:match("^%a+%dx%d$") ~= nil then
local vec_btype = btype:match("^%a+")
if primitive_class[vec_btype] ~= nil then
return p.get_type_color(vec_btype, rec_limit - 1)
end
end
-- Quaternion
if btype:match("^%a+Q$") ~= nil then
local q_btype = btype:sub(1,-2)
local rank = nil
if q_btype == "float" then rank = 0
elseif q_btype == "double" then rank = 1
end
if rank ~= nil then
return lerp_primitive_color(colors.QUATERNION_BASE, rank)
end
end
-- Nullable
if btype == "Nullable" then
local i = string.find(type_str, "<", 0, true)
local last = type_str:sub(-1)
if i == nil or last ~= ">" then error("Invalid Nullable") end
local color = p.get_type_color(type_str:sub(i + 1, -2), rec_limit - 1)
color.a = (color.a or 1) * 0.5
return color
end
return p.color_from_crc(checksum.crc32(btype))
end
function p.color_from_crc(value)
local h = bit32.band(value, 0xff) / 255
local lerp_s = bit32.band(bit32.rshift(value, 8), 0xff) / 255
local lerp_v = bit32.band(bit32.rshift(value, 16), 0xff) / 255
local s = lerp_unclamped(0.25, 0.75, lerp_s)
local v = lerp_unclamped(0.25, 1.00, lerp_v)
return hsv_to_rgb(h, s, v)
end
function p.get_impulse_color_css(frame)
local color = p.get_impulse_color(frame.args[1])
return color and color_to_css(color)
end
function p.get_type_color_css(frame)
local color = p.get_type_color(frame.args[1])
return color_to_css(color, 1.5)
end
function p.get_color_css(frame)
local text = frame.args[1]
local factor = 1
local color = p.get_impulse_color(text)
if color == nil then
factor, color = 1.5, p.get_type_color(text)
end
return color_to_css(color, factor)
end
function color_to_css(color, factor)
local mult = 255 * (factor or 1)
return ("rgba(%s,%s,%s,%s)"):format(color.r*mult, color.g*mult, color.b*mult, color.a or 1)
end
function get_base_type(type_str)
local i = type_str:find("<", 0, true)
if i == nil then
return type_str
else
return type_str:sub(1, i - 1)
end
end
function lerp_primitive_color(base, rank)
return lerp_color({r=0,g=0,b=0}, base, 0.75 + rank * 0.25)
end
function lerp_color(a, b, lerp)
if lerp <= 0 then return a end
if lerp >= 1 then return b end
return lerp_unclamped_color(a, b, lerp)
end
function inverse_lerp(a, b, lerp)
return (lerp - a) / (b - a)
end
function lerp_unclamped(a, b, lerp)
return a + (b - a) * lerp
end
function lerp_unclamped_color(a, b, lerp)
local prel = 1 - lerp
local alpha = 1
if a.a ~= nil and b.a ~= nil then
alpha = a.a * prel + b.a * lerp
end
return {
r=a.r * prel + b.r * lerp,
g=a.g * prel + b.g * lerp,
b=a.b * prel + b.b * lerp,
a=alpha,
}
end
function num_repeat(v, length)
return v - math.floor(v / length) * length
end
function hsv_to_rgb(h, s, v)
local gain = math.max(v, 1)
v = v / gain
local vs = v * s
local f = vs * (1 - math.abs(num_repeat(h * 6, 2) - 1))
local light = v - vs
local r,g,b = 0,0,0
local switch_on = math.floor(num_repeat(h, 1) / (1/6))
if switch_on == 0 then r,g,b = vs,f,0
elseif switch_on == 1 then r,g,b = f,vs,0
elseif switch_on == 2 then r,g,b = 0,vs,f
elseif switch_on == 3 then r,g,b = 0,f,vs
elseif switch_on == 4 then r,g,b = f,0,vs
elseif switch_on == 5 then r,g,b = vs,0,f
end
return {
r=(r+light)*gain,
g=(g+light)*gain,
b=(b+light)*gain
}
end
return p