NoSloppy

Untitled

Mar 31st, 2023
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 314.08 KB | None | 0 0
  1. <!DOCTYPE html>
  2.  
  3. <html lang="en">
  4. <style>
  5. * {
  6. -webkit-user-select: none;
  7. -moz-user-select: none;
  8. -ms-user-select: none;
  9. user-select: none;
  10. }
  11. * {
  12. box-sizing: border-box;
  13. }
  14. button, input[type="button"], #expand_button, #layerize_button {
  15. background-color: #ECECEC;
  16. color: black;
  17. border-radius: 2px;
  18. padding: 3px;
  19. font-size: 14px;
  20. border: 1px solid black;
  21. font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
  22. font-weight: normal;
  23. }
  24. button:hover, input[type="button"]:hover, #expand_button:hover, #layerize_button:hover {
  25. background-color: #B7B7B7;
  26. }
  27. button:active, input[type="button"]:active, #expand_button:active, #layerize_button:active {
  28. background-color: dodgerblue;
  29. }
  30. #expand_button.button_on,
  31. #layerize_button.button_on {
  32. background: lightblue;
  33. color: black;
  34. }
  35. #expand_button.button_off,
  36. #layerize_button.button_off {
  37. background: lightgray;
  38. color: darkgray;
  39. }
  40. td {
  41. vertical-align: top;
  42. width: 50%;
  43. }
  44. .canvas-style {
  45. width: 256px;
  46. height: 256px;
  47. }
  48. #SETTINGS_BUTTON {
  49. background: Green;
  50. color: white;
  51. width: 81px;
  52. margin-left: 25px;
  53. border-radius: 10%;
  54. border: 3px solid dodgerblue;
  55. position: relative;
  56. }
  57. #settings-panel {
  58. position: absolute;
  59. width: 220px;
  60. border: 3px solid dodgerblue;
  61. background: darkgrey;
  62. padding: 7px;
  63. padding-left: 14px;
  64. border-radius: 9px;
  65. box-shadow: 6px 10px 10px rgba(0, 0, 0, 0.9);
  66. opacity: 0;
  67. pointer-events: none;
  68. transition: opacity 0.25s ease-in-out;
  69. }
  70. #settings-panel.show {
  71. opacity: 1;
  72. pointer-events: auto;
  73. }
  74. #settings-panel::after {
  75. content: " ";
  76. position: absolute;
  77. top: 31%;
  78. right: 98%;
  79. margin-top: -11px;
  80. border-width: 18px;
  81. border-style: solid;
  82. border-color: transparent darkgrey transparent transparent;
  83. }
  84. #structured-view {
  85. vertical-align: top;
  86. width: 100%;
  87. height: 99vh;
  88. overflow-y: scroll;
  89. }
  90. div.MAGIC_CLASS_FUNCTION input[type=button].btn {
  91. background: green;
  92. color: black;
  93. padding: 2px 3px;
  94. }
  95. div.MAGIC_CLASS_COLOR input[type=button].btn {
  96. background: green;
  97. color: black;
  98. padding: 2px 3px;
  99. }
  100. div.MAGIC_CLASS_TRANSITION input[type=button].btn {
  101. background: green;
  102. color: black;
  103. padding: 2px 3px;
  104. }
  105. div.MAGIC_CLASS_INT input[type=button].btn {
  106. background: green;
  107. color: black;
  108. padding: 2px 3px;
  109. }
  110. div.MAGIC_CLASS_EFFECT input[type=button].btn {
  111. background: green;
  112. color: black;
  113. padding: 2px 3px;
  114. }
  115. div.MAGIC_INVISIBLE_CLASS_EFFECT {
  116. display: inline;
  117. }
  118. div.MAGIC_INVISIBLE_CLASS_TRANSITION {
  119. display: inline;
  120. }
  121. div.MAGIC_INVISIBLE_CLASS_FUNCTION {
  122. display: inline;
  123. }
  124. span.MAGIC_CLASS_FUNCTION input[type=button].btn {
  125. background: green;
  126. color: black;
  127. padding: 2px 3px;
  128. }
  129. span.MAGIC_CLASS_COLOR input[type=button].btn {
  130. background: green;
  131. color: black;
  132. padding: 2px 3px;
  133. }
  134. span.MAGIC_CLASS_TRANSITION input[type=button].btn {
  135. background: green;
  136. color: black;
  137. padding: 2px 3px;
  138. }
  139. span.MAGIC_CLASS_INT input[type=button].btn {
  140. background: green;
  141. color: black;
  142. padding: 2px 3px;
  143. }
  144. span.MAGIC_CLASS_EFFECT input[type=button].btn {
  145. background: green;
  146. color: black;
  147. padding: 2px 3px;
  148. }
  149. /* Style the tab */
  150. .tab {
  151. overflow: hidden;
  152. border: 1px solid #ccc;
  153. background-color: #f1f1f1;
  154. }
  155. /* Style the buttons that are used to open the tab content */
  156. .tab button {
  157. background-color: inherit;
  158. float: left;
  159. border: none;
  160. outline: none;
  161. cursor: pointer;
  162. padding: 7px 8px;
  163. transition: 0.3s;
  164. }
  165. /* Change background color of buttons on hover */
  166. .tab button:hover {
  167. background-color: #ddd;
  168. }
  169. /* Create an active/current tablink class */
  170. .tab button.active {
  171. background-color: #ccc;
  172. }
  173. /* Style the tab content */
  174. .tabcontent {
  175. display: none;
  176. padding: 6px 12px;
  177. border: 1px solid #ccc;
  178. border-top: none;
  179. }
  180. .variant-container, .alt-container {
  181. background: LightCyan;
  182. border: 1px solid black;
  183. font-size: 15px;
  184. padding: 2px;
  185. display: inline-block;
  186. color: black;
  187. }
  188. .variant-label, .alt-label {
  189. margin-right: 5px;
  190. }
  191. .variant-controls, .alt-controls {
  192. display: inline-flex;
  193. align-items: center;
  194. }
  195. .variant-slider {
  196. width: 100px;
  197. margin: 0 5px;
  198. }
  199. /* Slider */
  200. input[type=range] {
  201. -webkit-appearance: none;
  202. width: 65px;
  203. height: 10px;
  204. margin-top: 5px;
  205. cursor: pointer;
  206. }
  207. .variant-slider::-webkit-slider-thumb {
  208. -webkit-appearance: none;
  209. background-color: DodgerBlue;
  210. width: 14px;
  211. height: 14px;
  212. border-radius: 20%;
  213. border: none;
  214. }
  215. #error_message {
  216. color: red;
  217. font-weight: bold;
  218. }
  219. /* Fat font in Structured View */
  220. #pp span {
  221. padding-left: 6px;
  222. font-weight: 600;
  223. font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
  224. }
  225. .dark-mode {
  226. background-color: #202020;
  227. color: white !important;
  228. }
  229. /* Blade Style text box background */
  230. #style {
  231. background-color: #d0d0d0;
  232. color: #202020;
  233. font-weight: 600;
  234. }
  235. /* Tooltip container */
  236. .tooltip {
  237. position: relative;
  238. display: inline-block;
  239. }
  240. /* Tooltip text */
  241. .tooltiptext-textarea,
  242. .tooltiptext-submit,
  243. .tooltiptext-copy,
  244. .tooltiptext-expand,
  245. .tooltiptext-layerize,
  246. .tooltiptext-argify,
  247. .tooltiptext-rotate,
  248. .tooltiptext-inhilt,
  249. .tooltiptext-slow,
  250. .tooltiptext-settings,
  251. .tooltiptext-still,
  252. .tooltiptext-dark,
  253. .tooltiptext-tips {
  254. visibility: hidden;
  255. width: 180px;
  256. bottom: 100%;
  257. left: 0;
  258. background-color: black;
  259. color: #fff;
  260. text-align: center;
  261. font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
  262. padding: 5px;
  263. border-radius: 6px;
  264. position: absolute;
  265. z-index: 1;
  266. opacity: 0;
  267. transition: opacity 0.2s ease-in-out;
  268. transition-delay: 650ms;
  269. }
  270. /* Show tooltips text when toggled on and hovering */
  271. body.tooltips .tooltip:hover .tooltiptext-textarea,
  272. body.tooltips .tooltip:hover .tooltiptext-submit,
  273. body.tooltips .tooltip:hover .tooltiptext-copy,
  274. body.tooltips .tooltip:hover .tooltiptext-expand,
  275. body.tooltips .tooltip:hover .tooltiptext-layerize,
  276. body.tooltips .tooltip:hover .tooltiptext-argify,
  277. body.tooltips .tooltip:hover .tooltiptext-rotate,
  278. body.tooltips .tooltip:hover .tooltiptext-inhilt,
  279. body.tooltips .tooltip:hover .tooltiptext-slow,
  280. body.tooltips .tooltip:hover .tooltiptext-settings,
  281. body.tooltips .tooltip:hover .tooltiptext-still,
  282. body.tooltips .tooltip:hover .tooltiptext-dark,
  283. body.tooltips .tooltip:hover .tooltiptext-tips {
  284. opacity: 1;
  285. visibility: visible;
  286. }
  287. .hidden {
  288. visibility: hidden;
  289. }
  290. </style>
  291. <head>
  292. <title>Style Editor</title>
  293. <meta name="description" content="ProffieOS Style Editor">
  294. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  295. <meta name="viewport" content="width=device-width, initial-scale=1">
  296.  
  297. <title>Style Editor</title>
  298.  
  299. <link rel="stylesheet" type="text/css" href="styles.css">
  300.  
  301. <script id="vertex-shader" type="x-shader/x-vertex">
  302. precision highp float;
  303. attribute vec2 a_position;
  304. varying vec2 v_position;
  305. uniform float u_width;
  306. uniform float u_height;
  307.  
  308. void main() {
  309. v_position = a_position * vec2(u_width, u_height);
  310. gl_Position = vec4(a_position, 0, 1);
  311. }
  312. </script>
  313.  
  314. <script id="fragment-shader" type="x-shader/x-fragment">
  315. precision highp float;
  316. uniform float u_time;
  317. varying vec2 v_position;
  318. uniform float u_width;
  319. uniform float u_height;
  320. uniform sampler2D sampler;
  321. uniform mat4 u_move_matrix;
  322. uniform mat4 u_old_move_matrix;
  323.  
  324. $VARIABLES$
  325.  
  326. vec3 A = vec3(0,3,0);
  327. vec3 B = vec3(0,-4,0);
  328.  
  329. float get_point(vec3 p) {
  330. vec3 pa = p - A, ba = B - A;
  331. return clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
  332. }
  333.  
  334. int get_led(vec3 p) {
  335. return int(get_point(p) * 144.0);
  336. }
  337.  
  338. float blade(vec3 p, bool tangent) {
  339. vec3 pa = p - A, ba = B - A;
  340. float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
  341. vec3 tmp = pa - ba * h;
  342. float l2 = dot(tmp, tmp);
  343. // float R = 0.08;
  344. float R = 0.09;
  345. if (tangent && l2 >= R*R) {
  346. return sqrt(l2 - R*R);
  347. } else {
  348. return sqrt(l2) - R;
  349. }
  350. }
  351.  
  352. float handle(vec3 p) {
  353. vec2 h = vec2(.15, 0.7);
  354. p.y -= 3.65;
  355. vec2 d = abs(vec2(length(p.xz),p.y)) - h;
  356. return min(max(d.x,d.y),0.0) + length(max(d,0.0));
  357. }
  358.  
  359. float map(vec3 p, bool tangent) {
  360. return min(blade(p, tangent), handle(p));
  361. }
  362.  
  363.  
  364. vec3 getBladeColor(vec3 pos) {
  365. return texture2D(sampler, vec2(get_point(pos), 0.5)).rgb;
  366. }
  367.  
  368. float march(vec3 start, vec3 dir, out vec3 haze_color) {
  369. haze_color = vec3(0,0,0);
  370. float dist = 0.0;
  371. float last_dist = 0.0;
  372. float last_d = 0.0;
  373. bool hit = false;
  374. float haze = 1.0;
  375. for (int i = 0; i < 100; i++) {
  376. vec3 p =start + dir * dist;
  377. float hilt_dist = handle(p);
  378. float blade_dist = blade(p, !hit);
  379. float d = min(hilt_dist, blade_dist);
  380.  
  381. if (dist > 20.0) return 10000.0;
  382. if (d < 0.00001 * dist) {
  383. if (d < 0.0) {
  384. hit = true;
  385. // dist = last_dist + (dist - last_dist) * (last_d / (last_d - d));
  386. dist = last_dist;
  387. continue;
  388. }
  389. return dist;
  390. }
  391. if (get_led(p) > 0) {
  392. // haze_color += getBladeColor(p) * clamp(0.002 / (blade_dist*blade_dist), 0.0, 1.0);
  393.  
  394. // haze_color += getBladeColor(p) * 0.0005 / (blade_dist*blade_dist*blade_dist) * d;
  395.  
  396. float haze_m = clamp(0.004 / (blade_dist*blade_dist), 0.0, 1.0);
  397. haze_color += getBladeColor(p) * haze_m * haze;
  398. haze *= (1.0 - haze_m);
  399. }
  400. last_d = d;
  401. last_dist = dist;
  402. dist += d;
  403. }
  404. if (hit) return dist;
  405. return -1.0;
  406. }
  407.  
  408.  
  409. vec3 getNormal(vec3 p) {
  410. float E = 0.00001;
  411. vec3 X = vec3(E,0.0,0.0);
  412. vec3 Y = vec3(0.0,E,0.0);
  413. vec3 Z = vec3(0.0,0.0,E);
  414. // return normalize(vec3(map(p + X, false) - map(p - X, false),
  415. // map(p + Y, false) - map(p - Y, false),
  416. // map(p + Z, false) - map(p - Z, false)));
  417.  
  418. float D = map(p, false);
  419. return normalize(vec3(map(p + X, false) - D,
  420. map(p + Y, false) - D,
  421. map(p + Z, false) - D));
  422. }
  423.  
  424. float line_dist(vec3 pt1, vec3 dir1, vec3 pt2, vec3 dir2) {
  425. vec3 n = normalize(cross(dir1, dir2));
  426. return abs(dot(n, pt1 - pt2));
  427. }
  428.  
  429. void main() {
  430. vec3 light = vec3(-10.0, 5.0, -10.0);
  431. vec3 eye = vec3(0.0, 0.0, -12.0);
  432. float zoom = 1.5;
  433. vec3 dir = normalize(
  434. vec3((v_position.x) / u_width / zoom,
  435. (v_position.y) / u_width / zoom, 2.0));
  436. mat4 rot3 = mat4(0.0, -1.0, 0.0, 0.0,
  437. 0.0, 0.0, -1.0, 0.0,
  438. 1.0, 0.0, 0.0, 0.0,
  439. 0.0, 0.0, 0.0, 1.0);
  440.  
  441. mat4 rot = rot3 * u_move_matrix;
  442. vec3 new_eye = (rot * vec4(eye.xyz, 1.0)).xyz;
  443. vec3 new_dir = (rot * vec4(dir.xyz, 1.0)).xyz;
  444.  
  445. mat4 old_rot = rot3 * u_old_move_matrix;
  446. vec3 old_eye = (old_rot * vec4(eye.xyz, 1.0)).xyz;
  447. vec3 old_dir = (old_rot * vec4(dir.xyz, 1.0)).xyz;
  448.  
  449. float minpoint = 1.0;
  450.  
  451. if (true) {
  452. // gauss
  453. for (int i = 0; i < 5; i++) {
  454. vec3 e1 = mix(old_eye, new_eye, minpoint);
  455. vec3 d1 = normalize(mix(old_dir, new_dir, minpoint));
  456. float delta = 0.001;
  457. vec3 e2 = mix(old_eye, new_eye, minpoint - delta);
  458. vec3 d2 = normalize(mix(old_dir, new_dir, minpoint - delta));
  459. float dist1 = line_dist(e1, d1, A, B-A);
  460. float dist2 = line_dist(e2, d2, A, B-A);
  461. minpoint = minpoint - dist1 / ((dist1-dist2)/delta);
  462. }
  463. minpoint = clamp(minpoint, 0.0, 1.0);
  464. }
  465.  
  466. eye = mix(old_eye, new_eye, minpoint);
  467. dir = normalize(mix(old_dir, new_dir, minpoint));
  468.  
  469. vec3 haze_color;
  470. float x = march(eye, dir, haze_color);
  471. vec3 hp = eye + dir * x;
  472. vec3 color = vec3(1,1,1);
  473. vec3 color2 = getBladeColor(hp);
  474. if (blade(hp, false) > handle(hp)) {
  475. color = vec3(0.3,0.3,0.3);
  476. color2 = vec3(0);
  477. }
  478.  
  479. vec3 normal = getNormal(hp);
  480. vec3 light_dir = light - hp;
  481. float light_dist2 = dot(light_dir, light_dir) / 10.0;
  482. light_dir = normalize(light_dir);
  483. float l = dot(light_dir, normal) * 5.0;
  484.  
  485. l = max(l, 0.0);
  486. l /= sqrt(light_dist2);
  487. l += 0.1; // ambient
  488. color *= l;
  489. color += color2 * 2.0;
  490.  
  491. vec3 reflection = reflect(dir, normal);
  492. float l2 = max(dot(reflection, light_dir), 0.0);
  493. color += vec3(200.0) * pow(l2, 60.0);
  494. vec3 haze = vec3(0.01, 0.01, 0.01);
  495. float haze_mix = x < 0.0 ? 0.0 : pow(0.95, x);
  496. color = haze_mix * color + (1.0 - haze_mix) * haze;
  497. color += haze_color;
  498.  
  499. // Clip to white
  500. color += vec3(dot(max(color - vec3(1), vec3(0)), vec3(0.33)));
  501. // color += vec3(dot(max(color - vec3(1), 0.0), vec3(0.299, 0.587, 0.114)));
  502. // color += vec3(max(dot(color, vec3(0.299, 0.587, 0.114)) - 1.0, 0.0));
  503.  
  504. color = sqrt(color);
  505. gl_FragColor = vec4(color, 1.0);
  506. }
  507. </script>
  508.  
  509. <script>
  510. var gl = null;
  511. var shaderProgram = null;
  512. var t = 0.0;
  513.  
  514. var width;
  515. var height;
  516.  
  517. // Create n textures of about 1MB each.
  518. function initGL() {
  519. AddTab("color", "Styles",effect_links.sort().join(""))
  520. AddTab("rgb", "Colors",
  521. "<input type=color id=COLOR value='#ff0000' onclick='ClickColor()' />" +
  522. qlinks.sort().join(""));
  523. AddTab("layer", "Layers", layer_links.sort().join(""));
  524. AddTab("function", "Functions", function_links.sort().join(""));
  525. AddTab("transition", "Transitions", transition_links.sort().join(""));
  526. AddTab("effect", "Effects");
  527. AddTab("lockup_type", "Lockup Types");
  528. AddTab("arguments", "Arguments");
  529. AddTab("example", "Examples", template_links.join(""));
  530. AddTab("history", "History");
  531. AddTab("arg_string", "ArgString");
  532. EFFECT_ENUM_BUILDER.addToTab("effect", "EFFECT_");
  533. LOCKUP_ENUM_BUILDER.addToTab("lockup_type", "LOCKUP_");
  534. ArgumentName_ENUM_BUILDER.addToTab("arguments", "");
  535.  
  536. // Add arg string.
  537. var A = "";
  538. A += "Arg string: <input id=ARGSTR name=arg type=input size=80 value='builtin 0 1' onchange='ArgStringChanged()' /><br><table>";
  539. var v = Object.keys(ArgumentName_ENUM_BUILDER.value_to_name);
  540. for (var i = 0; i < v.length; i++) {
  541. var V = parseInt(v[i]);
  542. var N = ArgumentName_ENUM_BUILDER.value_to_name[V];
  543. A += "<tr><td>" + N + "</td><td>";
  544. if (N.search("COLOR") >= 0) {
  545. A += "<input type=color id=ARGSTR_"+N+" onclick='ClickArgColor("+N+")' onchange='ClickArgColor("+N+")' >";
  546. } else {
  547. A += "<input type=button value='<' onclick='IncreaseArg("+N+",-1)' >";
  548. A += "<input id=ARGSTR_"+N+" type=input size=6 value=0 onchange='ArgChanged("+N+")' >";
  549. A += "<input type=button value='>' onclick='IncreaseArg("+N+",1)' >";
  550. }
  551. A += "</td></tr>\n";
  552. }
  553. A += "</table\n";
  554. AddTabContent("arg_string", A);
  555.  
  556.  
  557. var canvas = FIND("canvas_id");
  558.  
  559. width = window.innerWidth;
  560. height = window.innerHeight;
  561.  
  562. if(window.devicePixelRatio !== undefined) {
  563. dpr = window.devicePixelRatio;
  564. } else {
  565. dpr = 1;
  566. }
  567.  
  568. width = width * 2 / 3;
  569. height /= 3;
  570. canvas.width = width * dpr;
  571. canvas.height = height * dpr;
  572. canvas.style.width = width + 'px';
  573. canvas.style.height = height + 'px';
  574.  
  575. gl = canvas.getContext("experimental-webgl", {colorSpace: "srgb", antialias:false});
  576.  
  577. if (!gl) {
  578. throw "Unable to fetch WebGL rendering context for Canvas";
  579. }
  580.  
  581. var str = new URL(window.location.href).searchParams.get("S");
  582. if (!str) {
  583. str = "Layers<RotateColorsX<Variation,Red>,ResponsiveLockupL<White,TrInstant,TrInstant,Int<26000>>,ResponsiveLightningBlockL<White>,ResponsiveMeltL<Mix<TwistAngle<>,Red,Yellow>>,ResponsiveDragL<White>,ResponsiveClashL<White,TrInstant,TrFade<200>,Int<26000>>,ResponsiveBlastL<White>,ResponsiveBlastWaveL<White>,ResponsiveBlastFadeL<White>,ResponsiveStabL<White>,InOutTrL<TrWipe<300>,TrWipeIn<500>>,TransitionEffectL<TrConcat<TrExtendX<Int<1000>,TrSmoothFade<200>>,AlphaL<Gradient<Blue,Green>,SmoothStep<VolumeLevel,Int<-1>>>,TrSmoothFade<500>>,EFFECT_VOLUME_LEVEL>,AlphaL<TransitionEffectL<TrConcat<TrSmoothFade<500>,AlphaL<Mix<BatteryLevel,Red,Green>,SmoothStep<Scale<BatteryLevel,Int<0>,Int<35000>>,Int<-1>>>,TrDelay<1000>,AlphaL<Mix<BatteryLevel,Red,Green>,SmoothStep<BatteryLevel,Int<-1>>>,TrSmoothFade<1000>>,EFFECT_BATTERY_LEVEL>,Ifon<Int<0>,Int<32768>>>,TransitionEffectL<TrConcat<TrWipe<50>,White,TrWipe<50>,Blue,TrWipe<50>,White,TrWipe<50>,Blue,TrWipe<50>>,EFFECT_QUOTE>,TransitionEffectL<TrConcat<TrInstant,AlphaL<White,Bump<Int<0>,Int<8000>>>,TrFade<3000>>,EFFECT_POSTOFF>>";
  584. }
  585. FIND("style").value = str;
  586.  
  587. Run();
  588.  
  589.  
  590. //FIND("color_links").innerHTML = qlinks;
  591. //FIND("effect_links").innerHTML = effect_links;
  592. //FIND("effect_type_links").innerHTML = effect_type_links;
  593. //FIND("template_links").innerHTML = template_links;
  594. //FIND("function_links").innerHTML = function_links;
  595. //FIND("transition_links").innerHTML = transition_links;
  596.  
  597. // Bind a vertex buffer with a single triangle
  598. var buffer = gl.createBuffer();
  599. gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  600. var bufferData = new Float32Array([
  601. -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0]);
  602. gl.bufferData(gl.ARRAY_BUFFER, bufferData, gl.STATIC_DRAW);
  603. gl.enableVertexAttribArray(shaderProgram.a_position);
  604. gl.vertexAttribPointer(shaderProgram.a_position, 2, gl.FLOAT, false, 0, 0);
  605.  
  606. var texture = gl.createTexture();
  607. gl.bindTexture(gl.TEXTURE_2D, texture);
  608.  
  609. // Start the event loop.
  610. tick();
  611. }
  612.  
  613. class Matrix {
  614. constructor(w, h) {
  615. this.w = w;
  616. this.h = h;
  617. this.values = new Float32Array(w * h);
  618. if (w == h) {
  619. for (var z = 0; z < w; z++) {
  620. this.set(z, z, 1.0);
  621. }
  622. }
  623. }
  624. get(x, y) { return this.values[y * this.w + x]; }
  625. set(x, y, v) { this.values[y * this.w + x] = v; }
  626. mult(o) {
  627. var ret = new Matrix(o.w, this.h);
  628. for (var x = 0; x < o.w; x++) {
  629. for (var y = 0; y < this.h; y++) {
  630. var sum = 0.0;
  631. for (var z = 0; z < this.w; z++) {
  632. sum += this.get(z, y) * o.get(x, z);
  633. }
  634. ret.set(x, y, sum);
  635. }
  636. }
  637. return ret;
  638. }
  639. static mkzrot(a) {
  640. var ret = new Matrix(4, 4);
  641. var s = Math.sin(a);
  642. var c = Math.cos(a);
  643. ret.set(0, 0, c);
  644. ret.set(1, 1, c);
  645. ret.set(0, 1, s);
  646. ret.set(1, 0, -s);
  647. return ret;
  648. }
  649. static mkxrot(a) {
  650. var ret = new Matrix(4, 4);
  651. var s = Math.sin(a);
  652. var c = Math.cos(a);
  653. ret.set(1, 1, c);
  654. ret.set(2, 2, c);
  655. ret.set(1, 2, s);
  656. ret.set(2, 1, -s);
  657. return ret;
  658. }
  659. static mkyrot(a) {
  660. var ret = new Matrix(4, 4);
  661. var s = Math.sin(a);
  662. var c = Math.cos(a);
  663. ret.set(0, 0, c);
  664. ret.set(2, 2, c);
  665. ret.set(0, 2, s);
  666. ret.set(2, 0, -s);
  667. return ret;
  668. }
  669. static mktranslate(x, y, z) {
  670. var ret = new Matrix(4, 4);
  671. ret.set(0,3,x);
  672. ret.set(1,3,y);
  673. ret.set(2,3,z);
  674. return ret;
  675. }
  676.  
  677. tostr() {
  678. var ret = "{";
  679. for (var x = 0; x < this.w; x++) {
  680. for (var y = 0; y < this.h; y++) {
  681. ret += this.get(x, y);
  682. ret += ", ";
  683. }
  684. ret += ";";
  685. }
  686. ret += "}";
  687. return ret;
  688. }
  689. };
  690.  
  691. function default_move_matrix() {
  692. return Matrix.mktranslate(0.00, 0.0, -0.08);
  693. }
  694.  
  695. var MOVE_MATRIX = default_move_matrix();
  696. var OLD_MOVE_MATRIX = default_move_matrix();
  697. var MOUSE_POSITIONS = [];
  698. var IN_FRAME = false;
  699. var BLADE_ANGLE = 0.0;
  700.  
  701. function mouse_speed(t1, t2) {
  702. var dx = MOUSE_POSITIONS[t1+0]-MOUSE_POSITIONS[t2+0];
  703. var dy = MOUSE_POSITIONS[t1+1]-MOUSE_POSITIONS[t2+1];
  704. var dt = MOUSE_POSITIONS[t1+2]-MOUSE_POSITIONS[t2+2];
  705. if (dt == 0) return 0.0;
  706. return Math.sqrt(dx * dx + dy * dy) / Math.abs(dt);
  707. }
  708.  
  709. function mouse_move(e) {
  710. if (STATE_STILL) return;
  711. IN_FRAME = true;
  712. var canvas = FIND("canvas_id");
  713. var rect = canvas.getBoundingClientRect();
  714. var w = rect.right - rect.left;
  715. var h = rect.bottom - rect.top;
  716. var d = min(h, w);
  717. var x = (e.clientX - (rect.left + rect.right)/2.0) / d;
  718. var y = (e.clientY - (rect.top + rect.bottom)/2.0) / d;
  719. var now = actual_millis();
  720. MOUSE_POSITIONS = MOUSE_POSITIONS.concat([x* 10000, y * 10000, now])
  721. while (MOUSE_POSITIONS.length > 0 && now - MOUSE_POSITIONS[2] > 100) {
  722. MOUSE_POSITIONS = MOUSE_POSITIONS.slice(3);
  723. }
  724.  
  725. // console.log("x = "+x+" y = "+y);
  726. if (e.shiftKey) {
  727. MOVE_MATRIX = default_move_matrix();
  728. } else {
  729. BLADE_ANGLE=-y;
  730. MOVE_MATRIX = Matrix.mkzrot(Math.PI/2.0).mult(Matrix.mkxrot(-y)).mult(Matrix.mkzrot(y));
  731.  
  732. MOVE_MATRIX = Matrix.mkyrot(Math.PI/2.0)
  733. MOVE_MATRIX = MOVE_MATRIX.mult(Matrix.mktranslate(1.0, 0.04, 0.0));
  734. MOVE_MATRIX = MOVE_MATRIX.mult(Matrix.mkyrot(-x/3));
  735. MOVE_MATRIX = MOVE_MATRIX.mult(Matrix.mktranslate(-1.0, 0.0, 0.0));
  736. MOVE_MATRIX = MOVE_MATRIX.mult(Matrix.mkzrot(-y));
  737. MOVE_MATRIX = MOVE_MATRIX.mult(Matrix.mktranslate(-0.17, 0.0, 0.0));
  738. }
  739. // console.log(MOVE_MATRIX.values);
  740. }
  741.  
  742. function get_swing_speed() {
  743. var now = actual_millis();
  744. while (MOUSE_POSITIONS.length > 0 && now - MOUSE_POSITIONS[2] > 100) {
  745. MOUSE_POSITIONS = MOUSE_POSITIONS.slice(3);
  746. }
  747. var len = MOUSE_POSITIONS.length;
  748. if (len >= 6) {
  749. return mouse_speed(0, len - 6);
  750. }
  751. // if (IN_FRAME) return 0.0;
  752. if (IN_FRAME || STATE_STILL) return 0.0; // BC ONLY
  753.  
  754. return Math.sin(millis() * Math.PI / 1000.0) * 250 + 250
  755. }
  756.  
  757. function get_swing_accel() {
  758. var now = actual_millis();
  759. while (MOUSE_POSITIONS.length > 0 && now - MOUSE_POSITIONS[2] > 100) {
  760. MOUSE_POSITIONS = MOUSE_POSITIONS.slice(3);
  761. }
  762. var len = MOUSE_POSITIONS.length;
  763. if (len >= 6) {
  764. var speed = mouse_speed(0, len - 6);
  765. if (MOUSE_POSITIONS.length >= 9) {
  766. return (speed - mouse_speed(0, Math.floor(len/6)*3)) * 2.0;
  767. }
  768. }
  769. if (IN_FRAME) return 0.0;
  770. return Math.cos(millis() * Math.PI / 500.0) * 100 + 100
  771. }
  772.  
  773. function mouse_leave(e) {
  774. console.log("Mouse leave!");
  775. MOVE_MATRIX = default_move_matrix();
  776. MOUSE_POSITIONS = [];
  777. IN_FRAME = false;
  778. }
  779.  
  780.  
  781. function compile() {
  782. // Create a shader that samples a 2D image.
  783. var vertexShader = gl.createShader(gl.VERTEX_SHADER);
  784. gl.shaderSource(vertexShader,
  785. FIND("vertex-shader").textContent);
  786. gl.compileShader(vertexShader);
  787.  
  788. var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  789. var shader_code = FIND("fragment-shader").textContent;
  790.  
  791. variables = [];
  792. // shader_code = shader_code.replace("$FUNCTION$", current_style.gencode());
  793. shader_code = shader_code.replace("$VARIABLES$", variables.join("\n"));
  794. // console.log(shader_code);
  795.  
  796. gl.shaderSource(fragmentShader, shader_code);
  797. gl.compileShader(fragmentShader);
  798. if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
  799.  
  800. var v = shader_code.split("\n");
  801. for (var i = 0; i < v.length; i++) {
  802. console.log( (i+1) + ": " + v[i]);
  803. }
  804. throw "Could not compile shader:\n\n" + gl.getShaderInfoLog(fragmentShader);
  805. }
  806.  
  807. shaderProgram = gl.createProgram();
  808. gl.attachShader(shaderProgram, vertexShader);
  809. gl.attachShader(shaderProgram, fragmentShader);
  810. gl.linkProgram(shaderProgram);
  811. if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
  812. throw "Could not link the shader program!\n\n" + gl.getProgramInfoLog(shaderProgram);
  813. }
  814. gl.useProgram(shaderProgram);
  815.  
  816. }
  817.  
  818. var varnum = 0;
  819. var variables = [];
  820. var vartypes = {};
  821.  
  822. function genvar(t) {
  823. varnum++;
  824. var variable = "u_" + varnum;
  825. variables.push( "uniform " + t + " " + variable + ";");
  826. vartypes[variable] = t;
  827. return variable;
  828. }
  829.  
  830. function setvar(variable, val) {
  831. // console.log(variable + " = " + val);
  832. if (vartypes[variable] == "float") {
  833. gl.uniform1f(gl.getUniformLocation(shaderProgram, variable), val);
  834. return;
  835. }
  836. if (vartypes[variable] == "int") {
  837. gl.uniform1i(gl.getUniformLocation(shaderProgram, variable), val);
  838. return;
  839. }
  840. console.log("SETVAR ERROR " + variable);
  841. }
  842.  
  843. class MyError {
  844. constructor(desc) {
  845. this.desc = desc;
  846. this.begin_pos = -1;
  847. this.end_pos = -1;
  848. }
  849. setBegin(pos) { this.begin_pos = pos; return this; }
  850. setEnd(pos) { this.end_pos = pos; return this; }
  851. setArg(arg) {
  852. if (arg && arg.__end_pos) {
  853. this.begin_pos = arg.__begin_pos;
  854. this.end_pos = arg.__end_pos;
  855. }
  856. return this;
  857. }
  858. setThis(arg) {
  859. if (arg && arg.__end_pos && this.begin_pos == -1) {
  860. this.begin_pos = arg.__begin_pos;
  861. this.end_pos = arg.__end_pos;
  862. }
  863. return this;
  864. }
  865. valueOf() { return this.desc; }
  866. };
  867.  
  868. function Arg(expected_type, arg, default_arg) {
  869. //console.log("ARGUMENT: " + expected_type);
  870. //console.log(arg);
  871. //if (typeof(arg) == "object") console.log(arg.ID);
  872. //console.log(default_arg);
  873. if (arg == undefined) {
  874. if (typeof(default_arg) == "number") {
  875. // console.log("DEFAULT ARG" + default_arg);
  876. return new INTEGER(default_arg);
  877. }
  878. if (default_arg != undefined) {
  879. // This must copy the argument!
  880. return default_arg;
  881. }
  882. throw "Too few arguments";
  883. }
  884. if (typeof(arg) != "number" && !arg.getType) {
  885. throw "What is this?? " + arg;
  886. }
  887. if (expected_type == "TIME_FUNCTION" && arg.getType() == "FUNCTION") {
  888. return arg;
  889. }
  890. if (typeof(arg) != "number" && arg.getType() != expected_type) {
  891. throw "Expected " + expected_type + " but got " + arg;
  892. }
  893. if (expected_type == "INT" || expected_type == "EFFECT" || expected_type == "LOCKUP_TYPE" || expected_type == "ArgumentName") {
  894. return arg;
  895. }
  896. if (expected_type == "COLOR" ||
  897. expected_type == "FireConfig" ||
  898. expected_type == "TRANSITION" ||
  899. expected_type == "FUNCTION" ||
  900. expected_type == "TIME_FUNCTION") {
  901. if (typeof(arg) != "object") {
  902. throw "Expected a " + expected_type;
  903. }
  904. return arg;
  905. }
  906.  
  907. throw "Not INT, COLOR, EFFECT, LOCKUP_TYPE, FUNCTION or TRANSITION";
  908. }
  909.  
  910. function IntArg(arg, def_arg) { return Arg("INT", arg, def_arg); }
  911. function ColorArg(arg, def_arg) { return Arg("COLOR", arg, def_arg); }
  912.  
  913. var pp_is_url = 0;
  914. var pp_is_verbose = 0;
  915.  
  916. var next_id = 1000;
  917. var style_ids = {};
  918.  
  919. var identifiers = {};
  920.  
  921. function AddIdentifier(name, value) {
  922. identifiers[name] = value;
  923. }
  924.  
  925. class ARG {
  926. constructor(name, type, comment, default_value) {
  927. this.name = name;
  928. this.type = type;
  929. this.comment = comment;
  930. this.default_value = default_value;
  931. }
  932. };
  933.  
  934. class STYLE {
  935. constructor(comment, args) {
  936. this.comment = comment;
  937. // if (args) console.log(args);
  938. this.args = args;
  939. this.argnum = 0;
  940. this.argdefs = [];
  941. this.super_short_desc = false;
  942. this.ID = next_id;
  943. next_id ++;
  944. }
  945.  
  946. add_arg(name, expected_type, comment, default_value) {
  947. if (focus_trace[0] == this.args[this.argnum]) {
  948. focus_trace = [this, name, expected_type, focus_trace];
  949. }
  950. // console.log("add_arg");
  951. // console.log(name);
  952. // console.log(this.args);
  953. // console.log(default_value);
  954. try {
  955. this[name] = Arg(expected_type, this.args[this.argnum], default_value);
  956. // console.log(this[name]);
  957. } catch(e) {
  958. if (typeof(e) == "string") {
  959. e = new MyError(e + " for argument " + (this.argnum + 1) + " (" + name + ")");
  960. e.setArg(this.args[this.argnum]);
  961. }
  962. throw e;
  963. }
  964. this.argnum++;
  965. this.argdefs.push(new ARG(name, expected_type, comment, default_value));
  966. }
  967.  
  968. get_id() {
  969. style_ids[this.ID] = this;
  970. return this.ID;
  971. }
  972.  
  973. DOCOPY() {
  974. pp_is_url++;
  975. var url = this.pp();
  976. pp_is_url--;
  977. var parser = new Parser(url, classes, identifiers);
  978. ret = parser.parse();
  979. ret.COMMENT = this.COMMENT;
  980. return ret;
  981. }
  982.  
  983. call_pp_no_comment(arg) {
  984. var C = arg.COMMENT;
  985. arg.COMMENT = null;
  986. var ret;
  987. try {
  988. ret = arg.pp();
  989. }
  990. finally {
  991. arg.COMMENT = C;
  992. }
  993. return ret;
  994. }
  995.  
  996. DescribeValue(arg) {
  997. if (typeof(arg) == "undefined") return "undefined";
  998. if (typeof(arg) == "number") {
  999. return "" + arg;
  1000. } else {
  1001. return arg.pp();
  1002. // return this.call_pp_no_comment(arg);
  1003. }
  1004. }
  1005.  
  1006. Indent(text) {
  1007. return text;
  1008. }
  1009.  
  1010. gencomment() {
  1011. if (!this.COMMENT) return "";
  1012. var ret = this.COMMENT;
  1013. if (ret[ret.length-1] != " ") ret += " ";
  1014. ret = "/*"+ret+"*/";
  1015. if (this.COMMENT.split("\n").length > 1) {
  1016. ret += "\n";
  1017. } else {
  1018. ret += " ";
  1019. }
  1020. return ret;
  1021. }
  1022.  
  1023. addcomment(COMMENT) {
  1024. if (!COMMENT) return;
  1025. if (!this.COMMENT) {
  1026. this.COMMENT = COMMENT;
  1027. } else {
  1028. this.COMMENT += "\n" + COMMENT;
  1029. }
  1030. }
  1031.  
  1032. prependcomment(COMMENT) {
  1033. if (!COMMENT) return;
  1034. if (!this.COMMENT) {
  1035. this.COMMENT = COMMENT;
  1036. } else {
  1037. this.COMMENT = COMMENT + "\n" + this.COMMENT;
  1038. }
  1039. }
  1040.  
  1041. PPURL(name, note) {
  1042. if (this.super_short_desc) return "$";
  1043. pp_is_url++;
  1044. var ret = name;
  1045. ret = this.gencomment() + ret;
  1046. var comma = false;
  1047. if (arguments.length > 2 || this.argdefs.length > 0) {
  1048. ret += "<";
  1049. for (var i = 2; i < arguments.length; i += 2) {
  1050. if (comma) ret += ",";
  1051. comma = true;
  1052. var V = this.DescribeValue(arguments[i]);
  1053. var arg = this.Indent(V);
  1054. ret += arg;
  1055. }
  1056. ret += ">";
  1057. }
  1058. pp_is_url--;
  1059.  
  1060. return ret;
  1061. }
  1062.  
  1063. extraButtons(arg) {
  1064. return "";
  1065. }
  1066.  
  1067. PP(name, note) {
  1068. if (pp_is_url) {
  1069. return this.PPURL.apply(this, arguments);
  1070. }
  1071. var id = this.get_id();
  1072. var ret = "";
  1073. if (this.COMMENT) {
  1074. ret += "/* "+this.COMMENT.split("\n").join("<br>")+" */<br>";
  1075. console.log("RET = " + ret);
  1076. }
  1077. ret += "<div id=X"+id+" style='border-style:solid;border-width:1px;border-color:gray;' onclick='FocusOn("+id+",event)'>\n";
  1078. ret += "<span title='"+ note +"'>" + name + "</span>&lt;\n";
  1079. ret += "<div style='margin-left:1em'>\n";
  1080. var comma = false;
  1081. for (var i = 2; i < arguments.length; i += 2) {
  1082. if (comma) ret += ",<br>";
  1083. comma = true;
  1084. var arg = arguments[i];
  1085. var note = arguments[i+1];
  1086. var comment = null;
  1087. if (typeof(arg) == "number") {
  1088. arg = "" + arg;
  1089. } else {
  1090. comment = arg.COMMENT;
  1091. arg = this.call_pp_no_comment(arg);
  1092. }
  1093. if (arg.indexOf("<br>") == -1 && arg.indexOf("<div") == -1 && !comment) {
  1094. ret += arg+" /* "+note+" */\n";
  1095. } else {
  1096. ret += "/* "+note+" */"+ this.extraButtons(i/2) +"<br>\n";
  1097. if (comment) {
  1098. ret += "/* "+comment+" */<br>\n";
  1099. }
  1100. ret += arg;
  1101. }
  1102. }
  1103. ret += "</div>&gt;</div>\n";
  1104.  
  1105. return ret;
  1106. }
  1107.  
  1108. PPshort(name, note) {
  1109. if (pp_is_url) {
  1110. return this.PPURL.apply(this, arguments);
  1111. }
  1112. var id = this.get_id();
  1113. var ret = this.gencomment();
  1114. ret += "<div id=X"+id+" style='border-style:solid;border-width:1px;border-color:gray;' onclick='FocusOn("+id+",event)'>\n";
  1115. ret += "<span title='"+ note +"'>" + name + "</span>\n";
  1116.  
  1117. if (arguments.length > 2) {
  1118. ret += "&lt;";
  1119. var comma = false;
  1120. for (var i = 2; i < arguments.length; i += 2) {
  1121. if (comma) ret += ",";
  1122. comma = true;
  1123. var arg = arguments[i];
  1124. var note = arguments[i+1];
  1125. if (typeof(arg) == "number") {
  1126. ret += "<span title='"+note+"'>"+arg+"</span>";
  1127. } else {
  1128. ret += "<span>/* "+note+" */</span><br>\n";
  1129. ret += arg.pp();
  1130. }
  1131. }
  1132. ret += "&gt;";
  1133. }
  1134. ret += "</div>\n";
  1135.  
  1136. return ret;
  1137. }
  1138.  
  1139. SameValue(a, b) {
  1140. // console.log("SAMEVALUE");
  1141. // console.log(a);
  1142. // console.log(b);
  1143. // console.log(this.DescribeValue(a));
  1144. // console.log(this.DescribeValue(b));
  1145. return a == b || this.DescribeValue(a) == this.DescribeValue(b);
  1146. }
  1147.  
  1148. pp() {
  1149. var tmp = [this.constructor.name.replace("Class", ""), this.comment];
  1150. var l = this.argdefs.length;
  1151. if (pp_is_url && !pp_is_verbose) {
  1152. // Drop default arguments
  1153. while (l > 0 && this.argdefs[l-1].default_value != undefined &&
  1154. this.SameValue(this[this.argdefs[l-1].name], this.argdefs[l-1].default_value)) l--;
  1155. }
  1156. for (var i = 0; i < l; i++) {
  1157. tmp.push(this[this.argdefs[i].name]);
  1158. tmp.push(this.argdefs[i].comment);
  1159. }
  1160. return this.PP.apply(this, tmp);
  1161. }
  1162. getType() { return "COLOR"; }
  1163.  
  1164. run(blade) {
  1165. for (var i = 0; i < this.argdefs.length; i++) {
  1166. var arg = this[this.argdefs[i].name];
  1167. if (typeof(arg) == "object") arg.run(blade);
  1168. }
  1169. }
  1170.  
  1171. isEffect() {
  1172. for (var i = 0; i < this.argdefs.length; i++) {
  1173. if (this.argdefs[i].type == "EFFECT") return true;
  1174. if (this.argdefs[i].type == "LOCKUP_TYPE") return true;
  1175. }
  1176. return false;
  1177. }
  1178.  
  1179. // Doesn't work??
  1180. toString() { return this.constructor.name + "[id = " + this.ID + "]"; }
  1181.  
  1182. set_right_side(right) {
  1183. if (this.argdefs.length != right.argdefs.length) {
  1184. console.log("SET RIGHT SIDE NON-MATCH");
  1185. return;
  1186. }
  1187. this.right_side = right;
  1188. for (var i = 0; i < this.argdefs.length; i++) {
  1189. if (this.argdefs[i].name != right.argdefs[i].name) {
  1190. console.log("SET RIGHT SIDE NON-MATCH");
  1191. return;
  1192. }
  1193.  
  1194. var l_arg = this[this.argdefs[i].name];
  1195. var r_arg = right[this.argdefs[i].name];
  1196. if (typeof(l_arg) == "object" && typeof(r_arg) == "object") {
  1197. l_arg.set_right_side(r_arg);
  1198. }
  1199. }
  1200. }
  1201.  
  1202. get_container() {
  1203. var id = this.ID;
  1204. if (this.right_side) id = this.right_side.ID;
  1205. return FIND("X" + id);
  1206. }
  1207.  
  1208. update_displays() {
  1209. for (var i = 0; i < this.argdefs.length; i++) {
  1210. var arg = this[this.argdefs[i].name];
  1211. if (typeof(arg) == "object") arg.update_displays();
  1212. }
  1213.  
  1214. if (this.IS_RUNNING) {
  1215. var container = this.get_container();
  1216. if (container) {
  1217. if (this.IS_RUNNING()) {
  1218. container.style["border-color"] = 'yellow';
  1219. container.style["border-width"] = '3px';
  1220. container.style["padding"] = '0px'; // Add this line to adjust the padding
  1221. } else {
  1222. container.style["border-color"] = 'gray';
  1223. container.style["border-width"] = '1px';
  1224. container.style["padding"] = '2px';
  1225. }
  1226. }
  1227. }
  1228. }
  1229.  
  1230. argify(state) {
  1231. for (var i = 0; i < this.argdefs.length; i++) {
  1232. var arg = this[this.argdefs[i].name];
  1233. if (typeof(arg) == "object") {
  1234. this[this.argdefs[i].name] = arg.argify(state);
  1235. }
  1236. }
  1237. return this;
  1238. }
  1239. }
  1240.  
  1241.  
  1242. class MACRO extends STYLE {
  1243. SetExpansion(expansion) {
  1244. this.expansion = expansion.DOCOPY();
  1245. }
  1246. run(blade) { this.expansion.run(blade); }
  1247. getInteger(led) { return this.expansion.getInteger(led); }
  1248. getColor(A,B,C) { return this.expansion.getColor(A,B,C); }
  1249. getType() { return this.expansion.getType(); }
  1250. isMacro() { return true; }
  1251. isEffect() { return this.expansion.isEffect(); }
  1252. begin() { this.expansion.begin(); }
  1253. done() { return this.expansion.done(); }
  1254. IS_RUNNING() {
  1255. if (this.expansion.IS_RUNNING)
  1256. return this.expansion.IS_RUNNING();
  1257. return false;
  1258. }
  1259. bend(t, len, scale) {
  1260. if (this.expansion.bend)
  1261. return this.expansion.bend(t, len, scale);
  1262. return scale * t / len;
  1263. }
  1264. };
  1265.  
  1266. class INTEGER extends STYLE {
  1267. constructor(v) {
  1268. super();
  1269. this.value = v;
  1270. }
  1271. run(blade) {}
  1272. getInteger(led) { return this.value; }
  1273. valueOf() { return this.value; }
  1274. pp() {
  1275. if (pp_is_url) {
  1276. if (this.super_short_desc) return "$";
  1277. return this.gencomment() + this.value;
  1278. }
  1279. return this.PPshort(this.value, "VALUE");
  1280. }
  1281. getType() { return "INT"; }
  1282. };
  1283.  
  1284. function INT(x) {
  1285. return new INTEGER(x);
  1286. }
  1287.  
  1288. class BINARY extends STYLE {
  1289. constructor(v) {
  1290. super();
  1291. this.value = v;
  1292. }
  1293. run(blade) {}
  1294. getInteger(led) { return this.value; }
  1295. valueOf() { return this.value; }
  1296. pp() {
  1297. if (pp_is_url) {
  1298. if (this.super_short_desc) return "$";
  1299. return this.gencomment() + "0b" +this.value.toString(2);
  1300. }
  1301. return this.PPshort("0b" +this.value.toString(2), "VALUE");
  1302. }
  1303. getType() { return "INT"; }
  1304. };
  1305.  
  1306.  
  1307. function AddEnum(enum_type, name, value) {
  1308. if (value == undefined) {
  1309. value = enum_type.last_value + 1;
  1310. }
  1311. enum_type.last_value = value;
  1312. enum_type.value_to_name[value] = name;
  1313. window[name] = value;
  1314. AddIdentifier(name, function() { return new enum_type(value); });
  1315. console.log(" ENUM " + name + " = " + value);
  1316. }
  1317.  
  1318. class EnumBuilder {
  1319. constructor(name, prefix) {
  1320. this.name = name;
  1321. this.prefix = prefix ? prefix : "";
  1322. this.last_value = -1
  1323. this.value_to_name = {};
  1324. }
  1325. addValue(name, value) {
  1326. if (value == undefined) {
  1327. value = this.last_value + 1;
  1328. }
  1329. this.last_value = value;
  1330. this.value_to_name[value] = name;
  1331. window[name] = value;
  1332. console.log(" ENUM " + name + " = " + value);
  1333. }
  1334. addToTab(tab, common_prefix) {
  1335. if (!common_prefix) {
  1336. common_prefix = "florb";
  1337. }
  1338. var v = Object.keys(this.value_to_name);
  1339. for (var i = 0; i < v.length; i++) {
  1340. var V = parseInt(v[i]);
  1341. var N = this.value_to_name[V];
  1342. var label = N.replace(common_prefix, "");
  1343. AddTabContent(tab, mkbutton2(label, this.prefix+N));
  1344. }
  1345. }
  1346. build() {
  1347. class ENUMClass extends INTEGER {
  1348. pp() {
  1349. if (pp_is_url) {
  1350. if (this.super_short_desc) return "$";
  1351. } else if (0) {
  1352. var ret = "<select>";
  1353. var v = Object.keys(this.constructor.value_to_name);
  1354. for (var i = 0; i < v.length; i++) {
  1355. var V = parseInt(v[i]);
  1356. var N = this.constructor.value_to_name[V];
  1357. ret += "<option value="+V;
  1358. if (this.value == V) ret+=" selected";
  1359. ret += ">"+N+"</option>";
  1360. }
  1361. ret += "</select>";
  1362. return ret;
  1363. }
  1364.  
  1365.  
  1366. var ret = this.gencomment() + this.value;
  1367. if (this.constructor.value_to_name[this.value]) {
  1368. ret = this.constructor.prefix + this.constructor.value_to_name[this.value];
  1369. }
  1370. return this.PPshort(ret, this.getType());
  1371. }
  1372. getType() { return this.constructor.NAME; }
  1373. };
  1374. ENUMClass.value_to_name = this.value_to_name;
  1375. ENUMClass.NAME = this.name;
  1376. ENUMClass.prefix = this.prefix
  1377.  
  1378. function ENUM(value) { return new ENUMClass(value); }
  1379. window[this.name] = ENUM;
  1380.  
  1381. var v = Object.keys(this.value_to_name);
  1382. for (var i = 0; i < v.length; i++) {
  1383. var V = parseInt(v[i]);
  1384. var N = this.value_to_name[V];
  1385. AddIdentifier(this.prefix + N, ENUM.bind(null, V));
  1386. }
  1387. }
  1388. }
  1389.  
  1390. EFFECT_ENUM_BUILDER = new EnumBuilder("EFFECT");
  1391. // EFFECT_ENUM_BUILDER.addValue("EFFECT_NONE", 0); /**************************************** organize/group EFFECT ENUMS */
  1392. // EFFECT_ENUM_BUILDER.addValue("EFFECT_CLASH");
  1393. // EFFECT_ENUM_BUILDER.addValue("EFFECT_STAB");
  1394. // EFFECT_ENUM_BUILDER.addValue("EFFECT_BLAST");
  1395. // EFFECT_ENUM_BUILDER.addValue("EFFECT_FORCE");
  1396. // EFFECT_ENUM_BUILDER.addValue("EFFECT_BOOT");
  1397. // EFFECT_ENUM_BUILDER.addValue("EFFECT_NEWFONT")
  1398. // EFFECT_ENUM_BUILDER.addValue("EFFECT_PREON");
  1399. // EFFECT_ENUM_BUILDER.addValue("EFFECT_POSTOFF");
  1400.  
  1401. // EFFECT_ENUM_BUILDER.addValue("EFFECT_LOCKUP_BEGIN");
  1402. // EFFECT_ENUM_BUILDER.addValue("EFFECT_LOCKUP_END");
  1403. // EFFECT_ENUM_BUILDER.addValue("EFFECT_DRAG_BEGIN");
  1404. // EFFECT_ENUM_BUILDER.addValue("EFFECT_DRAG_END");
  1405.  
  1406. // EFFECT_ENUM_BUILDER.addValue("EFFECT_IGNITION");
  1407. // EFFECT_ENUM_BUILDER.addValue("EFFECT_RETRACTION");
  1408. // EFFECT_ENUM_BUILDER.addValue("EFFECT_QUOTE");
  1409. // EFFECT_ENUM_BUILDER.addValue("EFFECT_NEXT_QUOTE");
  1410.  
  1411. // EFFECT_ENUM_BUILDER.addValue("EFFECT_LOW_BATTERY");
  1412. // EFFECT_ENUM_BUILDER.addValue("EFFECT_POWERSAVE");
  1413. // EFFECT_ENUM_BUILDER.addValue("EFFECT_BATTERY_LEVEL");
  1414. // EFFECT_ENUM_BUILDER.addValue("EFFECT_VOLUME_LEVEL");
  1415.  
  1416.  
  1417. // EFFECT_ENUM_BUILDER.addValue("EFFECT_ON");
  1418. // EFFECT_ENUM_BUILDER.addValue("EFFECT_OFF");
  1419. // EFFECT_ENUM_BUILDER.addValue("EFFECT_OFF_CLASH");
  1420. // EFFECT_ENUM_BUILDER.addValue("EFFECT_FAST_ON");
  1421. // EFFECT_ENUM_BUILDER.addValue("EFFECT_FAST_OFF");
  1422. // EFFECT_ENUM_BUILDER.addValue("EFFECT_SECONDARY_IGNITION");
  1423. // EFFECT_ENUM_BUILDER.addValue("EFFECT_SECONDARY_RETRACTION");
  1424.  
  1425. // EFFECT_ENUM_BUILDER.addValue("EFFECT_INTERACTIVE_PREON");
  1426. // EFFECT_ENUM_BUILDER.addValue("EFFECT_INTERACTIVE_BLAST");
  1427.  
  1428. // EFFECT_ENUM_BUILDER.addValue("EFFECT_BEGIN_BATTLE_MODE");
  1429. // EFFECT_ENUM_BUILDER.addValue("EFFECT_END_BATTLE_MODE");
  1430. // EFFECT_ENUM_BUILDER.addValue("EFFECT_BEGIN_AUTO_BLAST");
  1431. // EFFECT_ENUM_BUILDER.addValue("EFFECT_END_AUTO_BLAST");
  1432.  
  1433. // EFFECT_ENUM_BUILDER.addValue("EFFECT_TRACK");
  1434. // EFFECT_ENUM_BUILDER.addValue("EFFECT_CHANGE");
  1435. // EFFECT_ENUM_BUILDER.addValue("EFFECT_ALT_SOUND");
  1436. // EFFECT_ENUM_BUILDER.addValue("EFFECT_TRANSITION_SOUND");
  1437. // EFFECT_ENUM_BUILDER.addValue("EFFECT_SOUND_LOOP");
  1438.  
  1439. // EFFECT_ENUM_BUILDER.addValue("EFFECT_STUN");
  1440. // EFFECT_ENUM_BUILDER.addValue("EFFECT_FIRE");
  1441. // EFFECT_ENUM_BUILDER.addValue("EFFECT_CLIP_IN");
  1442. // EFFECT_ENUM_BUILDER.addValue("EFFECT_CLIP_OUT");
  1443. // EFFECT_ENUM_BUILDER.addValue("EFFECT_RELOAD");
  1444. // EFFECT_ENUM_BUILDER.addValue("EFFECT_MODE");
  1445. // EFFECT_ENUM_BUILDER.addValue("EFFECT_RANGE");
  1446. // EFFECT_ENUM_BUILDER.addValue("EFFECT_EMPTY");
  1447. // EFFECT_ENUM_BUILDER.addValue("EFFECT_FULL");
  1448. // EFFECT_ENUM_BUILDER.addValue("EFFECT_JAM");
  1449. // EFFECT_ENUM_BUILDER.addValue("EFFECT_UNJAM");
  1450. // EFFECT_ENUM_BUILDER.addValue("EFFECT_PLI_ON");
  1451. // EFFECT_ENUM_BUILDER.addValue("EFFECT_PLI_OFF");
  1452.  
  1453. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_START");
  1454. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_ACTION1");
  1455. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_ACTION2");
  1456. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_CHOICE");
  1457. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESPONSE1");
  1458. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESPONSE2");
  1459. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESULT1");
  1460. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESULT2");
  1461. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_WIN");
  1462. // EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_LOSE");
  1463.  
  1464. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER1");
  1465. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER2");
  1466. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER3");
  1467. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER4");
  1468. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER5");
  1469. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER6");
  1470. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER7");
  1471. // EFFECT_ENUM_BUILDER.addValue("EFFECT_USER8");
  1472. /**************************************** Alphabetical EFFECT ENUMS */
  1473. EFFECT_ENUM_BUILDER.addValue("EFFECT_NONE", 0);
  1474. EFFECT_ENUM_BUILDER.addValue("EFFECT_ALT_SOUND");
  1475. EFFECT_ENUM_BUILDER.addValue("EFFECT_BATTERY_LEVEL");
  1476. EFFECT_ENUM_BUILDER.addValue("EFFECT_BEGIN_AUTO_BLAST");
  1477. EFFECT_ENUM_BUILDER.addValue("EFFECT_BEGIN_BATTLE_MODE");
  1478. EFFECT_ENUM_BUILDER.addValue("EFFECT_BLAST");
  1479. EFFECT_ENUM_BUILDER.addValue("EFFECT_BOOT");
  1480. EFFECT_ENUM_BUILDER.addValue("EFFECT_CHANGE");
  1481. EFFECT_ENUM_BUILDER.addValue("EFFECT_CLASH");
  1482. EFFECT_ENUM_BUILDER.addValue("EFFECT_CLIP_IN");
  1483. EFFECT_ENUM_BUILDER.addValue("EFFECT_CLIP_OUT");
  1484. EFFECT_ENUM_BUILDER.addValue("EFFECT_DRAG_BEGIN");
  1485. EFFECT_ENUM_BUILDER.addValue("EFFECT_DRAG_END");
  1486. EFFECT_ENUM_BUILDER.addValue("EFFECT_EMPTY");
  1487. EFFECT_ENUM_BUILDER.addValue("EFFECT_END_AUTO_BLAST");
  1488. EFFECT_ENUM_BUILDER.addValue("EFFECT_END_BATTLE_MODE");
  1489. EFFECT_ENUM_BUILDER.addValue("EFFECT_FAST_OFF");
  1490. EFFECT_ENUM_BUILDER.addValue("EFFECT_FAST_ON");
  1491. EFFECT_ENUM_BUILDER.addValue("EFFECT_FIRE");
  1492. EFFECT_ENUM_BUILDER.addValue("EFFECT_FORCE");
  1493. EFFECT_ENUM_BUILDER.addValue("EFFECT_FULL");
  1494. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_ACTION1");
  1495. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_ACTION2");
  1496. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_CHOICE");
  1497. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_LOSE");
  1498. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESPONSE1");
  1499. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESPONSE2");
  1500. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESULT1");
  1501. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_RESULT2");
  1502. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_START");
  1503. EFFECT_ENUM_BUILDER.addValue("EFFECT_GAME_WIN");
  1504. EFFECT_ENUM_BUILDER.addValue("EFFECT_IGNITION");
  1505. EFFECT_ENUM_BUILDER.addValue("EFFECT_INTERACTIVE_BLAST");
  1506. EFFECT_ENUM_BUILDER.addValue("EFFECT_INTERACTIVE_PREON");
  1507. EFFECT_ENUM_BUILDER.addValue("EFFECT_JAM");
  1508. EFFECT_ENUM_BUILDER.addValue("EFFECT_LOCKUP_BEGIN");
  1509. EFFECT_ENUM_BUILDER.addValue("EFFECT_LOCKUP_END");
  1510. EFFECT_ENUM_BUILDER.addValue("EFFECT_LOW_BATTERY");
  1511. EFFECT_ENUM_BUILDER.addValue("EFFECT_MODE");
  1512. EFFECT_ENUM_BUILDER.addValue("EFFECT_NEWFONT")
  1513. EFFECT_ENUM_BUILDER.addValue("EFFECT_NEXT_QUOTE");
  1514. EFFECT_ENUM_BUILDER.addValue("EFFECT_OFF");
  1515. EFFECT_ENUM_BUILDER.addValue("EFFECT_OFF_CLASH");
  1516. EFFECT_ENUM_BUILDER.addValue("EFFECT_ON");
  1517. EFFECT_ENUM_BUILDER.addValue("EFFECT_PLI_OFF");
  1518. EFFECT_ENUM_BUILDER.addValue("EFFECT_PLI_ON");
  1519. EFFECT_ENUM_BUILDER.addValue("EFFECT_POSTOFF");
  1520. EFFECT_ENUM_BUILDER.addValue("EFFECT_POWERSAVE");
  1521. EFFECT_ENUM_BUILDER.addValue("EFFECT_PREON");
  1522. EFFECT_ENUM_BUILDER.addValue("EFFECT_QUOTE");
  1523. EFFECT_ENUM_BUILDER.addValue("EFFECT_RANGE");
  1524. EFFECT_ENUM_BUILDER.addValue("EFFECT_RELOAD");
  1525. EFFECT_ENUM_BUILDER.addValue("EFFECT_RETRACTION");
  1526. EFFECT_ENUM_BUILDER.addValue("EFFECT_SECONDARY_IGNITION");
  1527. EFFECT_ENUM_BUILDER.addValue("EFFECT_SECONDARY_RETRACTION");
  1528. EFFECT_ENUM_BUILDER.addValue("EFFECT_SOUND_LOOP");
  1529. EFFECT_ENUM_BUILDER.addValue("EFFECT_STAB");
  1530. EFFECT_ENUM_BUILDER.addValue("EFFECT_STUN");
  1531. EFFECT_ENUM_BUILDER.addValue("EFFECT_TRACK");
  1532. EFFECT_ENUM_BUILDER.addValue("EFFECT_TRANSITION_SOUND");
  1533. EFFECT_ENUM_BUILDER.addValue("EFFECT_UNJAM");
  1534. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER1");
  1535. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER2");
  1536. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER3");
  1537. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER4");
  1538. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER5");
  1539. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER6");
  1540. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER7");
  1541. EFFECT_ENUM_BUILDER.addValue("EFFECT_USER8");
  1542. EFFECT_ENUM_BUILDER.addValue("EFFECT_VOLUME_LEVEL");
  1543. // EFFECT_ENUM_BUILDER.addValue("EFFECT_SD_CARD_NOT_FOUND"); /**************************************** Remove unneeded EFFECT_Errror msgs */
  1544. // EFFECT_ENUM_BUILDER.addValue("EFFECT_ERROR_IN_FONT_DIRECTORY");
  1545. // EFFECT_ENUM_BUILDER.addValue("EFFECT_ERROR_IN_BLADE_ARRAY");
  1546. // EFFECT_ENUM_BUILDER.addValue("EFFECT_FONT_DIRECTORY_NOT_FOUND");
  1547. EFFECT_ENUM_BUILDER.build();
  1548.  
  1549. LOCKUP_ENUM_BUILDER = new EnumBuilder("LOCKUP_TYPE", "SaberBase::");
  1550. LOCKUP_ENUM_BUILDER.addValue("LOCKUP_NONE", 0);
  1551. LOCKUP_ENUM_BUILDER.addValue("LOCKUP_NORMAL");
  1552. LOCKUP_ENUM_BUILDER.addValue("LOCKUP_DRAG");
  1553. LOCKUP_ENUM_BUILDER.addValue("LOCKUP_ARMED");
  1554. LOCKUP_ENUM_BUILDER.addValue("LOCKUP_AUTOFIRE");
  1555. LOCKUP_ENUM_BUILDER.addValue("LOCKUP_MELT");
  1556. LOCKUP_ENUM_BUILDER.addValue("LOCKUP_LIGHTNING_BLOCK");
  1557. LOCKUP_ENUM_BUILDER.build();
  1558.  
  1559. ArgumentName_ENUM_BUILDER = new EnumBuilder("ArgumentName");
  1560. ArgumentName_ENUM_BUILDER.addValue("BASE_COLOR_ARG", 1);
  1561. ArgumentName_ENUM_BUILDER.addValue("ALT_COLOR_ARG", 2);
  1562. ArgumentName_ENUM_BUILDER.addValue("STYLE_OPTION_ARG", 3);
  1563. ArgumentName_ENUM_BUILDER.addValue("IGNITION_OPTION_ARG", 4);
  1564. ArgumentName_ENUM_BUILDER.addValue("IGNITION_TIME_ARG", 5);
  1565. ArgumentName_ENUM_BUILDER.addValue("IGNITION_DELAY_ARG", 6);
  1566. ArgumentName_ENUM_BUILDER.addValue("IGNITION_COLOR_ARG", 7);
  1567. ArgumentName_ENUM_BUILDER.addValue("IGNITION_POWER_UP_ARG", 8);
  1568. ArgumentName_ENUM_BUILDER.addValue("BLAST_COLOR_ARG", 9);
  1569. ArgumentName_ENUM_BUILDER.addValue("CLASH_COLOR_ARG", 10);
  1570. ArgumentName_ENUM_BUILDER.addValue("LOCKUP_COLOR_ARG", 11);
  1571. ArgumentName_ENUM_BUILDER.addValue("LOCKUP_POSITION_ARG", 12);
  1572. ArgumentName_ENUM_BUILDER.addValue("DRAG_COLOR_ARG", 13);
  1573. ArgumentName_ENUM_BUILDER.addValue("DRAG_SIZE_ARG", 14);
  1574. ArgumentName_ENUM_BUILDER.addValue("LB_COLOR_ARG", 15);
  1575. ArgumentName_ENUM_BUILDER.addValue("STAB_COLOR_ARG", 16);
  1576. ArgumentName_ENUM_BUILDER.addValue("MELT_SIZE_ARG", 17);
  1577. ArgumentName_ENUM_BUILDER.addValue("SWING_COLOR_ARG", 18);
  1578. ArgumentName_ENUM_BUILDER.addValue("SWING_OPTION_ARG", 19);
  1579. ArgumentName_ENUM_BUILDER.addValue("EMITTER_COLOR_ARG", 20);
  1580. ArgumentName_ENUM_BUILDER.addValue("EMITTER_SIZE_ARG", 21);
  1581. ArgumentName_ENUM_BUILDER.addValue("PREON_COLOR_ARG", 22);
  1582. ArgumentName_ENUM_BUILDER.addValue("PREON_OPTION_ARG", 23);
  1583. ArgumentName_ENUM_BUILDER.addValue("PREON_SIZE_ARG", 24);
  1584. ArgumentName_ENUM_BUILDER.addValue("RETRACTION_OPTION_ARG", 25);
  1585. ArgumentName_ENUM_BUILDER.addValue("RETRACTION_TIME_ARG", 26);
  1586. ArgumentName_ENUM_BUILDER.addValue("RETRACTION_DELAY_ARG", 27);
  1587. ArgumentName_ENUM_BUILDER.addValue("RETRACTION_COLOR_ARG", 28);
  1588. ArgumentName_ENUM_BUILDER.addValue("RETRACTION_COOL_DOWN_ARG", 29);
  1589. ArgumentName_ENUM_BUILDER.addValue("POSTOFF_COLOR_ARG", 30);
  1590. ArgumentName_ENUM_BUILDER.addValue("OFF_COLOR_ARG", 31);
  1591. ArgumentName_ENUM_BUILDER.addValue("OFF_OPTION_ARG", 32);
  1592. ArgumentName_ENUM_BUILDER.addValue("ALT_COLOR2_ARG", 33);
  1593. ArgumentName_ENUM_BUILDER.addValue("ALT_COLOR3_ARG", 34);
  1594. ArgumentName_ENUM_BUILDER.addValue("STYLE_OPTION2_ARG", 35);
  1595. ArgumentName_ENUM_BUILDER.addValue("STYLE_OPTION3_ARG", 36);
  1596. ArgumentName_ENUM_BUILDER.addValue("IGNITION_OPTION2_ARG", 37);
  1597. ArgumentName_ENUM_BUILDER.addValue("RETRACTION_OPTION2_ARG", 38);
  1598. ArgumentName_ENUM_BUILDER.build();
  1599.  
  1600. function effect_to_argument(effect) {
  1601. switch (effect + 0) {
  1602. case EFFECT_CLASH: return CLASH_COLOR_ARG;
  1603. case EFFECT_BLAST: return BLAST_COLOR_ARG;
  1604. case EFFECT_STAB: return STAB_COLOR_ARG;
  1605. case EFFECT_PREON: return PREON_COLOR_ARG;
  1606. case EFFECT_POSTOFF: return POSTOFF_COLOR_ARG;
  1607. }
  1608. return undefined;
  1609. }
  1610.  
  1611. function lockup_to_argument(effect) {
  1612. switch (effect + 0) {
  1613. case LOCKUP_NORMAL: return LOCKUP_COLOR_ARG;
  1614. case LOCKUP_DRAG: return DRAG_COLOR_ARG;
  1615. case LOCKUP_LIGHTNING_BLOCK: return LB_COLOR_ARG;
  1616. }
  1617. return undefined;
  1618. }
  1619.  
  1620. class FUNCTION extends STYLE {
  1621. getType() { return "FUNCTION"; }
  1622. };
  1623.  
  1624. class TIME_FUNCTION extends FUNCTION {
  1625. getType() { return "TIME_FUNCTION"; }
  1626. };
  1627.  
  1628. class TRANSITION extends STYLE {
  1629. getType() { return "TRANSITION"; }
  1630.  
  1631. IS_RUNNING() { return !this.done(); }
  1632. };
  1633.  
  1634. class CONFIG extends STYLE {
  1635. PP(name, note) {
  1636. if (pp_is_url) {
  1637. return this.PPURL.apply(this, arguments);
  1638. }
  1639. var id = this.get_id();
  1640. var ret = "";
  1641. ret += "<span title='"+ note +"'>" + name + "</span>&lt;\n";
  1642. ret += "<div style='margin-left:1em'>\n";
  1643. var comma = false;
  1644. for (var i = 2; i < arguments.length; i += 2) {
  1645. if (comma) ret += ",<br>";
  1646. comma = true;
  1647. var arg = arguments[i];
  1648. var note = arguments[i+1];
  1649. if (typeof(arg) == "number") {
  1650. arg = "" + arg;
  1651. } else {
  1652. arg = arg.pp();
  1653. }
  1654. var comment = arg.COMMENT;
  1655. if (arg.indexOf("<br>") == -1 && arg.indexOf("<div") == -1 && !comment) {
  1656. ret += arg+" /* "+note+" */\n";
  1657. } else {
  1658. ret += "/* "+note+" */<br>\n";
  1659. if (comment) {
  1660. ret += "/* "+comment+" */<br>\n";
  1661. }
  1662. ret += arg;
  1663. }
  1664. }
  1665. ret += "</div>&gt;\n";
  1666.  
  1667. return ret;
  1668. }
  1669. getType() { return "CONFIG"; }
  1670. };
  1671.  
  1672. function FixColor(c) {
  1673. return min(65535, Math.floor(Math.pow(parseInt(c, 16) / 255.0, 2.2) * 65536));
  1674. }
  1675.  
  1676. function hex2(N) {
  1677. var ret = N.toString(16);
  1678. if (ret.length < 2) ret = "0" + ret;
  1679. return ret;
  1680. }
  1681.  
  1682. function UnFixColor(c) {
  1683. return hex2(min(255, Math.floor(Math.pow(parseInt(c) / 65535.0, 1.0/2.2) * 255)));
  1684. }
  1685.  
  1686. function ClickColor() {
  1687. var color_button = FIND("COLOR");
  1688. color_button.addEventListener("input", ClickColor, false);
  1689. var R = FixColor(color_button.value.substr(1,2));
  1690. var G = FixColor(color_button.value.substr(3,2));
  1691. var B = FixColor(color_button.value.substr(5,2));
  1692. SetTo("Rgb16<"+R+","+G+","+B+">");
  1693. }
  1694.  
  1695. //var qlinks = "<b>Colors</b> <input type=color id=COLOR value='#ff0000' onclick='ClickColor()' />";
  1696. //var effect_links = "<b>Effects:</b>";
  1697. //var layer_links = "";
  1698. //var effect_type_links = "<b>Effect Types:</b>";
  1699. //var template_links = "<b>Templates:</b>";
  1700. //var function_links = "<b>Functions:</b>";
  1701. //var transition_links = "<b>Transitions:</b>";
  1702.  
  1703. var qlinks = [];
  1704. var effect_links = [];
  1705. var layer_links = [];
  1706. var effect_type_links = []
  1707. var template_links = [];
  1708. var function_links = []
  1709. var transition_links = [];
  1710.  
  1711. var all_colors = {};
  1712. var colorNames = {};
  1713.  
  1714. class RgbClass extends STYLE {
  1715. constructor(r,g,b,a) {
  1716. super();
  1717. this.r = IntArg(r)/255.0;
  1718. this.g = IntArg(g)/255.0;
  1719. this.b = IntArg(b)/255.0;
  1720. if (this.r < 0) throw "Red is negative";
  1721. if (this.g < 0) throw "Blue is negative";
  1722. if (this.b < 0) throw "Green is negative";
  1723. if (this.r > 1.0) throw "Red too big.";
  1724. if (this.g > 1.0) throw "Green too big.";
  1725. if (this.b > 1.0) throw "Blue too big.";
  1726. if (a == undefined) {
  1727. this.a = 1.0;
  1728. this.name = colorNames[r+","+g+","+b]
  1729. } else {
  1730. this.a = a;
  1731. }
  1732. }
  1733. run(blade) {}
  1734. getColor(led) {
  1735. return this;
  1736. }
  1737. pp() {
  1738. if (this.name) return this.PPshort(this.name,"Color");
  1739. return this.PPshort("Rgb", "RGB Color",
  1740. Math.round(this.r*255), "Red component",
  1741. Math.round(this.g*255), "Green component",
  1742. Math.round(this.b*255), "Blue component");
  1743. }
  1744. mix(other, blend) {
  1745. var ret = new RgbClass(0,0,0);
  1746. ret.r = other.r * blend + this.r * (1.0 - blend);
  1747. ret.g = other.g * blend + this.g * (1.0 - blend);
  1748. ret.b = other.b * blend + this.b * (1.0 - blend);
  1749. ret.a = other.a * blend + this.a * (1.0 - blend);
  1750. return ret;
  1751. }
  1752. multiply(v) {
  1753. var ret = new RgbClass(0,0,0);
  1754. ret.r = this.r * v;
  1755. ret.g = this.g * v;
  1756. ret.b = this.b * v;
  1757. ret.a = this.a * v;
  1758. return ret;
  1759. }
  1760. paintOver(other) {
  1761. var ret = new RgbClass(0,0,0);
  1762. ret.r = this.r * (1.0 - other.a) + other.r;
  1763. ret.g = this.g * (1.0 - other.a) + other.g;
  1764. ret.b = this.b * (1.0 - other.a) + other.b;
  1765. ret.a = this.a * (1.0 - other.a) + other.a;
  1766. return ret;
  1767. }
  1768.  
  1769. // angle = 0 - 98304 (32768 * 3) (non-inclusive)
  1770. rotate(angle) {
  1771. var H;
  1772. if (angle == 0) return this;
  1773. var MAX = max(this.r, this.g, this.b);
  1774. var MIN = min(this.r, this.g, this.b);
  1775. var C = MAX - MIN;
  1776. if (C == 0) return this; // Can't rotate something without color.
  1777. // Note 16384 = 60 degrees.
  1778. if (this.r == MAX) {
  1779. // r is biggest
  1780. H = (this.g - this.b) / C;
  1781. } else if (this.g == MAX) {
  1782. // g is biggest
  1783. H = (this.b - this.r) / C + 2;
  1784. } else {
  1785. // b is biggest
  1786. H = (this.r - this.g) / C + 4;
  1787. }
  1788. H += angle / 16384.0;
  1789. return new RgbClass(f(5+H, C, MAX), f(3+H, C, MAX), f(1+H, C, MAX));
  1790. }
  1791.  
  1792. argify(state) {
  1793. if (state.color_argument) {
  1794. ret = RgbArg_(ArgumentName(state.color_argument), this);
  1795. state.color_argument = false;
  1796. return ret;
  1797. } else {
  1798. return this;
  1799. }
  1800. }
  1801. };
  1802.  
  1803. function f(n, C, MAX) {
  1804. var k = n % 6;
  1805. var x = MAX - C * clamp(min(k, 4 - k), 0, 1);
  1806. return x*255.0;
  1807. }
  1808.  
  1809. function Rgb(r,g,b) {
  1810. return new RgbClass(r,g,b);
  1811. }
  1812.  
  1813. function Transparent(r,g,b) {
  1814. var ret = Rgb(0,0,0)
  1815. ret.a = 0.0;
  1816. return ret;
  1817. }
  1818.  
  1819. class Rgb16Class extends RgbClass {
  1820. constructor(r,g,b) {
  1821. super(r * 255.0/65535.0,g * 255.0/65535.0,b * 255.0/65535.0);
  1822. // this.name = colorNames[r+","+g+","+b]
  1823. // this.name
  1824. }
  1825. run(blade) {}
  1826. getColor(led) {
  1827. return this;
  1828. }
  1829. pp() {
  1830. if (this.name) return this.PPshort(this.name,"Color");
  1831. return this.PPshort("Rgb16", "RGB Color",
  1832. Math.round(this.r*65535), "Red component",
  1833. Math.round(this.g*65535), "Green component",
  1834. Math.round(this.b*65535), "Blue component");
  1835. }
  1836. };
  1837.  
  1838. function RgbF(r,g,b) {
  1839. return new Rgb16Class(r * 65535,g * 65535,b * 65535);
  1840. }
  1841.  
  1842.  
  1843. function Rgb16(r,g,b) {
  1844. return new Rgb16Class(r,g,b);
  1845. }
  1846.  
  1847. class AlphaLClass extends STYLE {
  1848. isEffect() { return this.ALPHA.isEffect(); }
  1849. constructor(COLOR, ALPHA) {
  1850. super("Makes transparent color", Array.from(arguments));
  1851. this.add_arg("COLOR", "COLOR", "COLOR");
  1852. this.add_arg("ALPHA", "FUNCTION", "Alpha function");
  1853. }
  1854. getColor(led) {
  1855. var ret = this.COLOR.getColor(led);
  1856. if (ret == 0) return Transparent(0,0,0);
  1857. return ret.multiply(this.ALPHA.getInteger(led)/32768.0)
  1858. }
  1859. IS_RUNNING() {
  1860. if (this.ALPHA.IS_RUNNING)
  1861. return this.ALPHA.IS_RUNNING();
  1862. if (this.COLOR.IS_RUNNING)
  1863. return this.COLOR.IS_RUNNING();
  1864. return false;
  1865. }
  1866. };
  1867.  
  1868. function AlphaL(COLOR, ALPHA) {
  1869. return new AlphaLClass(COLOR, ALPHA);
  1870. }
  1871.  
  1872. class AlphaMixLClass extends MACRO {
  1873. constructor(ARGS) {
  1874. super("Mix and alpha", ARGS);
  1875. this.COLORS = Array.from(ARGS).slice(1);
  1876. this.add_arg("F", "FUNCTION", "0=first color, 32768=last color");
  1877. for (var i = 1; i < this.COLORS.length + 1; i++)
  1878. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  1879. this.SetExpansion(AlphaL(new MixClass(ARGS), this.F.DOCOPY()));
  1880. }
  1881. }
  1882.  
  1883. function AlphaMixL(F, C1, C2) {
  1884. return new AlphaMixLClass(Array.from(arguments));
  1885. };
  1886.  
  1887. function ReplaceNode(old_node, new_node) {
  1888. FocusOnLow(old_node.get_id());
  1889. pp_is_url++;
  1890. FIND("style").value = new_node.pp();
  1891. pp_is_url--;
  1892. Run();
  1893. }
  1894.  
  1895. function DuplicateLayer(id, arg, event) {
  1896. event.stopPropagation();
  1897. console.log("DuplicateLayer: "+id +", "+arg);
  1898. arg-=2;
  1899. var layer = style_ids[id];
  1900. var new_layer = new LayersClass( [layer.BASE].concat(layer.LAYERS.slice(0, arg), [layer.LAYERS[arg].DOCOPY()], layer.LAYERS.slice(arg)) );
  1901. ReplaceNode(layer, new_layer);
  1902. }
  1903.  
  1904. function RemoveLayer(id, arg, event) {
  1905. event.stopPropagation();
  1906. console.log("RemoveLayer: "+id +", "+arg);
  1907. arg-=2;
  1908. var layer = style_ids[id];
  1909. var new_layer = new LayersClass( [layer.BASE].concat(layer.LAYERS.slice(0, arg), layer.LAYERS.slice(arg+1)) );
  1910. ReplaceNode(layer, new_layer);
  1911. }
  1912.  
  1913. function DownLayer(id, arg, event) {
  1914. event.stopPropagation();
  1915. console.log("DownLayer: "+id +", "+arg);
  1916. arg-=2;
  1917. var layer = style_ids[id];
  1918. var new_layer = new LayersClass( [layer.BASE].concat(layer.LAYERS.slice(0, arg),
  1919. [layer.LAYERS[arg+1], layer.LAYERS[arg]],
  1920. layer.LAYERS.slice(arg+2)) );
  1921. ReplaceNode(layer, new_layer);
  1922. }
  1923.  
  1924. function UpLayer(id, arg, event) {
  1925. console.log("UpLayer: "+id +", "+arg);
  1926. DownLayer(id, arg-1, event);
  1927. }
  1928.  
  1929. class LayersClass extends STYLE {
  1930. Indent(text) {
  1931. if (text.substr(0, 2) == '/*') {
  1932. var tmp = text.split('*/');
  1933. if (tmp[1][0] != '\n') tmp[1] = '\n' + tmp[1].trimStart();
  1934. text = tmp.join('*/');
  1935. }
  1936. return "\n " + text.split("\n").join("\n ");
  1937. }
  1938. extraButtons(arg) {
  1939. if (arg == 1) return "";
  1940. var id = this.get_id();
  1941. var ret = "<button onclick='DuplicateLayer("+id+","+arg+",event)'>+</button>";
  1942. ret += "<button onclick='RemoveLayer("+id+","+arg+",event)'>X</button>";
  1943. if (arg > 2) ret += "<button onclick='UpLayer("+id+","+arg+",event)'>&#5169;</button>";
  1944. if (arg <= this.LAYERS.length) ret += "<button onclick='DownLayer("+id+","+arg+",event)'>&#5167;</button>";
  1945. return ret;
  1946. }
  1947. constructor(ARGS) {
  1948. super("Mix alpha-blended layers", ARGS);
  1949. this.LAYERS = Array.from(ARGS).slice(1);
  1950. this.add_arg("BASE", "COLOR", "Base layer");
  1951. for (var i = 1; i < this.LAYERS.length + 1; i++)
  1952. this.add_arg("LAYER" + i, "COLOR", "Layer " + i);
  1953. }
  1954. getColor(led) {
  1955. var ret = this.BASE.getColor(led);
  1956. for (var i = 0; i < this.LAYERS.length; i++) {
  1957. ret = ret.paintOver(this.LAYERS[i].getColor(led));
  1958. }
  1959. return ret;
  1960. }
  1961. argify(state) {
  1962. this.BASE = this.BASE.argify(state);
  1963. state.color_argument = false;
  1964. var ret = super.argify(state);
  1965. state.color_argument = false;
  1966. return ret;
  1967. }
  1968. }
  1969.  
  1970. function Layers(BASE, Layer1, Layer2) {
  1971. return new LayersClass(Array.from(arguments));
  1972. }
  1973.  
  1974.  
  1975. function enc(s) {
  1976. return s.replace(/</g, "&lt;").replace(/>/g, "&gt;");
  1977. }
  1978. function encstr(s) {
  1979. return s.replace("\n", "\\n");
  1980. }
  1981.  
  1982. function mkbutton2(name, val) {
  1983. return "<input type=button class=btn onclick='SetToAndFormat(\""+val+"\")' value='"+enc(name)+"'>\n";
  1984. // return "<span class=btn onclick='SetTo(\""+name+"\")'>"+enc(name)+"</span>\n";
  1985. }
  1986. function mkbutton(name) {
  1987. return mkbutton2(name, name);
  1988. // return "<input type=button class=btn onclick='SetTo(\""+name+"\")' value='"+enc(name)+"'>\n";
  1989. // return "<span class=btn onclick='SetTo(\""+name+"\")'>"+enc(name)+"</span>\n";
  1990. }
  1991.  
  1992.  
  1993. function AddTemplate(name) {
  1994. var val = name;
  1995. if (name.length > 40) {
  1996. name = name.slice(0,40) + '...';
  1997. }
  1998. template_links.push( mkbutton2(name, val) );
  1999. }
  2000. function AddEffect(val) {
  2001. var name = val.split("<")[0];
  2002. effect_links.push( mkbutton2(name, val) );
  2003. }
  2004. function AddLayer(val) {
  2005. var name = val.split("<")[0];
  2006. layer_links.push( mkbutton2(name, val) );
  2007. }
  2008. function AddFunction(val) {
  2009. var name = val.split("<")[0];
  2010. function_links.push( mkbutton2(name, val) );
  2011. }
  2012. function AddTransition(val) {
  2013. var name = val.split("<")[0];
  2014. transition_links.push( mkbutton2(name, val) );
  2015. }
  2016. function AddEffectWL(val) {
  2017. AddEffect(val);
  2018. val=val.slice(0, val.length-1);
  2019. var tmp1 = val.split("<");
  2020. var tmp2 = val.split(",");
  2021. AddLayer(tmp1[0] + "L<" + tmp2.slice(1).join(",") + ">")
  2022. }
  2023. function AddEffectWLF(val) {
  2024. AddEffect(val);
  2025. val=val.slice(0, val.length-1);
  2026. var tmp1 = val.split("<");
  2027. var tmp2 = val.split(",");
  2028. AddLayer(tmp1[0] + "L<" + tmp2.slice(1).join(",") + ">")
  2029. AddFunction(tmp1[0] + "F<" + tmp2.slice(2).join(",") + ">")
  2030. }
  2031.  
  2032. var history_html = "";
  2033. function AddHistory(name, type) {
  2034. var label = name;
  2035. if (label.length > 80) label = label.slice(0,78) + "...";
  2036. name = name.split("\n").join(" ").split(" ").join(" ").split(" ").join(" ").split("< ").join("<");
  2037. var btn = "<input type=button class=btn onclick='SetToAndFormat(\""+name+"\")' value='"+enc(label)+"'>\n";
  2038. var tag = "<span class=MAGIC_CLASS_"+type+">" + btn + "</span>\n";
  2039. history_html = tag + history_html.replace(tag, "");
  2040. FIND("history_tabcontent").innerHTML = history_html;
  2041. }
  2042.  
  2043. function mapcolor(x) {
  2044. x /= 255.0;
  2045. x = Math.pow(x, 1.0/2.2);
  2046. return Math.round(x * 255);
  2047. }
  2048. function mkcolorbutton(name, r, g, b) {
  2049. r = mapcolor(r);
  2050. g = mapcolor(g);
  2051. b = mapcolor(b);
  2052. var color = "rgb("+r+","+g+","+b+")";
  2053. if (r == 0 && g == 0 && b == 0) color = "white";
  2054. return "<input type=button style='background:"+color+"' class=btn onclick='SetTo(\""+name+"\")' value='"+enc(name)+"'>\n";
  2055. }
  2056. function AddColor(name, r, g, b) {
  2057. colorNames[r+","+g+","+b] = name;
  2058. qlinks.push(mkcolorbutton(name, r, g, b));
  2059. all_colors[name] = new RgbClass(r, g, b);
  2060. }
  2061.  
  2062. AddTemplate("InOutHelper<SimpleClash<Lockup<Blast<Blue,White>,AudioFlicker<Blue,White>>,White>, 300, 800>");
  2063. // AddTemplate("StyleFirePtr<Red, Yellow>");
  2064. AddTemplate("InOutHelper<EasyBlade<OnSpark<Green>, White>, 300, 800>>");
  2065. AddTemplate("InOutHelper<EasyBlade<Sparkle<Blue>, White>, 300, 800>>");
  2066. AddTemplate("IgnitionDelay<500, InOutHelper<EasyBlade<OnSpark<Green>, White>, 300, 800>>>");
  2067. AddTemplate("RetractionDelay<500, InOutHelper<EasyBlade<OnSpark<Green>, White>, 300, 800>>>");
  2068. AddTemplate("StyleNormalPtr<AudioFlicker<Yellow, White>, Blue, 300, 800>");
  2069. AddTemplate("InOutSparkTip<EasyBlade<Magenta, White>, 300, 800>>");
  2070. AddTemplate("StyleNormalPtr<Gradient<Red, Blue>, Gradient<Cyan, Yellow>, 300, 800>");
  2071. AddTemplate("StyleNormalPtr<Pulsing<Red, Rgb<50,0,0>, 5000>, White, 300, 800, Red>");
  2072. AddTemplate("StyleRainbowPtr<300, 800>");
  2073. AddTemplate("StyleStrobePtr<White, Rainbow, 15, 300, 800>");
  2074. AddTemplate("StyleFirePtr<Red, Yellow>");
  2075. AddTemplate("Layers<Red, ResponsiveLockupL<White, TrInstant, TrInstant, Int<26000>, Int<6000>>,ResponsiveLightningBlockL<White, TrInstant, TrInstant>,ResponsiveMeltL<Mix<TwistAngle<>,Red,Yellow>, TrWipeIn<600>, TrWipe<600>, Int<4000>, Int<10000>>,ResponsiveDragL<White, TrInstant, TrInstant, Int<2000>, Int<10000>>,ResponsiveClashL<White, TrInstant, TrFade<200>, Int<26000>, Int<6000>>,ResponsiveBlastL<White, Int<400>, Int<100>, Int<400>, Int<28000>, Int<8000>>,ResponsiveBlastWaveL<White, Int<400>, Int<100>, Int<400>, Int<28000>, Int<8000>>,ResponsiveBlastFadeL<White, Int<8000>, Int<400>, Int<28000>, Int<8000>>,ResponsiveStabL<White, TrWipeIn<600>, TrWipe<600>, Int<14000>, Int<8000>>,InOutTrL<TrWipe<300>, TrWipeIn<500>>>");
  2076.  
  2077.  
  2078. AddLayer("AlphaL<Red, Int<16000>>");
  2079. AddLayer("AlphaMixL<Bump<Int<16384>,Int<16384>>,Red,Green,Blue>");
  2080. AddEffectWL("AudioFlicker<White, Blue>");
  2081. AddEffectWLF("Blast<Blue, White>");
  2082. AddEffectWL("BlastFadeout<Blue, White>");
  2083. AddEffect("Blinking<Red, Blue, 1000, 500>");
  2084. AddLayer("BlinkingL<Blue, Int<1000>, Int<500>>");
  2085. AddEffect("BrownNoiseFlicker<Green, Magenta, 50>");
  2086. AddLayer("BrownNoiseFlickerL<Magenta, Int<50>>");
  2087. AddEffect("ColorChange<TrInstant, Red, Green, Blue>");
  2088. AddEffect("ColorSelect<Variation, TrInstant, Red, Green, Blue>");
  2089. AddFunction("IntSelect<Variation, 0, 8192,32768>");
  2090. AddEffect("ColorCycle<Blue, 0, 1, Cyan, 100, 3000, 5000>");
  2091. AddEffect("ColorSequence<500, Red, Green, Blue>");
  2092. AddEffect("EffectSequence<EFFECT_CLASH, Red, Green, Blue>");
  2093. AddEffect("Cylon<Red, 5, 20>");
  2094. AddEffect("Gradient<Blue, Green, Yellow, Red>");
  2095. AddEffect("Gradient<Red, Blue, Green>");
  2096. AddEffect("Gradient<Red, Blue>");
  2097. AddEffect("Hue<16384>");
  2098. AddEffectWL("HumpFlicker<Green, Magenta, 50>");
  2099. AddEffect("InOutHelper<White, 300, 800, Black>");
  2100. AddEffect("InOutSparkTip<Red, 1000, 800, White>");
  2101. AddEffect("InOutTr<Green, TrColorCycle<3000>, TrFade<500>>");
  2102. AddEffect("Layers<Green, AlphaL<Red, Int<16000>>>");
  2103. AddEffectWL("LocalizedClash<Red, White>");
  2104. AddEffectWL("Lockup<Green, Red>");
  2105. AddEffectWL("LockupTr<Red, White, TrFade<100>, TrFade<100>, SaberBase::LOCKUP_MELT>");
  2106. AddEffect("Mix<Int<16384>, Red, Blue>");
  2107. AddEffect("OnSpark<Green, White, 200>");
  2108. AddLayer("OnSparkL<White, Int<200>>");
  2109. AddEffectWL("OriginalBlast<Blue, White>");
  2110. AddEffect("Pulsing<Blue, Red, 800>");
  2111. AddLayer("PulsingL<Red, Int<800>>");
  2112. AddEffect("Rainbow");
  2113. AddEffect("Remap<SmoothStep<Sin<Int<10>>, Sin<Int<7>>>, Rainbow>");
  2114. AddEffect("RandomBlink<3000>");
  2115. AddLayer("RandomBlinkL<Int<3000>, Green>");
  2116. AddEffect("RandomFlicker<Yellow, Blue>");
  2117. AddLayer("RandomL<Blue>");
  2118. AddEffectWL("RandomPerLEDFlicker<Green, Magenta>");
  2119. AddEffect("Rgb16<0,0,65536>");
  2120. AddEffect("Rgb<100,100,100>");
  2121. AddEffect("RgbCycle");
  2122. AddEffect("RotateColorsX<Variation,Red>");
  2123. AddEffect("Sequence<Red, Black, 100, 37, 0b0001010100011100, 0b0111000111000101, 0b0100000000000000>");
  2124. AddLayer("SequenceL<Red, 100, 37, 0b0001010100011100, 0b0111000111000101, 0b0100000000000000>");
  2125. AddEffectWL("SimpleClash<Red, White, 40>");
  2126. AddEffect("Sparkle<Blue>");
  2127. AddLayer("SparkleL");
  2128. AddEffect("Stripes<1000, 1000, Cyan, Magenta, Yellow, Blue>");
  2129. AddEffect("Strobe<Black, White, 15, 1>");
  2130. AddLayer("StrobeL<White, Int<15>, Int<1>>");
  2131. AddEffect("StyleFire<Blue, Cyan>");
  2132. AddEffect("MultiTransitionEffect<Blue, White, TrWipe<50>, TrWipe<50>, EFFECT_BLAST>");
  2133. AddEffect("TransitionEffect<Blue,Green,TrFade<500>,TrBoing<500,3>,EFFECT_BLAST>");
  2134. AddEffectWL("TransitionLoop<Blue, TrConcat<TrFade<200>, Red, TrFade<200>>>");
  2135. AddFunction("BendTimePow<1000, 16384>");
  2136. AddFunction("BendTimePowInv<1000, 16384>");
  2137. AddFunction("ReverseTime<1000, 16384>");
  2138.  
  2139. AddEffect("IgnitionDelay<500, InOutHelper<EasyBlade<OnSpark<Green>, White>, 300, 800>>>");
  2140. AddEffect("RetractionDelay<500, InOutHelper<EasyBlade<OnSpark<Green>, White>, 300, 800>>>");
  2141.  
  2142.  
  2143. AddLayer("TransitionEffectL<TrConcat<TrWipe<50>, White, TrWipe<50>>, EFFECT_BLAST>");
  2144. AddLayer("MultiTransitionEffectL<TrConcat<TrWipe<50>, White, TrWipe<50>>, EFFECT_BLAST>");
  2145. AddLayer("TransitionPulseL<TrConcat<TrFade<200>, Red, TrFade<200>>, ThresholdPulseF<Saw<Int<60>>, Int<16384>>>")
  2146.  
  2147. AddTransition("TrBoing<300, 2>");
  2148. AddTransition("TrBlink<1000, 3>");
  2149. AddTransition("TrColorCycle<3000>");
  2150. AddTransition("TrConcat<TrFade<100>, White, TrFade<100>>");
  2151. AddTransition("TrDelay<500>");
  2152. AddTransition("TrFade<300>");
  2153. AddTransition("TrInstant");
  2154. AddTransition("TrJoin<TrFade<500>, TrWipe<500>>");
  2155. AddTransition("TrJoinR<TrFade<500>, TrWipe<500>>");
  2156. AddTransition("TrRandom<TrFade<500>, TrWipe<500>, TrBoing<500, 2>>");
  2157. AddTransition("TrSelect<Variation,TrFade<500>, TrWipe<500>, TrBoing<500, 2>>");
  2158. AddTransition("TrSmoothFade<300>");
  2159. AddTransition("TrWipe<500>");
  2160. AddTransition("TrWipeIn<500>");
  2161. AddTransition("TrCenterWipe<500>");
  2162. AddTransition("TrCenterWipeSpark<WHITE, 500>");
  2163. AddTransition("TrCenterWipeIn<500>");
  2164. AddTransition("TrCenterWipeInSpark<WHITE, 500>");
  2165. AddTransition("TrWaveX<White>");
  2166. AddTransition("TrSparkX<White>");
  2167. AddTransition("TrWipeSparkTip<White, 300>");
  2168. AddTransition("TrWipeInSparkTip<White, 300>");
  2169. AddTransition("TrWipeSparkTipX<White, Int<300>>");
  2170. AddTransition("TrWipeInSparkTipX<White, Int<300>>");
  2171. AddTransition("TrExtend<1000, TrFade<500>>");
  2172. AddTransition("TrLoop<TrFade<500>>");
  2173. AddTransition("TrLoopN<5, TrFade<500>>");
  2174. AddTransition("TrLoopUntil<EffectPulseF<EFFECT_CLASH>, TrConcat<TrFade<500>, Green, TrFade<500>>, TrFade<100>>");
  2175. AddTransition("TrDoEffect<TrFade<100>, EFFECT_BLAST>");
  2176. AddTransition("TrDoEffectAlways<TrFade<100>, EFFECT_BLAST>");
  2177.  
  2178. AddFunction("BatteryLevel");
  2179. AddFunction("VolumeLevel");
  2180. AddFunction("BlinkingF<Int<1000>, Int<500>>");
  2181. AddFunction("BrownNoiseF<Int<50>>");
  2182. AddFunction("HumpFlickerF<50>");
  2183. AddFunction("NoisySoundLevel");
  2184. AddFunction("NoisySoundLevelCompat");
  2185. AddFunction("SmoothSoundLevel");
  2186. AddFunction("SwingSpeed<250>");
  2187. AddFunction("SwingAcceleration<130>");
  2188. AddFunction("ClashImpactF<>");
  2189. AddFunction("Bump<Int<16384>>");
  2190. AddFunction("Ifon<Int<0>, Int<32768>>");
  2191. AddFunction("IgnitionTime<>");
  2192. AddFunction("RetractionTime<>");
  2193. AddFunction("InOutFunc<300, 800>");
  2194. AddFunction("InOutHelperF<InOutFunc<300, 800>>");
  2195. AddFunction("Int<32768>");
  2196. AddFunction("Scale<Sin<Int<10>>,Int<0>,Int<4000>>");
  2197. AddFunction("InvertF<Ifon<Int<0>, Int<32768>>>");
  2198. AddFunction("Sin<Int<10>>");
  2199. AddFunction("Saw<Int<10>>");
  2200. AddFunction("SmoothStep<Sin<Int<10>>, Sin<Int<7>>>");
  2201. AddFunction("Trigger<EFFECT_FORCE, Int<500>, Int<1000>, Int<500>>");
  2202. AddFunction("ChangeSlowly<NoisySoundLevel, Int<50000>>");
  2203. AddFunction("SlowNoise<Int<1000>>");
  2204. AddFunction("IsLessThan<SwingSpeed<250>, Int<100>>");
  2205. AddFunction("IsGreaterThan<SwingSpeed<250>, Int<100>>");
  2206. AddFunction("IsBetween<SwingSpeed<250>, Int<100>, Int<120>>");
  2207. AddFunction("ClampF<RandomPerLEDF, 8000, 12000>");
  2208. AddFunction("LayerFunctions<Bump<Int<0>>, Bump<Int<32768>>>");
  2209. AddFunction("OnSparkF<Int<200>>");
  2210. AddFunction("PulsingF<Int<800>>");
  2211. AddFunction("RandomBlinkF<Int<3000>>");
  2212. AddFunction("RandomF");
  2213. AddFunction("RandomPerLEDF");
  2214. AddFunction("SequenceF<100, 37, 0b0001010100011100, 0b0111000111000101, 0b0100000000000000>");
  2215. AddFunction("SparkleF");
  2216. AddFunction("StrobeF<Int<15>, Int<1>>");
  2217. AddFunction("BlastFadeoutF");
  2218. AddFunction("OriginalBlastF");
  2219. AddFunction("Variation");
  2220. AddFunction("AltF");
  2221. AddFunction("SyncAltToVarianceF");
  2222. AddFunction("TwistAngle<>");
  2223. AddFunction("TwistAcceleration<>");
  2224. AddFunction("BladeAngle<>");
  2225. AddFunction("Sum<RandomPerLEDF, Bump<Int<16384>>>");
  2226. AddFunction("Subtract<RandomPerLEDF, Bump<Int<16384>>>");
  2227. AddFunction("Mult<RandomPerLEDF, Bump<Int<16384>>>");
  2228. AddFunction("Percentage<RandomPerLEDF, 20>");
  2229. AddFunction("Divide<RandomPerLEDF, Int<10>>");
  2230. AddFunction("ModF<Sin<Int<10>>, Int<8192>>");
  2231. AddFunction("HoldPeakF<RandomF, Int<300>, Int<32768>>");
  2232. AddFunction("CenterDistF<>");
  2233. AddFunction("EffectPosition<>");
  2234. AddFunction("TimeSinceEffect<>");
  2235. AddFunction("WavNum<>");
  2236. AddFunction("WavLen<>");
  2237. AddFunction("CircularSectionF<Sin<Int<3>>, Sin<Int<2>>>");
  2238. AddFunction("LinearSectionF<Sin<Int<3>>, Sin<Int<2>>>");
  2239. AddFunction("EffectRandomF<EFFECT_CLASH>");
  2240. AddFunction("EffectPulseF<EFFECT_CLASH>");
  2241. AddFunction("IncrementWithReset<EffectPulseF<EFFECT_CLASH>>");
  2242. AddFunction("IncrementModuloF<EffectPulseF<EFFECT_CLASH>>");
  2243. AddFunction("ThresholdPulseF<Saw<Int<60>>, Int<16384>>");
  2244. AddFunction("IncrementF<Saw<Int<60>>, Int<16384>, Int<32768>, Int<1024>>");
  2245. AddFunction("EffectIncrementF<EFFECT_CLASH, Int<32768>, Int<8192>>");
  2246. AddFunction("MarbleF<Int<-2000>, Int<40000>, Ifon<Int<827680>, Int<0>>, Int<1276800>>");
  2247.  
  2248. AddColor("AliceBlue", 223, 239, 255);
  2249. AddColor("Aqua", 0, 255, 255);
  2250. AddColor("Aquamarine", 55, 255, 169);
  2251. AddColor("Azure", 223, 255, 255);
  2252. AddColor("Bisque", 255, 199, 142);
  2253. AddColor("Black", 0, 0, 0);
  2254. AddColor("BlanchedAlmond", 255, 213, 157);
  2255. AddColor("Blue", 0, 0, 255);
  2256. AddColor("Chartreuse", 55, 255, 0);
  2257. AddColor("Coral", 255, 55, 19);
  2258. AddColor("Cornsilk", 255, 239, 184);
  2259. AddColor("Cyan", 0, 255, 255);
  2260. AddColor("DarkOrange", 255, 68, 0);
  2261. AddColor("DeepPink", 255, 0, 75);
  2262. AddColor("DeepSkyBlue", 0, 135, 255);
  2263. AddColor("DodgerBlue", 2, 72, 255);
  2264. AddColor("FloralWhite", 255, 244, 223);
  2265. AddColor("GhostWhite", 239, 239, 255);
  2266. AddColor("Green", 0, 255, 0);
  2267. AddColor("GreenYellow", 108, 255, 6);
  2268. AddColor("HoneyDew", 223, 255, 223);
  2269. AddColor("HotPink", 255, 36, 118);
  2270. AddColor("Ivory", 255, 255, 223);
  2271. AddColor("LavenderBlush", 255, 223, 233);
  2272. AddColor("LemonChiffon", 255, 244, 157);
  2273. AddColor("LightCyan", 191, 255, 255);
  2274. AddColor("LightPink", 255, 121, 138);
  2275. AddColor("LightSalmon", 255, 91, 50);
  2276. AddColor("LightYellow", 255, 255, 191);
  2277. AddColor("Magenta", 255, 0, 255);
  2278. AddColor("MintCream", 233, 255, 244);
  2279. AddColor("MistyRose", 255, 199, 193);
  2280. AddColor("Moccasin", 255, 199, 119);
  2281. AddColor("NavajoWhite", 255, 187, 108);
  2282. AddColor("Orange", 255, 97, 0);
  2283. AddColor("OrangeRed", 255, 14, 0);
  2284. AddColor("PapayaWhip", 255, 221, 171);
  2285. AddColor("PeachPuff", 255, 180, 125);
  2286. AddColor("Pink", 255, 136, 154);
  2287. AddColor("Red", 255, 0, 0);
  2288. AddColor("SeaShell", 255, 233, 219);
  2289. AddColor("Snow", 255, 244, 244);
  2290. AddColor("SpringGreen", 0, 255, 55);
  2291. AddColor("SteelBlue", 14, 57, 118);
  2292. AddColor("Tomato", 255, 31, 15);
  2293. AddColor("White", 255, 255, 255);
  2294. AddColor("Yellow", 255, 255, 0);
  2295.  
  2296. AddLayer("InOutHelperL<InOutFuncX<Int<300>,Int<800>>>");
  2297. AddLayer("InOutTrL<TrWipe<300>,TrWipeIn<500>>");
  2298.  
  2299. AddLayer("ResponsiveLockupL<White, TrInstant, TrInstant, Int<26000>, Int<6000>>");
  2300. AddLayer("ResponsiveLightningBlockL<White, TrInstant, TrInstant>");
  2301. AddLayer("ResponsiveMeltL<Mix<TwistAngle<>,Red,Yellow>, TrInstant, TrInstant, Int<4000>, Int<10000>>");
  2302. AddLayer("ResponsiveDragL<White, TrInstant, TrInstant, Int<2000>, Int<10000>>");
  2303. AddLayer("ResponsiveClashL<White, TrInstant, TrFade<200>, Int<26000>, Int<6000>>");
  2304. AddLayer("ResponsiveBlastL<White, Int<400>, Int<100>, Int<400>, Int<28000>, Int<8000>>");
  2305. AddLayer("ResponsiveBlastWaveL<White, Int<400>, Int<100>, Int<400>, Int<28000>, Int<8000>>");
  2306. AddLayer("ResponsiveBlastFadeL<White, Int<8000>, Int<400>, Int<28000>, Int<8000>>");
  2307. AddLayer("ResponsiveStabL<White, TrWipeIn<600>, TrWipe<600>, Int<14000>, Int<8000>>");
  2308. AddLayer("SyncAltToVarianceL");
  2309.  
  2310. var WHITE = Rgb(255,255,255);
  2311. var RED = Rgb(255,0,0);
  2312. var GREEN = Rgb(0,255,0);
  2313. var BLUE = Rgb(0,0,255);
  2314. var YELLOW = Rgb(255,255,0);
  2315. var CYAN = Rgb(0,255,255);
  2316. var MAGENTA = Rgb(255,0,255);
  2317. var WHITE = Rgb(255,255,255);
  2318. var BLACK = Rgb(0,0,0);
  2319. var OrangeRed = Rgb(255,14,0);
  2320.  
  2321.  
  2322. //--
  2323. class RainbowClass extends STYLE {
  2324. constructor() {
  2325. super("Scrolling color rainbow", arguments);
  2326. }
  2327. run(blade) {
  2328. this.m = millis();
  2329. }
  2330. getColor(led) {
  2331. return RgbF(max(0.0, sin( (this.m * 3.0 + led * 50.0) % 1024.0 * Math.PI * 2.0 / 1000.0)),
  2332. max(0.0, sin( (this.m * 3.0 + led * 50.0 + 1024.0/3.0) % 1024.0 * Math.PI * 2.0 / 1000.0)),
  2333. max(0.0, sin( (this.m * 3.0 + led * 50.0 + 1024.0 * 2.0/3.0) % 1024.0 * Math.PI * 2.0 / 1000.0)));
  2334. }
  2335.  
  2336. pp() { return this.PPshort("Rainbow", "Scrolling color rainbow"); }
  2337. };
  2338.  
  2339. function Rainbow() {
  2340. return new RainbowClass();
  2341. }
  2342.  
  2343. var STATE_ON = 0;
  2344. // 1 = lockup
  2345. // 2 = drag
  2346. // 3 = lb
  2347. // 4 = melt
  2348. var STATE_LOCKUP = 0;
  2349. var STATE_ROTATE = 0;
  2350. var STATE_STILL = 0;
  2351. var STATE_NUM_LEDS = 144;
  2352.  
  2353. var handled_lockups = {};
  2354.  
  2355. function IsHandledLockup(lockup_type) {
  2356. return current_style.__handled_lockups[lockup_type];
  2357. }
  2358.  
  2359. function HandleLockup(lockup_type) {
  2360. if (lockup_type.getInteger) {
  2361. lockup_type = lockup_type.getInteger(0);
  2362. }
  2363. handled_lockups[lockup_type] = 1;
  2364. }
  2365.  
  2366.  
  2367. class BladeEffect {
  2368. constructor(type, start_micros, location) {
  2369. this.type = type;
  2370. this.start_micros = start_micros;
  2371. this.location = location;
  2372. this.wavnum = random(10);
  2373. }
  2374. };
  2375.  
  2376.  
  2377. class Range {
  2378. constructor(start, end) {
  2379. this.start = start;
  2380. this.end = end;
  2381. }
  2382. Size() { return max(0, this.end - this.start); }
  2383. Intersect(other) {
  2384. return new Range(max(this.start, other.start), min(this.end, other.end));
  2385. }
  2386. };
  2387.  
  2388. // TODO
  2389. // Gray out buttons not applicable to the current type.
  2390. // Save -> save to local storage (keep 10?) maybe with images?
  2391. // save as -> save to local storage with name
  2392. // Mix
  2393.  
  2394. class ColorCycleClass extends STYLE {
  2395. constructor(COLOR, percentage, rpm,
  2396. ON_COLOR, on_percentage, on_rpm,
  2397. fade_time_millis) {
  2398. super();
  2399. this.COLOR = ColorArg(COLOR);
  2400. this.percentage = IntArg(percentage);
  2401. this.rpm = IntArg(rpm);
  2402. this.ON_COLOR = ColorArg(ON_COLOR, COLOR.DOCOPY());
  2403. this.on_percentage = IntArg(on_percentage, percentage);
  2404. this.on_rpm = IntArg(on_rpm, rpm);
  2405. this.fade_time_millis = IntArg(fade_time_millis, 1);
  2406. this.last_micros_ = 0;
  2407. this.fade_ = 0.0;
  2408. this.pos_ = 0.0;
  2409. }
  2410. run(blade) {
  2411. this.COLOR.run(blade);
  2412. this.ON_COLOR.run(blade);
  2413. var now = millis();
  2414. var delta = now - this.last_micros_;
  2415. this.last_micros_ = now;
  2416. if (delta > 1000) delta = 1;
  2417. var fade_delta = delta / this.fade_time_millis;
  2418. if (!blade.is_on()) fade_delta = - fade_delta;
  2419. this.fade_ = Math.max(0.0, Math.min(1.0, this.fade_ + fade_delta));
  2420. var rpm = this.rpm * (1.0 - this.fade_) + this.on_rpm * this.fade_;
  2421. var percentage = this.percentage * (1.0 - this.fade_) + this.on_percentage * this.fade_;
  2422. this.fraction_ = percentage / 100.0;
  2423. this.pos_ = ((this.pos_ + delta / 60000.0 * rpm) % 1.0);
  2424. }
  2425. getColor(led) {
  2426. var led_range = new Range(led / 144.0, (led + 1) / 144.0);
  2427. var black_mix = 0.0;
  2428. if (this.pos_ + this.fraction_ < 1.0) {
  2429. black_mix = new Range(this.pos_, this.pos_ + this.fraction_).Intersect(led_range).Size();
  2430. } else {
  2431. black_mix = new Range(this.pos_, 1.0).Intersect(led_range).Size() +
  2432. new Range(0.0, (this.pos_ + this.fraction_) % 1.0).Intersect(led_range).Size();
  2433. }
  2434. black_mix *= 144.0;
  2435. var c = this.COLOR.getColor(led);
  2436. var on_c = this.ON_COLOR.getColor(led);
  2437. c = c.mix(on_c, this.fade_);
  2438. c = BLACK.mix(c, black_mix);
  2439. return c;
  2440. }
  2441. pp() {
  2442. return this.PP("ColorCycle", "Rotating beam",
  2443. this.COLOR, "beam color",
  2444. this.percentage, "percentage of blade lit",
  2445. this.rpm, "rotation speed",
  2446. this.ON_COLOR, "beam color when on",
  2447. this.on_percentage, "percentage of blade lit when on",
  2448. this.on_rpm, "rotation speed when on",
  2449. this.fade_time_millis, "time to transition to/from on state");
  2450. }
  2451. };
  2452.  
  2453. function ColorCycle(COLOR, percentage, rpm,
  2454. ON_COLOR, on_percentage, on_rpm,
  2455. fade_time_millis) {
  2456. return new ColorCycleClass(COLOR, percentage, rpm,
  2457. ON_COLOR, on_percentage, on_rpm,
  2458. fade_time_millis);
  2459. }
  2460.  
  2461.  
  2462. class CylonClass extends STYLE {
  2463. constructor(COLOR, percentage, rpm,
  2464. ON_COLOR, on_percentage, on_rpm,
  2465. fade_time_millis) {
  2466. super();
  2467. this.COLOR = ColorArg(COLOR);
  2468. this.percentage = IntArg(percentage);
  2469. this.rpm = IntArg(rpm);
  2470. this.ON_COLOR = ColorArg(ON_COLOR, COLOR.DOCOPY());
  2471. this.on_percentage = IntArg(on_percentage, percentage);
  2472. this.on_rpm = IntArg(on_rpm, rpm);
  2473. this.fade_time_millis = IntArg(fade_time_millis, 1);
  2474. this.last_micros_ = 0;
  2475. this.fade_ = 0.0;
  2476. this.pos_ = 0.0;
  2477. }
  2478. run(blade) {
  2479. this.COLOR.run(blade);
  2480. this.ON_COLOR.run(blade);
  2481. var now = millis();
  2482. var delta = now - this.last_micros_;
  2483. this.last_micros_ = now;
  2484. if (delta > 1000) delta = 1;
  2485. var fade_delta = delta / this.fade_time_millis;
  2486. if (!blade.is_on()) fade_delta = - fade_delta;
  2487. this.fade_ = Math.max(0.0, Math.min(1.0, this.fade_ + fade_delta));
  2488. // setvar(this.MIX, this.fade_);
  2489. var rpm = this.rpm * (1.0 - this.fade_) + this.on_rpm * this.fade_;
  2490. var percentage = this.percentage * (1.0 - this.fade_) + this.on_percentage * this.fade_;
  2491. this.fraction_ = percentage / 100.0;
  2492. // TODO: FIXME THIS SHOULD BE SIN()
  2493. this.pos_ = (this.pos_ + delta / 60000.0 * rpm) % 1.0;
  2494. this.POS = (Math.sin(this.pos_ * Math.PI * 2.0) + 1.0) * (0.5 - percentage/200.0);
  2495. }
  2496. getColor(led) {
  2497. var led_range = new Range(led / 144.0, (led + 1) / 144.0);
  2498. var black_mix = new Range(this.POS, this.POS + this.fraction_).Intersect(led_range).Size();
  2499. black_mix *= 144.0;
  2500. var c = this.COLOR.getColor(led);
  2501. var on_c = this.ON_COLOR.getColor(led);
  2502. c = c.mix(on_c, this.fade_);
  2503. c = BLACK.mix(c, black_mix);
  2504. return c;
  2505. }
  2506. pp() {
  2507. return this.PP("Cylon", "Rotating beam",
  2508. this.COLOR, "beam color",
  2509. this.percentage, "percentage of blade lit",
  2510. this.rpm, "rotation speed",
  2511. this.ON_COLOR, "beam color when on",
  2512. this.on_percentage, "percentage of blade lit when on",
  2513. this.on_rpm, "rotation speed when on",
  2514. this.fade_time_millis, "time to transition to/from on state");
  2515. }
  2516. };
  2517.  
  2518. function Cylon(COLOR, percentage, rpm,
  2519. ON_COLOR, on_percentage, on_rpm,
  2520. fade_time_millis) {
  2521. return new CylonClass(COLOR, percentage, rpm,
  2522. ON_COLOR, on_percentage, on_rpm,
  2523. fade_time_millis);
  2524. }
  2525.  
  2526. class OnSparkFClass extends FUNCTION {
  2527. constructor(T, SPARK_COLOR, MILLIS) {
  2528. super("Returns 32768 on startup and then fades out for 'MILLIS' milliseconds on startup.", arguments);
  2529. this.add_arg("MILLIS", "FUNCTION", "Millis", 200);
  2530. this.on_ = false;
  2531. this.on_millis_ = 0;
  2532. }
  2533. run(blade) {
  2534. super.run(blade);
  2535. var ms = this.MILLIS.getInteger(0);
  2536.  
  2537. var m = millis();
  2538. if (blade.is_on() != this.on_) {
  2539. this.on_ = blade.is_on();
  2540. if (this.on_) this.on_millis_ = m;
  2541. }
  2542. var t = m - this.on_millis_;
  2543. if (t < ms) {
  2544. this.mix_ = 1.0 - t / ms;
  2545. } else {
  2546. this.mix_ = 0.0;
  2547. }
  2548. }
  2549. getInteger(led) {
  2550. return this.mix_ * 32768;
  2551. }
  2552. };
  2553.  
  2554. function OnSparkF(MILLIS) {
  2555. return new OnSparkFClass(MILLIS);
  2556. }
  2557.  
  2558. class OnSparkLClass extends MACRO {
  2559. constructor(SPARK_COLOR, MILLIS) {
  2560. super("Shows the spark color for 'MILLIS' milliseconds on startup.", arguments);
  2561. this.add_arg("SPARK_COLOR", "COLOR", "Spark color", WHITE.DOCOPY());
  2562. this.add_arg("MILLIS", "FUNCTION", "Millis", Int(200));
  2563. this.SetExpansion(AlphaL(this.SPARK_COLOR, OnSparkF(this.MILLIS)));
  2564. }
  2565. };
  2566.  
  2567. function OnSparkL(SPARK_COLOR, MILLIS) {
  2568. return new OnSparkLClass(SPARK_COLOR, MILLIS);
  2569. }
  2570.  
  2571. class OnSparkXClass extends MACRO {
  2572. constructor(T, SPARK_COLOR, MILLIS) {
  2573. super("Shows the spark color for 'MILLIS' milliseconds on startup.", arguments);
  2574. this.add_arg("T", "COLOR", "Base color");
  2575. this.add_arg("SPARK_COLOR", "COLOR", "Spark color", WHITE.DOCOPY());
  2576. this.add_arg("MILLIS", "FUNCTION", "Millis", Int(200));
  2577. this.SetExpansion(Layers(T, OnSparkL(this.SPARK_COLOR, this.MILLIS)));
  2578. }
  2579. };
  2580.  
  2581. function OnSparkX(T, SPARK_COLOR, MILLIS) {
  2582. return new OnSparkXClass(T, SPARK_COLOR, MILLIS);
  2583. }
  2584.  
  2585. class OnSparkClass extends MACRO {
  2586. constructor(T, SPARK_COLOR, MILLIS) {
  2587. super("Shows the spark color for 'MILLIS' milliseconds on startup.", arguments);
  2588. this.add_arg("T", "COLOR", "Base color");
  2589. this.add_arg("SPARK_COLOR", "COLOR", "Spark color", WHITE.DOCOPY());
  2590. this.add_arg("MILLIS", "INT", "Millis", 200);
  2591. this.SetExpansion(OnSparkX(T, this.SPARK_COLOR, Int(this.MILLIS)));
  2592. }
  2593. };
  2594.  
  2595. function OnSpark(T, SPARK_COLOR, MILLIS) {
  2596. return new OnSparkClass(T, SPARK_COLOR, MILLIS);
  2597. }
  2598.  
  2599. class PulsingFClass extends FUNCTION {
  2600. constructor(PULSE_MILLIS) {
  2601. super("Pulses between 0 and 32768 every M milliseconds", Array.from(arguments));
  2602. this.add_arg("PULSE_MILLIS", "FUNCTION", "M");
  2603. }
  2604. run(blade) {
  2605. super.run(blade)
  2606. this.var_ = 0.5 + 0.5 * Math.sin(millis() * 3.1415 * 2.0/ this.PULSE_MILLIS.getInteger(0));
  2607. }
  2608. getInteger(led) {
  2609. return this.var_ * 32768;
  2610. }
  2611. }
  2612.  
  2613. function PulsingF(PULSE_MILLIS) {
  2614. return new PulsingFClass(PULSE_MILLIS);
  2615. }
  2616.  
  2617. class PulsingLClass extends MACRO {
  2618. constructor(COLOR2, PULSE_MILLIS) {
  2619. super("Pulses between transparent and B every M milliseconds", Array.from(arguments));
  2620. this.add_arg("COLOR2", "COLOR", "B");
  2621. this.add_arg("PULSE_MILLIS", "FUNCTION", "M");
  2622. this.SetExpansion(AlphaL(COLOR2, PulsingF(PULSE_MILLIS)));
  2623. }
  2624. }
  2625.  
  2626. function PulsingL(COLOR2, PULSE_MILLIS) {
  2627. return new PulsingLClass(COLOR2, PULSE_MILLIS);
  2628. }
  2629.  
  2630. class PulsingXClass extends MACRO {
  2631. constructor(COLOR1, COLOR2, PULSE_MILLIS) {
  2632. super("Pulses between A and B every M milliseconds", Array.from(arguments));
  2633. this.add_arg("COLOR1", "COLOR", "A");
  2634. this.add_arg("COLOR2", "COLOR", "B");
  2635. this.add_arg("PULSE_MILLIS", "FUNCTION", "M");
  2636. this.SetExpansion(Layers(COLOR1, PulsingL(COLOR2, PULSE_MILLIS)));
  2637. }
  2638. }
  2639.  
  2640. function PulsingX(COLOR1, COLOR2, PULSE_MILLIS) {
  2641. return new PulsingXClass(COLOR1, COLOR2, PULSE_MILLIS);
  2642. }
  2643.  
  2644. class PulsingClass extends MACRO {
  2645. constructor(COLOR1, COLOR2, PULSE_MILLIS) {
  2646. super("Pulses between A and B every M milliseconds", Array.from(arguments));
  2647. this.add_arg("COLOR1", "COLOR", "A");
  2648. this.add_arg("COLOR2", "COLOR", "B");
  2649. this.add_arg("PULSE_MILLIS", "INT", "M");
  2650. this.SetExpansion(PulsingX(COLOR1, COLOR2, Int(PULSE_MILLIS)));
  2651. }
  2652. }
  2653.  
  2654. function Pulsing(COLOR1, COLOR2, PULSE_MILLIS) {
  2655. return new PulsingClass(COLOR1, COLOR2, PULSE_MILLIS);
  2656. }
  2657.  
  2658. class SparkleFClass extends FUNCTION {
  2659. constructor(SPARK_CHANCE_PROMILLE, SPARK_INTENSITY) {
  2660. super("Sparkles!!", Array.from(arguments));
  2661. this.add_arg("SPARK_CHANCE_PROMILLE", "INT", "Chance of new sparks.", 300);
  2662. this.add_arg("SPARK_INTENSITY", "INT", "Initial spark intensity", 1024);
  2663. this.sparks = new Uint16Array(144 + 4);
  2664. this.last_update = 0;
  2665. }
  2666. run(blade) {
  2667. super.run(blade);
  2668. var m = millis();
  2669. if (m - this.last_update >= 10) {
  2670. this.last_update = m;
  2671. var fifo = 0
  2672. var N = blade.num_leds();
  2673. for (var i = 2; i <= N + 2; i++) {
  2674. var x = ((this.sparks[i-1] + this.sparks[i+1]) * 200 + this.sparks[i] * 570) / 1024;
  2675. this.sparks[i-1] = fifo;
  2676. fifo = x;
  2677. }
  2678. this.sparks[N] = fifo;
  2679. if (random(1000) < this.SPARK_CHANCE_PROMILLE) {
  2680. this.sparks[random(blade.num_leds()) + 2] += this.SPARK_INTENSITY;
  2681. }
  2682. }
  2683. }
  2684. getInteger(led) {
  2685. return clamp(this.sparks[led + 2], 0, 255) << 7;
  2686. }
  2687. }
  2688.  
  2689. function SparkleF(SPARK_CHANCE_PROMILLE, SPARK_INTENSITY) {
  2690. return new SparkleFClass(SPARK_CHANCE_PROMILLE, SPARK_INTENSITY);
  2691. }
  2692.  
  2693. class SparkleLClass extends MACRO {
  2694. constructor(SPARKLE_COLOR, SPARK_CHANCE_PROMILLE, SPARK_INTENSITY) {
  2695. super("Sparkles!!", Array.from(arguments));
  2696. this.add_arg("SPARKLE_COLOR", "COLOR", "Spark color", Rgb(255,255,255));
  2697. this.add_arg("SPARK_CHANCE_PROMILLE", "INT", "Chance of new sparks.", 300);
  2698. this.add_arg("SPARK_INTENSITY", "INT", "Initial spark intensity", 1024);
  2699. this.SetExpansion(AlphaL(this.SPARKLE_COLOR, SparkleF(this.SPARK_CHANCE_PROMILLE, this.SPARK_INTENSITY)));
  2700. }
  2701. }
  2702.  
  2703. function SparkleL(SPARKLE_COLOR, SPARK_CHANCE_PROMILLE, SPARK_INTENSITY) {
  2704. return new SparkleLClass(SPARKLE_COLOR, SPARK_CHANCE_PROMILLE, SPARK_INTENSITY);
  2705. }
  2706.  
  2707. class SparkleClass extends MACRO {
  2708. constructor(BASE, SPARKLE_COLOR, SPARK_CHANCE_PROMILLE, SPARK_INTENSITY) {
  2709. super("Sparkles!!", Array.from(arguments));
  2710. this.add_arg("BASE", "COLOR", "Normal blade color");
  2711. this.add_arg("SPARKLE_COLOR", "COLOR", "Spark color", Rgb(255,255,255));
  2712. this.add_arg("SPARK_CHANCE_PROMILLE", "INT", "Chance of new sparks.", 300);
  2713. this.add_arg("SPARK_INTENSITY", "INT", "Initial spark intensity", 1024);
  2714. this.SetExpansion(Layers(BASE, SparkleL(this.SPARKLE_COLOR, this.SPARK_CHANCE_PROMILLE, this.SPARK_INTENSITY)));
  2715. }
  2716. }
  2717.  
  2718. function Sparkle(BASE, SPARKLE_COLOR, SPARK_CHANCE_PROMILLE, SPARK_INTENSITY) {
  2719. return new SparkleClass(BASE, SPARKLE_COLOR, SPARK_CHANCE_PROMILLE, SPARK_INTENSITY);
  2720. }
  2721.  
  2722. class StrobeFClass extends FUNCTION {
  2723. constructor(T, STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS) {
  2724. super("Stroboscope effect", arguments);
  2725. this.add_arg("STROBE_FREQUENCY", "FUNCTION", "Strobe frequency.");
  2726. this.add_arg("STROBE_MILLIS", "FUNCTION", "Pulse length in milliseconds.");
  2727. this.strobe_ = false;
  2728. this.strobe_start_ = 0;
  2729. }
  2730. run(blade) {
  2731. super.run(blade);
  2732. var m = millis();
  2733. var strobe_millis = this.STROBE_MILLIS.getInteger(0);
  2734. var strobe_frequency = this.STROBE_FREQUENCY.getInteger(0);
  2735. var timeout = this.strobe_ ? strobe_millis : (1000 / strobe_frequency);
  2736. if (m - this.strobe_start_ > timeout) {
  2737. this.strobe_start_ += timeout;
  2738. if (m - this.strobe_start_ > strobe_millis + (1000 / strobe_frequency))
  2739. this.strobe_start_ = m;
  2740. this.strobe_ = !this.strobe_;
  2741. }
  2742. }
  2743. getInteger(led) {
  2744. return this.strobe_ ? 32768 : 0;
  2745. }
  2746. };
  2747.  
  2748. function StrobeF(STROBE_FREQUENCY, STROBE_MILLIS) {
  2749. return new StrobeFClass(STROBE_FREQUENCY, STROBE_MILLIS);
  2750. }
  2751.  
  2752. class StrobeLClass extends MACRO {
  2753. constructor(STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS) {
  2754. super("Stroboscope effect", arguments);
  2755. this.add_arg("STROBE_COLOR", "COLOR", "Strobe color");
  2756. this.add_arg("STROBE_FREQUENCY", "FUNCTION", "Strobe frequency.");
  2757. this.add_arg("STROBE_MILLIS", "FUNCTION", "Pulse length in milliseconds.");
  2758. this.SetExpansion(AlphaL(STROBE_COLOR, StrobeF(STROBE_FREQUENCY, STROBE_MILLIS)));
  2759. }
  2760. };
  2761.  
  2762. function StrobeL(STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS) {
  2763. return new StrobeLClass(STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS);
  2764. }
  2765.  
  2766. class StrobeXClass extends MACRO {
  2767. constructor(T, STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS) {
  2768. super("Stroboscope effect", arguments);
  2769. this.add_arg("T", "COLOR", "Base color");
  2770. this.add_arg("STROBE_COLOR", "COLOR", "Strobe color");
  2771. this.add_arg("STROBE_FREQUENCY", "FUNCTION", "Strobe frequency.");
  2772. this.add_arg("STROBE_MILLIS", "FUNCTION", "Pulse length in milliseconds.");
  2773. this.SetExpansion(Layers(T, StrobeL(STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS)));
  2774. }
  2775. };
  2776.  
  2777. function StrobeX(T, STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS) {
  2778. return new StrobeXClass(T, STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS);
  2779. }
  2780.  
  2781. class StrobeClass extends MACRO {
  2782. constructor(T, STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS) {
  2783. super("Stroboscope effect", arguments);
  2784. this.add_arg("T", "COLOR", "Base color");
  2785. this.add_arg("STROBE_COLOR", "COLOR", "Strobe color");
  2786. this.add_arg("STROBE_FREQUENCY", "INT", "Strobe frequency.");
  2787. this.add_arg("STROBE_MILLIS", "INT", "Pulse length in milliseconds.");
  2788. this.SetExpansion(StrobeX(T, STROBE_COLOR, Int(STROBE_FREQUENCY), Int(STROBE_MILLIS)));
  2789. }
  2790. };
  2791.  
  2792. function Strobe(T, STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS) {
  2793. return new StrobeClass(T, STROBE_COLOR, STROBE_FREQUENCY, STROBE_MILLIS);
  2794. }
  2795.  
  2796. class GradientClass extends STYLE {
  2797. constructor(COLORS) {
  2798. super("COLOR2 at base, COLOR2 at tip, smooth gradient in between.", COLORS);
  2799. this.COLORS = COLORS;
  2800. for (var i = 0; i < this.COLORS.length; i++)
  2801. this.add_arg("COLOR" + (i + 1), "COLOR", "COLOR " + (i + 1));
  2802. }
  2803. run(blade) {
  2804. for (var i = 0; i < this.COLORS.length; i++)
  2805. this.COLORS[i].run(blade);
  2806. this.num_leds_ = 1.0 * blade.num_leds();
  2807. }
  2808. getColor(led) {
  2809. var pos = led / this.num_leds_ * (this.COLORS.length - 1);
  2810. var N = min(this.COLORS.length -2, Math.floor(pos));
  2811. return this.COLORS[N].getColor(led).mix(this.COLORS[N+1].getColor(led), pos - N) ;
  2812. }
  2813. };
  2814.  
  2815. function Gradient(A, B, C, D) {
  2816. return new GradientClass(Array.from(arguments));
  2817. }
  2818.  
  2819.  
  2820. class MixClass extends STYLE {
  2821. constructor(ARGS) {
  2822. super("Mix between colors", ARGS);
  2823. this.COLORS = Array.from(ARGS).slice(1);
  2824. this.add_arg("F", "FUNCTION", "0=first color, 32768=last color");
  2825. for (var i = 1; i < this.COLORS.length + 1; i++)
  2826. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  2827. }
  2828. run(blade) {
  2829. this.F.run(blade);
  2830. for (var i = 0; i < this.COLORS.length; i++)
  2831. this.COLORS[i].run(blade);
  2832. }
  2833. getColor(led) {
  2834. var v = this.F.getInteger(led);
  2835. var pos = max(0, min(32768, v)) * (this.COLORS.length - 1) / 32768;
  2836. var N = min(this.COLORS.length -2, Math.floor(pos));
  2837. return this.COLORS[N].getColor(led).mix(this.COLORS[N+1].getColor(led), pos - N) ;
  2838. }
  2839. };
  2840.  
  2841. function Mix(F, C1, C2) {
  2842. return new MixClass(Array.from(arguments));
  2843. };
  2844.  
  2845. class IgnitionDelayXClass extends STYLE {
  2846. constructor(DELAY_MILLIS, BASE) {
  2847. super("Delays ignition by DELAY_MILLIS", Array.from(arguments));
  2848. this.add_arg("DELAY_MILLIS", "FUNCTION", "Ignition delay, in milliseconds");
  2849. this.add_arg("BASE", "COLOR", "Blade style");
  2850. }
  2851. is_on() {
  2852. return this.is_on_;
  2853. }
  2854. num_leds() {
  2855. return this.blade.num_leds()
  2856. }
  2857. GetEffects() { return this.blade.GetEffects(); }
  2858. run(blade) {
  2859. this.DELAY_MILLIS.run(blade);
  2860. var delay_millis = this.DELAY_MILLIS.getInteger(0);
  2861. this.blade = blade;
  2862. if (blade.is_on()) {
  2863. if (!this.waiting) {
  2864. this.waiting = true;
  2865. this.wait_start_time = millis();
  2866. }
  2867. var waited = millis() - this.wait_start_time;
  2868. if (waited > delay_millis) {
  2869. this.is_on_ = true;
  2870. this.wait_start_time = millis() - delay_millis - 1;
  2871. }
  2872. } else {
  2873. this.waiting = false;
  2874. this.is_on_ = false;
  2875. }
  2876. this.BASE.run(this)
  2877. }
  2878. getColor(led) {
  2879. return this.BASE.getColor(led);
  2880. }
  2881. }
  2882.  
  2883. function IgnitionDelayX(millis, base) {
  2884. return new IgnitionDelayXClass(millis, base);
  2885. }
  2886.  
  2887. class IgnitionDelayClass extends MACRO {
  2888. constructor(DELAY_MILLIS, BASE) {
  2889. super("Delays ignition by DELAY_MILLIS", Array.from(arguments));
  2890. this.add_arg("DELAY_MILLIS", "INT", "Ignition delay, in milliseconds");
  2891. this.add_arg("BASE", "COLOR", "Blade style");
  2892. this.SetExpansion(IgnitionDelayX(Int(DELAY_MILLIS), BASE));
  2893. }
  2894. }
  2895.  
  2896. function IgnitionDelay(millis, base) {
  2897. return new IgnitionDelayClass(millis, base);
  2898. }
  2899.  
  2900. class RetractionDelayXClass extends STYLE {
  2901. constructor(DELAY_MILLIS, BASE) {
  2902. super("Delays retraction by DELAY_MILLIS", Array.from(arguments));
  2903. this.add_arg("DELAY_MILLIS", "FUNCTION", "Ignition delay, in milliseconds");
  2904. this.add_arg("BASE", "COLOR", "Blade style");
  2905. }
  2906. is_on() {
  2907. return this.is_on_;
  2908. }
  2909. num_leds() {
  2910. return this.blade.num_leds()
  2911. }
  2912. GetEffects() { return this.blade.GetEffects(); }
  2913. run(blade) {
  2914. this.DELAY_MILLIS.run(blade);
  2915. var delay_millis = this.DELAY_MILLIS.getInteger(0);
  2916. this.blade = blade;
  2917. if (!blade.is_on()) {
  2918. if (!this.waiting) {
  2919. this.waiting = true;
  2920. this.wait_start_time = millis();
  2921. }
  2922. var waited = millis() - this.wait_start_time;
  2923. if (waited > delay_millis) {
  2924. this.is_on_ = false;
  2925. this.wait_start_time = millis() - delay_millis - 1;
  2926. }
  2927. } else {
  2928. this.waiting = false;
  2929. this.is_on_ = true;
  2930. }
  2931. this.BASE.run(this)
  2932. }
  2933. getColor(led) {
  2934. return this.BASE.getColor(led);
  2935. }
  2936. }
  2937.  
  2938. function RetractionDelayX(millis, base) {
  2939. return new RetractionDelayXClass(millis, base);
  2940. }
  2941.  
  2942. class RetractionDelayClass extends MACRO {
  2943. constructor(DELAY_MILLIS, BASE) {
  2944. super("Delays retraction by DELAY_MILLIS", Array.from(arguments));
  2945. this.add_arg("DELAY_MILLIS", "INT", "Ignition delay, in milliseconds");
  2946. this.add_arg("BASE", "COLOR", "Blade style");
  2947. this.SetExpansion(RetractionDelayX(Int(DELAY_MILLIS), BASE));
  2948. }
  2949. }
  2950. function RetractionDelay(millis, base) {
  2951. return new RetractionDelayClass(millis, base);
  2952. }
  2953.  
  2954. class RandomBlinkFClass extends FUNCTION {
  2955. constructor(MILLIHZ) {
  2956. super("Blink each LED randomly MILLIHZ times per second.", arguments);
  2957. this.add_arg("MILLIHZ", "FUNCTION", "how often to blink");
  2958. this.last_update = 0;
  2959. this.state = [];
  2960. }
  2961. run(blade) {
  2962. super.run(blade);
  2963. var now = micros();
  2964. if (now - this.last_update > 1000000000 / this.MILLIHZ.getInteger(0)) {
  2965. this.last_update = now;
  2966. for (var i = 0; i < blade.num_leds(); i++) {
  2967. this.state[i] = random(2);
  2968. }
  2969. }
  2970. }
  2971.  
  2972. getInteger(led) {
  2973. return this.state[led] ? 32768 : 0;
  2974. }
  2975. };
  2976.  
  2977. function RandomBlinkF(millihz) {
  2978. return new RandomBlinkFClass(millihz);
  2979. }
  2980.  
  2981. class RandomBlinkLClass extends MACRO {
  2982. constructor(MILLIHZ, COLOR1, COLOR2) {
  2983. super("Blink each LED randomly MILLIHZ times per second.", arguments);
  2984. this.add_arg("MILLIHZ", "FUNCTION", "how often to blink");
  2985. this.add_arg("COLOR2", "COLOR", "second color", BLACK.DOCOPY());
  2986. this.SetExpansion(AlphaL(this.COLOR2, RandomBlinkF(MILLIHZ)));
  2987. }
  2988. };
  2989.  
  2990. function RandomBlinkL(millihz, c1) {
  2991. return new RandomBlinkLClass(millihz, c1);
  2992. }
  2993.  
  2994. class RandomBlinkXClass extends MACRO {
  2995. constructor(MILLIHZ, COLOR1, COLOR2) {
  2996. super("Blink each LED randomly MILLIHZ times per second.", arguments);
  2997. this.add_arg("MILLIHZ", "FUNCTION", "how often to blink");
  2998. this.add_arg("COLOR1", "COLOR", "first color", WHITE.DOCOPY());
  2999. this.add_arg("COLOR2", "COLOR", "second color", BLACK.DOCOPY());
  3000. this.SetExpansion(Layers(this.COLOR1, RandomBlinkL(this.MILLIHZ, this.COLOR2)));
  3001. }
  3002. };
  3003.  
  3004. function RandomBlinkX(millihz, c1, c2) {
  3005. return new RandomBlinkXClass(millihz, c1, c2);
  3006. }
  3007.  
  3008. class RandomBlinkClass extends MACRO {
  3009. constructor(MILLIHZ, COLOR1, COLOR2) {
  3010. super("Blink each LED randomly MILLIHZ times per second.", arguments);
  3011. this.add_arg("MILLIHZ", "INT", "how often to blink");
  3012. this.add_arg("COLOR1", "COLOR", "first color", WHITE.DOCOPY());
  3013. this.add_arg("COLOR2", "COLOR", "second color", BLACK.DOCOPY());
  3014. this.SetExpansion(RandomBlinkX(Int(this.MILLIHZ), this.COLOR1, this.COLOR2));
  3015. }
  3016. };
  3017.  
  3018. function RandomBlink(MILLIHZ, COLOR1, COLOR2) {
  3019. return new RandomBlinkClass(MILLIHZ, COLOR1, COLOR2);
  3020. }
  3021.  
  3022. class SequenceFClass extends FUNCTION {
  3023. constructor(ARGS) {
  3024. super("Pre-defined sequence of 0 and 32768", ARGS);
  3025. this.add_arg("MILLIS_PER_BIT", "INT", "Milliseconds per bit.");
  3026. this.add_arg("BITS", "INT", "total bits");
  3027. for (var i = 0; i < this.BITS; i+= 16) {
  3028. this.add_arg("BITS"+i, "INT", "Bit sequence " + ((i/16)+1));
  3029. }
  3030. this.SEQUENCE = Array.from(ARGS).slice(2);
  3031. }
  3032. run(blade) {
  3033. super.run(blade);
  3034. var now = millis();
  3035. var bit = (now / this.MILLIS_PER_BIT) % min(this.BITS, this.SEQUENCE.length * 16);
  3036. this.on = !!(this.SEQUENCE[bit >> 4] >> ((~bit) & 0xf) & 1)
  3037. }
  3038. getInteger(led) {
  3039. return this.on ? 32768 : 0;
  3040. }
  3041. };
  3042.  
  3043. function SequenceF(MILLIHZ_PER_BIT, BITS, SEQUENCE) {
  3044. return new SequenceFClass(Array.from(arguments));
  3045. }
  3046.  
  3047. class SequenceLClass extends MACRO {
  3048. constructor(ARGS) {
  3049. super("Pre-defined sequence", ARGS);
  3050. this.add_arg("COLOR", "COLOR", "Color if bit is 2");
  3051. this.add_arg("MILLIS_PER_BIT", "INT", "Milliseconds per bit.");
  3052. this.add_arg("BITS", "INT", "total bits");
  3053. for (var i = 0; i < this.BITS; i+= 16) {
  3054. this.add_arg("BITS"+i, "INT", "Bit sequence " + ((i/16)+1));
  3055. }
  3056. this.SetExpansion(AlphaL(this.COLOR, new SequenceFClass(ARGS.slice(1))));
  3057. }
  3058. };
  3059.  
  3060. function SequenceL(COLOR2, MILLIHZ_PER_BIT, BITS, SEQUENCE) {
  3061. return new SequenceLClass(Array.from(arguments));
  3062. }
  3063.  
  3064. class SequenceClass extends MACRO {
  3065. constructor(ARGS) {
  3066. super("Pre-defined sequence", ARGS);
  3067. this.add_arg("COLOR1", "COLOR", "Color if bit is 1");
  3068. this.add_arg("COLOR2", "COLOR", "Color if bit is 0");
  3069. this.add_arg("MILLIS_PER_BIT", "INT", "Milliseconds per bit.");
  3070. this.add_arg("BITS", "INT", "total bits");
  3071. for (var i = 0; i < this.BITS; i+= 16) {
  3072. this.add_arg("BITS"+i, "INT", "Bit sequence " + ((i/16)+1));
  3073. }
  3074. this.SetExpansion(Layers(this.COLOR2, new SequenceLClass([this.COLOR1].concat(ARGS.slice(2)))));
  3075. }
  3076. };
  3077.  
  3078. function Sequence(COLOR1, COLOR2, MILLIHZ_PER_BIT, BITS, SEQUENCE) {
  3079. return new SequenceClass(Array.from(arguments));
  3080. }
  3081.  
  3082. class ColorSequenceClass extends STYLE {
  3083. constructor(ARGS) {
  3084. super("Pre-defined sequence", ARGS);
  3085. this.add_arg("MILLIS_PER_COLOR", "INT", "Milliseconds before moving to next color.");
  3086. this.COLORS = Array.from(ARGS).slice(1);
  3087. for (var i = 1; i < this.COLORS.length + 1; i++)
  3088. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  3089. this.last_micros = 0;
  3090. this.n = 0;
  3091. }
  3092. run(blade) {
  3093. super.run(blade);
  3094. var now = micros();
  3095. var millis_per_color = this.MILLIS_PER_COLOR.getInteger(0);
  3096. if (now - this.last_micros > millis_per_color * 1000) {
  3097. if (now - this.last_micros > millis_per_color * 10000) {
  3098. this.n = 0;
  3099. this.last_micros = now;
  3100. } else {
  3101. this.n = (this.n + 1) % this.COLORS.length;
  3102. this.last_micros += millis_per_color * 1000;
  3103. }
  3104. }
  3105. }
  3106. getColor(led) { return this.COLORS[this.n].getColor(led); }
  3107. };
  3108.  
  3109. function ColorSequence(MPC, C) {
  3110. return new ColorSequenceClass(Array.from(arguments));
  3111. };
  3112.  
  3113. class EffectSequenceClass extends STYLE {
  3114. constructor(ARGS) {
  3115. super("Sequence that changes on events.", ARGS);
  3116. this.add_arg("EFFECT", "EFFECT", "effect that goes to next color");
  3117. this.COLORS = Array.from(ARGS).slice(1);
  3118. for (var i = 1; i < this.COLORS.length + 1; i++)
  3119. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  3120. this.last_micros = 0;
  3121. this.n = this.COLORS.length - 1;
  3122. this.effect_ = new OneshotEffectDetector(this.EFFECT);
  3123. }
  3124. run(blade) {
  3125. super.run(blade);
  3126. var now = micros();
  3127.  
  3128. if (this.effect_.Detect(blade)) {
  3129. this.n = (this.n + 1) % this.COLORS.length;
  3130. }
  3131. }
  3132. getColor(led) { return this.COLORS[this.n].getColor(led); }
  3133. };
  3134.  
  3135. function EffectSequence(MPC, C) {
  3136. return new EffectSequenceClass(Array.from(arguments));
  3137. };
  3138.  
  3139. class StripesXClass extends STYLE {
  3140. constructor(ARGS) {
  3141. super("Configurable rainbow", ARGS);
  3142. this.add_arg("WIDTH", "FUNCTION", "Stripe width");
  3143. this.add_arg("SPEED", "FUNCTION", "Scroll speed");
  3144. this.COLORS = ARGS.slice(2);
  3145. for (var i = 1; i < this.COLORS.length + 1; i++)
  3146. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  3147. this.last_micros = 0;
  3148. this.m = 0;
  3149. }
  3150. run(blade) {
  3151. super.run(blade);
  3152. var now_micros = micros();
  3153. var delta_micros = now_micros - this.last_micros;
  3154. this.last_micros = now_micros;
  3155. this.m = MOD( (this.m + delta_micros * this.SPEED.getInteger(0) / 333), (this.COLORS.length * 341 * 1024))
  3156. this.mult = (50000 * 1024 / this.WIDTH.getInteger(0));
  3157. }
  3158. GET_COLOR(N, led, p, ret) {
  3159. if (N >= this.COLORS.length || p < 0) return;
  3160. if (p > 0 && p < 512) {
  3161. var tmp = this.COLORS[N].getColor(led);
  3162. var mul = sin(p * Math.PI / 512.0);
  3163. ret.r += tmp.r * mul;
  3164. ret.g += tmp.g * mul;
  3165. ret.b += tmp.b * mul;
  3166. }
  3167. this.GET_COLOR(N+1, led, p - 341, ret);
  3168. }
  3169. getColor(led) {
  3170. var p = ((this.m + led * this.mult) >> 10) % (this.COLORS.length * 341);
  3171. var ret = Rgb(0,0,0);
  3172. this.GET_COLOR(0, led, p, ret);
  3173. this.GET_COLOR(0, led, p + 341 * this.COLORS.length, ret);
  3174. return ret;
  3175. }
  3176. }
  3177.  
  3178. function StripesX(W,S,C) {
  3179. return new StripesXClass(Array.from(arguments));
  3180. }
  3181.  
  3182. class StripesClass extends MACRO {
  3183. constructor(ARGS) {
  3184. super("Configurable rainbow", ARGS);
  3185. this.add_arg("WIDTH", "INT", "Stripe width");
  3186. this.add_arg("SPEED", "INT", "Scroll speed");
  3187. this.COLORS = ARGS.slice(2);
  3188. for (var i = 1; i < this.COLORS.length + 1; i++)
  3189. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  3190.  
  3191. this.SetExpansion(new StripesXClass([Int(this.WIDTH), Int(this.SPEED)].concat(this.COLORS)));
  3192. }
  3193. }
  3194.  
  3195. function Stripes(W,S,C) {
  3196. return new StripesClass(Array.from(arguments));
  3197. }
  3198.  
  3199. class AudioFlickerLClass extends MACRO {
  3200. constructor(COLOR) {
  3201. super("Audio flicker layer, higher volumes means less transparent.", arguments);
  3202. this.add_arg("COLOR", "COLOR", "COLOR");
  3203. this.SetExpansion(AlphaL(this.COLOR, NoisySoundLevelCompat()));
  3204. }
  3205. }
  3206.  
  3207. function AudioFlickerL(B) {
  3208. return new AudioFlickerLClass(B);
  3209. }
  3210.  
  3211. class AudioFlickerClass extends MACRO {
  3212. constructor(A, B) {
  3213. super("Select between A and B based on audio. Higher volumes means more B.", arguments);
  3214. this.add_arg("A","COLOR","A");
  3215. this.add_arg("B","COLOR","B");
  3216. this.SetExpansion(Layers(this.A, AudioFlickerL(this.B)));
  3217. }
  3218. };
  3219.  
  3220. function AudioFlicker(A, B) {
  3221. return new AudioFlickerClass(A, B);
  3222. }
  3223.  
  3224. class RandomFClass extends FUNCTION {
  3225. constructor(A, B) {
  3226. super("Random number 0 - 32768.", arguments);
  3227. }
  3228. run(blade) {
  3229. this.var_ = Math.random() * 32768;;
  3230. }
  3231. getInteger(led) {
  3232. return this.var_;
  3233. }
  3234. };
  3235.  
  3236. function RandomF() {
  3237. return new RandomFClass();
  3238. }
  3239.  
  3240. class RandomLClass extends MACRO {
  3241. constructor(A) {
  3242. super("Selects between A and transparent randomly.", arguments);
  3243. this.add_arg("A", "COLOR", "A");
  3244. this.SetExpansion(AlphaL(A, RandomF()));
  3245. }
  3246. };
  3247.  
  3248. function RandomL(A) {
  3249. return new RandomLClass(A);
  3250. }
  3251.  
  3252. class RandomFlickerClass extends MACRO {
  3253. constructor(A, B) {
  3254. super("Selects between A and B randomly.", arguments);
  3255. this.add_arg("A", "COLOR", "A");
  3256. this.add_arg("B", "COLOR", "B");
  3257. this.SetExpansion(Layers(A, RandomL(B)));
  3258. }
  3259. };
  3260.  
  3261. function RandomFlicker(A, B) {
  3262. return new RandomFlickerClass(A, B);
  3263. }
  3264.  
  3265. class RandomPerLEDFClass extends FUNCTION {
  3266. constructor() {
  3267. super("Returns random 0-32768.", arguments);
  3268. }
  3269. getInteger(led) {
  3270. return random(32768);
  3271. }
  3272. };
  3273.  
  3274. function RandomPerLEDF() {
  3275. return new RandomPerLEDFClass();
  3276. }
  3277.  
  3278. class RandomPerLEDFlickerLClass extends MACRO {
  3279. constructor(A) {
  3280. super("Selects between A and transparent randomly.", arguments);
  3281. this.add_arg("A", "COLOR", "A");
  3282. this.SetExpansion(AlphaL(A, RandomPerLEDF()));
  3283. }
  3284. };
  3285.  
  3286. function RandomPerLEDFlickerL(A) {
  3287. return new RandomPerLEDFlickerLClass(A);
  3288. }
  3289.  
  3290. class RandomPerLEDFlickerClass extends MACRO {
  3291. constructor(A, B) {
  3292. super("Selects between A and B randomly.", arguments);
  3293. this.add_arg("A", "COLOR", "A");
  3294. this.add_arg("B", "COLOR", "B");
  3295. this.SetExpansion(Layers(A, RandomPerLEDFlickerL(B)));
  3296. }
  3297. };
  3298.  
  3299. function RandomPerLEDFlicker(A, B) {
  3300. return new RandomPerLEDFlickerClass(A, B);
  3301. }
  3302.  
  3303. class RemapClass extends STYLE {
  3304. constructor(F, COLOR) {
  3305. super("Remaps the pixels of COLOR based on F", arguments);
  3306. this.add_arg("F", "FUNCTION", "remap function");
  3307. this.add_arg("COLOR", "COLOR", "COLOR");
  3308. }
  3309. run(blade) {
  3310. super.run(blade);
  3311. this.num_leds = blade.num_leds();
  3312. }
  3313. getColor(led) {
  3314. var pos = this.F.getInteger(led);
  3315. var led = clamp(pos * this.num_leds, 0, this.num_leds * 32768 - 1);
  3316. var fraction = led & 0x7fff;
  3317. led = clamp(led >> 15, 0, this.num_leds);
  3318. return this.COLOR.getColor(led).mix(
  3319. this.COLOR.getColor(min(led + 1, this.num_leds - 1)),
  3320. fraction / 32768);
  3321. }
  3322. }
  3323.  
  3324. function Remap(F, COLOR) {
  3325. return new RemapClass(F, COLOR);
  3326. }
  3327.  
  3328. class BrownNoiseFClass extends FUNCTION {
  3329. constructor(grade) {
  3330. super("Randomly return values between 0 and 32768, but keeps nearby values similar", Array.from(arguments));
  3331. this.add_arg("GRADE", "FUNCTION", "grade");
  3332. }
  3333. run(blade) {
  3334. super.run(blade);
  3335. this.mix = Math.floor(Math.random()*32768);
  3336. }
  3337. getInteger(led) {
  3338. var grade = this.GRADE.getInteger(led);
  3339. this.mix += Math.floor(Math.random() * (grade * 2 + 1)) - grade;
  3340. this.mix = clamp(this.mix, 0, 32768);
  3341. return this.mix;
  3342. }
  3343. };
  3344.  
  3345. function BrownNoiseF(grade) {
  3346. return new BrownNoiseFClass(grade);
  3347. }
  3348.  
  3349. class BrownNoiseFlickerLClass extends MACRO {
  3350. constructor(B, GRADE) {
  3351. super("Randomly selects between A and B but keeps nearby pixels similar", Array.from(arguments));
  3352. this.add_arg("B", "COLOR", "B");
  3353. this.add_arg("GRADE", "FUNCTION", "grade");
  3354. this.SetExpansion(AlphaL(B, BrownNoiseF(GRADE)))
  3355. }
  3356. };
  3357.  
  3358. function BrownNoiseFlickerL(B, grade) {
  3359. return new BrownNoiseFlickerLClass(B, grade);
  3360. }
  3361.  
  3362. class BrownNoiseFlickerClass extends MACRO {
  3363. constructor(A, B, GRADE) {
  3364. super("Randomly selects between A and B but keeps nearby pixels similar", Array.from(arguments));
  3365. this.add_arg("A", "COLOR", "A");
  3366. this.add_arg("B", "COLOR", "B");
  3367. this.add_arg("GRADE", "INT", "grade");
  3368. this.SetExpansion(Layers(A, BrownNoiseFlickerL(B, Int(this.GRADE * 128))))
  3369. }
  3370. };
  3371.  
  3372. function BrownNoiseFlicker(A, B, grade) {
  3373. return new BrownNoiseFlickerClass(A, B, grade);
  3374. }
  3375.  
  3376. class HumpFlickerFXClass extends FUNCTION {
  3377. constructor(hump_width) {
  3378. super("Picks a random spot for a bump each frame.", Array.from(arguments));
  3379. this.add_arg("hump_width", "FUNCTION", "Hump width");
  3380. }
  3381. run(blade) {
  3382. super.run(blade);
  3383. this.pos = Math.floor(Math.random() * blade.num_leds());
  3384. }
  3385. getInteger(led) {
  3386. return clamp(Math.abs(led - this.pos) * 32768 / this.hump_width.getInteger(led), 0, 32768);
  3387. }
  3388. };
  3389.  
  3390. function HumpFlickerFX(hump_width) {
  3391. return new HumpFlickerFXClass(hump_width);
  3392. }
  3393.  
  3394. class HumpFlickerFClass extends MACRO {
  3395. constructor(hump_width) {
  3396. super("Picks a random spot for a bump each frame.", Array.from(arguments));
  3397. this.add_arg("hump_width", "INT", "Hump width");
  3398. this.SetExpansion(HumpFlickerFX(Int(hump_width)));
  3399. }
  3400. };
  3401.  
  3402. function HumpFlickerF(hump_width) {
  3403. return new HumpFlickerFClass(hump_width);
  3404. }
  3405.  
  3406. class HumpFlickerLClass extends MACRO {
  3407. constructor(B, hump_width) {
  3408. super("Picks a random spot for a bump each frame.", Array.from(arguments));
  3409. this.add_arg("B", "COLOR", "B");
  3410. this.add_arg("hump_width", "INT", "Hump width");
  3411. this.SetExpansion(AlphaL(B, HumpFlickerF(hump_width)));
  3412. }
  3413. };
  3414.  
  3415. function HumpFlickerL(B, hump_width) {
  3416. return new HumpFlickerLClass(B, hump_width);
  3417. }
  3418.  
  3419. class HumpFlickerClass extends MACRO {
  3420. constructor(A, B, hump_width) {
  3421. super("Picks a random spot for a bump each frame.", Array.from(arguments));
  3422. this.add_arg("A", "COLOR", "A");
  3423. this.add_arg("B", "COLOR", "B");
  3424. this.add_arg("hump_width", "INT", "Hump width");
  3425. this.SetExpansion(Layers(A, HumpFlickerL(B, hump_width)));
  3426. }
  3427. };
  3428.  
  3429. function HumpFlicker(A, B, hump_width) {
  3430. return new HumpFlickerClass(A, B, hump_width);
  3431. }
  3432.  
  3433. class FireConfigClass extends CONFIG {
  3434. constructor(INTENSITY_BASE, INTENSITY_RAND, COOLING) {
  3435. super("Fire configuration", Array.from(arguments));
  3436. this.add_arg("intensity_base", "INT", "intensity base");
  3437. this.add_arg("intensity_rand", "INT", "intensity random");
  3438. this.add_arg("cooling", "INT", "cooling");
  3439. }
  3440. getType() { return "FireConfig"; }
  3441. }
  3442.  
  3443. function FireConfig(B, R, C) {
  3444. return new FireConfigClass(B, R, C);
  3445. }
  3446.  
  3447. function FireConfigI(B, R, C) {
  3448. return new FireConfigClass(new INTEGER(B), new INTEGER(R), new INTEGER(C));
  3449. }
  3450.  
  3451. const FIRE_STATE_OFF = 0
  3452. const FIRE_STATE_ACTIVATING = 1;
  3453. const FIRE_STATE_ON = 2;
  3454.  
  3455. class StyleFireClass extends STYLE {
  3456. constructor(COLOR1, COLOR2, DELAY, SPEED, NORM, CLASH, LOCK, OFF) {
  3457. super("Too complicated to describe briefly", Array.from(arguments));
  3458. this.add_arg("COLOR1", "COLOR", "Warm color");
  3459. this.add_arg("COLOR2", "COLOR", "Hot color");
  3460. this.add_arg("DELAY", "INT", "Delay", 0);
  3461. this.add_arg("SPEED", "INT", "Speed", 2);
  3462. this.add_arg("NORM", "FireConfig", "Config when on", FireConfigI(0, 2000, 5));
  3463. this.add_arg("CLASH", "FireConfig", "Config during clash", FireConfigI(3000, 0, 0));
  3464. this.add_arg("LOCK", "FireConfig", "Config during lockup", FireConfigI(0, 5000, 10));
  3465. this.add_arg("OFF", "FireConfig", "Config when off", FireConfigI(0, 0, this.NORM.cooling.value));
  3466. this.heat = new Uint16Array(144 + 13);
  3467. this.state = FIRE_STATE_OFF;
  3468. this.last_update = 0;
  3469. this.clash_detector_ = new OneshotEffectDetector(EFFECT_CLASH);
  3470. }
  3471. On(blade) {
  3472. if (!blade.is_on()) {
  3473. this.state = FIRE_STATE_OFF;
  3474. return false;
  3475. }
  3476. if (this.state == FIRE_STATE_OFF) {
  3477. this.state = FIRE_STATE_ACTIVATING;
  3478. this.on_time = millis();
  3479. }
  3480. if (this.state = FIRE_STATE_ACTIVATING) {
  3481. if (millis() - this.on_time < this.DELAY) return false;
  3482. this.state = FIRE_STATE_ON;
  3483. }
  3484. return true;
  3485. }
  3486. run(blade) {
  3487. super.run(blade);
  3488. var m = millis();
  3489. if (m - this.last_update < 10)
  3490. return;
  3491. if (m - this.last_update < 40) {
  3492. this.last_update += 10;;
  3493. } else {
  3494. this.last_update = m;
  3495. }
  3496. var num_leds = blade.num_leds();
  3497. this.num_leds = num_leds;
  3498. var conf = this.OFF;
  3499. if (this.clash_detector_.Detect(blade)) {
  3500. conf = this.CLASH;
  3501. } else if (this.On(blade)) {
  3502. if (STATE_LOCKUP == 0) {
  3503. conf = this.NORM;
  3504. } else {
  3505. conf = this.LOCK;
  3506. }
  3507. }
  3508.  
  3509. for (var i = 0; i < this.SPEED; i++) {
  3510. this.heat[num_leds + i] = conf.intensity_base +
  3511. random(random(random(conf.intensity_rand)));
  3512. }
  3513. for (var i = 0; i < num_leds; i++) {
  3514. var x = (this.heat[i + this.SPEED-1] * 3 + this.heat[i + this.SPEED] * 10 + this.heat[i + this.SPEED +1] * 3) >> 4;
  3515. x -= random(conf.cooling);
  3516. this.heat[i] = max(0, min(x, 65535));
  3517. }
  3518. }
  3519. getColor(led) {
  3520. var h = this.heat[this.num_leds - 1 - led];
  3521. if (h < 256) {
  3522. return BLACK.mix(this.COLOR1.getColor(led), h / 255.0);
  3523. } else if (h < 512) {
  3524. return this.COLOR1.getColor(led).mix(this.COLOR2.getColor(led), (h-256)/255.0);
  3525. } else if (h < 768) {
  3526. return this.COLOR2.getColor(led).mix(WHITE, (h - 512) / 255.0);
  3527. } else {
  3528. return WHITE;
  3529. }
  3530. }
  3531. };
  3532.  
  3533. function StyleFire(COLOR1, COLOR2, DELAY, SPEED, NORM, CLASH, LOCK, OFF) {
  3534. return new StyleFireClass(COLOR1, COLOR2, DELAY, SPEED, NORM, CLASH, LOCK, OFF);
  3535. }
  3536.  
  3537. class StaticFireClass extends MACRO {
  3538. constructor(COLOR1, COLOR2, DELAY, SPEED, BASE, RAND, COOLING) {
  3539. super("Non-responsive fire style alias.", Array.from(arguments));
  3540. this.add_arg("COLOR1", "COLOR", "Warm color");
  3541. this.add_arg("COLOR2", "COLOR", "Hot color");
  3542. this.add_arg("DELAY", "INT", "Delay", 0);
  3543. this.add_arg("SPEED", "INT", "Speed", 2);
  3544. this.add_arg("BASE", "INT", "Base", 0);
  3545. this.add_arg("RAND", "INT", "Random", 2000);
  3546. this.add_arg("COOLING", "INT", "Cooling", 5);
  3547. this.SetExpansion(StyleFire(COLOR1, COLOR2, this.DELAY, this.SPEED,
  3548. FireConfig(this.BASE, this.RAND, this.COOLING),
  3549. FireConfig(this.BASE, this.RAND, this.COOLING),
  3550. FireConfig(this.BASE, this.RAND, this.COOLING),
  3551. FireConfig(this.BASE, this.RAND, this.COOLING)));
  3552. }
  3553. };
  3554.  
  3555. function StaticFire(COLOR1, COLOR2, DELAY, SPEED, BASE, RAND, COOLING) {
  3556. return new StaticFireClass(COLOR1, COLOR2, DELAY, SPEED, BASE, RAND, COOLING);
  3557. }
  3558.  
  3559. class RgbCycleClass extends STYLE {
  3560. constructor() {
  3561. super();
  3562. this.n = 0;
  3563. }
  3564. run(blade) {
  3565. this.n++;
  3566. if (this.n >= 3) this.n = 0;
  3567. if (this.n == 0) this.RET = Rgb(255,0,0);
  3568. if (this.n == 1) this.RET = Rgb(0,255,0);
  3569. if (this.n == 2) this.RET = Rgb(0,0,250);
  3570. }
  3571. getColor(led) {
  3572. return this.RET;
  3573. }
  3574. pp() {
  3575. return this.PP("RgbCycle", "alternates betwen red, green and blue.");
  3576. }
  3577. };
  3578.  
  3579. function RgbCycle() {
  3580. return new RgbCycleClass();
  3581. }
  3582.  
  3583. function AddBlast() {
  3584. blade.addEffect(EFFECT_BLAST, Math.random() * 0.7 + 0.2);
  3585. }
  3586. function AddForce() {
  3587. blade.addEffect(EFFECT_FORCE, Math.random() * 0.7 + 0.2);
  3588. }
  3589. var current_clash_value = 0;
  3590. var current_clash_strength = 0;
  3591. function AddClash() {
  3592. current_clash_value = 200 + random(1600);
  3593. current_clash_strength = 100 + random(current_clash_value);
  3594. blade.addEffect(EFFECT_CLASH, Math.random() * 0.7 + 0.2);
  3595. }
  3596. function AddStab() {
  3597. blade.addEffect(EFFECT_STAB, 1.0);
  3598. }
  3599. function AddNewfont() {
  3600. blade.addEffect(EFFECT_NEWFONT, Math.random() * 0.7 + 0.2);
  3601. }
  3602. function AddBoot() {
  3603. blade.addEffect(EFFECT_BOOT, Math.random() * 0.7 + 0.2);
  3604. }
  3605. function AddPreon() {
  3606. blade.addEffect(EFFECT_PREON, 0.0);
  3607. }
  3608.  
  3609. var blast_hump = [ 255,255,252,247,240,232,222,211,
  3610. 199,186,173,159,145,132,119,106,
  3611. 94,82,72,62,53,45,38,32,
  3612. 26,22,18,14,11,9,7,5,0 ];
  3613.  
  3614. class BlastFClass extends FUNCTION {
  3615. constructor(FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT_ARG) {
  3616. super("Blast effect function", Array.from(arguments));
  3617. this.add_arg("FADEOUT_MS", "INT", "fadeout time in milliseconds", 200);
  3618. this.add_arg("WAVE_SIZE", "INT", "wave size", 100);
  3619. this.add_arg("WAVE_MS", "INT", "wave speed", 400);
  3620. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3621. }
  3622. run(blade) {
  3623. this.T = micros();
  3624. this.num_leds_ = 1.0 * blade.num_leds();
  3625. this.effects_ = blade.GetEffects();
  3626. }
  3627. getInteger(led) {
  3628. var b = 0.0;
  3629. for (var i = 0; i < this.effects_.length; i++) {
  3630. if (this.effects_[i].type != this.EFFECT) continue;
  3631. var T = (this.T - this.effects_[i].start_micros);
  3632. var M = 1000 - T / this.FADEOUT_MS;
  3633. if (M > 0) {
  3634. var dist = Math.abs(this.effects_[i].location - led / this.num_leds_);
  3635. var N = Math.floor(Math.abs(dist - T / (this.WAVE_MS * 1000.0)) * this.WAVE_SIZE);
  3636. if (N < 32) {
  3637. b += blast_hump[N] * M / 1000.0 / 255.0;
  3638. }
  3639. }
  3640. }
  3641. return clamp(b * 32768, 0, 32768);
  3642. }
  3643. };
  3644.  
  3645. function BlastF(FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT) {
  3646. return new BlastFClass(FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT);
  3647. }
  3648.  
  3649. class BlastLClass extends MACRO {
  3650. constructor(BLAST, FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT_ARG) {
  3651. super("Blast layer", Array.from(arguments));
  3652. this.add_arg("BLAST", "COLOR", "blast color");
  3653. this.add_arg("FADEOUT_MS", "INT", "fadeout time in milliseconds", 200);
  3654. this.add_arg("WAVE_SIZE", "INT", "wave size", 100);
  3655. this.add_arg("WAVE_MS", "INT", "wave speed", 400);
  3656. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3657. this.SetExpansion(AlphaL(BLAST, BlastF(FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT_ARG)));
  3658. }
  3659. argify(state) {
  3660. state.color_argument = BLAST_COLOR_ARG;
  3661. var ret = super.argify(state);
  3662. state.color_argument = null;
  3663. return ret;
  3664. }
  3665. };
  3666.  
  3667. function BlastL(BLAST, FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT) {
  3668. return new BlastLClass(BLAST, FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT);
  3669. }
  3670.  
  3671. class BlastClass extends MACRO {
  3672. constructor(BASE, BLAST, FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT_ARG) {
  3673. super("Blast effect", Array.from(arguments));
  3674. this.add_arg("BASE", "COLOR", "base color");
  3675. this.add_arg("BLAST", "COLOR", "blast color");
  3676. this.add_arg("FADEOUT_MS", "INT", "fadeout time in milliseconds", 200);
  3677. this.add_arg("WAVE_SIZE", "INT", "wave size", 100);
  3678. this.add_arg("WAVE_MS", "INT", "wave speed", 400);
  3679. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3680. this.SetExpansion(Layers(BASE, BlastL(BLAST, FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT_ARG)));
  3681. }
  3682. };
  3683.  
  3684. function Blast(BASE, BLAST, FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT) {
  3685. return new BlastClass(BASE, BLAST, FADEOUT_MS, WAVE_SIZE, WAVE_MS, EFFECT);
  3686. }
  3687.  
  3688. class BlastFadeoutFClass extends FUNCTION {
  3689. constructor(FADEOUT_MS, EFFECT_ARG) {
  3690. super("Fadeout on blast function", Array.from(arguments));
  3691. this.add_arg("FADEOUT_MS", "INT", "fadeout time in milliseconds", 200);
  3692. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3693. }
  3694. run(blade) {
  3695. super.run(blade);
  3696. this.T = micros();
  3697. this.effects_ = blade.GetEffects();
  3698. }
  3699. getInteger(led) {
  3700. var b = 0.0;
  3701. for (var i = 0; i < this.effects_.length; i++) {
  3702. if (this.effects_[i].type != this.EFFECT) continue;
  3703. var T = (this.T - this.effects_[i].start_micros);
  3704. var M = 1000 - T / this.FADEOUT_MS;
  3705. if (M > 0) {
  3706. b += M / 1000.0;
  3707. }
  3708. }
  3709. return clamp(b * 32768.0, 0, 32768.0);
  3710. }
  3711. };
  3712.  
  3713. function BlastFadeoutF(FADEOUT_MS, EFFECT) {
  3714. return new BlastFadeoutFClass(FADEOUT_MS, EFFECT);
  3715. }
  3716.  
  3717.  
  3718. class BlastFadeoutLClass extends MACRO {
  3719. constructor(BLAST, FADEOUT_MS, EFFECT_ARG) {
  3720. super("BlastFadeout layers", Array.from(arguments));
  3721. this.add_arg("BLAST", "COLOR", "blast color");
  3722. this.add_arg("FADEOUT_MS", "INT", "fadeout time in milliseconds", 200);
  3723. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3724. this.SetExpansion(AlphaL(BLAST, BlastFadeoutF(FADEOUT_MS, EFFECT_ARG)));
  3725. }
  3726. };
  3727.  
  3728. function BlastFadeoutL(BLAST, FADEOUT_MS, EFFECT) {
  3729. return new BlastFadeoutLClass(BLAST, FADEOUT_MS, EFFECT);
  3730. }
  3731.  
  3732.  
  3733. class BlastFadeoutClass extends MACRO {
  3734. constructor(BASE, BLAST, FADEOUT_MS, EFFECT_ARG) {
  3735. super("BlastFadeout effect", Array.from(arguments));
  3736. this.add_arg("BASE", "COLOR", "base color");
  3737. this.add_arg("BLAST", "COLOR", "blast color");
  3738. this.add_arg("FADEOUT_MS", "INT", "fadeout time in milliseconds", 200);
  3739. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3740. this.SetExpansion(Layers(BASE, BlastFadeoutL(BLAST, FADEOUT_MS, EFFECT_ARG)));
  3741. }
  3742. };
  3743.  
  3744. function BlastFadeout(BASE, BLAST, FADEOUT_MS, EFFECT) {
  3745. return new BlastFadeoutClass(BASE, BLAST, FADEOUT_MS, EFFECT);
  3746. }
  3747.  
  3748. class OriginalBlastFClass extends FUNCTION {
  3749. constructor(BASE, BLAST, EFFECT_ARG) {
  3750. super("Original blast effect", Array.from(arguments));
  3751. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3752. }
  3753. run(blade) {
  3754. super.run(blade);
  3755. this.T = micros();
  3756. this.num_leds_ = 1.0 * blade.num_leds();
  3757. this.effects_ = blade.GetEffects();
  3758. }
  3759. getInteger(led) {
  3760. var b = 0.0;
  3761. for (var i = 0; i < this.effects_.length; i++) {
  3762. if (this.effects_[i].type != this.EFFECT) continue;
  3763. var x = (this.effects_[i].location - led/this.num_leds_) * 30.0;
  3764. var T = (this.T - this.effects_[i].start_micros);
  3765. var t = 0.5 + T / 200000.0;
  3766. if (x == 0.0) {
  3767. b += 1.0 / (t * t);
  3768. } else {
  3769. b += sin(x / (t*t)) / x;
  3770. }
  3771. }
  3772. return min(b, 1.0) * 32768;
  3773. }
  3774. };
  3775.  
  3776. function OriginalBlastF(EFFECT) {
  3777. return new OriginalBlastFClass(EFFECT);
  3778. }
  3779.  
  3780. class OriginalBlastLClass extends MACRO {
  3781. constructor(BLAST, EFFECT_ARG) {
  3782. super("Original blast effect", Array.from(arguments));
  3783. this.add_arg("BLAST", "COLOR", "blast color");
  3784. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3785. this.SetExpansion(AlphaL(BLAST, OriginalBlastF(this.EFFECT)));
  3786. }
  3787. };
  3788.  
  3789. function OriginalBlastL(BLAST, EFFECT) {
  3790. return new OriginalBlastLClass(BLAST, EFFECT);
  3791. }
  3792.  
  3793. class OriginalBlastClass extends MACRO {
  3794. constructor(BASE, BLAST, EFFECT_ARG) {
  3795. super("Original blast effect", Array.from(arguments));
  3796. this.add_arg("BASE", "COLOR", "base color");
  3797. this.add_arg("BLAST", "COLOR", "blast color");
  3798. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  3799. this.SetExpansion(Layers(BASE, OriginalBlastL(BLAST, this.EFFECT)));
  3800. }
  3801. };
  3802.  
  3803. function OriginalBlast(BASE, BLAST, EFFECT) {
  3804. return new OriginalBlastClass(BASE, BLAST, EFFECT);
  3805. }
  3806.  
  3807. class BlinkingFClass extends FUNCTION {
  3808. constructor(BLINK_MILLIS, BLINK_PROMILLE) {
  3809. super("Blinks between 0 and 32768", Array.from(arguments));
  3810. this.add_arg("BLINK_MILLIS", "FUNCTION", "milliseconds between blinks");
  3811. this.add_arg("BLINK_PROMILLE", "FUNCTION", "0 = off, 1000 = on");
  3812. this.on_ = false;
  3813. this.pulse_start_micros_ = 0;
  3814. }
  3815. run(blade) {
  3816. super.run(blade);
  3817. var now = micros();
  3818. var pulse_millis = this.BLINK_MILLIS.getInteger(0);
  3819. if (pulse_millis <= 0) return;
  3820. var pulse_progress_micros = now - this.pulse_start_micros_;
  3821. if (pulse_progress_micros > pulse_millis * 1000) {
  3822. // Time to start a new pulse
  3823. if (pulse_progress_micros < pulse_millis * 2000) {
  3824. this.pulse_start_micros_ += pulse_millis * 1000;
  3825. } else {
  3826. this.pulse_start_micros_ = now;
  3827. }
  3828. pulse_progress_micros = now - this.pulse_start_micros_;
  3829. }
  3830. var pulse_progress_promille = pulse_progress_micros / pulse_millis;
  3831. this.value_ = pulse_progress_promille <= this.BLINK_PROMILLE.getInteger(0) ? 0 : 32768;
  3832. }
  3833. getInteger(led) {
  3834. return this.value_;
  3835. }
  3836. };
  3837.  
  3838. function BlinkingF(BM, BP) {
  3839. return new BlinkingFClass(BM, BP);
  3840. }
  3841.  
  3842. class BlinkingLClass extends MACRO {
  3843. constructor(COLOR, BLINK_MILLIS, BLINK_PROMILLE) {
  3844. super("Blinks transparent/opaque COLOR", Array.from(arguments));
  3845. this.add_arg("COLOR", "COLOR", "COLOR");
  3846. this.add_arg("BLINK_MILLIS", "FUNCTION", "milliseconds between blinks");
  3847. this.add_arg("BLINK_PROMILLE", "FUNCTION", "0 = off, 1000 = on");
  3848. this.SetExpansion(AlphaL(COLOR, BlinkingF(BLINK_MILLIS, BLINK_PROMILLE)));
  3849. }
  3850. };
  3851.  
  3852. function BlinkingL(A, B, BM, BP) {
  3853. return new BlinkingLClass(A, B, BM, BP);
  3854. }
  3855.  
  3856. class BlinkingXClass extends MACRO {
  3857. constructor(COLOR1, COLOR2, BLINK_MILLIS, BLINK_PROMILLE) {
  3858. super("Blinks between A and B", Array.from(arguments));
  3859. this.add_arg("COLOR1", "COLOR", "A");
  3860. this.add_arg("COLOR2", "COLOR", "B");
  3861. this.add_arg("BLINK_MILLIS", "FUNCTION", "milliseconds between blinks");
  3862. this.add_arg("BLINK_PROMILLE", "FUNCTION", "0 = off, 1000 = on");
  3863. this.SetExpansion(Layers(COLOR1, BlinkingL(COLOR2, BLINK_MILLIS, BLINK_PROMILLE)));
  3864. }
  3865. };
  3866.  
  3867. function BlinkingX(A, B, BM, BP) {
  3868. return new BlinkingXClass(A, B, BM, BP);
  3869. }
  3870.  
  3871. class BlinkingClass extends MACRO {
  3872. constructor(COLOR1, COLOR2, BLINK_MILLIS, BLINK_PROMILLE) {
  3873. super("Blinks between A and B", Array.from(arguments));
  3874. this.add_arg("COLOR1", "COLOR", "A");
  3875. this.add_arg("COLOR2", "COLOR", "B");
  3876. this.add_arg("BLINK_MILLIS", "INT", "milliseconds between blinks");
  3877. this.add_arg("BLINK_PROMILLE", "INT", "0 = off, 1000 = on");
  3878. this.SetExpansion(BlinkingX(COLOR1, COLOR2, Int(BLINK_MILLIS), Int(BLINK_PROMILLE)));
  3879. }
  3880. };
  3881.  
  3882. function Blinking(A, B, BM, BP) {
  3883. return new BlinkingClass(A, B, BM, BP);
  3884. }
  3885.  
  3886. class SimpleClashLClass extends STYLE {
  3887. constructor(T, CLASH, CLASH_MILLIS, EFFECT_ARG, STAB_SHAPE) {
  3888. super("Implements the clash effect", Array.from(arguments));
  3889. this.add_arg("CLASH", "COLOR", "Clash color");
  3890. this.add_arg("CLASH_MILLIS", "INT", "How many MS to show the clash color for.", 40);
  3891. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_CLASH));
  3892. this.add_arg("STAB_SHAPE", "FUNCTION", "Stab shape", SmoothStep(Int(16384), Int(24000)));
  3893. this.effect_ = new OneshotEffectDetector(this.EFFECT);
  3894. this.clash_ = false;
  3895. this.stab_ = false;
  3896. }
  3897. run(blade) {
  3898. super.run(blade);
  3899.  
  3900. if (this.clash_ && micros() - this.effect_.last_detected_ > this.CLASH_MILLIS * 1000) {
  3901. this.clash_ = false;
  3902. }
  3903. var e = this.effect_.Detect(blade);
  3904. if (e) {
  3905. this.clash_ = true;
  3906. this.stab_ = this.EFFECT == EFFECT_CLASH && e.type == EFFECT_STAB && blade.num_leds() > 1;
  3907. }
  3908. }
  3909. getColor(led) {
  3910. var ret = Transparent();
  3911. if (this.clash_) {
  3912. var ret = this.CLASH.getColor(led);
  3913. if (this.stab_) {
  3914. ret = ret.multiply(this.STAB_SHAPE.getInteger(led) / 32768.0);
  3915. }
  3916. }
  3917. return ret;
  3918. }
  3919. IS_RUNNING() {
  3920. return this.clash_;
  3921. }
  3922. argify(state) {
  3923. state.color_argument = effect_to_argument(this.EFFECT);
  3924. console.log("STATE IN SIMPLECLASHL:");
  3925. console.log(state);
  3926. var ret = super.argify(state);
  3927. state.color_argument = null;
  3928. return ret;
  3929. }
  3930. };
  3931.  
  3932. function SimpleClashL(T, CLASH, MILLIS, EF, SS) {
  3933. return new SimpleClashLClass(T, CLASH, MILLIS, EF, SS);
  3934. }
  3935.  
  3936. class SimpleClashClass extends MACRO {
  3937. constructor(T, CLASH, CLASH_MILLIS, EFFECT_ARG, STAB_SHAPE) {
  3938. super("Implements the clash effect", Array.from(arguments));
  3939. this.add_arg("T", "COLOR", "base color");
  3940. this.add_arg("CLASH", "COLOR", "Clash color");
  3941. this.add_arg("CLASH_MILLIS", "INT", "How many MS to show the clash color for.", 40);
  3942. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_CLASH));
  3943. this.add_arg("STAB_SHAPE", "FUNCTION", "Stab shape", SmoothStep(Int(16384), Int(24000)));
  3944. this.SetExpansion(Layers(T, SimpleClashL(CLASH, this.CLASH_MILLIS, this.EFFECT, this.STAB_SHAPE)));
  3945. }
  3946. };
  3947.  
  3948. function SimpleClash(T, CLASH, MILLIS, EF, SS) {
  3949. return new SimpleClashClass(T, CLASH, MILLIS, EF, SS);
  3950. }
  3951.  
  3952.  
  3953. class LocalizedClashLClass extends STYLE {
  3954. constructor(CLASH_COLOR, CLASH_MILLIS, CLASH_WIDTH_PERCENT, EFFECT_ARG) {
  3955. super("Localized clash", arguments);
  3956. this.add_arg("CLASH_COLOR", "COLOR", "Clash color", WHITE.DOCOPY());
  3957. this.add_arg("CLASH_MILLIS", "INT", "Clash duration in milliseconds", 40);
  3958. this.add_arg("CLASH_WIDTH_PERCENT", "INT", "Clash width in percent of entire blade", 50);
  3959. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_CLASH));
  3960. this.effect_ = new OneshotEffectDetector(this.EFFECT);
  3961. }
  3962. run(blade) {
  3963. super.run(blade);
  3964.  
  3965. var m = millis();
  3966. var clashing = 0;
  3967. var e = this.effect_.Detect(blade);
  3968. if (e) {
  3969. this.clash = true;
  3970. this.mult = blast_hump.length * 2 * 102400 / this.CLASH_WIDTH_PERCENT / blade.num_leds();
  3971. this.clash_location = e.location * blade.num_leds() * this.mult;
  3972. } else if (micros() - this.effect_.last_detected_ < this.CLASH_MILLIS.getInteger(0) * 1000) {
  3973. this.clash = true;
  3974. } else {
  3975. this.clash = false;
  3976. }
  3977. }
  3978. getColor(led) {
  3979. var ret = Transparent();
  3980. if (this.clash) {
  3981. var dist = Math.floor(Math.abs(led * this.mult - this.clash_location) / 1024);
  3982. if (dist < blast_hump.length) {
  3983. var ret = this.CLASH_COLOR.getColor(led);
  3984. ret = ret.multiply(blast_hump[dist] / 255.0);
  3985. }
  3986. }
  3987. return ret;
  3988. }
  3989. IS_RUNNING() {
  3990. return this.clash;
  3991. }
  3992. argify(state) {
  3993. state.color_argument = effect_to_argument(this.EFFECT);
  3994. var ret = super.argify(state);
  3995. state.color_argument = null;
  3996. return ret;
  3997. }
  3998. }
  3999.  
  4000. function LocalizedClashL(CLASH_COLOR, CLASH_MILLIS, CLASH_WIDTH_PERCENT, EF) {
  4001. return new LocalizedClashLClass(CLASH_COLOR, CLASH_MILLIS, CLASH_WIDTH_PERCENT, EF);
  4002. }
  4003.  
  4004. class LocalizedClashClass extends MACRO {
  4005. constructor(T, CLASH_COLOR, CLASH_MILLIS, CLASH_WIDTH_PERCENT, EFFECT_ARG) {
  4006. super("Localized clash", arguments);
  4007. this.add_arg("T", "COLOR", "base color");
  4008. this.add_arg("CLASH_COLOR", "COLOR", "Clash color", WHITE.DOCOPY());
  4009. this.add_arg("CLASH_MILLIS", "INT", "Clash duration in milliseconds", 40);
  4010. this.add_arg("CLASH_WIDTH_PERCENT", "INT", "Clash width in percent of entire blade", 50);
  4011. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_CLASH));
  4012. this.SetExpansion(Layers(T, LocalizedClashL(this.CLASH_COLOR, this.CLASH_MILLIS, this.CLASH_WIDTH_PERCENT, this.EFFECT)));
  4013. }
  4014. }
  4015.  
  4016. function LocalizedClash(T, CLASH_COLOR, CLASH_MILLIS, CLASH_WIDTH_PERCENT, EF) {
  4017. return new LocalizedClashClass(T, CLASH_COLOR, CLASH_MILLIS, CLASH_WIDTH_PERCENT, EF);
  4018. }
  4019.  
  4020. class LockupLClass extends STYLE {
  4021. isEffect() { return true; }
  4022. constructor(LOCKUP, DRAG_COLOR, LOCKUP_SHAPE, DRAG_SHAPE, LB_SHAPE) {
  4023. super("Implements the lockup and drag effects.", arguments);
  4024. this.add_arg("LOCKUP", "COLOR", "lockup color");
  4025. this.add_arg("DRAG_COLOR", "COLOR", "drag color", this.LOCKUP.DOCOPY());
  4026. this.add_arg("LOCKUP_SHAPE", "FUNCTION", "Lockup shape", Int(32768));
  4027. this.add_arg("DRAG_SHAPE", "FUNCTION", "Drag shape", SmoothStep(Int(28671), Int(4096)));
  4028. this.add_arg("LB_SHAPE", "FUNCTION", "Lightning block shape",
  4029. LayerFunctions(Bump(Scale(SlowNoise(Int(2000)),Int(3000),Int(16000)),
  4030. Scale(BrownNoiseF(Int(10)),Int(14000),Int(8000))),
  4031. Bump(Scale(SlowNoise(Int(2300)),Int(26000),Int(8000)),
  4032. Scale(NoisySoundLevel(),Int(5000),Int(10000))),
  4033. Bump(Scale(SlowNoise(Int(2300)),Int(20000),Int(30000)),
  4034. Scale(IsLessThan(SlowNoise(Int(1500)),Int(8000)),Scale(NoisySoundLevel(),Int(5000),Int(0)),Int(0)))));
  4035. }
  4036. run(blade) {
  4037. super.run(blade);
  4038. this.single_pixel_ = blade.num_leds() == 1;
  4039. this.handled = IsHandledLockup(STATE_LOCKUP);
  4040. }
  4041. getColor(led) {
  4042. var ret = Transparent();
  4043. if (this.handled) return ret;
  4044. if (STATE_LOCKUP == LOCKUP_LIGHTNING_BLOCK) {
  4045. ret = ret.mix(this.LOCKUP.getColor(led), this.LB_SHAPE.getInteger(led) / 32768.0);
  4046. }
  4047. if (STATE_LOCKUP == LOCKUP_DRAG) {
  4048. var blend = this.single_pixel_ ? 32768 : this.DRAG_SHAPE.getInteger(led);
  4049. ret = ret.mix(this.DRAG_COLOR.getColor(led), blend / 32768.0);
  4050. }
  4051. if (STATE_LOCKUP == LOCKUP_NORMAL) {
  4052. ret = ret.mix(this.LOCKUP.getColor(led), this.LOCKUP_SHAPE.getInteger(led) / 32768.0);
  4053. }
  4054. return ret;
  4055. }
  4056. IS_RUNNING() {
  4057. if (this.handled) return false;
  4058. if (STATE_LOCKUP == LOCKUP_LIGHTNING_BLOCK) true;
  4059. if (STATE_LOCKUP == LOCKUP_DRAG) return true;
  4060. if (STATE_LOCKUP == LOCKUP_NORMAL) return true;
  4061. return false;
  4062. }
  4063. argify(state) {
  4064. state.color_argument = LOCKUP_COLOR_ARG;
  4065. this.LOCKUP = this.LOCKUP.argify(state);
  4066. state.color_argument = DRAG_COLOR_ARG;
  4067. this.DRAG_COLOR = this.DRAG_COLOR.argify(state);
  4068. state.color_argument = null;
  4069. return this;
  4070. }
  4071. };
  4072.  
  4073. function LockupL(LOCKUP, DRAG, LOCKUP_SHAPE, DRAG_SHAPE, LB_SHAPE) {
  4074. return new LockupLClass(LOCKUP, DRAG, LOCKUP_SHAPE, DRAG_SHAPE, LB_SHAPE);
  4075. }
  4076.  
  4077. class LockupClass extends MACRO {
  4078. constructor(BASE, LOCKUP, DRAG_COLOR, LOCKUP_SHAPE, DRAG_SHAPE) {
  4079. super("Implements the lockup and drag effects.", arguments);
  4080. this.add_arg("BASE", "COLOR", "base color");
  4081. this.add_arg("LOCKUP", "COLOR", "lockup color");
  4082. this.add_arg("DRAG_COLOR", "COLOR", "drag color", this.LOCKUP.DOCOPY());
  4083. this.add_arg("LOCKUP_SHAPE", "FUNCTION", "Lockup shape", Int(32768));
  4084. this.add_arg("DRAG_SHAPE", "FUNCTION", "Drag shape", SmoothStep(Int(28671), Int(4096)));
  4085. this.SetExpansion(Layers(BASE, LockupL(LOCKUP, DRAG_COLOR, LOCKUP_SHAPE, DRAG_SHAPE)));
  4086. }
  4087. };
  4088.  
  4089. function Lockup(BASE, LOCKUP, DRAG, LOCKUP_SHAPE, DRAG_SHAPE) {
  4090. return new LockupClass(BASE, LOCKUP, DRAG, LOCKUP_SHAPE, DRAG_SHAPE);
  4091. }
  4092.  
  4093.  
  4094. class LockupTrLClass extends STYLE {
  4095. constructor(COLOR, BeginTr, EndTr, LOCKUP_TYPE) {
  4096. super("Transition based lockup effect.", arguments);
  4097. this.add_arg("COLOR", "COLOR", "Effect color.");
  4098. this.add_arg("BEGIN_TR", "TRANSITION", "Begin lockup transition.");
  4099. this.add_arg("END_TR", "TRANSITION", "End lockup transition.");
  4100. this.add_arg("LOCKUP_TYPE", "LOCKUP_TYPE", "Lockup type");
  4101. HandleLockup(LOCKUP_TYPE);
  4102. this.active = false;
  4103. this.begin_active = false;
  4104. this.end_active = false;
  4105. }
  4106. run(blade) {
  4107. super.run(blade);
  4108. if (this.active != (STATE_LOCKUP == this.LOCKUP_TYPE)) {
  4109. this.active = (STATE_LOCKUP == this.LOCKUP_TYPE);
  4110. if (this.active) {
  4111. this.BEGIN_TR.begin();
  4112. this.begin_active = true;
  4113. } else {
  4114. this.END_TR.begin();
  4115. this.end_active = true;
  4116. }
  4117. }
  4118.  
  4119. if (this.begin_active) {
  4120. this.BEGIN_TR.run(blade);
  4121. if (this.BEGIN_TR.done()) this.begin_active = false;
  4122. }
  4123. if (this.end_active) {
  4124. this.END_TR.run(blade);
  4125. if (this.END_TR.done()) this.end_active = false;
  4126. }
  4127. }
  4128. runBegin(a, b, led) {
  4129. if (this.begin_active) {
  4130. return this.BEGIN_TR.getColor(a, b, led);
  4131. } else {
  4132. return b;
  4133. }
  4134. }
  4135. runEnd(a, b, led) {
  4136. if (this.end_active) {
  4137. return this.END_TR.getColor(a, b, led);
  4138. } else {
  4139. return b;
  4140. }
  4141. }
  4142. getColor(led) {
  4143. var off_color = Transparent();
  4144. if (!this.begin_active && !this.end_active) {
  4145. if (this.active) {
  4146. return this.COLOR.getColor(led);
  4147. } else {
  4148. return off_color;
  4149. }
  4150. } else {
  4151. var on_color = this.COLOR.getColor(led);
  4152. if (this.active) {
  4153. return this.runBegin(this.runEnd(on_color, off_color, led), on_color, led);
  4154. } else {
  4155. return this.runEnd(this.runBegin(off_color, on_color, led), off_color, led);
  4156. }
  4157. }
  4158. }
  4159. IS_RUNNING() {
  4160. return this.active;
  4161. }
  4162. argify(state) {
  4163. state.color_argument = lockup_to_argument(this.LOCKUP_TYPE);
  4164. var ret = super.argify(state);
  4165. state.color_argument = null;
  4166. return ret;
  4167. }
  4168. };
  4169.  
  4170. function LockupTrL(COLOR, BeginTr, EndTr, LOCKUP_TYPE) {
  4171. return new LockupTrLClass(COLOR, BeginTr, EndTr, LOCKUP_TYPE);
  4172. }
  4173.  
  4174. class LockupTrClass extends MACRO {
  4175. constructor(BASE, COLOR, BeginTr, EndTr, LOCKUP_TYPE) {
  4176. super("Transition based lockup effect.", arguments);
  4177. this.add_arg("BASE", "COLOR", "Base color.");
  4178. this.add_arg("COLOR", "COLOR", "Effect color.");
  4179. this.add_arg("BEGIN_TR", "TRANSITION", "Begin lockup transition.");
  4180. this.add_arg("END_TR", "TRANSITION", "End lockup transition.");
  4181. this.add_arg("LOCKUP_TYPE", "LOCKUP_TYPE", "Lockup type");
  4182. this.SetExpansion(Layers(BASE, LockupTrL(COLOR, BeginTr, EndTr, LOCKUP_TYPE)));
  4183. }
  4184. argify(state) {
  4185. state.color_argument = lockup_to_argument(this.LOCKUP_TYPE);
  4186. var ret = super.argify(state);
  4187. state.color_argument = null;
  4188. return ret;
  4189. }
  4190. }
  4191.  
  4192. function LockupTr(BASE, COLOR, BeginTr, EndTr, LOCKUP_TYPE) {
  4193. return new LockupTrClass(BASE, COLOR, BeginTr, EndTr, LOCKUP_TYPE);
  4194. }
  4195.  
  4196. const start_millis = new Date().getTime();
  4197. function actual_millis() {
  4198. return new Date().getTime() - start_millis;
  4199. }
  4200. var current_micros = 0;
  4201. function micros() {
  4202. return current_micros;
  4203. }
  4204.  
  4205. function millis() {
  4206. return current_micros / 1000;
  4207. }
  4208.  
  4209. function fract(v) {
  4210. return v - Math.floor(v);
  4211. }
  4212.  
  4213. function FIND(id) {
  4214. ret = document.getElementById(id);
  4215. if (!ret) {
  4216. // console.log("Failed to find " + id);
  4217. }
  4218. return ret;
  4219. }
  4220.  
  4221. var max = Math.max;
  4222. var min = Math.min;
  4223. var sin = Math.sin;
  4224. function random(i) {
  4225. return Math.floor(Math.random() * i);
  4226. }
  4227. function clamp(a, b, c) {
  4228. if (a < b) return b;
  4229. if (a > c) return c;
  4230. return a;
  4231. }
  4232.  
  4233. class Blade {
  4234. constructor() {
  4235. this.effects_ = [];
  4236. }
  4237. is_on() {
  4238. return STATE_ON;
  4239. }
  4240. num_leds() {
  4241. return STATE_NUM_LEDS;
  4242. }
  4243. addEffect(type, location) {
  4244. console.log("Add effect " + type + " @ " + location);
  4245. this.effects_.push(new BladeEffect(type, micros(), location));
  4246. }
  4247. GetEffects() {
  4248. while (this.effects_.length > 0 && micros() - this.effects_[0].start_micros >= 5000000) {
  4249. this.effects_.shift();
  4250. }
  4251. return this.effects_;
  4252. }
  4253. };
  4254.  
  4255. var last_detected_blade_effect;
  4256.  
  4257. var handled_types = {};
  4258. function PushHandledTypes() {
  4259. ret = [ handled_types, handled_lockups ];
  4260. handled_types = {};
  4261. handled_lockups = {};
  4262. return ret;
  4263. }
  4264. function PopHandledTypes(old) {
  4265. handled_types = old[0];
  4266. handled_lockups = old[1];
  4267. }
  4268. function HandleEffectType(t) {
  4269. if (t.getInteger) t = t.getInteger(0);
  4270. handled_types[t] = 1;
  4271. }
  4272. function IsHandledEffectType(t) {
  4273. return current_style.__handled_types[EFFECT_STAB];
  4274. }
  4275.  
  4276. class OneshotEffectDetector {
  4277. constructor(type) {
  4278. this.last_detected_ = 0;
  4279. if (type.getInteger) {
  4280. type = type.getInteger(0);
  4281. }
  4282. this.type_ = type;
  4283. HandleEffectType(type);
  4284. }
  4285. Detect(blade) {
  4286. var mask = {};
  4287. mask[this.type_] = 1;
  4288. if (this.type_ == EFFECT_CLASH && !(current_style.__handled_types[EFFECT_STAB])) {
  4289. mask[EFFECT_STAB] = 1;
  4290. }
  4291.  
  4292. var effects = blade.GetEffects();
  4293. for (var i = effects.length -1 ; i >=0 ; i--) {
  4294. if (mask[effects[i].type]) {
  4295. if (effects[i].start_micros == this.last_detected_)
  4296. return 0;
  4297. this.last_detected_ = effects[i].start_micros;
  4298. last_detected_blade_effect = effects[i];
  4299. return effects[i];
  4300. }
  4301. }
  4302. return 0;
  4303. }
  4304. getDetected(blade) {
  4305. var mask = {};
  4306. mask[this.type_] = 1;
  4307. var effects = blade.GetEffects();
  4308. for (var i = effects.length -1 ; i >=0 ; i--)
  4309. if (mask[effects[i].type])
  4310. if (effects[i].start_micros == this.last_detected_)
  4311. return effects[i];
  4312. return 0;
  4313. }
  4314. };
  4315.  
  4316. var focus_catcher;
  4317. var focus_trace = [undefined];
  4318.  
  4319. function Focus(T) {
  4320. console.log("FOCUS=" + T);
  4321. console.log(T);
  4322. focus_catcher = T;
  4323. focus_trace = [T];
  4324. return T;
  4325. }
  4326.  
  4327. function StylePtr(T) {
  4328. return T;
  4329. }
  4330.  
  4331. class EasyBladeClass extends MACRO {
  4332. constructor(COLOR, CLASH_COLOR, LOCKUP_FLICKER_COLOR) {
  4333. super("Adds clash/lockup/blast/drag", arguments);
  4334. this.add_arg("COLOR","COLOR","Main color");
  4335. this.add_arg("CLASH_COLOR", "COLOR", "Clash color");
  4336. this.add_arg("LOCKUP_FLICKER_COLOR", "COLOR", "lockup flicker color", WHITE.DOCOPY());
  4337.  
  4338. this.SetExpansion(
  4339. SimpleClash(Lockup(Blast(this.COLOR, WHITE.DOCOPY()), AudioFlicker(this.COLOR.DOCOPY(), this.LOCKUP_FLICKER_COLOR)), this.CLASH_COLOR)
  4340. );
  4341. }
  4342. };
  4343.  
  4344. function EasyBlade(color, clash_color, lockup_flicker_color) {
  4345. return new EasyBladeClass(color, clash_color, lockup_flicker_color);
  4346. }
  4347.  
  4348. class StyleNormalPtrClass extends MACRO {
  4349. constructor(base_color, clash_color, out_ms, in_ms, lockup_flicker_color, blast_color) {
  4350. super("Blade to color.", arguments);
  4351. this.add_arg("BASE_COLOR","COLOR","Main color");
  4352. this.add_arg("CLASH_COLOR", "COLOR", "Clash color");
  4353. this.add_arg("OUT_MS", "INT", "extension length in milliseconds");
  4354. this.add_arg("IN_MS", "INT", "retraction length in milliseconds");
  4355. this.add_arg("LOCKUP_FLICKER_COLOR", "COLOR", "lockup flicker color", WHITE.DOCOPY());
  4356. this.add_arg("BLAST_COLOR", "COLOR", "Blast color", WHITE.DOCOPY());
  4357.  
  4358. var tmp = AudioFlicker(this.BASE_COLOR, this.LOCKUP_FLICKER_COLOR);
  4359. var tmp2 = Blast(this.BASE_COLOR.DOCOPY(), this.BLAST_COLOR);
  4360. tmp = Lockup(tmp2, tmp);
  4361. tmp = SimpleClash(tmp, this.CLASH_COLOR);
  4362. this.SetExpansion(InOutHelper(tmp, this.OUT_MS, this.IN_MS));
  4363. }
  4364. }
  4365.  
  4366. function StyleNormalPtr(base_color, clash_color, out_ms, in_ms, lockup_flicker_color, blast_color) {
  4367. return new StyleNormalPtrClass(base_color, clash_color, out_ms, in_ms, lockup_flicker_color, blast_color);
  4368. }
  4369.  
  4370. class StyleRainbowPtrClass extends MACRO {
  4371. constructor(OUT_MS, IN_MS, CLASH_COLOR, LOCKUP_FLICKER_COLOR) {
  4372. super("Rainbow style template", arguments);
  4373. this.add_arg("OUT_MS", "INT", "extension length in milliseconds");
  4374. this.add_arg("IN_MS", "INT", "retraction length in milliseconds");
  4375. this.add_arg("CLASH_COLOR", "COLOR", "Clash color", WHITE.DOCOPY());
  4376. this.add_arg("LOCKUP_FLICKER_COLOR", "COLOR", "lockup flicker color", WHITE.DOCOPY());
  4377.  
  4378. var tmp = AudioFlicker(Rainbow(), this.LOCKUP_FLICKER_COLOR);
  4379. tmp = Lockup(Rainbow(), tmp);
  4380. tmp = SimpleClash(tmp, this.CLASH_COLOR);
  4381. this.SetExpansion(InOutHelper(tmp, this.OUT_MS, this.IN_MS));
  4382. }
  4383. };
  4384.  
  4385. function StyleRainbowPtr(out_ms, in_ms, clash_color, lockup_flicker_color) {
  4386. return new StyleRainbowPtrClass(out_ms, in_ms, clash_color, lockup_flicker_color);
  4387. }
  4388.  
  4389.  
  4390. class StyleStrobePtrClass extends MACRO {
  4391. constructor(STROBE_COLOR, CLASH_COLOR, FREQUENCY, OUT_MS, IN_MS) {
  4392. super("Rainbow style template", arguments);
  4393. this.add_arg("STROBE_COLOR","COLOR","Strobe color");
  4394. this.add_arg("CLASH_COLOR", "COLOR", "Clash color");
  4395. this.add_arg("FREQUENCY", "INT", "frequency");
  4396. this.add_arg("OUT_MS", "INT", "extension length in milliseconds");
  4397. this.add_arg("IN_MS", "INT", "retraction length in milliseconds");
  4398.  
  4399. var strobe = Strobe(BLACK.DOCOPY(), this.STROBE_COLOR, this.FREQUENCY, 1);
  4400. var fast_strobe = Strobe(BLACK.DOCOPY(), this.STROBE_COLOR.DOCOPY(), this.FREQUENCY * 3, 1);
  4401. var tmp = Lockup(strobe, fast_strobe);
  4402. tmp = SimpleClash(tmp, this.CLASH_COLOR);
  4403. this.SetExpansion(InOutHelper(tmp, this.OUT_MS, this.IN_MS));
  4404. }
  4405. };
  4406.  
  4407. function StyleStrobePtr(strobe_color, clash_color, frequency, out_ms, in_ms) {
  4408. return new StyleStrobePtrClass(strobe_color, clash_color, frequency, out_ms, in_ms);
  4409. }
  4410.  
  4411. class StyleFirePtrClass extends MACRO {
  4412. constructor(COLOR1, COLOR2,
  4413. BLADE_NUM, DELAY, SPEED,
  4414. NORM_BASE, NORM_RAND, NORM_COOL,
  4415. CLSH_BASE, CLSH_RAND, CLSH_COOL,
  4416. LOCK_BASE, LOCK_RAND, LOCK_COOL,
  4417. OFF_BASE, OFF_RAND, OFF_COOL) {
  4418. super("Fire Blade", arguments);
  4419. this.add_arg("COLOR1", "COLOR", "Warm color.");
  4420. this.add_arg("COLOR2", "COLOR", "Hot color.");
  4421. this.add_arg("BLADE_NUM", "INT", "Ignored", INT(1));
  4422. this.add_arg("DELAY", "INT", "ignition delay", INT(0));
  4423. this.add_arg("SPEED", "INT", "fire speed", INT(2));
  4424. this.add_arg("NORM_BASE", "INT", "constant heat added in normal mode", INT(0));
  4425. this.add_arg("NORM_RAND", "INT", "random heat added in normal mode", INT(2000));
  4426. this.add_arg("NORM_COOL", "INT", "cooling in normal mode", INT(5));
  4427.  
  4428. this.add_arg("CLSH_BASE", "INT", "constant heat added in clash mode", INT(3000));
  4429. this.add_arg("CLSH_RAND", "INT", "random heat added in clash mode", INT(0));
  4430. this.add_arg("CLSH_COOL", "INT", "cooling in clash mode", INT(0));
  4431.  
  4432. this.add_arg("LOCK_BASE", "INT", "constant heat added in lockup mode", INT(0));
  4433. this.add_arg("LOCK_RAND", "INT", "random heat added in lockup mode", INT(5000));
  4434. this.add_arg("LOCK_COOL", "INT", "cooling in lockup mode", INT(10));
  4435.  
  4436. this.add_arg("OFF_BASE", "INT", "constant heat added in off mode", INT(0));
  4437. this.add_arg("OFF_RAND", "INT", "random heat added in off mode", INT(0));
  4438. this.add_arg("OFF_COOL", "INT", "cooling in off mode", INT(10));
  4439. this.SetExpansion(StyleFire(
  4440. this.COLOR1, this.COLOR2,
  4441. this.DELAY, this.SPEED,
  4442. FireConfig(this.NORM_BASE, this.NORM_RAND, this.NORM_COOL),
  4443. FireConfig(this.CLSH_BASE, this.CLSH_RAND, this.CLSH_COOL),
  4444. FireConfig(this.LOCK_BASE, this.LOCK_RAND, this.LOCK_COOL),
  4445. FireConfig(this.OFF_BASE, this.OFF_RAND, this.OFF_COOL)));
  4446. }
  4447. };
  4448.  
  4449. function StyleFirePtr(COLOR1, COLOR2,
  4450. BLADE_NUM, DELAY, SPEED,
  4451. NORM_BASE, NORM_RAND, NORM_COOL,
  4452. CLSH_BASE, CLSH_RAND, CLSH_COOL,
  4453. LOCK_BASE, LOCK_RAND, LOCK_COOL,
  4454. OFF_BASE, OFF_RAND, OFF_COOL) {
  4455. return new StyleFirePtrClass(COLOR1, COLOR2,
  4456. BLADE_NUM, DELAY, SPEED,
  4457. NORM_BASE, NORM_RAND, NORM_COOL,
  4458. CLSH_BASE, CLSH_RAND, CLSH_COOL,
  4459. LOCK_BASE, LOCK_RAND, LOCK_COOL,
  4460. OFF_BASE, OFF_RAND , OFF_COOL);
  4461. }
  4462.  
  4463. class InOutHelperFClass extends FUNCTION {
  4464. constructor(T, EXTENSION, OFF_COLOR, ALLOW_DISABLE) {
  4465. super("0=retracted, 32768=extended", arguments);
  4466. this.add_arg("EXTENSION", "FUNCTION", "extension amount");
  4467. this.add_arg("ALLOW_DISABLE", "INT", "allow disable?", 1);
  4468. }
  4469. run(blade) {
  4470. super.run(blade);
  4471. this.thres = (this.EXTENSION.getInteger(0) * blade.num_leds());
  4472. }
  4473. getInteger(led) {
  4474. return 32768 - clamp(this.thres - led * 32768, 0, 32768);
  4475. }
  4476. }
  4477.  
  4478. function InOutHelperF(EX, AD) {
  4479. return new InOutHelperFClass(EX, AD);
  4480. }
  4481.  
  4482. class InOutHelperLClass extends MACRO {
  4483. isEffect() { return true; }
  4484. constructor(EXTENSION, OFF_COLOR, ALLOW_DISABLE) {
  4485. super("0=retracted, 32768=extended", arguments);
  4486. this.add_arg("EXTENSION", "FUNCTION", "extension amount");
  4487. this.add_arg("OFF_COLOR", "COLOR", "color when retracted", BLACK.DOCOPY());
  4488. this.add_arg("ALLOW_DISABLE", "INT", "allow disable?", 1);
  4489. this.SetExpansion(AlphaL(this.OFF_COLOR, InOutHelperF(EXTENSION, this.ALLOW_DISABLE)));
  4490. }
  4491. }
  4492.  
  4493. function InOutHelperL(EX, O, AD) {
  4494. return new InOutHelperLClass(EX, O, AD);
  4495. }
  4496.  
  4497.  
  4498. class InOutHelperXClass extends MACRO {
  4499. constructor(T, EXTENSION, OFF_COLOR, ALLOW_DISABLE) {
  4500. super("0=retracted, 32768=extended", arguments);
  4501. this.add_arg("T", "COLOR", "base color");
  4502. this.add_arg("EXTENSION", "FUNCTION", "extension amount");
  4503. this.add_arg("OFF_COLOR", "COLOR", "color when retracted", BLACK.DOCOPY());
  4504. this.add_arg("ALLOW_DISABLE", "INT", "allow disable?", 1);
  4505. this.SetExpansion(Layers(T, InOutHelperL(EXTENSION, this.OFF_COLOR, this.ALLOW_DISABLE)));
  4506. }
  4507. }
  4508.  
  4509. function InOutHelperX(T, EX, O, AD) {
  4510. return new InOutHelperXClass(T, EX, O, AD);
  4511. }
  4512.  
  4513.  
  4514. //--
  4515. class InOutHelperClass extends MACRO {
  4516. constructor(T, OUT_MILLIS, IN_MILLIS, OFF_COLOR) {
  4517. super("Extend/extract blade", arguments);
  4518. this.add_arg("T", "COLOR", "Base color");
  4519. this.add_arg("OUT_MILLIS", "INT", "Time to extend.");
  4520. this.add_arg("IN_MILLIS", "INT", "Time to retract.");
  4521. this.add_arg("OFF_COLOR", "COLOR", "color when retracted", BLACK.DOCOPY());
  4522. this.SetExpansion(InOutHelperX(T, InOutFunc(OUT_MILLIS, IN_MILLIS), this.OFF_COLOR));
  4523. }
  4524. };
  4525.  
  4526. function InOutHelper(T, I, O, OFF) {
  4527. return new InOutHelperClass(T, I, O, OFF);
  4528. }
  4529.  
  4530.  
  4531. class InOutSparkTipClass extends STYLE {
  4532. constructor(T, OUT_MILLIS, IN_MILLIS, OFF_COLOR) {
  4533. super("Implements extention/retraction", arguments);
  4534. this.add_arg("T", "COLOR", "base color");
  4535. this.add_arg("OUT_MILLIS", "INT", "extentions length in ms");
  4536. this.add_arg("IN_MILLIS", "INT", "retraction length in ms");
  4537. this.add_arg("SPARK_COLOR", "COLOR", "color of spark tip", WHITE.DOCOPY());
  4538. this.last_micros_ = 0;
  4539. this.extension = 0;
  4540. }
  4541. run(blade) {
  4542. this.T.run(blade);
  4543. this.SPARK_COLOR.run(blade);
  4544.  
  4545. var now = micros();
  4546. var delta = now - this.last_micros_;
  4547. this.last_micros_ = now;
  4548. if (blade.is_on()) {
  4549. if (this.extension == 0.0) {
  4550. // We might have been off for a while, so delta might
  4551. // be insanely high.
  4552. this.extension = 0.00001;
  4553. } else {
  4554. this.extension += delta / (this.OUT_MILLIS * 1000.0);
  4555. this.extension = Math.min(this.extension, 1.0);
  4556. }
  4557. } else {
  4558. this.extension -= delta / (this.IN_MILLIS * 1000.0);
  4559. this.extension = Math.max(this.extension, 0.0);
  4560. }
  4561. var thres = this.extension * (blade.num_leds() + 5) * 256;
  4562. this.thres1 = Math.floor(thres);
  4563. if (blade.is_on()) {
  4564. this.thres2 = Math.floor(thres) - 1024;
  4565. } else {
  4566. this.thres2 = Math.floor(thres) + 1024;
  4567. }
  4568. }
  4569. getColor(led) {
  4570. var x1 = led + 1 - this.thres1 / 256.0;
  4571. x1 = min(x1, 1.0);
  4572. x1 = max(x1, 0.0);
  4573. var x2 = led + 1 - this.thres2 / 256.0;
  4574. x2 = min(x2, 1.0);
  4575. x2 = max(x2, 0.0);
  4576. var c = this.T.getColor(led);
  4577. var spark_color = this.SPARK_COLOR.getColor(led);
  4578. var off = Rgb(0,0,0);
  4579. return c.mix(spark_color, x2).mix(off, x1);
  4580. }
  4581. };
  4582.  
  4583. function InOutSparkTip(T, I, O, S) {
  4584. return new InOutSparkTipClass(T, I, O, S);
  4585. }
  4586.  
  4587. class ColorChangeClass extends MACRO {
  4588. constructor(ARGS) {
  4589. super("Change color based on variation", ARGS);
  4590. this.COLORS = Array.from(ARGS).slice(1);
  4591. this.add_arg("TRANSITION", "TRANSITION","Transition");
  4592. for (var i = 1; i < this.COLORS.length + 1; i++)
  4593. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  4594. this.SetExpansion(new ColorSelectClass([Variation(), this.TRANSITION].concat(this.COLORS)));
  4595. }
  4596. };
  4597.  
  4598. function ColorChange(T, A, B) {
  4599. return new ColorChangeClass(Array.from(arguments));
  4600. }
  4601.  
  4602. class ColorSelectClass extends STYLE {
  4603. constructor(ARGS) {
  4604. super("Change color based on function", ARGS);
  4605. this.COLORS = Array.from(ARGS).slice(2);
  4606. this.add_arg("F", "FUNCTION","Selector function");
  4607. this.add_arg("TRANSITION", "TRANSITION","Transition");
  4608. for (var i = 1; i < this.COLORS.length + 1; i++)
  4609. this.add_arg("COLOR" + i, "COLOR", "COLOR " + i);
  4610. this.selection = this.F.getInteger(0);
  4611. this.old_selection = this.selection;
  4612. if (this.F.pp() == "Variation") {
  4613. HandleEffectType(EFFECT_CHANGE);
  4614. }
  4615. }
  4616. run(blade) {
  4617. this.F.run(blade);
  4618. for (var i = 0; i < this.COLORS.length; i++)
  4619. this.COLORS[i].run(blade);
  4620. var f = this.F.getInteger(0);
  4621. while (f < 0) f += this.COLORS.length * 256;
  4622. var selection = f % this.COLORS.length;
  4623. if (selection != this.selection) {
  4624. // Start transition
  4625. this.old_selection = this.selection;
  4626. this.selection = selection;
  4627. this.TRANSITION.begin();
  4628. }
  4629. if (this.selection != this.old_selection) {
  4630. this.TRANSITION.run(blade);
  4631. if (this.TRANSITION.done()) {
  4632. this.old_selection = this.selection;
  4633. }
  4634. }
  4635. }
  4636. getColor(led) {
  4637. var ret = this.COLORS[this.selection + 0].getColor(led);
  4638. if (this.selection != this.old_selection) {
  4639. var old = this.COLORS[this.old_selection].getColor(led);
  4640. ret = this.TRANSITION.getColor(old, ret, led);
  4641. }
  4642. return ret;
  4643. }
  4644. };
  4645.  
  4646. function ColorSelect(F, T, A, B) {
  4647. return new ColorSelectClass(Array.from(arguments));
  4648. }
  4649.  
  4650. class IntSelectClass extends FUNCTION {
  4651. constructor(ARGS) {
  4652. super("Select number based on function", ARGS);
  4653. this.INTS = Array.from(ARGS).slice(1);
  4654. this.add_arg("F", "FUNCTION","Selector function");
  4655. for (var i = 1; i <= this.INTS.length; i++)
  4656. this.add_arg("INT" + i, "INT", "Integer " + i);
  4657. }
  4658. run(blade) {
  4659. this.F.run(blade);
  4660. var f = this.F.getInteger(0);
  4661. while (f < 0) f += this.COLORS.length * 256;
  4662. f = f % this.INTS.length;
  4663. this.value = this.INTS[f];
  4664. }
  4665. getInteger(led) {
  4666. return this.value;
  4667. }
  4668. };
  4669.  
  4670. function IntSelect(ARGS) {
  4671. return new IntSelectClass(Array.from(arguments));
  4672. }
  4673.  
  4674. class TransitionLoopLClass extends STYLE {
  4675. constructor(TRANSITION) {
  4676. super("Continiously loop a transition",arguments);
  4677. this.add_arg("TRANSITION", "TRANSITION", "Transition");
  4678. this.TRANSITION.begin();
  4679. }
  4680. run(blade) {
  4681. if (this.TRANSITION.done()) this.TRANSITION.begin();
  4682. super.run(blade);
  4683. }
  4684. getColor(led) {
  4685. return this.TRANSITION.getColor(Transparent(), Transparent(), led);
  4686. }
  4687. };
  4688.  
  4689. function TransitionLoopL(T) { return new TransitionLoopLClass(T); }
  4690.  
  4691. class TransitionLoopClass extends MACRO {
  4692. constructor(COLOR, TRANSITION) {
  4693. super("Continiously loop a transition",arguments);
  4694. this.add_arg("COLOR", "COLOR", "Color");
  4695. this.add_arg("TRANSITION", "TRANSITION", "Transition");
  4696. this.SetExpansion(Layers(COLOR, TransitionLoopL(TRANSITION)));
  4697. }
  4698. };
  4699.  
  4700. function TransitionLoop(C, T) { return new TransitionLoopClass(C, T); }
  4701.  
  4702. class MultiTransitionEffectLClass extends STYLE {
  4703. constructor(TRANSITION, EFFECT_ARG, N) {
  4704. super("Trigger transitions on an effect.", arguments);
  4705. this.add_arg("TRANSITION", "TRANSITION", "from EFFECT_COLOR T");
  4706. this.add_arg("EFFECT", "EFFECT", "Effect type");
  4707. this.add_arg("N", "INT", "Simultaneous effects.", 3);
  4708. this.effect_ = new OneshotEffectDetector(this.EFFECT);
  4709. this.TRANSITIONS=[];
  4710. this.running=[];
  4711. this.pos = 0;
  4712. for (var i = 0; i < this.N; i++) {
  4713. this.TRANSITIONS.push(this.TRANSITION.DOCOPY());
  4714. this.running.push(false);
  4715. }
  4716. HandleEffectType(EFFECT_ARG);
  4717. }
  4718. run(blade) {
  4719. var e = this.effect_.Detect(blade);
  4720. if (e) {
  4721. this.TRANSITIONS[this.pos].begin();
  4722. this.running[this.pos] = true;
  4723. this.pos++;
  4724. if (this.pos == this.N) this.pos = 0;
  4725. }
  4726. for (var i = 0; i < this.N; i++) {
  4727. if (this.running[i]) {
  4728. this.TRANSITIONS[i].run(blade);
  4729. if (this.TRANSITIONS[i].done()) {
  4730. this.running[i] = false;
  4731. }
  4732. }
  4733. }
  4734. }
  4735. getColor(led) {
  4736. var ret = Transparent();
  4737. var P = this.pos + 1;
  4738. for (var i = 0; i < this.N; i++) {
  4739. if (P > this.N) P = 0;
  4740. if (this.running[P]) {
  4741. ret = this.TRANSITIONS[P].getColor(ret, ret, led);
  4742. }
  4743. P++;
  4744. }
  4745. return ret;
  4746. }
  4747. IS_RUNNING() {
  4748. for (var i = 0; i < this.N; i++) {
  4749. if(this.running[i]) return true;
  4750. }
  4751. return false;
  4752. }
  4753.  
  4754. argify(state) {
  4755. state.color_argument = effect_to_argument(this.EFFECT);
  4756. var ret = super.argify(state);
  4757. state.color_argument = null;
  4758. return ret;
  4759. }
  4760. };
  4761.  
  4762. function MultiTransitionEffectL(T, E, N) {
  4763. return new MultiTransitionEffectLClass(T, E, N);
  4764. }
  4765.  
  4766. class MultiTransitionEffectClass extends MACRO {
  4767. constructor(T, EFFECT_COLOR, TRANSITION1, TRANSITION2, EFFECT, N) {
  4768. super("Trigger transitions on an effect.", arguments);
  4769. this.add_arg("T", "COLOR", "Base color.");
  4770. this.add_arg("EFFECT_COLOR", "COLOR", "Effect color.");
  4771. this.add_arg("TRANSITION1", "TRANSITION", "from T to EFFECT_COLOR");
  4772. this.add_arg("TRANSITION2", "TRANSITION", "from EFFECT_COLOR T");
  4773. this.add_arg("EFFECT", "EFFECT", "Effect type");
  4774. this.add_arg("N", "INT", "Number of simultaneous effects.", 3);
  4775. this.SetExpansion(Layers(this.T, MultiTransitionEffectL(TrConcat(this.TRANSITION1, this.EFFECT_COLOR, this.TRANSITION2), this.EFFECT, this.N)));
  4776. }
  4777. };
  4778.  
  4779. function MultiTransitionEffect(T, EC, T1, T2, E, N) {
  4780. return new MultiTransitionEffectClass(T, EC, T1, T2, E, N);
  4781. }
  4782.  
  4783. class TransitionEffectLClass extends STYLE {
  4784. constructor(EFFECT_COLOR, TRANSITION1, TRANSITION2, EFFECT_ARG) {
  4785. super("Trigger transitions on an effect.", arguments);
  4786. this.add_arg("TRANSITION", "TRANSITION", "from EFFECT_COLOR T");
  4787. this.add_arg("EFFECT", "EFFECT", "Effect type");
  4788. this.effect_ = new OneshotEffectDetector(this.EFFECT);
  4789. this.run_ = false;
  4790. }
  4791. run(blade) {
  4792. var e = this.effect_.Detect(blade);
  4793. if (e) {
  4794. this.TRANSITION.begin();
  4795. this.run_ = true;
  4796. }
  4797. this.TRANSITION.run(blade);
  4798. if (this.run_ && this.TRANSITION.done()) {
  4799. this.run_ = false;
  4800. }
  4801. }
  4802. getColor(led) {
  4803. var ret = Transparent();
  4804. if (this.run_) {
  4805. ret = this.TRANSITION.getColor(ret, ret, led);
  4806. }
  4807. return ret;
  4808. }
  4809. IS_RUNNING() { return this.run_; }
  4810.  
  4811. argify(state) {
  4812. state.color_argument = effect_to_argument(this.EFFECT);
  4813. var ret = super.argify(state);
  4814. state.color_argument = null;
  4815. return ret;
  4816. }
  4817. };
  4818.  
  4819. function TransitionEffectL(T, E) {
  4820. return new TransitionEffectLClass(T, E);
  4821. }
  4822.  
  4823. class TransitionEffectClass extends MACRO {
  4824. constructor(T, EFFECT_COLOR, TRANSITION1, TRANSITION2, EFFECT_ARG) {
  4825. super("Trigger transitions on an effect.", arguments);
  4826. this.add_arg("T", "COLOR", "Base color.");
  4827. this.add_arg("EFFECT_COLOR", "COLOR", "Effect color.");
  4828. this.add_arg("TRANSITION1", "TRANSITION", "from T to EFFECT_COLOR");
  4829. this.add_arg("TRANSITION2", "TRANSITION", "from EFFECT_COLOR T");
  4830. this.add_arg("EFFECT", "EFFECT", "Effect type");
  4831. this.SetExpansion(Layers(this.T, TransitionEffectL(TrConcat(this.TRANSITION1, this.EFFECT_COLOR, this.TRANSITION2), this.EFFECT)));
  4832. }
  4833. };
  4834.  
  4835. function TransitionEffect(T, EC, T1, T2, E) {
  4836. return new TransitionEffectClass(T, EC, T1, T2, E);
  4837. }
  4838.  
  4839. class TransitionPulseLClass extends STYLE {
  4840. constructor(TRANSITION, PULSE) {
  4841. super("Triggers transition when pulse occurs.", arguments);
  4842. this.add_arg("TRANSITION", "TRANSITION", "Transition.");
  4843. this.add_arg("PULSE", "FUNCTION", "Pulse.");
  4844. this.run_ = false;
  4845. }
  4846. run(blade) {
  4847. this.PULSE.run(blade);
  4848. if (this.PULSE.getInteger(0)) {
  4849. this.TRANSITION.begin();
  4850. this.run_ = true;
  4851. }
  4852. if (this.run_) {
  4853. this.TRANSITION.run(blade);
  4854. if (this.TRANSITION.done()) this.run_ = false;
  4855. }
  4856. }
  4857. getColor(led) {
  4858. if (this.run_) {
  4859. return this.TRANSITION.getColor(Transparent(), Transparent(), led);
  4860. } else {
  4861. return Transparent();
  4862. }
  4863. }
  4864. }
  4865. function TransitionPulseL(TRANSITION, PULSE) {
  4866. return new TransitionPulseLClass(TRANSITION, PULSE);
  4867. }
  4868.  
  4869. class InOutTrLClass extends STYLE {
  4870. isEffect() { return true; }
  4871. constructor(OUT_TR, IN_TR, OFF, AD) {
  4872. super("In-out based on transitions", arguments);
  4873. this.add_arg("OUT_TR", "TRANSITION", "IN-OUT transition");
  4874. this.add_arg("IN_TR", "TRANSITION", "OUT-IN transition");
  4875. this.add_arg("OFF", "COLOR", "Color when off", BLACK.DOCOPY());
  4876. this.add_arg("ALLOW_DISABLE", "INT", "allow disable?", 1);
  4877. this.on_ = false;
  4878. this.out_active_ = false;
  4879. this.in_active_ = false;
  4880. }
  4881. run(blade) {
  4882. this.OFF.run(blade);
  4883.  
  4884. if (this.on_ != blade.is_on()) {
  4885. this.on_ = blade.is_on();
  4886. if (this.on_) {
  4887. this.OUT_TR.begin();
  4888. this.out_active_ = true;
  4889. } else {
  4890. this.IN_TR.begin();
  4891. this.in_active_ = true;
  4892. }
  4893. }
  4894.  
  4895. if (this.out_active_) {
  4896. this.OUT_TR.run(blade);
  4897. if (this.OUT_TR.done()) {
  4898. this.out_active_ = false;
  4899. }
  4900. }
  4901.  
  4902. if (this.in_active_) {
  4903. this.IN_TR.run(blade);
  4904. if (this.IN_TR.done()) {
  4905. this.in_active_ = false;
  4906. }
  4907. }
  4908. }
  4909.  
  4910. runIn(A, B, led) {
  4911. if (this.in_active_) {
  4912. return this.IN_TR.getColor(A, B, led);
  4913. } else {
  4914. return B;
  4915. }
  4916. }
  4917.  
  4918. runOut(A, B, led) {
  4919. if (this.out_active_) {
  4920. return this.OUT_TR.getColor(A, B, led);
  4921. } else {
  4922. return B;
  4923. }
  4924. }
  4925.  
  4926. getColor(led) {
  4927. if (!this.out_active_ && !this.in_active_) {
  4928. if (this.on_) {
  4929. return Transparent();
  4930. } else {
  4931. return this.OFF.getColor(led);
  4932. }
  4933. } else {
  4934. var on = Transparent();
  4935. var off = this.OFF.getColor(led);
  4936. if (this.on_) {
  4937. return this.runOut(this.runIn(on, off, led), on, led);
  4938. } else {
  4939. return this.runIn(this.runOut(off, on, led), off, led);
  4940. }
  4941. }
  4942. }
  4943. };
  4944.  
  4945. function InOutTrL(OUT_TR, IN_TR, OFF, AD) {
  4946. return new InOutTrLClass(OUT_TR, IN_TR, OFF, AD);
  4947. }
  4948.  
  4949. class InOutTrClass extends MACRO {
  4950. constructor(ON, OUT_TR, IN_TR, OFF, AD) {
  4951. super("In-out based on transitions", arguments);
  4952. this.add_arg("ON", "COLOR", "Color when on.");
  4953. this.add_arg("OUT_TR", "TRANSITION", "IN-OUT transition");
  4954. this.add_arg("IN_TR", "TRANSITION", "OUT-IN transition");
  4955. this.add_arg("OFF", "COLOR", "Color when off", BLACK.DOCOPY());
  4956. this.add_arg("ALLOW_DISABLE", "INT", "allow disable?", 1);
  4957. this.SetExpansion(Layers(ON, InOutTrL(OUT_TR, IN_TR, this.OFF, this.ALLOW_DISABLE)));
  4958. }
  4959. };
  4960.  
  4961. function InOutTr(ON, OUT_TR, IN_TR, OFF, AD) {
  4962. return new InOutTrClass(ON, OUT_TR, IN_TR, OFF, AD);
  4963. }
  4964.  
  4965. class RotateColorsXClass extends STYLE {
  4966. constructor(ROTATION, COLOR) {
  4967. super("Rotate colors", arguments);
  4968. this.add_arg("ROTATION", "FUNCTION", "Rotation");
  4969. this.add_arg("COLOR", "COLOR", "Color");
  4970. }
  4971. getColor(led) {
  4972. var ret = this.COLOR.getColor(led);
  4973. return ret.rotate((this.ROTATION.getInteger(led) & 0x7fff) * 3);
  4974. }
  4975. argify(state) {
  4976. if (this.ROTATION.constructor == VariationClass) {
  4977. return this.COLOR.argify(state);
  4978. }
  4979. return super.argify(state);
  4980. }
  4981. };
  4982.  
  4983. function RotateColorsX(R, C) { return new RotateColorsXClass(R, C); }
  4984.  
  4985. class RotateColorsClass extends MACRO {
  4986. constructor(ROTATION, COLOR) {
  4987. super("Rotate colors", arguments);
  4988. this.add_arg("ROTATION", "INT", "Rotation");
  4989. this.add_arg("COLOR", "COLOR", "Color");
  4990. this.SetExpansion(RotateColorsX(Int(this.ROTATION), this.COLOR));
  4991. }
  4992. };
  4993.  
  4994. function RotateColors(R, C) { return new RotateColorsClass(R, C); }
  4995.  
  4996. class HueXClass extends MACRO {
  4997. constructor(ROTATION, COLOR) {
  4998. super("Rotate colors", arguments);
  4999. this.add_arg("HUE", "FUNCTION", "Hue");
  5000. this.SetExpansion(RotateColorsX(this.HUE, RED.DOCOPY()));
  5001. }
  5002. };
  5003.  
  5004. function HueX(H) { return new HueXClass(H); }
  5005.  
  5006. class HueClass extends MACRO {
  5007. constructor(ROTATION, COLOR) {
  5008. super("Rotate colors", arguments);
  5009. this.add_arg("HUE", "INT", "Hue");
  5010. this.SetExpansion(HueX(Int(this.HUE)));
  5011. }
  5012. };
  5013.  
  5014. function Hue(H) { return new HueClass(H); }
  5015.  
  5016. // TRANSITIONS
  5017.  
  5018. function AddBend(O, t, len, scale) {
  5019. if (O.bend) {
  5020. return O.bend(t, len, scale);
  5021. } else {
  5022. return scale * t / len;
  5023. }
  5024. }
  5025.  
  5026. class BendTimePowXClass extends TIME_FUNCTION {
  5027. constructor(MILLIS, BEND_FUNCTION) {
  5028. super("Bends time like a gamma function.", arguments);
  5029. this.add_arg("MILLIS", "TIME_FUNCTION", "millis");
  5030. this.add_arg("BEND_FUNCTION", "FUNCTION", "bend, 32768 = 1.0");
  5031. }
  5032. getInteger(led) { return this.MILLIS.getInteger(led); }
  5033. bend(t, len, scale) {
  5034. var exponent = this.BEND_FUNCTION.getInteger(0) / 32768.0;
  5035. return scale * Math.pow(AddBend(this.MILLIS, t, len, 1.0), exponent);
  5036. }
  5037. }
  5038.  
  5039. function BendTimePowX(MILLIS, BEND_FUNCTION) {
  5040. return new BendTimePowXClass(MILLIS, BEND_FUNCTION);
  5041. }
  5042.  
  5043. class ReverseTimeXClass extends TIME_FUNCTION {
  5044. constructor(MILLIS) {
  5045. super("Reverses time in a transition.", arguments);
  5046. this.add_arg("MILLIS", "TIME_FUNCTION", "millis");
  5047. }
  5048. getInteger(led) { return this.MILLIS.getInteger(led); }
  5049. bend(t, len, scale) {
  5050. return scale - AddBend(this.MILLIS, t, len, scale);
  5051. }
  5052. }
  5053.  
  5054. function ReverseTimeX(MILLIS) {
  5055. return new ReverseTimeXClass(MILLIS);
  5056. }
  5057.  
  5058. class BendTimePowInvXClass extends MACRO {
  5059. constructor(MILLIS, BEND_FUNCTION) {
  5060. super("Bends time like an inverted gamma function.", arguments);
  5061. this.add_arg("MILLIS", "TIME_FUNCTION", "millis");
  5062. this.add_arg("BEND_FUNCTION", "FUNCTION", "bend, 32768 = 1.0");
  5063. this.SetExpansion(ReverseTimeX(BendTimePowX(ReverseTimeX(MILLIS.DOCOPY()), BEND_FUNCTION.DOCOPY())));
  5064. }
  5065. }
  5066.  
  5067. function BendTimePowInvX(MILLIS, BEND_FUNCTION) {
  5068. return new BendTimePowInvXClass(MILLIS, BEND_FUNCTION);
  5069. }
  5070.  
  5071.  
  5072. class BendTimePowClass extends MACRO {
  5073. constructor(MILLIS, BEND_FUNCTION) {
  5074. super("Bends time like an gamma function.", arguments);
  5075. this.add_arg("MILLIS", "INT", "millis");
  5076. this.add_arg("BEND_FUNCTION", "INT", "bend, 32768 = 1.0");
  5077. this.SetExpansion(BendTimePowX(Int(MILLIS), Int(BEND_FUNCTION)));
  5078. }
  5079. }
  5080.  
  5081. function BendTimePow(MILLIS, BEND_FUNCTION) {
  5082. return new BendTimePowClass(MILLIS, BEND_FUNCTION);
  5083. }
  5084.  
  5085. class BendTimePowInvClass extends MACRO {
  5086. constructor(MILLIS, BEND_FUNCTION) {
  5087. super("Bends time like an inverted gamma function.", arguments);
  5088. this.add_arg("MILLIS", "INT", "millis");
  5089. this.add_arg("BEND_FUNCTION", "INT", "bend, 32768 = 1.0");
  5090. this.SetExpansion(BendTimePowInvX(Int(MILLIS), Int(BEND_FUNCTION)));
  5091. }
  5092. }
  5093.  
  5094. function BendTimePowInv(MILLIS, BEND_FUNCTION) {
  5095. return new BendTimePowInvClass(MILLIS, BEND_FUNCTION);
  5096. }
  5097.  
  5098. class ReverseTimeClass extends MACRO {
  5099. constructor(MILLIS) {
  5100. super("Reverse time in transitions.", arguments);
  5101. this.add_arg("MILLIS", "INT", "millis");
  5102. this.SetExpansion(ReverseTimeX(Int(MILLIS)));
  5103. }
  5104. }
  5105.  
  5106. function ReverseTime(MILLIS) {
  5107. return new ReverseTimeClass(MILLIS);
  5108. }
  5109.  
  5110.  
  5111. class TrInstantClass extends TRANSITION {
  5112. constructor() {
  5113. super("Instant transition");
  5114. }
  5115. run(blade) {}
  5116. begin() {}
  5117. done() { return true; }
  5118. getColor(A, B, led) { return B; }
  5119. };
  5120.  
  5121. function TrInstant() { return new TrInstantClass(); }
  5122.  
  5123. class TRANSITION_BASE extends TRANSITION {
  5124. constructor(comment, args) {
  5125. super(comment, args);
  5126. this.add_arg("MILLIS", "TIME_FUNCTION", "transition time in milliseconds");
  5127. this.restart_ = false;
  5128. this.start_millis = 0;
  5129. this.len_ = 0;
  5130. }
  5131. begin() { this.restart_ = true; }
  5132. done() { return this.len_ == 0; }
  5133. run(blade) {
  5134. super.run(blade);
  5135. if (this.restart_) {
  5136. this.start_millis_ = millis();
  5137. this.len_ = this.MILLIS.getInteger(0);
  5138. this.restart_ = false;
  5139. }
  5140. }
  5141.  
  5142. update(scale) {
  5143. if (this.len_ == 0) return scale;
  5144. var ms = millis() - this.start_millis_;
  5145. if (ms > this.len_) {
  5146. this.len_ = 0;
  5147. return scale;
  5148. }
  5149. var ret = AddBend(this.MILLIS, ms, this.len_, scale);
  5150. return ret;
  5151. }
  5152. restart() { return this.restart_; }
  5153. };
  5154.  
  5155. // Same as TRANSITION_BASE, but with INT argument instead
  5156. // of FUNCTION
  5157. class TRANSITION_BASE2 extends TRANSITION {
  5158. constructor(comment, args) {
  5159. super(comment, args);
  5160. this.add_arg("MILLIS", "INT", "WipeIn time in milliseconds");
  5161. this.restart_ = false;
  5162. this.start_millis = 0;
  5163. this.len_ = 0;
  5164. }
  5165. begin() { this.restart_ = true; }
  5166. done() { return this.len_ == 0; }
  5167. run(blade) {
  5168. this.MILLIS.run(blade);
  5169. if (this.restart_) {
  5170. this.start_millis_ = millis();
  5171. this.len_ = this.MILLIS.getInteger(0);
  5172. this.restart_ = false;
  5173. }
  5174. }
  5175.  
  5176. update(scale) {
  5177. if (this.len_ == 0) return scale;
  5178. var ms = millis() - this.start_millis_;
  5179. if (ms > this.len_) {
  5180. this.len_ = 0;
  5181. return scale;
  5182. }
  5183. return ms * scale / this.len_;
  5184. }
  5185. };
  5186.  
  5187. class TrFadeXClass extends TRANSITION_BASE {
  5188. constructor(MILLIS) {
  5189. super("Fading transition", arguments);
  5190. }
  5191. run(blade) {
  5192. super.run(blade);
  5193. this.fade_ = this.update(1.0);
  5194. }
  5195. getColor(A, B, led) {
  5196. return A.mix(B, this.fade_);
  5197. }
  5198. };
  5199.  
  5200. function TrFadeX(MILLIS) { return new TrFadeXClass(MILLIS); }
  5201.  
  5202. class TrFadeClass extends MACRO {
  5203. constructor(MILLIS) {
  5204. super("Fading transition", arguments);
  5205. this.add_arg("MILLIS","INT", "Fade time in milliseconds.");
  5206. this.SetExpansion(TrFadeX(Int(MILLIS)));
  5207. }
  5208. }
  5209.  
  5210. function TrFade(MILLIS) { return new TrFadeClass(MILLIS); }
  5211.  
  5212. class TrSmoothFadeXClass extends TRANSITION_BASE {
  5213. constructor(MILLIS) {
  5214. super("Smooth fading transition", arguments);
  5215. }
  5216. run(blade) {
  5217. super.run(blade);
  5218. this.fade_ = this.update(1.0);
  5219. this.fade_ = this.fade_ * this.fade_ * (3 - 2 * this.fade_);
  5220. }
  5221. getColor(A, B, led) {
  5222. return A.mix(B, this.fade_);
  5223. }
  5224. };
  5225.  
  5226. function TrSmoothFadeX(MILLIS) { return new TrSmoothFadeXClass(MILLIS); }
  5227.  
  5228. class TrSmoothFadeClass extends MACRO {
  5229. constructor(MILLIS) {
  5230. super("Smooth fading transition", arguments);
  5231. this.add_arg("MILLIS","INT", "SmoothFade time in milliseconds.");
  5232. this.SetExpansion(TrSmoothFadeX(Int(MILLIS)));
  5233. }
  5234. }
  5235.  
  5236. function TrSmoothFade(MILLIS) { return new TrSmoothFadeClass(MILLIS); }
  5237.  
  5238. class TrDelayXClass extends TRANSITION_BASE {
  5239. constructor(MILLIS) {
  5240. super("Delay transition", arguments);
  5241. }
  5242. run(blade) {
  5243. super.run(blade);
  5244. this.update(1.0);
  5245. }
  5246. getColor(A, B, led) {
  5247. if (this.done()) return B;
  5248. return A;
  5249. }
  5250. }
  5251.  
  5252. function TrDelayX(MILLIS) { return new TrDelayXClass(MILLIS); }
  5253.  
  5254. class TrDelayClass extends MACRO {
  5255. constructor(MILLIS) {
  5256. super("Delay transition", arguments);
  5257. this.add_arg("MILLIS", "INT", "Delay time in milliseconds.");
  5258. this.SetExpansion(TrDelayX(Int(MILLIS)));
  5259. }
  5260. }
  5261.  
  5262. function TrDelay(MILLIS) { return new TrDelayClass(MILLIS); }
  5263.  
  5264. class TrBoingXClass extends TRANSITION_BASE {
  5265. constructor(MILLIS, N) {
  5266. super("Boing transition", arguments);
  5267. this.add_arg("N", "INT", "Number of back-and-forth");
  5268. }
  5269. run(blade) {
  5270. this.N.run(blade);
  5271. super.run(blade);
  5272. this.fade_ = this.update(2 * this.N.getInteger(0) + 1) % 2.0;
  5273. if (this.fade_ > 1.0) {
  5274. this.fade_ = 2.0 - this.fade_;
  5275. }
  5276. }
  5277. getColor(A, B, led) {
  5278. return A.mix(B, this.fade_);
  5279. }
  5280. }
  5281.  
  5282. function TrBoingX(MILLIS, N) { return new TrBoingXClass(MILLIS, N); }
  5283.  
  5284. class TrBoingClass extends MACRO {
  5285. constructor(MILLIS, N) {
  5286. super("Boing transition", arguments);
  5287. this.add_arg("MILLIS", "INT", "Boing time in milliseconds.");
  5288. this.add_arg("N", "INT", "Number of back-and-forth");
  5289. this.SetExpansion(TrBoingX(Int(MILLIS), N));
  5290. }
  5291. }
  5292.  
  5293. function TrBoing(MILLIS, N) { return new TrBoingClass(MILLIS, N); }
  5294.  
  5295.  
  5296. class TrWipeXClass extends TRANSITION_BASE {
  5297. constructor(MILLIS) {
  5298. super("Wipe transition", arguments);
  5299. }
  5300. run(blade) {
  5301. super.run(blade);
  5302. this.num_leds_ = blade.num_leds();
  5303. this.fade_ = this.update(this.num_leds_);
  5304. }
  5305. getColor(A, B, led) {
  5306. var mix = (new Range(0, this.fade_).Intersect(new Range(led, (led + 1)))).Size();
  5307. return A.mix(B, mix);
  5308. }
  5309. }
  5310.  
  5311. function TrWipeX(MILLIS) { return new TrWipeXClass(MILLIS); }
  5312.  
  5313. class TrWipeClass extends MACRO {
  5314. constructor(MILLIS) {
  5315. super("Wipe transition", arguments);
  5316. this.add_arg("MILLIS", "INT", "Wipe time in milliseconds.");
  5317. this.SetExpansion(TrWipeX(Int(MILLIS)));
  5318. }
  5319. }
  5320.  
  5321. function TrWipe(MILLIS) { return new TrWipeClass(MILLIS); }
  5322.  
  5323. class TrWipeInXClass extends TRANSITION_BASE {
  5324. constructor(MILLIS) {
  5325. super("WipeIn transition", arguments);
  5326. }
  5327. run(blade) {
  5328. super.run(blade);
  5329. this.num_leds_ = blade.num_leds();
  5330. this.fade_ = new Range(this.num_leds_-
  5331. this.update(this.num_leds_),
  5332. this.num_leds_);
  5333. }
  5334. getColor(A, B, led) {
  5335. var mix = this.fade_.Intersect(new Range(led, (led + 1))).Size();
  5336. return A.mix(B, mix);
  5337. }
  5338. }
  5339.  
  5340. function TrWipeInX(MILLIS) { return new TrWipeInXClass(MILLIS); }
  5341.  
  5342. class TrWipeInClass extends MACRO {
  5343. constructor(MILLIS) {
  5344. super("WipeIn transition", arguments);
  5345. this.add_arg("MILLIS", "INT", "WipeIn time in milliseconds.");
  5346. this.SetExpansion(TrWipeInX(Int(MILLIS)));
  5347. }
  5348. }
  5349.  
  5350. function TrWipeIn(MILLIS) { return new TrWipeInClass(MILLIS); }
  5351.  
  5352. ///// CenterWipe
  5353.  
  5354. class TrCenterWipeXClass extends TRANSITION_BASE {
  5355. constructor(MILLIS, POS) {
  5356. super("Center Wipe transition", arguments);
  5357. this.add_arg("POS", "TIME_FUNCTION", "Position", Int(16384));
  5358. }
  5359. run(blade) {
  5360. super.run(blade);
  5361. var center = (this.POS.getInteger(0) * blade.num_leds()) / 32768.0;
  5362. var fade_top = this.update(blade.num_leds() - center);
  5363. var fade_bottom = this.update(center);
  5364. var top = clamp(center + fade_top, center, blade.num_leds());
  5365. var bottom = clamp(center - fade_bottom, 0, center);
  5366. this.range = new Range(bottom, top);
  5367. }
  5368. getColor(A, B, led) {
  5369. var mix = this.range.Intersect(new Range(led, (led + 1))).Size();
  5370. return A.mix(B, mix);
  5371. }
  5372. }
  5373.  
  5374. function TrCenterWipeX(MILLIS, POS) { return new TrCenterWipeXClass(MILLIS, POS); }
  5375.  
  5376. class TrCenterWipeClass extends MACRO {
  5377. constructor(MILLIS, POS) {
  5378. super("WipeIn transition", arguments);
  5379. this.add_arg("MILLIS", "INT", "Center Wipe time in milliseconds.");
  5380. this.add_arg("POS", "INT", "Position", 16384);
  5381. this.SetExpansion(TrCenterWipeX(Int(MILLIS), Int(this.POS)));
  5382. }
  5383. }
  5384.  
  5385. function TrCenterWipe(MILLIS, POS) { return new TrCenterWipeClass(MILLIS, POS); }
  5386.  
  5387. class TrCenterWipeSparkXClass extends MACRO {
  5388. constructor(COLOR, MILLIS, POS) {
  5389. super("WipeIn transition", arguments);
  5390. this.add_arg("COLOR", "COLOR", "Color");
  5391. this.add_arg("MILLIS", "FUNCTION", "Center Wipe time in milliseconds.");
  5392. this.add_arg("POS", "INT", "Position", Int(16384));
  5393. this.SetExpansion(TrJoin(TrCenterWipeX(MILLIS, this.POS),TrWaveX(COLOR, Sum(MILLIS, MILLIS, MILLIS, MILLIS), Int(200), Sum(MILLIS, MILLIS), this.POS)));
  5394. }
  5395. }
  5396.  
  5397. function TrCenterWipeSparkX(COLOR, MILLIS, POS) { return new TrCenterWipeSparkXClass(COLOR, MILLIS, POS); }
  5398.  
  5399. class TrCenterWipeSparkClass extends MACRO {
  5400. constructor(COLOR, MILLIS, POS) {
  5401. super("WipeIn transition", arguments);
  5402. this.add_arg("COLOR", "COLOR", "Color");
  5403. this.add_arg("MILLIS", "INT", "Center Wipe time in milliseconds.");
  5404. this.add_arg("POS", "INT", "Position", 16384);
  5405. this.SetExpansion(TrJoin(TrCenterWipeX(Int(MILLIS), Int(this.POS)),TrWaveX(COLOR, Sum(Int(MILLIS), Int(MILLIS), Int(MILLIS), Int(MILLIS)), Int(200), Sum(Int(MILLIS), Int(MILLIS)), Int(this.POS))));
  5406. }
  5407. }
  5408.  
  5409. function TrCenterWipeSpark(COLOR, MILLIS, POS) { return new TrCenterWipeSparkClass(COLOR, MILLIS, POS); }
  5410.  
  5411. ///// CenterWipeIn
  5412.  
  5413. class TrCenterWipeInXClass extends TRANSITION_BASE {
  5414. constructor(MILLIS, POS) {
  5415. super("Center Wipe-in transition", arguments);
  5416. this.add_arg("POS", "FUNCTION", "Position", Int(16384));
  5417. }
  5418. run(blade) {
  5419. super.run(blade);
  5420. var center = (this.POS.getInteger(0) * blade.num_leds()) / 32768.0;
  5421. var fade_top = this.update(blade.num_leds() - center);
  5422. var fade_bottom = this.update(center);
  5423. var top = clamp(blade.num_leds() - fade_top, center, blade.num_leds());
  5424. var bottom = clamp(fade_bottom, 0, center);
  5425. this.range = new Range(bottom, top);
  5426. }
  5427. getColor(A, B, led) {
  5428. var mix = this.range.Intersect(new Range(led, (led + 1))).Size();
  5429. return B.mix(A, mix);
  5430. }
  5431. }
  5432.  
  5433. function TrCenterWipeInX(MILLIS, POS) { return new TrCenterWipeInXClass(MILLIS, POS); }
  5434.  
  5435. class TrCenterWipeInClass extends MACRO {
  5436. constructor(MILLIS, POS) {
  5437. super("WipeIn transition", arguments);
  5438. this.add_arg("MILLIS", "INT", "Center Wipe time in milliseconds.");
  5439. this.add_arg("POS", "INT", "Position", 16384);
  5440. this.SetExpansion(TrCenterWipeInX(Int(MILLIS), Int(this.POS)));
  5441. }
  5442. }
  5443.  
  5444. function TrCenterWipeIn(MILLIS, POS) { return new TrCenterWipeInClass(MILLIS, POS); }
  5445.  
  5446. class TrCenterWipeInSparkXClass extends MACRO {
  5447. constructor(COLOR, MILLIS, POS) {
  5448. super("WipeIn transition", arguments);
  5449. this.add_arg("COLOR", "COLOR", "Color");
  5450. this.add_arg("MILLIS", "TIME_FUNCTION", "Center Wipe time in milliseconds.");
  5451. this.add_arg("POS", "INT", "Position", Int(16384));
  5452. this.SetExpansion(TrJoin(TrCenterWipeInX(MILLIS, this.POS),TrJoin(TrWaveX(COLOR, MILLIS.DOCOPY(), Int(200), Sum(MILLIS, MILLIS), Int(0)),TrWaveX(COLOR, MILLIS, Int(200), Sum(MILLIS, MILLIS), Int(32768)))));
  5453.  
  5454. }
  5455. }
  5456.  
  5457. function TrCenterWipeInSparkX(COLOR, MILLIS, POS) { return new TrCenterWipeInSparkXClass(COLOR, MILLIS, POS); }
  5458.  
  5459. class TrCenterWipeInSparkClass extends MACRO {
  5460. constructor(COLOR, MILLIS, POS) {
  5461. super("WipeIn transition", arguments);
  5462. this.add_arg("COLOR", "COLOR", "Color");
  5463. this.add_arg("MILLIS", "INT", "Center Wipe time in milliseconds.");
  5464. this.add_arg("POS", "INT", "Position", 16384);
  5465. this.SetExpansion(TrJoin(TrCenterWipeInX(Int(MILLIS), Int(this.POS)),TrJoin(TrWaveX(COLOR, Int(MILLIS), Int(200), Sum(Int(MILLIS), Int(MILLIS)), Int(0)),TrWaveX(COLOR, Int(MILLIS), Int(200), Sum(Int(MILLIS), Int(MILLIS)), Int(32768)))));
  5466. }
  5467. }
  5468.  
  5469. function TrCenterWipeInSpark(COLOR, MILLIS, POS) { return new TrCenterWipeInSparkClass(COLOR, MILLIS, POS); }
  5470.  
  5471. /////
  5472.  
  5473. class TrWipeSparkTipXClass extends MACRO {
  5474. constructor(SPARK_COLOR, MILLIS, SIZE) {
  5475. super("TrWipe with sparktip", arguments);
  5476. this.add_arg("SPARK_COLOR", "COLOR", "Spark color");
  5477. this.add_arg("MILLIS", "TIME_FUNCTION", "wipe milliseconds");
  5478. this.add_arg("SIZE", "FUNCTION", "Size of spark.", Int(400));
  5479. this.SetExpansion(TrJoin(TrWipeX(MILLIS),TrSparkX(SPARK_COLOR,this.SIZE,MILLIS,Int(0))));
  5480. }
  5481. };
  5482.  
  5483. function TrWipeSparkTipX(C, M, S) { return new TrWipeSparkTipXClass(C, M, S); }
  5484.  
  5485. class TrWipeSparkTipClass extends MACRO {
  5486. constructor(SPARK_COLOR, MILLIS, SIZE) {
  5487. super("TrWipe with sparktip", arguments);
  5488. this.add_arg("SPARK_COLOR", "COLOR", "Spark color");
  5489. this.add_arg("MILLIS", "INT", "wipe milliseconds");
  5490. this.add_arg("SIZE", "INT", "Size of spark.", 400);
  5491. this.SetExpansion(TrJoin(TrWipe(MILLIS),TrSparkX(SPARK_COLOR,Int(this.SIZE),Int(MILLIS),Int(0))));
  5492. }
  5493. };
  5494.  
  5495. function TrWipeSparkTip(C, M, S) { return new TrWipeSparkTipClass(C, M, S); }
  5496.  
  5497. class TrWipeInSparkTipXClass extends MACRO {
  5498. constructor(SPARK_COLOR, MILLIS, SIZE) {
  5499. super("TrWipeIn with sparktip", arguments);
  5500. this.add_arg("SPARK_COLOR", "COLOR", "Spark color");
  5501. this.add_arg("MILLIS", "TIME_FUNCTION", "wipe milliseconds");
  5502. this.add_arg("SIZE", "FUNCTION", "Size of spark.", Int(400));
  5503. this.SetExpansion(TrJoin(TrWipeInX(MILLIS),TrSparkX(SPARK_COLOR,this.SIZE,MILLIS,Int(32768))));
  5504. }
  5505. };
  5506.  
  5507. function TrWipeInSparkTipX(C, M, S) { return new TrWipeInSparkTipXClass(C, M, S); }
  5508.  
  5509. class TrWipeInSparkTipClass extends MACRO {
  5510. constructor(SPARK_COLOR, MILLIS, SIZE) {
  5511. super("TrWipeIn with sparktip", arguments);
  5512. this.add_arg("SPARK_COLOR", "COLOR", "Spark color");
  5513. this.add_arg("MILLIS", "INT", "wipe milliseconds");
  5514. this.add_arg("SIZE", "INT", "Size of spark.", 400);
  5515. this.SetExpansion(TrJoin(TrWipeIn(MILLIS),TrSparkX(SPARK_COLOR,Int(this.SIZE),Int(MILLIS),Int(32768))));
  5516. }
  5517. };
  5518.  
  5519. function TrWipeInSparkTip(C, M, S) { return new TrWipeInSparkTipClass(C, M, S); }
  5520.  
  5521.  
  5522. class TrWaveXClass extends TRANSITION {
  5523. constructor(COLOR, FADEOUT_MS, WAVE_SIZE, WAVE_MS, WAVE_CENTER) {
  5524. super("Wave travelling outwards.", arguments);
  5525. this.add_arg("COLOR", "COLOR", "Wave color.");
  5526. this.add_arg("FADEOUT_MS", "FUNCTION", "Fadeout time in milliseconds.", Int(200));
  5527. this.add_arg("WAVE_SIZE", "FUNCTION", "Wave size.", Int(100));
  5528. this.add_arg("WAVE_MS", "FUNCTION", "Wave millis.", Int(400));
  5529. this.add_arg("WAVE_CENTER", "FUNCTION", "Wave center.", Int(16384));
  5530. this.restart_ = false;
  5531. this.start_millis = 0;
  5532. this.len_ = 0;
  5533. }
  5534. begin() { this.restart_ = true; }
  5535. done() { return this.len_ == 0; }
  5536. run(blade) {
  5537. super.run(blade);
  5538.  
  5539. if (this.restart_) {
  5540. this.center_ = this.WAVE_CENTER.getInteger(0);
  5541. this.size_ = this.WAVE_SIZE.getInteger(0);
  5542.  
  5543. this.start_millis_ = millis();
  5544. this.len_ = this.FADEOUT_MS.getInteger(0);
  5545. this.restart_ = false;
  5546. }
  5547.  
  5548. this.mix_ = 32768 - this.update(32768);
  5549. this.num_leds_ = blade.num_leds();
  5550. this.offset_ = (millis() - this.start_millis_) * 32768 / this.WAVE_MS.getInteger(0);
  5551. }
  5552. getColor(A, B, led) {
  5553. var dist = Math.abs(this.center_ - led * 32768 / this.num_leds_);
  5554. var N = Math.abs(dist - this.offset_) * this.size_ >> 15;
  5555. var mix;
  5556. if (N <= 32) {
  5557. mix = blast_hump[N] * this.mix_ >> 8;
  5558. } else {
  5559. mix = 0;
  5560. }
  5561. return A.mix(this.COLOR.getColor(led), mix / 32768.0);
  5562. }
  5563.  
  5564. update(scale) {
  5565. if (this.len_ == 0) return scale;
  5566. var ms = millis() - this.start_millis_;
  5567. if (ms > this.len_) {
  5568. this.len_ = 0;
  5569. return scale;
  5570. }
  5571. return ms * scale / this.len_;
  5572. }
  5573. };
  5574.  
  5575. function TrWaveX(COLOR, FADEOUT_MS, WAVE_SIZE, WAVE_MS, WAVE_CENTER) {
  5576. return new TrWaveXClass(COLOR, FADEOUT_MS, WAVE_SIZE, WAVE_MS, WAVE_CENTER);
  5577. }
  5578.  
  5579. class TrSparkXClass extends TRANSITION {
  5580. constructor(COLOR, SPARK_SIZE, SPARK_MS, SPARK_CENTER) {
  5581. super("Spark wave transition", arguments);
  5582. this.add_arg("COLOR", "COLOR", "Color.");
  5583. this.add_arg("SPARK_SIZE", "FUNCTION", "Spark size.", Int(100));
  5584. this.add_arg("SPARK_MS", "TIME_FUNCTION", "Spark MS", Int(100));
  5585. this.add_arg("SPARK_CENTER", "FUNCTION", "Spark center.", Int(16384));
  5586. this.millis = new TRANSITION_BASE("millis", [this.SPARK_MS]);
  5587. }
  5588. begin() {
  5589. this.millis.begin();
  5590. }
  5591. run(blade) {
  5592. super.run(blade);
  5593. if (this.millis.restart()) {
  5594. this.center = this.SPARK_CENTER.getInteger(0);
  5595. this.size = this.SPARK_SIZE.getInteger(0);
  5596. }
  5597. this.millis.run(blade);
  5598. this.num_leds = blade.num_leds();
  5599. this.offset = this.millis.update(32768);
  5600. }
  5601. done() {
  5602. return this.millis.done();
  5603. }
  5604. getColor(A, B, led) {
  5605. var dist = Math.abs(this.center - led * 32768 / this.num_leds);
  5606. var N = Math.abs(dist - this.offset) * this.size >> 15;
  5607. var mix;
  5608. if (N <= 32) {
  5609. mix = blast_hump[N] << 7;
  5610. } else {
  5611. mix = 0;
  5612. }
  5613. return A.mix(this.COLOR.getColor(led), mix / 32768.0);
  5614. }
  5615. };
  5616.  
  5617. function TrSparkX(COLOR, SPARK_SIZE, SPARK_MS, SPARK_CENTER) {
  5618. return new TrSparkXClass(COLOR, SPARK_SIZE, SPARK_MS, SPARK_CENTER);
  5619. }
  5620.  
  5621. class TrColorCycleXClass extends TRANSITION_BASE {
  5622. constructor(MILLIS, START_RPM, END_RPM) {
  5623. super("ColorCycle transition", arguments);
  5624. this.add_arg("START_RPM", "INT", "RPM at the beginning of transition", 0);
  5625. this.add_arg("END_RPM", "INT", "RPM at the end of transition", 6000);
  5626. this.pos_ = 0.0;
  5627. this.last_micros_ = 0.0;
  5628. }
  5629. run(blade) {
  5630. super.run(blade);
  5631. var now = micros();
  5632. var delta = now - this.last_micros_;
  5633. this.last_micros_ = now;
  5634. if (delta > 1000000) delta = 1;
  5635.  
  5636. this.fade_ = this.update(1.0);
  5637.  
  5638. var current_rpm = this.START_RPM.getInteger(0) * (1 - this.fade_) + this.END_RPM.getInteger(0) * this.fade_;
  5639. var current_percentage = 100.0 * this.fade_;
  5640. this.pos_ = fract(this.pos_ + delta / 60000000.0 * current_rpm);
  5641. this.num_leds_ = blade.num_leds();
  5642. this.start_ = this.pos_ * this.num_leds_;
  5643. if (current_percentage == 100.0) {
  5644. this.start_ = 0;
  5645. this.end_ = this.num_leds_;
  5646. } else if (current_percentage == 0.0) {
  5647. this.start_ = 0;
  5648. this.end_ = 0;
  5649. } else {
  5650. this.end_ = fract(this.pos_ + current_percentage / 100.0) * this.num_leds_;
  5651. }
  5652. }
  5653. getColor(A, B, led) {
  5654. var led_range = new Range(led, led + 1);
  5655. var mix = 0;
  5656. if (this.start_ <= this.end_) {
  5657. mix = (new Range(this.start_, this.end_).Intersect(led_range)).Size();
  5658. } else {
  5659. mix = (new Range(0, this.end_).Intersect(led_range)).Size() +
  5660. (new Range(this.start_, this.num_leds_).Intersect(led_range)).Size();
  5661. }
  5662. return A.mix(B, mix);
  5663. }
  5664. }
  5665.  
  5666. function TrColorCycleX(MILLIS, START_RPM, END_RPM) { return new TrColorCycleXClass(MILLIS, START_RPM, END_RPM); }
  5667.  
  5668. class TrColorCycleClass extends MACRO {
  5669. constructor(MILLIS, START_RPM, END_RPM) {
  5670. super("ColorCycle transition", arguments);
  5671. this.add_arg("START_RPM", "INT", "RPM at the beginning of transition", 0);
  5672. this.add_arg("END_RPM", "INT", "RPM at the end of transition", 6000);
  5673. this.SetExpansion(TrColorCycleX(Int(MILLIS), this.START_RPM, this.END_RPM))
  5674. }
  5675. }
  5676.  
  5677. function TrColorCycle(MILLIS, START_RPM, END_RPM) { return new TrColorCycleClass(MILLIS, START_RPM, END_RPM); }
  5678.  
  5679. class TrConcatClass extends TRANSITION {
  5680. constructor(ARGS) {
  5681. super("Concatenate transitions", ARGS);
  5682. this.ARGS = Array.from(ARGS);
  5683. this.add_arg("TRANSITION", "TRANSITION", "Transition");
  5684. for (var i = 1; i < this.ARGS.length - 1; i++) {
  5685. if (this.ARGS[i].getType() == "TRANSITION") {
  5686. this.add_arg("TRANSITION" + i, "TRANSITION", "Transiton " + i);
  5687. } else {
  5688. this.add_arg("COLOR" + i, "COLOR", "Color " + i);
  5689. }
  5690. }
  5691. // Last argument must be a transition.
  5692. this.add_arg("TRANSITION" + i, "TRANSITION", "Transiton " + i);
  5693. this.pos_ = this.ARGS.length;
  5694. }
  5695. begin() {
  5696. this.pos_ = 0;
  5697. this.ARGS[0].begin();
  5698. }
  5699. done() {
  5700. return this.pos_ >= this.ARGS.length;
  5701. }
  5702. run(blade) {
  5703. while (true) {
  5704. if (this.pos_ < this.ARGS.length && this.ARGS[this.pos_].done()) {
  5705. this.pos_++;
  5706. if (
  5707. this.pos_ < this.ARGS.length &&
  5708. this.ARGS[this.pos_].getType() != "TRANSITION"
  5709. )
  5710. this.pos_++;
  5711. if (this.pos_ < this.ARGS.length) this.ARGS[this.pos_].begin();
  5712. } else {
  5713. break;
  5714. }
  5715. }
  5716. super.run(blade);
  5717. }
  5718. getColor(A, B, led) {
  5719. if (this.done()) return B;
  5720. if (this.pos_ != 0 && this.ARGS[this.pos_ - 1].getType() != "TRANSITION")
  5721. A = this.ARGS[this.pos_ - 1].getColor(led);
  5722. if (
  5723. this.pos_ < this.ARGS.length - 1 &&
  5724. this.ARGS[this.pos_ + 1].getType() != "TRANSITION"
  5725. )
  5726. B = this.ARGS[this.pos_ + 1].getColor(led);
  5727. return this.ARGS[this.pos_].getColor(A, B, led);
  5728. }
  5729. }
  5730.  
  5731. function TrConcat(ARGS) {
  5732. return new TrConcatClass(Array.from(arguments));
  5733. }
  5734.  
  5735. class TrJoinClass extends TRANSITION {
  5736. constructor(ARGS) {
  5737. super("Join transitions", ARGS);
  5738. this.ARGS = Array.from(ARGS);
  5739. for (var i = 0; i < this.ARGS.length; i++) {
  5740. this.add_arg("TRANSITION" + i, "TRANSITION", "Transiton " + i);
  5741. }
  5742. }
  5743. begin() {
  5744. for (var i = 0; i < this.ARGS.length; i++) this.ARGS[i].begin();
  5745. }
  5746. done() {
  5747. for (var i = 0; i < this.ARGS.length; i++) if (!this.ARGS[i].done()) return false;
  5748. return true;
  5749. }
  5750. getColor(A, B, led) {
  5751. for (var i = 0; i < this.ARGS.length; i++) {
  5752. A = this.ARGS[i].getColor(A, B, led);
  5753. }
  5754. return A;
  5755. }
  5756. };
  5757.  
  5758. function TrJoin(ARGS) { return new TrJoinClass(arguments); }
  5759.  
  5760. class TrJoinRClass extends TRANSITION {
  5761. constructor(ARGS) {
  5762. super("Right join transitions", ARGS);
  5763. this.ARGS = Array.from(ARGS);
  5764. for (var i = 0; i < this.ARGS.length; i++) {
  5765. this.add_arg("TRANSITION" + i, "TRANSITION", "Transiton " + i);
  5766. }
  5767. }
  5768. begin() {
  5769. for (var i = 0; i < this.ARGS.length; i++) this.ARGS[i].begin();
  5770. }
  5771. done() {
  5772. for (var i = 0; i < this.ARGS.length; i++) if (!this.ARGS[i].done()) return false;
  5773. return true;
  5774. }
  5775. getColor(A, B, led) {
  5776. for (var i = 0; i < this.ARGS.length; i++) {
  5777. B = this.ARGS[i].getColor(A, B, led);
  5778. }
  5779. return B;
  5780. }
  5781. };
  5782.  
  5783. function TrJoinR(ARGS) { return new TrJoinRClass(arguments); }
  5784.  
  5785. class TrRandomClass extends TRANSITION {
  5786. constructor(ARGS) {
  5787. super("Random transitions", ARGS);
  5788. this.ARGS = Array.from(ARGS);
  5789. for (var i = 0; i < this.ARGS.length; i++) {
  5790. this.add_arg("TRANSITION" + i, "TRANSITION", "Transiton " + i);
  5791. }
  5792. this.pos_ = random(this.ARGS.length);
  5793. }
  5794. begin() {
  5795. this.pos_ = random(this.ARGS.length);
  5796. this.ARGS[this.pos_].begin();
  5797. }
  5798. done() {
  5799. return this.ARGS[this.pos_].done();
  5800. }
  5801. getColor(A, B, led) {
  5802. return this.ARGS[this.pos_].getColor(A, B, led);
  5803. }
  5804. };
  5805.  
  5806. function TrRandom(ARGS) { return new TrRandomClass(Array.from(arguments)); }
  5807.  
  5808. class TrSelectClass extends TRANSITION {
  5809. constructor(ARGS) {
  5810. super("Select transitions", ARGS);
  5811. this.TRANSITIONS = Array.from(ARGS).slice(1);
  5812. this.add_arg("F", "FUNCTION", "Transition to select");
  5813. for (var i = 1; i <= max(this.TRANSITIONS.length, 1); i++) {
  5814. this.add_arg("TRANSITION" + i, "TRANSITION", "Transiton " + i);
  5815. }
  5816. this.begin_ = true;
  5817. }
  5818. begin() {
  5819. this.begin_ = true;
  5820. }
  5821. run(blade) {
  5822. this.F.run(blade);
  5823. if (this.begin_) {
  5824. var f = this.F.getInteger(0) + 0;
  5825. while (f < 0) f += this.TRANSITIONS.length * 255;
  5826. f %= this.TRANSITIONS.length;
  5827. this.selected = this.TRANSITIONS[f % this.TRANSITIONS.length];
  5828. this.selected.begin();
  5829. this.begin_ = false;
  5830. }
  5831. this.selected.run(blade);
  5832. }
  5833. done() {
  5834. return this.selected && this.selected.done();
  5835. }
  5836. getColor(A, B, led) {
  5837. return this.selected.getColor(A, B, led);
  5838. }
  5839. };
  5840.  
  5841. function TrSelect(ARGS) {
  5842. return new TrSelectClass(Array.from(arguments));
  5843. }
  5844.  
  5845. class TrExtendXClass extends TRANSITION {
  5846. constructor(MILLIS, TRANSITION) {
  5847. super("Extend a transition.", arguments);
  5848. this.add_arg("MILLIS", "TIME_FUNCTION", "How much to extend the transition.");
  5849. this.add_arg("TRANSITION", "TRANSITION", "Transition to extend.");
  5850. this.extending = false;
  5851. this.millis = new TRANSITION_BASE("millis", [this.MILLIS]);
  5852. }
  5853. begin() {
  5854. this.extending = false;
  5855. this.TRANSITION.begin();
  5856. }
  5857. run(blade) {
  5858. this.TRANSITION.run(blade);
  5859. if (!this.extending && this.TRANSITION.done()) {
  5860. this.extending = true;
  5861. this.millis.begin();
  5862. }
  5863. if (this.extending) {
  5864. this.millis.run(blade);
  5865. this.millis.update(0);
  5866. }
  5867. }
  5868. done() { return this.extending && this.millis.done(); }
  5869. getColor(A, B, led) {
  5870. return this.TRANSITION.getColor(A, B, led);
  5871. }
  5872. };
  5873.  
  5874. function TrExtendX(MILLIS, TRANSACTION) {
  5875. return new TrExtendXClass(MILLIS, TRANSACTION);
  5876. }
  5877.  
  5878. class TrExtendClass extends MACRO {
  5879. constructor(MILLIS, TRANSITION) {
  5880. super("Extend a transition.", arguments);
  5881. this.add_arg("MILLIS", "INT", "How much to extend the transition.");
  5882. this.add_arg("TRANSITION", "TRANSITION", "Transition to extend.");
  5883. this.SetExpansion(TrExtendX(Int(MILLIS), TRANSITION));
  5884. }
  5885. };
  5886.  
  5887. function TrExtend(MILLIS, TRANSACTION) {
  5888. return new TrExtendClass(MILLIS, TRANSACTION);
  5889. }
  5890.  
  5891. class TrBlinkXClass extends TRANSITION_BASE {
  5892. constructor(MILLIS, N, WIDTH) {
  5893. super("Blink N times", arguments);
  5894. this.add_arg("N", "INT", "How many times to blink.");
  5895. this.add_arg("WIDTH", "FUNCTION", "Blink pulse width, 16384 = 50%", Int(16384));
  5896. this.blink = false
  5897. }
  5898. run(blade) {
  5899. super.run(blade);
  5900. this.blink = (this.update(32768 * this.N) & 0x7fff) < this.WIDTH.getInteger(0);
  5901. }
  5902. getColor(a, b, led) {
  5903. if (this.blink) return a;
  5904. return b;
  5905. }
  5906. }
  5907. function TrBlinkX(MILLIS, N, WIDTH) {
  5908. return new TrBlinkXClass(MILLIS, N, WIDTH);
  5909. }
  5910. class TrBlinkClass extends MACRO {
  5911. constructor(MILLIS, N, WIDTH) {
  5912. super("Blink N times", arguments);
  5913. this.add_arg("MILLIS", "INT", "Transition length in milliseconds.")
  5914. this.add_arg("N", "INT", "How many times to blink.");
  5915. this.add_arg("WIDTH", "INT", "Blink pulse width, 16384 = 50%", 16384);
  5916. this.SetExpansion(TrBlinkX(Int(MILLIS), N, Int(this.WIDTH)));
  5917. }
  5918. }
  5919. function TrBlink(MILLIS, N, WIDTH) {
  5920. return new TrBlinkClass(MILLIS, N, WIDTH);
  5921. }
  5922.  
  5923. class TrDoEffectAlwaysXClass extends TRANSITION {
  5924. constructor(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  5925. super("Do effect", arguments);
  5926. this.add_arg("TRANSITION","TRANSITION", "Wrapped transition");
  5927. this.add_arg("EFFECT", "EFFECT", "Effect to trigger.");
  5928. this.add_arg("WAVNUM", "FUNCTION", "Select wave number.");
  5929. this.add_arg("LOCATION", "FUNCTION", "Effect location.");
  5930. this.begin_ = false;
  5931. }
  5932. begin() {
  5933. this.TRANSITION.begin();
  5934. this.begin_ = true;
  5935. }
  5936. run(blade) {
  5937. super.run(blade);
  5938. if (this.begin_) {
  5939. var location = this.LOCATION.getInteger(0);
  5940. if (location == -1) location = random(32768)/32768.0;
  5941. blade.addEffect(this.EFFECT, location);
  5942. this.begin_ = false;
  5943. }
  5944. }
  5945. done() { return this.TRANSITION.done(); }
  5946. getColor(a, b, led) { return this.TRANSITION.getColor(a, b, led); }
  5947. }
  5948. function TrDoEffectAlwaysX(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  5949. return new TrDoEffectAlwaysXClass(TRANSITION, EFFECT, WAVNUM, LOCATION);
  5950. }
  5951.  
  5952. class TrDoEffectAlwaysClass extends MACRO {
  5953. constructor(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  5954. super("Do effect", arguments);
  5955. this.add_arg("TRANSITION","TRANSITION", "Wrapped transition");
  5956. this.add_arg("EFFECT", "EFFECT", "Effect to trigger.");
  5957. this.add_arg("WAVNUM", "INT", "Select wave number.", -1);
  5958. this.add_arg("LOCATION", "INT", "Effect location.", -1);
  5959. this.SetExpansion(TrDoEffectAlwaysX(TRANSITION, EFFECT, Int(this.WAVNUM), Int(this.LOCATION)));
  5960. }
  5961. }
  5962. function TrDoEffectAlways(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  5963. return new TrDoEffectAlwaysClass(TRANSITION, EFFECT, WAVNUM, LOCATION);
  5964. }
  5965.  
  5966. class TrDoEffectXClass extends TRANSITION {
  5967. constructor(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  5968. super("Do effect", arguments);
  5969. this.add_arg("TRANSITION","TRANSITION", "Wrapped transition");
  5970. this.add_arg("EFFECT", "EFFECT", "Effect to trigger.");
  5971. this.add_arg("WAVNUM", "FUNCTION", "Select wave number.");
  5972. this.add_arg("LOCATION", "FUNCTION", "Effect location.");
  5973. this.begin_ = false;
  5974. this.done_ = false;
  5975. }
  5976. begin() {
  5977. this.TRANSITION.begin();
  5978. this.begin_ = true;
  5979. this.done_ = false;
  5980. }
  5981. run(blade) {
  5982. super.run(blade);
  5983. if (this.begin_) {
  5984. if (blade.is_on()) {
  5985. var location = this.LOCATION.getInteger(0);
  5986. if (location == -1) location = random(32768)/32768.0;
  5987. blade.addEffect(this.EFFECT, location);
  5988. }
  5989. this.begin_ = false;
  5990. }
  5991. if (!this.done_) {
  5992. /*
  5993. if (!blade.is_on() && !blade.is_powered()) {
  5994. this.done_ = true;
  5995. }
  5996. */
  5997. }
  5998. }
  5999. done() { return this.done_ || this.TRANSITION.done(); }
  6000. getColor(a, b, led) {
  6001. if (this.done_) return b;
  6002. return this.TRANSITION.getColor(a, b, led);
  6003. }
  6004. }
  6005. function TrDoEffectX(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  6006. return new TrDoEffectXClass(TRANSITION, EFFECT, WAVNUM, LOCATION);
  6007. }
  6008. class TrDoEffectClass extends MACRO {
  6009. constructor(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  6010. super("Do effect", arguments);
  6011. this.add_arg("TRANSITION","TRANSITION", "Wrapped transition");
  6012. this.add_arg("EFFECT", "EFFECT", "Effect to trigger.");
  6013. this.add_arg("WAVNUM", "INT", "Select wave number.", -1);
  6014. this.add_arg("LOCATION", "INT", "Effect location.", -1);
  6015. this.SetExpansion(TrDoEffectX(TRANSITION, EFFECT, Int(this.WAVNUM), Int(this.LOCATION)));
  6016. }
  6017. }
  6018. function TrDoEffect(TRANSITION, EFFECT, WAVNUM, LOCATION) {
  6019. return new TrDoEffectClass(TRANSITION, EFFECT, WAVNUM, LOCATION);
  6020. }
  6021.  
  6022. class TrLoopClass extends TRANSITION {
  6023. constructor(TRANSITION) {
  6024. super("Loop transition", arguments);
  6025. this.add_arg("TRANSITION", "TRANSITION", "Transition to loop");
  6026. }
  6027. run(blade) {
  6028. if (this.TRANSITION.done()) this.TRANSITION.begin();
  6029. super.run(blade);
  6030. }
  6031. begin() { this.TRANSITION.begin(); }
  6032. done() { return false; }
  6033. getColor(a, b, led) { return this.TRANSITION.getColor(a, b, led); }
  6034. }
  6035. function TrLoop(TRANSITION) {
  6036. return new TrLoopClass(TRANSITION);
  6037. }
  6038.  
  6039. class TrLoopNXClass extends TRANSITION {
  6040. constructor(N, TRANSITION) {
  6041. super("Loop transition", arguments);
  6042. this.add_arg("N","FUNCTION", "How many loops.");
  6043. this.add_arg("TRANSITION", "TRANSITION", "Transition to loop");
  6044. this.loops = 0;
  6045. }
  6046. run(blade) {
  6047. this.N.run(blade);
  6048. if (this.loops < 0) this.loops = this.N.getInteger(0) + 1;
  6049. if (this.loops > 0 && this.TRANSITION.done()) {
  6050. if (this.loops > 1) this.TRANSITION.begin();
  6051. this.loops --;
  6052. }
  6053. this.TRANSITION.run(blade);
  6054. }
  6055. begin() {
  6056. this.TRANSITION.begin();
  6057. this.loops = -1;
  6058. }
  6059. done() { return this.loops == 0; }
  6060. getColor(a, b, led) { return this.TRANSITION.getColor(a, b, led); }
  6061. }
  6062. function TrLoopNX(N, TRANSITION) {
  6063. return new TrLoopNXClass(N, TRANSITION);
  6064. }
  6065. class TrLoopNClass extends MACRO {
  6066. constructor(N, TRANSITION) {
  6067. super("Loop transition", arguments);
  6068. this.add_arg("N","INT", "How many loops.");
  6069. this.add_arg("TRANSITION", "TRANSITION", "Transition to loop");
  6070. this.SetExpansion(TrLoopNX(Int(N), TRANSITION))
  6071. }
  6072. }
  6073. function TrLoopN(N, TRANSITION) {
  6074. return new TrLoopNClass(N, TRANSITION);
  6075. }
  6076.  
  6077. class TrLoopUntilClass extends TRANSITION {
  6078. constructor(PULSE, TR, OUT) {
  6079. super("Loop transition until pulse occurs.", arguments);
  6080. this.add_arg("PULSE", "FUNCTION", "Pulse");
  6081. this.add_arg("TR", "TRANSITION", "Transition");
  6082. this.add_arg("OUT", "TRANSITION", "Fade-out transition");
  6083. this.pulsed = false;
  6084. }
  6085. begin() {
  6086. this.TR.begin();
  6087. this.pulsed = false;
  6088. }
  6089. done() {
  6090. return this.pulsed && this.OUT.done();
  6091. }
  6092. run(blade) {
  6093. this.PULSE.run(blade);
  6094. if (this.TR.done()) {
  6095. this.TR.begin();
  6096. }
  6097. this.TR.run(blade);
  6098. if (!this.pulsed) {
  6099. if (this.PULSE.getInteger(0)) {
  6100. this.OUT.begin();
  6101. this.pulsed = true;
  6102. }
  6103. }
  6104. if (this.pulsed) {
  6105. this.OUT.run(blade);
  6106. }
  6107. }
  6108. getColor(a, b, led) {
  6109. var ret = this.TR.getColor(a, a, led);
  6110. if (this.pulsed) {
  6111. ret = this.TR.getColor(ret, b, led);
  6112. }
  6113. return ret;
  6114. }
  6115. }
  6116. function TrLoopUntil(PULSE, TR, OUT) {
  6117. return new TrLoopUntilClass(PULSE, TR, OUT);
  6118. }
  6119.  
  6120. // FUNCTIONS
  6121.  
  6122. var BATTERY_LEVEL=24000
  6123.  
  6124. class BatteryLevelClass extends FUNCTION {
  6125. constructor() {
  6126. super("Returns 0-32768 based on battery level.", []);
  6127. }
  6128. run(blade) {}
  6129. getInteger(led) { return 32768 - ((millis() * 3) & 0x7fff); }
  6130. };
  6131.  
  6132. function BatteryLevel() {
  6133. return new BatteryLevelClass();
  6134. }
  6135.  
  6136. class VolumeLevelClass extends FUNCTION {
  6137. constructor() {
  6138. super("Returns 0-32768 based on volume level.", []);
  6139. }
  6140. run(blade) {}
  6141. // getInteger(led) { return 0 + ((millis() * 7) & 0x7fff); }
  6142. getInteger(led) { return 0 + ((millis() / 500) % 11) * 32767 / 10; }
  6143. };
  6144.  
  6145. function VolumeLevel() {
  6146. return new VolumeLevelClass();
  6147. }
  6148.  
  6149. class BumpClass extends FUNCTION {
  6150. constructor() {
  6151. super("Function returning a bump shape", arguments);
  6152. this.add_arg("BUMP_POSITION", "FUNCTION", "0=bump at hilt, 32768=bump at tip");
  6153. this.add_arg("BUMP_WIDTH_FRACTION", "FUNCTION", "bump width", Int(16384));
  6154. }
  6155. run(blade) {
  6156. this.BUMP_POSITION.run(blade);
  6157. this.BUMP_WIDTH_FRACTION.run(blade);
  6158. var fraction = this.BUMP_WIDTH_FRACTION.getInteger(0);
  6159. if (fraction == 0) {
  6160. this.mult = 1;
  6161. this.location = -10000;
  6162. return;
  6163. }
  6164. this.mult = 32 * 2.0 * 128 * 32768 / fraction / blade.num_leds();
  6165. this.location = (this.BUMP_POSITION.getInteger(0) * blade.num_leds() * this.mult) / 32768;
  6166. }
  6167. getInteger(led) {
  6168. var dist = Math.abs(led * this.mult - this.location);
  6169. var p = dist >> 7;
  6170. if (p >= 32) return 0;
  6171. var m = dist & 0x3f;
  6172. return blast_hump[p] * (128 - m) + blast_hump[p+1] * m;
  6173. }
  6174. };
  6175.  
  6176. function Bump(P, F) {
  6177. return new BumpClass(P, F);
  6178. }
  6179.  
  6180.  
  6181. class ChangeSlowlyClass extends FUNCTION {
  6182. constructor(F, SPEED) {
  6183. super("Changes F by no more than SPEED values per second.", arguments);
  6184. this.add_arg("F", "FUNCTION", "Function to moderate");
  6185. this.add_arg("SPEED", "FUNCTION", "maximum change speed");
  6186. this.last_micros = micros();
  6187. this.value = 0;
  6188. }
  6189. run(blade) {
  6190. super.run(blade);
  6191. var now = micros();
  6192. var delta = now - this.last_micros;
  6193. if (delta > 1000000) delta = 1;
  6194. this.last_micros = now;
  6195. delta *= this.SPEED.getInteger(0);
  6196. delta /= 1000000;
  6197. var target = this.F.getInteger(0);
  6198. if (delta > Math.abs(this.value - target)) {
  6199. this.value = target;
  6200. } else if (this.value < target) {
  6201. this.value += delta;
  6202. } else {
  6203. this.value -= delta;
  6204. }
  6205. }
  6206. getInteger(led) { return this.value; }
  6207. }
  6208.  
  6209. function ChangeSlowly(F, SPEED) {
  6210. return new ChangeSlowlyClass(F, SPEED);
  6211. }
  6212.  
  6213. class IfonClass extends FUNCTION {
  6214. constructor(A, B) {
  6215. super("A if on, B if off.", arguments);
  6216. this.add_arg("A", "FUNCTION", "A");
  6217. this.add_arg("B", "FUNCTION", "B");
  6218. }
  6219. run(blade) {
  6220. this.A.run(blade);
  6221. this.B.run(blade);
  6222. this.on = blade.is_on();
  6223. }
  6224. getInteger(led) {
  6225. if (this.on) return this.A.getInteger(led);
  6226. return this.B.getInteger(led);
  6227. }
  6228. };
  6229.  
  6230. function Ifon(A, B) { return new IfonClass(A, B); }
  6231.  
  6232. class InOutFuncXClass extends FUNCTION {
  6233. constructor(OUT_MILLIS, IN_MILLIS) {
  6234. super("0 when off, 32768 when on, OUT_MILLIS/IN_MILLIS determines speed in between.", arguments);
  6235. this.add_arg("OUT_MILLIS", "FUNCTION", "millis to ramp up");
  6236. this.add_arg("IN_MILLIS", "FUNCTION", "millis to ramp down");
  6237. this.last_micros = 0;
  6238. this.extension = 0.0;
  6239. }
  6240. run(blade) {
  6241. super.run(blade);
  6242. var now = micros();
  6243. var delta = now - this.last_micros;
  6244. this.last_micros = now;
  6245. if (blade.is_on()) {
  6246. if (this.extension == 0.0) {
  6247. this.extension = 0.00001;
  6248. } else {
  6249. this.extension += delta / (this.OUT_MILLIS.getInteger(0) * 1000.0);
  6250. this.extension = Math.min(this.extension, 1.0);
  6251. }
  6252. } else {
  6253. this.extension -= delta / (this.IN_MILLIS.getInteger(0) * 1000.0);
  6254. this.extension = Math.max(this.extension, 0.0);
  6255. }
  6256. this.ret = this.extension * 32768;
  6257. }
  6258. getInteger(led) { return this.ret; }
  6259. argify(status) {
  6260. state.int_argument = IGNITION_TIME_ARG;
  6261. this.OUT_MILLIS = this.OUT_MILLIS.argify(status);
  6262.  
  6263. state.int_argument = RETRACTION_TIME_ARG;
  6264. this.IN_MILLIS = this.IN_MILLIS.argify(status);
  6265.  
  6266. return this;
  6267. }
  6268. };
  6269.  
  6270. function InOutFuncX(O, I) {
  6271. return new InOutFuncXClass(O, I);
  6272. }
  6273. function InOutFunc(O, I) {
  6274. return InOutFuncX(Int(O), Int(I));
  6275. }
  6276.  
  6277. // TODO: InOutFuncTD
  6278.  
  6279. class IntClass extends FUNCTION {
  6280. constructor(N) {
  6281. super("Constant integer function", arguments);
  6282. this.add_arg("N","INT","number to return.");
  6283. }
  6284. getInteger(led) { return this.N; }
  6285. pp() {
  6286. if (pp_is_url) {
  6287. if (this.super_short_desc) return "$";
  6288. return this.gencomment() + "Int<" + this.N + ">";
  6289. }
  6290. // return this.PPshort("Int<" + this.N +">", "VALUE");
  6291. return this.PPshort("Int<" + (this.N < 0 ? "&minus;" : "") + Math.abs(this.N) +">", "VALUE"); /**************************************** Left Arrow Fix. */
  6292.  
  6293. }
  6294. argify(state) {
  6295. if (state.int_argument) {
  6296. ret = IntArg_(ArgumentName(state.int_argument), this.N);
  6297. state.int_argument = false;
  6298. return ret;
  6299. } else {
  6300. return this;
  6301. }
  6302. }
  6303. };
  6304.  
  6305. function Int(n) { return new IntClass(Math.round(n)); }
  6306.  
  6307. class IntArgClass extends FUNCTION {
  6308. constructor(ARG, N) {
  6309. super("Dynamic Integer argument", arguments);
  6310. this.add_arg("ARG","ArgumentName","argument number.");
  6311. this.add_arg("DEFAULT","INT","default.");
  6312. }
  6313. run(blade) {
  6314. super.run(blade);
  6315. this.value = parseInt(getARG(this.ARG, "" + this.DEFAULT));
  6316. }
  6317. getInteger(led) { return this.value; }
  6318. argify(state) {
  6319. if (state.int_argument == this.ARG) {
  6320. state.int_argument = false;
  6321. }
  6322. return this;
  6323. }
  6324. };
  6325.  
  6326. function IntArg_(ARG, N) {
  6327. return new IntArgClass(ARG, N);
  6328. }
  6329.  
  6330. class RgbArgClass extends STYLE {
  6331. constructor(ARG, N) {
  6332. super("Dynamic Color argument", arguments);
  6333. this.add_arg("ARG","ArgumentName","number to return.");
  6334. this.add_arg("DEFAULT","COLOR","default.");
  6335. }
  6336. run(blade) {
  6337. super.run(blade);
  6338. var d = Math.round(this.DEFAULT.r * 65535) + "," + Math.round(this.DEFAULT.g * 65535)+ "," +Math.round(this.DEFAULT.b * 65535);
  6339. var v = getARG(this.ARG, d).split(",");
  6340. this.value = Rgb16(parseInt(v[0]), parseInt(v[1]), parseInt(v[2]));
  6341. }
  6342. getColor(led) { return this.value; }
  6343. argify(state) {
  6344. if (state.color_argument == this.ARG) {
  6345. state.color_argument = false;
  6346. }
  6347. return this;
  6348. }
  6349. };
  6350.  
  6351. function RgbArg_(ARG, COLOR) {
  6352. return new RgbArgClass(ARG, COLOR);
  6353. }
  6354.  
  6355. class ScaleClass extends FUNCTION {
  6356. constructor(F, A, B) {
  6357. super("Changes values in range 0-32768 to A-B.", arguments);
  6358. this.add_arg("F","FUNCTION","input");
  6359. this.add_arg("A","FUNCTION","lower output limit");
  6360. this.add_arg("B","FUNCTION","upper output limit");
  6361. }
  6362. run(blade) {
  6363. super.run(blade);
  6364. var a = this.A.getInteger(0);
  6365. var b = this.B.getInteger(0);
  6366. this.mul = (b - a);
  6367. this.add = a;
  6368. }
  6369. getInteger(led) {
  6370. return (this.F.getInteger(led) * this.mul >> 15) + this.add;
  6371. }
  6372. };
  6373.  
  6374. function Scale(F, A, B) { return new ScaleClass(F, A, B); }
  6375.  
  6376. class InvertFClass extends MACRO {
  6377. constructor(F) {
  6378. super("Invert input function", arguments);
  6379. this.add_arg("F", "FUNCTION", "Function to invert.");
  6380. this.SetExpansion(Scale(this.F, Int(32768), Int(0)));
  6381. }
  6382. };
  6383.  
  6384. function InvertF(F) { return new InvertFClass(F); }
  6385.  
  6386.  
  6387. class SinClass extends FUNCTION {
  6388. constructor(RPM, LOW, HIGH) {
  6389. super("Pulses between LOW and HIGH RPM times per minute.", arguments);
  6390. this.add_arg("RPM", "FUNCTION", "Revolutions per minute");
  6391. this.add_arg("HIGH", "FUNCTION", "upper output limit", Int(32768));
  6392. this.add_arg("LOW", "FUNCTION", "lower output limit", Int(0));
  6393. this.pos = 0.0;
  6394. this.last_micros = 0;
  6395. }
  6396. run(blade) {
  6397. super.run(blade);
  6398. var now = micros();
  6399. var delta = now - this.last_micros;
  6400. this.last_micros = now;
  6401. this.pos = fract(this.pos + delta / 60000000.0 * this.RPM.getInteger(0));
  6402. var high = this.HIGH.getInteger(0);
  6403. var low = this.LOW.getInteger(0);
  6404. var tmp = Math.sin(this.pos * Math.PI * 2.0) / 2.0;
  6405. this.value = Math.floor( (tmp + 0.5) * (high - low) + low );
  6406. }
  6407. getInteger(led) { return this.value; }
  6408. };
  6409.  
  6410. function Sin(RPM, LOW, HIGH) { return new SinClass(RPM, LOW, HIGH); }
  6411.  
  6412. class SawClass extends FUNCTION {
  6413. constructor(RPM, LOW, HIGH) {
  6414. super("Pulses between LOW and HIGH RPM times per minute.", arguments);
  6415. this.add_arg("RPM", "FUNCTION", "Revolutions per minute");
  6416. this.add_arg("HIGH", "FUNCTION", "upper output limit", Int(32768));
  6417. this.add_arg("LOW", "FUNCTION", "lower output limit", Int(0));
  6418. this.pos = 0.0;
  6419. this.last_micros = 0;
  6420. }
  6421. run(blade) {
  6422. super.run(blade);
  6423. var now = micros();
  6424. var delta = now - this.last_micros;
  6425. this.last_micros = now;
  6426. this.pos = fract(this.pos + delta / 60000000.0 * this.RPM.getInteger(0));
  6427. var high = this.HIGH.getInteger(0);
  6428. var low = this.LOW.getInteger(0);
  6429. this.value = low + this.pos * (high - low);
  6430. }
  6431. getInteger(led) { return this.value; }
  6432. };
  6433.  
  6434. function Saw(RPM, LOW, HIGH) { return new SawClass(RPM, LOW, HIGH); }
  6435.  
  6436. const TRIGGER_DELAY = 0;
  6437. const TRIGGER_ATTACK = 1;
  6438. const TRIGGER_SUSTAIN = 2;
  6439. const TRIGGER_RELEASE = 3;
  6440. const TRIGGER_OFF = 4;
  6441.  
  6442. class TriggerClass extends FUNCTION {
  6443. constructor(EFFECT, FADE_IN_MILLIS, SUSTAIN_MILLIS, FADE_OUT_MILLIS, DELAY_MILLIS) {
  6444. super("When EFFECT occurs, DELAY_MILLIS controls a pause, then we ramp up from 0 to 32768, stay there for SUSTAIN_MILLIS, then ramp down again.", arguments);
  6445. this.add_arg("EFFECT", "EFFECT", "Trigger event");
  6446. this.add_arg("FADE_IN_MILLIS", "FUNCTION", "How long it takes to ramp to 32768");
  6447. this.add_arg("SUSTAIN_MILLIS", "FUNCTION", "Stay at 32768 for this long.");
  6448. this.add_arg("FADE_OUT_MILLIS", "FUNCTION", "How long it takes to ramp back down to zero.");
  6449. this.add_arg("DELAY_MILLIS", "FUNCTION", "How long to delay before trigger starts.", Int(0));
  6450.  
  6451. this.trigger_state = TRIGGER_OFF;
  6452. console.log("EFFECT INIT");
  6453. this.effect = new OneshotEffectDetector(this.EFFECT);
  6454. this.start_time = 0;
  6455. }
  6456. run(blade) {
  6457. super.run(blade);
  6458. if (this.effect.Detect(blade)) {
  6459. this.start_time = micros();
  6460. this.trigger_state = TRIGGER_DELAY;
  6461. }
  6462. if (this.trigger_state == this.TRIGGER_OFF) {
  6463. this.value = 0;
  6464. return;
  6465. }
  6466. var t = micros() - this.start_time;
  6467. while (true) {
  6468. var micros_for_state = this.get_millis_for_state() * 1000;
  6469. if (t < micros_for_state) {
  6470. switch (this.trigger_state) {
  6471. case TRIGGER_DELAY:
  6472. this.value = 0;
  6473. return;
  6474. case TRIGGER_ATTACK:
  6475. this.value = t * 32768.0 / micros_for_state;
  6476. return;
  6477. case TRIGGER_SUSTAIN:
  6478. this.value = 32768;
  6479. return;
  6480. case TRIGGER_RELEASE:
  6481. this.value = 32768 - t * 32768 / micros_for_state;
  6482. return;
  6483. case TRIGGER_OFF:
  6484. this.value = 0;
  6485. return;
  6486. }
  6487. }
  6488. if (this.TRIGGER_STATE >= 4) throw "Weird state?";
  6489. this.trigger_state++;
  6490. t -= micros_for_state;
  6491. this.start_time += micros_for_state;
  6492. }
  6493. }
  6494. get_millis_for_state() {
  6495. switch (this.trigger_state) {
  6496. case TRIGGER_DELAY: return this.DELAY_MILLIS.getInteger(0);
  6497. case TRIGGER_ATTACK: return this.FADE_IN_MILLIS.getInteger(0);
  6498. case TRIGGER_SUSTAIN: return this.SUSTAIN_MILLIS.getInteger(0);
  6499. case TRIGGER_RELEASE: return this.FADE_OUT_MILLIS.getInteger(0);
  6500. case TRIGGER_OFF:
  6501. }
  6502. return 10000000;
  6503. }
  6504. getInteger(led) { return this.value; }
  6505. IS_RUNNING() {
  6506. return this.trigger_state != TRIGGER_OFF;
  6507. }
  6508. };
  6509.  
  6510. function Trigger(EFFECT, FADE_IN_MILLIS, SUSTAIN_MILLIS, FADE_OUT_MILLIS, DELAY_MILLIS) {
  6511. return new TriggerClass(EFFECT, FADE_IN_MILLIS, SUSTAIN_MILLIS, FADE_OUT_MILLIS, DELAY_MILLIS);
  6512. }
  6513.  
  6514. class SmoothStepClass extends FUNCTION {
  6515. constructor(POS, WIDTH) {
  6516. super("SmoothStep function", arguments);
  6517. this.add_arg("POS", "FUNCTION", "Position 0=hilt, 32768=tip");
  6518. this.add_arg("WIDTH", "FUNCTION", "Step width 32768=length of blade");
  6519. }
  6520. run(blade) {
  6521. super.run(blade);
  6522. var width=this.WIDTH.getInteger(0);
  6523. if (width == 0) {
  6524. this.mult = 32768;
  6525. } else {
  6526. this.mult = 32768 * 32768 / width / blade.num_leds();
  6527. }
  6528. this.location = blade.num_leds() * this.mult * (this.POS.getInteger(0) - width/2) / 32768;
  6529. }
  6530. getInteger(led) {
  6531. var x = led * this.mult - this.location;
  6532. if (x < 0) return 0;
  6533. if (x > 32768) return 32768;
  6534. return (((x * x) >> 14) * ((3<<14) - x)) >> 15;
  6535. }
  6536. };
  6537.  
  6538. function SmoothStep(POS, WIDTH) { return new SmoothStepClass(POS, WIDTH); }
  6539.  
  6540. class RampFClass extends FUNCTION {
  6541. constructor() {
  6542. super("0 at base, 32768 at tip", arguments);
  6543. }
  6544. run(blade) {
  6545. this.num_leds = blade.num_leds();
  6546. }
  6547. getInteger(led) {
  6548. return led * 32768 / this.num_leds;
  6549. }
  6550. }
  6551.  
  6552. function RampF() {
  6553. return new RampFClass();
  6554. }
  6555.  
  6556. class MultClass extends FUNCTION {
  6557. constructor(ARGS) {
  6558. super("Multiply values", ARGS);
  6559. this.FUNCTIONS = Array.from(ARGS);
  6560. for (var i = 1; i < this.FUNCTIONS.length + 1; i++)
  6561. this.add_arg("FUNCTION" + i, "FUNCTION", "COLOR " + i);
  6562. }
  6563. getInteger(led) {
  6564. var ret = this.FUNCTIONS[0].getInteger(led);
  6565. for (var i = 1; i < this.FUNCTIONS.length; i++) {
  6566. ret = (ret * this.FUNCTIONS[i].getInteger(led)) >> 15;
  6567. }
  6568. return ret;
  6569. }
  6570. }
  6571.  
  6572. function Mult(ARGS) {
  6573. return new MultClass(Array.from(arguments));
  6574. }
  6575.  
  6576. class PercentageClass extends MACRO {
  6577. constructor(F, P) {
  6578. super("Returns P % of F.", arguments);
  6579. this.add_arg("F","FUNCTION","F");
  6580. this.add_arg("P","INT", "Percent")
  6581. this.SetExpansion(Mult(this.F.DOCOPY(), Int(this.P * 32768 / 100)));
  6582. }
  6583. }
  6584.  
  6585. function Percentage(F, P) {
  6586. return new PercentageClass(F, P);
  6587. }
  6588.  
  6589. class NoisySoundLevelClass extends FUNCTION {
  6590. constructor() {
  6591. super("Noisy sound level.", arguments);
  6592. }
  6593. run(blade) {
  6594. this.var_ = (Math.random() * Math.random()) * 32768;
  6595. }
  6596. getInteger(led) { return this.var_; }
  6597. };
  6598.  
  6599. function NoisySoundLevel() { return new NoisySoundLevelClass(); }
  6600.  
  6601. class NoisySoundLevelCompatClass extends FUNCTION {
  6602. constructor() {
  6603. super("Noisy sound level.", arguments);
  6604. }
  6605. run(blade) {
  6606. this.var_ = clamp((Math.random() * Math.random()) * 32768 * 2, 0, 32768);
  6607. }
  6608. getInteger(led) { return this.var_; }
  6609. };
  6610.  
  6611. function NoisySoundLevelCompat() { return new NoisySoundLevelCompatClass(); }
  6612.  
  6613. class SmoothSoundLevelClass extends FUNCTION {
  6614. constructor() {
  6615. super("Noisy sound level.", arguments);
  6616. this.var_ = 0.0;
  6617. }
  6618. run(blade) {
  6619. var v = Math.random() * 20000.0;
  6620. v *= v;
  6621. this.var_ = (this.var_ + v) / 100.0 ;
  6622. }
  6623. getInteger(led) { return this.var_; }
  6624. };
  6625.  
  6626. function SmoothSoundLevel() { return new SmoothSoundLevelClass(); }
  6627.  
  6628. class WavLenClass extends FUNCTION {
  6629. constructor() {
  6630. super("Length of associated wav file in MS", arguments);
  6631. this.add_arg("EFFECT", "EFFECT", "Which effect to get the length of.", EFFECT(EFFECT_NONE));
  6632. }
  6633. getInteger(led) { return 500; }
  6634. };
  6635.  
  6636. function WavLen(EFFECT) { return new WavLenClass(EFFECT); }
  6637.  
  6638. class SwingSpeedXClass extends FUNCTION {
  6639. constructor() {
  6640. super("Swing Speed", arguments);
  6641. this.add_arg("MAX", "FUNCTION", "What swing speed returns 32768.");
  6642. this.var_ = 0.0;
  6643. }
  6644. run(blade) {
  6645. super.run(blade);
  6646. var speed = get_swing_speed();
  6647. var v = speed / this.MAX.getInteger(0);
  6648. this.var_ = clamp(v * 32768, 0, 32768);
  6649. }
  6650. getInteger(led) { return this.var_; }
  6651. };
  6652.  
  6653. function SwingSpeedX(MAX) { return new SwingSpeedXClass(MAX); }
  6654.  
  6655. class SwingSpeedClass extends MACRO {
  6656. constructor() {
  6657. super("Swing Speed", arguments);
  6658. this.add_arg("MAX", "INT", "What swing speed returns 32768.");
  6659. this.SetExpansion(SwingSpeedX(Int(this.MAX)));
  6660. }
  6661. };
  6662.  
  6663. function SwingSpeed(MAX) { return new SwingSpeedClass(MAX); }
  6664.  
  6665. class ClashImpactFXClass extends FUNCTION {
  6666. constructor(MIN, MAX) {
  6667. super("Returns clash strength.", arguments);
  6668. this.add_arg("MIN", "FUNCTION", "Minimum, translates to zero", Int(200));
  6669. this.add_arg("MAX", "FUNCTION", "Maximum, translates to 32768", Int(1600));
  6670. this.value = 0;
  6671. }
  6672. run(blade) {
  6673. super.run(blade);
  6674. current_clash_strength = max(current_clash_strength, random(current_clash_value));
  6675. current_clash_value -= random(random(current_clash_value));
  6676. this.value = clamp((current_clash_strength - this.MIN.getInteger(0)) * 32768 / this.MAX.getInteger(0), 0, 32768);
  6677. }
  6678. getInteger(led) {
  6679. return this.value;
  6680. }
  6681. };
  6682.  
  6683. function ClashImpactFX(MIN, MAX) {
  6684. return new ClashImpactFXClass(MIN, MAX);
  6685. }
  6686.  
  6687. class ClashImpactFClass extends MACRO {
  6688. constructor(MIN, MAX) {
  6689. super("Returns clash strength.", arguments);
  6690. this.add_arg("MIN", "INT", "Minimum, translates to zero", 200);
  6691. this.add_arg("MAX", "INT", "Maximum, translates to 32768", 1600);
  6692. this.SetExpansion(ClashImpactFX(Int(this.MIN), Int(this.MAX)));
  6693. }
  6694. }
  6695.  
  6696. function ClashImpactF(MIN, MAX) {
  6697. return new ClashImpactFClass(MIN, MAX);
  6698. }
  6699.  
  6700. class SwingAccelerationXClass extends FUNCTION {
  6701. constructor() {
  6702. super("Swing Acceleration", arguments);
  6703. this.add_arg("MAX", "FUNCTION", "What swing speed returns 32768.", Int(130));
  6704. this.var_ = 0.0;
  6705. }
  6706. run(blade) {
  6707. super.run(blade);
  6708. var accel = get_swing_accel();
  6709. var v = accel / this.MAX.getInteger(0);
  6710. this.var_ = clamp(v * 32768, 0, 32768);
  6711. }
  6712. getInteger(led) { return this.var_; }
  6713. };
  6714.  
  6715. function SwingAccelerationX(MAX) { return new SwingAccelerationXClass(MAX); }
  6716.  
  6717. class SwingAccelerationClass extends MACRO {
  6718. constructor() {
  6719. super("Swing Speed", arguments);
  6720. this.add_arg("MAX", "INT", "What swing speed returns 32768.", 130);
  6721. this.SetExpansion(SwingAccelerationX(Int(this.MAX)));
  6722. }
  6723. };
  6724.  
  6725. function SwingAcceleration(MAX) { return new SwingAccelerationClass(MAX); }
  6726.  
  6727.  
  6728. class LayerFunctionsClass extends FUNCTION {
  6729. constructor(ARGS) {
  6730. super("Mix functions", ARGS);
  6731. this.LAYERS = Array.from(ARGS);
  6732. for (var i = 1; i < this.LAYERS.length + 1; i++)
  6733. this.add_arg("FUNCTION" + i, "FUNCTION", "COLOR " + i);
  6734. }
  6735. getInteger(led) {
  6736. var ret = 0;
  6737. for (var i = 0; i < this.LAYERS.length; i++) {
  6738. ret = 32768 - ((((32768 - ret) * (32768 - this.LAYERS[i].getInteger(led)))) >> 15);
  6739. }
  6740. return ret;
  6741. }
  6742. };
  6743.  
  6744. function LayerFunctions(Layer1, Layer2) {
  6745. return new LayerFunctionsClass(Array.from(arguments));
  6746. }
  6747.  
  6748. class SlowNoiseClass extends FUNCTION {
  6749. constructor(SPEED) {
  6750. super("Returns a value between 0 and 32768, which slowly changes up and down randomly.", Array.from(arguments));
  6751. this.add_arg("SPEED", "FUNCTION", "Change speed");
  6752. this.value = random(32768);
  6753. }
  6754. run(blade) {
  6755. super.run(blade);
  6756. var now = millis();
  6757. var delta = now - this.last_millis;
  6758. this.last_millis = now;
  6759. if (delta > 100) delta = 1;
  6760. var speed = this.SPEED.getInteger(0);
  6761. // console.log("DELTA = " + delta + " SPEED = " + speed + " VALUE="+this.value);
  6762. while (delta > 0) {
  6763. this.value = clamp(this.value + random(speed * 2 + 1) - speed, 0, 32768);
  6764. delta--;
  6765. }
  6766. }
  6767. getInteger(led) { return this.value; }
  6768. };
  6769.  
  6770. function SlowNoise(SPEED) {
  6771. return new SlowNoiseClass(SPEED);
  6772. }
  6773.  
  6774. class IsLessThanClass extends FUNCTION {
  6775. constructor(F, V) {
  6776. super("Returns 32768 if F < V, 0 otherwise.", arguments);
  6777. this.add_arg("F", "FUNCTION", "F");
  6778. this.add_arg("V", "FUNCTION", "V");
  6779. }
  6780. getInteger(led) {
  6781. return this.F.getInteger(led) < this.V.getInteger(led) ? 32768 : 0;
  6782. }
  6783. };
  6784.  
  6785. function IsLessThan(F, V) {
  6786. return new IsLessThanClass(F, V);
  6787. }
  6788.  
  6789. class IsGreaterThanClass extends MACRO {
  6790. constructor(F, V) {
  6791. super("Returns 32768 if F > V, 0 otherwise.", arguments);
  6792. this.add_arg("F", "FUNCTION", "F");
  6793. this.add_arg("V", "FUNCTION", "V");
  6794. this.SetExpansion(IsLessThan(V.DOCOPY(), F.DOCOPY()));
  6795. }
  6796. };
  6797.  
  6798. function IsGreaterThan(F, V) {
  6799. return new IsGreaterThanClass(F, V);
  6800. }
  6801.  
  6802. class IsBetweenClass extends FUNCTION {
  6803. constructor(F, BOTTOM, TOP) {
  6804. super("Returns 32768 if BOTTOM < F < TOP, 0 otherwise.", arguments);
  6805. this.add_arg("F", "FUNCTION", "F");
  6806. this.add_arg("BOTTOM", "FUNCTION", "BOTTOM");
  6807. this.add_arg("TOP", "FUNCTION", "TOP");
  6808. }
  6809. getInteger(led) {
  6810. var f = this.F.getInteger(led);
  6811. return this.BOTTOM.getInteger(led) < f && f < this.TOP.getInteger(led) ? 32768 : 0;
  6812. }
  6813. };
  6814.  
  6815. function IsBetween(F, BOTTOM, TOP) {
  6816. return new IsBetweenClass(F, BOTTOM, TOP);
  6817. }
  6818.  
  6819. class ClampFXClass extends FUNCTION {
  6820. constructor(F, MIN, MAX) {
  6821. super("Returns F, clamped to MIN...MAX", arguments);
  6822. this.add_arg("F", "FUNCTION", "F");
  6823. this.add_arg("MIN", "FUNCTION", "MIN");
  6824. this.add_arg("MAX", "FUNCTION", "MAX");
  6825. }
  6826. getInteger(led) {
  6827. return clamp(this.F.getInteger(led), this.MIN.getInteger(led), this.MAX.getInteger(led));
  6828. }
  6829. };
  6830.  
  6831. function ClampFX(F, MIN, MAX) {
  6832. return new ClampFXClass(F, MIN, MAX);
  6833. }
  6834.  
  6835. class ClampFClass extends MACRO {
  6836. constructor(F, MIN, MAX) {
  6837. super("Returns F, clamped to MIN...MAX", arguments);
  6838. this.add_arg("F", "FUNCTION", "F");
  6839. this.add_arg("MIN", "INT", "MIN");
  6840. this.add_arg("MAX", "INT", "MAX");
  6841. this.SetExpansion(ClampFX(F.DOCOPY(), Int(MIN), Int(MAX)));
  6842. }
  6843. };
  6844.  
  6845. function ClampF(F, MIN, MAX) {
  6846. return new ClampFClass(F, MIN, MAX);
  6847. }
  6848.  
  6849. class VariationClass extends FUNCTION {
  6850. constructor() {
  6851. super("Returns the current variation", arguments);
  6852. }
  6853. getInteger(led) {
  6854. return Variant() & 0x7fff;
  6855. }
  6856. };
  6857.  
  6858. function Variation() {
  6859. return new VariationClass();
  6860. }
  6861.  
  6862. class AltFClass extends FUNCTION {
  6863. constructor() {
  6864. super("Returns the current alt", arguments);
  6865. }
  6866. getInteger(led) {
  6867. return Alt() & 0x7fff;
  6868. }
  6869. };
  6870.  
  6871. function AltF() {
  6872. return new AltFClass();
  6873. }
  6874.  
  6875. function MOD(x, m) {
  6876. if (x >= 0) return x % m;
  6877. return m + ~((~x) % m)
  6878. }
  6879.  
  6880. class SyncAltToVarianceFClass extends FUNCTION {
  6881. constructor() {
  6882. super("Synchronizes Alt and Variance.", arguments);
  6883. this.last_ = 0x7fffffff;
  6884. }
  6885. run(blade) {
  6886. super.run(blade)
  6887. if (num_alternatives == 0) return;
  6888. var VAR = MOD(Variant(), num_alternatives);
  6889. if (VAR == this.last_ && Alt() == this.last_) return;
  6890. if (this.last_ == 0x7fffffff) {
  6891. console.log("SYNC FIRST");
  6892. FIND("ALT").value = VAR;
  6893. } else if (VAR != this.last_) {
  6894. console.log("SYNC ALT");
  6895. FIND("ALT").value = VAR;
  6896. blade.addEffect(EFFECT_ALT_SOUND, 0.0);
  6897. } else {
  6898. console.log("SYNC VAR");
  6899. VAR = Alt();
  6900. FIND("VARIANT_VALUE").value = VAR;
  6901. }
  6902. this.last_ = VAR;
  6903. }
  6904. getInteger(led) { return 0; }
  6905. }
  6906.  
  6907. function SyncAltToVarianceF() {
  6908. return new SyncAltToVarianceFClass();
  6909. }
  6910.  
  6911. class SyncAltToVarianceLClass extends MACRO {
  6912. constructor() {
  6913. super("Invisble layer for synchronizing Alt and Variance.", arguments);
  6914. this.SetExpansion(AlphaL(BLACK, SyncAltToVarianceF()));
  6915. }
  6916. }
  6917.  
  6918. function SyncAltToVarianceL() {
  6919. return new SyncAltToVarianceLClass();
  6920. }
  6921.  
  6922. class EffectPulseFClass extends FUNCTION {
  6923. constructor() {
  6924. super("Generate a pulse every time an effect occurs", arguments);
  6925. this.add_arg("EFFECT", "EFFECT", "Effect to trigger new random.");
  6926. this.effect = new OneshotEffectDetector(this.EFFECT);
  6927. this.value = 0;
  6928. }
  6929. run(blade) {
  6930. super.run(blade);
  6931. if (this.effect.Detect(blade)) {
  6932. this.value = 32768;
  6933. } else {
  6934. this.value = 0;
  6935. }
  6936. }
  6937. getInteger(led) { return this.value; }
  6938. };
  6939.  
  6940. function EffectPulseF(EFFECT) {
  6941. return new EffectPulseFClass(EFFECT);
  6942. }
  6943.  
  6944. class IncrementWithResetClass extends FUNCTION {
  6945. constructor(PULSE, RESET_PULSE, MAX, I) {
  6946. super("Increment by I each time PULSE occurs.", arguments);
  6947. this.add_arg("PULSE", "FUNCTION", "Pulse.");
  6948. this.add_arg("RESET_PULSE", "FUNCTION", "Reset pulse.", Int(0));
  6949. this.add_arg("MAX", "FUNCTION", "Max value", Int(32768));
  6950. this.add_arg("I", "FUNCTION", "Increment", Int(1));
  6951. this.value = 0;
  6952. }
  6953. run(blade) {
  6954. super.run(blade);
  6955. if (this.RESET_PULSE.getInteger(0)) {
  6956. this.value = 0;
  6957. }
  6958. if (this.PULSE.getInteger(0)) {
  6959. this.value = min(this.value + this.I.getInteger(0), this.MAX.getInteger(0));;
  6960. }
  6961. }
  6962. getInteger(led) { return this.value; }
  6963. }
  6964.  
  6965. function IncrementWithReset(PULSE, RESET_PULSE, MAX, I) {
  6966. return new IncrementWithResetClass(PULSE, RESET_PULSE, MAX, I);
  6967. }
  6968.  
  6969. class IncrementModuloFClass extends FUNCTION {
  6970. constructor(PULSE, MAX, I) {
  6971. super("Increment by I each time PULSE occurs.", arguments);
  6972. this.add_arg("PULSE", "FUNCTION", "Pulse.");
  6973. this.add_arg("MAX", "FUNCTION", "Max value", Int(32768));
  6974. this.add_arg("I", "FUNCTION", "Increment", Int(1));
  6975. this.value = 0;
  6976. }
  6977. run(blade) {
  6978. super.run(blade);
  6979. if (this.PULSE.getInteger(0)) {
  6980. this.value = (this.value + this.I.getInteger(0)) % this.MAX.getInteger(0);
  6981. }
  6982. }
  6983. getInteger(led) { return this.value; }
  6984. }
  6985.  
  6986. function IncrementModuloF(PULSE, MAX, I) {
  6987. return new IncrementModuloFClass(PULSE, MAX, I);
  6988. }
  6989.  
  6990. class ThresholdPulseFClass extends FUNCTION {
  6991. constructor(F, THRESHOLD, HYST_PERCENT) {
  6992. super("Generate a Pulse when F > THRESHOLD.", arguments);
  6993. this.add_arg("F", "FUNCTION", "Input");
  6994. this.add_arg("THRESHOLD", "FUNCTION", "Threshold", Int(32768));
  6995. this.add_arg("HYST_PERCENT", "FUNCTION", "Hysteresis percent", Int(66));
  6996. this.value = 0;
  6997. this.triggered = 0;
  6998. }
  6999. run(blade) {
  7000. super.run(blade);
  7001. var f = this.F.getInteger(0);
  7002. var threshold = this.THRESHOLD.getInteger(0);
  7003. this.value = 0;
  7004. if (this.triggered) {
  7005. if (f < threshold * this.HYST_PERCENT.getInteger(0) / 100) {
  7006. this.triggered = false;
  7007. }
  7008. } else {
  7009. if (f >= threshold) {
  7010. this.triggered = true;
  7011. this.value = 32768;
  7012. }
  7013. }
  7014. }
  7015. getInteger(led) { return this.value; }
  7016. }
  7017.  
  7018. function ThresholdPulseF(F, THRESHOLD, HYST_PERCENT) {
  7019. return new ThresholdPulseFClass(F, THRESHOLD, HYST_PERCENT);
  7020. }
  7021.  
  7022. class IncrementFClass extends MACRO {
  7023. constructor(F, V, MAX, I, HYST_PERCENT) {
  7024. super("Increase by I every time F > V.", arguments);
  7025. this.add_arg("F", "FUNCTION", "Input");
  7026. this.add_arg("V", "FUNCTION", "Compare value.", Int(32768));
  7027. this.add_arg("MAX", "FUNCTION", "Max value.", Int(32768));
  7028. this.add_arg("I", "FUNCTION", "Increment", Int(1));
  7029. this.add_arg("HYST_PERCENT", "FUNCTION", "Hysteresis percent", Int(66));
  7030. this.SetExpansion(IncrementModuloF(ThresholdPulseF(this.F, this.V, this.HYST_PERCENT), this.MAX, this.I));
  7031. }
  7032. };
  7033.  
  7034. function IncrementF(F, V, MAX, I, HYST_PERCENT) {
  7035. return new IncrementFClass(F, V, MAX, I, HYST_PERCENT);
  7036. }
  7037.  
  7038. class EffectIncrementFClass extends MACRO {
  7039. constructor(EFFECT, MAX, I) {
  7040. super("Increase by I every time F > V.", arguments);
  7041. this.add_arg("EFFECT", "EFFECT", "Effect to trigger increment.");
  7042. this.add_arg("MAX", "FUNCTION", "Max value.", Int(32768));
  7043. this.add_arg("I", "FUNCTION", "Increment", Int(1));
  7044. this.SetExpansion(IncrementModuloF(EffectPulseF(this.EFFECT), this.MAX, this.I));
  7045. }
  7046. };
  7047.  
  7048. function EffectIncrementF(EFFECT, MAX, I) {
  7049. return new EffectIncrementFClass(EFFECT, MAX, I);
  7050. }
  7051.  
  7052. class EffectRandomFClass extends FUNCTION {
  7053. constructor() {
  7054. super("Select a new random value every time an effect occurs", arguments);
  7055. this.add_arg("EFFECT", "EFFECT", "Effect to trigger new random.");
  7056. this.effect = new OneshotEffectDetector(this.EFFECT);
  7057. this.value = random(32768);
  7058. }
  7059. run(blade) {
  7060. super.run(blade);
  7061. if (this.effect.Detect(blade)) {
  7062. this.value = random(32768);
  7063. }
  7064. }
  7065.  
  7066. getInteger(led) { return this.value; }
  7067. };
  7068.  
  7069. function EffectRandomF(EFFECT) {
  7070. return new EffectRandomFClass(EFFECT);
  7071. }
  7072.  
  7073. class EffectPositionClass extends FUNCTION {
  7074. constructor() {
  7075. super("Select a new random value every time an effect occurs", arguments);
  7076. this.add_arg("EFFECT", "EFFECT", "Effect to trigger new random.", EFFECT(EFFECT_NONE));
  7077. this.value = 0;
  7078. }
  7079. run(blade) {
  7080. super.run(blade);
  7081. var effect;
  7082. if (this.EFFECT+0 == 0) {
  7083. effect = last_detected_blade_effect;
  7084. } else {
  7085. var e = new OneshotEffectDetector(this.EFFECT);
  7086. effect = e.Detect(blade);
  7087. }
  7088. if (effect) {
  7089. this.value = effect.location * 32768;
  7090. } else {
  7091. this.value = 0;
  7092. }
  7093. }
  7094. getInteger(led) {
  7095. return this.value;
  7096. }
  7097. };
  7098.  
  7099. function EffectPosition(EFFECT) {
  7100. return new EffectPositionClass(EFFECT);
  7101. }
  7102.  
  7103. class TimeSinceEffectClass extends FUNCTION {
  7104. constructor() {
  7105. super("Returns milliseconds since effect occured", arguments);
  7106. this.add_arg("EFFECT", "EFFECT", "Effect to get time since.", EFFECT(EFFECT_NONE));
  7107. this.value = 0;
  7108. }
  7109. run(blade) {
  7110. super.run(blade);
  7111. var effect;
  7112. if (this.EFFECT == 0) {
  7113. effect = last_detected_blade_effect;
  7114. } else {
  7115. var e = new OneshotEffectDetector(this.EFFECT);
  7116. effect = e.Detect(blade);
  7117. }
  7118. if (effect) {
  7119. this.value = (micros() - effect.start_micros) / 1000;
  7120. }
  7121. }
  7122. getInteger(led) {
  7123. return this.value;
  7124. }
  7125. };
  7126.  
  7127. function TimeSinceEffect(EFFECT) {
  7128. return new TimeSinceEffectClass(EFFECT);
  7129. }
  7130.  
  7131. class WavNumClass extends FUNCTION {
  7132. constructor() {
  7133. super("Returns milliseconds since effect occured", arguments);
  7134. this.add_arg("EFFECT", "EFFECT", "Effect to get time since.", EFFECT(EFFECT_NONE));
  7135. this.value = 0;
  7136. }
  7137. run(blade) {
  7138. super.run(blade);
  7139. var effect;
  7140. if (this.EFFECT == 0) {
  7141. effect = last_detected_blade_effect;
  7142. } else {
  7143. var e = new OneshotEffectDetector(this.EFFECT);
  7144. effect = e.Detect(blade);
  7145. }
  7146. if (effect) {
  7147. this.value = effect.wavnum;
  7148. }
  7149. }
  7150. getInteger(led) {
  7151. return this.value;
  7152. }
  7153. };
  7154.  
  7155. function WavNum(EFFECT) {
  7156. return new WavNumClass(EFFECT);
  7157. }
  7158.  
  7159. class CenterDistFClass extends FUNCTION {
  7160. constructor(CENTER) {
  7161. super("Distance from center.", arguments);
  7162. this.add_arg("CENTER", "FUNCTION", "Center point", Int(16384));
  7163. }
  7164. run(blade) {
  7165. super.run(blade);
  7166. this.num_leds = blade.num_leds();
  7167. }
  7168. getInteger(led) {
  7169. return Math.abs(led * 32768 / this.num_leds - this.CENTER.getInteger(led));
  7170. }
  7171. };
  7172.  
  7173. function CenterDistF(CENTER) {
  7174. return new CenterDistFClass(CENTER);
  7175. }
  7176.  
  7177. class BladeAngleXClass extends FUNCTION {
  7178. constructor() {
  7179. super("Blade Angle", arguments);
  7180. this.add_arg("MIN", "FUNCTION", "What angle returns 0.", Int(0));
  7181. this.add_arg("MAX", "FUNCTION", "What angle returns 32768.", Int(32768));
  7182. }
  7183. run(blade) {
  7184. super.run(blade);
  7185. if (IN_FRAME) {
  7186. var min = this.MIN.getInteger(0);
  7187. var max = this.MAX.getInteger(0);
  7188. var v = fract( (BLADE_ANGLE + Math.PI / 2) / Math.PI);
  7189. if (v > 1) v = 2 - v;
  7190. v *= 32768.0;
  7191. this.var_ = clamp((v - min) * 32768 / (max - min), 0, 32768);
  7192. } else {
  7193. var v = Math.sin(millis() * Math.PI / 10000.0)/2.0 + 0.5;
  7194. this.var_ = clamp(v * 32768, 0, 32768);
  7195. }
  7196. }
  7197. getInteger(led) { return this.var_; }
  7198. };
  7199.  
  7200. function BladeAngleX(MIN, MAX) {
  7201. return new BladeAngleXClass(MIN, MAX);
  7202. }
  7203.  
  7204. class TwistAngleClass extends FUNCTION {
  7205. constructor() {
  7206. super("Twist Angle", arguments);
  7207. this.add_arg("N", "INT", "Number of up/downs per rotation.", 2);
  7208. this.add_arg("OFFSET", "INT", "Angular offset", 0);
  7209. }
  7210. run(blade) {
  7211. super.run(blade);
  7212. var v = Math.sin(millis() * Math.PI / 3000.0)/2.0 + 0.5;
  7213. this.var_ = clamp(v * 32768, 0, 32768);
  7214. }
  7215. getInteger(led) { return this.var_; }
  7216. };
  7217.  
  7218. function TwistAngle(N, OFFSET) {
  7219. return new TwistAngleClass(N, OFFSET);
  7220. }
  7221.  
  7222. class TwistAccelerationClass extends FUNCTION {
  7223. constructor() {
  7224. super("Twist Acceleration", arguments);
  7225. this.add_arg("MAX", "INT", "Acceleration needed to return 32768", 90);
  7226. }
  7227. run(blade) {
  7228. super.run(blade);
  7229. var v = Math.cos(millis() * Math.PI / 3000.0)/2.0 + 0.5;
  7230. this.var_ = clamp(v * 32768, 0, 32768);
  7231. }
  7232. getInteger(led) { return this.var_; }
  7233. };
  7234.  
  7235. function TwistAcceleration(N, OFFSET) {
  7236. return new TwistAccelerationClass(N, OFFSET);
  7237. }
  7238.  
  7239. class BladeAngleClass extends MACRO {
  7240. constructor() {
  7241. super("Blade Angle", arguments);
  7242. this.add_arg("MIN", "INT", "What angle returns 0.", 0);
  7243. this.add_arg("MAX", "INT", "What angle returns 32768.", 32768);
  7244. this.SetExpansion(BladeAngleX(Int(this.MIN), Int(this.MAX)));
  7245. }
  7246. };
  7247.  
  7248. function BladeAngle(MIN, MAX) {
  7249. return new BladeAngleClass(MIN, MAX);
  7250. }
  7251.  
  7252. class LockupPulseFClass extends FUNCTION {
  7253. constructor() {
  7254. super("32768 if specified lockup type, 0 otherwise.", arguments);
  7255. this.add_arg("LOCKUP_TYPE", "LOCKUP_TYPE", "Lockup type");
  7256. this.value_ = 0;
  7257. }
  7258. run(blade) {
  7259. super.run(blade)
  7260. if (STATE_LOCKUP == this.LOCKUP_TYPE) {
  7261. this.value_ = 32768;
  7262. } else {
  7263. this.value_ = 0;
  7264. }
  7265. }
  7266. getInteger(led) { return this.value_; }
  7267. }
  7268.  
  7269. function LockupPulseF(LOCKUP_TYPE) {
  7270. return new LockupPulseFClass(LOCKUP_TYPE);
  7271. }
  7272.  
  7273. class ResponsiveLockupLClass extends MACRO {
  7274. constructor(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7275. super("Responsive localized lockup layer.", arguments);
  7276. this.add_arg("COLOR", "COLOR", "Color.");
  7277. this.add_arg("TR1", "TRANSITION", "Begin transition", TrInstant());
  7278. this.add_arg("TR2", "TRANSITION", "End transition", TrInstant());
  7279. this.add_arg("TOP", "FUNCTION", "uppermost lockup limit", Scale(BladeAngle(0, 16000), Int(4000), Int(26000)));
  7280. this.add_arg("BOTTOM", "FUNCTION", "lowermost lockup limit", Int(6000));
  7281. this.add_arg("SIZE", "FUNCTION", "lockup size", Scale(SwingSpeed(100), Int(9000), Int(14000)));
  7282. this.SetExpansion(LockupTrL(AlphaL(COLOR, Bump(Scale(BladeAngle(), this.TOP, this.BOTTOM), this.SIZE)),
  7283. this.TR1,
  7284. this.TR2,
  7285. LOCKUP_TYPE(LOCKUP_NORMAL)));;
  7286. }
  7287. argify(state) {
  7288. state.color_argument = LOCKUP_COLOR_ARG;
  7289. var ret = super.argify(state);
  7290. state.color_argument = null;
  7291. return ret;
  7292. }
  7293. };
  7294.  
  7295. function ResponsiveLockupL(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7296. return new ResponsiveLockupLClass(COLOR, TR1, TR2, TOP, BOTTOM, SIZE);
  7297. }
  7298.  
  7299. class ResponsiveDragLClass extends MACRO {
  7300. constructor(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7301. super("Responsive localized drag layer.", arguments);
  7302. this.add_arg("COLOR", "COLOR", "Color.");
  7303. this.add_arg("TR1", "TRANSITION", "Begin transition", TrInstant());
  7304. this.add_arg("TR2", "TRANSITION", "End transition", TrInstant());
  7305. this.add_arg("SIZE1", "FUNCTION", "lower twist limit", Int(2000));
  7306. this.add_arg("SIZE2", "FUNCTION", "upper twist limit", Int(10000));
  7307. this.SetExpansion(LockupTrL(AlphaL(COLOR, SmoothStep(Int(32000), Scale(TwistAngle(), this.SIZE1, this.SIZE2))),
  7308. this.TR1,
  7309. this.TR2,
  7310. LOCKUP_TYPE(LOCKUP_DRAG)));
  7311. }
  7312. argify(state) {
  7313. state.color_argument = DRAG_COLOR_ARG;
  7314. var ret = super.argify(state);
  7315. state.color_argument = null;
  7316. return ret;
  7317. }
  7318. };
  7319.  
  7320. function ResponsiveDragL(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7321. return new ResponsiveDragLClass(COLOR, TR1, TR2, TOP, BOTTOM, SIZE);
  7322. }
  7323.  
  7324. class ResponsiveMeltLClass extends MACRO {
  7325. constructor(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7326. super("Responsive localized melt layer.", arguments);
  7327. this.add_arg("COLOR", "COLOR", "Color.", Mix(TwistAngle(), OrangeRed.DOCOPY(), RED.DOCOPY()));
  7328. this.add_arg("TR1", "TRANSITION", "Begin transition", TrWipeIn(600));
  7329. this.add_arg("TR2", "TRANSITION", "End transition", TrWipe(600));
  7330. this.add_arg("SIZE1", "FUNCTION", "lower twist limit", Int(4000));
  7331. this.add_arg("SIZE2", "FUNCTION", "upper twist limit", Int(10000));
  7332. this.SetExpansion(LockupTrL(AlphaL(this.COLOR, SmoothStep(Int(30000), Scale(TwistAngle(), this.SIZE1, this.SIZE2))),
  7333. this.TR1,
  7334. this.TR2,
  7335. LOCKUP_TYPE(LOCKUP_MELT)));
  7336. }
  7337. };
  7338.  
  7339. function ResponsiveMeltL(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7340. return new ResponsiveMeltLClass(COLOR, TR1, TR2, TOP, BOTTOM, SIZE);
  7341. }
  7342.  
  7343. class ResponsiveLightningBlockLClass extends MACRO {
  7344. constructor(COLOR, TR1, TR2) {
  7345. super("Responsive lightning block layer", arguments);
  7346. this.add_arg("COLOR", "COLOR", "Color.");
  7347. this.add_arg("TR1", "TRANSITION", "Begin transition", TrInstant());
  7348. this.add_arg("TR2", "TRANSITION", "End transition", TrInstant());
  7349. this.SetExpansion(
  7350. LockupTrL(
  7351. AlphaL(COLOR,
  7352. LayerFunctions(
  7353. Bump(Scale(SlowNoise(Scale(BladeAngle(24000,32768),Int(2100),Int(1000))),Scale(BladeAngle(24000,32768),Int(3000),Int(10000)),Int(16000)),
  7354. Scale(BrownNoiseF(Int(10)),Scale(TwistAngle(),Int(4000),Int(10000)),Scale(TwistAngle(),Int(9000),Int(14000)))),
  7355. Bump(Scale(SlowNoise(Int(2200)),Scale(BladeAngle(24000,32768),Int(26000),Int(18000)),Int(8000)),
  7356. Scale(NoisySoundLevel(),Scale(TwistAngle(),Int(6000),Int(10000)),Scale(TwistAngle(),Int(10000),Int(14000)))),
  7357. Bump(Scale(SlowNoise(Int(2300)),Scale(BladeAngle(24000,32768),Int(20000),Int(16000)),Scale(BladeAngle(24000,32768),Int(30000),Int(24000))),
  7358. Scale(IsLessThan(SlowNoise(Int(2000)),Int(12000)),Scale(NoisySoundLevel(),Scale(TwistAngle(),Int(9000),Int(5000)),Int(0)),Int(0))))),
  7359. this.TR1,
  7360. this.TR2,
  7361. LOCKUP_TYPE(LOCKUP_LIGHTNING_BLOCK)));
  7362. }
  7363. argify(state) {
  7364. state.color_argument = LB_COLOR_ARG;
  7365. var ret = super.argify(state);
  7366. state.color_argument = null;
  7367. return ret;
  7368. }
  7369. };
  7370.  
  7371. function ResponsiveLightningBlockL(COLOR, TR1, TR2) {
  7372. return new ResponsiveLightningBlockLClass(COLOR, TR1, TR2);
  7373. }
  7374.  
  7375. class ResponsiveClashLClass extends MACRO {
  7376. constructor(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7377. super("Responsive localized lockup layer.", arguments);
  7378. this.add_arg("COLOR", "COLOR", "Color.");
  7379. this.add_arg("TR1", "TRANSITION", "Begin transition", TrInstant());
  7380. this.add_arg("TR2", "TRANSITION", "End transition", TrFade(200));
  7381. this.add_arg("TOP", "FUNCTION", "uppermost lockup limit", Scale(BladeAngle(0, 16000), Int(4000), Int(26000)));
  7382. this.add_arg("BOTTOM", "FUNCTION", "lowermost lockup limit", Int(6000));
  7383. this.add_arg("SIZE", "FUNCTION", "lockup size", Int(10000));
  7384. this.SetExpansion(TransitionEffectL(TrConcat(this.TR1,
  7385. AlphaL(COLOR, Bump(Scale(BladeAngle(), this.TOP, this.BOTTOM), this.SIZE)),
  7386. this.TR2),
  7387. EFFECT(EFFECT_CLASH)));
  7388. }
  7389. argify(state) {
  7390. state.color_argument = CLASH_COLOR_ARG;
  7391. var ret = super.argify(state);
  7392. state.color_argument = null;
  7393. return ret;
  7394. }
  7395. };
  7396.  
  7397. function ResponsiveClashL(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7398. return new ResponsiveClashLClass(COLOR, TR1, TR2, TOP, BOTTOM, SIZE);
  7399. }
  7400.  
  7401. class ResponsiveBlastLClass extends MACRO {
  7402. constructor(COLOR, FADE, SIZE, SPEED, TOP, BOTTOM, EFFECT_ARG) {
  7403. super("Responsive localized blast layer.", arguments);
  7404. this.add_arg("COLOR", "COLOR", "Color.");
  7405. this.add_arg("FADE", "FUNCTION", "fadeout time", Int(400));
  7406. this.add_arg("SIZE", "FUNCTION", "blast size", Int(100));
  7407. this.add_arg("SPEED", "FUNCTION", "blast speed", Int(400));
  7408. this.add_arg("TOP", "FUNCTION", "uppermost blast limit", Int(28000));
  7409. this.add_arg("BOTTOM", "FUNCTION", "lowermost blast limit", Int(8000));
  7410. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  7411. this.SetExpansion(
  7412. AlphaL(MultiTransitionEffectL(
  7413. TrWaveX(this.COLOR, this.FADE, this.SIZE, this.SPEED, Scale(BladeAngle(), this.TOP, this.BOTTOM)),
  7414. this.EFFECT),
  7415. Bump(Scale(BladeAngle(), this.TOP, this.BOTTOM), Int(24000))));
  7416. }
  7417. argify(state) {
  7418. state.color_argument = BLAST_COLOR_ARG;
  7419. var ret = super.argify(state);
  7420. state.color_argument = null;
  7421. return ret;
  7422. }
  7423. };
  7424.  
  7425. function ResponsiveBlastL(COLOR, FADE, SIZE, SPEED, TOP, BOTTOM, EFFECT) {
  7426. return new ResponsiveBlastLClass(COLOR, FADE, SIZE, SPEED, TOP, BOTTOM, EFFECT);
  7427. }
  7428.  
  7429. class ResponsiveBlastWaveLClass extends MACRO {
  7430. constructor(COLOR, FADE, SIZE, SPEED, TOP, BOTTOM, EFFECT_ARG) {
  7431. super("Responsive localized blast layer.", arguments);
  7432. this.add_arg("COLOR", "COLOR", "Color.");
  7433. this.add_arg("FADE", "FUNCTION", "fadeout time", Int(400));
  7434. this.add_arg("SIZE", "FUNCTION", "blast size", Int(100));
  7435. this.add_arg("SPEED", "FUNCTION", "blast speed", Int(400));
  7436. this.add_arg("TOP", "FUNCTION", "uppermost blast limit", Int(28000));
  7437. this.add_arg("BOTTOM", "FUNCTION", "lowermost blast limit", Int(8000));
  7438. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  7439. this.SetExpansion(
  7440. MultiTransitionEffectL(
  7441. TrWaveX(this.COLOR, this.FADE, this.SIZE, this.SPEED, Scale(BladeAngle(), this.TOP, this.BOTTOM)),
  7442. this.EFFECT));
  7443.  
  7444. }
  7445. argify(state) {
  7446. state.color_argument = BLAST_COLOR_ARG;
  7447. var ret = super.argify(state);
  7448. state.color_argument = null;
  7449. return ret;
  7450. }
  7451. };
  7452.  
  7453. function ResponsiveBlastWaveL(COLOR, FADE, SIZE, SPEED, TOP, BOTTOM, EFFECT) {
  7454. return new ResponsiveBlastWaveLClass(COLOR, FADE, SIZE, SPEED, TOP, BOTTOM, EFFECT);
  7455. }
  7456.  
  7457. class ResponsiveBlastFadeLClass extends MACRO {
  7458. constructor(COLOR, FADE, SIZE, TOP, BOTTOM, EFFECT_ARG) {
  7459. super("Responsive localized blast layer.", arguments);
  7460. this.add_arg("COLOR", "COLOR", "Color.");
  7461. this.add_arg("SIZE", "FUNCTION", "blast size", Int(8000));
  7462. this.add_arg("FADE", "FUNCTION", "fadeout time", Int(400));
  7463. this.add_arg("TOP", "FUNCTION", "uppermost blast limit", Int(28000));
  7464. this.add_arg("BOTTOM", "FUNCTION", "lowermost blast limit", Int(8000));
  7465. this.add_arg("EFFECT", "EFFECT", "effect type", EFFECT(EFFECT_BLAST));
  7466. this.SetExpansion(
  7467. MultiTransitionEffectL(
  7468. TrConcat(TrInstant(),
  7469. AlphaL(this.COLOR, Bump(Scale(BladeAngle(), this.TOP, this.BOTTOM), this.SIZE)),
  7470. TrFadeX(this.FADE)),
  7471. this.EFFECT));
  7472.  
  7473. }
  7474. argify(state) {
  7475. state.color_argument = BLAST_COLOR_ARG;
  7476. var ret = super.argify(state);
  7477. state.color_argument = null;
  7478. return ret;
  7479. }
  7480. };
  7481.  
  7482. function ResponsiveBlastFadeL(COLOR, FADE, SIZE, TOP, BOTTOM, EFFECT) {
  7483. return new ResponsiveBlastFadeLClass(COLOR, FADE, SIZE, TOP, BOTTOM, EFFECT);
  7484. }
  7485.  
  7486. class ResponsiveStabLClass extends MACRO {
  7487. constructor(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7488. super("Responsive localized stab layer.", arguments);
  7489. this.add_arg("COLOR", "COLOR", "Color.");
  7490. this.add_arg("TR1", "TRANSITION", "Begin transition", TrWipeIn(600));
  7491. this.add_arg("TR2", "TRANSITION", "End transition", TrWipe(600));
  7492. this.add_arg("SIZE1", "FUNCTION", "lower twist limit", Int(14000));
  7493. this.add_arg("SIZE2", "FUNCTION", "upper twist limit", Int(8000));
  7494. this.SetExpansion(
  7495. TransitionEffectL(TrConcat(this.TR1,
  7496. AlphaL(COLOR, SmoothStep(Int(32000), Scale(BladeAngle(), this.SIZE1, this.SIZE2))),
  7497. this.TR2),
  7498. EFFECT(EFFECT_STAB)));
  7499.  
  7500. }
  7501. argify(state) {
  7502. state.color_argument = STAB_COLOR_ARG;
  7503. var ret = super.argify(state);
  7504. state.color_argument = null;
  7505. return ret;
  7506. }
  7507. };
  7508.  
  7509. function ResponsiveStabL(COLOR, TR1, TR2, TOP, BOTTOM, SIZE) {
  7510. return new ResponsiveStabLClass(COLOR, TR1, TR2, TOP, BOTTOM, SIZE);
  7511. }
  7512.  
  7513. ///////
  7514.  
  7515. class IgnitionTimeClass extends MACRO {
  7516. constructor(DEFAULT_VALUE) {
  7517. super("arg/wavlen ignition time", arguments);
  7518. this.add_arg("DEFAULT_VALUE", "INT", "Default value.", 300);
  7519. this.SetExpansion(Scale(IsLessThan(IntArg_(ArgumentName(IGNITION_TIME_ARG),this.DEFAULT_VALUE),Int(1)),IntArg_(ArgumentName(IGNITION_TIME_ARG),this.DEFAULT_VALUE),WavLen(EFFECT(EFFECT_IGNITION))));
  7520. }
  7521. }
  7522.  
  7523. function IgnitionTime(DEFAULT_VALUE) {
  7524. return new IgnitionTimeClass(DEFAULT_VALUE);
  7525. }
  7526.  
  7527. class RetractionTimeClass extends MACRO {
  7528. constructor(DEFAULT_VALUE) {
  7529. super("arg/wavlen ignition time", arguments);
  7530. this.add_arg("DEFAULT_VALUE", "INT", "Default value.", 0);
  7531. this.SetExpansion(Scale(IsLessThan(IntArg_(ArgumentName(RETRACTION_TIME_ARG),this.DEFAULT_VALUE),Int(1)),IntArg_(ArgumentName(RETRACTION_TIME_ARG),this.DEFAULT_VALUE),WavLen(EFFECT(EFFECT_RETRACTION))));
  7532. }
  7533. }
  7534.  
  7535. function RetractionTime(DEFAULT_VALUE) {
  7536. return new RetractionTimeClass(DEFAULT_VALUE);
  7537. }
  7538.  
  7539. ////////////////
  7540.  
  7541. class SumClass extends FUNCTION {
  7542. constructor(ARGS) {
  7543. super("Add functions together", ARGS);
  7544. this.F = Array.from(ARGS);
  7545. for (var i = 1; i <= this.F.length; i++) {
  7546. this.add_arg("FUN" + i, "FUNCTION", "Function " + i);
  7547. }
  7548. }
  7549. getInteger(led) {
  7550. var ret = 0;
  7551. for (var i = 0; i < this.F.length; i++) {
  7552. ret += this.F[i].getInteger(led);
  7553. }
  7554. return ret;
  7555. }
  7556. }
  7557.  
  7558. function Sum(ARGS) {
  7559. return new SumClass(Array.from(arguments));
  7560. }
  7561.  
  7562. class DivideClass extends FUNCTION {
  7563. constructor(F, V) {
  7564. super("Returns F / V", arguments);
  7565. this.add_arg("F", "FUNCTION", "F");
  7566. this.add_arg("V", "FUNCTION", "V");
  7567. }
  7568. getInteger(led) {
  7569. var v = this.V.getInteger(led);
  7570. if (v == 0) return 0;
  7571. return this.F.getInteger(led) / v;
  7572. }
  7573. };
  7574.  
  7575. function Divide(F, V) {
  7576. return new DivideClass(F, V);
  7577. }
  7578.  
  7579. class ModFClass extends FUNCTION {
  7580. constructor(F, V) {
  7581. super("Returns F mod V (always positive)", arguments);
  7582. this.add_arg("F", "FUNCTION", "F");
  7583. this.add_arg("V", "FUNCTION", "V");
  7584. }
  7585. getInteger(led) {
  7586. var v = this.V.getInteger(led);
  7587. if (v == 0) return 0;
  7588. return MOD(this.F.getInteger(led), v);
  7589. }
  7590. };
  7591. function ModF(F, V) {
  7592. return new ModFClass(F, V);
  7593. }
  7594.  
  7595. class SubtractClass extends FUNCTION {
  7596. constructor(F, V) {
  7597. super("Returns F - V", arguments);
  7598. this.add_arg("F", "FUNCTION", "F");
  7599. this.add_arg("V", "FUNCTION", "V");
  7600. }
  7601. getInteger(led) {
  7602. return this.F.getInteger(led) - this.V.getInteger(led);
  7603. }
  7604. };
  7605.  
  7606. function Subtract(F, V) {
  7607. return new SubtractClass(F, V);
  7608. }
  7609. ///////
  7610.  
  7611. class HoldPeakFClass extends FUNCTION {
  7612. constructor(F, HOLD_MILLIS, SPEED) {
  7613. super("Holds peak values for the given number of millis, then falls at given speed.", arguments);
  7614. this.add_arg("F", "FUNCTION", "Function to process");
  7615. this.add_arg("HOLD_MILLIS", "FUNCTION", "Millis to hold.");
  7616. this.add_arg("SPEED", "FUNCTION", "Decay speed (per second)");
  7617. this.last_micros = micros();
  7618. this.last_peak = 0;
  7619. this.value = 0;
  7620. }
  7621. run(blade) {
  7622. super.run(blade);
  7623. var current = this.F.getInteger(0);
  7624. var hold_millis = this.HOLD_MILLIS.getInteger(0);
  7625. var now = micros();
  7626. var delta = now - this.last_micros;
  7627. this.last_micros = now;
  7628. if (millis() - this.last_peak > hold_millis) {
  7629. if (delta > 1000000) delta = 1;
  7630. delta *= this.SPEED.getInteger(0);
  7631. delta /= 1000000;
  7632. this.value -= delta;
  7633. }
  7634. if (current > this.value) {
  7635. this.value = current;
  7636. this.last_peak = millis();
  7637. }
  7638. }
  7639.  
  7640. getInteger(led) {
  7641. return this.value;
  7642. }
  7643. }
  7644.  
  7645. function HoldPeakF(F, HOLD_MILLIS, SPEED) {
  7646. return new HoldPeakFClass(F, HOLD_MILLIS, SPEED);
  7647. }
  7648.  
  7649. ///////
  7650.  
  7651. class CircularSectionFClass extends FUNCTION {
  7652. constructor(POSITION, FRACTION) {
  7653. super("Circular section", arguments);
  7654. this.add_arg("POSITION", "FUNCTION", "Position of circular secion.");
  7655. this.add_arg("FRACTION", "FUNCTION", "Fraction of circle lit up.");
  7656. }
  7657. run(blade) {
  7658. super.run(blade);
  7659. this.num_leds = blade.num_leds();
  7660. var fraction = this.FRACTION.getInteger(0);
  7661. if (fraction == 32768) {
  7662. this.start = 0;
  7663. this.end = num_leds * 32768;
  7664. } else if (fraction == 0) {
  7665. this.start = 0;
  7666. this.end = 0;
  7667. } else {
  7668. var pos = this.POSITION.getInteger(0);
  7669. this.start = ((pos + 32768 - fraction / 2) & 32767) * this.num_leds;
  7670. this.end = ((pos + fraction / 2) & 32767) * this.num_leds;
  7671. }
  7672. this.num_leds *= 32768;
  7673. // console.log("START="+this.start+" END="+this.end +" num_leds="+this.num_leds);
  7674. }
  7675. getInteger(led) {
  7676. var led_range = new Range(led * 32768, led * 32768 + 32768);
  7677. var black_mix = 0;
  7678. if (this.start <= this.end) {
  7679. black_mix = (new Range(this.start, this.end).Intersect(led_range)).Size();
  7680. } else {
  7681. black_mix = (new Range(0, this.end).Intersect(led_range)).Size() +
  7682. (new Range(this.start, this.num_leds).Intersect(led_range)).Size();
  7683. }
  7684. // console.log("BLACK MIX = " + black_mix);
  7685. return black_mix;
  7686. }
  7687. }
  7688.  
  7689. function CircularSectionF(POSITION, FRACTION) {
  7690. return new CircularSectionFClass(POSITION, FRACTION);
  7691. }
  7692.  
  7693. ///////
  7694.  
  7695. class MarbleFClass extends FUNCTION {
  7696. constructor(OFFSET, FRICTION, ACCELERATION, GRAVITY) {
  7697. super("Circular marble simulator.", arguments);
  7698. this.add_arg("OFFSET","FUNCTION", "Offset");
  7699. this.add_arg("FRICTION","FUNCTION", "Friction");
  7700. this.add_arg("ACCELERATION","FUNCTION", "Acceleration");
  7701. this.add_arg("GRAVITY","FUNCTION", "Gravity");
  7702. this.last_micros = 0;
  7703. this.pos = 0;
  7704. this.value = 0;
  7705. this.pos = 0.0;
  7706. this.speed = 0.0;
  7707. }
  7708. run(blade) {
  7709. super.run(blade);
  7710. var now = micros();
  7711. var delta = now - this.last_micros;
  7712. this.last_micros = now;
  7713. if (delta > 1000000) delta = 1;
  7714. var fraction = delta / 1000000.0;
  7715. var rad = (this.pos + this.OFFSET.getInteger(0) / 32768.0) * Math.PI * 2.0;
  7716. var down = { x:0.0, y:1.0, z:0.0 };
  7717. var gravity = this.GRAVITY.getInteger(0) / 32768.0;
  7718. var accel = (down.y * Math.sin(rad) + down.z * Math.cos(rad)) * gravity;
  7719. accel += this.ACCELERATION.getInteger(0) / 32768.0;
  7720. accel-= this.speed * this.FRICTION.getInteger(0) / 32768.0;
  7721. this.speed += accel * fraction;
  7722. this.pos = fract(this.pos + this.speed * fraction);
  7723. this.value = this.pos * 32768.0;
  7724. }
  7725. getInteger(led) { return this.value; }
  7726. };
  7727.  
  7728. function MarbleF(OFFSET, FRICTION, ACCELERATION, GRAVITY) {
  7729. return new MarbleFClass(OFFSET, FRICTION, ACCELERATION, GRAVITY);
  7730. }
  7731.  
  7732. ///////
  7733.  
  7734. class LinearSectionFClass extends FUNCTION {
  7735. constructor(POSITION, FRACTION) {
  7736. super("Linear section", arguments);
  7737. this.add_arg("POSITION", "FUNCTION", "Position of linear secion.");
  7738. this.add_arg("FRACTION", "FUNCTION", "Fraction lit up.");
  7739. }
  7740. run(blade) {
  7741. super.run(blade);
  7742. var num_leds = blade.num_leds();
  7743. var fraction = this.FRACTION.getInteger(0);
  7744. var pos = this.POSITION.getInteger(0);
  7745. this.range = new Range(clamp((pos - fraction / 2) * num_leds, 0, 32768 * num_leds), clamp((pos + fraction / 2) * num_leds, 0, 32768 * num_leds));
  7746. }
  7747. getInteger(led) {
  7748. var led_range = new Range(led * 32768, led * 32768 + 32768);
  7749. return this.range.Intersect(led_range).Size();
  7750. }
  7751. }
  7752.  
  7753. function LinearSectionF(POSITION, FRACTION) {
  7754. return new LinearSectionFClass(POSITION, FRACTION);
  7755. }
  7756.  
  7757. ///////
  7758.  
  7759. var start = new Date().getTime();
  7760.  
  7761. var current_focus;
  7762. var current_focus_url;
  7763. var style_tree;
  7764.  
  7765. function newCall(Cls) {
  7766. return new (Function.prototype.bind.apply(Cls, arguments));
  7767. }
  7768.  
  7769.  
  7770. var classes = {
  7771. AlphaL : AlphaL,
  7772. AlphaMixL : AlphaMixL,
  7773. AudioFlicker : AudioFlicker,
  7774. AudioFlickerL : AudioFlickerL,
  7775. Blast : Blast,
  7776. BlastL : BlastL,
  7777. BlastF : BlastF,
  7778. BlastFadeout : BlastFadeout,
  7779. BlastFadeoutL : BlastFadeoutL,
  7780. BlastFadeoutF : BlastFadeoutF,
  7781. Blinking : Blinking,
  7782. BlinkingL : BlinkingL,
  7783. BlinkingX : BlinkingX,
  7784. BlinkingF : BlinkingF,
  7785. BrownNoiseFlicker : BrownNoiseFlicker,
  7786. BrownNoiseFlickerL : BrownNoiseFlickerL,
  7787. BrownNoiseF : BrownNoiseF,
  7788. ColorCycle : ColorCycle,
  7789. ColorChange : ColorChange,
  7790. ColorSelect : ColorSelect,
  7791. IntSelect : IntSelect,
  7792. ColorSequence : ColorSequence,
  7793. EffectSequence : EffectSequence,
  7794. Cylon : Cylon,
  7795. EasyBlade : EasyBlade,
  7796. FOCUS : Focus,
  7797. FireConfig : FireConfig,
  7798. Gradient : Gradient,
  7799. HumpFlicker : HumpFlicker,
  7800. HumpFlickerL : HumpFlickerL,
  7801. HumpFlickerF : HumpFlickerF,
  7802. HumpFlickerFX : HumpFlickerFX,
  7803. IgnitionDelay : IgnitionDelay,
  7804. IgnitionDelayX : IgnitionDelayX,
  7805. RetractionDelay : RetractionDelay,
  7806. RetractionDelayX : RetractionDelayX,
  7807. InOutHelper : InOutHelper,
  7808. InOutHelperX : InOutHelperX,
  7809. InOutHelperL : InOutHelperL,
  7810. InOutHelperF : InOutHelperF,
  7811. InOutSparkTip : InOutSparkTip,
  7812. Layers : Layers,
  7813. LocalizedClash : LocalizedClash,
  7814. LocalizedClashL : LocalizedClashL,
  7815. Lockup : Lockup,
  7816. LockupL : LockupL,
  7817. LockupTr : LockupTr,
  7818. LockupTrL : LockupTrL,
  7819. Mix : Mix,
  7820. OnSpark : OnSpark,
  7821. OnSparkX : OnSparkX,
  7822. OnSparkL : OnSparkL,
  7823. OnSparkF : OnSparkF,
  7824. OriginalBlast : OriginalBlast,
  7825. OriginalBlastL : OriginalBlastL,
  7826. OriginalBlastF : OriginalBlastF,
  7827. Pulsing : Pulsing,
  7828. PulsingX : PulsingX,
  7829. PulsingL : PulsingL,
  7830. PulsingF : PulsingF,
  7831. RandomFlicker : RandomFlicker,
  7832. RandomL : RandomL,
  7833. RandomF : RandomF,
  7834. RandomPerLEDFlicker : RandomPerLEDFlicker,
  7835. RandomPerLEDFlickerL : RandomPerLEDFlickerL,
  7836. RandomPerLEDF : RandomPerLEDF,
  7837. RandomBlink : RandomBlink,
  7838. RandomBlinkX : RandomBlinkX,
  7839. RandomBlinkL : RandomBlinkL,
  7840. RandomBlinkF : RandomBlinkF,
  7841. Remap : Remap,
  7842. Sequence : Sequence,
  7843. SequenceL : SequenceL,
  7844. SequenceF : SequenceF,
  7845. Rgb : Rgb,
  7846. Rgb16 : Rgb16,
  7847. SimpleClash : SimpleClash,
  7848. SimpleClashL : SimpleClashL,
  7849. Sparkle : Sparkle,
  7850. SparkleL : SparkleL,
  7851. SparkleF : SparkleF,
  7852. Strobe : Strobe,
  7853. StrobeX : StrobeX,
  7854. StrobeL : StrobeL,
  7855. StrobeF : StrobeF,
  7856. Stripes : Stripes,
  7857. StripesX : StripesX,
  7858. StyleFire : StyleFire,
  7859. StylePtr : StylePtr,
  7860. StyleFirePtr : StyleFirePtr,
  7861. StyleNormalPtr : StyleNormalPtr,
  7862. StyleRainbowPtr : StyleRainbowPtr,
  7863. StyleStrobePtr : StyleStrobePtr,
  7864. StaticFire : StaticFire,
  7865. TransitionLoop : TransitionLoop,
  7866. TransitionLoopL : TransitionLoopL,
  7867. TransitionEffect : TransitionEffect,
  7868. TransitionEffectL : TransitionEffectL,
  7869. MultiTransitionEffect : MultiTransitionEffect,
  7870. MultiTransitionEffectL : MultiTransitionEffectL,
  7871. TransitionPulseL : TransitionPulseL,
  7872. InOutTr : InOutTr,
  7873. InOutTrL : InOutTrL,
  7874.  
  7875. RotateColorsX : RotateColorsX,
  7876. RotateColors : RotateColors,
  7877. HueX : HueX,
  7878. Hue : Hue,
  7879.  
  7880. TrInstant : TrInstant,
  7881. TrFade : TrFade,
  7882. TrFadeX : TrFadeX,
  7883. TrSmoothFade : TrSmoothFade,
  7884. TrSmoothFadeX : TrSmoothFadeX,
  7885. TrDelay : TrDelay,
  7886. TrDelayX : TrDelayX,
  7887. TrBoing : TrBoing,
  7888. TrBoingX : TrBoingX,
  7889. TrBlink : TrBlink,
  7890. TrBlinkX : TrBlinkX,
  7891. TrDoEffect : TrDoEffect,
  7892. TrDoEffectX : TrDoEffectX,
  7893. TrDoEffectAlways : TrDoEffectAlways,
  7894. TrDoEffectAlwaysX : TrDoEffectAlwaysX,
  7895. TrWipe : TrWipe,
  7896. TrWipeX : TrWipeX,
  7897. TrWipeIn : TrWipeIn,
  7898. TrWipeInX : TrWipeInX,
  7899. TrCenterWipe : TrCenterWipe,
  7900. TrCenterWipeX : TrCenterWipeX,
  7901. TrCenterWipeSpark : TrCenterWipeSpark,
  7902. TrCenterWipeSparkX : TrCenterWipeSparkX,
  7903. TrCenterWipeIn : TrCenterWipeIn,
  7904. TrCenterWipeInX : TrCenterWipeInX,
  7905. TrCenterWipeInSpark : TrCenterWipeInSpark,
  7906. TrCenterWipeInSparkX : TrCenterWipeInSparkX,
  7907. TrColorCycle : TrColorCycle,
  7908. TrColorCycleX : TrColorCycleX,
  7909. TrConcat : TrConcat,
  7910. TrJoin : TrJoin,
  7911. TrJoinR : TrJoinR,
  7912. TrRandom : TrRandom,
  7913. TrSelect : TrSelect,
  7914. TrWaveX : TrWaveX,
  7915. TrSparkX : TrSparkX,
  7916. TrWipeSparkTip : TrWipeSparkTip,
  7917. TrWipeSparkTipX : TrWipeSparkTipX,
  7918. TrWipeInSparkTip : TrWipeInSparkTip,
  7919. TrWipeInSparkTipX : TrWipeInSparkTipX,
  7920. TrExtendX : TrExtendX,
  7921. TrExtend : TrExtend,
  7922. TrLoop : TrLoop,
  7923. TrLoopN : TrLoopN,
  7924. TrLoopNX : TrLoopNX,
  7925. TrLoopUntil : TrLoopUntil,
  7926.  
  7927. ReverseTime : ReverseTime,
  7928. ReverseTimeX : ReverseTimeX,
  7929. BendTimePow : BendTimePow,
  7930. BendTimePowX : BendTimePowX,
  7931. BendTimePowInv : BendTimePowInv,
  7932. BendTimePowInvX : BendTimePowInvX,
  7933.  
  7934. BatteryLevel : BatteryLevel,
  7935. VolumeLevel : VolumeLevel,
  7936. Bump : Bump,
  7937. Ifon : Ifon,
  7938. ChangeSlowly : ChangeSlowly,
  7939. InOutFunc : InOutFunc,
  7940. InOutFuncX : InOutFuncX,
  7941. Int : Int,
  7942. IntArg : IntArg_,
  7943. RgbArg : RgbArg_,
  7944. Scale : Scale,
  7945. InvertF : InvertF,
  7946. Sin : Sin,
  7947. Saw : Saw,
  7948. Trigger : Trigger,
  7949. SmoothStep : SmoothStep,
  7950. RampF : RampF,
  7951. Mult : Mult,
  7952. Percentage : Percentage,
  7953. NoisySoundLevel : NoisySoundLevel,
  7954. NoisySoundLevelCompat : NoisySoundLevelCompat,
  7955. SmoothSoundLevel : SmoothSoundLevel,
  7956. SwingSpeedX : SwingSpeedX,
  7957. SwingSpeed : SwingSpeed,
  7958. SwingAccelerationX : SwingAccelerationX,
  7959. SwingAcceleration : SwingAcceleration,
  7960. ClashImpactFX : ClashImpactFX,
  7961. ClashImpactF : ClashImpactF,
  7962. LayerFunctions : LayerFunctions,
  7963. SlowNoise : SlowNoise,
  7964. IsLessThan : IsLessThan,
  7965. IsGreaterThan : IsGreaterThan,
  7966. IsBetween : IsBetween,
  7967. ClampFX : ClampFX,
  7968. ClampF : ClampF,
  7969. Variation : Variation,
  7970. AltF : AltF,
  7971. SyncAltToVarianceF : SyncAltToVarianceF,
  7972. SyncAltToVarianceL : SyncAltToVarianceL,
  7973. BladeAngleX : BladeAngleX,
  7974. BladeAngle : BladeAngle,
  7975. TwistAngle : TwistAngle,
  7976. TwistAcceleration : TwistAcceleration,
  7977. Sum : Sum,
  7978. Divide : Divide,
  7979. ModF : ModF,
  7980. Subtract : Subtract,
  7981. HoldPeakF : HoldPeakF,
  7982. ThresholdPulseF : ThresholdPulseF,
  7983. EffectRandomF : EffectRandomF,
  7984. EffectPulseF : EffectPulseF,
  7985. EffectPosition : EffectPosition,
  7986. TimeSinceEffect : TimeSinceEffect,
  7987. WavNum : WavNum,
  7988. CenterDistF : CenterDistF,
  7989. CircularSectionF : CircularSectionF,
  7990. LinearSectionF : LinearSectionF,
  7991. IncrementWithReset : IncrementWithReset,
  7992. IncrementModuloF : IncrementModuloF,
  7993. IncrementF : IncrementF,
  7994. EffectIncrementF : EffectIncrementF,
  7995. MarbleF : MarbleF,
  7996.  
  7997. ResponsiveLockupL : ResponsiveLockupL,
  7998. ResponsiveDragL : ResponsiveDragL,
  7999. ResponsiveMeltL : ResponsiveMeltL,
  8000. ResponsiveLightningBlockL : ResponsiveLightningBlockL,
  8001. ResponsiveClashL : ResponsiveClashL,
  8002. ResponsiveBlastL : ResponsiveBlastL,
  8003. ResponsiveBlastWaveL : ResponsiveBlastWaveL,
  8004. ResponsiveBlastFadeL : ResponsiveBlastFadeL,
  8005. ResponsiveStabL : ResponsiveStabL,
  8006.  
  8007. IgnitionTime : IgnitionTime,
  8008. RetractionTime : RetractionTime,
  8009. WavLen : WavLen,
  8010. LockupPulseF : LockupPulseF,
  8011. };
  8012.  
  8013.  
  8014. AddIdentifier("RgbCycle", RgbCycle);
  8015. AddIdentifier("Rainbow", Rainbow);
  8016. AddIdentifier("WHITE", Rgb.bind(null, 255,255,255));
  8017. AddIdentifier("BLACK", Rgb.bind(null, 0,0,0));
  8018.  
  8019. AddIdentifier("RED", Rgb.bind(null, 255,0,0));
  8020. AddIdentifier("GREEN", Rgb.bind(null, 0,255,0));
  8021. AddIdentifier("BLUE", Rgb.bind(null, 0,0,255));
  8022. AddIdentifier("YELLOW", Rgb.bind(null, 255,255,0));
  8023. AddIdentifier("CYAN", Rgb.bind(null, 0,255,255));
  8024. AddIdentifier("MAGENTA", Rgb.bind(null, 255,0,255));
  8025. AddIdentifier("WHITE", Rgb.bind(null, 255,255,255));
  8026. AddIdentifier("BLACK", Rgb.bind(null, 0,0,0));
  8027.  
  8028. AddIdentifier("AliceBlue", Rgb.bind(null, 223, 239, 255));
  8029. AddIdentifier("Aqua", Rgb.bind(null, 0, 255, 255));
  8030. AddIdentifier("Aquamarine", Rgb.bind(null, 55, 255, 169));
  8031. AddIdentifier("Azure", Rgb.bind(null, 223, 255, 255));
  8032. AddIdentifier("Bisque", Rgb.bind(null, 255, 199, 142));
  8033. AddIdentifier("Black", Rgb.bind(null, 0, 0, 0));
  8034. AddIdentifier("BlanchedAlmond", Rgb.bind(null, 255, 213, 157));
  8035. AddIdentifier("Blue", Rgb.bind(null, 0, 0, 255));
  8036. AddIdentifier("Chartreuse", Rgb.bind(null, 55, 255, 0));
  8037. AddIdentifier("Coral", Rgb.bind(null, 255, 55, 19));
  8038. AddIdentifier("Cornsilk", Rgb.bind(null, 255, 239, 184));
  8039. AddIdentifier("Cyan", Rgb.bind(null, 0, 255, 255));
  8040. AddIdentifier("DarkOrange", Rgb.bind(null, 255, 68, 0));
  8041. AddIdentifier("DeepPink", Rgb.bind(null, 255, 0, 75));
  8042. AddIdentifier("DeepSkyBlue", Rgb.bind(null, 0, 135, 255));
  8043. AddIdentifier("DodgerBlue", Rgb.bind(null, 2, 72, 255));
  8044. AddIdentifier("FloralWhite", Rgb.bind(null, 255, 244, 223));
  8045. AddIdentifier("Fuchsia", Rgb.bind(null, 255, 0, 255));
  8046. AddIdentifier("GhostWhite", Rgb.bind(null, 239, 239, 255));
  8047. AddIdentifier("Green", Rgb.bind(null, 0, 255, 0));
  8048. AddIdentifier("GreenYellow", Rgb.bind(null, 108, 255, 6));
  8049. AddIdentifier("HoneyDew", Rgb.bind(null, 223, 255, 223));
  8050. AddIdentifier("HotPink", Rgb.bind(null, 255, 36, 118));
  8051. AddIdentifier("Ivory", Rgb.bind(null, 255, 255, 223));
  8052. AddIdentifier("LavenderBlush", Rgb.bind(null, 255, 223, 233));
  8053. AddIdentifier("LemonChiffon", Rgb.bind(null, 255, 244, 157));
  8054. AddIdentifier("LightCyan", Rgb.bind(null, 191, 255, 255));
  8055. AddIdentifier("LightPink", Rgb.bind(null, 255, 121, 138));
  8056. AddIdentifier("LightSalmon", Rgb.bind(null, 255, 91, 50));
  8057. AddIdentifier("LightYellow", Rgb.bind(null, 255, 255, 191));
  8058. AddIdentifier("Lime", Rgb.bind(null, 0, 255, 0));
  8059. AddIdentifier("Magenta", Rgb.bind(null, 255, 0, 255));
  8060. AddIdentifier("MintCream", Rgb.bind(null, 233, 255, 244));
  8061. AddIdentifier("MistyRose", Rgb.bind(null, 255, 199, 193));
  8062. AddIdentifier("Moccasin", Rgb.bind(null, 255, 199, 119));
  8063. AddIdentifier("NavajoWhite", Rgb.bind(null, 255, 187, 108));
  8064. AddIdentifier("Orange", Rgb.bind(null, 255, 97, 0));
  8065. AddIdentifier("OrangeRed", Rgb.bind(null, 255, 14, 0));
  8066. AddIdentifier("PapayaWhip", Rgb.bind(null, 255, 221, 171));
  8067. AddIdentifier("PeachPuff", Rgb.bind(null, 255, 180, 125));
  8068. AddIdentifier("Pink", Rgb.bind(null, 255, 136, 154));
  8069. AddIdentifier("Red", Rgb.bind(null, 255, 0, 0));
  8070. AddIdentifier("SeaShell", Rgb.bind(null, 255, 233, 219));
  8071. AddIdentifier("Snow", Rgb.bind(null, 255, 244, 244));
  8072. AddIdentifier("SpringGreen", Rgb.bind(null, 0, 255, 55));
  8073. AddIdentifier("SteelBlue", Rgb.bind(null, 14, 57, 118));
  8074. AddIdentifier("Tomato", Rgb.bind(null, 255, 31, 15));
  8075. AddIdentifier("White", Rgb.bind(null, 255, 255, 255));
  8076. AddIdentifier("Yellow", Rgb.bind(null, 255, 255, 0));
  8077.  
  8078. class Parser {
  8079. constructor(str, classes, identifiers) {
  8080. console.log("PARSING: " + str);
  8081. this.str = str;
  8082. this.pos = 0;
  8083. this.classes = classes;
  8084. this.identifiers = identifiers;
  8085. }
  8086. peek() {
  8087. if (this.pos >= this.str.length) return ""
  8088. return this.str[this.pos]
  8089. }
  8090. peek2() {
  8091. if (this.pos + 1 >= this.str.length) return ""
  8092. return this.str[this.pos + 1]
  8093. }
  8094. gobble(c) {
  8095. this.skipspace();
  8096. if (this.peek() == c) {
  8097. this.pos++;
  8098. return true;
  8099. }
  8100. return false;
  8101. }
  8102. expect(c) {
  8103. if (!this.gobble(c)) throw "Missing " + c;
  8104. }
  8105. skipspace2() {
  8106. var start_pos = this.pos;
  8107. while (true) {
  8108. if (this.peek() == ' ' || this.peek() == '\t' || this.peek() == '\n' || this.peek() == '\r') { this.pos++; continue; }
  8109. if (this.peek() == '/') {
  8110. if (this.peek2() == '*') {
  8111. this.pos += 2;
  8112. while (this.pos < this.str.length && !(this.peek() == '*' && this.peek2() == '/')) this.pos++;
  8113. this.pos += 2;
  8114. continue;
  8115. }
  8116. if (this.peek2() == '/') {
  8117. this.pos += 2;
  8118. while (this.pos < this.str.length && this.peek() != '\n') this.pos++;
  8119. this.pos ++;
  8120. continue;
  8121. }
  8122. }
  8123. return this.str.substr(start_pos, this.pos - start_pos); // trim?
  8124. }
  8125. }
  8126.  
  8127. skipspace() {
  8128. var ret = this.skipspace2();
  8129. if (ret.trim()) {
  8130. console.log("COMMENT DROPPED ON GROUND: "+ret);
  8131. console.trace();
  8132. }
  8133. }
  8134.  
  8135. startswithnewline(str) {
  8136. var tmp = str.trimStart();
  8137. var start = str.substr(0, str.length - tmp.length);
  8138. return start.split('\n').length > 1;
  8139. }
  8140.  
  8141. stripcomment(str) {
  8142. var ret = "";
  8143. while (true) {
  8144. str = str.trim();
  8145. if (str) console.log("STRIPCOMMENT: "+str);
  8146. if (str == "") {
  8147. if (ret) console.log("STRIPCOMMENT -> "+ret);
  8148. return ret;
  8149. }
  8150. if (ret != "") ret += "\n";
  8151. if (str[0] == '/' && str[1] == '/') {
  8152. var tmp = str.split('\n');
  8153. ret += tmp[0].substr(2);
  8154. str = tmp.slice(1).join('\n');
  8155. } else if (str[0] == '/' && str[1] == '*') {
  8156. var tmp = str.split('*/');
  8157. ret += tmp[0].substr(2);
  8158. str = tmp.slice(1).join('*/');
  8159. } else {
  8160. if (ret) console.log("STRIPCOMMENT -> "+ret);
  8161. return ret;
  8162. }
  8163. }
  8164. }
  8165.  
  8166. identifier() {
  8167. var ret = "";
  8168. while (true) {
  8169. var c = this.peek();
  8170. if ((c >= 'a' && c <= 'z') ||
  8171. (c >= 'A' && c <= 'Z') ||
  8172. (c >= '0' && c <= '9') || c == '_' || c == ':') {
  8173. ret += c;
  8174. this.pos++;
  8175. } else {
  8176. return ret;
  8177. }
  8178. }
  8179. }
  8180.  
  8181. parse_optional_string() {
  8182. this.skipspace();
  8183. if (this.peek() != '"') return null;
  8184. var ret = "";
  8185. while (this.gobble('"')) {
  8186. while (this.peek() != '"') {
  8187. ret += this.peek();
  8188. this.pos++;
  8189. }
  8190. this.expect('"')
  8191. this.skipspace();
  8192. }
  8193. return ret;
  8194. }
  8195.  
  8196. // recursive descent parser
  8197. parse_atom() {
  8198. this.skipspace();
  8199. var start_of_atom = this.pos;
  8200. var id = this.identifier();
  8201. if (id == "") {
  8202. throw "Expected identifier or number";
  8203. }
  8204. if ((id[0] >= '0' && id[0] <= '9')) {
  8205. if (id.slice(0,2) == "0b") {
  8206. return new BINARY(parseInt(id.slice(2), 2));
  8207. }
  8208. return new INTEGER(parseInt(id));
  8209. }
  8210. var midcomment = this.skipspace2();
  8211. var args = 0;
  8212. var argstring = 0;
  8213. if (this.peek() == "<") {
  8214. this.pos++;
  8215. var POS = this.pos;
  8216. this.skipspace2();
  8217. args = [null];
  8218. if (this.peek() != '>') {
  8219. this.pos = POS; // backtrack for comments
  8220. while (true) {
  8221. var v = this.parse_internal();
  8222. args.push(v);
  8223. this.skipspace2();
  8224. if (this.peek() != ',') break;
  8225. this.pos++;
  8226. POS = this.pos
  8227. var comment = this.skipspace2();
  8228. if (this.startswithnewline(comment)) {
  8229. // Comment belongs to next value.
  8230. // rewind and let parse_unary do it.
  8231. this.pos = POS;
  8232. } else {
  8233. v.addcomment(this.stripcomment(comment));
  8234. if (v.COMMENT) console.log("SETCOMMENT:" + v.COMMENT);
  8235. }
  8236. }
  8237. }
  8238. if (this.peek() != '>') {
  8239. throw "Missing > or ,";
  8240. }
  8241. this.pos++;
  8242. if (this.peek() == '(') {
  8243. this.pos++;
  8244. argstring = this.parse_optional_string();
  8245. if (this.peek() != ')') throw "Missing )";
  8246. this.pos++;
  8247. }
  8248. }
  8249. var ret;
  8250. if (this.identifiers[id]) {
  8251. if (args != 0) {
  8252. throw "Unexpected arguments";
  8253. }
  8254. ret = this.identifiers[id]();
  8255. } else if (this.classes[id]) {
  8256. //console.log(id);
  8257. //console.log(this.classes[id]);
  8258. //console.log(args);
  8259. if (args == 0) args = [null];
  8260. // var ret = new (Function.prototype.bind.apply(this.classes[id], args));
  8261. try {
  8262. ret = classes[id].apply(args[0], args.slice(1));
  8263. } catch(e) {
  8264. if (typeof(e) == "string")
  8265. e = new MyError(id +":" + e);
  8266. if (typeof(e) == "object" && e.constructor == MyError)
  8267. e.desc = id + ":" + e.desc;
  8268. if (typeof(e) == "object" && e.constructor == MyError && e.end_pos == -1) {
  8269. e.setBegin(start_of_atom);
  8270. e.setEnd(this.pos);
  8271. }
  8272. throw e;
  8273. }
  8274. // console.log(ret);
  8275. if (argstring) {
  8276. console.log("ARGSTRING : " + argstring);
  8277. ret.argstring = argstring;
  8278. }
  8279. }
  8280. if (!ret) {
  8281. throw "Unknown identifier:" + id;
  8282. }
  8283. ret.addcomment(this.stripcomment(midcomment));
  8284. return ret;
  8285. }
  8286.  
  8287. parse_unary() {
  8288. var pre_comment = this.skipspace2();
  8289. var ret = 0;
  8290. if (this.peek() == '-') {
  8291. this.pos++;
  8292. ret = this.parse_atom();
  8293. if (ret.getType() != "INT")
  8294. throw "Expected integer, got " + ret.getType();
  8295. ret.value = - ret.value;
  8296. return ret;
  8297. } else {
  8298. ret = this.parse_atom();
  8299. }
  8300. if (pre_comment.trim()) {
  8301. ret.prependcomment(this.stripcomment(pre_comment));
  8302. }
  8303. return ret;
  8304. }
  8305.  
  8306. parse_internal() {
  8307. var ret = this.parse_unary();
  8308. this.skipspace();
  8309. while (this.peek() == '|') {
  8310. this.pos++;
  8311. ret.value |= this.parse_unary();
  8312. this.skipspace();
  8313. }
  8314. //console.log("PARSE, returns ID " + ret.get_id());
  8315. // console.log(ret);
  8316. // console.trace();
  8317.  
  8318. return ret;
  8319. }
  8320.  
  8321. parse() {
  8322. var OLD = PushHandledTypes();
  8323. var begin_pos = this.pos;
  8324. var ret = this.parse_internal();
  8325.  
  8326. // secret handshake
  8327. ret.__begin_pos = begin_pos;
  8328. ret.__end_pos = this.pos;
  8329. ret.__handled_types = handled_types;
  8330. ret.__handled_lockups = handled_lockups;
  8331. PopHandledTypes(OLD);
  8332.  
  8333. return ret;
  8334. }
  8335. };
  8336.  
  8337. var current_style = InOutHelper(SimpleClash(Lockup(new BlastClass(BLUE, WHITE), new AudioFlickerClass(BLUE, WHITE)), WHITE, 40), 300, 800);
  8338. //var current_style = InOutHelper(SimpleClash(Lockup(new BlastClass(new RainbowClass(), WHITE), new AudioFlickerClass(BLUE, WHITE)), WHITE, 40), 300, 800);
  8339. var blade = new Blade();
  8340. var rotate_start;
  8341. var last_micros;
  8342.  
  8343. var last_style;
  8344. var show_style;
  8345.  
  8346. var numTick = 0;
  8347. var framesPerUpdate = 0;
  8348.  
  8349. function drawScene() {
  8350. last_micros = current_micros;
  8351. current_micros = actual_millis() * 1000;
  8352. num_leds = blade.num_leds()
  8353. var pixels = new Uint8Array(num_leds * 4 * 2);
  8354. var S = current_style;
  8355. if (S != last_style) {
  8356. last_style = S;
  8357. if (S.getType) {
  8358. S.set_right_side(current_focus || style_tree)
  8359. if (S.getType() == "TRANSITION") {
  8360. S = TransitionLoop(Rgb(0,0,0), TrConcat(TrDelay(500), Rgb(255,0,0), S, Rgb(0,0,255), TrInstant()));
  8361. }
  8362. if (S.getType() == "FUNCTION") {
  8363. S = Mix(S, Rgb(0,0,0), Rgb(255,255,255));
  8364. }
  8365. }
  8366. show_style = S;
  8367. } else {
  8368. S = show_style;
  8369. }
  8370. if (S.getColor && S.getType && S.getType() == "COLOR") {
  8371. S.run(blade);
  8372. for (var i = 0; i < num_leds; i++) {
  8373. c = S.getColor(i);
  8374. pixels[i*4 + 0] = Math.round(c.r * 255);
  8375. pixels[i*4 + 1] = Math.round(c.g * 255);
  8376. pixels[i*4 + 2] = Math.round(c.b * 255);
  8377. pixels[i*4 + 3] = 255;
  8378. }
  8379. if (last_micros != 0) {
  8380. current_micros += (current_micros - last_micros) / 2;
  8381. }
  8382. if (framesPerUpdate == 0) {
  8383. S.run(blade);
  8384. }
  8385. for (var i = 0; i < num_leds; i++) {
  8386. c = S.getColor(i);
  8387. pixels[i*4 + 0 + num_leds * 4] = Math.round(c.r * 255);
  8388. pixels[i*4 + 1 + num_leds * 4] = Math.round(c.g * 255);
  8389. pixels[i*4 + 2 + num_leds * 4] = Math.round(c.b * 255);
  8390. pixels[i*4 + 3 + num_leds * 4] = 255;
  8391. }
  8392. S.update_displays();
  8393. }
  8394. // TODO: Generate mipmaps, then adjust level based on distance from blade
  8395. gl.texImage2D(
  8396. gl.TEXTURE_2D,
  8397. 0, // level
  8398. gl.RGBA, // internalFormat
  8399. num_leds, 2, // width, height
  8400. 0, // border
  8401. gl.RGBA, // source format
  8402. gl.UNSIGNED_BYTE, // source type
  8403. pixels);
  8404.  
  8405. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  8406. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  8407. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  8408. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  8409.  
  8410. // Draw these textures to the screen, offset by 1 pixel increments
  8411. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  8412. gl.viewport(0, 0, width * dpr, height * dpr);
  8413. gl.clearColor(0.0, 1.0, 0.0, 1.0);
  8414. gl.clear(gl.COLOR_BUFFER_BIT);
  8415.  
  8416. gl.viewport(0, 0, width * dpr, height * dpr);
  8417. var rotation = MOVE_MATRIX;
  8418. if (STATE_ROTATE) {
  8419. var u_value = (new Date().getTime() - rotate_start) / 3000.0;
  8420. var rotation = default_move_matrix();
  8421. rotation = rotation.mult(Matrix.mkyrot(u_value));
  8422. rotation = rotation.mult(Matrix.mkzrot(u_value / 7.777));
  8423.  
  8424. } else {
  8425. if (0) {
  8426. OLD_MOVE_MATRIX = default_move_matrix();
  8427. rotation = default_move_matrix();
  8428. rotation = rotation.mult(Matrix.mkzrot(0.2));
  8429. }
  8430. rotate_start = new Date().getTime();
  8431. }
  8432. gl.uniform1f(gl.getUniformLocation(shaderProgram, "u_time"),
  8433. (new Date().getTime() - start) / 1000.0);
  8434. gl.uniform1f(gl.getUniformLocation(shaderProgram, "u_width"), width);
  8435. gl.uniform1f(gl.getUniformLocation(shaderProgram, "u_height"), height);
  8436.  
  8437. gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, "u_move_matrix"), false, rotation.values);
  8438. gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, "u_old_move_matrix"), false, OLD_MOVE_MATRIX.values);
  8439. OLD_MOVE_MATRIX = rotation;
  8440. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  8441.  
  8442. t += 1;
  8443. }
  8444.  
  8445. function tick() {
  8446. window.requestAnimationFrame(tick);
  8447. numTick++;
  8448. if (numTick > framesPerUpdate) {
  8449. numTick = 0;
  8450. drawScene();
  8451. }
  8452. }
  8453. var overall_string;
  8454.  
  8455. function ReplaceCurrentFocus(str) {
  8456. current_focus_url = str;
  8457.  
  8458. if (current_focus) {
  8459. current_focus.super_short_desc = true;
  8460. pp_is_url++;
  8461. pp_is_verbose++;
  8462. var url = style_tree.pp();
  8463. console.log("FOCUS URL: " + url);
  8464. pp_is_url--;
  8465. pp_is_verbose--;
  8466. current_focus.super_short_desc = false;
  8467. str = url.replace("$", "FOCUS<" + str + ">");
  8468. }
  8469.  
  8470. var old_focus = current_focus;
  8471. current_focus = 0;
  8472. focus_catcher = 0;
  8473.  
  8474. var parser = new Parser(str, classes, identifiers);
  8475. try {
  8476. style_tree = parser.parse();
  8477. }
  8478. catch(e) {
  8479. var err = FIND("error_message");
  8480. current_focus = old_focus;
  8481. console.log(e);
  8482. console.log(e.stack);
  8483. console.log(typeof(e));
  8484. if (typeof(e) == "string") {
  8485. err.innerHTML = e;
  8486. return;
  8487. } else if (typeof(e) == "object" && e.constructor == MyError) {
  8488. err.innerHTML = e.desc;
  8489. return;
  8490. } else {
  8491. throw e;
  8492. }
  8493. }
  8494. var tmp = "";
  8495. tmp += style_tree.pp();
  8496. FIND("pp").innerHTML = tmp;
  8497. if (focus_catcher) {
  8498. current_focus = focus_catcher;
  8499. var id = current_focus.get_id();
  8500. var container = FIND("X"+id);
  8501. if (!container) {
  8502. console.log("Lost focus when parsing " + str);
  8503. console.log(focus_trace);
  8504. } else {
  8505. container.style.backgroundColor = 'lightblue';
  8506. }
  8507. } else {
  8508. console.log("No focus catcher found!!");
  8509. }
  8510. var type = "COLOR";
  8511. var classname = "Style";
  8512. // if (current_focus && current_style && current_focus != current_style) {
  8513. // type = current_style.getType();
  8514. // classname = current_focus.constructor.name;
  8515. // }
  8516.  
  8517. if (current_style) {
  8518. type = current_style.getType();
  8519. classname = current_style.constructor.name;
  8520. }
  8521.  
  8522. AddHistory(current_focus_url, current_style.getType());
  8523. console.log("TYPE = " + type);
  8524. // FIND("color_links").className = type == "COLOR" ? "normal" : "grayout";
  8525. // FIND("effect_links").className = type == "COLOR" ? "normal" : "grayout";
  8526. // FIND("effect_type_links").className = type == "EFFECT" ? "normal" : "grayout";
  8527. // FIND("template_links").className = type == "COLOR" ? "normal" : "grayout";
  8528. // FIND("function_links").className = type == "FUNCTION" ? "normal" : "grayout";
  8529. // FIND("transition_links").className = type == "TRANSITION" ? "normal" : "grayout";
  8530. FIND("expand_button").className = current_style && current_style.isMacro ? "button_on" : "button_off";
  8531. FIND("layerize_button").className = CanLayerize(current_style) ? "button_on" : "button_off";
  8532.  
  8533. if (type == "COLOR" && classname.endsWith("LClass")) {
  8534. ActivateTab("layer");
  8535. } else if (type == "COLOR" && (classname == "Rgb16Class" || classname == "RgbClass")) {
  8536. ActivateTab("rgb");
  8537. } else {
  8538. ActivateTab(type.toLowerCase());
  8539. }
  8540.  
  8541. for (var i = 0; i < document.styleSheets.length; i++) {
  8542. var sheet = document.styleSheets[i];
  8543. for (var r = 0; r < sheet.cssRules.length; r++) {
  8544. var rule = sheet.cssRules[r];
  8545. if (rule.cssText.toLowerCase().includes("magic_class_") ) {
  8546. if (rule.cssText.toLowerCase().includes("magic_class_" + type.toLowerCase())) {
  8547. rule.style.background = "lightblue";
  8548. rule.style.color = "black";
  8549. } else {
  8550. rule.style.background = "lightgray";
  8551. rule.style.color = "darkgray";
  8552. }
  8553. }
  8554. if (rule.cssText.toLowerCase().includes("magic_invisible_class_") ) {
  8555. if (rule.cssText.toLowerCase().includes("magic_invisible_class_" + type.toLowerCase())) {
  8556. rule.style.display = 'inline';
  8557. } else {
  8558. rule.style.display = 'none';
  8559. }
  8560. }
  8561. }
  8562. }
  8563. }
  8564.  
  8565.  
  8566. function Run() {
  8567. var sty = FIND("style");
  8568. var err = FIND("error_message");
  8569. var str = sty.value;
  8570. var parser = new Parser(str,
  8571. classes,
  8572. identifiers);
  8573. err.innerHTML = "";
  8574. try {
  8575. current_style = parser.parse();
  8576. }
  8577. catch(e) {
  8578. console.log(e);
  8579. console.log(e.stack);
  8580. console.log(typeof(e));
  8581. if (typeof(e) == "string") {
  8582.  
  8583. err.innerHTML = e;
  8584. sty.focus();
  8585. sty.setSelectionRange(parser.pos, parser.pos);
  8586.  
  8587. parser = new Parser("BLACK",
  8588. classes,
  8589. identifiers);
  8590. current_style = parser.parse();
  8591. compile();
  8592. return;
  8593. } else if (typeof(e) == "object" && e.constructor == MyError) {
  8594. err.innerHTML = e.desc;
  8595. sty.focus();
  8596. if (e.begin_pos > -1) {
  8597. sty.setSelectionRange(e.begin_pos, e.end_pos);
  8598. } else {
  8599. sty.setSelectionRange(parser.pos, parser.pos);
  8600. }
  8601.  
  8602. parser = new Parser("BLACK",
  8603. classes,
  8604. identifiers);
  8605. current_style = parser.parse();
  8606. compile();
  8607. return;
  8608. } else {
  8609. throw e;
  8610. }
  8611. }
  8612. ReplaceCurrentFocus(str);
  8613. compile();
  8614. if (current_style.argstring) {
  8615. FIND("ARGSTR").value = "builtin 0 1 " + current_style.argstring
  8616. ArgStringChanged();
  8617. }
  8618. }
  8619.  
  8620. var ARGUMENTS = ["builtin", "0", "1"];
  8621. var default_arguments = [];
  8622.  
  8623. function updateArgTag(ARG, VALUE) {
  8624. var N = ArgumentName_ENUM_BUILDER.value_to_name[ARG];
  8625. var tag = FIND("ARGSTR_"+N);
  8626. if (VALUE.search(",") >= 0) {
  8627. console.log("FIXING COLOR VALUE: "+VALUE);
  8628. var values = VALUE.split(",")
  8629. VALUE = '#' + UnFixColor(values[0])+UnFixColor(values[1])+UnFixColor(values[2]);
  8630. }
  8631. console.log("Setting tag from: " + tag.value + " to " + VALUE);
  8632. tag.value = VALUE;
  8633. }
  8634.  
  8635. function getARG(ARG, DEFAULT) {
  8636. ARG = ARG + 2;
  8637. if (!default_arguments[ARG]) {
  8638. updateArgTag(ARG - 2, DEFAULT);
  8639. }
  8640. default_arguments[ARG] = DEFAULT;
  8641. if (ARGUMENTS[ARG] && ARGUMENTS[ARG] != "~")
  8642. return ARGUMENTS[ARG];
  8643. return DEFAULT;
  8644. }
  8645.  
  8646. function ArgStringChanged() {
  8647. var tag = FIND("ARGSTR");
  8648. ARGUMENTS = tag.value.split(" ");
  8649. for (var i = 3; i < ARGUMENTS.length; i++) {
  8650. if (ARGUMENTS[i] == "~") continue;
  8651. if (!ARGUMENTS[i]) continue;
  8652. var ARG = i - 2;
  8653. updateArgTag(ARG, ARGUMENTS[i]);
  8654. }
  8655. }
  8656.  
  8657. function setARG(ARG, TO) {
  8658. ARG += 2;
  8659. ARGUMENTS[ARG] = TO;
  8660. for (var i = 0; i < ARGUMENTS.length; i++) {
  8661. if (!ARGUMENTS[i]) {
  8662. ARGUMENTS[i] = '~';
  8663. }
  8664. }
  8665. FIND("ARGSTR").value = ARGUMENTS.join(" ");
  8666. }
  8667.  
  8668. function ArgChanged(ARG) {
  8669. var N = ArgumentName_ENUM_BUILDER.value_to_name[ARG];
  8670. var tag = FIND("ARGSTR_"+N);
  8671. setARG(ARG, tag.value);
  8672. }
  8673.  
  8674. function IncreaseArg(ARG, I) {
  8675. var N = ArgumentName_ENUM_BUILDER.value_to_name[ARG];
  8676. var tag = FIND("ARGSTR_"+N);
  8677. tag.value = parseInt(tag.value) + I;
  8678. setARG(ARG, tag.value);
  8679. }
  8680.  
  8681. function ClickArgColor(ARG) {
  8682. var N = ArgumentName_ENUM_BUILDER.value_to_name[ARG];
  8683. var tag = FIND("ARGSTR_"+N);
  8684. var R = FixColor(tag.value.substr(1,2));
  8685. var G = FixColor(tag.value.substr(3,2));
  8686. var B = FixColor(tag.value.substr(5,2));
  8687. setARG(ARG, R+","+G+","+B);
  8688. }
  8689.  
  8690. function PopState(event) {
  8691. if (event.state) {
  8692. FIND("style").value = event.state;
  8693. Run();
  8694. }
  8695. }
  8696.  
  8697. function SetTo(str) {
  8698. console.log(str);
  8699. var old = FIND("style").value;
  8700. var url = new URL(window.location.href);
  8701. url.searchParams.set("S", str);
  8702.  
  8703. // FIXME: Use pushState and fix back arrow
  8704. window.history.replaceState(old, "Style Editor", window.location.href);
  8705. window.history.pushState(str, "Style Editor", url);
  8706. window.onpopstate = PopState;
  8707.  
  8708. FIND("style").value = str;
  8709. Run();
  8710. }
  8711.  
  8712. function SetToAndFormat(str) {
  8713. var parser = new Parser(str, classes, identifiers);
  8714. var style = parser.parse();
  8715. pp_is_url++;
  8716. var url = style.pp();
  8717. pp_is_url--;
  8718. SetTo(url);
  8719. }
  8720.  
  8721. function FocusOnLow(id) {
  8722. console.log("FOCUSON: " + id);
  8723. var style = style_ids[id];
  8724. console.log(id);
  8725. console.log(style);
  8726. current_focus = style;
  8727. var container = FIND("X"+id);
  8728. console.log(container);
  8729. container.style.backgroundColor = 'lightblue';
  8730. pp_is_url++;
  8731. var url = style.pp();
  8732. pp_is_url--;
  8733. console.log(url);
  8734. current_focus_url = url;
  8735. SetTo(url);
  8736. return true;
  8737. }
  8738.  
  8739. function FocusOn(id, event) {
  8740. event.stopPropagation();
  8741. FocusOnLow(id);
  8742. }
  8743.  
  8744. function ClickRotate() {
  8745. STATE_ROTATE = !STATE_ROTATE;
  8746. var rotate_button = FIND("ROTATE_BUTTON");
  8747. rotate_button.style.backgroundColor = STATE_ROTATE ? "lightblue" : "";
  8748. console.log("ROTATE");
  8749. }
  8750.  
  8751. function ClickPower() {
  8752. STATE_ON = !STATE_ON; STATE_LOCKUP=0;
  8753. var power_button = FIND("POWER_BUTTON");
  8754. power_button.style.backgroundColor = STATE_ON ? "lightblue" : "";
  8755. console.log("POWER");
  8756. blade.addEffect(STATE_ON ? EFFECT_IGNITION : EFFECT_RETRACTION, Math.random() * 0.7 + 0.2);
  8757. }
  8758.  
  8759. function UpdateLockupButtons() {
  8760. var button = FIND("LOCKUP_BUTTON");
  8761. button.style.backgroundColor = STATE_LOCKUP == LOCKUP_NORMAL ? "lightblue" : "";
  8762. var button = FIND("DRAG_BUTTON");
  8763. button.style.backgroundColor = STATE_LOCKUP == LOCKUP_DRAG ? "lightblue" : "";
  8764. var button = FIND("MELT_BUTTON");
  8765. button.style.backgroundColor = STATE_LOCKUP == LOCKUP_MELT ? "lightblue" : "";
  8766. var button = FIND("LB_BUTTON");
  8767. button.style.backgroundColor = STATE_LOCKUP == LOCKUP_LIGHTNING_BLOCK ? "lightblue" : "";
  8768. }
  8769.  
  8770. var lockups_to_event = {};
  8771. lockups_to_event[LOCKUP_NORMAL] = [ EFFECT_LOCKUP_BEGIN, EFFECT_LOCKUP_END ];
  8772. lockups_to_event[LOCKUP_DRAG] = [ EFFECT_DRAG_BEGIN, EFFECT_DRAG_END ];
  8773.  
  8774. function OnLockupChange() {
  8775. console.log("OnLockupChange");
  8776. var select = FIND("LOCKUP");
  8777. var old = STATE_LOCKUP;
  8778. STATE_LOCKUP = window[select.value];
  8779. if (STATE_LOCKUP && lockups_to_event[STATE_LOCKUP]) {
  8780. blade.addEffect(lockups_to_event[STATE_LOCKUP][0], Math.random() * 0.7 + 0.2);
  8781. } else if (old && lockups_to_event[old]) {
  8782. blade.addEffect(lockups_to_event[old][1], Math.random() * 0.7 + 0.2);
  8783. }
  8784. }
  8785.  
  8786. function ClickLockup() {
  8787. STATE_LOCKUP = STATE_LOCKUP == LOCKUP_NORMAL ? 0 : LOCKUP_NORMAL;
  8788. UpdateLockupButtons();
  8789. blade.addEffect(STATE_LOCKUP ? EFFECT_LOCKUP_BEGIN : EFFECT_LOCKUP_END, Math.random() * 0.7 + 0.2);
  8790. }
  8791.  
  8792. function ClickDrag() {
  8793. STATE_LOCKUP = STATE_LOCKUP == LOCKUP_DRAG ? 0 : LOCKUP_DRAG;
  8794. UpdateLockupButtons();
  8795. blade.addEffect(STATE_LOCKUP ? EFFECT_DRAG_BEGIN : EFFECT_DRAG_END, 1.0);
  8796. }
  8797.  
  8798. function ClickLB() {
  8799. STATE_LOCKUP = STATE_LOCKUP == LOCKUP_LIGHTNING_BLOCK ? 0 : LOCKUP_LIGHTNING_BLOCK;
  8800. UpdateLockupButtons();
  8801. }
  8802.  
  8803. function ClickMelt() {
  8804. STATE_LOCKUP = STATE_LOCKUP == LOCKUP_MELT ? 0 : LOCKUP_MELT;
  8805. UpdateLockupButtons();
  8806. }
  8807.  
  8808. function ClickInhilt() {
  8809. STATE_NUM_LEDS = 145 - STATE_NUM_LEDS;
  8810. var button = FIND("INHILT_BUTTON");
  8811. button.style.backgroundColor = STATE_NUM_LEDS == 1 ? "lightblue" : "";
  8812. }
  8813.  
  8814. function ClickSlow() {
  8815. framesPerUpdate = 60 - framesPerUpdate;
  8816. var button = FIND("SLOW_BUTTON");
  8817. button.style.backgroundColor = framesPerUpdate == 60 ? "lightblue" : "";
  8818. }
  8819.  
  8820. /* Settings buttons saved as local cookies */
  8821. function saveSettingToLocalStorage(settingType, settingValue) {
  8822. localStorage.setItem(settingType, settingValue);
  8823. }
  8824.  
  8825. function getSettingFromLocalStorage(settingType) {
  8826. return localStorage.getItem(settingType);
  8827. }
  8828.  
  8829. function onPageLoad() {
  8830. // Retrieve the values of the settings from local storage
  8831. var darkModeOn = getSettingFromLocalStorage("darkModeState") === "true";
  8832. var stillOn = getSettingFromLocalStorage("stillState") === "true";
  8833. var tooltipsOn = getSettingFromLocalStorage("tooltipsState") === "true";
  8834.  
  8835. // Set the state of the settings buttons based on the retrieved values
  8836. var body = document.querySelector("body");
  8837. if (darkModeOn) {
  8838. body.classList.add("dark-mode");
  8839. var button = document.getElementById("DARK_BUTTON");
  8840. button.style.backgroundColor = "lightblue";
  8841. }
  8842. if (stillOn) {
  8843. STATE_STILL = true;
  8844. var button = document.getElementById("STILL_BUTTON");
  8845. button.style.backgroundColor = "lightblue";
  8846. }
  8847. if (tooltipsOn) {
  8848. body.classList.add("tooltips");
  8849. var button = document.getElementById("TIPS_BUTTON");
  8850. button.style.backgroundColor = "lightblue";
  8851. }
  8852. }
  8853.  
  8854. // Call the onPageLoad function when the page is loaded
  8855. window.addEventListener('load', onPageLoad);
  8856.  
  8857. function ClickStill() {
  8858. STATE_STILL = !STATE_STILL;
  8859. var button = FIND("STILL_BUTTON");
  8860. button.style.backgroundColor = STATE_STILL ? "lightblue" : "";
  8861. saveSettingToLocalStorage("stillState", STATE_STILL.toString());
  8862. }
  8863.  
  8864. function ClickDark() {
  8865. const body = document.querySelector("body");
  8866. body.classList.toggle("dark-mode");
  8867. const button = document.getElementById("DARK_BUTTON");
  8868. button.style.backgroundColor = body.classList.contains("dark-mode") ? "lightblue" : "";
  8869. const darkModeOn = body.classList.contains("dark-mode") ? "true" : "false";
  8870. saveSettingToLocalStorage("darkModeState", darkModeOn);
  8871. }
  8872.  
  8873. function ClickTips() {
  8874. const body = document.querySelector("body");
  8875. body.classList.toggle("tooltips");
  8876. const button = document.getElementById("TIPS_BUTTON");
  8877. button.style.backgroundColor = body.classList.contains("tooltips") ? "lightblue" : "";
  8878. const tooltipsOn = body.classList.contains("tooltips") ? "true" : "false";
  8879. saveSettingToLocalStorage("tooltipsState", tooltipsOn);
  8880. }
  8881.  
  8882.  
  8883.  
  8884. var num_alternatives = 1000;
  8885.  
  8886. function Alt() {
  8887. return parseInt(FIND("ALT").value);
  8888. }
  8889.  
  8890. function IncreaseAlt(n) {
  8891. var v = Alt() + n;
  8892. if (v < 0) v += num_alternatives;
  8893. if (v > num_alternatives) v -= num_alternatives;
  8894. FIND("ALT").value = v;
  8895. console.log("Updated Alt: " + v); // BC add
  8896. }
  8897.  
  8898. function Variant() {
  8899. return parseInt(FIND("VARIANT_VALUE").value);
  8900. }
  8901.  
  8902. /* Variant Slider functions */
  8903.  
  8904. function updateVariantValue(newValue) {
  8905. if (newValue < 0) {
  8906. newValue = 0;
  8907. } else if (newValue > 32768) {
  8908. newValue = 32768;
  8909. }
  8910. document.getElementById("VARIANT_VALUE").value = newValue;
  8911. document.getElementById("VARIANT_SLIDER").value = newValue;
  8912. console.log("Updated Variant: " + newValue);
  8913. }
  8914.  
  8915. var timeoutId, intervalId;
  8916.  
  8917. // Single click arrow to adjust by 1, hold to accelerate.
  8918. function startAdjustingValue(adjustment, inputId) {
  8919. adjustmentValue(adjustment, inputId);
  8920. var speed = 100;
  8921. clearTimeout(timeoutId);
  8922. timeoutId = setTimeout(function() {
  8923. var startTime = new Date().getTime();
  8924. intervalId = setInterval(function() {
  8925. var elapsedTime = new Date().getTime() - startTime;
  8926. var progress = elapsedTime / speed;
  8927. var ease = Math.pow(progress, 2);
  8928. var value = Math.round(adjustment * ease);
  8929. adjustmentValue(value, inputId);
  8930. }, 1000 / 60); // 60 FPS for more responsive input
  8931. }, 500);
  8932. }
  8933.  
  8934. function adjustmentValue(adjustment, inputId) {
  8935. var variantInput = document.getElementById(inputId);
  8936. var newValue = parseInt(variantInput.value) + adjustment;
  8937. variantInput.value = newValue;
  8938. updateVariantValue(newValue);
  8939. }
  8940.  
  8941. // Release or mouse leave arrow button
  8942. function stopAdjustingValue() {
  8943. clearInterval(intervalId);
  8944. clearTimeout(timeoutId);
  8945. }
  8946. /* End Variant Slider functions */
  8947.  
  8948. function Copy() {
  8949. var copyText = FIND("style");
  8950. var argStr = '"' + ARGUMENTS.slice(3).join(" ") + '"';
  8951. if (argStr == '""') argStr = "";
  8952. if(copyText.value.includes("StylePtr") ||
  8953. copyText.value.includes("StyleNormalPtr") ||
  8954. copyText.value.includes("StyleFirePtr") ||
  8955. copyText.value.includes("StyleRainbowPtr"))
  8956. {
  8957. if(!copyText.value.endsWith(")"))
  8958. copyText.value = copyText.value + "("+ argStr +")";
  8959. } else {
  8960. copyText.value = "StylePtr<" + copyText.value + ">" + "("+ argStr +")";
  8961. }
  8962. copyText.select();
  8963. document.execCommand("copy");
  8964. // alert("Copy to Clipboard" + copyText.value);
  8965. // myAlertTop("Copy to Clipboard");
  8966. }
  8967.  
  8968. function DoExpand() {
  8969. if (current_style && current_style.expansion) {
  8970. pp_is_url++;
  8971. var url = current_style.expansion.pp();
  8972. pp_is_url--;
  8973. SetTo(url);
  8974. }
  8975. }
  8976.  
  8977. function ShouldJoin(layer1, layer2) {
  8978. if (layer1.LAYERS.length == 0) return true;
  8979. if (layer2.LAYERS.length == 0) return true;
  8980. return layer1.LAYERS[0].isEffect() == layer2.LAYERS[0].isEffect();
  8981. }
  8982.  
  8983. function RecursiveLayerize(node) {
  8984. while (node.isMacro) {
  8985. node = node.expansion;
  8986. }
  8987. if (node.constructor == LayersClass) {
  8988. node.BASE = RecursiveLayerize(node.BASE);
  8989. while (node.BASE.constructor == LayersClass && ShouldJoin(node, node.BASE)) {
  8990. node = new LayersClass([node.BASE.BASE].concat(node.BASE.LAYERS,node.LAYERS));
  8991. }
  8992. }
  8993. return node;
  8994. }
  8995.  
  8996. function CanLayerize(node) {
  8997. if (!node) return false;
  8998. if (node.constructor == LayersClass) return false;
  8999. while (node.isMacro) {
  9000. node = node.expansion;
  9001. }
  9002. return node.constructor == LayersClass;
  9003. }
  9004.  
  9005. function DoLayerize() {
  9006. var tmp = RecursiveLayerize(current_style);
  9007. pp_is_url++;
  9008. tmp = tmp.pp();
  9009. pp_is_url--;
  9010. SetTo(tmp);
  9011. }
  9012.  
  9013. function DoArgify() {
  9014. state = {}
  9015. // Only do this if at top level...
  9016. state.color_argument = BASE_COLOR_ARG;
  9017. var tmp = current_style.argify(state);
  9018. pp_is_url++;
  9019. tmp = tmp.pp();
  9020. pp_is_url--;
  9021. SetTo(tmp);
  9022. }
  9023.  
  9024. function AddTab(tab, name, contents) {
  9025. FIND("TABLINKS").innerHTML += "<button id="+tab+"_tab class=tablinks onclick=\"ActivateTab('"+tab+"')\">" + name + "</button>";
  9026. FIND("TABBODIES").innerHTML += "<div id="+tab+"_tabcontent class=tabcontent></div>";
  9027. if (contents) {
  9028. AddTabContent(tab, contents);
  9029. }
  9030. }
  9031.  
  9032. function AddTabContent(tab, data) {
  9033. FIND(tab + "_tabcontent").innerHTML += data;
  9034. }
  9035.  
  9036. function ActivateTab(tab) {
  9037. if(!FIND(tab+"_tab")) {
  9038. console.log("No such tab");
  9039. return;
  9040. }
  9041. // Get all elements with class="tabcontent" and hide them
  9042. var tabcontent = document.getElementsByClassName("tabcontent");
  9043. for (var i = 0; i < tabcontent.length; i++) {
  9044. tabcontent[i].style.display = "none";
  9045. }
  9046.  
  9047. // Get all elements with class="tablinks" and remove the class "active"
  9048. var tablinks = document.getElementsByClassName("tablinks");
  9049. for (var i = 0; i < tablinks.length; i++) {
  9050. tablinks[i].className = tablinks[i].className.replace(" active", "");
  9051. }
  9052.  
  9053. // Show the current tab, and add an "active" class to the button that opened the tab
  9054. FIND(tab+"_tabcontent").style.display = "block";
  9055. FIND(tab+"_tab").className += " active";
  9056. }
  9057.  
  9058.  
  9059. </script>
  9060. </head>
  9061. <!-- /**************************************** tooltips */
  9062. -->
  9063.  
  9064. <body onload="initGL()">
  9065.  
  9066. <table>
  9067. <tr>
  9068. <td>
  9069. <canvas id="canvas_id" width="256" height="256" class="canvas-style" onmousemove='mouse_move(event)' onmouseleave='mouse_leave(event)' onclick='AddClash()'> </canvas>
  9070. <br>
  9071. <input id=POWER_BUTTON name=on type=button value="Power" onclick="ClickPower();" >
  9072. <input name=clash type=button value="Clash" onclick="AddClash();" >
  9073. <input name=stab type=button value="Stab" onclick="AddStab();" >
  9074. <input name=blast type=button value="Blast" onclick="AddBlast()"; >
  9075. <input name=force type=button value="Force" onclick="AddForce()"; >
  9076. <input name=boot type=button value="Boot" onclick="AddBoot()"; >
  9077. <input name=newfont type=button value="NewFont" onclick="AddNewfont()"; >
  9078. <input name=preon type=button value="Preon" onclick="AddPreon()"; >
  9079.  
  9080. <select name=lockup id=LOCKUP onchange='OnLockupChange()'>
  9081. <option value=LOCKUP_NONE>No lockup</option>
  9082. <option value=LOCKUP_NORMAL>Lockup</option>
  9083. <option value=LOCKUP_DRAG>Drag</option>
  9084. <option value=LOCKUP_MELT>Melt</option>
  9085. <option value=LOCKUP_LIGHTNING_BLOCK>LB</option>
  9086. </select>
  9087.  
  9088. <span style="white-space:nowrap">
  9089. <select id="more_effects_menu">
  9090. <option>Select more effects</option>
  9091. </select>
  9092. <button id="do-selected">Do Selected</button>
  9093. </span>
  9094.  
  9095. <script>
  9096.  
  9097. // Get the menu and button elements
  9098. const menu = document.getElementById('more_effects_menu');
  9099. const button = document.getElementById('do-selected');
  9100.  
  9101. // Create a dictionary to store actions for each item
  9102. const actions = {};
  9103.  
  9104. // Add values from the enum builder to an array and sort alphabetically
  9105. const values = Object.entries(EFFECT_ENUM_BUILDER.value_to_name)
  9106. .sort((a, b) => a[1].localeCompare(b[1]))
  9107. .filter(([value]) => ![
  9108. EFFECT_CLASH,
  9109. EFFECT_STAB,
  9110. EFFECT_BLAST,
  9111. EFFECT_FORCE,
  9112. EFFECT_BOOT,
  9113. EFFECT_NEWFONT,
  9114. EFFECT_PREON,
  9115. // EFFECT_ERROR_IN_BLADE_ARRAY, /**************************************** Remove unneeded EFFECT_Errror msgs */
  9116. // EFFECT_ERROR_IN_FONT_DIRECTORY,
  9117. // EFFECT_FONT_DIRECTORY_NOT_FOUND,
  9118. // EFFECT_SD_CARD_NOT_FOUND
  9119. ].includes(Number(value)));
  9120.  
  9121. // Add sub-groups for the different categories of effects
  9122. const generalEffectsMenu = document.createElement('optgroup');
  9123. generalEffectsMenu.label = 'General Effects';
  9124. const userEffectsMenu = document.createElement('optgroup');
  9125. userEffectsMenu.label = 'User Effects';
  9126. const blasterEffectsMenu = document.createElement('optgroup');
  9127. blasterEffectsMenu.label = 'Blaster Effects';
  9128. const gameEffectsMenu = document.createElement('optgroup');
  9129. gameEffectsMenu.label = 'Game Effects';
  9130.  
  9131. // Add sorted values to the menu and actions dictionary,
  9132. // excluding effects with dedicated buttons and error msgs.
  9133. for (const [value, name] of values) {
  9134. const nameWithoutEffect = name.replace(/^EFFECT_/, '');
  9135. const option = document.createElement('option');
  9136. option.value = value;
  9137. option.text = nameWithoutEffect;
  9138.  
  9139. // Check if the effect belongs to a certain category and add it to the corresponding sub-group
  9140. if (name.startsWith('EFFECT_GAME')) {
  9141. gameEffectsMenu.appendChild(option);
  9142. } else if (name.startsWith('EFFECT_USER')) {
  9143. userEffectsMenu.appendChild(option);
  9144. } else if ([
  9145. EFFECT_STUN,
  9146. EFFECT_FIRE,
  9147. EFFECT_CLIP_IN,
  9148. EFFECT_CLIP_OUT,
  9149. EFFECT_RELOAD,
  9150. EFFECT_MODE,
  9151. EFFECT_RANGE,
  9152. EFFECT_EMPTY,
  9153. EFFECT_FULL,
  9154. EFFECT_JAM,
  9155. EFFECT_UNJAM,
  9156. EFFECT_PLI_ON,
  9157. EFFECT_PLI_OFF
  9158. ].includes(Number(value))) {
  9159. blasterEffectsMenu.appendChild(option);
  9160. } else {
  9161. generalEffectsMenu.appendChild(option);
  9162. }
  9163. actions[value] = function() { blade.addEffect(value, 0.0) };
  9164. }
  9165.  
  9166. // Add the sub-groups to the main menu
  9167. menu.appendChild(generalEffectsMenu);
  9168. menu.appendChild(userEffectsMenu);
  9169. menu.appendChild(blasterEffectsMenu);
  9170. menu.appendChild(gameEffectsMenu);
  9171.  
  9172. // Set up the event listener for the menu
  9173. menu.addEventListener('change', function() {
  9174. // Get the selected option value
  9175. const value = menu.value;
  9176.  
  9177. // If the selected value is not the default, enable the button and set its action
  9178. if (value !== '') {
  9179. button.disabled = false;
  9180. button.onclick = actions[value];
  9181. } else {
  9182. // If the selected value is the default, disable the button
  9183. button.disabled = true;
  9184. button.onclick = null;
  9185. }
  9186. });
  9187.  
  9188.  
  9189. function toggleSettings() {
  9190. var settingsButton = document.getElementById("SETTINGS_BUTTON");
  9191. var settingsPanel = document.getElementById("settings-panel");
  9192.  
  9193. // Get button position
  9194. var buttonRect = settingsButton.getBoundingClientRect();
  9195. var buttonLeft = buttonRect.left + window.scrollX;
  9196. var buttonTop = buttonRect.top + window.scrollY;
  9197. var buttonWidth = buttonRect.width;
  9198.  
  9199. // Set panel position based on button position
  9200. settingsPanel.style.left = buttonLeft + buttonWidth + 20 + "px";
  9201. settingsPanel.style.top = buttonTop - 10 + "px";
  9202.  
  9203. settingsPanel.classList.toggle("show");
  9204.  
  9205. // Add mouseout event listener
  9206. if (settingsPanel.classList.contains("show")) {
  9207. settingsPanel.addEventListener("mouseout", function(e) {
  9208. if (!e.relatedTarget || !settingsPanel.contains(e.relatedTarget)) {
  9209. settingsPanel.classList.remove("show");
  9210. }
  9211. });
  9212. }
  9213. }
  9214. </script>
  9215.  
  9216. <span style="white-space:nowrap">
  9217. <div class="variant-container">
  9218. <span class="variant-label">Variant:</span>
  9219. <div class="variant-controls">
  9220. <input id="VARIANT_MINUS" name="varminus" type="button" value="<" onmousedown="startAdjustingValue(-1, 'VARIANT_SLIDER')" onmouseup="stopAdjustingValue()" onmouseleave="stopAdjustingValue()" >
  9221. <input id="VARIANT_SLIDER" name="varslider" type="range" class="variant-slider" min="0" max="32768" step="1" value="0" oninput="updateVariantValue(this.value)" >
  9222. <input id="VARIANT_VALUE" name="varvalue" type="input" size="6" value="0" oninput="updateVariantValue(this.value)">
  9223. <input id="VARIANT_PLUS" name="varplus" type="button" value=">" onmousedown="startAdjustingValue(1, 'VARIANT_SLIDER')" onmouseup="stopAdjustingValue()" onmouseleave="stopAdjustingValue()" >
  9224. </div>
  9225. </div>
  9226. <div class="alt-container">
  9227. <span class="alt-label">Alt:</span>
  9228. <div class="alt-controls">
  9229. <input id="ALT_MINUS" name="altminus" type="button" value="<" onclick="IncreaseAlt(-1)" >
  9230. <input id="ALT" name="alt" type="input" size="3" value="0" >
  9231. <input id="ALT_PLUS" name="altplus" type="button" value=">" onclick="IncreaseAlt(1)" >
  9232. </div>
  9233. </div>
  9234. </span>
  9235. <!-- /**************************************** Dark Mode */
  9236. -->
  9237. <span id="error_message"></span>
  9238.  
  9239. <br>
  9240. <div class="tooltip">
  9241. <pre><textarea rows=10 cols=80 id=style wrap=off></textarea></pre>
  9242. <span class="tooltiptext tooltiptext-textarea hidden">Style and value editing area. Edits in here are committed but clicking the Submit button below.</span>
  9243. </div><br>
  9244. <!-- /**************************************** tooltip */
  9245. -->
  9246. <div class="tooltip">
  9247. <input type='button' name='run' value='Submit' onclick='Run()'>
  9248. <span class="tooltiptext tooltiptext-submit hidden">Submit what is currently in the text box above.</span>
  9249. </div>
  9250. <div class="tooltip">
  9251. <input type='button' name='copy' value='Copy' onclick='Copy()'>
  9252. <span class="tooltiptext tooltiptext-copy hidden">Adds StylePtr&lt;&gt;() wrapper and copies the style to the clipboard.</span>
  9253. </div>
  9254. <div class="tooltip">
  9255. <input type=button name='expand' value="Expand" id='expand_button' onclick="DoExpand()">
  9256. <span class="tooltiptext tooltiptext-expand hidden">Reveals the "under the hood" code that the shorthand macro uses. This allows access to otherwise omitted arguments, and is only an active button when applicable.</span>
  9257. </div>
  9258. <div class="tooltip">
  9259. <input type=button name='layerize' value="Layerize" id='layerize_button' onclick="DoLayerize()">
  9260. <span class="tooltiptext tooltiptext-layerize hidden">Transforms nested version style code and breaks it out into more contemporary Layers format.</span>
  9261. </div>
  9262. <div class="tooltip">
  9263. <input type=button name='argify' value="Argify" id='argify_button' onclick="DoArgify()">
  9264. <span class="tooltiptext tooltiptext-argify hidden">Converts arguments to their ARG version counterparts for use with ProffieOS Workbench or Edit Mode. See the "ArgString" tab below.</span>
  9265. </div>
  9266. <div class="tooltip">
  9267. <input id=ROTATE_BUTTON name=rotate type=button value="Rotate" onclick="ClickRotate()" >
  9268. <span class="tooltiptext tooltiptext-rotate hidden">Toggles animation of the preview blade above.</span>
  9269. </div>
  9270. <div class="tooltip">
  9271. <input id=INHILT_BUTTON name=inhilt type=button value="Inhilt" onclick="ClickInhilt()" >
  9272. <span class="tooltiptext tooltiptext-inhilt hidden">Simulates In-Hilt LED blades, (no addressable pixel effects).</span>
  9273. </div>
  9274. <div class="tooltip">
  9275. <input id=SLOW_BUTTON name=inhilt type=button value="Slow" onclick="ClickSlow()" >
  9276. <span class="tooltiptext tooltiptext-slow hidden">Provides "snapshots" of rapidly moving things to see what they look like without fast movement.</span>
  9277. </div>
  9278. <div class="tooltip">
  9279. <input id="SETTINGS_BUTTON" name="settings" type="button" value="Settings" onclick="toggleSettings()">
  9280. <span class="tooltiptext tooltiptext-settings hidden">Contains page display options. These use cookies to save settings between browser sessions.</span>
  9281. </div>
  9282. <div id="settings-panel">
  9283. <div class="tooltip">
  9284. <input id="STILL_BUTTON" name="still" type="button" value="Still" onclick="ClickStill()">
  9285. <span class="tooltiptext tooltiptext-still hidden">Toggles the option for swinging the preview blade above around using mouse control.</span>
  9286. </div>
  9287. <div class="tooltip">
  9288. <input id="DARK_BUTTON" name="dark" type="button" value="DarkMode" onclick="ClickDark()">
  9289. <span class="tooltiptext tooltiptext-dark hidden">Toggles a Dark Mode look to this page.</span>
  9290. </div>
  9291. <div class="tooltip">
  9292. <input id="TIPS_BUTTON" name="tips" type="button" value="ToolTips" onclick="ClickTips()">
  9293. <span class="tooltiptext tooltiptext-tips hidden">Toggles these tool tips on or off.</span>
  9294. </div>
  9295. </div><br>
  9296. <!-- /**************************************** tooltip */
  9297. -->
  9298. <div id=TABS>
  9299. <div id=TABLINKS class=tab></div>
  9300. <div id=TABBODIES class=tabcontainer></div>
  9301. </div>
  9302.  
  9303.  
  9304. <!--
  9305. <div id=effect_links class=MAGIC_CLASS_COLOR></div>
  9306. <div id=color_links class=MAGIC_CLASS_COLOR></div>
  9307. <div id=transition_links class=MAGIC_INVISIBLE_CLASS_TRANSITION></div>
  9308. <div id=function_links class=MAGIC_INVISIBLE_CLASS_FUNCTION></div>
  9309. <div id=effect_type_links class=MAGIC_INVISIBLE_CLASS_EFFECT></div>
  9310. <div id=template_links class=MAGIC_CLASS_COLOR></div>
  9311. <b>History:</b><div id=history_links></div>
  9312. -->
  9313.  
  9314. <!-- accessed N times since D. Lat modified D .....not working anyway -->
  9315. <!-- <div>
  9316. <font face="helvetica,arial" size=-1>
  9317. This page has been accessed <accessed type=comma_grouped> times since
  9318. <accessed since part=month type=string>
  9319. <accessed since part=date type=ordered>,
  9320. <accessed since part=year>.<br>
  9321. Last modified:
  9322. <modified part=month type=string>
  9323. <modified part=date type=ordered>,
  9324. <modified part=year>
  9325. </div> -->
  9326. </td>
  9327. <td>
  9328. <div id="structured-view">
  9329. <b>Structured view, click to edit</b>
  9330. <div id=pp></div>
  9331. </div>
  9332. </td>
  9333. </tr>
  9334. </table>
  9335. </body>
  9336. </html>
  9337.  
Add Comment
Please, Sign In to add comment