From 2366c40049d49fc648b10e1d707076ed4e49c663 Mon Sep 17 00:00:00 2001 From: livie Date: Mon, 26 Jan 2026 19:37:46 +0200 Subject: [PATCH] minimal panel 0.1 --- minimal_panel.lsl | 455 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 455 insertions(+) create mode 100644 minimal_panel.lsl diff --git a/minimal_panel.lsl b/minimal_panel.lsl new file mode 100644 index 0000000..57a6749 --- /dev/null +++ b/minimal_panel.lsl @@ -0,0 +1,455 @@ +// based loosely on icon-mono.lsl + +//-------------------------------------------------------------------------- +// BEGIN config + +// use flags +//#define USE_BOLTS +#define USE_VERBOSE + +// metadata +#define PANEL_VERSION "0.1" +#define PANEL_DEVICE_NAME "connectors" + +// gauge +#define GAUGE_CUT_START 0 +#define GAUGE_CUT_END 1 +#define GAUGE_SRC "power" +#define GAUGE_MIN 0 +#define GAUGE_MAX 1 +#define GAUGE_DANGER 0.2 + +// lights +#define MAX_GLOW 0.3 +#define FULLBRIGHT_ON_GLOW +#define OFF_DAMP_FACTOR 0.4 + +// END config +//-------------------------------------------------------------------------- +// BEGIN macros + +#define color_parse(_argv) <(float)gets(_argv, 1), (float)gets(argv, 2), (float)gets(argv, 3)> +#define add_device(_id, _ch) tell(_id, _ch, "add " + PANEL_DEVICE_NAME) +#define try_add_port(_id, _ch, _port, _link) if (_link != LINK_THIS) tell(_id, _ch, "port " + _port + " " + (string)llGetLinkKey(_link)) + +#define GAUGE_SRC_Q GAUGE_SRC + "-q" + +// END macros +//-------------------------------------------------------------------------- +// BEGIN includes + +#include +#include + +// END includes +//-------------------------------------------------------------------------- +// BEGIN globals + +integer LN_GAUGE = LINK_THIS; +integer LN_POWER_BUTTON = LINK_THIS; +integer LN_PLUG_POWER = LINK_THIS; +integer LN_PLUG_DATA1 = LINK_THIS; +integer LN_PLUG_DATA2 = LINK_THIS; +integer LN_PLUG_AUDIO1 = LINK_THIS; +integer LN_PLUG_AUDIO2 = LINK_THIS; + +integer L_CAPS = 0; +integer L_LIGHTS = 0; + +#define C_CAPS 411 +integer C_LIGHTS = 0; + +integer power_on = 1; +integer broken = 0; +integer charging = 0; +float gap = 0; + +vector color = <1, 1, 1>; +vector color2 = <1, 1, 1>; +vector color3 = <1, 1, 1>; +vector color4 = <1, 1, 1>; + +float gauge_value = GAUGE_MIN; + +key avatar = NULL_KEY; +key controller = NULL_KEY; + +// END globals +//-------------------------------------------------------------------------- +// BEGIN functions + +integer get_prim_count() { + if (llGetAttached()) { + return llGetNumberOfPrims(); + } + + return llGetObjectPrimCount(llGetKey()); +} // get_prim_count() + +populate_link_nums() { + integer i = get_prim_count(); + string link_name; + for (; i > 0; i--) { + link_name = llGetLinkName(i); + switch (link_name) { + case "gauge": + LN_GAUGE = i; + break; + case "powerbutton": + LN_POWER_BUTTON = i; + break; + case "port-power": + LN_PLUG_POWER = i; + break; + case "port-data-1": + LN_PLUG_DATA1 = i; + break; + case "port-data-2": + LN_PLUG_DATA2 = i; + break; + case "port-audio-in": + LN_PLUG_AUDIO1 = i; + break; + case "port-audio-out": + LN_PLUG_AUDIO2 = i; + break; + default: + break; + } // switch (link_name) + } // for (...) +} // populate_link_nums() + +init() { + avatar = llGetOwner(); + + populate_link_nums(); + + C_LIGHTS = 105 - (integer)("0x" + substr(avatar, 29, 35)); + llListenRemove(L_LIGHTS); + L_LIGHTS = llListen(C_LIGHTS, "", NULL_KEY, ""); + + llListenRemove(L_CAPS); + L_CAPS = llListen(C_CAPS, "", NULL_KEY, ""); + + power_on = 1; + + add_device(avatar, C_LIGHTS); +} // init() + +set_tint(integer link, integer side, vector tint) { + llSetLinkColor(link, tint, side); + + llSetLinkGLTFOverrides(link, side, [ + OVERRIDE_GLTF_BASE_COLOR_FACTOR, llsRGB2Linear(tint), + OVERRIDE_GLTF_EMISSIVE_FACTOR, llsRGB2Linear(tint) + ]); +} // set_tint(link, side, tint) + +set_alpha(integer link, integer side, float alpha) { + llSetLinkAlpha(link, alpha, side); + + integer alpha_mode = PRIM_GLTF_ALPHA_MODE_BLEND; + if (alpha == 1 || alpha == 0) { + alpha_mode = PRIM_GLTF_ALPHA_MODE_MASK; + } + + llSetLinkGLTFOverrides(link, side, [ + OVERRIDE_GLTF_BASE_ALPHA_MODE, alpha_mode, + OVERRIDE_GLTF_BASE_ALPHA_MASK, 0.5, + OVERRIDE_GLTF_BASE_ALPHA, alpha + ]); +} // set_alpha(link, side, alpha) + +set_glow(integer link, integer side, float glow) { +#ifdef FULLBRIGHT_ON_GLOW + integer fullbright = 0; + if (glow > 0) { + fullbright = 1; + } +#endif + + setp(link, [ + PRIM_GLOW, side, glow +#ifdef FULLBRIGHT_ON_GLOW + , + PRIM_FULLBRIGHT, side, fullbright +#endif + ]); +} // set_glow(link, side, glow) + +// level clamped to [0, 1] +update_colors(float level) { + if (level < 0) { + level = 0; + } else if (level > 1) { + level = 1; + } + + if (!power_on) { + set_tint(LN_POWER_BUTTON, ALL_SIDES, color * OFF_DAMP_FACTOR); + set_glow(LN_POWER_BUTTON, ALL_SIDES, 0); + + set_tint(LN_GAUGE, ALL_SIDES, color * OFF_DAMP_FACTOR); + set_glow(LN_GAUGE, ALL_SIDES, 0); + + return; + } + + set_tint(LN_POWER_BUTTON, ALL_SIDES, color * level); + set_glow(LN_POWER_BUTTON, ALL_SIDES, MAX_GLOW * level); + + if (charging) { + set_tint(LN_GAUGE, ALL_SIDES, color2 * level); + } else if (gauge_value < GAUGE_DANGER) { + set_tint(LN_GAUGE, ALL_SIDES, color3 * level); + } else { + set_tint(LN_GAUGE, ALL_SIDES, color * level); + } + + set_glow(LN_GAUGE, ALL_SIDES, MAX_GLOW * level); +} // update_colors(level) + +update_gauge() { + if (LN_GAUGE == LINK_THIS) { + return; + } + + float interval = GAUGE_CUT_END - GAUGE_CUT_START; + float gauge_pct = gauge_value / (GAUGE_MAX - GAUGE_MIN); + float gauge_extent = gauge_pct * interval; + float gauge_end = interval * gauge_extent; + + // clamp 100% just in case of rounding errors + if (gauge_end > 1.0) { + gauge_end = 1.0; + } + + // minimum slice step + if (gauge_end < 0.05) { + gauge_end = 0.05; + } + + // NEED MANUAL EDITING FOR DIFFERENT SHAPES >~> + setp(LN_GAUGE, [ + PRIM_TYPE, + PRIM_TYPE_TUBE, + PRIM_HOLE_DEFAULT, // hole_shape + , // cut + 0.0, // hollow + <0, 0, 0>, // twist + <1.0, 0.1, 0>, // hole_size + <0, 0, 0>, // top_shear + <0, 1, 0>, // advanced_cut + <0, 0, 0>, // taper + 1, // revolutions + 0, // radius_offset + 0 // skew + ]); + +} // update_gauge() + +update_port(string port_type, key src_id, integer connected) { + integer port_link = 0; + + switch (port_type) { + case "power": + port_link = LN_PLUG_POWER; + break; + case "audio-in": + port_link = LN_PLUG_AUDIO1; + break; + case "audio-out": + port_link = LN_PLUG_AUDIO2; + break; + case "data-1": + port_link = LN_PLUG_DATA1; + break; + case "data-2": + port_link = LN_PLUG_DATA2; + break; + default: +#ifdef USE_VERBOSE + echo("Unknown port: " + port_type); +#endif + break; + } // switch (port_type) + + if (connected) { + tell(src_id, C_LIGHTS, "port-real " + port_type + " " + (string)llGetLinkKey(port_link)); + } + + set_alpha(port_link, ALL_SIDES, (float)connected); +} // update_port(port_type, src_id, connected) + +// END functions +//-------------------------------------------------------------------------- +// BEGIN main + +default { + state_entry() { + init(); + } // state_entry() + + on_rez(integer n) { + init(); + } // on_rez(...) + + touch_end(integer n) { + while (n--) { + key user = llDetectedKey(n); + integer touched_link = llDetectedLinkNumber(n); + + if (touched_link == LN_POWER_BUTTON) { + if(power_on) { + tell(controller, C_LIGHTS, "command " + (string)user + " " + (string)user + " power off"); + llTriggerSound("88af7a41-10e7-06ad-799e-313cbbe0ffad", 1); + } else { + tell(controller, C_LIGHTS, "command " + (string)user + " " + (string)user + " power on"); + llTriggerSound("dccca2d0-b50c-e069-a1f9-c3336249421d", 1); + } + } + } + } // touch_end(...) + + listen(integer cc, string src, key id, string msg) { + if (cc == C_CAPS) { + if (substr(msg, 0, 4) == "info ") { + integer rc = (integer)delstring(msg, 0, 4); + tell(id, rc, "hwc " + jsobject([ + "vendor", "Cat Conspiracy", + "version", PANEL_VERSION, + "purpose", "info", + "channel", jsobject(["caps", C_CAPS, "lights", C_LIGHTS]), + "private", 0, + "busy", 0, + "usable", power_on, + "health", 1.0, + "info", "http://localhost:8080/" + ])); + } // if (cmd == "info") + } // if (cc == C_CAPS) + else if (cc == C_LIGHTS) { + list argv = split(msg, " "); + string cmd = gets(argv, 0); + + switch (cmd) { + case "off": + power_on = 0; + gap = 0; + update_colors(1); + break; + case "on": + power_on = 1; + if (broken) { + gap = 0.05; + } else { + gap = 0; + } + update_colors(1); + break; +#ifdef USE_BOLTS + case "bolts": + if (gets(argv, 1) == "on") { + echo("@detach=n"); + } else if (gets(argv, 1) == "off") { + echo("@detach=y"); + } + break; +#endif + case "broken": + gap = 0.05; + broken = 1; + break; + case "fixed": + broken = 0; + update_colors(1); + break; + case "color": + color = color_parse(argv); + update_colors(1); + break; + case "color-2": + color2 = color_parse(argv); + update_colors(1); + break; + case "color-3": + color3 = color_parse(argv); + update_colors(1); + break; + case "color-4": + color4 = color_parse(argv); + update_colors(1); + break; + case "name": + llSetObjectName(concat(delrange(argv, 0, 0), " ") + " (" + PANEL_DEVICE_NAME + ")"); + break; + case "probe": + add_device(id, C_LIGHTS); + break; + case "add-confirm": + controller = id; + + // Queries + tell(id, C_LIGHTS, "color-q"); + tell(id, C_LIGHTS, "power-q"); + tell(id, C_LIGHTS, GAUGE_SRC_Q); + + // Ports + /*try_add_port(id, C_LIGHTS, "power", LN_PLUG_POWER); + try_add_port(id, C_LIGHTS, "audio-in", LN_PLUG_AUDIO1); + try_add_port(id, C_LIGHTS, "audio-out", LN_PLUG_AUDIO2); + try_add_port(id, C_LIGHTS, "data-1", LN_PLUG_DATA1); + try_add_port(id, C_LIGHTS, "data-2", LN_PLUG_DATA2);*/ + tell(id, C_LIGHTS, "port power " + (string)llGetKey()); + tell(id, C_LIGHTS, "port audio-in " + (string)llGetKey()); + tell(id, C_LIGHTS, "port audio-out " + (string)llGetKey()); + tell(id, C_LIGHTS, "port data-1 " + (string)llGetKey()); + tell(id, C_LIGHTS, "port data-2 " + (string)llGetKey()); + + break; + case GAUGE_SRC: + gauge_value = (float)gets(argv, 1); + update_gauge(); + update_colors(1); + break; + case "charge": + if (gets(argv, 1) == "start") { + charging = 1; + } else if (gets(argv, 1) == "stop") { + charging = 0; + } + update_colors(1); + break; + case "port-connect": + update_port(gets(argv, 1), id, 1); + break; + case "port-disconnect": + update_port(gets(argv, 1), id, 0); + break; + default: +#ifdef USE_VERBOSE + echo("Unhandled light bus (" + src + "): " + msg); +#endif + break; + } // switch (cmd) + + llSetTimerEvent(gap); + } // if (cc == C_LIGHTS) + } // listen(...) + + timer() { + if (!broken) { + return; + } + + float t = 1; + if (llFrand(1.0) < 0.1) { + t = llFrand(0.2); + } + + update_colors(t); + } // timer() +} // state default + +// END main +//--------------------------------------------------------------------------