NoSloppy

style_editor_GPT

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