diff --git "a/bundle.js" "b/bundle.js" --- "a/bundle.js" +++ "b/bundle.js" @@ -3,8 +3,8 @@ var app = (function () { 'use strict'; - function noop() { } - function assign(tar, src) { + function noop$2() { } + function assign$3(tar, src) { // @ts-ignore for (const k in src) tar[k] = src[k]; @@ -48,11 +48,16 @@ var app = (function () { } function subscribe(store, ...callbacks) { if (store == null) { - return noop; + return noop$2; } const unsub = store.subscribe(...callbacks); return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub; } + function get_store_value(store) { + let value; + subscribe(store, _ => value = _)(); + return value; + } function component_subscribe(component, store, callback) { component.$$.on_destroy.push(subscribe(store, callback)); } @@ -64,7 +69,7 @@ var app = (function () { } function get_slot_context(definition, ctx, $$scope, fn) { return definition[1] && fn - ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) + ? assign$3($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx; } function get_slot_changes(definition, $$scope, dirty, fn) { @@ -132,7 +137,7 @@ var app = (function () { iterations[i].d(detaching); } } - function element(name) { + function element$1(name) { return document.createElement(name); } function text(data) { @@ -558,7 +563,7 @@ var app = (function () { ctx: [], // state props, - update: noop, + update: noop$2, not_equal, bound: blank_object(), // lifecycle @@ -617,11 +622,11 @@ var app = (function () { class SvelteComponent { $destroy() { destroy_component(this, 1); - this.$destroy = noop; + this.$destroy = noop$2; } $on(type, callback) { if (!is_function(callback)) { - return noop; + return noop$2; } const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = [])); callbacks.push(callback); @@ -726,34 +731,34 @@ var app = (function () { /* src\VideoGradioComponentBrainstorming.svelte generated by Svelte v3.59.2 */ - const { console: console_1$e } = globals; - const file$t = "src\\VideoGradioComponentBrainstorming.svelte"; + const { console: console_1$g } = globals; + const file$y = "src\\VideoGradioComponentBrainstorming.svelte"; - function get_each_context$j(ctx, list, i) { + function get_each_context$o(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[15] = list[i]; return child_ctx; } // (85:4) {#each kitchenOptions as option} - function create_each_block$j(ctx) { + function create_each_block$o(ctx) { let option; let t_value = /*option*/ ctx[15] + ""; let t; const block = { c: function create() { - option = element("option"); + option = element$1("option"); t = text(t_value); option.__value = /*option*/ ctx[15]; option.value = option.__value; - add_location(option, file$t, 85, 6, 2561); + add_location(option, file$y, 85, 6, 2561); }, m: function mount(target, anchor) { insert_dev(target, option, anchor); append_dev(option, t); }, - p: noop, + p: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(option); } @@ -761,7 +766,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$j.name, + id: create_each_block$o.name, type: "each", source: "(85:4) {#each kitchenOptions as option}", ctx @@ -770,7 +775,7 @@ var app = (function () { return block; } - function create_fragment$t(ctx) { + function create_fragment$y(ctx) { let h1; let t1; let div1; @@ -797,64 +802,64 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$j(get_each_context$j(ctx, each_value, i)); + each_blocks[i] = create_each_block$o(get_each_context$o(ctx, each_value, i)); } const block = { c: function create() { - h1 = element("h1"); + h1 = element$1("h1"); h1.textContent = "AI Vision Assistant - Auto prompt HF agent + Cohere + Object detection - Text write on screen test"; t1 = space(); - div1 = element("div"); - video = element("video"); - track = element("track"); + div1 = element$1("div"); + video = element$1("video"); + track = element$1("track"); t2 = space(); - div0 = element("div"); + div0 = element$1("div"); t3 = text("Text Overlay Test and "); t4 = text(/*TestVerb*/ ctx[3]); t5 = space(); - canvas_1 = element("canvas"); + canvas_1 = element$1("canvas"); t6 = space(); - input = element("input"); + input = element$1("input"); t7 = space(); - div2 = element("div"); - button = element("button"); + div2 = element$1("div"); + button = element$1("button"); button.textContent = "Verb Test"; t9 = space(); - select = element("select"); + select = element$1("select"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h1, file$t, 66, 0, 1800); + add_location(h1, file$y, 66, 0, 1800); attr_dev(track, "kind", "captions"); if (!src_url_equal(track.src, track_src_value = "path/to/your/captions/file.vtt")) attr_dev(track, "src", track_src_value); attr_dev(track, "srclang", "en"); attr_dev(track, "label", "English"); - add_location(track, file$t, 72, 4, 2006); + add_location(track, file$y, 72, 4, 2006); attr_dev(video, "id", "videoCanvas"); video.autoplay = true; attr_dev(video, "class", "svelte-ufd3fo"); - add_location(video, file$t, 70, 2, 1965); + add_location(video, file$y, 70, 2, 1965); attr_dev(div0, "id", "overlayText"); attr_dev(div0, "class", "svelte-ufd3fo"); - add_location(div0, file$t, 74, 2, 2111); + add_location(div0, file$y, 74, 2, 2111); attr_dev(div1, "id", "videoContainer"); attr_dev(div1, "class", "svelte-ufd3fo"); - add_location(div1, file$t, 68, 0, 1911); + add_location(div1, file$y, 68, 0, 1911); attr_dev(canvas_1, "id", "myCanvas"); set_style(canvas_1, "border", "2px solid black"); attr_dev(canvas_1, "width", "500"); attr_dev(canvas_1, "height", "500"); - add_location(canvas_1, file$t, 77, 0, 2186); + add_location(canvas_1, file$y, 77, 0, 2186); attr_dev(input, "type", "text"); - add_location(input, file$t, 78, 0, 2294); - add_location(button, file$t, 82, 2, 2429); + add_location(input, file$y, 78, 0, 2294); + add_location(button, file$y, 82, 2, 2429); if (/*selectedOption*/ ctx[0] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[9].call(select)); - add_location(select, file$t, 83, 2, 2479); + add_location(select, file$y, 83, 2, 2479); attr_dev(div2, "id", "frameForButtons"); - add_location(div2, file$t, 81, 0, 2399); + add_location(div2, file$y, 81, 0, 2399); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -913,12 +918,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$j(ctx, each_value, i); + const child_ctx = get_each_context$o(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$j(child_ctx); + each_blocks[i] = create_each_block$o(child_ctx); each_blocks[i].c(); each_blocks[i].m(select, null); } @@ -935,8 +940,8 @@ var app = (function () { select_option(select, /*selectedOption*/ ctx[0]); } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(h1); if (detaching) detach_dev(t1); @@ -956,7 +961,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$t.name, + id: create_fragment$y.name, type: "component", source: "", ctx @@ -969,7 +974,7 @@ var app = (function () { } // Logic for 'Test OCR' button - function instance$t($$self, $$props, $$invalidate) { + function instance$y($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('VideoGradioComponentBrainstorming', slots, []); let selectedOption = 'Stove - lu'; // default value @@ -1031,7 +1036,7 @@ var app = (function () { const writable_props = []; Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$e.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$g.warn(` was created with unknown prop '${key}'`); }); function canvas_1_binding($$value) { @@ -1102,13 +1107,13 @@ var app = (function () { class VideoGradioComponentBrainstorming extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$t, create_fragment$t, safe_not_equal, {}); + init(this, options, instance$y, create_fragment$y, safe_not_equal, {}); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "VideoGradioComponentBrainstorming", options, - id: create_fragment$t.name + id: create_fragment$y.name }); } } @@ -1119,7 +1124,7 @@ var app = (function () { * @param {*=}value initial value * @param {StartStopNotifier=} start */ - function writable(value, start = noop) { + function writable(value, start = noop$2) { let stop; const subscribers = new Set(); function set(new_value) { @@ -1143,11 +1148,11 @@ var app = (function () { function update(fn) { set(fn(value)); } - function subscribe(run, invalidate = noop) { + function subscribe(run, invalidate = noop$2) { const subscriber = [run, invalidate]; subscribers.add(subscriber); if (subscribers.size === 1) { - stop = start(set) || noop; + stop = start(set) || noop$2; } run(value); return () => { @@ -1162,19 +1167,19 @@ var app = (function () { } /* src\MovingDotPortfromReact.svelte generated by Svelte v3.59.2 */ - const file$s = "src\\MovingDotPortfromReact.svelte"; + const file$x = "src\\MovingDotPortfromReact.svelte"; - function create_fragment$s(ctx) { + function create_fragment$x(ctx) { let button; const block = { c: function create() { - button = element("button"); + button = element$1("button"); attr_dev(button, "class", "MovingDot svelte-1mg0qyd"); set_style(button, "left", /*position*/ ctx[0].x + "px"); set_style(button, "top", /*position*/ ctx[0].y + "px"); attr_dev(button, "tabindex", "0"); - add_location(button, file$s, 48, 0, 1573); + add_location(button, file$x, 48, 0, 1573); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -1192,8 +1197,8 @@ var app = (function () { set_style(button, "top", /*position*/ ctx[0].y + "px"); } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(button); /*button_binding*/ ctx[4](null); @@ -1202,7 +1207,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$s.name, + id: create_fragment$x.name, type: "component", source: "", ctx @@ -1211,9 +1216,9 @@ var app = (function () { return block; } - const step = 10; + const step$2 = 10; - function instance$s($$self, $$props, $$invalidate) { + function instance$x($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('MovingDotPortfromReact', slots, []); let { position = { x: 0, y: 0 } } = $$props; @@ -1241,16 +1246,16 @@ var app = (function () { switch (e.key) { case 'ArrowLeft': - newX -= step; + newX -= step$2; break; case 'ArrowRight': - newX += step; + newX += step$2; break; case 'ArrowUp': - newY -= step; + newY -= step$2; break; case 'ArrowDown': - newY += step; + newY += step$2; break; } @@ -1294,7 +1299,7 @@ var app = (function () { createEventDispatcher, position, boundaries, - step, + step: step$2, dispatch, dotElement, moveDot, @@ -1318,13 +1323,13 @@ var app = (function () { class MovingDotPortfromReact extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$s, create_fragment$s, safe_not_equal, { position: 0, boundaries: 2, focusDot: 3 }); + init(this, options, instance$x, create_fragment$x, safe_not_equal, { position: 0, boundaries: 2, focusDot: 3 }); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "MovingDotPortfromReact", options, - id: create_fragment$s.name + id: create_fragment$x.name }); } @@ -1355,18 +1360,18 @@ var app = (function () { /* src\MovingDotTargetPortfromReact.svelte generated by Svelte v3.59.2 */ - const file$r = "src\\MovingDotTargetPortfromReact.svelte"; + const file$w = "src\\MovingDotTargetPortfromReact.svelte"; - function create_fragment$r(ctx) { + function create_fragment$w(ctx) { let div; const block = { c: function create() { - div = element("div"); - attr_dev(div, "class", "target svelte-4yc66h"); + div = element$1("div"); + attr_dev(div, "class", "target svelte-100j21r"); set_style(div, "left", /*position*/ ctx[0].x + "px"); set_style(div, "top", /*position*/ ctx[0].y + "px"); - add_location(div, file$r, 4, 0, 49); + add_location(div, file$w, 4, 0, 49); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -1383,8 +1388,8 @@ var app = (function () { set_style(div, "top", /*position*/ ctx[0].y + "px"); } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(div); } @@ -1392,7 +1397,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$r.name, + id: create_fragment$w.name, type: "component", source: "", ctx @@ -1401,7 +1406,7 @@ var app = (function () { return block; } - function instance$r($$self, $$props, $$invalidate) { + function instance$w($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('MovingDotTargetPortfromReact', slots, []); let { position } = $$props; @@ -1438,13 +1443,13 @@ var app = (function () { class MovingDotTargetPortfromReact extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$r, create_fragment$r, safe_not_equal, { position: 0 }); + init(this, options, instance$w, create_fragment$w, safe_not_equal, { position: 0 }); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "MovingDotTargetPortfromReact", options, - id: create_fragment$r.name + id: create_fragment$w.name }); } @@ -1459,17 +1464,17 @@ var app = (function () { /* src\MovingDotSpaceSimpleModal.svelte generated by Svelte v3.59.2 */ - const { console: console_1$d } = globals; - const file$q = "src\\MovingDotSpaceSimpleModal.svelte"; + const { console: console_1$f } = globals; + const file$v = "src\\MovingDotSpaceSimpleModal.svelte"; - function get_each_context$i(ctx, list, i) { + function get_each_context$n(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[10] = list[i]; return child_ctx; } // (34:0) {#if isOpen} - function create_if_block$f(ctx) { + function create_if_block$i(ctx) { let div3; let div2; let div0; @@ -1489,41 +1494,41 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$i(get_each_context$i(ctx, each_value, i)); + each_blocks[i] = create_each_block$n(get_each_context$n(ctx, each_value, i)); } const block = { c: function create() { - div3 = element("div"); - div2 = element("div"); - div0 = element("div"); - h2 = element("h2"); + div3 = element$1("div"); + div2 = element$1("div"); + div0 = element$1("div"); + h2 = element$1("h2"); t0 = text(/*title*/ ctx[1]); t1 = space(); - button = element("button"); + button = element$1("button"); button.textContent = "×"; t3 = space(); - div1 = element("div"); + div1 = element$1("div"); t4 = text(/*content*/ ctx[2]); t5 = space(); - ul = element("ul"); + ul = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h2, file$q, 37, 8, 1159); - add_location(button, file$q, 38, 8, 1185); + add_location(h2, file$v, 37, 8, 1159); + add_location(button, file$v, 38, 8, 1185); attr_dev(div0, "class", "modal-header svelte-m51ous"); - add_location(div0, file$q, 36, 6, 1123); + add_location(div0, file$v, 36, 6, 1123); attr_dev(ul, "class", "modal-items"); - add_location(ul, file$q, 42, 8, 1309); + add_location(ul, file$v, 42, 8, 1309); attr_dev(div1, "class", "modal-content svelte-m51ous"); - add_location(div1, file$q, 40, 6, 1253); + add_location(div1, file$v, 40, 6, 1253); attr_dev(div2, "class", "modal svelte-m51ous"); - add_location(div2, file$q, 35, 4, 1096); + add_location(div2, file$v, 35, 4, 1096); attr_dev(div3, "class", "modal-overlay svelte-m51ous"); - add_location(div3, file$q, 34, 2, 1063); + add_location(div3, file$v, 34, 2, 1063); }, m: function mount(target, anchor) { insert_dev(target, div3, anchor); @@ -1560,12 +1565,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$i(ctx, each_value, i); + const child_ctx = get_each_context$n(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$i(child_ctx); + each_blocks[i] = create_each_block$n(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul, null); } @@ -1588,7 +1593,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$f.name, + id: create_if_block$i.name, type: "if", source: "(34:0) {#if isOpen}", ctx @@ -1598,7 +1603,7 @@ var app = (function () { } // (44:10) {#each items as item} - function create_each_block$i(ctx) { + function create_each_block$n(ctx) { let button; let t_value = /*item*/ ctx[10].label + ""; let t; @@ -1611,9 +1616,9 @@ var app = (function () { const block = { c: function create() { - button = element("button"); + button = element$1("button"); t = text(t_value); - add_location(button, file$q, 44, 12, 1380); + add_location(button, file$v, 44, 12, 1380); }, m: function mount(target, anchor) { insert_dev(target, button, anchor); @@ -1637,7 +1642,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$i.name, + id: create_each_block$n.name, type: "each", source: "(44:10) {#each items as item}", ctx @@ -1646,9 +1651,9 @@ var app = (function () { return block; } - function create_fragment$q(ctx) { + function create_fragment$v(ctx) { let if_block_anchor; - let if_block = /*isOpen*/ ctx[0] && create_if_block$f(ctx); + let if_block = /*isOpen*/ ctx[0] && create_if_block$i(ctx); const block = { c: function create() { @@ -1667,7 +1672,7 @@ var app = (function () { if (if_block) { if_block.p(ctx, dirty); } else { - if_block = create_if_block$f(ctx); + if_block = create_if_block$i(ctx); if_block.c(); if_block.m(if_block_anchor.parentNode, if_block_anchor); } @@ -1676,8 +1681,8 @@ var app = (function () { if_block = null; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (if_block) if_block.d(detaching); if (detaching) detach_dev(if_block_anchor); @@ -1686,7 +1691,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$q.name, + id: create_fragment$v.name, type: "component", source: "", ctx @@ -1695,7 +1700,7 @@ var app = (function () { return block; } - function instance$q($$self, $$props, $$invalidate) { + function instance$v($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('MovingDotSpaceSimpleModal', slots, []); let { isOpen = false } = $$props; @@ -1730,11 +1735,11 @@ var app = (function () { $$self.$$.on_mount.push(function () { if (onClose === undefined && !('onClose' in $$props || $$self.$$.bound[$$self.$$.props['onClose']])) { - console_1$d.warn(" was created without expected prop 'onClose'"); + console_1$f.warn(" was created without expected prop 'onClose'"); } if (themeActions === undefined && !('themeActions' in $$props || $$self.$$.bound[$$self.$$.props['themeActions']])) { - console_1$d.warn(" was created without expected prop 'themeActions'"); + console_1$f.warn(" was created without expected prop 'themeActions'"); } }); @@ -1749,7 +1754,7 @@ var app = (function () { ]; Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$d.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$f.warn(` was created with unknown prop '${key}'`); }); const click_handler = item => handleItemClick(item); @@ -1808,7 +1813,7 @@ var app = (function () { constructor(options) { super(options); - init(this, options, instance$q, create_fragment$q, safe_not_equal, { + init(this, options, instance$v, create_fragment$v, safe_not_equal, { isOpen: 0, title: 1, content: 2, @@ -1822,7 +1827,7 @@ var app = (function () { component: this, tagName: "MovingDotSpaceSimpleModal", options, - id: create_fragment$q.name + id: create_fragment$v.name }); } @@ -1899,6 +1904,9 @@ var app = (function () { const fightplayerHuman = createfightPlayer(); const fightplayerComputer = createfightPlayer(); const fightcurrentTurn = writable('human'); // 'human' or 'computer' + const themedfightplayerHuman = createfightPlayer(); + const themedfightplayerComputer = createfightPlayer(); + const themedfightcurrentTurn = writable('human'); // 'human' or 'computer' const themeactions = writable({}); const autogenconfigtest = writable({ background: '/AutoGameBackgrounds/theme_background.png', @@ -1916,6 +1924,34 @@ var app = (function () { actions: [], }); + const autogenconfigtestsmmdoalfromgraph = writable({ + background: '/AutoGameBackgrounds/theme_background.png', + inventory: [ + { type: "weapon", name: "Random waepon", description: "A powerful weapon." }, + // ... more space items + ], + skills: [ + { branch: "Skill Group 1", name: "Skill One", learned: false }, + // ... more space skills + ], + persistentTargets: [ + { name: "Background Target 1", x: 500, y: 500, collisionType: "alert", collisiontext: "First Test"}, + ], + actions: [], + story: [ + { + part: 0, + objectives: [], + targets: [ + { name: "Target 1", x: 50, y: 50, collisionType: "alert", collisiontext: "First Test", + subtargets: [ + { name: "Target 1 sub 1", x: 100, y: 75, collisionType: "alert", collisiontext: "First Test in Sub of First Test"} , + ], + }], + }, + ], + }); + function createfightPlayer() { return writable({ fighthealth: 100, @@ -1987,17 +2023,17 @@ var app = (function () { /* src\SimpleStateMachineModal.svelte generated by Svelte v3.59.2 */ - const { console: console_1$c } = globals; - const file$p = "src\\SimpleStateMachineModal.svelte"; + const { Error: Error_1, Object: Object_1$7, console: console_1$e } = globals; + const file$u = "src\\SimpleStateMachineModal.svelte"; - function get_each_context$h(ctx, list, i) { + function get_each_context$m(ctx, list, i) { const child_ctx = ctx.slice(); - child_ctx[14] = list[i]; + child_ctx[17] = list[i]; return child_ctx; } - // (64:0) {#if isOpen} - function create_if_block$e(ctx) { + // (85:0) {#if isOpen} + function create_if_block$h(ctx) { let div3; let div2; let div0; @@ -2010,6 +2046,7 @@ var app = (function () { let t4; let t5; let ul; + let t6; let mounted; let dispose; let each_value = /*items*/ ctx[3]; @@ -2017,41 +2054,45 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$h(get_each_context$h(ctx, each_value, i)); + each_blocks[i] = create_each_block$m(get_each_context$m(ctx, each_value, i)); } + let if_block = /*modalimg*/ ctx[4] && create_if_block_1$8(ctx); + const block = { c: function create() { - div3 = element("div"); - div2 = element("div"); - div0 = element("div"); - h2 = element("h2"); + div3 = element$1("div"); + div2 = element$1("div"); + div0 = element$1("div"); + h2 = element$1("h2"); t0 = text(/*title*/ ctx[1]); t1 = space(); - button = element("button"); + button = element$1("button"); button.textContent = "×"; t3 = space(); - div1 = element("div"); + div1 = element$1("div"); t4 = text(/*content*/ ctx[2]); t5 = space(); - ul = element("ul"); + ul = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h2, file$p, 67, 12, 2262); - add_location(button, file$p, 68, 12, 2292); + t6 = space(); + if (if_block) if_block.c(); + add_location(h2, file$u, 88, 10, 3296); + add_location(button, file$u, 89, 10, 3324); attr_dev(div0, "class", "modal-header svelte-13fuaz8"); - add_location(div0, file$p, 66, 8, 2222); + add_location(div0, file$u, 87, 6, 3258); attr_dev(ul, "class", "modal-items"); - add_location(ul, file$p, 72, 12, 2428); + add_location(ul, file$u, 93, 10, 3452); attr_dev(div1, "class", "modal-content svelte-13fuaz8"); - add_location(div1, file$p, 70, 8, 2364); + add_location(div1, file$u, 91, 6, 3392); attr_dev(div2, "class", "modal svelte-13fuaz8"); - add_location(div2, file$p, 65, 8, 2193); + add_location(div2, file$u, 86, 4, 3231); attr_dev(div3, "class", "modal-overlay svelte-13fuaz8"); - add_location(div3, file$p, 64, 4, 2156); + add_location(div3, file$u, 85, 2, 3198); }, m: function mount(target, anchor) { insert_dev(target, div3, anchor); @@ -2073,8 +2114,11 @@ var app = (function () { } } + append_dev(div1, t6); + if (if_block) if_block.m(div1, null); + if (!mounted) { - dispose = listen_dev(button, "click", /*closeModal*/ ctx[5], false, false, false, false); + dispose = listen_dev(button, "click", /*closeModal*/ ctx[6], false, false, false, false); mounted = true; } }, @@ -2082,18 +2126,18 @@ var app = (function () { if (dirty & /*title*/ 2) set_data_dev(t0, /*title*/ ctx[1]); if (dirty & /*content*/ 4) set_data_dev(t4, /*content*/ ctx[2]); - if (dirty & /*handleItemClick, items*/ 72) { + if (dirty & /*handleItemClick, items*/ 136) { each_value = /*items*/ ctx[3]; validate_each_argument(each_value); let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$h(ctx, each_value, i); + const child_ctx = get_each_context$m(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$h(child_ctx); + each_blocks[i] = create_each_block$m(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul, null); } @@ -2105,10 +2149,24 @@ var app = (function () { each_blocks.length = each_value.length; } + + if (/*modalimg*/ ctx[4]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block_1$8(ctx); + if_block.c(); + if_block.m(div1, null); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } }, d: function destroy(detaching) { if (detaching) detach_dev(div3); destroy_each(each_blocks, detaching); + if (if_block) if_block.d(); mounted = false; dispose(); } @@ -2116,32 +2174,32 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$e.name, + id: create_if_block$h.name, type: "if", - source: "(64:0) {#if isOpen}", + source: "(85:0) {#if isOpen}", ctx }); return block; } - // (74:12) {#each items as item} - function create_each_block$h(ctx) { + // (95:10) {#each items as item} + function create_each_block$m(ctx) { let button; - let t_value = /*item*/ ctx[14].label + ""; + let t_value = /*item*/ ctx[17].label + ""; let t; let mounted; let dispose; function click_handler() { - return /*click_handler*/ ctx[10](/*item*/ ctx[14]); + return /*click_handler*/ ctx[11](/*item*/ ctx[17]); } const block = { c: function create() { - button = element("button"); + button = element$1("button"); t = text(t_value); - add_location(button, file$p, 74, 16, 2505); + add_location(button, file$u, 95, 14, 3525); }, m: function mount(target, anchor) { insert_dev(target, button, anchor); @@ -2154,7 +2212,7 @@ var app = (function () { }, p: function update(new_ctx, dirty) { ctx = new_ctx; - if (dirty & /*items*/ 8 && t_value !== (t_value = /*item*/ ctx[14].label + "")) set_data_dev(t, t_value); + if (dirty & /*items*/ 8 && t_value !== (t_value = /*item*/ ctx[17].label + "")) set_data_dev(t, t_value); }, d: function destroy(detaching) { if (detaching) detach_dev(button); @@ -2165,18 +2223,54 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$h.name, + id: create_each_block$m.name, type: "each", - source: "(74:12) {#each items as item}", + source: "(95:10) {#each items as item}", ctx }); return block; } - function create_fragment$p(ctx) { + // (99:10) {#if modalimg} + function create_if_block_1$8(ctx) { + let img; + let img_src_value; + + const block = { + c: function create() { + img = element$1("img"); + if (!src_url_equal(img.src, img_src_value = /*modalimg*/ ctx[4])) attr_dev(img, "src", img_src_value); + attr_dev(img, "alt", ""); + add_location(img, file$u, 98, 25, 3656); + }, + m: function mount(target, anchor) { + insert_dev(target, img, anchor); + }, + p: function update(ctx, dirty) { + if (dirty & /*modalimg*/ 16 && !src_url_equal(img.src, img_src_value = /*modalimg*/ ctx[4])) { + attr_dev(img, "src", img_src_value); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(img); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_1$8.name, + type: "if", + source: "(99:10) {#if modalimg}", + ctx + }); + + return block; + } + + function create_fragment$u(ctx) { let if_block_anchor; - let if_block = /*isOpen*/ ctx[0] && create_if_block$e(ctx); + let if_block = /*isOpen*/ ctx[0] && create_if_block$h(ctx); const block = { c: function create() { @@ -2184,7 +2278,7 @@ var app = (function () { if_block_anchor = empty(); }, l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + throw new Error_1("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, m: function mount(target, anchor) { if (if_block) if_block.m(target, anchor); @@ -2195,7 +2289,7 @@ var app = (function () { if (if_block) { if_block.p(ctx, dirty); } else { - if_block = create_if_block$e(ctx); + if_block = create_if_block$h(ctx); if_block.c(); if_block.m(if_block_anchor.parentNode, if_block_anchor); } @@ -2204,8 +2298,8 @@ var app = (function () { if_block = null; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (if_block) if_block.d(detaching); if (detaching) detach_dev(if_block_anchor); @@ -2214,7 +2308,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$p.name, + id: create_fragment$u.name, type: "component", source: "", ctx @@ -2223,23 +2317,32 @@ var app = (function () { return block; } - function instance$p($$self, $$props, $$invalidate) { + function instance$u($$self, $$props, $$invalidate) { let $themeactions; let $state; validate_store(themeactions, 'themeactions'); - component_subscribe($$self, themeactions, $$value => $$invalidate(12, $themeactions = $$value)); + component_subscribe($$self, themeactions, $$value => $$invalidate(13, $themeactions = $$value)); let { $$slots: slots = {}, $$scope } = $$props; validate_slots('SimpleStateMachineModal', slots, []); let { modalStates } = $$props; let { isOpen = false } = $$props; - let state = writable("default"); // Manage modal state + + //let state = writable("default"); // Manage modal state + //let title = modalStates.default.title; // Define title + //let content = modalStates.default.content; // Define content + //let items = modalStates.default.items; // Define items + //let consequences = modalStates.default.consequences //modalStates.default.consequences; // Define consequences + const [firstStateKey, firstState] = Object.entries(modalStates)[0] || []; + + let state = writable(firstStateKey); // Manage modal state validate_store(state, 'state'); - component_subscribe($$self, state, value => $$invalidate(9, $state = value)); - let title = modalStates.default.title; // Define title - let content = modalStates.default.content; // Define content - let items = modalStates.default.items; // Define items - let consequences = modalStates.default.consequences; //modalStates.default.consequences; // Define consequences + component_subscribe($$self, state, value => $$invalidate(10, $state = value)); + let title = firstState ? firstState.title : ''; // modalStates.default.title; // Define title + let content = firstState ? firstState.content : ''; // Define content + let items = firstState ? firstState.items : ''; // Define items + let consequences = firstState ? firstState.consequences : ''; //modalStates.default.consequences; // Define consequences let { onClose } = $$props; + let modalimg = firstState ? firstState.modalimg : ''; function closeModal() { if (onClose) { @@ -2260,50 +2363,58 @@ var app = (function () { case 'guidance': case 'forest': console.log("Went to the forest. Leaves were blowing everywhere"); - case 'default': - state.set(item.action); - break; default: - console.log("Action not recognized"); - } + $$invalidate(4, modalimg = ''); + updateModal(item.action); + } //console.log("Action not recognized"); } //Execute the consequences function updateModal(newState) { - $$invalidate(1, title = modalStates[newState].title); - $$invalidate(2, content = modalStates[newState].content); - $$invalidate(3, items = modalStates[newState].items); - consequences = modalStates[newState].consequences; + if (modalStates[newState]) { + $$invalidate(1, title = modalStates[newState].title); + $$invalidate(2, content = modalStates[newState].content); + $$invalidate(3, items = modalStates[newState].items); + consequences = modalStates[newState].consequences; + + //consequences.forEach(func => func()); // Execute each function in consequences + consequences.forEach(consequence => { + if ($themeactions[consequence]) { + $themeactions[consequence](); // Execute consequence functions by name + } - //consequences.forEach(func => func()); // Execute each function in consequences - consequences.forEach(consequence => { - if ($themeactions[consequence]) { - $themeactions[consequence](); // Execute consequence functions by name - } - }); + if (modalStates[newState].modalimg) { + $$invalidate(4, modalimg = modalStates[newState].modalimg); + } else { + $$invalidate(4, modalimg = ''); + } + }); + } else { + throw new Error(`modalStates doesn't have a property with the key "${newState}"`); + } } $$self.$$.on_mount.push(function () { if (modalStates === undefined && !('modalStates' in $$props || $$self.$$.bound[$$self.$$.props['modalStates']])) { - console_1$c.warn(" was created without expected prop 'modalStates'"); + console_1$e.warn(" was created without expected prop 'modalStates'"); } if (onClose === undefined && !('onClose' in $$props || $$self.$$.bound[$$self.$$.props['onClose']])) { - console_1$c.warn(" was created without expected prop 'onClose'"); + console_1$e.warn(" was created without expected prop 'onClose'"); } }); const writable_props = ['modalStates', 'isOpen', 'onClose']; - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$c.warn(` was created with unknown prop '${key}'`); + Object_1$7.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$e.warn(` was created with unknown prop '${key}'`); }); const click_handler = item => handleItemClick(item); $$self.$$set = $$props => { - if ('modalStates' in $$props) $$invalidate(7, modalStates = $$props.modalStates); + if ('modalStates' in $$props) $$invalidate(8, modalStates = $$props.modalStates); if ('isOpen' in $$props) $$invalidate(0, isOpen = $$props.isOpen); - if ('onClose' in $$props) $$invalidate(8, onClose = $$props.onClose); + if ('onClose' in $$props) $$invalidate(9, onClose = $$props.onClose); }; $$self.$capture_state = () => ({ @@ -2311,12 +2422,15 @@ var app = (function () { themeactions, modalStates, isOpen, + firstStateKey, + firstState, state, title, content, items, consequences, onClose, + modalimg, closeModal, handleItemClick, updateModal, @@ -2325,14 +2439,15 @@ var app = (function () { }); $$self.$inject_state = $$props => { - if ('modalStates' in $$props) $$invalidate(7, modalStates = $$props.modalStates); + if ('modalStates' in $$props) $$invalidate(8, modalStates = $$props.modalStates); if ('isOpen' in $$props) $$invalidate(0, isOpen = $$props.isOpen); - if ('state' in $$props) $$invalidate(4, state = $$props.state); + if ('state' in $$props) $$invalidate(5, state = $$props.state); if ('title' in $$props) $$invalidate(1, title = $$props.title); if ('content' in $$props) $$invalidate(2, content = $$props.content); if ('items' in $$props) $$invalidate(3, items = $$props.items); if ('consequences' in $$props) consequences = $$props.consequences; - if ('onClose' in $$props) $$invalidate(8, onClose = $$props.onClose); + if ('onClose' in $$props) $$invalidate(9, onClose = $$props.onClose); + if ('modalimg' in $$props) $$invalidate(4, modalimg = $$props.modalimg); }; if ($$props && "$$inject" in $$props) { @@ -2340,7 +2455,7 @@ var app = (function () { } $$self.$$.update = () => { - if ($$self.$$.dirty & /*$state*/ 512) { + if ($$self.$$.dirty & /*$state*/ 1024) { // Reactive statements to update the modal based on state changes (updateModal($state)); } @@ -2351,6 +2466,7 @@ var app = (function () { title, content, items, + modalimg, state, closeModal, handleItemClick, @@ -2364,65 +2480,65 @@ var app = (function () { class SimpleStateMachineModal extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$p, create_fragment$p, safe_not_equal, { modalStates: 7, isOpen: 0, onClose: 8 }); + init(this, options, instance$u, create_fragment$u, safe_not_equal, { modalStates: 8, isOpen: 0, onClose: 9 }); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "SimpleStateMachineModal", options, - id: create_fragment$p.name + id: create_fragment$u.name }); } get modalStates() { - throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); + throw new Error_1(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); } set modalStates(value) { - throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); + throw new Error_1(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); } get isOpen() { - throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); + throw new Error_1(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); } set isOpen(value) { - throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); + throw new Error_1(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); } get onClose() { - throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); + throw new Error_1(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); } set onClose(value) { - throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); + throw new Error_1(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); } } /* src\MovingDotStatDisplay.svelte generated by Svelte v3.59.2 */ - const file$o = "src\\MovingDotStatDisplay.svelte"; + const file$t = "src\\MovingDotStatDisplay.svelte"; - function get_each_context$g(ctx, list, i) { + function get_each_context$l(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[13] = list[i]; return child_ctx; } - function get_each_context_1$9(ctx, list, i) { + function get_each_context_1$d(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[16] = list[i]; return child_ctx; } - function get_each_context_2$3(ctx, list, i) { + function get_each_context_2$6(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[16] = list[i]; return child_ctx; } // (14:6) {#each $objectives as item} - function create_each_block_2$3(ctx) { + function create_each_block_2$6(ctx) { let li; let t0_value = /*item*/ ctx[16].id + ""; let t0; @@ -2436,14 +2552,14 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(": "); t2 = text(t2_value); t3 = space(); t4 = text(t4_value); attr_dev(li, "class", li_class_value = "" + (null_to_empty(/*item*/ ctx[16].complete ? 'completedobjetive' : '') + " svelte-w7krpq")); - add_location(li, file$o, 15, 8, 453); + add_location(li, file$t, 15, 8, 453); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -2469,7 +2585,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_2$3.name, + id: create_each_block_2$6.name, type: "each", source: "(14:6) {#each $objectives as item}", ctx @@ -2479,7 +2595,7 @@ var app = (function () { } // (26:8) {#each $inventory as item} - function create_each_block_1$9(ctx) { + function create_each_block_1$d(ctx) { let button; let t0_value = /*item*/ ctx[16].name + ""; let t0; @@ -2493,11 +2609,11 @@ var app = (function () { const block = { c: function create() { - button = element("button"); + button = element$1("button"); t0 = text(t0_value); t1 = space(); attr_dev(button, "class", "skill"); - add_location(button, file$o, 26, 10, 813); + add_location(button, file$t, 26, 10, 813); }, m: function mount(target, anchor) { insert_dev(target, button, anchor); @@ -2522,7 +2638,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_1$9.name, + id: create_each_block_1$d.name, type: "each", source: "(26:8) {#each $inventory as item}", ctx @@ -2532,7 +2648,7 @@ var app = (function () { } // (50:8) {#each $skills as skill} - function create_each_block$g(ctx) { + function create_each_block$l(ctx) { let li; let t0_value = /*skill*/ ctx[13].name + ""; let t0; @@ -2545,13 +2661,13 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(": "); t2 = text(t2_value); t3 = text(" - Learned: "); t4 = text(t4_value); - add_location(li, file$o, 50, 10, 1580); + add_location(li, file$t, 50, 10, 1580); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -2573,7 +2689,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$g.name, + id: create_each_block$l.name, type: "each", source: "(50:8) {#each $skills as skill}", ctx @@ -2582,7 +2698,7 @@ var app = (function () { return block; } - function create_fragment$o(ctx) { + function create_fragment$t(ctx) { let div10; let div0; let h10; @@ -2637,7 +2753,7 @@ var app = (function () { let each_blocks_2 = []; for (let i = 0; i < each_value_2.length; i += 1) { - each_blocks_2[i] = create_each_block_2$3(get_each_context_2$3(ctx, each_value_2, i)); + each_blocks_2[i] = create_each_block_2$6(get_each_context_2$6(ctx, each_value_2, i)); } let each_value_1 = /*$inventory*/ ctx[1]; @@ -2645,7 +2761,7 @@ var app = (function () { let each_blocks_1 = []; for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks_1[i] = create_each_block_1$9(get_each_context_1$9(ctx, each_value_1, i)); + each_blocks_1[i] = create_each_block_1$d(get_each_context_1$d(ctx, each_value_1, i)); } let each_value = /*$skills*/ ctx[10]; @@ -2653,47 +2769,47 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$g(get_each_context$g(ctx, each_value, i)); + each_blocks[i] = create_each_block$l(get_each_context$l(ctx, each_value, i)); } const block = { c: function create() { - div10 = element("div"); - div0 = element("div"); - h10 = element("h1"); + div10 = element$1("div"); + div0 = element$1("div"); + h10 = element$1("h1"); h10.textContent = "Objectives"; t1 = space(); - ul0 = element("ul"); + ul0 = element$1("ul"); for (let i = 0; i < each_blocks_2.length; i += 1) { each_blocks_2[i].c(); } t2 = space(); - div2 = element("div"); - div1 = element("div"); - h20 = element("h2"); + div2 = element$1("div"); + div1 = element$1("div"); + h20 = element$1("h2"); h20.textContent = "Inventory"; t4 = space(); - h60 = element("h6"); + h60 = element$1("h6"); h60.textContent = "Affects movement and modal action options"; t6 = space(); - ul1 = element("ul"); + ul1 = element$1("ul"); for (let i = 0; i < each_blocks_1.length; i += 1) { each_blocks_1[i].c(); } t7 = space(); - div7 = element("div"); - div6 = element("div"); - h11 = element("h1"); + div7 = element$1("div"); + div6 = element$1("div"); + h11 = element$1("h1"); h11.textContent = "Player Stats"; t9 = space(); - h61 = element("h6"); + h61 = element$1("h6"); h61.textContent = "Affects how Modal Interactions"; t11 = space(); - div3 = element("div"); + div3 = element$1("div"); t12 = text("Health: "); t13 = text(/*$health*/ ctx[2]); t14 = text(" Mana: "); @@ -2707,57 +2823,57 @@ var app = (function () { t22 = text(" Charisma: "); t23 = text(/*$charisma*/ ctx[7]); t24 = space(); - div4 = element("div"); + div4 = element$1("div"); t25 = text("Luck: "); t26 = text(/*$luck*/ ctx[8]); t27 = space(); - div5 = element("div"); + div5 = element$1("div"); t28 = text("Money: "); t29 = text(/*$money*/ ctx[9]); t30 = space(); - div9 = element("div"); - div8 = element("div"); - h21 = element("h2"); + div9 = element$1("div"); + div8 = element$1("div"); + h21 = element$1("h2"); h21.textContent = "Skill Tree / Abilities"; t32 = space(); - h62 = element("h6"); + h62 = element$1("h6"); h62.textContent = "Affects effectiveness of inventory"; t34 = space(); - ul2 = element("ul"); + ul2 = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h10, file$o, 11, 4, 329); - add_location(ul0, file$o, 12, 4, 354); + add_location(h10, file$t, 11, 4, 329); + add_location(ul0, file$t, 12, 4, 354); attr_dev(div0, "class", "grid-statsitem svelte-w7krpq"); - add_location(div0, file$o, 10, 2, 295); - add_location(h20, file$o, 22, 6, 677); - add_location(h60, file$o, 23, 6, 703); - add_location(ul1, file$o, 24, 6, 761); + add_location(div0, file$t, 10, 2, 295); + add_location(h20, file$t, 22, 6, 677); + add_location(h60, file$t, 23, 6, 703); + add_location(ul1, file$t, 24, 6, 761); attr_dev(div1, "class", "inventory svelte-w7krpq"); - add_location(div1, file$o, 21, 4, 646); + add_location(div1, file$t, 21, 4, 646); attr_dev(div2, "class", "grid-statsitem svelte-w7krpq"); - add_location(div2, file$o, 20, 2, 612); - add_location(h11, file$o, 36, 6, 1066); - add_location(h61, file$o, 37, 6, 1095); - add_location(div3, file$o, 38, 6, 1142); - add_location(div4, file$o, 39, 6, 1286); - add_location(div5, file$o, 40, 6, 1318); + add_location(div2, file$t, 20, 2, 612); + add_location(h11, file$t, 36, 6, 1066); + add_location(h61, file$t, 37, 6, 1095); + add_location(div3, file$t, 38, 6, 1142); + add_location(div4, file$t, 39, 6, 1286); + add_location(div5, file$t, 40, 6, 1318); attr_dev(div6, "class", "stats svelte-w7krpq"); - add_location(div6, file$o, 35, 4, 1039); + add_location(div6, file$t, 35, 4, 1039); attr_dev(div7, "class", "grid-statsitem svelte-w7krpq"); - add_location(div7, file$o, 34, 2, 1005); - add_location(h21, file$o, 46, 6, 1440); - add_location(h62, file$o, 47, 6, 1479); - add_location(ul2, file$o, 48, 6, 1530); + add_location(div7, file$t, 34, 2, 1005); + add_location(h21, file$t, 46, 6, 1440); + add_location(h62, file$t, 47, 6, 1479); + add_location(ul2, file$t, 48, 6, 1530); attr_dev(div8, "class", "skill-tree svelte-w7krpq"); - add_location(div8, file$o, 45, 4, 1408); + add_location(div8, file$t, 45, 4, 1408); attr_dev(div9, "class", "grid-statsitem svelte-w7krpq"); - add_location(div9, file$o, 44, 2, 1374); + add_location(div9, file$t, 44, 2, 1374); attr_dev(div10, "class", "grid-statsContainer svelte-w7krpq"); - add_location(div10, file$o, 9, 0, 258); + add_location(div10, file$t, 9, 0, 258); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -2840,12 +2956,12 @@ var app = (function () { let i; for (i = 0; i < each_value_2.length; i += 1) { - const child_ctx = get_each_context_2$3(ctx, each_value_2, i); + const child_ctx = get_each_context_2$6(ctx, each_value_2, i); if (each_blocks_2[i]) { each_blocks_2[i].p(child_ctx, dirty); } else { - each_blocks_2[i] = create_each_block_2$3(child_ctx); + each_blocks_2[i] = create_each_block_2$6(child_ctx); each_blocks_2[i].c(); each_blocks_2[i].m(ul0, null); } @@ -2864,12 +2980,12 @@ var app = (function () { let i; for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$9(ctx, each_value_1, i); + const child_ctx = get_each_context_1$d(ctx, each_value_1, i); if (each_blocks_1[i]) { each_blocks_1[i].p(child_ctx, dirty); } else { - each_blocks_1[i] = create_each_block_1$9(child_ctx); + each_blocks_1[i] = create_each_block_1$d(child_ctx); each_blocks_1[i].c(); each_blocks_1[i].m(ul1, null); } @@ -2897,12 +3013,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$g(ctx, each_value, i); + const child_ctx = get_each_context$l(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$g(child_ctx); + each_blocks[i] = create_each_block$l(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul2, null); } @@ -2915,8 +3031,8 @@ var app = (function () { each_blocks.length = each_value.length; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(div10); destroy_each(each_blocks_2, detaching); @@ -2927,7 +3043,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$o.name, + id: create_fragment$t.name, type: "component", source: "", ctx @@ -2936,7 +3052,7 @@ var app = (function () { return block; } - function instance$o($$self, $$props, $$invalidate) { + function instance$t($$self, $$props, $$invalidate) { let $objectives; let $inventory; let $health; @@ -3032,23 +3148,23 @@ var app = (function () { class MovingDotStatDisplay extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$o, create_fragment$o, safe_not_equal, {}); + init(this, options, instance$t, create_fragment$t, safe_not_equal, {}); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "MovingDotStatDisplay", options, - id: create_fragment$o.name + id: create_fragment$t.name }); } } /* src\SimpleCollapsible.svelte generated by Svelte v3.59.2 */ - const file$n = "src\\SimpleCollapsible.svelte"; + const file$s = "src\\SimpleCollapsible.svelte"; // (16:4) {#if isOpen} - function create_if_block$d(ctx) { + function create_if_block$g(ctx) { let div; let current; const default_slot_template = /*#slots*/ ctx[4].default; @@ -3056,10 +3172,10 @@ var app = (function () { const block = { c: function create() { - div = element("div"); + div = element$1("div"); if (default_slot) default_slot.c(); attr_dev(div, "class", "content svelte-rzwxvd"); - add_location(div, file$n, 16, 6, 335); + add_location(div, file$s, 16, 6, 335); }, m: function mount(target, anchor) { insert_dev(target, div, anchor); @@ -3103,7 +3219,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$d.name, + id: create_if_block$g.name, type: "if", source: "(16:4) {#if isOpen}", ctx @@ -3112,7 +3228,7 @@ var app = (function () { return block; } - function create_fragment$n(ctx) { + function create_fragment$s(ctx) { let div; let button; let t0_value = (/*isOpen*/ ctx[1] ? 'Close' : 'Open') + ""; @@ -3123,21 +3239,21 @@ var app = (function () { let current; let mounted; let dispose; - let if_block = /*isOpen*/ ctx[1] && create_if_block$d(ctx); + let if_block = /*isOpen*/ ctx[1] && create_if_block$g(ctx); const block = { c: function create() { - div = element("div"); - button = element("button"); + div = element$1("div"); + button = element$1("button"); t0 = text(t0_value); t1 = space(); t2 = text(/*title*/ ctx[0]); t3 = space(); if (if_block) if_block.c(); attr_dev(button, "class", "svelte-rzwxvd"); - add_location(button, file$n, 11, 4, 210); + add_location(button, file$s, 11, 4, 210); attr_dev(div, "class", "collapsible svelte-rzwxvd"); - add_location(div, file$n, 10, 0, 179); + add_location(div, file$s, 10, 0, 179); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -3169,7 +3285,7 @@ var app = (function () { transition_in(if_block, 1); } } else { - if_block = create_if_block$d(ctx); + if_block = create_if_block$g(ctx); if_block.c(); transition_in(if_block, 1); if_block.m(div, null); @@ -3203,7 +3319,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$n.name, + id: create_fragment$s.name, type: "component", source: "", ctx @@ -3212,7 +3328,7 @@ var app = (function () { return block; } - function instance$n($$self, $$props, $$invalidate) { + function instance$s($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('SimpleCollapsible', slots, ['default']); let { title = '' } = $$props; @@ -3250,13 +3366,13 @@ var app = (function () { class SimpleCollapsible extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$n, create_fragment$n, safe_not_equal, { title: 0 }); + init(this, options, instance$s, create_fragment$s, safe_not_equal, { title: 0 }); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "SimpleCollapsible", options, - id: create_fragment$n.name + id: create_fragment$s.name }); } @@ -3271,29 +3387,29 @@ var app = (function () { /* src\BrainstormGameConfigsRandom.svelte generated by Svelte v3.59.2 */ - const { console: console_1$b } = globals; - const file$m = "src\\BrainstormGameConfigsRandom.svelte"; + const { console: console_1$d } = globals; + const file$r = "src\\BrainstormGameConfigsRandom.svelte"; - function get_each_context$f(ctx, list, i) { + function get_each_context$k(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[9] = list[i]; return child_ctx; } - function get_each_context_1$8(ctx, list, i) { + function get_each_context_1$c(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[12] = list[i]; child_ctx[14] = i; return child_ctx; } - function get_each_context_2$2(ctx, list, i) { + function get_each_context_2$5(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[15] = list[i]; return child_ctx; } - function get_each_context_3(ctx, list, i) { + function get_each_context_3$1(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[18] = list[i]; return child_ctx; @@ -3347,12 +3463,12 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(" - "); t2 = text(t2_value); attr_dev(li, "class", "svelte-utjjnp"); - add_location(li, file$m, 262, 28, 10991); + add_location(li, file$r, 262, 28, 10991); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -3391,13 +3507,13 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(" - "); t2 = text(t2_value); attr_dev(li, "class", "svelte-utjjnp"); toggle_class(li, "learned", /*skill*/ ctx[30].learned); - add_location(li, file$m, 269, 28, 11282); + add_location(li, file$r, 269, 28, 11282); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -3440,13 +3556,13 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(" - "); t2 = text(t2_value); attr_dev(li, "class", "svelte-utjjnp"); toggle_class(li, "complete", /*objective*/ ctx[21].complete); - add_location(li, file$m, 276, 28, 11612); + add_location(li, file$r, 276, 28, 11612); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -3495,7 +3611,7 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(" - ("); t2 = text(t2_value); @@ -3504,7 +3620,7 @@ var app = (function () { t5 = text(") - "); t6 = text(t6_value); attr_dev(li, "class", "svelte-utjjnp"); - add_location(li, file$m, 288, 28, 12148); + add_location(li, file$r, 288, 28, 12148); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -3559,24 +3675,24 @@ var app = (function () { const block = { c: function create() { - h3 = element("h3"); + h3 = element$1("h3"); t0 = text("Chapter "); t1 = text(t1_value); t2 = space(); - p = element("p"); + p = element$1("p"); p.textContent = "Targets:"; t4 = space(); - ul = element("ul"); + ul = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } t5 = space(); - add_location(h3, file$m, 284, 24, 11960); - add_location(p, file$m, 285, 24, 12010); + add_location(h3, file$r, 284, 24, 11960); + add_location(p, file$r, 285, 24, 12010); attr_dev(ul, "class", "svelte-utjjnp"); - add_location(ul, file$m, 286, 24, 12051); + add_location(ul, file$r, 286, 24, 12051); }, m: function mount(target, anchor) { insert_dev(target, h3, anchor); @@ -3653,18 +3769,18 @@ var app = (function () { const block = { c: function create() { - li = element("li"); - span = element("span"); + li = element$1("li"); + span = element$1("span"); t0 = text(t0_value); t1 = space(); - input = element("input"); + input = element$1("input"); t2 = space(); - add_location(span, file$m, 309, 44, 13293); + add_location(span, file$r, 309, 44, 13293); attr_dev(input, "type", "text"); attr_dev(input, "placeholder", "Enter objective details"); - add_location(input, file$m, 310, 44, 13368); + add_location(input, file$r, 310, 44, 13368); attr_dev(li, "class", "svelte-utjjnp"); - add_location(li, file$m, 308, 40, 13243); + add_location(li, file$r, 308, 40, 13243); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -3694,7 +3810,7 @@ var app = (function () { } // (326:44) {#if target.subTargets && target.subTargets.length > 0} - function create_if_block$c(ctx) { + function create_if_block$f(ctx) { let div; let h5; let t0; @@ -3707,26 +3823,26 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value_3.length; i += 1) { - each_blocks[i] = create_each_block_3(get_each_context_3(ctx, each_value_3, i)); + each_blocks[i] = create_each_block_3$1(get_each_context_3$1(ctx, each_value_3, i)); } const block = { c: function create() { - div = element("div"); - h5 = element("h5"); + div = element$1("div"); + h5 = element$1("h5"); t0 = text("Subtargets of "); t1 = text(t1_value); t2 = space(); - ul = element("ul"); + ul = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h5, file$m, 327, 52, 14525); + add_location(h5, file$r, 327, 52, 14525); attr_dev(ul, "class", "svelte-utjjnp"); - add_location(ul, file$m, 328, 52, 14615); - add_location(div, file$m, 326, 48, 14466); + add_location(ul, file$r, 328, 52, 14615); + add_location(div, file$r, 326, 48, 14466); }, m: function mount(target, anchor) { insert_dev(target, div, anchor); @@ -3751,12 +3867,12 @@ var app = (function () { let i; for (i = 0; i < each_value_3.length; i += 1) { - const child_ctx = get_each_context_3(ctx, each_value_3, i); + const child_ctx = get_each_context_3$1(ctx, each_value_3, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block_3(child_ctx); + each_blocks[i] = create_each_block_3$1(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul, null); } @@ -3777,7 +3893,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$c.name, + id: create_if_block$f.name, type: "if", source: "(326:44) {#if target.subTargets && target.subTargets.length > 0}", ctx @@ -3787,7 +3903,7 @@ var app = (function () { } // (330:56) {#each target.subTargets as subTarget} - function create_each_block_3(ctx) { + function create_each_block_3$1(ctx) { let li; let span; let t0_value = /*subTarget*/ ctx[18].name + ""; @@ -3815,36 +3931,36 @@ var app = (function () { const block = { c: function create() { - li = element("li"); - span = element("span"); + li = element$1("li"); + span = element$1("span"); t0 = text(t0_value); t1 = space(); - input = element("input"); + input = element$1("input"); t2 = space(); - p0 = element("p"); + p0 = element$1("p"); t3 = text("Coordinates: ("); t4 = text(t4_value); t5 = text(", "); t6 = text(t6_value); t7 = text(")"); t8 = space(); - p1 = element("p"); + p1 = element$1("p"); t9 = text("Collision Type: "); t10 = text(t10_value); t11 = space(); - textarea = element("textarea"); + textarea = element$1("textarea"); t12 = space(); - add_location(span, file$m, 331, 64, 14847); + add_location(span, file$r, 331, 64, 14847); attr_dev(input, "type", "text"); attr_dev(input, "placeholder", "Enter subtarget details"); - add_location(input, file$m, 332, 64, 14942); - add_location(p0, file$m, 333, 64, 15067); - add_location(p1, file$m, 334, 64, 15183); + add_location(input, file$r, 332, 64, 14942); + add_location(p0, file$r, 333, 64, 15067); + add_location(p1, file$r, 334, 64, 15183); attr_dev(textarea, "placeholder", "Enter collision text"); textarea.value = textarea_value_value = /*subTarget*/ ctx[18].collisiontext; - add_location(textarea, file$m, 335, 64, 15297); + add_location(textarea, file$r, 335, 64, 15297); attr_dev(li, "class", "svelte-utjjnp"); - add_location(li, file$m, 330, 60, 14777); + add_location(li, file$r, 330, 60, 14777); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -3884,7 +4000,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_3.name, + id: create_each_block_3$1.name, type: "each", source: "(330:56) {#each target.subTargets as subTarget}", ctx @@ -3894,7 +4010,7 @@ var app = (function () { } // (319:36) {#each storyPart.targets as target} - function create_each_block_2$2(ctx) { + function create_each_block_2$5(ctx) { let li; let span; let t0_value = /*target*/ ctx[15].name + ""; @@ -3920,42 +4036,42 @@ var app = (function () { let textarea_value_value; let t12; let t13; - let if_block = /*target*/ ctx[15].subTargets && /*target*/ ctx[15].subTargets.length > 0 && create_if_block$c(ctx); + let if_block = /*target*/ ctx[15].subTargets && /*target*/ ctx[15].subTargets.length > 0 && create_if_block$f(ctx); const block = { c: function create() { - li = element("li"); - span = element("span"); + li = element$1("li"); + span = element$1("span"); t0 = text(t0_value); t1 = space(); - input = element("input"); + input = element$1("input"); t2 = space(); - p0 = element("p"); + p0 = element$1("p"); t3 = text("Coordinates: ("); t4 = text(t4_value); t5 = text(", "); t6 = text(t6_value); t7 = text(")"); t8 = space(); - p1 = element("p"); + p1 = element$1("p"); t9 = text("Collision Type: "); t10 = text(t10_value); t11 = space(); - textarea = element("textarea"); + textarea = element$1("textarea"); t12 = space(); if (if_block) if_block.c(); t13 = space(); - add_location(span, file$m, 320, 44, 13882); + add_location(span, file$r, 320, 44, 13882); attr_dev(input, "type", "text"); attr_dev(input, "placeholder", "Enter target details"); - add_location(input, file$m, 321, 44, 13954); - add_location(p0, file$m, 322, 44, 14056); - add_location(p1, file$m, 323, 44, 14146); + add_location(input, file$r, 321, 44, 13954); + add_location(p0, file$r, 322, 44, 14056); + add_location(p1, file$r, 323, 44, 14146); attr_dev(textarea, "placeholder", "Enter collision text"); textarea.value = textarea_value_value = /*target*/ ctx[15].collisiontext; - add_location(textarea, file$m, 324, 44, 14237); + add_location(textarea, file$r, 324, 44, 14237); attr_dev(li, "class", "svelte-utjjnp"); - add_location(li, file$m, 319, 40, 13832); + add_location(li, file$r, 319, 40, 13832); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -3994,7 +4110,7 @@ var app = (function () { if (if_block) { if_block.p(ctx, dirty); } else { - if_block = create_if_block$c(ctx); + if_block = create_if_block$f(ctx); if_block.c(); if_block.m(li, t13); } @@ -4011,7 +4127,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_2$2.name, + id: create_each_block_2$5.name, type: "each", source: "(319:36) {#each storyPart.targets as target}", ctx @@ -4021,7 +4137,7 @@ var app = (function () { } // (302:20) {#each randomContentStructureSubtargets.story as storyPart, i} - function create_each_block_1$8(ctx) { + function create_each_block_1$c(ctx) { let div2; let h3; let t0; @@ -4051,48 +4167,48 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value_2.length; i += 1) { - each_blocks[i] = create_each_block_2$2(get_each_context_2$2(ctx, each_value_2, i)); + each_blocks[i] = create_each_block_2$5(get_each_context_2$5(ctx, each_value_2, i)); } const block = { c: function create() { - div2 = element("div"); - h3 = element("h3"); + div2 = element$1("div"); + h3 = element$1("h3"); t0 = text("Part "); t1 = text(t1_value); t2 = space(); - div0 = element("div"); - h40 = element("h4"); + div0 = element$1("div"); + h40 = element$1("h4"); h40.textContent = "Objectives"; t4 = space(); - ul0 = element("ul"); + ul0 = element$1("ul"); for (let i = 0; i < each_blocks_1.length; i += 1) { each_blocks_1[i].c(); } t5 = space(); - div1 = element("div"); - h41 = element("h4"); + div1 = element$1("div"); + h41 = element$1("h4"); h41.textContent = "Targets"; t7 = space(); - ul1 = element("ul"); + ul1 = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } t8 = space(); - add_location(h3, file$m, 303, 28, 12962); - add_location(h40, file$m, 305, 32, 13065); + add_location(h3, file$r, 303, 28, 12962); + add_location(h40, file$r, 305, 32, 13065); attr_dev(ul0, "class", "svelte-utjjnp"); - add_location(ul0, file$m, 306, 32, 13118); - add_location(div0, file$m, 304, 28, 13026); - add_location(h41, file$m, 316, 32, 13663); + add_location(ul0, file$r, 306, 32, 13118); + add_location(div0, file$r, 304, 28, 13026); + add_location(h41, file$r, 316, 32, 13663); attr_dev(ul1, "class", "svelte-utjjnp"); - add_location(ul1, file$m, 317, 32, 13713); - add_location(div1, file$m, 315, 28, 13624); - add_location(div2, file$m, 302, 24, 12927); + add_location(ul1, file$r, 317, 32, 13713); + add_location(div1, file$r, 315, 28, 13624); + add_location(div2, file$r, 302, 24, 12927); }, m: function mount(target, anchor) { insert_dev(target, div2, anchor); @@ -4158,12 +4274,12 @@ var app = (function () { let i; for (i = 0; i < each_value_2.length; i += 1) { - const child_ctx = get_each_context_2$2(ctx, each_value_2, i); + const child_ctx = get_each_context_2$5(ctx, each_value_2, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block_2$2(child_ctx); + each_blocks[i] = create_each_block_2$5(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul1, null); } @@ -4185,7 +4301,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_1$8.name, + id: create_each_block_1$c.name, type: "each", source: "(302:20) {#each randomContentStructureSubtargets.story as storyPart, i}", ctx @@ -4195,7 +4311,7 @@ var app = (function () { } // (358:12) {#each timelinePoints as point} - function create_each_block$f(ctx) { + function create_each_block$k(ctx) { let li; let strong; let t0_value = /*point*/ ctx[9].name + ""; @@ -4208,17 +4324,17 @@ var app = (function () { const block = { c: function create() { - li = element("li"); - strong = element("strong"); + li = element$1("li"); + strong = element$1("strong"); t0 = text(t0_value); t1 = space(); - p = element("p"); + p = element$1("p"); t2 = text(t2_value); t3 = space(); - add_location(strong, file$m, 359, 20, 16431); - add_location(p, file$m, 360, 20, 16482); + add_location(strong, file$r, 359, 20, 16431); + add_location(p, file$r, 360, 20, 16482); attr_dev(li, "class", "svelte-utjjnp"); - add_location(li, file$m, 358, 16, 16405); + add_location(li, file$r, 358, 16, 16405); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -4240,7 +4356,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$f.name, + id: create_each_block$k.name, type: "each", source: "(358:12) {#each timelinePoints as point}", ctx @@ -4249,7 +4365,7 @@ var app = (function () { return block; } - function create_fragment$m(ctx) { + function create_fragment$r(ctx) { let div10; let h10; let t1; @@ -4342,7 +4458,7 @@ var app = (function () { let each_blocks_1 = []; for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks_1[i] = create_each_block_1$8(get_each_context_1$8(ctx, each_value_1, i)); + each_blocks_1[i] = create_each_block_1$c(get_each_context_1$c(ctx, each_value_1, i)); } let each_value = /*timelinePoints*/ ctx[2]; @@ -4350,67 +4466,67 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$f(get_each_context$f(ctx, each_value, i)); + each_blocks[i] = create_each_block$k(get_each_context$k(ctx, each_value, i)); } const block = { c: function create() { - div10 = element("div"); - h10 = element("h1"); + div10 = element$1("div"); + h10 = element$1("h1"); h10.textContent = "Prototyping Custom User Config game on the fly"; t1 = space(); - div8 = element("div"); - div7 = element("div"); - div4 = element("div"); - div0 = element("div"); - h11 = element("h1"); + div8 = element$1("div"); + div7 = element$1("div"); + div4 = element$1("div"); + div0 = element$1("div"); + h11 = element$1("h1"); h11.textContent = "Random Game Content Generator"; t3 = space(); - button0 = element("button"); + button0 = element$1("button"); button0.textContent = "Generate New Content"; t5 = space(); - button1 = element("button"); + button1 = element$1("button"); button1.textContent = "Copy Content Config to Clipboard"; t7 = space(); - div3 = element("div"); - div1 = element("div"); - h20 = element("h2"); + div3 = element$1("div"); + div1 = element$1("div"); + h20 = element$1("h2"); h20.textContent = "Background"; t9 = space(); t10 = text(t10_value); t11 = space(); - h21 = element("h2"); + h21 = element$1("h2"); h21.textContent = "Inventory"; t13 = space(); - ul0 = element("ul"); + ul0 = element$1("ul"); for (let i = 0; i < each_blocks_5.length; i += 1) { each_blocks_5[i].c(); } t14 = space(); - h22 = element("h2"); + h22 = element$1("h2"); h22.textContent = "Skills"; t16 = space(); - ul1 = element("ul"); + ul1 = element$1("ul"); for (let i = 0; i < each_blocks_4.length; i += 1) { each_blocks_4[i].c(); } t17 = space(); - h23 = element("h2"); + h23 = element$1("h2"); h23.textContent = "Objectives"; t19 = space(); - ul2 = element("ul"); + ul2 = element$1("ul"); for (let i = 0; i < each_blocks_3.length; i += 1) { each_blocks_3[i].c(); } t20 = space(); - div2 = element("div"); - h24 = element("h2"); + div2 = element$1("div"); + h24 = element$1("h2"); h24.textContent = "Story"; t22 = space(); @@ -4419,77 +4535,77 @@ var app = (function () { } t23 = space(); - div6 = element("div"); - h12 = element("h1"); + div6 = element$1("div"); + h12 = element$1("h1"); h12.textContent = "Random Game Structure Generator subtargets"; t25 = space(); - button2 = element("button"); + button2 = element$1("button"); button2.textContent = "Generate New Content Story Structure"; t27 = space(); - button3 = element("button"); + button3 = element$1("button"); button3.textContent = "Copy Random Structure to Clipboard"; t29 = space(); - div5 = element("div"); + div5 = element$1("div"); for (let i = 0; i < each_blocks_1.length; i += 1) { each_blocks_1[i].c(); } t30 = space(); - h13 = element("h1"); + h13 = element$1("h1"); h13.textContent = "Random Game Structure to Timeline Generator"; t32 = space(); - button4 = element("button"); + button4 = element$1("button"); button4.textContent = "Generate Random Timeline from Story Structure"; t34 = space(); - button5 = element("button"); + button5 = element$1("button"); button5.textContent = "Generate Linear Timeline from Story Structure"; t36 = space(); - div9 = element("div"); - ul3 = element("ul"); + div9 = element$1("div"); + ul3 = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h10, file$m, 244, 4, 10201); - add_location(h11, file$m, 250, 20, 10377); - add_location(button0, file$m, 251, 20, 10437); - add_location(button1, file$m, 252, 20, 10553); - add_location(div0, file$m, 249, 16, 10350); - add_location(h20, file$m, 256, 24, 10749); - add_location(h21, file$m, 259, 24, 10848); + add_location(h10, file$r, 244, 4, 10201); + add_location(h11, file$r, 250, 20, 10377); + add_location(button0, file$r, 251, 20, 10437); + add_location(button1, file$r, 252, 20, 10553); + add_location(div0, file$r, 249, 16, 10350); + add_location(h20, file$r, 256, 24, 10749); + add_location(h21, file$r, 259, 24, 10848); attr_dev(ul0, "class", "svelte-utjjnp"); - add_location(ul0, file$m, 260, 24, 10892); - add_location(h22, file$m, 266, 24, 11144); + add_location(ul0, file$r, 260, 24, 10892); + add_location(h22, file$r, 266, 24, 11144); attr_dev(ul1, "class", "svelte-utjjnp"); - add_location(ul1, file$m, 267, 24, 11185); - add_location(h23, file$m, 273, 24, 11462); + add_location(ul1, file$r, 267, 24, 11185); + add_location(h23, file$r, 273, 24, 11462); attr_dev(ul2, "class", "svelte-utjjnp"); - add_location(ul2, file$m, 274, 24, 11507); - add_location(div1, file$m, 255, 20, 10718); - add_location(h24, file$m, 282, 24, 11853); - add_location(div2, file$m, 281, 20, 11822); + add_location(ul2, file$r, 274, 24, 11507); + add_location(div1, file$r, 255, 20, 10718); + add_location(h24, file$r, 282, 24, 11853); + add_location(div2, file$r, 281, 20, 11822); attr_dev(div3, "class", "StatColumns svelte-utjjnp"); - add_location(div3, file$m, 254, 16, 10671); - add_location(div4, file$m, 248, 12, 10323); - add_location(h12, file$m, 297, 16, 12442); - add_location(button2, file$m, 298, 16, 12511); - add_location(button3, file$m, 299, 16, 12677); + add_location(div3, file$r, 254, 16, 10671); + add_location(div4, file$r, 248, 12, 10323); + add_location(h12, file$r, 297, 16, 12442); + add_location(button2, file$r, 298, 16, 12511); + add_location(button3, file$r, 299, 16, 12677); attr_dev(div5, "class", "StatColumns svelte-utjjnp"); - add_location(div5, file$m, 300, 16, 12792); - add_location(div6, file$m, 296, 12, 12419); + add_location(div5, file$r, 300, 16, 12792); + add_location(div6, file$r, 296, 12, 12419); attr_dev(div7, "class", "ContainerColumns svelte-utjjnp"); - add_location(div7, file$m, 247, 8, 10279); - add_location(div8, file$m, 246, 4, 10264); - add_location(h13, file$m, 352, 4, 15984); - add_location(button4, file$m, 353, 4, 16042); - add_location(button5, file$m, 354, 4, 16177); + add_location(div7, file$r, 247, 8, 10279); + add_location(div8, file$r, 246, 4, 10264); + add_location(h13, file$r, 352, 4, 15984); + add_location(button4, file$r, 353, 4, 16042); + add_location(button5, file$r, 354, 4, 16177); attr_dev(ul3, "class", "svelte-utjjnp"); - add_location(ul3, file$m, 356, 8, 16338); + add_location(ul3, file$r, 356, 8, 16338); attr_dev(div9, "class", "timeline svelte-utjjnp"); - add_location(div9, file$m, 355, 4, 16306); - add_location(div10, file$m, 243, 0, 10190); + add_location(div9, file$r, 355, 4, 16306); + add_location(div10, file$r, 243, 0, 10190); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -4707,12 +4823,12 @@ var app = (function () { let i; for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$8(ctx, each_value_1, i); + const child_ctx = get_each_context_1$c(ctx, each_value_1, i); if (each_blocks_1[i]) { each_blocks_1[i].p(child_ctx, dirty); } else { - each_blocks_1[i] = create_each_block_1$8(child_ctx); + each_blocks_1[i] = create_each_block_1$c(child_ctx); each_blocks_1[i].c(); each_blocks_1[i].m(div5, null); } @@ -4731,12 +4847,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$f(ctx, each_value, i); + const child_ctx = get_each_context$k(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$f(child_ctx); + each_blocks[i] = create_each_block$k(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul3, null); } @@ -4749,8 +4865,8 @@ var app = (function () { each_blocks.length = each_value.length; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(div10); destroy_each(each_blocks_5, detaching); @@ -4766,7 +4882,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$m.name, + id: create_fragment$r.name, type: "component", source: "", ctx @@ -5002,7 +5118,7 @@ var app = (function () { return allPoints; } - function instance$m($$self, $$props, $$invalidate) { + function instance$r($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('BrainstormGameConfigsRandom', slots, []); let randomContent = generateRandomContent(); @@ -5046,7 +5162,7 @@ var app = (function () { const writable_props = []; Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$b.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$d.warn(` was created with unknown prop '${key}'`); }); const click_handler = () => $$invalidate(0, randomContent = generateRandomContent()); @@ -5092,35 +5208,35 @@ var app = (function () { class BrainstormGameConfigsRandom extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$m, create_fragment$m, safe_not_equal, {}, null, [-1, -1]); + init(this, options, instance$r, create_fragment$r, safe_not_equal, {}, null, [-1, -1]); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "BrainstormGameConfigsRandom", options, - id: create_fragment$m.name + id: create_fragment$r.name }); } } /* src\BrainstormStateTransitionsRandom.svelte generated by Svelte v3.59.2 */ - const { console: console_1$a } = globals; - const file$l = "src\\BrainstormStateTransitionsRandom.svelte"; + const { console: console_1$c } = globals; + const file$q = "src\\BrainstormStateTransitionsRandom.svelte"; - function get_each_context$e(ctx, list, i) { + function get_each_context$j(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[47] = list[i]; return child_ctx; } - function get_each_context_1$7(ctx, list, i) { + function get_each_context_1$b(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[50] = list[i]; return child_ctx; } - function get_each_context_2$1(ctx, list, i) { + function get_each_context_2$4(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[47] = list[i]; return child_ctx; @@ -5143,7 +5259,7 @@ var app = (function () { let each_blocks_1 = []; for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks_1[i] = create_each_block_1$7(get_each_context_1$7(ctx, each_value_1, i)); + each_blocks_1[i] = create_each_block_1$b(get_each_context_1$b(ctx, each_value_1, i)); } let each_value = /*$mergedTimeline*/ ctx[8]; @@ -5151,12 +5267,12 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$e(get_each_context$e(ctx, each_value, i)); + each_blocks[i] = create_each_block$j(get_each_context$j(ctx, each_value, i)); } const block = { c: function create() { - h20 = element("h2"); + h20 = element$1("h2"); h20.textContent = "Timelines"; t1 = space(); @@ -5165,22 +5281,22 @@ var app = (function () { } t2 = space(); - h21 = element("h2"); + h21 = element$1("h2"); h21.textContent = "Merged Timeline"; t4 = space(); - button = element("button"); + button = element$1("button"); button.textContent = "Merge Timelines"; t6 = space(); - ul = element("ul"); + ul = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h20, file$l, 293, 6, 11327); - add_location(h21, file$l, 306, 6, 11735); - add_location(button, file$l, 307, 6, 11767); - add_location(ul, file$l, 308, 6, 11833); + add_location(h20, file$q, 293, 6, 11327); + add_location(h21, file$q, 306, 6, 11735); + add_location(button, file$q, 307, 6, 11767); + add_location(ul, file$q, 308, 6, 11833); }, m: function mount(target, anchor) { insert_dev(target, h20, anchor); @@ -5217,12 +5333,12 @@ var app = (function () { let i; for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$7(ctx, each_value_1, i); + const child_ctx = get_each_context_1$b(ctx, each_value_1, i); if (each_blocks_1[i]) { each_blocks_1[i].p(child_ctx, dirty); } else { - each_blocks_1[i] = create_each_block_1$7(child_ctx); + each_blocks_1[i] = create_each_block_1$b(child_ctx); each_blocks_1[i].c(); each_blocks_1[i].m(t2.parentNode, t2); } @@ -5241,12 +5357,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$e(ctx, each_value, i); + const child_ctx = get_each_context$j(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$e(child_ctx); + each_blocks[i] = create_each_block$j(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul, null); } @@ -5287,7 +5403,7 @@ var app = (function () { } // (298:10) {#each timeline.points as point} - function create_each_block_2$1(ctx) { + function create_each_block_2$4(ctx) { let li; let t0_value = /*point*/ ctx[47].year + ""; let t0; @@ -5297,11 +5413,11 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(": "); t2 = text(t2_value); - add_location(li, file$l, 298, 12, 11496); + add_location(li, file$q, 298, 12, 11496); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -5320,7 +5436,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_2$1.name, + id: create_each_block_2$4.name, type: "each", source: "(298:10) {#each timeline.points as point}", ctx @@ -5330,7 +5446,7 @@ var app = (function () { } // (295:6) {#each $timelines as timeline} - function create_each_block_1$7(ctx) { + function create_each_block_1$b(ctx) { let h3; let t0; let t1_value = /*timeline*/ ctx[50].id + ""; @@ -5349,7 +5465,7 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value_2.length; i += 1) { - each_blocks[i] = create_each_block_2$1(get_each_context_2$1(ctx, each_value_2, i)); + each_blocks[i] = create_each_block_2$4(get_each_context_2$4(ctx, each_value_2, i)); } function click_handler() { @@ -5358,23 +5474,23 @@ var app = (function () { const block = { c: function create() { - h3 = element("h3"); + h3 = element$1("h3"); t0 = text("Timeline "); t1 = text(t1_value); t2 = space(); - ul = element("ul"); + ul = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } t3 = space(); - button = element("button"); + button = element$1("button"); t4 = text("Add Points to Timeline "); t5 = text(t5_value); - add_location(h3, file$l, 295, 8, 11393); - add_location(ul, file$l, 296, 8, 11434); - add_location(button, file$l, 301, 8, 11582); + add_location(h3, file$q, 295, 8, 11393); + add_location(ul, file$q, 296, 8, 11434); + add_location(button, file$q, 301, 8, 11582); }, m: function mount(target, anchor) { insert_dev(target, h3, anchor); @@ -5409,12 +5525,12 @@ var app = (function () { let i; for (i = 0; i < each_value_2.length; i += 1) { - const child_ctx = get_each_context_2$1(ctx, each_value_2, i); + const child_ctx = get_each_context_2$4(ctx, each_value_2, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block_2$1(child_ctx); + each_blocks[i] = create_each_block_2$4(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul, null); } @@ -5443,7 +5559,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_1$7.name, + id: create_each_block_1$b.name, type: "each", source: "(295:6) {#each $timelines as timeline}", ctx @@ -5453,7 +5569,7 @@ var app = (function () { } // (310:8) {#each $mergedTimeline as point} - function create_each_block$e(ctx) { + function create_each_block$j(ctx) { let li; let t0_value = /*point*/ ctx[47].year + ""; let t0; @@ -5467,14 +5583,14 @@ var app = (function () { const block = { c: function create() { - li = element("li"); + li = element$1("li"); t0 = text(t0_value); t1 = text(": "); t2 = text(t2_value); t3 = text(" (Timeline "); t4 = text(t4_value); t5 = text(")\r\n "); - add_location(li, file$l, 310, 10, 11891); + add_location(li, file$q, 310, 10, 11891); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -5497,7 +5613,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$e.name, + id: create_each_block$j.name, type: "each", source: "(310:8) {#each $mergedTimeline as point}", ctx @@ -5507,7 +5623,7 @@ var app = (function () { } // (339:6) {#if sequence.length > 0} - function create_if_block_3(ctx) { + function create_if_block_3$2(ctx) { let div; let p; let t0; @@ -5516,12 +5632,12 @@ var app = (function () { const block = { c: function create() { - div = element("div"); - p = element("p"); + div = element$1("div"); + p = element$1("p"); t0 = text("Generated Sequence: "); t1 = text(t1_value); - add_location(p, file$l, 340, 10, 12886); - add_location(div, file$l, 339, 8, 12869); + add_location(p, file$q, 340, 10, 12886); + add_location(div, file$q, 339, 8, 12869); }, m: function mount(target, anchor) { insert_dev(target, div, anchor); @@ -5539,7 +5655,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block_3.name, + id: create_if_block_3$2.name, type: "if", source: "(339:6) {#if sequence.length > 0}", ctx @@ -5549,7 +5665,7 @@ var app = (function () { } // (329:4) {#if isTwoColumnLayout} - function create_if_block_2$1(ctx) { + function create_if_block_2$4(ctx) { let div2; let div0; let p0; @@ -5565,24 +5681,24 @@ var app = (function () { const block = { c: function create() { - div2 = element("div"); - div0 = element("div"); - p0 = element("p"); + div2 = element$1("div"); + div0 = element$1("div"); + p0 = element$1("p"); t0 = text("Player Sequence: "); t1 = text(t1_value); t2 = space(); - div1 = element("div"); - p1 = element("p"); + div1 = element$1("div"); + p1 = element$1("p"); t3 = text("Enemy Sequence: "); t4 = text(t4_value); - add_location(p0, file$l, 331, 10, 12623); + add_location(p0, file$q, 331, 10, 12623); set_style(div0, "flex", "1"); - add_location(div0, file$l, 330, 8, 12589); - add_location(p1, file$l, 334, 10, 12734); + add_location(div0, file$q, 330, 8, 12589); + add_location(p1, file$q, 334, 10, 12734); set_style(div1, "flex", "1"); - add_location(div1, file$l, 333, 8, 12700); + add_location(div1, file$q, 333, 8, 12700); set_style(div2, "display", "flex"); - add_location(div2, file$l, 329, 6, 12551); + add_location(div2, file$q, 329, 6, 12551); }, m: function mount(target, anchor) { insert_dev(target, div2, anchor); @@ -5607,7 +5723,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block_2$1.name, + id: create_if_block_2$4.name, type: "if", source: "(329:4) {#if isTwoColumnLayout}", ctx @@ -5617,7 +5733,7 @@ var app = (function () { } // (346:4) {#if sequence.length > 0} - function create_if_block_1$4(ctx) { + function create_if_block_1$7(ctx) { let div; let button0; let t1; @@ -5631,23 +5747,23 @@ var app = (function () { const block = { c: function create() { - div = element("div"); - button0 = element("button"); + div = element$1("div"); + button0 = element$1("button"); button0.textContent = "Copy 5 Items"; t1 = space(); - button1 = element("button"); + button1 = element$1("button"); button1.textContent = "Copy 10 Items"; t3 = space(); - button2 = element("button"); + button2 = element$1("button"); button2.textContent = "Copy 30 Items"; t5 = space(); - button3 = element("button"); + button3 = element$1("button"); button3.textContent = "Copy All Events"; - add_location(button0, file$l, 347, 8, 13032); - add_location(button1, file$l, 348, 8, 13107); - add_location(button2, file$l, 349, 8, 13184); - add_location(button3, file$l, 350, 8, 13261); - add_location(div, file$l, 346, 6, 13017); + add_location(button0, file$q, 347, 8, 13032); + add_location(button1, file$q, 348, 8, 13107); + add_location(button2, file$q, 349, 8, 13184); + add_location(button3, file$q, 350, 8, 13261); + add_location(div, file$q, 346, 6, 13017); }, m: function mount(target, anchor) { insert_dev(target, div, anchor); @@ -5670,7 +5786,7 @@ var app = (function () { mounted = true; } }, - p: noop, + p: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(div); mounted = false; @@ -5680,7 +5796,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block_1$4.name, + id: create_if_block_1$7.name, type: "if", source: "(346:4) {#if sequence.length > 0}", ctx @@ -5690,7 +5806,7 @@ var app = (function () { } // (355:4) {#if jsonScaffold} - function create_if_block$b(ctx) { + function create_if_block$e(ctx) { let div; let button; let t1; @@ -5704,18 +5820,18 @@ var app = (function () { const block = { c: function create() { - div = element("div"); - button = element("button"); + div = element$1("div"); + button = element$1("button"); button.textContent = "Copy editable fields for llm"; t1 = space(); - pre = element("pre"); + pre = element$1("pre"); t2 = text(" "); t3 = text(t3_value); t4 = text("\r\n "); - add_location(button, file$l, 356, 8, 13438); - add_location(pre, file$l, 358, 8, 13549); + add_location(button, file$q, 356, 8, 13438); + add_location(pre, file$q, 358, 8, 13549); attr_dev(div, "class", "scrollable svelte-1d8ch82"); - add_location(div, file$l, 355, 6, 13404); + add_location(div, file$q, 355, 6, 13404); }, m: function mount(target, anchor) { insert_dev(target, div, anchor); @@ -5743,7 +5859,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$b.name, + id: create_if_block$e.name, type: "if", source: "(355:4) {#if jsonScaffold}", ctx @@ -5752,7 +5868,7 @@ var app = (function () { return block; } - function create_fragment$l(ctx) { + function create_fragment$q(ctx) { let div0; let h2; let t1; @@ -5790,53 +5906,53 @@ var app = (function () { let if_block0 = /*$timelines*/ ctx[5].length > 0 && create_if_block_4(ctx); function select_block_type(ctx, dirty) { - if (/*isTwoColumnLayout*/ ctx[3]) return create_if_block_2$1; - if (/*sequence*/ ctx[0].length > 0) return create_if_block_3; + if (/*isTwoColumnLayout*/ ctx[3]) return create_if_block_2$4; + if (/*sequence*/ ctx[0].length > 0) return create_if_block_3$2; } let current_block_type = select_block_type(ctx); let if_block1 = current_block_type && current_block_type(ctx); - let if_block2 = /*sequence*/ ctx[0].length > 0 && create_if_block_1$4(ctx); - let if_block3 = /*jsonScaffold*/ ctx[4] && create_if_block$b(ctx); + let if_block2 = /*sequence*/ ctx[0].length > 0 && create_if_block_1$7(ctx); + let if_block3 = /*jsonScaffold*/ ctx[4] && create_if_block$e(ctx); const block = { c: function create() { - div0 = element("div"); - h2 = element("h2"); + div0 = element$1("div"); + h2 = element$1("h2"); h2.textContent = "Timeline Generator (esp backstories)"; t1 = space(); - label0 = element("label"); + label0 = element$1("label"); label0.textContent = "Number of Timelines:"; t3 = space(); - input0 = element("input"); + input0 = element$1("input"); t4 = space(); - button0 = element("button"); + button0 = element$1("button"); button0.textContent = "Create Timelines"; t6 = space(); - label1 = element("label"); + label1 = element$1("label"); label1.textContent = "Number of Events per Timeline:"; t8 = space(); - input1 = element("input"); + input1 = element$1("input"); t9 = space(); if (if_block0) if_block0.c(); t10 = space(); - hr0 = element("hr"); - hr1 = element("hr"); + hr0 = element$1("hr"); + hr1 = element$1("hr"); t11 = space(); - h1 = element("h1"); + h1 = element$1("h1"); h1.textContent = "Sequence and psuedo json scaffold generator"; t13 = space(); - div1 = element("div"); - button1 = element("button"); + div1 = element$1("div"); + button1 = element$1("button"); button1.textContent = "Generate New Sequence"; t15 = space(); - button2 = element("button"); + button2 = element$1("button"); t16 = text("Generate Follow-Up Sequence"); t17 = space(); - button3 = element("button"); + button3 = element$1("button"); button3.textContent = "Generate Main Enemy (solo protagonist) based Sequence"; t19 = space(); - button4 = element("button"); + button4 = element$1("button"); button4.textContent = "Generate JSON Scaffold"; t21 = space(); if (if_block1) if_block1.c(); @@ -5844,30 +5960,30 @@ var app = (function () { if (if_block2) if_block2.c(); t23 = space(); if (if_block3) if_block3.c(); - add_location(h2, file$l, 283, 4, 10882); + add_location(h2, file$q, 283, 4, 10882); attr_dev(label0, "for", "numTimelines"); - add_location(label0, file$l, 285, 4, 10937); + add_location(label0, file$q, 285, 4, 10937); attr_dev(input0, "type", "number"); attr_dev(input0, "id", "numTimelines"); attr_dev(input0, "min", "1"); - add_location(input0, file$l, 286, 4, 10997); - add_location(button0, file$l, 287, 4, 11077); + add_location(input0, file$q, 286, 4, 10997); + add_location(button0, file$q, 287, 4, 11077); attr_dev(label1, "for", "numEvents"); - add_location(label1, file$l, 289, 4, 11147); + add_location(label1, file$q, 289, 4, 11147); attr_dev(input1, "type", "number"); attr_dev(input1, "id", "numEvents"); attr_dev(input1, "min", "1"); - add_location(input1, file$l, 290, 4, 11214); - add_location(div0, file$l, 282, 2, 10871); - add_location(hr0, file$l, 318, 2, 12048); - add_location(hr1, file$l, 318, 6, 12052); - add_location(h1, file$l, 320, 2, 12064); - add_location(button1, file$l, 323, 4, 12135); + add_location(input1, file$q, 290, 4, 11214); + add_location(div0, file$q, 282, 2, 10871); + add_location(hr0, file$q, 318, 2, 12048); + add_location(hr1, file$q, 318, 6, 12052); + add_location(h1, file$q, 320, 2, 12064); + add_location(button1, file$q, 323, 4, 12135); button2.disabled = button2_disabled_value = /*sequence*/ ctx[0].length === 0; - add_location(button2, file$l, 324, 4, 12207); - add_location(button3, file$l, 325, 4, 12326); - add_location(button4, file$l, 326, 4, 12439); - add_location(div1, file$l, 322, 2, 12124); + add_location(button2, file$q, 324, 4, 12207); + add_location(button3, file$q, 325, 4, 12326); + add_location(button4, file$q, 326, 4, 12439); + add_location(div1, file$q, 322, 2, 12124); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -5967,7 +6083,7 @@ var app = (function () { if (if_block2) { if_block2.p(ctx, dirty); } else { - if_block2 = create_if_block_1$4(ctx); + if_block2 = create_if_block_1$7(ctx); if_block2.c(); if_block2.m(div1, t23); } @@ -5980,7 +6096,7 @@ var app = (function () { if (if_block3) { if_block3.p(ctx, dirty); } else { - if_block3 = create_if_block$b(ctx); + if_block3 = create_if_block$e(ctx); if_block3.c(); if_block3.m(div1, null); } @@ -5989,8 +6105,8 @@ var app = (function () { if_block3 = null; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(div0); if (if_block0) if_block0.d(); @@ -6015,7 +6131,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$l.name, + id: create_fragment$q.name, type: "component", source: "", ctx @@ -6050,7 +6166,7 @@ var app = (function () { return { filteredKeys, remainingKeys }; } - function instance$l($$self, $$props, $$invalidate) { + function instance$q($$self, $$props, $$invalidate) { let $timelines; let $numEvents; let $numTimelines; @@ -6463,7 +6579,7 @@ var app = (function () { const writable_props = []; Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$a.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$c.warn(` was created with unknown prop '${key}'`); }); function input0_input_handler() { @@ -6593,45 +6709,45 @@ var app = (function () { class BrainstormStateTransitionsRandom extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$l, create_fragment$l, safe_not_equal, {}, null, [-1, -1]); + init(this, options, instance$q, create_fragment$q, safe_not_equal, {}, null, [-1, -1]); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "BrainstormStateTransitionsRandom", options, - id: create_fragment$l.name + id: create_fragment$q.name }); } } /* src\testbrainstorminstantpopulate.svelte generated by Svelte v3.59.2 */ - const { console: console_1$9 } = globals; - const file$k = "src\\testbrainstorminstantpopulate.svelte"; + const { console: console_1$b } = globals; + const file$p = "src\\testbrainstorminstantpopulate.svelte"; - function get_each_context$d(ctx, list, i) { + function get_each_context$i(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[6] = list[i]; return child_ctx; } - function get_each_context_1$6(ctx, list, i) { + function get_each_context_1$a(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[6] = list[i]; return child_ctx; } // (70:12) {#each filteredKeys as key} - function create_each_block_1$6(ctx) { + function create_each_block_1$a(ctx) { let li; let t_value = /*key*/ ctx[6] + ""; let t; const block = { c: function create() { - li = element("li"); + li = element$1("li"); t = text(t_value); - add_location(li, file$k, 70, 14, 2213); + add_location(li, file$p, 70, 14, 2213); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -6647,7 +6763,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_1$6.name, + id: create_each_block_1$a.name, type: "each", source: "(70:12) {#each filteredKeys as key}", ctx @@ -6657,16 +6773,16 @@ var app = (function () { } // (79:12) {#each remainingKeys as key} - function create_each_block$d(ctx) { + function create_each_block$i(ctx) { let li; let t_value = /*key*/ ctx[6] + ""; let t; const block = { c: function create() { - li = element("li"); + li = element$1("li"); t = text(t_value); - add_location(li, file$k, 79, 14, 2410); + add_location(li, file$p, 79, 14, 2410); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -6682,7 +6798,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$d.name, + id: create_each_block$i.name, type: "each", source: "(79:12) {#each remainingKeys as key}", ctx @@ -6691,7 +6807,7 @@ var app = (function () { return block; } - function create_fragment$k(ctx) { + function create_fragment$p(ctx) { let main; let h1; let t1; @@ -6720,7 +6836,7 @@ var app = (function () { let each_blocks_1 = []; for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks_1[i] = create_each_block_1$6(get_each_context_1$6(ctx, each_value_1, i)); + each_blocks_1[i] = create_each_block_1$a(get_each_context_1$a(ctx, each_value_1, i)); } let each_value = /*remainingKeys*/ ctx[2]; @@ -6728,67 +6844,67 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$d(get_each_context$d(ctx, each_value, i)); + each_blocks[i] = create_each_block$i(get_each_context$i(ctx, each_value, i)); } const block = { c: function create() { - main = element("main"); - h1 = element("h1"); + main = element$1("main"); + h1 = element$1("h1"); h1.textContent = "JSON Key Extractor"; t1 = space(); - div4 = element("div"); - div0 = element("div"); - label = element("label"); + div4 = element$1("div"); + div0 = element$1("div"); + label = element$1("label"); label.textContent = "Enter JSON:"; t3 = space(); - textarea = element("textarea"); + textarea = element$1("textarea"); t4 = space(); - button = element("button"); + button = element$1("button"); button.textContent = "Extract Keys"; t6 = space(); - div3 = element("div"); - div1 = element("div"); - h20 = element("h2"); + div3 = element$1("div"); + div1 = element$1("div"); + h20 = element$1("h2"); h20.textContent = "Filtered Keys:"; t8 = space(); - ul0 = element("ul"); + ul0 = element$1("ul"); for (let i = 0; i < each_blocks_1.length; i += 1) { each_blocks_1[i].c(); } t9 = space(); - div2 = element("div"); - h21 = element("h2"); + div2 = element$1("div"); + h21 = element$1("h2"); h21.textContent = "Remaining Keys:"; t11 = space(); - ul1 = element("ul"); + ul1 = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h1, file$k, 56, 4, 1730); + add_location(h1, file$p, 56, 4, 1730); attr_dev(label, "for", "jsonInput"); - add_location(label, file$k, 60, 8, 1834); + add_location(label, file$p, 60, 8, 1834); attr_dev(textarea, "id", "jsonInput"); attr_dev(textarea, "class", "svelte-1t47hvo"); - add_location(textarea, file$k, 61, 8, 1886); - add_location(button, file$k, 62, 8, 1985); + add_location(textarea, file$p, 61, 8, 1886); + add_location(button, file$p, 62, 8, 1985); attr_dev(div0, "class", "input-column svelte-1t47hvo"); - add_location(div0, file$k, 59, 6, 1798); - add_location(h20, file$k, 67, 10, 2117); - add_location(ul0, file$k, 68, 10, 2152); - add_location(div1, file$k, 66, 8, 2100); - add_location(h21, file$k, 76, 10, 2312); - add_location(ul1, file$k, 77, 10, 2348); - add_location(div2, file$k, 75, 8, 2295); + add_location(div0, file$p, 59, 6, 1798); + add_location(h20, file$p, 67, 10, 2117); + add_location(ul0, file$p, 68, 10, 2152); + add_location(div1, file$p, 66, 8, 2100); + add_location(h21, file$p, 76, 10, 2312); + add_location(ul1, file$p, 77, 10, 2348); + add_location(div2, file$p, 75, 8, 2295); attr_dev(div3, "class", "output-column svelte-1t47hvo"); - add_location(div3, file$k, 65, 6, 2063); + add_location(div3, file$p, 65, 6, 2063); attr_dev(div4, "class", "container svelte-1t47hvo"); - add_location(div4, file$k, 58, 4, 1767); - add_location(main, file$k, 55, 2, 1718); + add_location(div4, file$p, 58, 4, 1767); + add_location(main, file$p, 55, 2, 1718); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -6851,12 +6967,12 @@ var app = (function () { let i; for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$6(ctx, each_value_1, i); + const child_ctx = get_each_context_1$a(ctx, each_value_1, i); if (each_blocks_1[i]) { each_blocks_1[i].p(child_ctx, dirty); } else { - each_blocks_1[i] = create_each_block_1$6(child_ctx); + each_blocks_1[i] = create_each_block_1$a(child_ctx); each_blocks_1[i].c(); each_blocks_1[i].m(ul0, null); } @@ -6875,12 +6991,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$d(ctx, each_value, i); + const child_ctx = get_each_context$i(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$d(child_ctx); + each_blocks[i] = create_each_block$i(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul1, null); } @@ -6893,8 +7009,8 @@ var app = (function () { each_blocks.length = each_value.length; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(main); destroy_each(each_blocks_1, detaching); @@ -6906,7 +7022,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$k.name, + id: create_fragment$p.name, type: "component", source: "", ctx @@ -6947,7 +7063,7 @@ var app = (function () { textarea.style.height = `${textarea.scrollHeight}px`; } - function instance$k($$self, $$props, $$invalidate) { + function instance$p($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('Testbrainstorminstantpopulate', slots, []); let jsonInput = ''; @@ -6975,7 +7091,7 @@ var app = (function () { const writable_props = []; Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$9.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$b.warn(` was created with unknown prop '${key}'`); }); function textarea_input_handler() { @@ -7010,24 +7126,24 @@ var app = (function () { class Testbrainstorminstantpopulate extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$k, create_fragment$k, safe_not_equal, {}); + init(this, options, instance$p, create_fragment$p, safe_not_equal, {}); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "Testbrainstorminstantpopulate", options, - id: create_fragment$k.name + id: create_fragment$p.name }); } } /* src\testjsonmatchingfieldmerge.svelte generated by Svelte v3.59.2 */ - const { Object: Object_1$4, console: console_1$8 } = globals; - const file$j = "src\\testjsonmatchingfieldmerge.svelte"; + const { Object: Object_1$6, console: console_1$a } = globals; + const file$o = "src\\testjsonmatchingfieldmerge.svelte"; // (195:4) {#if Object.keys(mergedJson).length > 0} - function create_if_block$a(ctx) { + function create_if_block$d(ctx) { let div; let h3; let t1; @@ -7037,15 +7153,15 @@ var app = (function () { const block = { c: function create() { - div = element("div"); - h3 = element("h3"); + div = element$1("div"); + h3 = element$1("h3"); h3.textContent = "Merged JSON:"; t1 = space(); - pre = element("pre"); + pre = element$1("pre"); t2 = text(t2_value); - add_location(h3, file$j, 196, 8, 4625); - add_location(pre, file$j, 197, 8, 4656); - add_location(div, file$j, 195, 6, 4610); + add_location(h3, file$o, 196, 8, 4625); + add_location(pre, file$o, 197, 8, 4656); + add_location(div, file$o, 195, 6, 4610); }, m: function mount(target, anchor) { insert_dev(target, div, anchor); @@ -7064,7 +7180,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$a.name, + id: create_if_block$d.name, type: "if", source: "(195:4) {#if Object.keys(mergedJson).length > 0}", ctx @@ -7073,7 +7189,7 @@ var app = (function () { return block; } - function create_fragment$j(ctx) { + function create_fragment$o(ctx) { let main; let h2; let t1; @@ -7092,41 +7208,41 @@ var app = (function () { let show_if = Object.keys(/*mergedJson*/ ctx[2]).length > 0; let mounted; let dispose; - let if_block = show_if && create_if_block$a(ctx); + let if_block = show_if && create_if_block$d(ctx); const block = { c: function create() { - main = element("main"); - h2 = element("h2"); + main = element$1("main"); + h2 = element$1("h2"); h2.textContent = "JSON Merger"; t1 = space(); - div0 = element("div"); - h30 = element("h3"); + div0 = element$1("div"); + h30 = element$1("h3"); h30.textContent = "Original JSON:"; t3 = space(); - textarea0 = element("textarea"); + textarea0 = element$1("textarea"); t4 = space(); - div1 = element("div"); - h31 = element("h3"); + div1 = element$1("div"); + h31 = element$1("h3"); h31.textContent = "Snippet JSON:"; t6 = space(); - textarea1 = element("textarea"); + textarea1 = element$1("textarea"); t7 = space(); - button = element("button"); + button = element$1("button"); button.textContent = "Merge JSON"; t9 = space(); if (if_block) if_block.c(); - add_location(h2, file$j, 180, 4, 4178); - add_location(h30, file$j, 183, 6, 4221); + add_location(h2, file$o, 180, 4, 4178); + add_location(h30, file$o, 183, 6, 4221); attr_dev(textarea0, "class", "svelte-1jgnkl9"); - add_location(textarea0, file$j, 184, 6, 4252); - add_location(div0, file$j, 182, 4, 4208); - add_location(h31, file$j, 188, 6, 4369); + add_location(textarea0, file$o, 184, 6, 4252); + add_location(div0, file$o, 182, 4, 4208); + add_location(h31, file$o, 188, 6, 4369); attr_dev(textarea1, "class", "svelte-1jgnkl9"); - add_location(textarea1, file$j, 189, 6, 4399); - add_location(div1, file$j, 187, 4, 4356); - add_location(button, file$j, 192, 4, 4502); - add_location(main, file$j, 179, 2, 4166); + add_location(textarea1, file$o, 189, 6, 4399); + add_location(div1, file$o, 187, 4, 4356); + add_location(button, file$o, 192, 4, 4502); + add_location(main, file$o, 179, 2, 4166); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -7178,7 +7294,7 @@ var app = (function () { if (if_block) { if_block.p(ctx, dirty); } else { - if_block = create_if_block$a(ctx); + if_block = create_if_block$d(ctx); if_block.c(); if_block.m(main, null); } @@ -7187,8 +7303,8 @@ var app = (function () { if_block = null; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(main); if (if_block) if_block.d(); @@ -7199,7 +7315,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$j.name, + id: create_fragment$o.name, type: "component", source: "", ctx @@ -7257,7 +7373,7 @@ var app = (function () { textarea.style.height = `${textarea.scrollHeight}px`; } - function instance$j($$self, $$props, $$invalidate) { + function instance$o($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('Testjsonmatchingfieldmerge', slots, []); @@ -7389,8 +7505,8 @@ var app = (function () { const writable_props = []; - Object_1$4.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$8.warn(` was created with unknown prop '${key}'`); + Object_1$6.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$a.warn(` was created with unknown prop '${key}'`); }); function textarea0_input_handler() { @@ -7439,29 +7555,29 @@ var app = (function () { class Testjsonmatchingfieldmerge extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$j, create_fragment$j, safe_not_equal, {}); + init(this, options, instance$o, create_fragment$o, safe_not_equal, {}); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "Testjsonmatchingfieldmerge", options, - id: create_fragment$j.name + id: create_fragment$o.name }); } } /* src\SimpleIFrame.svelte generated by Svelte v3.59.2 */ - const file$i = "src\\SimpleIFrame.svelte"; + const file$n = "src\\SimpleIFrame.svelte"; - function get_each_context$c(ctx, list, i) { + function get_each_context$h(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[4] = list[i]; return child_ctx; } // (17:6) {#each webpages as webpage} - function create_each_block$c(ctx) { + function create_each_block$h(ctx) { let option; let t_value = /*webpage*/ ctx[4].name + ""; let t; @@ -7469,11 +7585,11 @@ var app = (function () { const block = { c: function create() { - option = element("option"); + option = element$1("option"); t = text(t_value); option.__value = option_value_value = /*webpage*/ ctx[4].url; option.value = option.__value; - add_location(option, file$i, 17, 8, 538); + add_location(option, file$n, 17, 8, 538); }, m: function mount(target, anchor) { insert_dev(target, option, anchor); @@ -7494,7 +7610,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$c.name, + id: create_each_block$h.name, type: "each", source: "(17:6) {#each webpages as webpage}", ctx @@ -7504,19 +7620,19 @@ var app = (function () { } // (22:4) {#if selectedUrl} - function create_if_block$9(ctx) { + function create_if_block$c(ctx) { let iframe; let iframe_src_value; const block = { c: function create() { - iframe = element("iframe"); + iframe = element$1("iframe"); if (!src_url_equal(iframe.src, iframe_src_value = /*selectedUrl*/ ctx[1])) attr_dev(iframe, "src", iframe_src_value); attr_dev(iframe, "title", "Webpage"); attr_dev(iframe, "width", "100%"); attr_dev(iframe, "height", "800px"); attr_dev(iframe, "frameborder", "0"); - add_location(iframe, file$i, 22, 6, 662); + add_location(iframe, file$n, 22, 6, 662); }, m: function mount(target, anchor) { insert_dev(target, iframe, anchor); @@ -7533,7 +7649,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$9.name, + id: create_if_block$c.name, type: "if", source: "(22:4) {#if selectedUrl}", ctx @@ -7542,7 +7658,7 @@ var app = (function () { return block; } - function create_fragment$i(ctx) { + function create_fragment$n(ctx) { let div; let select; let option; @@ -7556,16 +7672,16 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$c(get_each_context$c(ctx, each_value, i)); + each_blocks[i] = create_each_block$h(get_each_context$h(ctx, each_value, i)); } - let if_block = /*selectedUrl*/ ctx[1] && create_if_block$9(ctx); + let if_block = /*selectedUrl*/ ctx[1] && create_if_block$c(ctx); const block = { c: function create() { - div = element("div"); - select = element("select"); - option = element("option"); + div = element$1("div"); + select = element$1("select"); + option = element$1("option"); option.textContent = "Select a webpage"; for (let i = 0; i < each_blocks.length; i += 1) { @@ -7573,16 +7689,16 @@ var app = (function () { } t1 = space(); - br = element("br"); + br = element$1("br"); t2 = space(); if (if_block) if_block.c(); option.__value = ""; option.value = option.__value; - add_location(option, file$i, 15, 6, 451); + add_location(option, file$n, 15, 6, 451); if (/*selectedUrl*/ ctx[1] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[3].call(select)); - add_location(select, file$i, 14, 4, 385); - add_location(br, file$i, 20, 4, 625); - add_location(div, file$i, 13, 2, 374); + add_location(select, file$n, 14, 4, 385); + add_location(br, file$n, 20, 4, 625); + add_location(div, file$n, 13, 2, 374); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -7620,12 +7736,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$c(ctx, each_value, i); + const child_ctx = get_each_context$h(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$c(child_ctx); + each_blocks[i] = create_each_block$h(child_ctx); each_blocks[i].c(); each_blocks[i].m(select, null); } @@ -7646,7 +7762,7 @@ var app = (function () { if (if_block) { if_block.p(ctx, dirty); } else { - if_block = create_if_block$9(ctx); + if_block = create_if_block$c(ctx); if_block.c(); if_block.m(div, null); } @@ -7655,8 +7771,8 @@ var app = (function () { if_block = null; } }, - i: noop, - o: noop, + i: noop$2, + o: noop$2, d: function destroy(detaching) { if (detaching) detach_dev(div); destroy_each(each_blocks, detaching); @@ -7668,7 +7784,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$i.name, + id: create_fragment$n.name, type: "component", source: "", ctx @@ -7677,7 +7793,7 @@ var app = (function () { return block; } - function instance$i($$self, $$props, $$invalidate) { + function instance$n($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('SimpleIFrame', slots, []); let selectedUrl = ''; @@ -7734,13 +7850,13 @@ var app = (function () { class SimpleIFrame extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$i, create_fragment$i, safe_not_equal, { webpages: 0 }); + init(this, options, instance$n, create_fragment$n, safe_not_equal, { webpages: 0 }); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "SimpleIFrame", options, - id: create_fragment$i.name + id: create_fragment$n.name }); } @@ -7755,32 +7871,32 @@ var app = (function () { /* src\CustomGameConfigHelper.svelte generated by Svelte v3.59.2 */ - const { Object: Object_1$3, console: console_1$7 } = globals; - const file$h = "src\\CustomGameConfigHelper.svelte"; + const { Object: Object_1$5, console: console_1$9 } = globals; + const file$m = "src\\CustomGameConfigHelper.svelte"; - function get_each_context$b(ctx, list, i) { + function get_each_context$g(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[32] = list[i]; return child_ctx; } - function get_each_context_1$5(ctx, list, i) { + function get_each_context_1$9(ctx, list, i) { const child_ctx = ctx.slice(); child_ctx[32] = list[i]; return child_ctx; } // (360:16) {#each filteredKeys as key} - function create_each_block_1$5(ctx) { + function create_each_block_1$9(ctx) { let li; let t_value = /*key*/ ctx[32] + ""; let t; const block = { c: function create() { - li = element("li"); + li = element$1("li"); t = text(t_value); - add_location(li, file$h, 360, 16, 14731); + add_location(li, file$m, 360, 16, 14741); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -7796,7 +7912,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_1$5.name, + id: create_each_block_1$9.name, type: "each", source: "(360:16) {#each filteredKeys as key}", ctx @@ -7806,16 +7922,16 @@ var app = (function () { } // (369:16) {#each remainingKeys as key} - function create_each_block$b(ctx) { + function create_each_block$g(ctx) { let li; let t_value = /*key*/ ctx[32] + ""; let t; const block = { c: function create() { - li = element("li"); + li = element$1("li"); t = text(t_value); - add_location(li, file$h, 369, 16, 14954); + add_location(li, file$m, 369, 16, 14964); }, m: function mount(target, anchor) { insert_dev(target, li, anchor); @@ -7831,7 +7947,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$b.name, + id: create_each_block$g.name, type: "each", source: "(369:16) {#each remainingKeys as key}", ctx @@ -7841,7 +7957,7 @@ var app = (function () { } // (408:8) {#if Object.keys(mergedJson).length > 0} - function create_if_block$8(ctx) { + function create_if_block$b(ctx) { let div; let h3; let t1; @@ -7859,26 +7975,26 @@ var app = (function () { const block = { c: function create() { - div = element("div"); - h3 = element("h3"); + div = element$1("div"); + h3 = element$1("h3"); h3.textContent = "Merged JSON:"; t1 = space(); - pre = element("pre"); + pre = element$1("pre"); t2 = text(t2_value); t3 = text("\r\n placeholder for image input for background - optional\r\n "); - br = element("br"); + br = element$1("br"); t4 = space(); - button0 = element("button"); + button0 = element$1("button"); button0.textContent = "Download Configuration"; t6 = space(); - button1 = element("button"); + button1 = element$1("button"); button1.textContent = "Test load for the auto gen config"; - add_location(h3, file$h, 409, 12, 16347); - add_location(pre, file$h, 410, 12, 16382); - add_location(div, file$h, 408, 8, 16328); - add_location(br, file$h, 413, 8, 16519); - add_location(button0, file$h, 414, 8, 16533); - add_location(button1, file$h, 415, 8, 16622); + add_location(h3, file$m, 409, 12, 16361); + add_location(pre, file$m, 410, 12, 16396); + add_location(div, file$m, 408, 8, 16342); + add_location(br, file$m, 413, 8, 16533); + add_location(button0, file$m, 414, 8, 16547); + add_location(button1, file$m, 415, 8, 16636); }, m: function mount(target, anchor) { insert_dev(target, div, anchor); @@ -7920,7 +8036,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$8.name, + id: create_if_block$b.name, type: "if", source: "(408:8) {#if Object.keys(mergedJson).length > 0}", ctx @@ -7929,7 +8045,7 @@ var app = (function () { return block; } - function create_fragment$h(ctx) { + function create_fragment$m(ctx) { let div5; let h1; let t1; @@ -7989,7 +8105,7 @@ var app = (function () { let each_blocks_1 = []; for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks_1[i] = create_each_block_1$5(get_each_context_1$5(ctx, each_value_1, i)); + each_blocks_1[i] = create_each_block_1$9(get_each_context_1$9(ctx, each_value_1, i)); } let each_value = /*remainingKeys*/ ctx[1]; @@ -7997,7 +8113,7 @@ var app = (function () { let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$b(get_each_context$b(ctx, each_value, i)); + each_blocks[i] = create_each_block$g(get_each_context$g(ctx, each_value, i)); } simpleiframe = new SimpleIFrame({ @@ -8005,117 +8121,117 @@ var app = (function () { $$inline: true }); - let if_block = show_if && create_if_block$8(ctx); + let if_block = show_if && create_if_block$b(ctx); const block = { c: function create() { - div5 = element("div"); - h1 = element("h1"); + div5 = element$1("div"); + h1 = element$1("h1"); h1.textContent = "Streamlined Config Creator Randomiser has been forced to max 2 story parts and 2 targets each to test load"; t1 = space(); - h20 = element("h2"); + h20 = element$1("h2"); h20.textContent = "User should be able to control the length in respect to llm used and should be able prompt the llm in chunks"; t3 = space(); - div4 = element("div"); - div0 = element("div"); - pre = element("pre"); + div4 = element$1("div"); + div0 = element$1("div"); + pre = element$1("pre"); pre.textContent = ` ${JSON.stringify(/*randomContentStructureSubtargets*/ ctx[4], null, 2)} `; t7 = space(); - div3 = element("div"); - div1 = element("div"); - h21 = element("h2"); + div3 = element$1("div"); + div1 = element$1("div"); + h21 = element$1("h2"); h21.textContent = "Filtered Keys:"; t9 = space(); - ul0 = element("ul"); + ul0 = element$1("ul"); for (let i = 0; i < each_blocks_1.length; i += 1) { each_blocks_1[i].c(); } t10 = space(); - div2 = element("div"); - h22 = element("h2"); + div2 = element$1("div"); + h22 = element$1("h2"); h22.textContent = "Remaining Keys:"; t12 = space(); - ul1 = element("ul"); + ul1 = element$1("ul"); for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } t13 = space(); - div7 = element("div"); - div6 = element("div"); - hr0 = element("hr"); + div7 = element$1("div"); + div6 = element$1("div"); + hr0 = element$1("hr"); t14 = space(); - h3 = element("h3"); + h3 = element$1("h3"); h3.textContent = "Snippet JSON (Get from LLM APIs or interfaces), Use the following prompt from the below :"; t16 = space(); - button0 = element("button"); + button0 = element$1("button"); button0.textContent = "Copy System Prompt"; t18 = space(); - button1 = element("button"); + button1 = element$1("button"); button1.textContent = "Copy User Prompt"; - t20 = space(); - button2 = element("button"); + t20 = text("\r\n ||| "); + button2 = element$1("button"); button2.textContent = "Copy Obstacle Prompt"; t22 = space(); - button3 = element("button"); + button3 = element$1("button"); button3.textContent = "Copy Resolution Prompt"; t24 = text("\r\n LLM: "); create_component(simpleiframe.$$.fragment); t25 = space(); - hr1 = element("hr"); + hr1 = element$1("hr"); t26 = text("\r\n\r\n LLM Response to be pasted below\r\n "); - textarea = element("textarea"); + textarea = element$1("textarea"); t27 = space(); - button4 = element("button"); + button4 = element$1("button"); button4.textContent = "Merge JSON"; t29 = space(); if (if_block) if_block.c(); t30 = space(); - hr2 = element("hr"); + hr2 = element$1("hr"); t31 = text("\r\n\r\n Major Issues now are how are how to incorporate non alert types OR just assume this is the manual part i.e. filling in the blanks the autogen doesnt manage AND "); - br0 = element("br"); + br0 = element$1("br"); t32 = text("\r\n Long Structures? "); - br1 = element("br"); + br1 = element$1("br"); t33 = text("\r\n How to use the sequence planner in the same workflow? AND "); - br2 = element("br"); - add_location(h1, file$h, 344, 4, 13965); - add_location(h20, file$h, 345, 4, 14086); - add_location(pre, file$h, 350, 12, 14435); + br2 = element$1("br"); + add_location(h1, file$m, 344, 4, 13975); + add_location(h20, file$m, 345, 4, 14096); + add_location(pre, file$m, 350, 12, 14445); attr_dev(div0, "class", "input-column svelte-1ynthow"); - add_location(div0, file$h, 348, 8, 14253); - add_location(h21, file$h, 357, 12, 14627); - add_location(ul0, file$h, 358, 12, 14664); - add_location(div1, file$h, 356, 12, 14608); - add_location(h22, file$h, 366, 12, 14848); - add_location(ul1, file$h, 367, 12, 14886); - add_location(div2, file$h, 365, 12, 14829); + add_location(div0, file$m, 348, 8, 14263); + add_location(h21, file$m, 357, 12, 14637); + add_location(ul0, file$m, 358, 12, 14674); + add_location(div1, file$m, 356, 12, 14618); + add_location(h22, file$m, 366, 12, 14858); + add_location(ul1, file$m, 367, 12, 14896); + add_location(div2, file$m, 365, 12, 14839); attr_dev(div3, "class", "output-column svelte-1ynthow"); - add_location(div3, file$h, 355, 8, 14567); + add_location(div3, file$m, 355, 8, 14577); attr_dev(div4, "class", "ContainerColumns svelte-1ynthow"); - add_location(div4, file$h, 346, 4, 14209); - add_location(div5, file$h, 342, 0, 13952); - add_location(hr0, file$h, 391, 8, 15460); - add_location(h3, file$h, 392, 8, 15474); - add_location(button0, file$h, 393, 8, 15582); - add_location(button1, file$h, 394, 8, 15681); - add_location(button2, file$h, 395, 8, 15776); - add_location(button3, file$h, 396, 8, 15879); - add_location(hr1, file$h, 399, 8, 16042); + add_location(div4, file$m, 346, 4, 14219); + add_location(div5, file$m, 342, 0, 13962); + add_location(hr0, file$m, 391, 8, 15470); + add_location(h3, file$m, 392, 8, 15484); + add_location(button0, file$m, 393, 8, 15592); + add_location(button1, file$m, 394, 8, 15691); + add_location(button2, file$m, 395, 12, 15790); + add_location(button3, file$m, 396, 8, 15893); + add_location(hr1, file$m, 399, 8, 16056); attr_dev(textarea, "class", "svelte-1ynthow"); - add_location(textarea, file$h, 402, 8, 16099); - add_location(div6, file$h, 378, 8, 15099); - add_location(button4, file$h, 405, 8, 16212); - add_location(div7, file$h, 377, 4, 15084); - add_location(hr2, file$h, 419, 4, 16748); - add_location(br0, file$h, 421, 164, 16920); - add_location(br1, file$h, 422, 21, 16947); - add_location(br2, file$h, 423, 62, 17015); + add_location(textarea, file$m, 402, 8, 16113); + add_location(div6, file$m, 378, 8, 15109); + add_location(button4, file$m, 405, 8, 16226); + add_location(div7, file$m, 377, 4, 15094); + add_location(hr2, file$m, 419, 4, 16762); + add_location(br0, file$m, 421, 164, 16934); + add_location(br1, file$m, 422, 21, 16961); + add_location(br2, file$m, 423, 62, 17029); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -8210,12 +8326,12 @@ var app = (function () { let i; for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$5(ctx, each_value_1, i); + const child_ctx = get_each_context_1$9(ctx, each_value_1, i); if (each_blocks_1[i]) { each_blocks_1[i].p(child_ctx, dirty); } else { - each_blocks_1[i] = create_each_block_1$5(child_ctx); + each_blocks_1[i] = create_each_block_1$9(child_ctx); each_blocks_1[i].c(); each_blocks_1[i].m(ul0, null); } @@ -8234,12 +8350,12 @@ var app = (function () { let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$b(ctx, each_value, i); + const child_ctx = get_each_context$g(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$b(child_ctx); + each_blocks[i] = create_each_block$g(child_ctx); each_blocks[i].c(); each_blocks[i].m(ul1, null); } @@ -8262,7 +8378,7 @@ var app = (function () { if (if_block) { if_block.p(ctx, dirty); } else { - if_block = create_if_block$8(ctx); + if_block = create_if_block$b(ctx); if_block.c(); if_block.m(div7, null); } @@ -8303,7 +8419,7 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$h.name, + id: create_fragment$m.name, type: "component", source: "", ctx @@ -8402,7 +8518,7 @@ var app = (function () { } } - function instance$h($$self, $$props, $$invalidate) { + function instance$m($$self, $$props, $$invalidate) { let { $$slots: slots = {}, $$scope } = $$props; validate_slots('CustomGameConfigHelper', slots, []); let randomContentStructureSubtargets = generateRandomContentStructureSubtargets(); @@ -8664,8 +8780,8 @@ var app = (function () { const writable_props = []; - Object_1$3.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$7.warn(` was created with unknown prop '${key}'`); + Object_1$5.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$9.warn(` was created with unknown prop '${key}'`); }); const click_handler = () => copyText(CopyGameAssistSystemPrompt); @@ -8766,5221 +8882,36676 @@ var app = (function () { class CustomGameConfigHelper extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$h, create_fragment$h, safe_not_equal, {}, null, [-1, -1]); + init(this, options, instance$m, create_fragment$m, safe_not_equal, {}, null, [-1, -1]); dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "CustomGameConfigHelper", options, - id: create_fragment$h.name + id: create_fragment$m.name }); } } - /* src\MovingDotSpaceThemeManager.svelte generated by Svelte v3.59.2 */ - const file$g = "src\\MovingDotSpaceThemeManager.svelte"; + /** + * Copyright (c) 2016-2024, The Cytoscape Consortium. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the “Software”), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ - // (97:4) - function create_default_slot_2(ctx) { - let customgameconfighelper; - let current; - customgameconfighelper = new CustomGameConfigHelper({ $$inline: true }); + function _typeof(obj) { + "@babel/helpers - typeof"; - const block = { - c: function create() { - create_component(customgameconfighelper.$$.fragment); - }, - m: function mount(target, anchor) { - mount_component(customgameconfighelper, target, anchor); - current = true; - }, - i: function intro(local) { - if (current) return; - transition_in(customgameconfighelper.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(customgameconfighelper.$$.fragment, local); - current = false; - }, - d: function destroy(detaching) { - destroy_component(customgameconfighelper, detaching); - } - }; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }, _typeof(obj); + } + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + function _defineProperty$1(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + return obj; + } + function _slicedToArray(arr, i) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); + } + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + function _iterableToArrayLimit(arr, i) { + var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; + if (_i == null) return; + var _arr = []; + var _n = true; + var _d = false; + var _s, _e; + try { + for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); + } + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _createForOfIteratorHelper(o, allowArrayLike) { + var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; + if (!it) { + if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { + if (it) o = it; + var i = 0; + var F = function () {}; + return { + s: F, + n: function () { + if (i >= o.length) return { + done: true + }; + return { + done: false, + value: o[i++] + }; + }, + e: function (e) { + throw e; + }, + f: F + }; + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + var normalCompletion = true, + didErr = false, + err; + return { + s: function () { + it = it.call(o); + }, + n: function () { + var step = it.next(); + normalCompletion = step.done; + return step; + }, + e: function (e) { + didErr = true; + err = e; + }, + f: function () { + try { + if (!normalCompletion && it.return != null) it.return(); + } finally { + if (didErr) throw err; + } + } + }; + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_default_slot_2.name, - type: "slot", - source: "(97:4) ", - ctx - }); + var _window = typeof window === 'undefined' ? null : window; // eslint-disable-line no-undef - return block; - } + var navigator$1 = _window ? _window.navigator : null; + _window ? _window.document : null; + var typeofstr = _typeof(''); + var typeofobj = _typeof({}); + var typeoffn = _typeof(function () {}); + var typeofhtmlele = typeof HTMLElement === "undefined" ? "undefined" : _typeof(HTMLElement); + var instanceStr = function instanceStr(obj) { + return obj && obj.instanceString && fn$6(obj.instanceString) ? obj.instanceString() : null; + }; - // (101:4) - function create_default_slot_1(ctx) { - let hr; - let t0; - let br0; - let t1; - let br1; - let t2; - let brainstormstatetransitionsrandom; - let current; - brainstormstatetransitionsrandom = new BrainstormStateTransitionsRandom({ $$inline: true }); + var string = function string(obj) { + return obj != null && _typeof(obj) == typeofstr; + }; + var fn$6 = function fn(obj) { + return obj != null && _typeof(obj) === typeoffn; + }; + var array = function array(obj) { + return !elementOrCollection(obj) && (Array.isArray ? Array.isArray(obj) : obj != null && obj instanceof Array); + }; + var plainObject = function plainObject(obj) { + return obj != null && _typeof(obj) === typeofobj && !array(obj) && obj.constructor === Object; + }; + var object = function object(obj) { + return obj != null && _typeof(obj) === typeofobj; + }; + var number$1 = function number(obj) { + return obj != null && _typeof(obj) === _typeof(1) && !isNaN(obj); + }; + var integer = function integer(obj) { + return number$1(obj) && Math.floor(obj) === obj; + }; + var htmlElement = function htmlElement(obj) { + if ('undefined' === typeofhtmlele) { + return undefined; + } else { + return null != obj && obj instanceof HTMLElement; + } + }; + var elementOrCollection = function elementOrCollection(obj) { + return element(obj) || collection(obj); + }; + var element = function element(obj) { + return instanceStr(obj) === 'collection' && obj._private.single; + }; + var collection = function collection(obj) { + return instanceStr(obj) === 'collection' && !obj._private.single; + }; + var core$1 = function core(obj) { + return instanceStr(obj) === 'core'; + }; + var stylesheet = function stylesheet(obj) { + return instanceStr(obj) === 'stylesheet'; + }; + var event = function event(obj) { + return instanceStr(obj) === 'event'; + }; + var emptyString = function emptyString(obj) { + if (obj === undefined || obj === null) { + // null is empty + return true; + } else if (obj === '' || obj.match(/^\s+$/)) { + return true; // empty string is empty + } - const block = { - c: function create() { - hr = element("hr"); - t0 = text("\r\n Early Sequence examples - \r\n "); - br0 = element("br"); - t1 = text("Write a story where the main event are in this order: gosomewhere getsomething makeobservation getsomething talktosomeone makeobservation getsomething talktosomeone gosomewhere fight talktosomeone fight fight talktosomeone talktosomeone talktosomeone gosomewhere talktosomeone\r\n "); - br1 = element("br"); - t2 = text("lets write the story to fit this order - stats location stats inventory stats location location skills inventory stats inventory skills skills skills stats stats skills\r\n \r\n "); - create_component(brainstormstatetransitionsrandom.$$.fragment); - add_location(hr, file$g, 101, 8, 4653); - add_location(br0, file$g, 103, 8, 4703); - add_location(br1, file$g, 104, 8, 4993); - }, - m: function mount(target, anchor) { - insert_dev(target, hr, anchor); - insert_dev(target, t0, anchor); - insert_dev(target, br0, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, br1, anchor); - insert_dev(target, t2, anchor); - mount_component(brainstormstatetransitionsrandom, target, anchor); - current = true; - }, - p: noop, - i: function intro(local) { - if (current) return; - transition_in(brainstormstatetransitionsrandom.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(brainstormstatetransitionsrandom.$$.fragment, local); - current = false; - }, - d: function destroy(detaching) { - if (detaching) detach_dev(hr); - if (detaching) detach_dev(t0); - if (detaching) detach_dev(br0); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(br1); - if (detaching) detach_dev(t2); - destroy_component(brainstormstatetransitionsrandom, detaching); - } - }; + return false; // otherwise, we don't know what we've got + }; + var domElement = function domElement(obj) { + if (typeof HTMLElement === 'undefined') { + return false; // we're not in a browser so it doesn't matter + } else { + return obj instanceof HTMLElement; + } + }; + var boundingBox = function boundingBox(obj) { + return plainObject(obj) && number$1(obj.x1) && number$1(obj.x2) && number$1(obj.y1) && number$1(obj.y2); + }; + var promise = function promise(obj) { + return object(obj) && fn$6(obj.then); + }; + var ms = function ms() { + return navigator$1 && navigator$1.userAgent.match(/msie|trident|edge/i); + }; // probably a better way to detect this... + + var memoize$1 = function memoize(fn, keyFn) { + if (!keyFn) { + keyFn = function keyFn() { + if (arguments.length === 1) { + return arguments[0]; + } else if (arguments.length === 0) { + return 'undefined'; + } + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + return args.join('$'); + }; + } + var memoizedFn = function memoizedFn() { + var self = this; + var args = arguments; + var ret; + var k = keyFn.apply(self, args); + var cache = memoizedFn.cache; + if (!(ret = cache[k])) { + ret = cache[k] = fn.apply(self, args); + } + return ret; + }; + memoizedFn.cache = {}; + return memoizedFn; + }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_default_slot_1.name, - type: "slot", - source: "(101:4) ", - ctx - }); + var camel2dash = memoize$1(function (str) { + return str.replace(/([A-Z])/g, function (v) { + return '-' + v.toLowerCase(); + }); + }); + var dash2camel = memoize$1(function (str) { + return str.replace(/(-\w)/g, function (v) { + return v[1].toUpperCase(); + }); + }); + var prependCamel = memoize$1(function (prefix, str) { + return prefix + str[0].toUpperCase() + str.substring(1); + }, function (prefix, str) { + return prefix + '$' + str; + }); + var capitalize = function capitalize(str) { + if (emptyString(str)) { + return str; + } + return str.charAt(0).toUpperCase() + str.substring(1); + }; - return block; - } + var number = '(?:[-+]?(?:(?:\\d+|\\d*\\.\\d+)(?:[Ee][+-]?\\d+)?))'; + var rgba = 'rgb[a]?\\((' + number + '[%]?)\\s*,\\s*(' + number + '[%]?)\\s*,\\s*(' + number + '[%]?)(?:\\s*,\\s*(' + number + '))?\\)'; + var rgbaNoBackRefs = 'rgb[a]?\\((?:' + number + '[%]?)\\s*,\\s*(?:' + number + '[%]?)\\s*,\\s*(?:' + number + '[%]?)(?:\\s*,\\s*(?:' + number + '))?\\)'; + var hsla = 'hsl[a]?\\((' + number + ')\\s*,\\s*(' + number + '[%])\\s*,\\s*(' + number + '[%])(?:\\s*,\\s*(' + number + '))?\\)'; + var hslaNoBackRefs = 'hsl[a]?\\((?:' + number + ')\\s*,\\s*(?:' + number + '[%])\\s*,\\s*(?:' + number + '[%])(?:\\s*,\\s*(?:' + number + '))?\\)'; + var hex3 = '\\#[0-9a-fA-F]{3}'; + var hex6 = '\\#[0-9a-fA-F]{6}'; - // (72:0) - function create_default_slot$2(ctx) { - let t0; - let hr; - let t1; - let simplecollapsible0; - let t2; - let simplecollapsible1; - let current; + var ascending = function ascending(a, b) { + if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } + }; + var descending = function descending(a, b) { + return -1 * ascending(a, b); + }; - simplecollapsible0 = new SimpleCollapsible({ - props: { - title: "Streamlined Config Steps", - $$slots: { default: [create_default_slot_2] }, - $$scope: { ctx } - }, - $$inline: true - }); + var extend$1 = Object.assign != null ? Object.assign.bind(Object) : function (tgt) { + var args = arguments; + for (var i = 1; i < args.length; i++) { + var obj = args[i]; + if (obj == null) { + continue; + } + var keys = Object.keys(obj); + for (var j = 0; j < keys.length; j++) { + var k = keys[j]; + tgt[k] = obj[k]; + } + } + return tgt; + }; - simplecollapsible1 = new SimpleCollapsible({ - props: { - title: "Incomplete Story structure and Timeline suggestion engines", - $$slots: { default: [create_default_slot_1] }, - $$scope: { ctx } - }, - $$inline: true - }); + // get [r, g, b] from #abc or #aabbcc + var hex2tuple = function hex2tuple(hex) { + if (!(hex.length === 4 || hex.length === 7) || hex[0] !== '#') { + return; + } + var shortHex = hex.length === 4; + var r, g, b; + var base = 16; + if (shortHex) { + r = parseInt(hex[1] + hex[1], base); + g = parseInt(hex[2] + hex[2], base); + b = parseInt(hex[3] + hex[3], base); + } else { + r = parseInt(hex[1] + hex[2], base); + g = parseInt(hex[3] + hex[4], base); + b = parseInt(hex[5] + hex[6], base); + } + return [r, g, b]; + }; - const block = { - c: function create() { - t0 = text("Currently the state machine is the json config - Story parts / target type controlled by switch case for collisions and smmodal (state machine modal as the targets all have to a transitions field) (modals and smmodals not yet part of randomisers below)\r\n "); - hr = element("hr"); - t1 = text("\r\n Incomplete/Unpolished Custom game setting assistant\r\n \r\n \r\n\r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n "); - create_component(simplecollapsible0.$$.fragment); - t2 = space(); - create_component(simplecollapsible1.$$.fragment); - add_location(hr, file$g, 73, 4, 3323); - }, - m: function mount(target, anchor) { - insert_dev(target, t0, anchor); - insert_dev(target, hr, anchor); - insert_dev(target, t1, anchor); - mount_component(simplecollapsible0, target, anchor); - insert_dev(target, t2, anchor); - mount_component(simplecollapsible1, target, anchor); - current = true; - }, - p: function update(ctx, dirty) { - const simplecollapsible0_changes = {}; + // get [r, g, b, a] from hsl(0, 0, 0) or hsla(0, 0, 0, 0) + var hsl2tuple = function hsl2tuple(hsl) { + var ret; + var h, s, l, a, r, g, b; + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + var m = new RegExp('^' + hsla + '$').exec(hsl); + if (m) { + // get hue + h = parseInt(m[1]); + if (h < 0) { + h = (360 - -1 * h % 360) % 360; + } else if (h > 360) { + h = h % 360; + } + h /= 360; // normalise on [0, 1] + + s = parseFloat(m[2]); + if (s < 0 || s > 100) { + return; + } // saturation is [0, 100] + s = s / 100; // normalise on [0, 1] + + l = parseFloat(m[3]); + if (l < 0 || l > 100) { + return; + } // lightness is [0, 100] + l = l / 100; // normalise on [0, 1] + + a = m[4]; + if (a !== undefined) { + a = parseFloat(a); + if (a < 0 || a > 1) { + return; + } // alpha is [0, 1] + } - if (dirty & /*$$scope*/ 8192) { - simplecollapsible0_changes.$$scope = { dirty, ctx }; - } + // now, convert to rgb + // code from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript + if (s === 0) { + r = g = b = Math.round(l * 255); // achromatic + } else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = Math.round(255 * hue2rgb(p, q, h + 1 / 3)); + g = Math.round(255 * hue2rgb(p, q, h)); + b = Math.round(255 * hue2rgb(p, q, h - 1 / 3)); + } + ret = [r, g, b, a]; + } + return ret; + }; - simplecollapsible0.$set(simplecollapsible0_changes); - const simplecollapsible1_changes = {}; + // get [r, g, b, a] from rgb(0, 0, 0) or rgba(0, 0, 0, 0) + var rgb2tuple = function rgb2tuple(rgb) { + var ret; + var m = new RegExp('^' + rgba + '$').exec(rgb); + if (m) { + ret = []; + var isPct = []; + for (var i = 1; i <= 3; i++) { + var channel = m[i]; + if (channel[channel.length - 1] === '%') { + isPct[i] = true; + } + channel = parseFloat(channel); + if (isPct[i]) { + channel = channel / 100 * 255; // normalise to [0, 255] + } + + if (channel < 0 || channel > 255) { + return; + } // invalid channel value - if (dirty & /*$$scope*/ 8192) { - simplecollapsible1_changes.$$scope = { dirty, ctx }; - } + ret.push(Math.floor(channel)); + } + var atLeastOneIsPct = isPct[1] || isPct[2] || isPct[3]; + var allArePct = isPct[1] && isPct[2] && isPct[3]; + if (atLeastOneIsPct && !allArePct) { + return; + } // must all be percent values if one is + + var alpha = m[4]; + if (alpha !== undefined) { + alpha = parseFloat(alpha); + if (alpha < 0 || alpha > 1) { + return; + } // invalid alpha value - simplecollapsible1.$set(simplecollapsible1_changes); - }, - i: function intro(local) { - if (current) return; - transition_in(simplecollapsible0.$$.fragment, local); - transition_in(simplecollapsible1.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(simplecollapsible0.$$.fragment, local); - transition_out(simplecollapsible1.$$.fragment, local); - current = false; - }, - d: function destroy(detaching) { - if (detaching) detach_dev(t0); - if (detaching) detach_dev(hr); - if (detaching) detach_dev(t1); - destroy_component(simplecollapsible0, detaching); - if (detaching) detach_dev(t2); - destroy_component(simplecollapsible1, detaching); - } - }; + ret.push(alpha); + } + } + return ret; + }; + var colorname2tuple = function colorname2tuple(color) { + return colors[color.toLowerCase()]; + }; + var color2tuple = function color2tuple(color) { + return (array(color) ? color : null) || colorname2tuple(color) || hex2tuple(color) || rgb2tuple(color) || hsl2tuple(color); + }; + var colors = { + // special colour names + transparent: [0, 0, 0, 0], + // NB alpha === 0 + + // regular colours + aliceblue: [240, 248, 255], + antiquewhite: [250, 235, 215], + aqua: [0, 255, 255], + aquamarine: [127, 255, 212], + azure: [240, 255, 255], + beige: [245, 245, 220], + bisque: [255, 228, 196], + black: [0, 0, 0], + blanchedalmond: [255, 235, 205], + blue: [0, 0, 255], + blueviolet: [138, 43, 226], + brown: [165, 42, 42], + burlywood: [222, 184, 135], + cadetblue: [95, 158, 160], + chartreuse: [127, 255, 0], + chocolate: [210, 105, 30], + coral: [255, 127, 80], + cornflowerblue: [100, 149, 237], + cornsilk: [255, 248, 220], + crimson: [220, 20, 60], + cyan: [0, 255, 255], + darkblue: [0, 0, 139], + darkcyan: [0, 139, 139], + darkgoldenrod: [184, 134, 11], + darkgray: [169, 169, 169], + darkgreen: [0, 100, 0], + darkgrey: [169, 169, 169], + darkkhaki: [189, 183, 107], + darkmagenta: [139, 0, 139], + darkolivegreen: [85, 107, 47], + darkorange: [255, 140, 0], + darkorchid: [153, 50, 204], + darkred: [139, 0, 0], + darksalmon: [233, 150, 122], + darkseagreen: [143, 188, 143], + darkslateblue: [72, 61, 139], + darkslategray: [47, 79, 79], + darkslategrey: [47, 79, 79], + darkturquoise: [0, 206, 209], + darkviolet: [148, 0, 211], + deeppink: [255, 20, 147], + deepskyblue: [0, 191, 255], + dimgray: [105, 105, 105], + dimgrey: [105, 105, 105], + dodgerblue: [30, 144, 255], + firebrick: [178, 34, 34], + floralwhite: [255, 250, 240], + forestgreen: [34, 139, 34], + fuchsia: [255, 0, 255], + gainsboro: [220, 220, 220], + ghostwhite: [248, 248, 255], + gold: [255, 215, 0], + goldenrod: [218, 165, 32], + gray: [128, 128, 128], + grey: [128, 128, 128], + green: [0, 128, 0], + greenyellow: [173, 255, 47], + honeydew: [240, 255, 240], + hotpink: [255, 105, 180], + indianred: [205, 92, 92], + indigo: [75, 0, 130], + ivory: [255, 255, 240], + khaki: [240, 230, 140], + lavender: [230, 230, 250], + lavenderblush: [255, 240, 245], + lawngreen: [124, 252, 0], + lemonchiffon: [255, 250, 205], + lightblue: [173, 216, 230], + lightcoral: [240, 128, 128], + lightcyan: [224, 255, 255], + lightgoldenrodyellow: [250, 250, 210], + lightgray: [211, 211, 211], + lightgreen: [144, 238, 144], + lightgrey: [211, 211, 211], + lightpink: [255, 182, 193], + lightsalmon: [255, 160, 122], + lightseagreen: [32, 178, 170], + lightskyblue: [135, 206, 250], + lightslategray: [119, 136, 153], + lightslategrey: [119, 136, 153], + lightsteelblue: [176, 196, 222], + lightyellow: [255, 255, 224], + lime: [0, 255, 0], + limegreen: [50, 205, 50], + linen: [250, 240, 230], + magenta: [255, 0, 255], + maroon: [128, 0, 0], + mediumaquamarine: [102, 205, 170], + mediumblue: [0, 0, 205], + mediumorchid: [186, 85, 211], + mediumpurple: [147, 112, 219], + mediumseagreen: [60, 179, 113], + mediumslateblue: [123, 104, 238], + mediumspringgreen: [0, 250, 154], + mediumturquoise: [72, 209, 204], + mediumvioletred: [199, 21, 133], + midnightblue: [25, 25, 112], + mintcream: [245, 255, 250], + mistyrose: [255, 228, 225], + moccasin: [255, 228, 181], + navajowhite: [255, 222, 173], + navy: [0, 0, 128], + oldlace: [253, 245, 230], + olive: [128, 128, 0], + olivedrab: [107, 142, 35], + orange: [255, 165, 0], + orangered: [255, 69, 0], + orchid: [218, 112, 214], + palegoldenrod: [238, 232, 170], + palegreen: [152, 251, 152], + paleturquoise: [175, 238, 238], + palevioletred: [219, 112, 147], + papayawhip: [255, 239, 213], + peachpuff: [255, 218, 185], + peru: [205, 133, 63], + pink: [255, 192, 203], + plum: [221, 160, 221], + powderblue: [176, 224, 230], + purple: [128, 0, 128], + red: [255, 0, 0], + rosybrown: [188, 143, 143], + royalblue: [65, 105, 225], + saddlebrown: [139, 69, 19], + salmon: [250, 128, 114], + sandybrown: [244, 164, 96], + seagreen: [46, 139, 87], + seashell: [255, 245, 238], + sienna: [160, 82, 45], + silver: [192, 192, 192], + skyblue: [135, 206, 235], + slateblue: [106, 90, 205], + slategray: [112, 128, 144], + slategrey: [112, 128, 144], + snow: [255, 250, 250], + springgreen: [0, 255, 127], + steelblue: [70, 130, 180], + tan: [210, 180, 140], + teal: [0, 128, 128], + thistle: [216, 191, 216], + tomato: [255, 99, 71], + turquoise: [64, 224, 208], + violet: [238, 130, 238], + wheat: [245, 222, 179], + white: [255, 255, 255], + whitesmoke: [245, 245, 245], + yellow: [255, 255, 0], + yellowgreen: [154, 205, 50] + }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_default_slot$2.name, - type: "slot", - source: "(72:0) ", - ctx - }); + // sets the value in a map (map may not be built) + var setMap = function setMap(options) { + var obj = options.map; + var keys = options.keys; + var l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (plainObject(key)) { + throw Error('Tried to set map with object key'); + } + if (i < keys.length - 1) { + // extend the map if necessary + if (obj[key] == null) { + obj[key] = {}; + } + obj = obj[key]; + } else { + // set the value + obj[key] = options.value; + } + } + }; - return block; + // gets the value in a map even if it's not built in places + var getMap = function getMap(options) { + var obj = options.map; + var keys = options.keys; + var l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (plainObject(key)) { + throw Error('Tried to get map with object key'); + } + obj = obj[key]; + if (obj == null) { + return obj; + } + } + return obj; + }; + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject$1(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); } - function create_fragment$g(ctx) { - let simplecollapsible; - let t0; - let hr; - let t1; - let div3; - let div0; - let t2; - let br0; - let t3; - let br1; - let t4; - let br2; - let t5; - let t6; - let div1; - let t7; - let br3; - let t8; - let br4; - let t9; - let t10; - let div2; - let t11; - let t12; - let br5; - let t13; - let current; + var isObject_1$1 = isObject$1; - simplecollapsible = new SimpleCollapsible({ - props: { - title: "Config Customisation Assistant - WIP", - $$slots: { default: [create_default_slot$2] }, - $$scope: { ctx } - }, - $$inline: true - }); + var commonjsGlobal$1 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - const block = { - c: function create() { - create_component(simplecollapsible.$$.fragment); - t0 = space(); - hr = element("hr"); - t1 = text("\r\nNext Is autogenerate + extract + llm api call for the JSON snippet + Merge in one button press + load into game component for testing + Sequence generate built into autogenerate json as an option (sequence becomes the placeholder text)\r\n\r\n"); - div3 = element("div"); - div0 = element("div"); - t2 = text("TODO - "); - br0 = element("br"); - t3 = text(" Simplify Theme Manager "); - br1 = element("br"); - t4 = text(" Fix state transition and game mechanic integration "); - br2 = element("br"); - t5 = text(" Flesh out Iframe modal gameplay eg. youtube video as an item and llm judge"); - t6 = space(); - div1 = element("div"); - t7 = text("Website = multilingual support in chrome (when running locally) "); - br3 = element("br"); - t8 = text("\r\n The mechanics here are location based so story should be location based "); - br4 = element("br"); - t9 = text("\r\n Simultaneous relationships between multiple items = complexity - eg. player location and objectives"); - t10 = space(); - div2 = element("div"); - t11 = text(/*ChangedContentPlaceholder*/ ctx[0]); - t12 = space(); - br5 = element("br"); - t13 = text("\r\n Most stories for games are about a character that lacks something to beat their problems and the 90% inbetween the begining and the end is acquiring"); - add_location(hr, file$g, 111, 0, 5275); - add_location(br0, file$g, 117, 15, 5587); - add_location(br1, file$g, 117, 43, 5615); - add_location(br2, file$g, 117, 99, 5671); - add_location(div0, file$g, 116, 4, 5565); - add_location(br3, file$g, 121, 72, 5849); - add_location(br4, file$g, 122, 80, 5935); - add_location(div1, file$g, 120, 4, 5770); - add_location(br5, file$g, 127, 38, 6113); - add_location(div2, file$g, 126, 4, 6068); - attr_dev(div3, "class", "grid-themegridContainer svelte-qg4vfk"); - add_location(div3, file$g, 114, 0, 5520); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - mount_component(simplecollapsible, target, anchor); - insert_dev(target, t0, anchor); - insert_dev(target, hr, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, div3, anchor); - append_dev(div3, div0); - append_dev(div0, t2); - append_dev(div0, br0); - append_dev(div0, t3); - append_dev(div0, br1); - append_dev(div0, t4); - append_dev(div0, br2); - append_dev(div0, t5); - append_dev(div3, t6); - append_dev(div3, div1); - append_dev(div1, t7); - append_dev(div1, br3); - append_dev(div1, t8); - append_dev(div1, br4); - append_dev(div1, t9); - append_dev(div3, t10); - append_dev(div3, div2); - append_dev(div2, t11); - append_dev(div2, t12); - append_dev(div2, br5); - append_dev(div2, t13); - current = true; - }, - p: function update(ctx, [dirty]) { - const simplecollapsible_changes = {}; + function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; + } - if (dirty & /*$$scope*/ 8192) { - simplecollapsible_changes.$$scope = { dirty, ctx }; - } + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof commonjsGlobal$1 == 'object' && commonjsGlobal$1 && commonjsGlobal$1.Object === Object && commonjsGlobal$1; - simplecollapsible.$set(simplecollapsible_changes); - if (!current || dirty & /*ChangedContentPlaceholder*/ 1) set_data_dev(t11, /*ChangedContentPlaceholder*/ ctx[0]); - }, - i: function intro(local) { - if (current) return; - transition_in(simplecollapsible.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(simplecollapsible.$$.fragment, local); - current = false; - }, - d: function destroy(detaching) { - destroy_component(simplecollapsible, detaching); - if (detaching) detach_dev(t0); - if (detaching) detach_dev(hr); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(div3); - } - }; + var _freeGlobal = freeGlobal; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$g.name, - type: "component", - source: "", - ctx - }); + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - return block; - } + /** Used as a reference to the global object. */ + var root = _freeGlobal || freeSelf || Function('return this')(); - function instance$g($$self, $$props, $$invalidate) { - let $targets; - let $objectives; - let $skills; - let $inventory; - validate_store(targets, 'targets'); - component_subscribe($$self, targets, $$value => $$invalidate(4, $targets = $$value)); - validate_store(objectives, 'objectives'); - component_subscribe($$self, objectives, $$value => $$invalidate(5, $objectives = $$value)); - validate_store(skills, 'skills'); - component_subscribe($$self, skills, $$value => $$invalidate(6, $skills = $$value)); - validate_store(inventory, 'inventory'); - component_subscribe($$self, inventory, $$value => $$invalidate(7, $inventory = $$value)); - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('MovingDotSpaceThemeManager', slots, []); - let { ChangedContentPlaceholder = "" } = $$props; - let newItem = { type: "", name: "", description: "" }; - let newSkill = { branch: "", name: "", learned: false }; - let newObjective = { branch: "", name: "", complete: false }; + var _root = root; - // ... similarly for targets - function addItem() { - inventory.update(items => [...items, newItem]); - newItem = { type: "", name: "", description: "" }; // Reset form - } + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now$1 = function() { + return _root.Date.now(); + }; - function addSkill() { - skills.update(skills => [...skills, newSkill]); - newSkill = { branch: "", name: "", learned: false }; // Reset form - } + var now_1 = now$1; - function addObjective() { - objectives.update(objectives => [...objectives, newObjective]); - newObjective = { branch: "", name: "", complete: false }; // Reset form - } + /** Used to match a single whitespace character. */ + var reWhitespace = /\s/; - // ... similarly for targets - // Functions to save and load configurations to/from localStorage or a backend would also be defined here - // Function to download the current configuration as a JSON file - function downloadConfiguration() { - const gameConfig = { - inventory: $inventory, - skills: $skills, - objectives: $objectives, - targets: $targets - }; + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the last non-whitespace character. + */ + function trimmedEndIndex(string) { + var index = string.length; - const blob = new Blob([JSON.stringify(gameConfig, null, 2)], { type: 'application/json' }); - const href = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = href; - link.download = 'gameConfig.json'; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } + while (index-- && reWhitespace.test(string.charAt(index))) {} + return index; + } - // Function to load configuration from an uploaded JSON file - function handleFileUpload(event) { - const file = event.target.files[0]; + var _trimmedEndIndex = trimmedEndIndex; - if (file) { - const reader = new FileReader(); + /** Used to match leading whitespace. */ + var reTrimStart = /^\s+/; - reader.onload = e => { - const fileContent = e.target.result; - const { inventory: loadedInventory, skills: loadedSkills, objectives: loadedObjectives, targets: loadedTargets } = JSON.parse(fileContent); - inventory.set(loadedInventory); - skills.set(loadedSkills); - objectives.set(loadedObjectives); - targets.set(loadedTargets); - alert('Configuration loaded!'); - }; + /** + * The base implementation of `_.trim`. + * + * @private + * @param {string} string The string to trim. + * @returns {string} Returns the trimmed string. + */ + function baseTrim(string) { + return string + ? string.slice(0, _trimmedEndIndex(string) + 1).replace(reTrimStart, '') + : string; + } - reader.readAsText(file); - } - } + var _baseTrim = baseTrim; - const writable_props = ['ChangedContentPlaceholder']; + /** Built-in value references. */ + var Symbol$1 = _root.Symbol; - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); + var _Symbol = Symbol$1; - $$self.$$set = $$props => { - if ('ChangedContentPlaceholder' in $$props) $$invalidate(0, ChangedContentPlaceholder = $$props.ChangedContentPlaceholder); - }; + /** Used for built-in method references. */ + var objectProto$5 = Object.prototype; - $$self.$capture_state = () => ({ - ChangedContentPlaceholder, - inventory, - skills, - objectives, - targets, - SimpleCollapsible, - BrainstormGameConfigsRandom, - BrainstormStateTransitionsRandom, - Testbrainstorminstantpopulate, - Testjsonmatchingfieldmerge, - CustomGameConfigHelper, - newItem, - newSkill, - newObjective, - addItem, - addSkill, - addObjective, - downloadConfiguration, - handleFileUpload, - $targets, - $objectives, - $skills, - $inventory - }); + /** Used to check objects for own properties. */ + var hasOwnProperty$4 = objectProto$5.hasOwnProperty; - $$self.$inject_state = $$props => { - if ('ChangedContentPlaceholder' in $$props) $$invalidate(0, ChangedContentPlaceholder = $$props.ChangedContentPlaceholder); - if ('newItem' in $$props) newItem = $$props.newItem; - if ('newSkill' in $$props) newSkill = $$props.newSkill; - if ('newObjective' in $$props) newObjective = $$props.newObjective; - }; + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString$1 = objectProto$5.toString; - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + /** Built-in value references. */ + var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined; - return [ChangedContentPlaceholder]; + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty$4.call(value, symToStringTag$1), + tag = value[symToStringTag$1]; + + try { + value[symToStringTag$1] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString$1.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$1] = tag; + } else { + delete value[symToStringTag$1]; + } + } + return result; } - class MovingDotSpaceThemeManager extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$g, create_fragment$g, safe_not_equal, { ChangedContentPlaceholder: 0 }); + var _getRawTag = getRawTag; - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "MovingDotSpaceThemeManager", - options, - id: create_fragment$g.name - }); - } + /** Used for built-in method references. */ + var objectProto$4 = Object.prototype; - get ChangedContentPlaceholder() { - throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); - } + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto$4.toString; - set ChangedContentPlaceholder(value) { - throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); - } + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); } - /* src\MovingDotSpaceGameFight.svelte generated by Svelte v3.59.2 */ - - const file$f = "src\\MovingDotSpaceGameFight.svelte"; - - // (88:8) {#if $fightcurrentTurn === 'human'} - function create_if_block$7(ctx) { - let button0; - let t1; - let button1; - let t3; - let button2; - let mounted; - let dispose; + var _objectToString = objectToString; - const block_1 = { - c: function create() { - button0 = element("button"); - button0.textContent = "Attack"; - t1 = space(); - button1 = element("button"); - button1.textContent = "Special Attack"; - t3 = space(); - button2 = element("button"); - button2.textContent = "Block"; - add_location(button0, file$f, 88, 12, 3623); - add_location(button1, file$f, 89, 12, 3730); - add_location(button2, file$f, 90, 12, 3856); - }, - m: function mount(target, anchor) { - insert_dev(target, button0, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, button1, anchor); - insert_dev(target, t3, anchor); - insert_dev(target, button2, anchor); + /** `Object#toString` result references. */ + var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; - if (!mounted) { - dispose = [ - listen_dev(button0, "click", /*click_handler*/ ctx[5], false, false, false, false), - listen_dev(button1, "click", /*click_handler_1*/ ctx[6], false, false, false, false), - listen_dev(button2, "click", /*click_handler_2*/ ctx[7], false, false, false, false) - ]; + /** Built-in value references. */ + var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined; - mounted = true; - } - }, - p: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(button0); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(button1); - if (detaching) detach_dev(t3); - if (detaching) detach_dev(button2); - mounted = false; - run_all(dispose); - } - }; + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? _getRawTag(value) + : _objectToString(value); + } - dispatch_dev("SvelteRegisterBlock", { - block: block_1, - id: create_if_block$7.name, - type: "if", - source: "(88:8) {#if $fightcurrentTurn === 'human'}", - ctx - }); + var _baseGetTag = baseGetTag; - return block_1; + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; } - function create_fragment$f(ctx) { - let div4; - let div0; - let t0; - let br0; - let t1; - let t2_value = /*$fightplayerHuman*/ ctx[1].fighthealth + ""; - let t2; - let t3; - let br1; - let t4; - let t5_value = /*$fightplayerHuman*/ ctx[1].fightstamina + ""; - let t5; - let t6; - let br2; - let t7; + var isObjectLike_1 = isObjectLike; - let t8_value = (/*$fightplayerHuman*/ ctx[1].fightisBlocking - ? 'Blocking' - : '') + ""; + /** `Object#toString` result references. */ + var symbolTag = '[object Symbol]'; - let t8; - let t9; - let br3; - let t10; - let t11_value = /*$fightplayerHuman*/ ctx[1].fightcooldowns.attack + ""; - let t11; - let t12; - let br4; - let t13; - let div2; - let div1; + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike_1(value) && _baseGetTag(value) == symbolTag); + } - let t14_value = (/*$fightcurrentTurn*/ ctx[0] === 'human' - ? "Your turn" - : "Computer's turn") + ""; + var isSymbol_1 = isSymbol; - let t14; - let t15; - let t16; - let div3; - let t17; - let br5; - let t18; - let t19_value = /*$fightplayerComputer*/ ctx[2].fighthealth + ""; - let t19; - let t20; - let br6; - let t21; - let t22_value = /*$fightplayerComputer*/ ctx[2].fightstamina + ""; - let t22; - let t23; - let br7; - let t24; + /** Used as references for various `Number` constants. */ + var NAN = 0 / 0; - let t25_value = (/*$fightplayerComputer*/ ctx[2].fightisBlocking - ? 'Blocking' - : '') + ""; + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - let t25; - let t26; - let br8; - let t27; - let t28_value = /*$fightplayerComputer*/ ctx[2].fightcooldowns.attack + ""; - let t28; - let t29; - let br9; - let if_block = /*$fightcurrentTurn*/ ctx[0] === 'human' && create_if_block$7(ctx); + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; - const block_1 = { - c: function create() { - div4 = element("div"); - div0 = element("div"); - t0 = text("Player 1 "); - br0 = element("br"); - t1 = text("\r\n Health: "); - t2 = text(t2_value); - t3 = space(); - br1 = element("br"); - t4 = text("\r\n Stamina: "); - t5 = text(t5_value); - t6 = space(); - br2 = element("br"); - t7 = space(); - t8 = text(t8_value); - t9 = space(); - br3 = element("br"); - t10 = text("\r\n Cooldown: Attack - "); - t11 = text(t11_value); - t12 = text("s "); - br4 = element("br"); - t13 = space(); - div2 = element("div"); - div1 = element("div"); - t14 = text(t14_value); - t15 = space(); - if (if_block) if_block.c(); - t16 = space(); - div3 = element("div"); - t17 = text("Player 2 "); - br5 = element("br"); - t18 = text("\r\n Health: "); - t19 = text(t19_value); - t20 = space(); - br6 = element("br"); - t21 = text("\r\n Stamina: "); - t22 = text(t22_value); - t23 = space(); - br7 = element("br"); - t24 = space(); - t25 = text(t25_value); - t26 = space(); - br8 = element("br"); - t27 = text("\r\n Cooldown: Attack - "); - t28 = text(t28_value); - t29 = text("s "); - br9 = element("br"); - add_location(br0, file$f, 76, 17, 3171); - add_location(br1, file$f, 77, 48, 3225); - add_location(br2, file$f, 78, 50, 3281); - add_location(br3, file$f, 79, 62, 3349); - add_location(br4, file$f, 80, 70, 3425); - add_location(div0, file$f, 75, 4, 3147); - add_location(div1, file$f, 84, 8, 3464); - add_location(div2, file$f, 83, 4, 3449); - add_location(br5, file$f, 95, 17, 3978); - add_location(br6, file$f, 96, 51, 4035); - add_location(br7, file$f, 97, 53, 4094); - add_location(br8, file$f, 98, 65, 4165); - add_location(br9, file$f, 99, 73, 4244); - add_location(div3, file$f, 94, 4, 3954); - attr_dev(div4, "class", "statscontainer svelte-izilsr"); - add_location(div4, file$f, 74, 0, 3113); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, div4, anchor); - append_dev(div4, div0); - append_dev(div0, t0); - append_dev(div0, br0); - append_dev(div0, t1); - append_dev(div0, t2); - append_dev(div0, t3); - append_dev(div0, br1); - append_dev(div0, t4); - append_dev(div0, t5); - append_dev(div0, t6); - append_dev(div0, br2); - append_dev(div0, t7); - append_dev(div0, t8); - append_dev(div0, t9); - append_dev(div0, br3); - append_dev(div0, t10); - append_dev(div0, t11); - append_dev(div0, t12); - append_dev(div0, br4); - append_dev(div4, t13); - append_dev(div4, div2); - append_dev(div2, div1); - append_dev(div1, t14); - append_dev(div2, t15); - if (if_block) if_block.m(div2, null); - append_dev(div4, t16); - append_dev(div4, div3); - append_dev(div3, t17); - append_dev(div3, br5); - append_dev(div3, t18); - append_dev(div3, t19); - append_dev(div3, t20); - append_dev(div3, br6); - append_dev(div3, t21); - append_dev(div3, t22); - append_dev(div3, t23); - append_dev(div3, br7); - append_dev(div3, t24); - append_dev(div3, t25); - append_dev(div3, t26); - append_dev(div3, br8); - append_dev(div3, t27); - append_dev(div3, t28); - append_dev(div3, t29); - append_dev(div3, br9); - }, - p: function update(ctx, [dirty]) { - if (dirty & /*$fightplayerHuman*/ 2 && t2_value !== (t2_value = /*$fightplayerHuman*/ ctx[1].fighthealth + "")) set_data_dev(t2, t2_value); - if (dirty & /*$fightplayerHuman*/ 2 && t5_value !== (t5_value = /*$fightplayerHuman*/ ctx[1].fightstamina + "")) set_data_dev(t5, t5_value); + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; - if (dirty & /*$fightplayerHuman*/ 2 && t8_value !== (t8_value = (/*$fightplayerHuman*/ ctx[1].fightisBlocking - ? 'Blocking' - : '') + "")) set_data_dev(t8, t8_value); + /** Built-in method references without a dependency on `root`. */ + var freeParseInt = parseInt; - if (dirty & /*$fightplayerHuman*/ 2 && t11_value !== (t11_value = /*$fightplayerHuman*/ ctx[1].fightcooldowns.attack + "")) set_data_dev(t11, t11_value); + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol_1(value)) { + return NAN; + } + if (isObject_1$1(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject_1$1(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = _baseTrim(value); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } - if (dirty & /*$fightcurrentTurn*/ 1 && t14_value !== (t14_value = (/*$fightcurrentTurn*/ ctx[0] === 'human' - ? "Your turn" - : "Computer's turn") + "")) set_data_dev(t14, t14_value); + var toNumber_1 = toNumber; - if (/*$fightcurrentTurn*/ ctx[0] === 'human') { - if (if_block) { - if_block.p(ctx, dirty); - } else { - if_block = create_if_block$7(ctx); - if_block.c(); - if_block.m(div2, null); - } - } else if (if_block) { - if_block.d(1); - if_block = null; - } + /** Error message constants. */ + var FUNC_ERROR_TEXT$1 = 'Expected a function'; - if (dirty & /*$fightplayerComputer*/ 4 && t19_value !== (t19_value = /*$fightplayerComputer*/ ctx[2].fighthealth + "")) set_data_dev(t19, t19_value); - if (dirty & /*$fightplayerComputer*/ 4 && t22_value !== (t22_value = /*$fightplayerComputer*/ ctx[2].fightstamina + "")) set_data_dev(t22, t22_value); + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeMax = Math.max, + nativeMin = Math.min; - if (dirty & /*$fightplayerComputer*/ 4 && t25_value !== (t25_value = (/*$fightplayerComputer*/ ctx[2].fightisBlocking - ? 'Blocking' - : '') + "")) set_data_dev(t25, t25_value); + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT$1); + } + wait = toNumber_1(wait) || 0; + if (isObject_1$1(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber_1(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } - if (dirty & /*$fightplayerComputer*/ 4 && t28_value !== (t28_value = /*$fightplayerComputer*/ ctx[2].fightcooldowns.attack + "")) set_data_dev(t28, t28_value); - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(div4); - if (if_block) if_block.d(); - } - }; + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; - dispatch_dev("SvelteRegisterBlock", { - block: block_1, - id: create_fragment$f.name, - type: "component", - source: "", - ctx - }); + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } - return block_1; - } + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } - function updatefightPlayer(player, changes) { - player.update(current => { - return { ...current, ...changes }; - }); - } + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; - function instance$f($$self, $$props, $$invalidate) { - let $fightcurrentTurn; - let $fightplayerHuman; - let $fightplayerComputer; - validate_store(fightcurrentTurn, 'fightcurrentTurn'); - component_subscribe($$self, fightcurrentTurn, $$value => $$invalidate(0, $fightcurrentTurn = $$value)); - validate_store(fightplayerHuman, 'fightplayerHuman'); - component_subscribe($$self, fightplayerHuman, $$value => $$invalidate(1, $fightplayerHuman = $$value)); - validate_store(fightplayerComputer, 'fightplayerComputer'); - component_subscribe($$self, fightplayerComputer, $$value => $$invalidate(2, $fightplayerComputer = $$value)); - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('MovingDotSpaceGameFight', slots, []); + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } - function switchTurn() { - fightcurrentTurn.update(turn => turn === 'human' ? 'computer' : 'human'); + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; - // Immediately after switching to computer's turn, initiate the computer's action. - if ($fightcurrentTurn === 'computer') { - setTimeout(() => computerAction(), 1000); // Simulate thinking delay for the computer's turn - } - } + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } - function performAttack(attacker, defender, attackType = 'normal') { - //fightcurrentTurn.update(turn => { - if ($fightcurrentTurn === 'human' && attacker === fightplayerHuman || $fightcurrentTurn === 'computer' && attacker === fightplayerComputer) { - // Perform attack logic here - attacker.update(a => { - if (a.fightstamina < 20 || a.fightcooldowns.attack > 0) { - return a; // Not enough stamina or attack is on cooldown - } + function timerExpired() { + var time = now_1(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } - defender.update(d => { - if (!d.fightisBlocking) { - d.fighthealth -= attackType === 'normal' ? 10 : 25; // Special attack does more damage - } + function trailingEdge(time) { + timerId = undefined; - return d; - }); + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } - return { - ...a, - fightstamina: a.fightstamina - 20, - fightcooldowns: { - ...a.fightcooldowns, - attack: attackType === 'normal' ? 1 : 3 - }, // Cooldown in seconds - - }; - }); + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } - // Start cooldown timer - setTimeout( - () => { - attacker.update(a => { - return { - ...a, - fightcooldowns: { ...a.fightcooldowns, attack: 0 } - }; - }); - }, - attackType === 'normal' ? 1000 : 3000 - ); // Cooldown period - } + function flush() { + return timerId === undefined ? result : trailingEdge(now_1()); + } - switchTurn(); - } + function debounced() { + var time = now_1(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + clearTimeout(timerId); + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } - function block(player) { - if ($fightcurrentTurn === 'human' && player === fightplayerHuman || $fightcurrentTurn === 'computer' && player === fightplayerComputer) { - // Perform block logic here - updatefightPlayer(player, { fightisBlocking: true }); + var debounce_1 = debounce; - setTimeout( - () => { - updatefightPlayer(player, { fightisBlocking: false }); - }, - 1000 - ); // Unblock after 1 second - } + var performance$1 = _window ? _window.performance : null; + var pnow = performance$1 && performance$1.now ? function () { + return performance$1.now(); + } : function () { + return Date.now(); + }; + var raf = function () { + if (_window) { + if (_window.requestAnimationFrame) { + return function (fn) { + _window.requestAnimationFrame(fn); + }; + } else if (_window.mozRequestAnimationFrame) { + return function (fn) { + _window.mozRequestAnimationFrame(fn); + }; + } else if (_window.webkitRequestAnimationFrame) { + return function (fn) { + _window.webkitRequestAnimationFrame(fn); + }; + } else if (_window.msRequestAnimationFrame) { + return function (fn) { + _window.msRequestAnimationFrame(fn); + }; + } + } + return function (fn) { + if (fn) { + setTimeout(function () { + fn(pnow()); + }, 1000 / 60); + } + }; + }(); + var requestAnimationFrame$1 = function requestAnimationFrame(fn) { + return raf(fn); + }; + var performanceNow = pnow; + + var DEFAULT_HASH_SEED = 9261; + var K = 65599; // 37 also works pretty well + var DEFAULT_HASH_SEED_ALT = 5381; + var hashIterableInts = function hashIterableInts(iterator) { + var seed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_HASH_SEED; + // sdbm/string-hash + var hash = seed; + var entry; + for (;;) { + entry = iterator.next(); + if (entry.done) { + break; + } + hash = hash * K + entry.value | 0; + } + return hash; + }; + var hashInt = function hashInt(num) { + var seed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_HASH_SEED; + // sdbm/string-hash + return seed * K + num | 0; + }; + var hashIntAlt = function hashIntAlt(num) { + var seed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_HASH_SEED_ALT; + // djb2/string-hash + return (seed << 5) + seed + num | 0; + }; + var combineHashes = function combineHashes(hash1, hash2) { + return hash1 * 0x200000 + hash2; + }; + var combineHashesArray = function combineHashesArray(hashes) { + return hashes[0] * 0x200000 + hashes[1]; + }; + var hashArrays = function hashArrays(hashes1, hashes2) { + return [hashInt(hashes1[0], hashes2[0]), hashIntAlt(hashes1[1], hashes2[1])]; + }; + var hashIntsArray = function hashIntsArray(ints, seed) { + var entry = { + value: 0, + done: false + }; + var i = 0; + var length = ints.length; + var iterator = { + next: function next() { + if (i < length) { + entry.value = ints[i++]; + } else { + entry.done = true; + } + return entry; + } + }; + return hashIterableInts(iterator, seed); + }; + var hashString = function hashString(str, seed) { + var entry = { + value: 0, + done: false + }; + var i = 0; + var length = str.length; + var iterator = { + next: function next() { + if (i < length) { + entry.value = str.charCodeAt(i++); + } else { + entry.done = true; + } + return entry; + } + }; + return hashIterableInts(iterator, seed); + }; + var hashStrings = function hashStrings() { + return hashStringsArray(arguments); + }; + var hashStringsArray = function hashStringsArray(strs) { + var hash; + for (var i = 0; i < strs.length; i++) { + var str = strs[i]; + if (i === 0) { + hash = hashString(str); + } else { + hash = hashString(str, hash); + } + } + return hash; + }; - switchTurn(); - } + /*global console */ + var warningsEnabled = true; + var warnSupported = console.warn != null; // eslint-disable-line no-console + var traceSupported = console.trace != null; // eslint-disable-line no-console - function computerAction() { - // Simple AI: Choose to attack or block randomly - const action = Math.random() > 0.4 ? 'attack' : 'block'; + var MAX_INT$1 = Number.MAX_SAFE_INTEGER || 9007199254740991; + var trueify = function trueify() { + return true; + }; + var falsify = function falsify() { + return false; + }; + var zeroify = function zeroify() { + return 0; + }; + var noop$1 = function noop() {}; + var error = function error(msg) { + throw new Error(msg); + }; + var warnings = function warnings(enabled) { + if (enabled !== undefined) { + warningsEnabled = !!enabled; + } else { + return warningsEnabled; + } + }; + var warn = function warn(msg) { + /* eslint-disable no-console */ + if (!warnings()) { + return; + } + if (warnSupported) { + console.warn(msg); + } else { + console.log(msg); + if (traceSupported) { + console.trace(); + } + } + }; /* eslint-enable */ - if (action === 'attack') { - performAttack(fightplayerComputer, fightplayerHuman); - } else { - block(fightplayerComputer); - } - } //switchTurn(); // Return control to the human player + var clone = function clone(obj) { + return extend$1({}, obj); + }; - const writable_props = []; + // gets a shallow copy of the argument + var copy = function copy(obj) { + if (obj == null) { + return obj; + } + if (array(obj)) { + return obj.slice(); + } else if (plainObject(obj)) { + return clone(obj); + } else { + return obj; + } + }; + var copyArray$1 = function copyArray(arr) { + return arr.slice(); + }; + var uuid = function uuid(a, b /* placeholders */) { + for ( + // loop :) + b = a = ''; + // b - result , a - numeric letiable + a++ < 36; + // + b += a * 51 & 52 // if "a" is not 9 or 14 or 19 or 24 + ? + // return a random number or 4 + (a ^ 15 // if "a" is not 15 + ? + // generate a random number from 0 to 15 + 8 ^ Math.random() * (a ^ 20 ? 16 : 4) // unless "a" is 20, in which case a random number from 8 to 11 + : 4 // otherwise 4 + ).toString(16) : '-' // in other cases (if "a" is 9,14,19,24) insert "-" + ) { + } + return b; + }; + var _staticEmptyObject = {}; + var staticEmptyObject = function staticEmptyObject() { + return _staticEmptyObject; + }; + var defaults$g = function defaults(_defaults) { + var keys = Object.keys(_defaults); + return function (opts) { + var filledOpts = {}; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var optVal = opts == null ? undefined : opts[key]; + filledOpts[key] = optVal === undefined ? _defaults[key] : optVal; + } + return filledOpts; + }; + }; + var removeFromArray = function removeFromArray(arr, ele, oneCopy) { + for (var i = arr.length - 1; i >= 0; i--) { + if (arr[i] === ele) { + arr.splice(i, 1); + if (oneCopy) { + break; + } + } + } + }; + var clearArray = function clearArray(arr) { + arr.splice(0, arr.length); + }; + var push = function push(arr, otherArr) { + for (var i = 0; i < otherArr.length; i++) { + var el = otherArr[i]; + arr.push(el); + } + }; + var getPrefixedProperty = function getPrefixedProperty(obj, propName, prefix) { + if (prefix) { + propName = prependCamel(prefix, propName); // e.g. (labelWidth, source) => sourceLabelWidth + } - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); + return obj[propName]; + }; + var setPrefixedProperty = function setPrefixedProperty(obj, propName, prefix, value) { + if (prefix) { + propName = prependCamel(prefix, propName); // e.g. (labelWidth, source) => sourceLabelWidth + } - const click_handler = () => performAttack(fightplayerHuman, fightplayerComputer); - const click_handler_1 = () => performAttack(fightplayerHuman, fightplayerComputer, 'special'); - const click_handler_2 = () => block(fightplayerHuman); + obj[propName] = value; + }; - $$self.$capture_state = () => ({ - fightplayerHuman, - fightplayerComputer, - fightcurrentTurn, - switchTurn, - updatefightPlayer, - performAttack, - block, - computerAction, - $fightcurrentTurn, - $fightplayerHuman, - $fightplayerComputer - }); + /* global Map */ + var ObjectMap = /*#__PURE__*/function () { + function ObjectMap() { + _classCallCheck(this, ObjectMap); + this._obj = {}; + } + _createClass(ObjectMap, [{ + key: "set", + value: function set(key, val) { + this._obj[key] = val; + return this; + } + }, { + key: "delete", + value: function _delete(key) { + this._obj[key] = undefined; + return this; + } + }, { + key: "clear", + value: function clear() { + this._obj = {}; + } + }, { + key: "has", + value: function has(key) { + return this._obj[key] !== undefined; + } + }, { + key: "get", + value: function get(key) { + return this._obj[key]; + } + }]); + return ObjectMap; + }(); + var Map$2 = typeof Map !== 'undefined' ? Map : ObjectMap; + + /* global Set */ + + var undef = "undefined" ; + var ObjectSet = /*#__PURE__*/function () { + function ObjectSet(arrayOrObjectSet) { + _classCallCheck(this, ObjectSet); + this._obj = Object.create(null); + this.size = 0; + if (arrayOrObjectSet != null) { + var arr; + if (arrayOrObjectSet.instanceString != null && arrayOrObjectSet.instanceString() === this.instanceString()) { + arr = arrayOrObjectSet.toArray(); + } else { + arr = arrayOrObjectSet; + } + for (var i = 0; i < arr.length; i++) { + this.add(arr[i]); + } + } + } + _createClass(ObjectSet, [{ + key: "instanceString", + value: function instanceString() { + return 'set'; + } + }, { + key: "add", + value: function add(val) { + var o = this._obj; + if (o[val] !== 1) { + o[val] = 1; + this.size++; + } + } + }, { + key: "delete", + value: function _delete(val) { + var o = this._obj; + if (o[val] === 1) { + o[val] = 0; + this.size--; + } + } + }, { + key: "clear", + value: function clear() { + this._obj = Object.create(null); + } + }, { + key: "has", + value: function has(val) { + return this._obj[val] === 1; + } + }, { + key: "toArray", + value: function toArray() { + var _this = this; + return Object.keys(this._obj).filter(function (key) { + return _this.has(key); + }); + } + }, { + key: "forEach", + value: function forEach(callback, thisArg) { + return this.toArray().forEach(callback, thisArg); + } + }]); + return ObjectSet; + }(); + var Set$1 = (typeof Set === "undefined" ? "undefined" : _typeof(Set)) !== undef ? Set : ObjectSet; + + // represents a node or an edge + var Element = function Element(cy, params) { + var restore = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + if (cy === undefined || params === undefined || !core$1(cy)) { + error('An element must have a core reference and parameters set'); + return; + } + var group = params.group; + + // try to automatically infer the group if unspecified + if (group == null) { + if (params.data && params.data.source != null && params.data.target != null) { + group = 'edges'; + } else { + group = 'nodes'; + } + } - return [ - $fightcurrentTurn, - $fightplayerHuman, - $fightplayerComputer, - performAttack, - block, - click_handler, - click_handler_1, - click_handler_2 - ]; - } + // validate group + if (group !== 'nodes' && group !== 'edges') { + error('An element must be of type `nodes` or `edges`; you specified `' + group + '`'); + return; + } - class MovingDotSpaceGameFight extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$f, create_fragment$f, safe_not_equal, {}); + // make the element array-like, just like a collection + this.length = 1; + this[0] = this; + + // NOTE: when something is added here, add also to ele.json() + var _p = this._private = { + cy: cy, + single: true, + // indicates this is an element + data: params.data || {}, + // data object + position: params.position || { + x: 0, + y: 0 + }, + // (x, y) position pair + autoWidth: undefined, + // width and height of nodes calculated by the renderer when set to special 'auto' value + autoHeight: undefined, + autoPadding: undefined, + compoundBoundsClean: false, + // whether the compound dimensions need to be recalculated the next time dimensions are read + listeners: [], + // array of bound listeners + group: group, + // string; 'nodes' or 'edges' + style: {}, + // properties as set by the style + rstyle: {}, + // properties for style sent from the renderer to the core + styleCxts: [], + // applied style contexts from the styler + styleKeys: {}, + // per-group keys of style property values + removed: true, + // whether it's inside the vis; true if removed (set true here since we call restore) + selected: params.selected ? true : false, + // whether it's selected + selectable: params.selectable === undefined ? true : params.selectable ? true : false, + // whether it's selectable + locked: params.locked ? true : false, + // whether the element is locked (cannot be moved) + grabbed: false, + // whether the element is grabbed by the mouse; renderer sets this privately + grabbable: params.grabbable === undefined ? true : params.grabbable ? true : false, + // whether the element can be grabbed + pannable: params.pannable === undefined ? group === 'edges' ? true : false : params.pannable ? true : false, + // whether the element has passthrough panning enabled + active: false, + // whether the element is active from user interaction + classes: new Set$1(), + // map ( className => true ) + animation: { + // object for currently-running animations + current: [], + queue: [] + }, + rscratch: {}, + // object in which the renderer can store information + scratch: params.scratch || {}, + // scratch objects + edges: [], + // array of connected edges + children: [], + // array of children + parent: params.parent && params.parent.isNode() ? params.parent : null, + // parent ref + traversalCache: {}, + // cache of output of traversal functions + backgrounding: false, + // whether background images are loading + bbCache: null, + // cache of the current bounding box + bbCacheShift: { + x: 0, + y: 0 + }, + // shift applied to cached bb to be applied on next get + bodyBounds: null, + // bounds cache of element body, w/o overlay + overlayBounds: null, + // bounds cache of element body, including overlay + labelBounds: { + // bounds cache of labels + all: null, + source: null, + target: null, + main: null + }, + arrowBounds: { + // bounds cache of edge arrows + source: null, + target: null, + 'mid-source': null, + 'mid-target': null + } + }; + if (_p.position.x == null) { + _p.position.x = 0; + } + if (_p.position.y == null) { + _p.position.y = 0; + } - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "MovingDotSpaceGameFight", - options, - id: create_fragment$f.name - }); - } - } + // renderedPosition overrides if specified + if (params.renderedPosition) { + var rpos = params.renderedPosition; + var pan = cy.pan(); + var zoom = cy.zoom(); + _p.position = { + x: (rpos.x - pan.x) / zoom, + y: (rpos.y - pan.y) / zoom + }; + } + var classes = []; + if (array(params.classes)) { + classes = params.classes; + } else if (string(params.classes)) { + classes = params.classes.split(/\s+/); + } + for (var i = 0, l = classes.length; i < l; i++) { + var cls = classes[i]; + if (!cls || cls === '') { + continue; + } + _p.classes.add(cls); + } + this.createEmitter(); + var bypass = params.style || params.css; + if (bypass) { + warn('Setting a `style` bypass at element creation should be done only when absolutely necessary. Try to use the stylesheet instead.'); + this.style(bypass); + } + if (restore === undefined || restore) { + this.restore(); + } + }; - /** - * @license - * Copyright 2010-2022 Three.js Authors - * SPDX-License-Identifier: MIT - */ - const REVISION = '145'; - const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; - const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; - const CullFaceNone = 0; - const CullFaceBack = 1; - const CullFaceFront = 2; - const CullFaceFrontBack = 3; - const BasicShadowMap = 0; - const PCFShadowMap = 1; - const PCFSoftShadowMap = 2; - const VSMShadowMap = 3; - const FrontSide = 0; - const BackSide = 1; - const DoubleSide = 2; - const NoBlending = 0; - const NormalBlending = 1; - const AdditiveBlending = 2; - const SubtractiveBlending = 3; - const MultiplyBlending = 4; - const CustomBlending = 5; - const AddEquation = 100; - const SubtractEquation = 101; - const ReverseSubtractEquation = 102; - const MinEquation = 103; - const MaxEquation = 104; - const ZeroFactor = 200; - const OneFactor = 201; - const SrcColorFactor = 202; - const OneMinusSrcColorFactor = 203; - const SrcAlphaFactor = 204; - const OneMinusSrcAlphaFactor = 205; - const DstAlphaFactor = 206; - const OneMinusDstAlphaFactor = 207; - const DstColorFactor = 208; - const OneMinusDstColorFactor = 209; - const SrcAlphaSaturateFactor = 210; - const NeverDepth = 0; - const AlwaysDepth = 1; - const LessDepth = 2; - const LessEqualDepth = 3; - const EqualDepth = 4; - const GreaterEqualDepth = 5; - const GreaterDepth = 6; - const NotEqualDepth = 7; - const MultiplyOperation = 0; - const MixOperation = 1; - const AddOperation = 2; - const NoToneMapping = 0; - const LinearToneMapping = 1; - const ReinhardToneMapping = 2; - const CineonToneMapping = 3; - const ACESFilmicToneMapping = 4; - const CustomToneMapping = 5; + var defineSearch = function defineSearch(params) { + params = { + bfs: params.bfs || !params.dfs, + dfs: params.dfs || !params.bfs + }; + + // from pseudocode on wikipedia + return function searchFn(roots, fn, directed) { + var options; + if (plainObject(roots) && !elementOrCollection(roots)) { + options = roots; + roots = options.roots || options.root; + fn = options.visit; + directed = options.directed; + } + directed = arguments.length === 2 && !fn$6(fn) ? fn : directed; + fn = fn$6(fn) ? fn : function () {}; + var cy = this._private.cy; + var v = roots = string(roots) ? this.filter(roots) : roots; + var Q = []; + var connectedNodes = []; + var connectedBy = {}; + var id2depth = {}; + var V = {}; + var j = 0; + var found; + var _this$byGroup = this.byGroup(), + nodes = _this$byGroup.nodes, + edges = _this$byGroup.edges; + + // enqueue v + for (var i = 0; i < v.length; i++) { + var vi = v[i]; + var viId = vi.id(); + if (vi.isNode()) { + Q.unshift(vi); + if (params.bfs) { + V[viId] = true; + connectedNodes.push(vi); + } + id2depth[viId] = 0; + } + } + var _loop = function _loop() { + var v = params.bfs ? Q.shift() : Q.pop(); + var vId = v.id(); + if (params.dfs) { + if (V[vId]) { + return "continue"; + } + V[vId] = true; + connectedNodes.push(v); + } + var depth = id2depth[vId]; + var prevEdge = connectedBy[vId]; + var src = prevEdge != null ? prevEdge.source() : null; + var tgt = prevEdge != null ? prevEdge.target() : null; + var prevNode = prevEdge == null ? undefined : v.same(src) ? tgt[0] : src[0]; + var ret = void 0; + ret = fn(v, prevEdge, prevNode, j++, depth); + if (ret === true) { + found = v; + return "break"; + } + if (ret === false) { + return "break"; + } + var vwEdges = v.connectedEdges().filter(function (e) { + return (!directed || e.source().same(v)) && edges.has(e); + }); + for (var _i2 = 0; _i2 < vwEdges.length; _i2++) { + var e = vwEdges[_i2]; + var w = e.connectedNodes().filter(function (n) { + return !n.same(v) && nodes.has(n); + }); + var wId = w.id(); + if (w.length !== 0 && !V[wId]) { + w = w[0]; + Q.push(w); + if (params.bfs) { + V[wId] = true; + connectedNodes.push(w); + } + connectedBy[wId] = e; + id2depth[wId] = id2depth[vId] + 1; + } + } + }; + while (Q.length !== 0) { + var _ret = _loop(); + if (_ret === "continue") continue; + if (_ret === "break") break; + } + var connectedEles = cy.collection(); + for (var _i = 0; _i < connectedNodes.length; _i++) { + var node = connectedNodes[_i]; + var edge = connectedBy[node.id()]; + if (edge != null) { + connectedEles.push(edge); + } + connectedEles.push(node); + } + return { + path: cy.collection(connectedEles), + found: cy.collection(found) + }; + }; + }; - const UVMapping = 300; - const CubeReflectionMapping = 301; - const CubeRefractionMapping = 302; - const EquirectangularReflectionMapping = 303; - const EquirectangularRefractionMapping = 304; - const CubeUVReflectionMapping = 306; - const RepeatWrapping = 1000; - const ClampToEdgeWrapping = 1001; - const MirroredRepeatWrapping = 1002; - const NearestFilter = 1003; - const NearestMipmapNearestFilter = 1004; - const NearestMipMapNearestFilter = 1004; - const NearestMipmapLinearFilter = 1005; - const NearestMipMapLinearFilter = 1005; - const LinearFilter = 1006; - const LinearMipmapNearestFilter = 1007; - const LinearMipMapNearestFilter = 1007; - const LinearMipmapLinearFilter = 1008; - const LinearMipMapLinearFilter = 1008; - const UnsignedByteType = 1009; - const ByteType = 1010; - const ShortType = 1011; - const UnsignedShortType = 1012; - const IntType = 1013; - const UnsignedIntType = 1014; - const FloatType = 1015; - const HalfFloatType = 1016; - const UnsignedShort4444Type = 1017; - const UnsignedShort5551Type = 1018; - const UnsignedInt248Type = 1020; - const AlphaFormat = 1021; - const RGBFormat = 1022; // @deprecated since r137 - const RGBAFormat = 1023; - const LuminanceFormat = 1024; - const LuminanceAlphaFormat = 1025; - const DepthFormat = 1026; - const DepthStencilFormat = 1027; - const RedFormat = 1028; - const RedIntegerFormat = 1029; - const RGFormat = 1030; - const RGIntegerFormat = 1031; - const RGBAIntegerFormat = 1033; + // search, spanning trees, etc + var elesfn$v = { + breadthFirstSearch: defineSearch({ + bfs: true + }), + depthFirstSearch: defineSearch({ + dfs: true + }) + }; - const RGB_S3TC_DXT1_Format = 33776; - const RGBA_S3TC_DXT1_Format = 33777; - const RGBA_S3TC_DXT3_Format = 33778; - const RGBA_S3TC_DXT5_Format = 33779; - const RGB_PVRTC_4BPPV1_Format = 35840; - const RGB_PVRTC_2BPPV1_Format = 35841; - const RGBA_PVRTC_4BPPV1_Format = 35842; - const RGBA_PVRTC_2BPPV1_Format = 35843; - const RGB_ETC1_Format = 36196; - const RGB_ETC2_Format = 37492; - const RGBA_ETC2_EAC_Format = 37496; - const RGBA_ASTC_4x4_Format = 37808; - const RGBA_ASTC_5x4_Format = 37809; - const RGBA_ASTC_5x5_Format = 37810; - const RGBA_ASTC_6x5_Format = 37811; - const RGBA_ASTC_6x6_Format = 37812; - const RGBA_ASTC_8x5_Format = 37813; - const RGBA_ASTC_8x6_Format = 37814; - const RGBA_ASTC_8x8_Format = 37815; - const RGBA_ASTC_10x5_Format = 37816; - const RGBA_ASTC_10x6_Format = 37817; - const RGBA_ASTC_10x8_Format = 37818; - const RGBA_ASTC_10x10_Format = 37819; - const RGBA_ASTC_12x10_Format = 37820; - const RGBA_ASTC_12x12_Format = 37821; - const RGBA_BPTC_Format = 36492; - const LoopOnce = 2200; - const LoopRepeat = 2201; - const LoopPingPong = 2202; - const InterpolateDiscrete = 2300; - const InterpolateLinear = 2301; - const InterpolateSmooth = 2302; - const ZeroCurvatureEnding = 2400; - const ZeroSlopeEnding = 2401; - const WrapAroundEnding = 2402; - const NormalAnimationBlendMode = 2500; - const AdditiveAnimationBlendMode = 2501; - const TrianglesDrawMode = 0; - const TriangleStripDrawMode = 1; - const TriangleFanDrawMode = 2; - const LinearEncoding = 3000; - const sRGBEncoding = 3001; - const BasicDepthPacking = 3200; - const RGBADepthPacking = 3201; - const TangentSpaceNormalMap = 0; - const ObjectSpaceNormalMap = 1; + // nice, short mathematical alias + elesfn$v.bfs = elesfn$v.breadthFirstSearch; + elesfn$v.dfs = elesfn$v.depthFirstSearch; - // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. - const NoColorSpace = ''; - const SRGBColorSpace = 'srgb'; - const LinearSRGBColorSpace = 'srgb-linear'; + var heap$1 = createCommonjsModule(function (module, exports) { + // Generated by CoffeeScript 1.8.0 + (function() { + var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, updateItem, _siftdown, _siftup; - const ZeroStencilOp = 0; - const KeepStencilOp = 7680; - const ReplaceStencilOp = 7681; - const IncrementStencilOp = 7682; - const DecrementStencilOp = 7683; - const IncrementWrapStencilOp = 34055; - const DecrementWrapStencilOp = 34056; - const InvertStencilOp = 5386; + floor = Math.floor, min = Math.min; - const NeverStencilFunc = 512; - const LessStencilFunc = 513; - const EqualStencilFunc = 514; - const LessEqualStencilFunc = 515; - const GreaterStencilFunc = 516; - const NotEqualStencilFunc = 517; - const GreaterEqualStencilFunc = 518; - const AlwaysStencilFunc = 519; - const StaticDrawUsage = 35044; - const DynamicDrawUsage = 35048; - const StreamDrawUsage = 35040; - const StaticReadUsage = 35045; - const DynamicReadUsage = 35049; - const StreamReadUsage = 35041; - const StaticCopyUsage = 35046; - const DynamicCopyUsage = 35050; - const StreamCopyUsage = 35042; + /* + Default comparison function to be used + */ - const GLSL1 = '100'; - const GLSL3 = '300 es'; + defaultCmp = function(x, y) { + if (x < y) { + return -1; + } + if (x > y) { + return 1; + } + return 0; + }; + + + /* + Insert item x in list a, and keep it sorted assuming a is sorted. + + If x is already in a, insert it to the right of the rightmost x. + + Optional args lo (default 0) and hi (default a.length) bound the slice + of a to be searched. + */ + + insort = function(a, x, lo, hi, cmp) { + var mid; + if (lo == null) { + lo = 0; + } + if (cmp == null) { + cmp = defaultCmp; + } + if (lo < 0) { + throw new Error('lo must be non-negative'); + } + if (hi == null) { + hi = a.length; + } + while (lo < hi) { + mid = floor((lo + hi) / 2); + if (cmp(x, a[mid]) < 0) { + hi = mid; + } else { + lo = mid + 1; + } + } + return ([].splice.apply(a, [lo, lo - lo].concat(x)), x); + }; - const _SRGBAFormat = 1035; // fallback for WebGL 1 - /** - * https://github.com/mrdoob/eventdispatcher.js/ - */ + /* + Push item onto heap, maintaining the heap invariant. + */ - class EventDispatcher { + heappush = function(array, item, cmp) { + if (cmp == null) { + cmp = defaultCmp; + } + array.push(item); + return _siftdown(array, 0, array.length - 1, cmp); + }; - addEventListener( type, listener ) { - if ( this._listeners === undefined ) this._listeners = {}; + /* + Pop the smallest item off the heap, maintaining the heap invariant. + */ - const listeners = this._listeners; + heappop = function(array, cmp) { + var lastelt, returnitem; + if (cmp == null) { + cmp = defaultCmp; + } + lastelt = array.pop(); + if (array.length) { + returnitem = array[0]; + array[0] = lastelt; + _siftup(array, 0, cmp); + } else { + returnitem = lastelt; + } + return returnitem; + }; + + + /* + Pop and return the current smallest value, and add the new item. + + This is more efficient than heappop() followed by heappush(), and can be + more appropriate when using a fixed size heap. Note that the value + returned may be larger than item! That constrains reasonable use of + this routine unless written as part of a conditional replacement: + if item > array[0] + item = heapreplace(array, item) + */ + + heapreplace = function(array, item, cmp) { + var returnitem; + if (cmp == null) { + cmp = defaultCmp; + } + returnitem = array[0]; + array[0] = item; + _siftup(array, 0, cmp); + return returnitem; + }; - if ( listeners[ type ] === undefined ) { - listeners[ type ] = []; + /* + Fast version of a heappush followed by a heappop. + */ - } + heappushpop = function(array, item, cmp) { + var _ref; + if (cmp == null) { + cmp = defaultCmp; + } + if (array.length && cmp(array[0], item) < 0) { + _ref = [array[0], item], item = _ref[0], array[0] = _ref[1]; + _siftup(array, 0, cmp); + } + return item; + }; - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - listeners[ type ].push( listener ); + /* + Transform list into a heap, in-place, in O(array.length) time. + */ - } + heapify = function(array, cmp) { + var i, _i, _len, _ref1, _results, _results1; + if (cmp == null) { + cmp = defaultCmp; + } + _ref1 = (function() { + _results1 = []; + for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--){ _results1.push(_j); } + return _results1; + }).apply(this).reverse(); + _results = []; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + i = _ref1[_i]; + _results.push(_siftup(array, i, cmp)); + } + return _results; + }; - } - hasEventListener( type, listener ) { + /* + Update the position of the given item in the heap. + This function should be called every time the item is being modified. + */ - if ( this._listeners === undefined ) return false; + updateItem = function(array, item, cmp) { + var pos; + if (cmp == null) { + cmp = defaultCmp; + } + pos = array.indexOf(item); + if (pos === -1) { + return; + } + _siftdown(array, 0, pos, cmp); + return _siftup(array, pos, cmp); + }; - const listeners = this._listeners; - return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; + /* + Find the n largest elements in a dataset. + */ - } + nlargest = function(array, n, cmp) { + var elem, result, _i, _len, _ref; + if (cmp == null) { + cmp = defaultCmp; + } + result = array.slice(0, n); + if (!result.length) { + return result; + } + heapify(result, cmp); + _ref = array.slice(n); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + elem = _ref[_i]; + heappushpop(result, elem, cmp); + } + return result.sort(cmp).reverse(); + }; - removeEventListener( type, listener ) { - if ( this._listeners === undefined ) return; + /* + Find the n smallest elements in a dataset. + */ - const listeners = this._listeners; - const listenerArray = listeners[ type ]; + nsmallest = function(array, n, cmp) { + var elem, los, result, _i, _j, _len, _ref, _ref1, _results; + if (cmp == null) { + cmp = defaultCmp; + } + if (n * 10 <= array.length) { + result = array.slice(0, n).sort(cmp); + if (!result.length) { + return result; + } + los = result[result.length - 1]; + _ref = array.slice(n); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + elem = _ref[_i]; + if (cmp(elem, los) < 0) { + insort(result, elem, 0, null, cmp); + result.pop(); + los = result[result.length - 1]; + } + } + return result; + } + heapify(array, cmp); + _results = []; + for (_j = 0, _ref1 = min(n, array.length); 0 <= _ref1 ? _j < _ref1 : _j > _ref1; 0 <= _ref1 ? ++_j : --_j) { + _results.push(heappop(array, cmp)); + } + return _results; + }; - if ( listenerArray !== undefined ) { + _siftdown = function(array, startpos, pos, cmp) { + var newitem, parent, parentpos; + if (cmp == null) { + cmp = defaultCmp; + } + newitem = array[pos]; + while (pos > startpos) { + parentpos = (pos - 1) >> 1; + parent = array[parentpos]; + if (cmp(newitem, parent) < 0) { + array[pos] = parent; + pos = parentpos; + continue; + } + break; + } + return array[pos] = newitem; + }; - const index = listenerArray.indexOf( listener ); + _siftup = function(array, pos, cmp) { + var childpos, endpos, newitem, rightpos, startpos; + if (cmp == null) { + cmp = defaultCmp; + } + endpos = array.length; + startpos = pos; + newitem = array[pos]; + childpos = 2 * pos + 1; + while (childpos < endpos) { + rightpos = childpos + 1; + if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) { + childpos = rightpos; + } + array[pos] = array[childpos]; + pos = childpos; + childpos = 2 * pos + 1; + } + array[pos] = newitem; + return _siftdown(array, startpos, pos, cmp); + }; - if ( index !== - 1 ) { + Heap = (function() { + Heap.push = heappush; - listenerArray.splice( index, 1 ); + Heap.pop = heappop; - } + Heap.replace = heapreplace; - } + Heap.pushpop = heappushpop; - } + Heap.heapify = heapify; - dispatchEvent( event ) { + Heap.updateItem = updateItem; - if ( this._listeners === undefined ) return; + Heap.nlargest = nlargest; - const listeners = this._listeners; - const listenerArray = listeners[ event.type ]; + Heap.nsmallest = nsmallest; - if ( listenerArray !== undefined ) { + function Heap(cmp) { + this.cmp = cmp != null ? cmp : defaultCmp; + this.nodes = []; + } - event.target = this; + Heap.prototype.push = function(x) { + return heappush(this.nodes, x, this.cmp); + }; - // Make a copy, in case listeners are removed while iterating. - const array = listenerArray.slice( 0 ); + Heap.prototype.pop = function() { + return heappop(this.nodes, this.cmp); + }; - for ( let i = 0, l = array.length; i < l; i ++ ) { + Heap.prototype.peek = function() { + return this.nodes[0]; + }; - array[ i ].call( this, event ); + Heap.prototype.contains = function(x) { + return this.nodes.indexOf(x) !== -1; + }; - } + Heap.prototype.replace = function(x) { + return heapreplace(this.nodes, x, this.cmp); + }; - event.target = null; + Heap.prototype.pushpop = function(x) { + return heappushpop(this.nodes, x, this.cmp); + }; - } + Heap.prototype.heapify = function() { + return heapify(this.nodes, this.cmp); + }; - } + Heap.prototype.updateItem = function(x) { + return updateItem(this.nodes, x, this.cmp); + }; - } + Heap.prototype.clear = function() { + return this.nodes = []; + }; - const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; + Heap.prototype.empty = function() { + return this.nodes.length === 0; + }; - let _seed = 1234567; + Heap.prototype.size = function() { + return this.nodes.length; + }; + Heap.prototype.clone = function() { + var heap; + heap = new Heap(); + heap.nodes = this.nodes.slice(0); + return heap; + }; - const DEG2RAD = Math.PI / 180; - const RAD2DEG = 180 / Math.PI; + Heap.prototype.toArray = function() { + return this.nodes.slice(0); + }; - // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 - function generateUUID() { + Heap.prototype.insert = Heap.prototype.push; - const d0 = Math.random() * 0xffffffff | 0; - const d1 = Math.random() * 0xffffffff | 0; - const d2 = Math.random() * 0xffffffff | 0; - const d3 = Math.random() * 0xffffffff | 0; - const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + - _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + - _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + - _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; + Heap.prototype.top = Heap.prototype.peek; - // .toLowerCase() here flattens concatenated strings to save heap memory space. - return uuid.toLowerCase(); + Heap.prototype.front = Heap.prototype.peek; - } + Heap.prototype.has = Heap.prototype.contains; - function clamp( value, min, max ) { + Heap.prototype.copy = Heap.prototype.clone; - return Math.max( min, Math.min( max, value ) ); + return Heap; - } + })(); - // compute euclidean modulo of m % n - // https://en.wikipedia.org/wiki/Modulo_operation - function euclideanModulo( n, m ) { + (function(root, factory) { + { + return module.exports = factory(); + } + })(this, function() { + return Heap; + }); - return ( ( n % m ) + m ) % m; + }).call(commonjsGlobal$1); + }); - } + var heap = heap$1; - // Linear mapping from range to range - function mapLinear( x, a1, a2, b1, b2 ) { + var dijkstraDefaults = defaults$g({ + root: null, + weight: function weight(edge) { + return 1; + }, + directed: false + }); + var elesfn$u = { + dijkstra: function dijkstra(options) { + if (!plainObject(options)) { + var args = arguments; + options = { + root: args[0], + weight: args[1], + directed: args[2] + }; + } + var _dijkstraDefaults = dijkstraDefaults(options), + root = _dijkstraDefaults.root, + weight = _dijkstraDefaults.weight, + directed = _dijkstraDefaults.directed; + var eles = this; + var weightFn = weight; + var source = string(root) ? this.filter(root)[0] : root[0]; + var dist = {}; + var prev = {}; + var knownDist = {}; + var _this$byGroup = this.byGroup(), + nodes = _this$byGroup.nodes, + edges = _this$byGroup.edges; + edges.unmergeBy(function (ele) { + return ele.isLoop(); + }); + var getDist = function getDist(node) { + return dist[node.id()]; + }; + var setDist = function setDist(node, d) { + dist[node.id()] = d; + Q.updateItem(node); + }; + var Q = new heap(function (a, b) { + return getDist(a) - getDist(b); + }); + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + dist[node.id()] = node.same(source) ? 0 : Infinity; + Q.push(node); + } + var distBetween = function distBetween(u, v) { + var uvs = (directed ? u.edgesTo(v) : u.edgesWith(v)).intersect(edges); + var smallestDistance = Infinity; + var smallestEdge; + for (var _i = 0; _i < uvs.length; _i++) { + var edge = uvs[_i]; + var _weight = weightFn(edge); + if (_weight < smallestDistance || !smallestEdge) { + smallestDistance = _weight; + smallestEdge = edge; + } + } + return { + edge: smallestEdge, + dist: smallestDistance + }; + }; + while (Q.size() > 0) { + var u = Q.pop(); + var smalletsDist = getDist(u); + var uid = u.id(); + knownDist[uid] = smalletsDist; + if (smalletsDist === Infinity) { + continue; + } + var neighbors = u.neighborhood().intersect(nodes); + for (var _i2 = 0; _i2 < neighbors.length; _i2++) { + var v = neighbors[_i2]; + var vid = v.id(); + var vDist = distBetween(u, v); + var alt = smalletsDist + vDist.dist; + if (alt < getDist(v)) { + setDist(v, alt); + prev[vid] = { + node: u, + edge: vDist.edge + }; + } + } // for + } // while + + return { + distanceTo: function distanceTo(node) { + var target = string(node) ? nodes.filter(node)[0] : node[0]; + return knownDist[target.id()]; + }, + pathTo: function pathTo(node) { + var target = string(node) ? nodes.filter(node)[0] : node[0]; + var S = []; + var u = target; + var uid = u.id(); + if (target.length > 0) { + S.unshift(target); + while (prev[uid]) { + var p = prev[uid]; + S.unshift(p.edge); + S.unshift(p.node); + u = p.node; + uid = u.id(); + } + } + return eles.spawn(S); + } + }; + } + }; - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + var elesfn$t = { + // kruskal's algorithm (finds min spanning tree, assuming undirected graph) + // implemented from pseudocode from wikipedia + kruskal: function kruskal(weightFn) { + weightFn = weightFn || function (edge) { + return 1; + }; + var _this$byGroup = this.byGroup(), + nodes = _this$byGroup.nodes, + edges = _this$byGroup.edges; + var numNodes = nodes.length; + var forest = new Array(numNodes); + var A = nodes; // assumes byGroup() creates new collections that can be safely mutated + + var findSetIndex = function findSetIndex(ele) { + for (var i = 0; i < forest.length; i++) { + var eles = forest[i]; + if (eles.has(ele)) { + return i; + } + } + }; - } + // start with one forest per node + for (var i = 0; i < numNodes; i++) { + forest[i] = this.spawn(nodes[i]); + } + var S = edges.sort(function (a, b) { + return weightFn(a) - weightFn(b); + }); + for (var _i = 0; _i < S.length; _i++) { + var edge = S[_i]; + var u = edge.source()[0]; + var v = edge.target()[0]; + var setUIndex = findSetIndex(u); + var setVIndex = findSetIndex(v); + var setU = forest[setUIndex]; + var setV = forest[setVIndex]; + if (setUIndex !== setVIndex) { + A.merge(edge); + + // combine forests for u and v + setU.merge(setV); + forest.splice(setVIndex, 1); + } + } + return A; + } + }; - // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ - function inverseLerp( x, y, value ) { + var aStarDefaults = defaults$g({ + root: null, + goal: null, + weight: function weight(edge) { + return 1; + }, + heuristic: function heuristic(edge) { + return 0; + }, + directed: false + }); + var elesfn$s = { + // Implemented from pseudocode from wikipedia + aStar: function aStar(options) { + var cy = this.cy(); + var _aStarDefaults = aStarDefaults(options), + root = _aStarDefaults.root, + goal = _aStarDefaults.goal, + heuristic = _aStarDefaults.heuristic, + directed = _aStarDefaults.directed, + weight = _aStarDefaults.weight; + root = cy.collection(root)[0]; + goal = cy.collection(goal)[0]; + var sid = root.id(); + var tid = goal.id(); + var gScore = {}; + var fScore = {}; + var closedSetIds = {}; + var openSet = new heap(function (a, b) { + return fScore[a.id()] - fScore[b.id()]; + }); + var openSetIds = new Set$1(); + var cameFrom = {}; + var cameFromEdge = {}; + var addToOpenSet = function addToOpenSet(ele, id) { + openSet.push(ele); + openSetIds.add(id); + }; + var cMin, cMinId; + var popFromOpenSet = function popFromOpenSet() { + cMin = openSet.pop(); + cMinId = cMin.id(); + openSetIds["delete"](cMinId); + }; + var isInOpenSet = function isInOpenSet(id) { + return openSetIds.has(id); + }; + addToOpenSet(root, sid); + gScore[sid] = 0; + fScore[sid] = heuristic(root); + + // Counter + var steps = 0; + + // Main loop + while (openSet.size() > 0) { + popFromOpenSet(); + steps++; + + // If we've found our goal, then we are done + if (cMinId === tid) { + var path = []; + var pathNode = goal; + var pathNodeId = tid; + var pathEdge = cameFromEdge[pathNodeId]; + for (;;) { + path.unshift(pathNode); + if (pathEdge != null) { + path.unshift(pathEdge); + } + pathNode = cameFrom[pathNodeId]; + if (pathNode == null) { + break; + } + pathNodeId = pathNode.id(); + pathEdge = cameFromEdge[pathNodeId]; + } + return { + found: true, + distance: gScore[cMinId], + path: this.spawn(path), + steps: steps + }; + } - if ( x !== y ) { + // Add cMin to processed nodes + closedSetIds[cMinId] = true; - return ( value - x ) / ( y - x ); + // Update scores for neighbors of cMin + // Take into account if graph is directed or not + var vwEdges = cMin._private.edges; + for (var i = 0; i < vwEdges.length; i++) { + var e = vwEdges[i]; - } else { + // edge must be in set of calling eles + if (!this.hasElementWithId(e.id())) { + continue; + } - return 0; + // cMin must be the source of edge if directed + if (directed && e.data('source') !== cMinId) { + continue; + } + var wSrc = e.source(); + var wTgt = e.target(); + var w = wSrc.id() !== cMinId ? wSrc : wTgt; + var wid = w.id(); + + // node must be in set of calling eles + if (!this.hasElementWithId(wid)) { + continue; + } - } + // if node is in closedSet, ignore it + if (closedSetIds[wid]) { + continue; + } - } + // New tentative score for node w + var tempScore = gScore[cMinId] + weight(e); + + // Update gScore for node w if: + // w not present in openSet + // OR + // tentative gScore is less than previous value + + // w not in openSet + if (!isInOpenSet(wid)) { + gScore[wid] = tempScore; + fScore[wid] = tempScore + heuristic(w); + addToOpenSet(w, wid); + cameFrom[wid] = cMin; + cameFromEdge[wid] = e; + continue; + } - // https://en.wikipedia.org/wiki/Linear_interpolation - function lerp( x, y, t ) { + // w already in openSet, but with greater gScore + if (tempScore < gScore[wid]) { + gScore[wid] = tempScore; + fScore[wid] = tempScore + heuristic(w); + cameFrom[wid] = cMin; + cameFromEdge[wid] = e; + } + } // End of neighbors update + } // End of main loop + + // If we've reached here, then we've not reached our goal + return { + found: false, + distance: undefined, + path: undefined, + steps: steps + }; + } + }; // elesfn - return ( 1 - t ) * x + t * y; + var floydWarshallDefaults = defaults$g({ + weight: function weight(edge) { + return 1; + }, + directed: false + }); + var elesfn$r = { + // Implemented from pseudocode from wikipedia + floydWarshall: function floydWarshall(options) { + var cy = this.cy(); + var _floydWarshallDefault = floydWarshallDefaults(options), + weight = _floydWarshallDefault.weight, + directed = _floydWarshallDefault.directed; + var weightFn = weight; + var _this$byGroup = this.byGroup(), + nodes = _this$byGroup.nodes, + edges = _this$byGroup.edges; + var N = nodes.length; + var Nsq = N * N; + var indexOf = function indexOf(node) { + return nodes.indexOf(node); + }; + var atIndex = function atIndex(i) { + return nodes[i]; + }; - } + // Initialize distance matrix + var dist = new Array(Nsq); + for (var n = 0; n < Nsq; n++) { + var j = n % N; + var i = (n - j) / N; + if (i === j) { + dist[n] = 0; + } else { + dist[n] = Infinity; + } + } - // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ - function damp( x, y, lambda, dt ) { + // Initialize matrix used for path reconstruction + // Initialize distance matrix + var next = new Array(Nsq); + var edgeNext = new Array(Nsq); + + // Process edges + for (var _i = 0; _i < edges.length; _i++) { + var edge = edges[_i]; + var src = edge.source()[0]; + var tgt = edge.target()[0]; + if (src === tgt) { + continue; + } // exclude loops + + var s = indexOf(src); + var t = indexOf(tgt); + var st = s * N + t; // source to target index + var _weight = weightFn(edge); + + // Check if already process another edge between same 2 nodes + if (dist[st] > _weight) { + dist[st] = _weight; + next[st] = t; + edgeNext[st] = edge; + } + + // If undirected graph, process 'reversed' edge + if (!directed) { + var ts = t * N + s; // target to source index + + if (!directed && dist[ts] > _weight) { + dist[ts] = _weight; + next[ts] = s; + edgeNext[ts] = edge; + } + } + } - return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); + // Main loop + for (var k = 0; k < N; k++) { + for (var _i2 = 0; _i2 < N; _i2++) { + var ik = _i2 * N + k; + for (var _j = 0; _j < N; _j++) { + var ij = _i2 * N + _j; + var kj = k * N + _j; + if (dist[ik] + dist[kj] < dist[ij]) { + dist[ij] = dist[ik] + dist[kj]; + next[ij] = next[ik]; + } + } + } + } + var getArgEle = function getArgEle(ele) { + return (string(ele) ? cy.filter(ele) : ele)[0]; + }; + var indexOfArgEle = function indexOfArgEle(ele) { + return indexOf(getArgEle(ele)); + }; + var res = { + distance: function distance(from, to) { + var i = indexOfArgEle(from); + var j = indexOfArgEle(to); + return dist[i * N + j]; + }, + path: function path(from, to) { + var i = indexOfArgEle(from); + var j = indexOfArgEle(to); + var fromNode = atIndex(i); + if (i === j) { + return fromNode.collection(); + } + if (next[i * N + j] == null) { + return cy.collection(); + } + var path = cy.collection(); + var prev = i; + var edge; + path.merge(fromNode); + while (i !== j) { + prev = i; + i = next[i * N + j]; + edge = edgeNext[prev * N + i]; + path.merge(edge); + path.merge(atIndex(i)); + } + return path; + } + }; + return res; + } // floydWarshall + }; // elesfn + + var bellmanFordDefaults = defaults$g({ + weight: function weight(edge) { + return 1; + }, + directed: false, + root: null + }); + var elesfn$q = { + // Implemented from pseudocode from wikipedia + bellmanFord: function bellmanFord(options) { + var _this = this; + var _bellmanFordDefaults = bellmanFordDefaults(options), + weight = _bellmanFordDefaults.weight, + directed = _bellmanFordDefaults.directed, + root = _bellmanFordDefaults.root; + var weightFn = weight; + var eles = this; + var cy = this.cy(); + var _this$byGroup = this.byGroup(), + edges = _this$byGroup.edges, + nodes = _this$byGroup.nodes; + var numNodes = nodes.length; + var infoMap = new Map$2(); + var hasNegativeWeightCycle = false; + var negativeWeightCycles = []; + root = cy.collection(root)[0]; // in case selector passed + + edges.unmergeBy(function (edge) { + return edge.isLoop(); + }); + var numEdges = edges.length; + var getInfo = function getInfo(node) { + var obj = infoMap.get(node.id()); + if (!obj) { + obj = {}; + infoMap.set(node.id(), obj); + } + return obj; + }; + var getNodeFromTo = function getNodeFromTo(to) { + return (string(to) ? cy.$(to) : to)[0]; + }; + var distanceTo = function distanceTo(to) { + return getInfo(getNodeFromTo(to)).dist; + }; + var pathTo = function pathTo(to) { + var thisStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : root; + var end = getNodeFromTo(to); + var path = []; + var node = end; + for (;;) { + if (node == null) { + return _this.spawn(); + } + var _getInfo = getInfo(node), + edge = _getInfo.edge, + pred = _getInfo.pred; + path.unshift(node[0]); + if (node.same(thisStart) && path.length > 0) { + break; + } + if (edge != null) { + path.unshift(edge); + } + node = pred; + } + return eles.spawn(path); + }; - } + // Initializations { dist, pred, edge } + for (var i = 0; i < numNodes; i++) { + var node = nodes[i]; + var info = getInfo(node); + if (node.same(root)) { + info.dist = 0; + } else { + info.dist = Infinity; + } + info.pred = null; + info.edge = null; + } - // https://www.desmos.com/calculator/vcsjnyz7x4 - function pingpong( x, length = 1 ) { + // Edges relaxation + var replacedEdge = false; + var checkForEdgeReplacement = function checkForEdgeReplacement(node1, node2, edge, info1, info2, weight) { + var dist = info1.dist + weight; + if (dist < info2.dist && !edge.same(info1.edge)) { + info2.dist = dist; + info2.pred = node1; + info2.edge = edge; + replacedEdge = true; + } + }; + for (var _i = 1; _i < numNodes; _i++) { + replacedEdge = false; + for (var e = 0; e < numEdges; e++) { + var edge = edges[e]; + var src = edge.source(); + var tgt = edge.target(); + var _weight = weightFn(edge); + var srcInfo = getInfo(src); + var tgtInfo = getInfo(tgt); + checkForEdgeReplacement(src, tgt, edge, srcInfo, tgtInfo, _weight); + + // If undirected graph, we need to take into account the 'reverse' edge + if (!directed) { + checkForEdgeReplacement(tgt, src, edge, tgtInfo, srcInfo, _weight); + } + } + if (!replacedEdge) { + break; + } + } + if (replacedEdge) { + // Check for negative weight cycles + var negativeWeightCycleIds = []; + for (var _e = 0; _e < numEdges; _e++) { + var _edge = edges[_e]; + var _src = _edge.source(); + var _tgt = _edge.target(); + var _weight2 = weightFn(_edge); + var srcDist = getInfo(_src).dist; + var tgtDist = getInfo(_tgt).dist; + if (srcDist + _weight2 < tgtDist || !directed && tgtDist + _weight2 < srcDist) { + if (!hasNegativeWeightCycle) { + warn('Graph contains a negative weight cycle for Bellman-Ford'); + hasNegativeWeightCycle = true; + } + if (options.findNegativeWeightCycles !== false) { + var negativeNodes = []; + if (srcDist + _weight2 < tgtDist) { + negativeNodes.push(_src); + } + if (!directed && tgtDist + _weight2 < srcDist) { + negativeNodes.push(_tgt); + } + var numNegativeNodes = negativeNodes.length; + for (var n = 0; n < numNegativeNodes; n++) { + var start = negativeNodes[n]; + var cycle = [start]; + cycle.push(getInfo(start).edge); + var _node = getInfo(start).pred; + while (cycle.indexOf(_node) === -1) { + cycle.push(_node); + cycle.push(getInfo(_node).edge); + _node = getInfo(_node).pred; + } + cycle = cycle.slice(cycle.indexOf(_node)); + var smallestId = cycle[0].id(); + var smallestIndex = 0; + for (var c = 2; c < cycle.length; c += 2) { + if (cycle[c].id() < smallestId) { + smallestId = cycle[c].id(); + smallestIndex = c; + } + } + cycle = cycle.slice(smallestIndex).concat(cycle.slice(0, smallestIndex)); + cycle.push(cycle[0]); + var cycleId = cycle.map(function (el) { + return el.id(); + }).join(","); + if (negativeWeightCycleIds.indexOf(cycleId) === -1) { + negativeWeightCycles.push(eles.spawn(cycle)); + negativeWeightCycleIds.push(cycleId); + } + } + } else { + break; + } + } + } + } + return { + distanceTo: distanceTo, + pathTo: pathTo, + hasNegativeWeightCycle: hasNegativeWeightCycle, + negativeWeightCycles: negativeWeightCycles + }; + } // bellmanFord + }; // elesfn - return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); + var sqrt2 = Math.sqrt(2); - } + // Function which colapses 2 (meta) nodes into one + // Updates the remaining edge lists + // Receives as a paramater the edge which causes the collapse + var collapse = function collapse(edgeIndex, nodeMap, remainingEdges) { + if (remainingEdges.length === 0) { + error("Karger-Stein must be run on a connected (sub)graph"); + } + var edgeInfo = remainingEdges[edgeIndex]; + var sourceIn = edgeInfo[1]; + var targetIn = edgeInfo[2]; + var partition1 = nodeMap[sourceIn]; + var partition2 = nodeMap[targetIn]; + var newEdges = remainingEdges; // re-use array + + // Delete all edges between partition1 and partition2 + for (var i = newEdges.length - 1; i >= 0; i--) { + var edge = newEdges[i]; + var src = edge[1]; + var tgt = edge[2]; + if (nodeMap[src] === partition1 && nodeMap[tgt] === partition2 || nodeMap[src] === partition2 && nodeMap[tgt] === partition1) { + newEdges.splice(i, 1); + } + } - // http://en.wikipedia.org/wiki/Smoothstep - function smoothstep( x, min, max ) { + // All edges pointing to partition2 should now point to partition1 + for (var _i = 0; _i < newEdges.length; _i++) { + var _edge = newEdges[_i]; + if (_edge[1] === partition2) { + // Check source + newEdges[_i] = _edge.slice(); // copy + newEdges[_i][1] = partition1; + } else if (_edge[2] === partition2) { + // Check target + newEdges[_i] = _edge.slice(); // copy + newEdges[_i][2] = partition1; + } + } - if ( x <= min ) return 0; - if ( x >= max ) return 1; + // Move all nodes from partition2 to partition1 + for (var _i2 = 0; _i2 < nodeMap.length; _i2++) { + if (nodeMap[_i2] === partition2) { + nodeMap[_i2] = partition1; + } + } + return newEdges; + }; - x = ( x - min ) / ( max - min ); + // Contracts a graph until we reach a certain number of meta nodes + var contractUntil = function contractUntil(metaNodeMap, remainingEdges, size, sizeLimit) { + while (size > sizeLimit) { + // Choose an edge randomly + var edgeIndex = Math.floor(Math.random() * remainingEdges.length); - return x * x * ( 3 - 2 * x ); + // Collapse graph based on edge + remainingEdges = collapse(edgeIndex, metaNodeMap, remainingEdges); + size--; + } + return remainingEdges; + }; + var elesfn$p = { + // Computes the minimum cut of an undirected graph + // Returns the correct answer with high probability + kargerStein: function kargerStein() { + var _this = this; + var _this$byGroup = this.byGroup(), + nodes = _this$byGroup.nodes, + edges = _this$byGroup.edges; + edges.unmergeBy(function (edge) { + return edge.isLoop(); + }); + var numNodes = nodes.length; + var numEdges = edges.length; + var numIter = Math.ceil(Math.pow(Math.log(numNodes) / Math.LN2, 2)); + var stopSize = Math.floor(numNodes / sqrt2); + if (numNodes < 2) { + error('At least 2 nodes are required for Karger-Stein algorithm'); + return undefined; + } - } + // Now store edge destination as indexes + // Format for each edge (edge index, source node index, target node index) + var edgeIndexes = []; + for (var i = 0; i < numEdges; i++) { + var e = edges[i]; + edgeIndexes.push([i, nodes.indexOf(e.source()), nodes.indexOf(e.target())]); + } - function smootherstep( x, min, max ) { + // We will store the best cut found here + var minCutSize = Infinity; + var minCutEdgeIndexes = []; + var minCutNodeMap = new Array(numNodes); + + // Initial meta node partition + var metaNodeMap = new Array(numNodes); + var metaNodeMap2 = new Array(numNodes); + var copyNodesMap = function copyNodesMap(from, to) { + for (var _i3 = 0; _i3 < numNodes; _i3++) { + to[_i3] = from[_i3]; + } + }; - if ( x <= min ) return 0; - if ( x >= max ) return 1; + // Main loop + for (var iter = 0; iter <= numIter; iter++) { + // Reset meta node partition + for (var _i4 = 0; _i4 < numNodes; _i4++) { + metaNodeMap[_i4] = _i4; + } + + // Contract until stop point (stopSize nodes) + var edgesState = contractUntil(metaNodeMap, edgeIndexes.slice(), numNodes, stopSize); + var edgesState2 = edgesState.slice(); // copy + + // Create a copy of the colapsed nodes state + copyNodesMap(metaNodeMap, metaNodeMap2); + + // Run 2 iterations starting in the stop state + var res1 = contractUntil(metaNodeMap, edgesState, stopSize, 2); + var res2 = contractUntil(metaNodeMap2, edgesState2, stopSize, 2); + + // Is any of the 2 results the best cut so far? + if (res1.length <= res2.length && res1.length < minCutSize) { + minCutSize = res1.length; + minCutEdgeIndexes = res1; + copyNodesMap(metaNodeMap, minCutNodeMap); + } else if (res2.length <= res1.length && res2.length < minCutSize) { + minCutSize = res2.length; + minCutEdgeIndexes = res2; + copyNodesMap(metaNodeMap2, minCutNodeMap); + } + } // end of main loop + + // Construct result + var cut = this.spawn(minCutEdgeIndexes.map(function (e) { + return edges[e[0]]; + })); + var partition1 = this.spawn(); + var partition2 = this.spawn(); + + // traverse metaNodeMap for best cut + var witnessNodePartition = minCutNodeMap[0]; + for (var _i5 = 0; _i5 < minCutNodeMap.length; _i5++) { + var partitionId = minCutNodeMap[_i5]; + var node = nodes[_i5]; + if (partitionId === witnessNodePartition) { + partition1.merge(node); + } else { + partition2.merge(node); + } + } - x = ( x - min ) / ( max - min ); + // construct components corresponding to each disjoint subset of nodes + var constructComponent = function constructComponent(subset) { + var component = _this.spawn(); + subset.forEach(function (node) { + component.merge(node); + node.connectedEdges().forEach(function (edge) { + // ensure edge is within calling collection and edge is not in cut + if (_this.contains(edge) && !cut.contains(edge)) { + component.merge(edge); + } + }); + }); + return component; + }; + var components = [constructComponent(partition1), constructComponent(partition2)]; + var ret = { + cut: cut, + components: components, + // n.b. partitions are included to be compatible with the old api spec + // (could be removed in a future major version) + partition1: partition1, + partition2: partition2 + }; + return ret; + } + }; // elesfn - return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); + var copyPosition = function copyPosition(p) { + return { + x: p.x, + y: p.y + }; + }; + var modelToRenderedPosition = function modelToRenderedPosition(p, zoom, pan) { + return { + x: p.x * zoom + pan.x, + y: p.y * zoom + pan.y + }; + }; + var renderedToModelPosition = function renderedToModelPosition(p, zoom, pan) { + return { + x: (p.x - pan.x) / zoom, + y: (p.y - pan.y) / zoom + }; + }; + var array2point = function array2point(arr) { + return { + x: arr[0], + y: arr[1] + }; + }; + var min = function min(arr) { + var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length; + var min = Infinity; + for (var i = begin; i < end; i++) { + var val = arr[i]; + if (isFinite(val)) { + min = Math.min(val, min); + } + } + return min; + }; + var max = function max(arr) { + var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length; + var max = -Infinity; + for (var i = begin; i < end; i++) { + var val = arr[i]; + if (isFinite(val)) { + max = Math.max(val, max); + } + } + return max; + }; + var mean = function mean(arr) { + var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length; + var total = 0; + var n = 0; + for (var i = begin; i < end; i++) { + var val = arr[i]; + if (isFinite(val)) { + total += val; + n++; + } + } + return total / n; + }; + var median = function median(arr) { + var begin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : arr.length; + var copy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; + var sort = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; + var includeHoles = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; + if (copy) { + arr = arr.slice(begin, end); + } else { + if (end < arr.length) { + arr.splice(end, arr.length - end); + } + if (begin > 0) { + arr.splice(0, begin); + } + } - } + // all non finite (e.g. Infinity, NaN) elements must be -Infinity so they go to the start + var off = 0; // offset from non-finite values + for (var i = arr.length - 1; i >= 0; i--) { + var v = arr[i]; + if (includeHoles) { + if (!isFinite(v)) { + arr[i] = -Infinity; + off++; + } + } else { + // just remove it if we don't want to consider holes + arr.splice(i, 1); + } + } + if (sort) { + arr.sort(function (a, b) { + return a - b; + }); // requires copy = true if you don't want to change the orig + } - // Random integer from interval - function randInt( low, high ) { + var len = arr.length; + var mid = Math.floor(len / 2); + if (len % 2 !== 0) { + return arr[mid + 1 + off]; + } else { + return (arr[mid - 1 + off] + arr[mid + off]) / 2; + } + }; + var deg2rad = function deg2rad(deg) { + return Math.PI * deg / 180; + }; + var getAngleFromDisp = function getAngleFromDisp(dispX, dispY) { + return Math.atan2(dispY, dispX) - Math.PI / 2; + }; + var log2 = Math.log2 || function (n) { + return Math.log(n) / Math.log(2); + }; + var signum = function signum(x) { + if (x > 0) { + return 1; + } else if (x < 0) { + return -1; + } else { + return 0; + } + }; + var dist = function dist(p1, p2) { + return Math.sqrt(sqdist(p1, p2)); + }; + var sqdist = function sqdist(p1, p2) { + var dx = p2.x - p1.x; + var dy = p2.y - p1.y; + return dx * dx + dy * dy; + }; + var inPlaceSumNormalize = function inPlaceSumNormalize(v) { + var length = v.length; - return low + Math.floor( Math.random() * ( high - low + 1 ) ); + // First, get sum of all elements + var total = 0; + for (var i = 0; i < length; i++) { + total += v[i]; + } - } + // Now, divide each by the sum of all elements + for (var _i = 0; _i < length; _i++) { + v[_i] = v[_i] / total; + } + return v; + }; - // Random float from interval - function randFloat( low, high ) { + // from http://en.wikipedia.org/wiki/Bézier_curve#Quadratic_curves + var qbezierAt = function qbezierAt(p0, p1, p2, t) { + return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2; + }; + var qbezierPtAt = function qbezierPtAt(p0, p1, p2, t) { + return { + x: qbezierAt(p0.x, p1.x, p2.x, t), + y: qbezierAt(p0.y, p1.y, p2.y, t) + }; + }; + var lineAt = function lineAt(p0, p1, t, d) { + var vec = { + x: p1.x - p0.x, + y: p1.y - p0.y + }; + var vecDist = dist(p0, p1); + var normVec = { + x: vec.x / vecDist, + y: vec.y / vecDist + }; + t = t == null ? 0 : t; + d = d != null ? d : t * vecDist; + return { + x: p0.x + normVec.x * d, + y: p0.y + normVec.y * d + }; + }; + var bound = function bound(min, val, max) { + return Math.max(min, Math.min(max, val)); + }; - return low + Math.random() * ( high - low ); + // makes a full bb (x1, y1, x2, y2, w, h) from implicit params + var makeBoundingBox = function makeBoundingBox(bb) { + if (bb == null) { + return { + x1: Infinity, + y1: Infinity, + x2: -Infinity, + y2: -Infinity, + w: 0, + h: 0 + }; + } else if (bb.x1 != null && bb.y1 != null) { + if (bb.x2 != null && bb.y2 != null && bb.x2 >= bb.x1 && bb.y2 >= bb.y1) { + return { + x1: bb.x1, + y1: bb.y1, + x2: bb.x2, + y2: bb.y2, + w: bb.x2 - bb.x1, + h: bb.y2 - bb.y1 + }; + } else if (bb.w != null && bb.h != null && bb.w >= 0 && bb.h >= 0) { + return { + x1: bb.x1, + y1: bb.y1, + x2: bb.x1 + bb.w, + y2: bb.y1 + bb.h, + w: bb.w, + h: bb.h + }; + } + } + }; + var copyBoundingBox = function copyBoundingBox(bb) { + return { + x1: bb.x1, + x2: bb.x2, + w: bb.w, + y1: bb.y1, + y2: bb.y2, + h: bb.h + }; + }; + var clearBoundingBox = function clearBoundingBox(bb) { + bb.x1 = Infinity; + bb.y1 = Infinity; + bb.x2 = -Infinity; + bb.y2 = -Infinity; + bb.w = 0; + bb.h = 0; + }; + var shiftBoundingBox = function shiftBoundingBox(bb, dx, dy) { + return { + x1: bb.x1 + dx, + x2: bb.x2 + dx, + y1: bb.y1 + dy, + y2: bb.y2 + dy, + w: bb.w, + h: bb.h + }; + }; + var updateBoundingBox = function updateBoundingBox(bb1, bb2) { + // update bb1 with bb2 bounds + + bb1.x1 = Math.min(bb1.x1, bb2.x1); + bb1.x2 = Math.max(bb1.x2, bb2.x2); + bb1.w = bb1.x2 - bb1.x1; + bb1.y1 = Math.min(bb1.y1, bb2.y1); + bb1.y2 = Math.max(bb1.y2, bb2.y2); + bb1.h = bb1.y2 - bb1.y1; + }; + var expandBoundingBoxByPoint = function expandBoundingBoxByPoint(bb, x, y) { + bb.x1 = Math.min(bb.x1, x); + bb.x2 = Math.max(bb.x2, x); + bb.w = bb.x2 - bb.x1; + bb.y1 = Math.min(bb.y1, y); + bb.y2 = Math.max(bb.y2, y); + bb.h = bb.y2 - bb.y1; + }; + var expandBoundingBox = function expandBoundingBox(bb) { + var padding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + bb.x1 -= padding; + bb.x2 += padding; + bb.y1 -= padding; + bb.y2 += padding; + bb.w = bb.x2 - bb.x1; + bb.h = bb.y2 - bb.y1; + return bb; + }; + var expandBoundingBoxSides = function expandBoundingBoxSides(bb) { + var padding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [0]; + var top, right, bottom, left; + if (padding.length === 1) { + top = right = bottom = left = padding[0]; + } else if (padding.length === 2) { + top = bottom = padding[0]; + left = right = padding[1]; + } else if (padding.length === 4) { + var _padding = _slicedToArray(padding, 4); + top = _padding[0]; + right = _padding[1]; + bottom = _padding[2]; + left = _padding[3]; + } + bb.x1 -= left; + bb.x2 += right; + bb.y1 -= top; + bb.y2 += bottom; + bb.w = bb.x2 - bb.x1; + bb.h = bb.y2 - bb.y1; + return bb; + }; - } + // assign the values of bb2 into bb1 + var assignBoundingBox = function assignBoundingBox(bb1, bb2) { + bb1.x1 = bb2.x1; + bb1.y1 = bb2.y1; + bb1.x2 = bb2.x2; + bb1.y2 = bb2.y2; + bb1.w = bb1.x2 - bb1.x1; + bb1.h = bb1.y2 - bb1.y1; + }; + var boundingBoxesIntersect = function boundingBoxesIntersect(bb1, bb2) { + // case: one bb to right of other + if (bb1.x1 > bb2.x2) { + return false; + } + if (bb2.x1 > bb1.x2) { + return false; + } - // Random float from <-range/2, range/2> interval - function randFloatSpread( range ) { + // case: one bb to left of other + if (bb1.x2 < bb2.x1) { + return false; + } + if (bb2.x2 < bb1.x1) { + return false; + } - return range * ( 0.5 - Math.random() ); - - } - - // Deterministic pseudo-random float in the interval [ 0, 1 ] - function seededRandom( s ) { + // case: one bb above other + if (bb1.y2 < bb2.y1) { + return false; + } + if (bb2.y2 < bb1.y1) { + return false; + } - if ( s !== undefined ) _seed = s; + // case: one bb below other + if (bb1.y1 > bb2.y2) { + return false; + } + if (bb2.y1 > bb1.y2) { + return false; + } - // Mulberry32 generator + // otherwise, must have some overlap + return true; + }; + var inBoundingBox = function inBoundingBox(bb, x, y) { + return bb.x1 <= x && x <= bb.x2 && bb.y1 <= y && y <= bb.y2; + }; + var pointInBoundingBox = function pointInBoundingBox(bb, pt) { + return inBoundingBox(bb, pt.x, pt.y); + }; + var boundingBoxInBoundingBox = function boundingBoxInBoundingBox(bb1, bb2) { + return inBoundingBox(bb1, bb2.x1, bb2.y1) && inBoundingBox(bb1, bb2.x2, bb2.y2); + }; + var roundRectangleIntersectLine = function roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding) { + var radius = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 'auto'; + var cornerRadius = radius === 'auto' ? getRoundRectangleRadius(width, height) : radius; + var halfWidth = width / 2; + var halfHeight = height / 2; + cornerRadius = Math.min(cornerRadius, halfWidth, halfHeight); + var doWidth = cornerRadius !== halfWidth, + doHeight = cornerRadius !== halfHeight; + + // Check intersections with straight line segments + var straightLineIntersections; + + // Top segment, left to right + if (doWidth) { + var topStartX = nodeX - halfWidth + cornerRadius - padding; + var topStartY = nodeY - halfHeight - padding; + var topEndX = nodeX + halfWidth - cornerRadius + padding; + var topEndY = topStartY; + straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, topStartX, topStartY, topEndX, topEndY, false); + if (straightLineIntersections.length > 0) { + return straightLineIntersections; + } + } - let t = _seed += 0x6D2B79F5; + // Right segment, top to bottom + if (doHeight) { + var rightStartX = nodeX + halfWidth + padding; + var rightStartY = nodeY - halfHeight + cornerRadius - padding; + var rightEndX = rightStartX; + var rightEndY = nodeY + halfHeight - cornerRadius + padding; + straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, rightStartX, rightStartY, rightEndX, rightEndY, false); + if (straightLineIntersections.length > 0) { + return straightLineIntersections; + } + } - t = Math.imul( t ^ t >>> 15, t | 1 ); + // Bottom segment, left to right + if (doWidth) { + var bottomStartX = nodeX - halfWidth + cornerRadius - padding; + var bottomStartY = nodeY + halfHeight + padding; + var bottomEndX = nodeX + halfWidth - cornerRadius + padding; + var bottomEndY = bottomStartY; + straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, bottomStartX, bottomStartY, bottomEndX, bottomEndY, false); + if (straightLineIntersections.length > 0) { + return straightLineIntersections; + } + } - t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); + // Left segment, top to bottom + if (doHeight) { + var leftStartX = nodeX - halfWidth - padding; + var leftStartY = nodeY - halfHeight + cornerRadius - padding; + var leftEndX = leftStartX; + var leftEndY = nodeY + halfHeight - cornerRadius + padding; + straightLineIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, leftStartX, leftStartY, leftEndX, leftEndY, false); + if (straightLineIntersections.length > 0) { + return straightLineIntersections; + } + } - return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; + // Check intersections with arc segments + var arcIntersections; - } + // Top Left + { + var topLeftCenterX = nodeX - halfWidth + cornerRadius; + var topLeftCenterY = nodeY - halfHeight + cornerRadius; + arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, topLeftCenterX, topLeftCenterY, cornerRadius + padding); - function degToRad( degrees ) { + // Ensure the intersection is on the desired quarter of the circle + if (arcIntersections.length > 0 && arcIntersections[0] <= topLeftCenterX && arcIntersections[1] <= topLeftCenterY) { + return [arcIntersections[0], arcIntersections[1]]; + } + } - return degrees * DEG2RAD; + // Top Right + { + var topRightCenterX = nodeX + halfWidth - cornerRadius; + var topRightCenterY = nodeY - halfHeight + cornerRadius; + arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, topRightCenterX, topRightCenterY, cornerRadius + padding); - } + // Ensure the intersection is on the desired quarter of the circle + if (arcIntersections.length > 0 && arcIntersections[0] >= topRightCenterX && arcIntersections[1] <= topRightCenterY) { + return [arcIntersections[0], arcIntersections[1]]; + } + } - function radToDeg( radians ) { + // Bottom Right + { + var bottomRightCenterX = nodeX + halfWidth - cornerRadius; + var bottomRightCenterY = nodeY + halfHeight - cornerRadius; + arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, bottomRightCenterX, bottomRightCenterY, cornerRadius + padding); - return radians * RAD2DEG; + // Ensure the intersection is on the desired quarter of the circle + if (arcIntersections.length > 0 && arcIntersections[0] >= bottomRightCenterX && arcIntersections[1] >= bottomRightCenterY) { + return [arcIntersections[0], arcIntersections[1]]; + } + } - } + // Bottom Left + { + var bottomLeftCenterX = nodeX - halfWidth + cornerRadius; + var bottomLeftCenterY = nodeY + halfHeight - cornerRadius; + arcIntersections = intersectLineCircle(x, y, nodeX, nodeY, bottomLeftCenterX, bottomLeftCenterY, cornerRadius + padding); - function isPowerOfTwo( value ) { + // Ensure the intersection is on the desired quarter of the circle + if (arcIntersections.length > 0 && arcIntersections[0] <= bottomLeftCenterX && arcIntersections[1] >= bottomLeftCenterY) { + return [arcIntersections[0], arcIntersections[1]]; + } + } + return []; // if nothing + }; - return ( value & ( value - 1 ) ) === 0 && value !== 0; + var inLineVicinity = function inLineVicinity(x, y, lx1, ly1, lx2, ly2, tolerance) { + var t = tolerance; + var x1 = Math.min(lx1, lx2); + var x2 = Math.max(lx1, lx2); + var y1 = Math.min(ly1, ly2); + var y2 = Math.max(ly1, ly2); + return x1 - t <= x && x <= x2 + t && y1 - t <= y && y <= y2 + t; + }; + var inBezierVicinity = function inBezierVicinity(x, y, x1, y1, x2, y2, x3, y3, tolerance) { + var bb = { + x1: Math.min(x1, x3, x2) - tolerance, + x2: Math.max(x1, x3, x2) + tolerance, + y1: Math.min(y1, y3, y2) - tolerance, + y2: Math.max(y1, y3, y2) + tolerance + }; + + // if outside the rough bounding box for the bezier, then it can't be a hit + if (x < bb.x1 || x > bb.x2 || y < bb.y1 || y > bb.y2) { + // console.log('bezier out of rough bb') + return false; + } else { + // console.log('do more expensive check'); + return true; + } + }; + var solveQuadratic = function solveQuadratic(a, b, c, val) { + c -= val; + var r = b * b - 4 * a * c; + if (r < 0) { + return []; + } + var sqrtR = Math.sqrt(r); + var denom = 2 * a; + var root1 = (-b + sqrtR) / denom; + var root2 = (-b - sqrtR) / denom; + return [root1, root2]; + }; + var solveCubic = function solveCubic(a, b, c, d, result) { + // Solves a cubic function, returns root in form [r1, i1, r2, i2, r3, i3], where + // r is the real component, i is the imaginary component - } + // An implementation of the Cardano method from the year 1545 + // http://en.wikipedia.org/wiki/Cubic_function#The_nature_of_the_roots - function ceilPowerOfTwo( value ) { + var epsilon = 0.00001; - return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); + // avoid division by zero while keeping the overall expression close in value + if (a === 0) { + a = epsilon; + } + b /= a; + c /= a; + d /= a; + var discriminant, q, r, dum1, s, t, term1, r13; + q = (3.0 * c - b * b) / 9.0; + r = -(27.0 * d) + b * (9.0 * c - 2.0 * (b * b)); + r /= 54.0; + discriminant = q * q * q + r * r; + result[1] = 0; + term1 = b / 3.0; + if (discriminant > 0) { + s = r + Math.sqrt(discriminant); + s = s < 0 ? -Math.pow(-s, 1.0 / 3.0) : Math.pow(s, 1.0 / 3.0); + t = r - Math.sqrt(discriminant); + t = t < 0 ? -Math.pow(-t, 1.0 / 3.0) : Math.pow(t, 1.0 / 3.0); + result[0] = -term1 + s + t; + term1 += (s + t) / 2.0; + result[4] = result[2] = -term1; + term1 = Math.sqrt(3.0) * (-t + s) / 2; + result[3] = term1; + result[5] = -term1; + return; + } + result[5] = result[3] = 0; + if (discriminant === 0) { + r13 = r < 0 ? -Math.pow(-r, 1.0 / 3.0) : Math.pow(r, 1.0 / 3.0); + result[0] = -term1 + 2.0 * r13; + result[4] = result[2] = -(r13 + term1); + return; + } + q = -q; + dum1 = q * q * q; + dum1 = Math.acos(r / Math.sqrt(dum1)); + r13 = 2.0 * Math.sqrt(q); + result[0] = -term1 + r13 * Math.cos(dum1 / 3.0); + result[2] = -term1 + r13 * Math.cos((dum1 + 2.0 * Math.PI) / 3.0); + result[4] = -term1 + r13 * Math.cos((dum1 + 4.0 * Math.PI) / 3.0); + return; + }; + var sqdistToQuadraticBezier = function sqdistToQuadraticBezier(x, y, x1, y1, x2, y2, x3, y3) { + // Find minimum distance by using the minimum of the distance + // function between the given point and the curve + + // This gives the coefficients of the resulting cubic equation + // whose roots tell us where a possible minimum is + // (Coefficients are divided by 4) + + var a = 1.0 * x1 * x1 - 4 * x1 * x2 + 2 * x1 * x3 + 4 * x2 * x2 - 4 * x2 * x3 + x3 * x3 + y1 * y1 - 4 * y1 * y2 + 2 * y1 * y3 + 4 * y2 * y2 - 4 * y2 * y3 + y3 * y3; + var b = 1.0 * 9 * x1 * x2 - 3 * x1 * x1 - 3 * x1 * x3 - 6 * x2 * x2 + 3 * x2 * x3 + 9 * y1 * y2 - 3 * y1 * y1 - 3 * y1 * y3 - 6 * y2 * y2 + 3 * y2 * y3; + var c = 1.0 * 3 * x1 * x1 - 6 * x1 * x2 + x1 * x3 - x1 * x + 2 * x2 * x2 + 2 * x2 * x - x3 * x + 3 * y1 * y1 - 6 * y1 * y2 + y1 * y3 - y1 * y + 2 * y2 * y2 + 2 * y2 * y - y3 * y; + var d = 1.0 * x1 * x2 - x1 * x1 + x1 * x - x2 * x + y1 * y2 - y1 * y1 + y1 * y - y2 * y; + + // debug("coefficients: " + a / a + ", " + b / a + ", " + c / a + ", " + d / a); + + var roots = []; + + // Use the cubic solving algorithm + solveCubic(a, b, c, d, roots); + var zeroThreshold = 0.0000001; + var params = []; + for (var index = 0; index < 6; index += 2) { + if (Math.abs(roots[index + 1]) < zeroThreshold && roots[index] >= 0 && roots[index] <= 1.0) { + params.push(roots[index]); + } + } + params.push(1.0); + params.push(0.0); + var minDistanceSquared = -1; + var curX, curY, distSquared; + for (var i = 0; i < params.length; i++) { + curX = Math.pow(1.0 - params[i], 2.0) * x1 + 2.0 * (1 - params[i]) * params[i] * x2 + params[i] * params[i] * x3; + curY = Math.pow(1 - params[i], 2.0) * y1 + 2 * (1.0 - params[i]) * params[i] * y2 + params[i] * params[i] * y3; + distSquared = Math.pow(curX - x, 2) + Math.pow(curY - y, 2); + // debug('distance for param ' + params[i] + ": " + Math.sqrt(distSquared)); + if (minDistanceSquared >= 0) { + if (distSquared < minDistanceSquared) { + minDistanceSquared = distSquared; + } + } else { + minDistanceSquared = distSquared; + } + } + return minDistanceSquared; + }; + var sqdistToFiniteLine = function sqdistToFiniteLine(x, y, x1, y1, x2, y2) { + var offset = [x - x1, y - y1]; + var line = [x2 - x1, y2 - y1]; + var lineSq = line[0] * line[0] + line[1] * line[1]; + var hypSq = offset[0] * offset[0] + offset[1] * offset[1]; + var dotProduct = offset[0] * line[0] + offset[1] * line[1]; + var adjSq = dotProduct * dotProduct / lineSq; + if (dotProduct < 0) { + return hypSq; + } + if (adjSq > lineSq) { + return (x - x2) * (x - x2) + (y - y2) * (y - y2); + } + return hypSq - adjSq; + }; + var pointInsidePolygonPoints = function pointInsidePolygonPoints(x, y, points) { + var x1, y1, x2, y2; + var y3; + + // Intersect with vertical line through (x, y) + var up = 0; + // let down = 0; + for (var i = 0; i < points.length / 2; i++) { + x1 = points[i * 2]; + y1 = points[i * 2 + 1]; + if (i + 1 < points.length / 2) { + x2 = points[(i + 1) * 2]; + y2 = points[(i + 1) * 2 + 1]; + } else { + x2 = points[(i + 1 - points.length / 2) * 2]; + y2 = points[(i + 1 - points.length / 2) * 2 + 1]; + } + if (x1 == x && x2 == x) ; else if (x1 >= x && x >= x2 || x1 <= x && x <= x2) { + y3 = (x - x1) / (x2 - x1) * (y2 - y1) + y1; + if (y3 > y) { + up++; + } + + // if( y3 < y ){ + // down++; + // } + } else { + continue; + } + } + if (up % 2 === 0) { + return false; + } else { + return true; + } + }; + var pointInsidePolygon = function pointInsidePolygon(x, y, basePoints, centerX, centerY, width, height, direction, padding) { + var transformedPoints = new Array(basePoints.length); + + // Gives negative angle + var angle; + if (direction[0] != null) { + angle = Math.atan(direction[1] / direction[0]); + if (direction[0] < 0) { + angle = angle + Math.PI / 2; + } else { + angle = -angle - Math.PI / 2; + } + } else { + angle = direction; + } + var cos = Math.cos(-angle); + var sin = Math.sin(-angle); + + // console.log("base: " + basePoints); + for (var i = 0; i < transformedPoints.length / 2; i++) { + transformedPoints[i * 2] = width / 2 * (basePoints[i * 2] * cos - basePoints[i * 2 + 1] * sin); + transformedPoints[i * 2 + 1] = height / 2 * (basePoints[i * 2 + 1] * cos + basePoints[i * 2] * sin); + transformedPoints[i * 2] += centerX; + transformedPoints[i * 2 + 1] += centerY; + } + var points; + if (padding > 0) { + var expandedLineSet = expandPolygon(transformedPoints, -padding); + points = joinLines(expandedLineSet); + } else { + points = transformedPoints; + } + return pointInsidePolygonPoints(x, y, points); + }; + var pointInsideRoundPolygon = function pointInsideRoundPolygon(x, y, basePoints, centerX, centerY, width, height, corners) { + var cutPolygonPoints = new Array(basePoints.length * 2); + for (var i = 0; i < corners.length; i++) { + var corner = corners[i]; + cutPolygonPoints[i * 4 + 0] = corner.startX; + cutPolygonPoints[i * 4 + 1] = corner.startY; + cutPolygonPoints[i * 4 + 2] = corner.stopX; + cutPolygonPoints[i * 4 + 3] = corner.stopY; + var squaredDistance = Math.pow(corner.cx - x, 2) + Math.pow(corner.cy - y, 2); + if (squaredDistance <= Math.pow(corner.radius, 2)) { + return true; + } + } + return pointInsidePolygonPoints(x, y, cutPolygonPoints); + }; + var joinLines = function joinLines(lineSet) { + var vertices = new Array(lineSet.length / 2); + var currentLineStartX, currentLineStartY, currentLineEndX, currentLineEndY; + var nextLineStartX, nextLineStartY, nextLineEndX, nextLineEndY; + for (var i = 0; i < lineSet.length / 4; i++) { + currentLineStartX = lineSet[i * 4]; + currentLineStartY = lineSet[i * 4 + 1]; + currentLineEndX = lineSet[i * 4 + 2]; + currentLineEndY = lineSet[i * 4 + 3]; + if (i < lineSet.length / 4 - 1) { + nextLineStartX = lineSet[(i + 1) * 4]; + nextLineStartY = lineSet[(i + 1) * 4 + 1]; + nextLineEndX = lineSet[(i + 1) * 4 + 2]; + nextLineEndY = lineSet[(i + 1) * 4 + 3]; + } else { + nextLineStartX = lineSet[0]; + nextLineStartY = lineSet[1]; + nextLineEndX = lineSet[2]; + nextLineEndY = lineSet[3]; + } + var intersection = finiteLinesIntersect(currentLineStartX, currentLineStartY, currentLineEndX, currentLineEndY, nextLineStartX, nextLineStartY, nextLineEndX, nextLineEndY, true); + vertices[i * 2] = intersection[0]; + vertices[i * 2 + 1] = intersection[1]; + } + return vertices; + }; + var expandPolygon = function expandPolygon(points, pad) { + var expandedLineSet = new Array(points.length * 2); + var currentPointX, currentPointY, nextPointX, nextPointY; + for (var i = 0; i < points.length / 2; i++) { + currentPointX = points[i * 2]; + currentPointY = points[i * 2 + 1]; + if (i < points.length / 2 - 1) { + nextPointX = points[(i + 1) * 2]; + nextPointY = points[(i + 1) * 2 + 1]; + } else { + nextPointX = points[0]; + nextPointY = points[1]; + } - } + // Current line: [currentPointX, currentPointY] to [nextPointX, nextPointY] - function floorPowerOfTwo( value ) { + // Assume CCW polygon winding - return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); + var offsetX = nextPointY - currentPointY; + var offsetY = -(nextPointX - currentPointX); - } + // Normalize + var offsetLength = Math.sqrt(offsetX * offsetX + offsetY * offsetY); + var normalizedOffsetX = offsetX / offsetLength; + var normalizedOffsetY = offsetY / offsetLength; + expandedLineSet[i * 4] = currentPointX + normalizedOffsetX * pad; + expandedLineSet[i * 4 + 1] = currentPointY + normalizedOffsetY * pad; + expandedLineSet[i * 4 + 2] = nextPointX + normalizedOffsetX * pad; + expandedLineSet[i * 4 + 3] = nextPointY + normalizedOffsetY * pad; + } + return expandedLineSet; + }; + var intersectLineEllipse = function intersectLineEllipse(x, y, centerX, centerY, ellipseWradius, ellipseHradius) { + var dispX = centerX - x; + var dispY = centerY - y; + dispX /= ellipseWradius; + dispY /= ellipseHradius; + var len = Math.sqrt(dispX * dispX + dispY * dispY); + var newLength = len - 1; + if (newLength < 0) { + return []; + } + var lenProportion = newLength / len; + return [(centerX - x) * lenProportion + x, (centerY - y) * lenProportion + y]; + }; + var checkInEllipse = function checkInEllipse(x, y, width, height, centerX, centerY, padding) { + x -= centerX; + y -= centerY; + x /= width / 2 + padding; + y /= height / 2 + padding; + return x * x + y * y <= 1; + }; - function setQuaternionFromProperEuler( q, a, b, c, order ) { + // Returns intersections of increasing distance from line's start point + var intersectLineCircle = function intersectLineCircle(x1, y1, x2, y2, centerX, centerY, radius) { + // Calculate d, direction vector of line + var d = [x2 - x1, y2 - y1]; // Direction vector of line + var f = [x1 - centerX, y1 - centerY]; + var a = d[0] * d[0] + d[1] * d[1]; + var b = 2 * (f[0] * d[0] + f[1] * d[1]); + var c = f[0] * f[0] + f[1] * f[1] - radius * radius; + var discriminant = b * b - 4 * a * c; + if (discriminant < 0) { + return []; + } + var t1 = (-b + Math.sqrt(discriminant)) / (2 * a); + var t2 = (-b - Math.sqrt(discriminant)) / (2 * a); + var tMin = Math.min(t1, t2); + var tMax = Math.max(t1, t2); + var inRangeParams = []; + if (tMin >= 0 && tMin <= 1) { + inRangeParams.push(tMin); + } + if (tMax >= 0 && tMax <= 1) { + inRangeParams.push(tMax); + } + if (inRangeParams.length === 0) { + return []; + } + var nearIntersectionX = inRangeParams[0] * d[0] + x1; + var nearIntersectionY = inRangeParams[0] * d[1] + y1; + if (inRangeParams.length > 1) { + if (inRangeParams[0] == inRangeParams[1]) { + return [nearIntersectionX, nearIntersectionY]; + } else { + var farIntersectionX = inRangeParams[1] * d[0] + x1; + var farIntersectionY = inRangeParams[1] * d[1] + y1; + return [nearIntersectionX, nearIntersectionY, farIntersectionX, farIntersectionY]; + } + } else { + return [nearIntersectionX, nearIntersectionY]; + } + }; + var midOfThree = function midOfThree(a, b, c) { + if (b <= a && a <= c || c <= a && a <= b) { + return a; + } else if (a <= b && b <= c || c <= b && b <= a) { + return b; + } else { + return c; + } + }; - // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles + // (x1,y1)=>(x2,y2) intersect with (x3,y3)=>(x4,y4) + var finiteLinesIntersect = function finiteLinesIntersect(x1, y1, x2, y2, x3, y3, x4, y4, infiniteLines) { + var dx13 = x1 - x3; + var dx21 = x2 - x1; + var dx43 = x4 - x3; + var dy13 = y1 - y3; + var dy21 = y2 - y1; + var dy43 = y4 - y3; + var ua_t = dx43 * dy13 - dy43 * dx13; + var ub_t = dx21 * dy13 - dy21 * dx13; + var u_b = dy43 * dx21 - dx43 * dy21; + if (u_b !== 0) { + var ua = ua_t / u_b; + var ub = ub_t / u_b; + var flptThreshold = 0.001; + var _min = 0 - flptThreshold; + var _max = 1 + flptThreshold; + if (_min <= ua && ua <= _max && _min <= ub && ub <= _max) { + return [x1 + ua * dx21, y1 + ua * dy21]; + } else { + if (!infiniteLines) { + return []; + } else { + return [x1 + ua * dx21, y1 + ua * dy21]; + } + } + } else { + if (ua_t === 0 || ub_t === 0) { + // Parallel, coincident lines. Check if overlap + + // Check endpoint of second line + if (midOfThree(x1, x2, x4) === x4) { + return [x4, y4]; + } + + // Check start point of second line + if (midOfThree(x1, x2, x3) === x3) { + return [x3, y3]; + } + + // Endpoint of first line + if (midOfThree(x3, x4, x2) === x2) { + return [x2, y2]; + } + return []; + } else { + // Parallel, non-coincident + return []; + } + } + }; - // rotations are applied to the axes in the order specified by 'order' - // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' - // angles are in radians + // math.polygonIntersectLine( x, y, basePoints, centerX, centerY, width, height, padding ) + // intersect a node polygon (pts transformed) + // + // math.polygonIntersectLine( x, y, basePoints, centerX, centerY ) + // intersect the points (no transform) + var polygonIntersectLine = function polygonIntersectLine(x, y, basePoints, centerX, centerY, width, height, padding) { + var intersections = []; + var intersection; + var transformedPoints = new Array(basePoints.length); + var doTransform = true; + if (width == null) { + doTransform = false; + } + var points; + if (doTransform) { + for (var i = 0; i < transformedPoints.length / 2; i++) { + transformedPoints[i * 2] = basePoints[i * 2] * width + centerX; + transformedPoints[i * 2 + 1] = basePoints[i * 2 + 1] * height + centerY; + } + if (padding > 0) { + var expandedLineSet = expandPolygon(transformedPoints, -padding); + points = joinLines(expandedLineSet); + } else { + points = transformedPoints; + } + } else { + points = basePoints; + } + var currentX, currentY, nextX, nextY; + for (var _i2 = 0; _i2 < points.length / 2; _i2++) { + currentX = points[_i2 * 2]; + currentY = points[_i2 * 2 + 1]; + if (_i2 < points.length / 2 - 1) { + nextX = points[(_i2 + 1) * 2]; + nextY = points[(_i2 + 1) * 2 + 1]; + } else { + nextX = points[0]; + nextY = points[1]; + } + intersection = finiteLinesIntersect(x, y, centerX, centerY, currentX, currentY, nextX, nextY); + if (intersection.length !== 0) { + intersections.push(intersection[0], intersection[1]); + } + } + return intersections; + }; + var roundPolygonIntersectLine = function roundPolygonIntersectLine(x, y, basePoints, centerX, centerY, width, height, padding, corners) { + var intersections = []; + var intersection; + var lines = new Array(basePoints.length * 2); + corners.forEach(function (corner, i) { + if (i === 0) { + lines[lines.length - 2] = corner.startX; + lines[lines.length - 1] = corner.startY; + } else { + lines[i * 4 - 2] = corner.startX; + lines[i * 4 - 1] = corner.startY; + } + lines[i * 4] = corner.stopX; + lines[i * 4 + 1] = corner.stopY; + intersection = intersectLineCircle(x, y, centerX, centerY, corner.cx, corner.cy, corner.radius); + if (intersection.length !== 0) { + intersections.push(intersection[0], intersection[1]); + } + }); + for (var i = 0; i < lines.length / 4; i++) { + intersection = finiteLinesIntersect(x, y, centerX, centerY, lines[i * 4], lines[i * 4 + 1], lines[i * 4 + 2], lines[i * 4 + 3], false); + if (intersection.length !== 0) { + intersections.push(intersection[0], intersection[1]); + } + } + if (intersections.length > 2) { + var lowestIntersection = [intersections[0], intersections[1]]; + var lowestSquaredDistance = Math.pow(lowestIntersection[0] - x, 2) + Math.pow(lowestIntersection[1] - y, 2); + for (var _i3 = 1; _i3 < intersections.length / 2; _i3++) { + var squaredDistance = Math.pow(intersections[_i3 * 2] - x, 2) + Math.pow(intersections[_i3 * 2 + 1] - y, 2); + if (squaredDistance <= lowestSquaredDistance) { + lowestIntersection[0] = intersections[_i3 * 2]; + lowestIntersection[1] = intersections[_i3 * 2 + 1]; + lowestSquaredDistance = squaredDistance; + } + } + return lowestIntersection; + } + return intersections; + }; + var shortenIntersection = function shortenIntersection(intersection, offset, amount) { + var disp = [intersection[0] - offset[0], intersection[1] - offset[1]]; + var length = Math.sqrt(disp[0] * disp[0] + disp[1] * disp[1]); + var lenRatio = (length - amount) / length; + if (lenRatio < 0) { + lenRatio = 0.00001; + } + return [offset[0] + lenRatio * disp[0], offset[1] + lenRatio * disp[1]]; + }; + var generateUnitNgonPointsFitToSquare = function generateUnitNgonPointsFitToSquare(sides, rotationRadians) { + var points = generateUnitNgonPoints(sides, rotationRadians); + points = fitPolygonToSquare(points); + return points; + }; + var fitPolygonToSquare = function fitPolygonToSquare(points) { + var x, y; + var sides = points.length / 2; + var minX = Infinity, + minY = Infinity, + maxX = -Infinity, + maxY = -Infinity; + for (var i = 0; i < sides; i++) { + x = points[2 * i]; + y = points[2 * i + 1]; + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + } - const cos = Math.cos; - const sin = Math.sin; + // stretch factors + var sx = 2 / (maxX - minX); + var sy = 2 / (maxY - minY); + for (var _i4 = 0; _i4 < sides; _i4++) { + x = points[2 * _i4] = points[2 * _i4] * sx; + y = points[2 * _i4 + 1] = points[2 * _i4 + 1] * sy; + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + } + if (minY < -1) { + for (var _i5 = 0; _i5 < sides; _i5++) { + y = points[2 * _i5 + 1] = points[2 * _i5 + 1] + (-1 - minY); + } + } + return points; + }; + var generateUnitNgonPoints = function generateUnitNgonPoints(sides, rotationRadians) { + var increment = 1.0 / sides * 2 * Math.PI; + var startAngle = sides % 2 === 0 ? Math.PI / 2.0 + increment / 2.0 : Math.PI / 2.0; + startAngle += rotationRadians; + var points = new Array(sides * 2); + var currentAngle; + for (var i = 0; i < sides; i++) { + currentAngle = i * increment + startAngle; + points[2 * i] = Math.cos(currentAngle); // x + points[2 * i + 1] = Math.sin(-currentAngle); // y + } - const c2 = cos( b / 2 ); - const s2 = sin( b / 2 ); + return points; + }; - const c13 = cos( ( a + c ) / 2 ); - const s13 = sin( ( a + c ) / 2 ); + // Set the default radius, unless half of width or height is smaller than default + var getRoundRectangleRadius = function getRoundRectangleRadius(width, height) { + return Math.min(width / 4, height / 4, 8); + }; - const c1_3 = cos( ( a - c ) / 2 ); - const s1_3 = sin( ( a - c ) / 2 ); + // Set the default radius + var getRoundPolygonRadius = function getRoundPolygonRadius(width, height) { + return Math.min(width / 10, height / 10, 8); + }; + var getCutRectangleCornerLength = function getCutRectangleCornerLength() { + return 8; + }; + var bezierPtsToQuadCoeff = function bezierPtsToQuadCoeff(p0, p1, p2) { + return [p0 - 2 * p1 + p2, 2 * (p1 - p0), p0]; + }; - const c3_1 = cos( ( c - a ) / 2 ); - const s3_1 = sin( ( c - a ) / 2 ); + // get curve width, height, and control point position offsets as a percentage of node height / width + var getBarrelCurveConstants = function getBarrelCurveConstants(width, height) { + return { + heightOffset: Math.min(15, 0.05 * height), + widthOffset: Math.min(100, 0.25 * width), + ctrlPtOffsetPct: 0.05 + }; + }; - switch ( order ) { + var pageRankDefaults = defaults$g({ + dampingFactor: 0.8, + precision: 0.000001, + iterations: 200, + weight: function weight(edge) { + return 1; + } + }); + var elesfn$o = { + pageRank: function pageRank(options) { + var _pageRankDefaults = pageRankDefaults(options), + dampingFactor = _pageRankDefaults.dampingFactor, + precision = _pageRankDefaults.precision, + iterations = _pageRankDefaults.iterations, + weight = _pageRankDefaults.weight; + var cy = this._private.cy; + var _this$byGroup = this.byGroup(), + nodes = _this$byGroup.nodes, + edges = _this$byGroup.edges; + var numNodes = nodes.length; + var numNodesSqd = numNodes * numNodes; + var numEdges = edges.length; + + // Construct transposed adjacency matrix + // First lets have a zeroed matrix of the right size + // We'll also keep track of the sum of each column + var matrix = new Array(numNodesSqd); + var columnSum = new Array(numNodes); + var additionalProb = (1 - dampingFactor) / numNodes; + + // Create null matrix + for (var i = 0; i < numNodes; i++) { + for (var j = 0; j < numNodes; j++) { + var n = i * numNodes + j; + matrix[n] = 0; + } + columnSum[i] = 0; + } - case 'XYX': - q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); - break; + // Now, process edges + for (var _i = 0; _i < numEdges; _i++) { + var edge = edges[_i]; + var srcId = edge.data('source'); + var tgtId = edge.data('target'); + + // Don't include loops in the matrix + if (srcId === tgtId) { + continue; + } + var s = nodes.indexOfId(srcId); + var t = nodes.indexOfId(tgtId); + var w = weight(edge); + var _n = t * numNodes + s; + + // Update matrix + matrix[_n] += w; + + // Update column sum + columnSum[s] += w; + } - case 'YZY': - q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); - break; + // Add additional probability based on damping factor + // Also, take into account columns that have sum = 0 + var p = 1.0 / numNodes + additionalProb; // Shorthand + + // Traverse matrix, column by column + for (var _j = 0; _j < numNodes; _j++) { + if (columnSum[_j] === 0) { + // No 'links' out from node jth, assume equal probability for each possible node + for (var _i2 = 0; _i2 < numNodes; _i2++) { + var _n2 = _i2 * numNodes + _j; + matrix[_n2] = p; + } + } else { + // Node jth has outgoing link, compute normalized probabilities + for (var _i3 = 0; _i3 < numNodes; _i3++) { + var _n3 = _i3 * numNodes + _j; + matrix[_n3] = matrix[_n3] / columnSum[_j] + additionalProb; + } + } + } - case 'ZXZ': - q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); - break; + // Compute dominant eigenvector using power method + var eigenvector = new Array(numNodes); + var temp = new Array(numNodes); + var previous; - case 'XZX': - q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); - break; + // Start with a vector of all 1's + // Also, initialize a null vector which will be used as shorthand + for (var _i4 = 0; _i4 < numNodes; _i4++) { + eigenvector[_i4] = 1; + } + for (var iter = 0; iter < iterations; iter++) { + // Temp array with all 0's + for (var _i5 = 0; _i5 < numNodes; _i5++) { + temp[_i5] = 0; + } + + // Multiply matrix with previous result + for (var _i6 = 0; _i6 < numNodes; _i6++) { + for (var _j2 = 0; _j2 < numNodes; _j2++) { + var _n4 = _i6 * numNodes + _j2; + temp[_i6] += matrix[_n4] * eigenvector[_j2]; + } + } + inPlaceSumNormalize(temp); + previous = eigenvector; + eigenvector = temp; + temp = previous; + var diff = 0; + // Compute difference (squared module) of both vectors + for (var _i7 = 0; _i7 < numNodes; _i7++) { + var delta = previous[_i7] - eigenvector[_i7]; + diff += delta * delta; + } + + // If difference is less than the desired threshold, stop iterating + if (diff < precision) { + break; + } + } - case 'YXY': - q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); - break; + // Construct result + var res = { + rank: function rank(node) { + node = cy.collection(node)[0]; + return eigenvector[nodes.indexOf(node)]; + } + }; + return res; + } // pageRank + }; // elesfn + + var defaults$f = defaults$g({ + root: null, + weight: function weight(edge) { + return 1; + }, + directed: false, + alpha: 0 + }); + var elesfn$n = { + degreeCentralityNormalized: function degreeCentralityNormalized(options) { + options = defaults$f(options); + var cy = this.cy(); + var nodes = this.nodes(); + var numNodes = nodes.length; + if (!options.directed) { + var degrees = {}; + var maxDegree = 0; + for (var i = 0; i < numNodes; i++) { + var node = nodes[i]; + + // add current node to the current options object and call degreeCentrality + options.root = node; + var currDegree = this.degreeCentrality(options); + if (maxDegree < currDegree.degree) { + maxDegree = currDegree.degree; + } + degrees[node.id()] = currDegree.degree; + } + return { + degree: function degree(node) { + if (maxDegree === 0) { + return 0; + } + if (string(node)) { + // from is a selector string + node = cy.filter(node); + } + return degrees[node.id()] / maxDegree; + } + }; + } else { + var indegrees = {}; + var outdegrees = {}; + var maxIndegree = 0; + var maxOutdegree = 0; + for (var _i = 0; _i < numNodes; _i++) { + var _node = nodes[_i]; + var id = _node.id(); + + // add current node to the current options object and call degreeCentrality + options.root = _node; + var _currDegree = this.degreeCentrality(options); + if (maxIndegree < _currDegree.indegree) maxIndegree = _currDegree.indegree; + if (maxOutdegree < _currDegree.outdegree) maxOutdegree = _currDegree.outdegree; + indegrees[id] = _currDegree.indegree; + outdegrees[id] = _currDegree.outdegree; + } + return { + indegree: function indegree(node) { + if (maxIndegree == 0) { + return 0; + } + if (string(node)) { + // from is a selector string + node = cy.filter(node); + } + return indegrees[node.id()] / maxIndegree; + }, + outdegree: function outdegree(node) { + if (maxOutdegree === 0) { + return 0; + } + if (string(node)) { + // from is a selector string + node = cy.filter(node); + } + return outdegrees[node.id()] / maxOutdegree; + } + }; + } + }, + // degreeCentralityNormalized + + // Implemented from the algorithm in Opsahl's paper + // "Node centrality in weighted networks: Generalizing degree and shortest paths" + // check the heading 2 "Degree" + degreeCentrality: function degreeCentrality(options) { + options = defaults$f(options); + var cy = this.cy(); + var callingEles = this; + var _options = options, + root = _options.root, + weight = _options.weight, + directed = _options.directed, + alpha = _options.alpha; + root = cy.collection(root)[0]; + if (!directed) { + var connEdges = root.connectedEdges().intersection(callingEles); + var k = connEdges.length; + var s = 0; + + // Now, sum edge weights + for (var i = 0; i < connEdges.length; i++) { + s += weight(connEdges[i]); + } + return { + degree: Math.pow(k, 1 - alpha) * Math.pow(s, alpha) + }; + } else { + var edges = root.connectedEdges(); + var incoming = edges.filter(function (edge) { + return edge.target().same(root) && callingEles.has(edge); + }); + var outgoing = edges.filter(function (edge) { + return edge.source().same(root) && callingEles.has(edge); + }); + var k_in = incoming.length; + var k_out = outgoing.length; + var s_in = 0; + var s_out = 0; + + // Now, sum incoming edge weights + for (var _i2 = 0; _i2 < incoming.length; _i2++) { + s_in += weight(incoming[_i2]); + } + + // Now, sum outgoing edge weights + for (var _i3 = 0; _i3 < outgoing.length; _i3++) { + s_out += weight(outgoing[_i3]); + } + return { + indegree: Math.pow(k_in, 1 - alpha) * Math.pow(s_in, alpha), + outdegree: Math.pow(k_out, 1 - alpha) * Math.pow(s_out, alpha) + }; + } + } // degreeCentrality + }; // elesfn + + // nice, short mathematical alias + elesfn$n.dc = elesfn$n.degreeCentrality; + elesfn$n.dcn = elesfn$n.degreeCentralityNormalised = elesfn$n.degreeCentralityNormalized; + + var defaults$e = defaults$g({ + harmonic: true, + weight: function weight() { + return 1; + }, + directed: false, + root: null + }); + var elesfn$m = { + closenessCentralityNormalized: function closenessCentralityNormalized(options) { + var _defaults = defaults$e(options), + harmonic = _defaults.harmonic, + weight = _defaults.weight, + directed = _defaults.directed; + var cy = this.cy(); + var closenesses = {}; + var maxCloseness = 0; + var nodes = this.nodes(); + var fw = this.floydWarshall({ + weight: weight, + directed: directed + }); - case 'ZYZ': - q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); - break; + // Compute closeness for every node and find the maximum closeness + for (var i = 0; i < nodes.length; i++) { + var currCloseness = 0; + var node_i = nodes[i]; + for (var j = 0; j < nodes.length; j++) { + if (i !== j) { + var d = fw.distance(node_i, nodes[j]); + if (harmonic) { + currCloseness += 1 / d; + } else { + currCloseness += d; + } + } + } + if (!harmonic) { + currCloseness = 1 / currCloseness; + } + if (maxCloseness < currCloseness) { + maxCloseness = currCloseness; + } + closenesses[node_i.id()] = currCloseness; + } + return { + closeness: function closeness(node) { + if (maxCloseness == 0) { + return 0; + } + if (string(node)) { + // from is a selector string + node = cy.filter(node)[0].id(); + } else { + // from is a node + node = node.id(); + } + return closenesses[node] / maxCloseness; + } + }; + }, + // Implemented from pseudocode from wikipedia + closenessCentrality: function closenessCentrality(options) { + var _defaults2 = defaults$e(options), + root = _defaults2.root, + weight = _defaults2.weight, + directed = _defaults2.directed, + harmonic = _defaults2.harmonic; + root = this.filter(root)[0]; + + // we need distance from this node to every other node + var dijkstra = this.dijkstra({ + root: root, + weight: weight, + directed: directed + }); + var totalDistance = 0; + var nodes = this.nodes(); + for (var i = 0; i < nodes.length; i++) { + var n = nodes[i]; + if (!n.same(root)) { + var d = dijkstra.distanceTo(n); + if (harmonic) { + totalDistance += 1 / d; + } else { + totalDistance += d; + } + } + } + return harmonic ? totalDistance : 1 / totalDistance; + } // closenessCentrality + }; // elesfn - default: - console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); + // nice, short mathematical alias + elesfn$m.cc = elesfn$m.closenessCentrality; + elesfn$m.ccn = elesfn$m.closenessCentralityNormalised = elesfn$m.closenessCentralityNormalized; - } + var defaults$d = defaults$g({ + weight: null, + directed: false + }); + var elesfn$l = { + // Implemented from the algorithm in the paper "On Variants of Shortest-Path Betweenness Centrality and their Generic Computation" by Ulrik Brandes + betweennessCentrality: function betweennessCentrality(options) { + var _defaults = defaults$d(options), + directed = _defaults.directed, + weight = _defaults.weight; + var weighted = weight != null; + var cy = this.cy(); + + // starting + var V = this.nodes(); + var A = {}; + var _C = {}; + var max = 0; + var C = { + set: function set(key, val) { + _C[key] = val; + if (val > max) { + max = val; + } + }, + get: function get(key) { + return _C[key]; + } + }; - } + // A contains the neighborhoods of every node + for (var i = 0; i < V.length; i++) { + var v = V[i]; + var vid = v.id(); + if (directed) { + A[vid] = v.outgoers().nodes(); // get outgoers of every node + } else { + A[vid] = v.openNeighborhood().nodes(); // get neighbors of every node + } + + C.set(vid, 0); + } + var _loop = function _loop(s) { + var sid = V[s].id(); + var S = []; // stack + var P = {}; + var g = {}; + var d = {}; + var Q = new heap(function (a, b) { + return d[a] - d[b]; + }); // queue + + // init dictionaries + for (var _i = 0; _i < V.length; _i++) { + var _vid = V[_i].id(); + P[_vid] = []; + g[_vid] = 0; + d[_vid] = Infinity; + } + g[sid] = 1; // sigma + d[sid] = 0; // distance to s + + Q.push(sid); + while (!Q.empty()) { + var _v = Q.pop(); + S.push(_v); + if (weighted) { + for (var j = 0; j < A[_v].length; j++) { + var w = A[_v][j]; + var vEle = cy.getElementById(_v); + var edge = void 0; + if (vEle.edgesTo(w).length > 0) { + edge = vEle.edgesTo(w)[0]; + } else { + edge = w.edgesTo(vEle)[0]; + } + var edgeWeight = weight(edge); + w = w.id(); + if (d[w] > d[_v] + edgeWeight) { + d[w] = d[_v] + edgeWeight; + if (Q.nodes.indexOf(w) < 0) { + //if w is not in Q + Q.push(w); + } else { + // update position if w is in Q + Q.updateItem(w); + } + g[w] = 0; + P[w] = []; + } + if (d[w] == d[_v] + edgeWeight) { + g[w] = g[w] + g[_v]; + P[w].push(_v); + } + } + } else { + for (var _j = 0; _j < A[_v].length; _j++) { + var _w = A[_v][_j].id(); + if (d[_w] == Infinity) { + Q.push(_w); + d[_w] = d[_v] + 1; + } + if (d[_w] == d[_v] + 1) { + g[_w] = g[_w] + g[_v]; + P[_w].push(_v); + } + } + } + } + var e = {}; + for (var _i2 = 0; _i2 < V.length; _i2++) { + e[V[_i2].id()] = 0; + } + while (S.length > 0) { + var _w2 = S.pop(); + for (var _j2 = 0; _j2 < P[_w2].length; _j2++) { + var _v2 = P[_w2][_j2]; + e[_v2] = e[_v2] + g[_v2] / g[_w2] * (1 + e[_w2]); + } + if (_w2 != V[s].id()) { + C.set(_w2, C.get(_w2) + e[_w2]); + } + } + }; + for (var s = 0; s < V.length; s++) { + _loop(s); + } + var ret = { + betweenness: function betweenness(node) { + var id = cy.collection(node).id(); + return C.get(id); + }, + betweennessNormalized: function betweennessNormalized(node) { + if (max == 0) { + return 0; + } + var id = cy.collection(node).id(); + return C.get(id) / max; + } + }; - function denormalize( value, array ) { + // alias + ret.betweennessNormalised = ret.betweennessNormalized; + return ret; + } // betweennessCentrality + }; // elesfn + + // nice, short mathematical alias + elesfn$l.bc = elesfn$l.betweennessCentrality; + + // Implemented by Zoe Xi @zoexi for GSOC 2016 + + /* eslint-disable no-unused-vars */ + var defaults$c = defaults$g({ + expandFactor: 2, + // affects time of computation and cluster granularity to some extent: M * M + inflateFactor: 2, + // affects cluster granularity (the greater the value, the more clusters): M(i,j) / E(j) + multFactor: 1, + // optional self loops for each node. Use a neutral value to improve cluster computations. + maxIterations: 20, + // maximum number of iterations of the MCL algorithm in a single run + attributes: [ + // attributes/features used to group nodes, ie. similarity values between nodes + function (edge) { + return 1; + }] + }); + /* eslint-enable */ - switch ( array.constructor ) { + var setOptions$3 = function setOptions(options) { + return defaults$c(options); + }; + /* eslint-enable */ - case Float32Array: + var getSimilarity$1 = function getSimilarity(edge, attributes) { + var total = 0; + for (var i = 0; i < attributes.length; i++) { + total += attributes[i](edge); + } + return total; + }; + var addLoops = function addLoops(M, n, val) { + for (var i = 0; i < n; i++) { + M[i * n + i] = val; + } + }; + var normalize$1 = function normalize(M, n) { + var sum; + for (var col = 0; col < n; col++) { + sum = 0; + for (var row = 0; row < n; row++) { + sum += M[row * n + col]; + } + for (var _row = 0; _row < n; _row++) { + M[_row * n + col] = M[_row * n + col] / sum; + } + } + }; - return value; + // TODO: blocked matrix multiplication? + var mmult = function mmult(A, B, n) { + var C = new Array(n * n); + for (var i = 0; i < n; i++) { + for (var j = 0; j < n; j++) { + C[i * n + j] = 0; + } + for (var k = 0; k < n; k++) { + for (var _j = 0; _j < n; _j++) { + C[i * n + _j] += A[i * n + k] * B[k * n + _j]; + } + } + } + return C; + }; + var expand = function expand(M, n, expandFactor /** power **/) { + var _M = M.slice(0); + for (var p = 1; p < expandFactor; p++) { + M = mmult(M, _M, n); + } + return M; + }; + var inflate = function inflate(M, n, inflateFactor /** r **/) { + var _M = new Array(n * n); - case Uint16Array: + // M(i,j) ^ inflatePower + for (var i = 0; i < n * n; i++) { + _M[i] = Math.pow(M[i], inflateFactor); + } + normalize$1(_M, n); + return _M; + }; + var hasConverged = function hasConverged(M, _M, n2, roundFactor) { + // Check that both matrices have the same elements (i,j) + for (var i = 0; i < n2; i++) { + var v1 = Math.round(M[i] * Math.pow(10, roundFactor)) / Math.pow(10, roundFactor); // truncate to 'roundFactor' decimal places + var v2 = Math.round(_M[i] * Math.pow(10, roundFactor)) / Math.pow(10, roundFactor); + if (v1 !== v2) { + return false; + } + } + return true; + }; + var assign$2 = function assign(M, n, nodes, cy) { + var clusters = []; + for (var i = 0; i < n; i++) { + var cluster = []; + for (var j = 0; j < n; j++) { + // Row-wise attractors and elements that they attract belong in same cluster + if (Math.round(M[i * n + j] * 1000) / 1000 > 0) { + cluster.push(nodes[j]); + } + } + if (cluster.length !== 0) { + clusters.push(cy.collection(cluster)); + } + } + return clusters; + }; + var isDuplicate = function isDuplicate(c1, c2) { + for (var i = 0; i < c1.length; i++) { + if (!c2[i] || c1[i].id() !== c2[i].id()) { + return false; + } + } + return true; + }; + var removeDuplicates = function removeDuplicates(clusters) { + for (var i = 0; i < clusters.length; i++) { + for (var j = 0; j < clusters.length; j++) { + if (i != j && isDuplicate(clusters[i], clusters[j])) { + clusters.splice(j, 1); + } + } + } + return clusters; + }; + var markovClustering = function markovClustering(options) { + var nodes = this.nodes(); + var edges = this.edges(); + var cy = this.cy(); + + // Set parameters of algorithm: + var opts = setOptions$3(options); + + // Map each node to its position in node array + var id2position = {}; + for (var i = 0; i < nodes.length; i++) { + id2position[nodes[i].id()] = i; + } - return value / 65535.0; + // Generate stochastic matrix M from input graph G (should be symmetric/undirected) + var n = nodes.length, + n2 = n * n; + var M = new Array(n2), + _M; + for (var _i = 0; _i < n2; _i++) { + M[_i] = 0; + } + for (var e = 0; e < edges.length; e++) { + var edge = edges[e]; + var _i2 = id2position[edge.source().id()]; + var j = id2position[edge.target().id()]; + var sim = getSimilarity$1(edge, opts.attributes); + M[_i2 * n + j] += sim; // G should be symmetric and undirected + M[j * n + _i2] += sim; + } - case Uint8Array: + // Begin Markov cluster algorithm - return value / 255.0; + // Step 1: Add self loops to each node, ie. add multFactor to matrix diagonal + addLoops(M, n, opts.multFactor); - case Int16Array: + // Step 2: M = normalize( M ); + normalize$1(M, n); + var isStillMoving = true; + var iterations = 0; + while (isStillMoving && iterations < opts.maxIterations) { + isStillMoving = false; - return Math.max( value / 32767.0, - 1.0 ); + // Step 3: + _M = expand(M, n, opts.expandFactor); - case Int8Array: + // Step 4: + M = inflate(_M, n, opts.inflateFactor); - return Math.max( value / 127.0, - 1.0 ); + // Step 5: check to see if ~steady state has been reached + if (!hasConverged(M, _M, n2, 4)) { + isStillMoving = true; + } + iterations++; + } - default: + // Build clusters from matrix + var clusters = assign$2(M, n, nodes, cy); - throw new Error( 'Invalid component type.' ); + // Remove duplicate clusters due to symmetry of graph and M matrix + clusters = removeDuplicates(clusters); + return clusters; + }; + var markovClustering$1 = { + markovClustering: markovClustering, + mcl: markovClustering + }; - } + // Common distance metrics for clustering algorithms + var identity = function identity(x) { + return x; + }; + var absDiff = function absDiff(p, q) { + return Math.abs(q - p); + }; + var addAbsDiff = function addAbsDiff(total, p, q) { + return total + absDiff(p, q); + }; + var addSquaredDiff = function addSquaredDiff(total, p, q) { + return total + Math.pow(q - p, 2); + }; + var sqrt = function sqrt(x) { + return Math.sqrt(x); + }; + var maxAbsDiff = function maxAbsDiff(currentMax, p, q) { + return Math.max(currentMax, absDiff(p, q)); + }; + var getDistance = function getDistance(length, getP, getQ, init, visit) { + var post = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : identity; + var ret = init; + var p, q; + for (var dim = 0; dim < length; dim++) { + p = getP(dim); + q = getQ(dim); + ret = visit(ret, p, q); + } + return post(ret); + }; + var distances = { + euclidean: function euclidean(length, getP, getQ) { + if (length >= 2) { + return getDistance(length, getP, getQ, 0, addSquaredDiff, sqrt); + } else { + // for single attr case, more efficient to avoid sqrt + return getDistance(length, getP, getQ, 0, addAbsDiff); + } + }, + squaredEuclidean: function squaredEuclidean(length, getP, getQ) { + return getDistance(length, getP, getQ, 0, addSquaredDiff); + }, + manhattan: function manhattan(length, getP, getQ) { + return getDistance(length, getP, getQ, 0, addAbsDiff); + }, + max: function max(length, getP, getQ) { + return getDistance(length, getP, getQ, -Infinity, maxAbsDiff); + } + }; + // in case the user accidentally doesn't use camel case + distances['squared-euclidean'] = distances['squaredEuclidean']; + distances['squaredeuclidean'] = distances['squaredEuclidean']; + function clusteringDistance (method, length, getP, getQ, nodeP, nodeQ) { + var impl; + if (fn$6(method)) { + impl = method; + } else { + impl = distances[method] || distances.euclidean; + } + if (length === 0 && fn$6(method)) { + return impl(nodeP, nodeQ); + } else { + return impl(length, getP, getQ, nodeP, nodeQ); + } } - function normalize( value, array ) { - - switch ( array.constructor ) { - - case Float32Array: - - return value; - - case Uint16Array: + var defaults$b = defaults$g({ + k: 2, + m: 2, + sensitivityThreshold: 0.0001, + distance: 'euclidean', + maxIterations: 10, + attributes: [], + testMode: false, + testCentroids: null + }); + var setOptions$2 = function setOptions(options) { + return defaults$b(options); + }; - return Math.round( value * 65535.0 ); + var getDist = function getDist(type, node, centroid, attributes, mode) { + var noNodeP = mode !== 'kMedoids'; + var getP = noNodeP ? function (i) { + return centroid[i]; + } : function (i) { + return attributes[i](centroid); + }; + var getQ = function getQ(i) { + return attributes[i](node); + }; + var nodeP = centroid; + var nodeQ = node; + return clusteringDistance(type, attributes.length, getP, getQ, nodeP, nodeQ); + }; + var randomCentroids = function randomCentroids(nodes, k, attributes) { + var ndim = attributes.length; + var min = new Array(ndim); + var max = new Array(ndim); + var centroids = new Array(k); + var centroid = null; + + // Find min, max values for each attribute dimension + for (var i = 0; i < ndim; i++) { + min[i] = nodes.min(attributes[i]).value; + max[i] = nodes.max(attributes[i]).value; + } - case Uint8Array: + // Build k centroids, each represented as an n-dim feature vector + for (var c = 0; c < k; c++) { + centroid = []; + for (var _i = 0; _i < ndim; _i++) { + centroid[_i] = Math.random() * (max[_i] - min[_i]) + min[_i]; // random initial value + } - return Math.round( value * 255.0 ); + centroids[c] = centroid; + } + return centroids; + }; + var classify = function classify(node, centroids, distance, attributes, type) { + var min = Infinity; + var index = 0; + for (var i = 0; i < centroids.length; i++) { + var dist = getDist(distance, node, centroids[i], attributes, type); + if (dist < min) { + min = dist; + index = i; + } + } + return index; + }; + var buildCluster = function buildCluster(centroid, nodes, assignment) { + var cluster = []; + var node = null; + for (var n = 0; n < nodes.length; n++) { + node = nodes[n]; + if (assignment[node.id()] === centroid) { + //console.log("Node " + node.id() + " is associated with medoid #: " + m); + cluster.push(node); + } + } + return cluster; + }; + var haveValuesConverged = function haveValuesConverged(v1, v2, sensitivityThreshold) { + return Math.abs(v2 - v1) <= sensitivityThreshold; + }; + var haveMatricesConverged = function haveMatricesConverged(v1, v2, sensitivityThreshold) { + for (var i = 0; i < v1.length; i++) { + for (var j = 0; j < v1[i].length; j++) { + var diff = Math.abs(v1[i][j] - v2[i][j]); + if (diff > sensitivityThreshold) { + return false; + } + } + } + return true; + }; + var seenBefore = function seenBefore(node, medoids, n) { + for (var i = 0; i < n; i++) { + if (node === medoids[i]) return true; + } + return false; + }; + var randomMedoids = function randomMedoids(nodes, k) { + var medoids = new Array(k); + + // For small data sets, the probability of medoid conflict is greater, + // so we need to check to see if we've already seen or chose this node before. + if (nodes.length < 50) { + // Randomly select k medoids from the n nodes + for (var i = 0; i < k; i++) { + var node = nodes[Math.floor(Math.random() * nodes.length)]; + + // If we've already chosen this node to be a medoid, don't choose it again (for small data sets). + // Instead choose a different random node. + while (seenBefore(node, medoids, i)) { + node = nodes[Math.floor(Math.random() * nodes.length)]; + } + medoids[i] = node; + } + } else { + // Relatively large data set, so pretty safe to not check and just select random nodes + for (var _i2 = 0; _i2 < k; _i2++) { + medoids[_i2] = nodes[Math.floor(Math.random() * nodes.length)]; + } + } + return medoids; + }; + var findCost = function findCost(potentialNewMedoid, cluster, attributes) { + var cost = 0; + for (var n = 0; n < cluster.length; n++) { + cost += getDist('manhattan', cluster[n], potentialNewMedoid, attributes, 'kMedoids'); + } + return cost; + }; + var kMeans = function kMeans(options) { + var cy = this.cy(); + var nodes = this.nodes(); + var node = null; + + // Set parameters of algorithm: # of clusters, distance metric, etc. + var opts = setOptions$2(options); + + // Begin k-means algorithm + var clusters = new Array(opts.k); + var assignment = {}; + var centroids; + + // Step 1: Initialize centroid positions + if (opts.testMode) { + if (typeof opts.testCentroids === 'number') { + // TODO: implement a seeded random number generator. + opts.testCentroids; + centroids = randomCentroids(nodes, opts.k, opts.attributes); + } else if (_typeof(opts.testCentroids) === 'object') { + centroids = opts.testCentroids; + } else { + centroids = randomCentroids(nodes, opts.k, opts.attributes); + } + } else { + centroids = randomCentroids(nodes, opts.k, opts.attributes); + } + var isStillMoving = true; + var iterations = 0; + while (isStillMoving && iterations < opts.maxIterations) { + // Step 2: Assign nodes to the nearest centroid + for (var n = 0; n < nodes.length; n++) { + node = nodes[n]; + // Determine which cluster this node belongs to: node id => cluster # + assignment[node.id()] = classify(node, centroids, opts.distance, opts.attributes, 'kMeans'); + } - case Int16Array: + // Step 3: For each of the k clusters, update its centroid + isStillMoving = false; + for (var c = 0; c < opts.k; c++) { + // Get all nodes that belong to this cluster + var cluster = buildCluster(c, nodes, assignment); + if (cluster.length === 0) { + // If cluster is empty, break out early & move to next cluster + continue; + } + + // Update centroids by calculating avg of all nodes within the cluster. + var ndim = opts.attributes.length; + var centroid = centroids[c]; // [ dim_1, dim_2, dim_3, ... , dim_n ] + var newCentroid = new Array(ndim); + var sum = new Array(ndim); + for (var d = 0; d < ndim; d++) { + sum[d] = 0.0; + for (var i = 0; i < cluster.length; i++) { + node = cluster[i]; + sum[d] += opts.attributes[d](node); + } + newCentroid[d] = sum[d] / cluster.length; - return Math.round( value * 32767.0 ); + // Check to see if algorithm has converged, i.e. when centroids no longer change + if (!haveValuesConverged(newCentroid[d], centroid[d], opts.sensitivityThreshold)) { + isStillMoving = true; + } + } + centroids[c] = newCentroid; + clusters[c] = cy.collection(cluster); + } + iterations++; + } + return clusters; + }; + var kMedoids = function kMedoids(options) { + var cy = this.cy(); + var nodes = this.nodes(); + var node = null; + var opts = setOptions$2(options); + + // Begin k-medoids algorithm + var clusters = new Array(opts.k); + var medoids; + var assignment = {}; + var curCost; + var minCosts = new Array(opts.k); // minimum cost configuration for each cluster + + // Step 1: Initialize k medoids + if (opts.testMode) { + if (typeof opts.testCentroids === 'number') ; else if (_typeof(opts.testCentroids) === 'object') { + medoids = opts.testCentroids; + } else { + medoids = randomMedoids(nodes, opts.k); + } + } else { + medoids = randomMedoids(nodes, opts.k); + } + var isStillMoving = true; + var iterations = 0; + while (isStillMoving && iterations < opts.maxIterations) { + // Step 2: Assign nodes to the nearest medoid + for (var n = 0; n < nodes.length; n++) { + node = nodes[n]; + // Determine which cluster this node belongs to: node id => cluster # + assignment[node.id()] = classify(node, medoids, opts.distance, opts.attributes, 'kMedoids'); + } + isStillMoving = false; + // Step 3: For each medoid m, and for each node associated with mediod m, + // select the node with the lowest configuration cost as new medoid. + for (var m = 0; m < medoids.length; m++) { + // Get all nodes that belong to this medoid + var cluster = buildCluster(m, nodes, assignment); + if (cluster.length === 0) { + // If cluster is empty, break out early & move to next cluster + continue; + } + minCosts[m] = findCost(medoids[m], cluster, opts.attributes); // original cost + + // Select different medoid if its configuration has the lowest cost + for (var _n = 0; _n < cluster.length; _n++) { + curCost = findCost(cluster[_n], cluster, opts.attributes); + if (curCost < minCosts[m]) { + minCosts[m] = curCost; + medoids[m] = cluster[_n]; + isStillMoving = true; + } + } + clusters[m] = cy.collection(cluster); + } + iterations++; + } + return clusters; + }; + var updateCentroids = function updateCentroids(centroids, nodes, U, weight, opts) { + var numerator, denominator; + for (var n = 0; n < nodes.length; n++) { + for (var c = 0; c < centroids.length; c++) { + weight[n][c] = Math.pow(U[n][c], opts.m); + } + } + for (var _c = 0; _c < centroids.length; _c++) { + for (var dim = 0; dim < opts.attributes.length; dim++) { + numerator = 0; + denominator = 0; + for (var _n2 = 0; _n2 < nodes.length; _n2++) { + numerator += weight[_n2][_c] * opts.attributes[dim](nodes[_n2]); + denominator += weight[_n2][_c]; + } + centroids[_c][dim] = numerator / denominator; + } + } + }; + var updateMembership = function updateMembership(U, _U, centroids, nodes, opts) { + // Save previous step + for (var i = 0; i < U.length; i++) { + _U[i] = U[i].slice(); + } + var sum, numerator, denominator; + var pow = 2 / (opts.m - 1); + for (var c = 0; c < centroids.length; c++) { + for (var n = 0; n < nodes.length; n++) { + sum = 0; + for (var k = 0; k < centroids.length; k++) { + // against all other centroids + numerator = getDist(opts.distance, nodes[n], centroids[c], opts.attributes, 'cmeans'); + denominator = getDist(opts.distance, nodes[n], centroids[k], opts.attributes, 'cmeans'); + sum += Math.pow(numerator / denominator, pow); + } + U[n][c] = 1 / sum; + } + } + }; + var assign$1 = function assign(nodes, U, opts, cy) { + var clusters = new Array(opts.k); + for (var c = 0; c < clusters.length; c++) { + clusters[c] = []; + } + var max; + var index; + for (var n = 0; n < U.length; n++) { + // for each node (U is N x C matrix) + max = -Infinity; + index = -1; + // Determine which cluster the node is most likely to belong in + for (var _c2 = 0; _c2 < U[0].length; _c2++) { + if (U[n][_c2] > max) { + max = U[n][_c2]; + index = _c2; + } + } + clusters[index].push(nodes[n]); + } - case Int8Array: + // Turn every array into a collection of nodes + for (var _c3 = 0; _c3 < clusters.length; _c3++) { + clusters[_c3] = cy.collection(clusters[_c3]); + } + return clusters; + }; + var fuzzyCMeans = function fuzzyCMeans(options) { + var cy = this.cy(); + var nodes = this.nodes(); + var opts = setOptions$2(options); + + // Begin fuzzy c-means algorithm + var clusters; + var centroids; + var U; + var _U; + var weight; + + // Step 1: Initialize letiables. + _U = new Array(nodes.length); + for (var i = 0; i < nodes.length; i++) { + // N x C matrix + _U[i] = new Array(opts.k); + } + U = new Array(nodes.length); + for (var _i3 = 0; _i3 < nodes.length; _i3++) { + // N x C matrix + U[_i3] = new Array(opts.k); + } + for (var _i4 = 0; _i4 < nodes.length; _i4++) { + var total = 0; + for (var j = 0; j < opts.k; j++) { + U[_i4][j] = Math.random(); + total += U[_i4][j]; + } + for (var _j = 0; _j < opts.k; _j++) { + U[_i4][_j] = U[_i4][_j] / total; + } + } + centroids = new Array(opts.k); + for (var _i5 = 0; _i5 < opts.k; _i5++) { + centroids[_i5] = new Array(opts.attributes.length); + } + weight = new Array(nodes.length); + for (var _i6 = 0; _i6 < nodes.length; _i6++) { + // N x C matrix + weight[_i6] = new Array(opts.k); + } + // end init FCM - return Math.round( value * 127.0 ); + var isStillMoving = true; + var iterations = 0; + while (isStillMoving && iterations < opts.maxIterations) { + isStillMoving = false; - default: + // Step 2: Calculate the centroids for each step. + updateCentroids(centroids, nodes, U, weight, opts); - throw new Error( 'Invalid component type.' ); + // Step 3: Update the partition matrix U. + updateMembership(U, _U, centroids, nodes, opts); - } + // Step 4: Check for convergence. + if (!haveMatricesConverged(U, _U, opts.sensitivityThreshold)) { + isStillMoving = true; + } + iterations++; + } - } + // Assign nodes to clusters with highest probability. + clusters = assign$1(nodes, U, opts, cy); + return { + clusters: clusters, + degreeOfMembership: U + }; + }; + var kClustering = { + kMeans: kMeans, + kMedoids: kMedoids, + fuzzyCMeans: fuzzyCMeans, + fcm: fuzzyCMeans + }; - var MathUtils = /*#__PURE__*/Object.freeze({ - __proto__: null, - DEG2RAD: DEG2RAD, - RAD2DEG: RAD2DEG, - generateUUID: generateUUID, - clamp: clamp, - euclideanModulo: euclideanModulo, - mapLinear: mapLinear, - inverseLerp: inverseLerp, - lerp: lerp, - damp: damp, - pingpong: pingpong, - smoothstep: smoothstep, - smootherstep: smootherstep, - randInt: randInt, - randFloat: randFloat, - randFloatSpread: randFloatSpread, - seededRandom: seededRandom, - degToRad: degToRad, - radToDeg: radToDeg, - isPowerOfTwo: isPowerOfTwo, - ceilPowerOfTwo: ceilPowerOfTwo, - floorPowerOfTwo: floorPowerOfTwo, - setQuaternionFromProperEuler: setQuaternionFromProperEuler, - normalize: normalize, - denormalize: denormalize + // Implemented by Zoe Xi @zoexi for GSOC 2016 + var defaults$a = defaults$g({ + distance: 'euclidean', + // distance metric to compare nodes + linkage: 'min', + // linkage criterion : how to determine the distance between clusters of nodes + mode: 'threshold', + // mode:'threshold' => clusters must be threshold distance apart + threshold: Infinity, + // the distance threshold + // mode:'dendrogram' => the nodes are organised as leaves in a tree (siblings are close), merging makes clusters + addDendrogram: false, + // whether to add the dendrogram to the graph for viz + dendrogramDepth: 0, + // depth at which dendrogram branches are merged into the returned clusters + attributes: [] // array of attr functions }); - class Vector2 { + var linkageAliases = { + 'single': 'min', + 'complete': 'max' + }; + var setOptions$1 = function setOptions(options) { + var opts = defaults$a(options); + var preferredAlias = linkageAliases[opts.linkage]; + if (preferredAlias != null) { + opts.linkage = preferredAlias; + } + return opts; + }; + var mergeClosest = function mergeClosest(clusters, index, dists, mins, opts) { + // Find two closest clusters from cached mins + var minKey = 0; + var min = Infinity; + var dist; + var attrs = opts.attributes; + var getDist = function getDist(n1, n2) { + return clusteringDistance(opts.distance, attrs.length, function (i) { + return attrs[i](n1); + }, function (i) { + return attrs[i](n2); + }, n1, n2); + }; + for (var i = 0; i < clusters.length; i++) { + var key = clusters[i].key; + var _dist = dists[key][mins[key]]; + if (_dist < min) { + minKey = key; + min = _dist; + } + } + if (opts.mode === 'threshold' && min >= opts.threshold || opts.mode === 'dendrogram' && clusters.length === 1) { + return false; + } + var c1 = index[minKey]; + var c2 = index[mins[minKey]]; + var merged; + + // Merge two closest clusters + if (opts.mode === 'dendrogram') { + merged = { + left: c1, + right: c2, + key: c1.key + }; + } else { + merged = { + value: c1.value.concat(c2.value), + key: c1.key + }; + } + clusters[c1.index] = merged; + clusters.splice(c2.index, 1); + index[c1.key] = merged; + + // Update distances with new merged cluster + for (var _i = 0; _i < clusters.length; _i++) { + var cur = clusters[_i]; + if (c1.key === cur.key) { + dist = Infinity; + } else if (opts.linkage === 'min') { + dist = dists[c1.key][cur.key]; + if (dists[c1.key][cur.key] > dists[c2.key][cur.key]) { + dist = dists[c2.key][cur.key]; + } + } else if (opts.linkage === 'max') { + dist = dists[c1.key][cur.key]; + if (dists[c1.key][cur.key] < dists[c2.key][cur.key]) { + dist = dists[c2.key][cur.key]; + } + } else if (opts.linkage === 'mean') { + dist = (dists[c1.key][cur.key] * c1.size + dists[c2.key][cur.key] * c2.size) / (c1.size + c2.size); + } else { + if (opts.mode === 'dendrogram') dist = getDist(cur.value, c1.value);else dist = getDist(cur.value[0], c1.value[0]); + } + dists[c1.key][cur.key] = dists[cur.key][c1.key] = dist; // distance matrix is symmetric + } - constructor( x = 0, y = 0 ) { + // Update cached mins + for (var _i2 = 0; _i2 < clusters.length; _i2++) { + var key1 = clusters[_i2].key; + if (mins[key1] === c1.key || mins[key1] === c2.key) { + var _min = key1; + for (var j = 0; j < clusters.length; j++) { + var key2 = clusters[j].key; + if (dists[key1][key2] < dists[key1][_min]) { + _min = key2; + } + } + mins[key1] = _min; + } + clusters[_i2].index = _i2; + } - Vector2.prototype.isVector2 = true; + // Clean up meta data used for clustering + c1.key = c2.key = c1.index = c2.index = null; + return true; + }; + var getAllChildren = function getAllChildren(root, arr, cy) { + if (!root) return; + if (root.value) { + arr.push(root.value); + } else { + if (root.left) getAllChildren(root.left, arr); + if (root.right) getAllChildren(root.right, arr); + } + }; + var buildDendrogram = function buildDendrogram(root, cy) { + if (!root) return ''; + if (root.left && root.right) { + var leftStr = buildDendrogram(root.left, cy); + var rightStr = buildDendrogram(root.right, cy); + var node = cy.add({ + group: 'nodes', + data: { + id: leftStr + ',' + rightStr + } + }); + cy.add({ + group: 'edges', + data: { + source: leftStr, + target: node.id() + } + }); + cy.add({ + group: 'edges', + data: { + source: rightStr, + target: node.id() + } + }); + return node.id(); + } else if (root.value) { + return root.value.id(); + } + }; + var buildClustersFromTree = function buildClustersFromTree(root, k, cy) { + if (!root) return []; + var left = [], + right = [], + leaves = []; + if (k === 0) { + // don't cut tree, simply return all nodes as 1 single cluster + if (root.left) getAllChildren(root.left, left); + if (root.right) getAllChildren(root.right, right); + leaves = left.concat(right); + return [cy.collection(leaves)]; + } else if (k === 1) { + // cut at root + + if (root.value) { + // leaf node + return [cy.collection(root.value)]; + } else { + if (root.left) getAllChildren(root.left, left); + if (root.right) getAllChildren(root.right, right); + return [cy.collection(left), cy.collection(right)]; + } + } else { + if (root.value) { + return [cy.collection(root.value)]; + } else { + if (root.left) left = buildClustersFromTree(root.left, k - 1, cy); + if (root.right) right = buildClustersFromTree(root.right, k - 1, cy); + return left.concat(right); + } + } + }; - this.x = x; - this.y = y; + var hierarchicalClustering = function hierarchicalClustering(options) { + var cy = this.cy(); + var nodes = this.nodes(); + + // Set parameters of algorithm: linkage type, distance metric, etc. + var opts = setOptions$1(options); + var attrs = opts.attributes; + var getDist = function getDist(n1, n2) { + return clusteringDistance(opts.distance, attrs.length, function (i) { + return attrs[i](n1); + }, function (i) { + return attrs[i](n2); + }, n1, n2); + }; + + // Begin hierarchical algorithm + var clusters = []; + var dists = []; // distances between each pair of clusters + var mins = []; // closest cluster for each cluster + var index = []; // hash of all clusters by key + + // In agglomerative (bottom-up) clustering, each node starts as its own cluster + for (var n = 0; n < nodes.length; n++) { + var cluster = { + value: opts.mode === 'dendrogram' ? nodes[n] : [nodes[n]], + key: n, + index: n + }; + clusters[n] = cluster; + index[n] = cluster; + dists[n] = []; + mins[n] = 0; + } - } + // Calculate the distance between each pair of clusters + for (var i = 0; i < clusters.length; i++) { + for (var j = 0; j <= i; j++) { + var dist = void 0; + if (opts.mode === 'dendrogram') { + // modes store cluster values differently + dist = i === j ? Infinity : getDist(clusters[i].value, clusters[j].value); + } else { + dist = i === j ? Infinity : getDist(clusters[i].value[0], clusters[j].value[0]); + } + dists[i][j] = dist; + dists[j][i] = dist; + if (dist < dists[i][mins[i]]) { + mins[i] = j; // Cache mins: closest cluster to cluster i is cluster j + } + } + } - get width() { + // Find the closest pair of clusters and merge them into a single cluster. + // Update distances between new cluster and each of the old clusters, and loop until threshold reached. + var merged = mergeClosest(clusters, index, dists, mins, opts); + while (merged) { + merged = mergeClosest(clusters, index, dists, mins, opts); + } + var retClusters; + + // Dendrogram mode builds the hierarchy and adds intermediary nodes + edges + // in addition to returning the clusters. + if (opts.mode === 'dendrogram') { + retClusters = buildClustersFromTree(clusters[0], opts.dendrogramDepth, cy); + if (opts.addDendrogram) buildDendrogram(clusters[0], cy); + } else { + // Regular mode simply returns the clusters + + retClusters = new Array(clusters.length); + clusters.forEach(function (cluster, i) { + // Clean up meta data used for clustering + cluster.key = cluster.index = null; + retClusters[i] = cy.collection(cluster.value); + }); + } + return retClusters; + }; + var hierarchicalClustering$1 = { + hierarchicalClustering: hierarchicalClustering, + hca: hierarchicalClustering + }; - return this.x; + // Implemented by Zoe Xi @zoexi for GSOC 2016 + var defaults$9 = defaults$g({ + distance: 'euclidean', + // distance metric to compare attributes between two nodes + preference: 'median', + // suitability of a data point to serve as an exemplar + damping: 0.8, + // damping factor between [0.5, 1) + maxIterations: 1000, + // max number of iterations to run + minIterations: 100, + // min number of iterations to run in order for clustering to stop + attributes: [// functions to quantify the similarity between any two points + // e.g. node => node.data('weight') + ] + }); + var setOptions = function setOptions(options) { + var dmp = options.damping; + var pref = options.preference; + if (!(0.5 <= dmp && dmp < 1)) { + error("Damping must range on [0.5, 1). Got: ".concat(dmp)); + } + var validPrefs = ['median', 'mean', 'min', 'max']; + if (!(validPrefs.some(function (v) { + return v === pref; + }) || number$1(pref))) { + error("Preference must be one of [".concat(validPrefs.map(function (p) { + return "'".concat(p, "'"); + }).join(', '), "] or a number. Got: ").concat(pref)); + } + return defaults$9(options); + }; - } + var getSimilarity = function getSimilarity(type, n1, n2, attributes) { + var attr = function attr(n, i) { + return attributes[i](n); + }; + + // nb negative because similarity should have an inverse relationship to distance + return -clusteringDistance(type, attributes.length, function (i) { + return attr(n1, i); + }, function (i) { + return attr(n2, i); + }, n1, n2); + }; + var getPreference = function getPreference(S, preference) { + // larger preference = greater # of clusters + var p = null; + if (preference === 'median') { + p = median(S); + } else if (preference === 'mean') { + p = mean(S); + } else if (preference === 'min') { + p = min(S); + } else if (preference === 'max') { + p = max(S); + } else { + // Custom preference number, as set by user + p = preference; + } + return p; + }; + var findExemplars = function findExemplars(n, R, A) { + var indices = []; + for (var i = 0; i < n; i++) { + if (R[i * n + i] + A[i * n + i] > 0) { + indices.push(i); + } + } + return indices; + }; + var assignClusters = function assignClusters(n, S, exemplars) { + var clusters = []; + for (var i = 0; i < n; i++) { + var index = -1; + var max = -Infinity; + for (var ei = 0; ei < exemplars.length; ei++) { + var e = exemplars[ei]; + if (S[i * n + e] > max) { + index = e; + max = S[i * n + e]; + } + } + if (index > 0) { + clusters.push(index); + } + } + for (var _ei = 0; _ei < exemplars.length; _ei++) { + clusters[exemplars[_ei]] = exemplars[_ei]; + } + return clusters; + }; + var assign = function assign(n, S, exemplars) { + var clusters = assignClusters(n, S, exemplars); + for (var ei = 0; ei < exemplars.length; ei++) { + var ii = []; + for (var c = 0; c < clusters.length; c++) { + if (clusters[c] === exemplars[ei]) { + ii.push(c); + } + } + var maxI = -1; + var maxSum = -Infinity; + for (var i = 0; i < ii.length; i++) { + var sum = 0; + for (var j = 0; j < ii.length; j++) { + sum += S[ii[j] * n + ii[i]]; + } + if (sum > maxSum) { + maxI = i; + maxSum = sum; + } + } + exemplars[ei] = ii[maxI]; + } + clusters = assignClusters(n, S, exemplars); + return clusters; + }; + var affinityPropagation = function affinityPropagation(options) { + var cy = this.cy(); + var nodes = this.nodes(); + var opts = setOptions(options); + + // Map each node to its position in node array + var id2position = {}; + for (var i = 0; i < nodes.length; i++) { + id2position[nodes[i].id()] = i; + } - set width( value ) { + // Begin affinity propagation algorithm - this.x = value; + var n; // number of data points + var n2; // size of matrices + var S; // similarity matrix (1D array) + var p; // preference/suitability of a data point to serve as an exemplar + var R; // responsibility matrix (1D array) + var A; // availability matrix (1D array) - } + n = nodes.length; + n2 = n * n; - get height() { + // Initialize and build S similarity matrix + S = new Array(n2); + for (var _i = 0; _i < n2; _i++) { + S[_i] = -Infinity; // for cases where two data points shouldn't be linked together + } - return this.y; + for (var _i2 = 0; _i2 < n; _i2++) { + for (var j = 0; j < n; j++) { + if (_i2 !== j) { + S[_i2 * n + j] = getSimilarity(opts.distance, nodes[_i2], nodes[j], opts.attributes); + } + } + } - } + // Place preferences on the diagonal of S + p = getPreference(S, opts.preference); + for (var _i3 = 0; _i3 < n; _i3++) { + S[_i3 * n + _i3] = p; + } - set height( value ) { + // Initialize R responsibility matrix + R = new Array(n2); + for (var _i4 = 0; _i4 < n2; _i4++) { + R[_i4] = 0.0; + } - this.y = value; + // Initialize A availability matrix + A = new Array(n2); + for (var _i5 = 0; _i5 < n2; _i5++) { + A[_i5] = 0.0; + } + var old = new Array(n); + var Rp = new Array(n); + var se = new Array(n); + for (var _i6 = 0; _i6 < n; _i6++) { + old[_i6] = 0.0; + Rp[_i6] = 0.0; + se[_i6] = 0; + } + var e = new Array(n * opts.minIterations); + for (var _i7 = 0; _i7 < e.length; _i7++) { + e[_i7] = 0; + } + var iter; + for (iter = 0; iter < opts.maxIterations; iter++) { + // main algorithmic loop + + // Update R responsibility matrix + for (var _i8 = 0; _i8 < n; _i8++) { + var max = -Infinity, + max2 = -Infinity, + maxI = -1, + AS = 0.0; + for (var _j = 0; _j < n; _j++) { + old[_j] = R[_i8 * n + _j]; + AS = A[_i8 * n + _j] + S[_i8 * n + _j]; + if (AS >= max) { + max2 = max; + max = AS; + maxI = _j; + } else if (AS > max2) { + max2 = AS; + } + } + for (var _j2 = 0; _j2 < n; _j2++) { + R[_i8 * n + _j2] = (1 - opts.damping) * (S[_i8 * n + _j2] - max) + opts.damping * old[_j2]; + } + R[_i8 * n + maxI] = (1 - opts.damping) * (S[_i8 * n + maxI] - max2) + opts.damping * old[maxI]; + } - } + // Update A availability matrix + for (var _i9 = 0; _i9 < n; _i9++) { + var sum = 0; + for (var _j3 = 0; _j3 < n; _j3++) { + old[_j3] = A[_j3 * n + _i9]; + Rp[_j3] = Math.max(0, R[_j3 * n + _i9]); + sum += Rp[_j3]; + } + sum -= Rp[_i9]; + Rp[_i9] = R[_i9 * n + _i9]; + sum += Rp[_i9]; + for (var _j4 = 0; _j4 < n; _j4++) { + A[_j4 * n + _i9] = (1 - opts.damping) * Math.min(0, sum - Rp[_j4]) + opts.damping * old[_j4]; + } + A[_i9 * n + _i9] = (1 - opts.damping) * (sum - Rp[_i9]) + opts.damping * old[_i9]; + } - set( x, y ) { + // Check for convergence + var K = 0; + for (var _i10 = 0; _i10 < n; _i10++) { + var E = A[_i10 * n + _i10] + R[_i10 * n + _i10] > 0 ? 1 : 0; + e[iter % opts.minIterations * n + _i10] = E; + K += E; + } + if (K > 0 && (iter >= opts.minIterations - 1 || iter == opts.maxIterations - 1)) { + var _sum = 0; + for (var _i11 = 0; _i11 < n; _i11++) { + se[_i11] = 0; + for (var _j5 = 0; _j5 < opts.minIterations; _j5++) { + se[_i11] += e[_j5 * n + _i11]; + } + if (se[_i11] === 0 || se[_i11] === opts.minIterations) { + _sum++; + } + } + if (_sum === n) { + // then we have convergence + break; + } + } + } - this.x = x; - this.y = y; + // Identify exemplars (cluster centers) + var exemplarsIndices = findExemplars(n, R, A); - return this; + // Assign nodes to clusters + var clusterIndices = assign(n, S, exemplarsIndices); + var clusters = {}; + for (var c = 0; c < exemplarsIndices.length; c++) { + clusters[exemplarsIndices[c]] = []; + } + for (var _i12 = 0; _i12 < nodes.length; _i12++) { + var pos = id2position[nodes[_i12].id()]; + var clusterIndex = clusterIndices[pos]; + if (clusterIndex != null) { + // the node may have not been assigned a cluster if no valid attributes were specified + clusters[clusterIndex].push(nodes[_i12]); + } + } + var retClusters = new Array(exemplarsIndices.length); + for (var _c = 0; _c < exemplarsIndices.length; _c++) { + retClusters[_c] = cy.collection(clusters[exemplarsIndices[_c]]); + } + return retClusters; + }; + var affinityPropagation$1 = { + affinityPropagation: affinityPropagation, + ap: affinityPropagation + }; - } + var hierholzerDefaults = defaults$g({ + root: undefined, + directed: false + }); + var elesfn$k = { + hierholzer: function hierholzer(options) { + if (!plainObject(options)) { + var args = arguments; + options = { + root: args[0], + directed: args[1] + }; + } + var _hierholzerDefaults = hierholzerDefaults(options), + root = _hierholzerDefaults.root, + directed = _hierholzerDefaults.directed; + var eles = this; + var dflag = false; + var oddIn; + var oddOut; + var startVertex; + if (root) startVertex = string(root) ? this.filter(root)[0].id() : root[0].id(); + var nodes = {}; + var edges = {}; + if (directed) { + eles.forEach(function (ele) { + var id = ele.id(); + if (ele.isNode()) { + var ind = ele.indegree(true); + var outd = ele.outdegree(true); + var d1 = ind - outd; + var d2 = outd - ind; + if (d1 == 1) { + if (oddIn) dflag = true;else oddIn = id; + } else if (d2 == 1) { + if (oddOut) dflag = true;else oddOut = id; + } else if (d2 > 1 || d1 > 1) { + dflag = true; + } + nodes[id] = []; + ele.outgoers().forEach(function (e) { + if (e.isEdge()) nodes[id].push(e.id()); + }); + } else { + edges[id] = [undefined, ele.target().id()]; + } + }); + } else { + eles.forEach(function (ele) { + var id = ele.id(); + if (ele.isNode()) { + var d = ele.degree(true); + if (d % 2) { + if (!oddIn) oddIn = id;else if (!oddOut) oddOut = id;else dflag = true; + } + nodes[id] = []; + ele.connectedEdges().forEach(function (e) { + return nodes[id].push(e.id()); + }); + } else { + edges[id] = [ele.source().id(), ele.target().id()]; + } + }); + } + var result = { + found: false, + trail: undefined + }; + if (dflag) return result;else if (oddOut && oddIn) { + if (directed) { + if (startVertex && oddOut != startVertex) { + return result; + } + startVertex = oddOut; + } else { + if (startVertex && oddOut != startVertex && oddIn != startVertex) { + return result; + } else if (!startVertex) { + startVertex = oddOut; + } + } + } else { + if (!startVertex) startVertex = eles[0].id(); + } + var walk = function walk(v) { + var currentNode = v; + var subtour = [v]; + var adj, adjTail, adjHead; + while (nodes[currentNode].length) { + adj = nodes[currentNode].shift(); + adjTail = edges[adj][0]; + adjHead = edges[adj][1]; + if (currentNode != adjHead) { + nodes[adjHead] = nodes[adjHead].filter(function (e) { + return e != adj; + }); + currentNode = adjHead; + } else if (!directed && currentNode != adjTail) { + nodes[adjTail] = nodes[adjTail].filter(function (e) { + return e != adj; + }); + currentNode = adjTail; + } + subtour.unshift(adj); + subtour.unshift(currentNode); + } + return subtour; + }; + var trail = []; + var subtour = []; + subtour = walk(startVertex); + while (subtour.length != 1) { + if (nodes[subtour[0]].length == 0) { + trail.unshift(eles.getElementById(subtour.shift())); + trail.unshift(eles.getElementById(subtour.shift())); + } else { + subtour = walk(subtour.shift()).concat(subtour); + } + } + trail.unshift(eles.getElementById(subtour.shift())); // final node - setScalar( scalar ) { + for (var d in nodes) { + if (nodes[d].length) { + return result; + } + } + result.found = true; + result.trail = this.spawn(trail, true); + return result; + } + }; - this.x = scalar; - this.y = scalar; - - return this; - - } - - setX( x ) { + var hopcroftTarjanBiconnected = function hopcroftTarjanBiconnected() { + var eles = this; + var nodes = {}; + var id = 0; + var edgeCount = 0; + var components = []; + var stack = []; + var visitedEdges = {}; + var buildComponent = function buildComponent(x, y) { + var i = stack.length - 1; + var cutset = []; + var component = eles.spawn(); + while (stack[i].x != x || stack[i].y != y) { + cutset.push(stack.pop().edge); + i--; + } + cutset.push(stack.pop().edge); + cutset.forEach(function (edge) { + var connectedNodes = edge.connectedNodes().intersection(eles); + component.merge(edge); + connectedNodes.forEach(function (node) { + var nodeId = node.id(); + var connectedEdges = node.connectedEdges().intersection(eles); + component.merge(node); + if (!nodes[nodeId].cutVertex) { + component.merge(connectedEdges); + } else { + component.merge(connectedEdges.filter(function (edge) { + return edge.isLoop(); + })); + } + }); + }); + components.push(component); + }; + var biconnectedSearch = function biconnectedSearch(root, currentNode, parent) { + if (root === parent) edgeCount += 1; + nodes[currentNode] = { + id: id, + low: id++, + cutVertex: false + }; + var edges = eles.getElementById(currentNode).connectedEdges().intersection(eles); + if (edges.size() === 0) { + components.push(eles.spawn(eles.getElementById(currentNode))); + } else { + var sourceId, targetId, otherNodeId, edgeId; + edges.forEach(function (edge) { + sourceId = edge.source().id(); + targetId = edge.target().id(); + otherNodeId = sourceId === currentNode ? targetId : sourceId; + if (otherNodeId !== parent) { + edgeId = edge.id(); + if (!visitedEdges[edgeId]) { + visitedEdges[edgeId] = true; + stack.push({ + x: currentNode, + y: otherNodeId, + edge: edge + }); + } + if (!(otherNodeId in nodes)) { + biconnectedSearch(root, otherNodeId, currentNode); + nodes[currentNode].low = Math.min(nodes[currentNode].low, nodes[otherNodeId].low); + if (nodes[currentNode].id <= nodes[otherNodeId].low) { + nodes[currentNode].cutVertex = true; + buildComponent(currentNode, otherNodeId); + } + } else { + nodes[currentNode].low = Math.min(nodes[currentNode].low, nodes[otherNodeId].id); + } + } + }); + } + }; + eles.forEach(function (ele) { + if (ele.isNode()) { + var nodeId = ele.id(); + if (!(nodeId in nodes)) { + edgeCount = 0; + biconnectedSearch(nodeId, nodeId); + nodes[nodeId].cutVertex = edgeCount > 1; + } + } + }); + var cutVertices = Object.keys(nodes).filter(function (id) { + return nodes[id].cutVertex; + }).map(function (id) { + return eles.getElementById(id); + }); + return { + cut: eles.spawn(cutVertices), + components: components + }; + }; + var hopcroftTarjanBiconnected$1 = { + hopcroftTarjanBiconnected: hopcroftTarjanBiconnected, + htbc: hopcroftTarjanBiconnected, + htb: hopcroftTarjanBiconnected, + hopcroftTarjanBiconnectedComponents: hopcroftTarjanBiconnected + }; - this.x = x; + var tarjanStronglyConnected = function tarjanStronglyConnected() { + var eles = this; + var nodes = {}; + var index = 0; + var components = []; + var stack = []; + var cut = eles.spawn(eles); + var stronglyConnectedSearch = function stronglyConnectedSearch(sourceNodeId) { + stack.push(sourceNodeId); + nodes[sourceNodeId] = { + index: index, + low: index++, + explored: false + }; + var connectedEdges = eles.getElementById(sourceNodeId).connectedEdges().intersection(eles); + connectedEdges.forEach(function (edge) { + var targetNodeId = edge.target().id(); + if (targetNodeId !== sourceNodeId) { + if (!(targetNodeId in nodes)) { + stronglyConnectedSearch(targetNodeId); + } + if (!nodes[targetNodeId].explored) { + nodes[sourceNodeId].low = Math.min(nodes[sourceNodeId].low, nodes[targetNodeId].low); + } + } + }); + if (nodes[sourceNodeId].index === nodes[sourceNodeId].low) { + var componentNodes = eles.spawn(); + for (;;) { + var nodeId = stack.pop(); + componentNodes.merge(eles.getElementById(nodeId)); + nodes[nodeId].low = nodes[sourceNodeId].index; + nodes[nodeId].explored = true; + if (nodeId === sourceNodeId) { + break; + } + } + var componentEdges = componentNodes.edgesWith(componentNodes); + var component = componentNodes.merge(componentEdges); + components.push(component); + cut = cut.difference(component); + } + }; + eles.forEach(function (ele) { + if (ele.isNode()) { + var nodeId = ele.id(); + if (!(nodeId in nodes)) { + stronglyConnectedSearch(nodeId); + } + } + }); + return { + cut: cut, + components: components + }; + }; + var tarjanStronglyConnected$1 = { + tarjanStronglyConnected: tarjanStronglyConnected, + tsc: tarjanStronglyConnected, + tscc: tarjanStronglyConnected, + tarjanStronglyConnectedComponents: tarjanStronglyConnected + }; - return this; + var elesfn$j = {}; + [elesfn$v, elesfn$u, elesfn$t, elesfn$s, elesfn$r, elesfn$q, elesfn$p, elesfn$o, elesfn$n, elesfn$m, elesfn$l, markovClustering$1, kClustering, hierarchicalClustering$1, affinityPropagation$1, elesfn$k, hopcroftTarjanBiconnected$1, tarjanStronglyConnected$1].forEach(function (props) { + extend$1(elesfn$j, props); + }); - } + /*! + Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable + Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com) + Licensed under The MIT License (http://opensource.org/licenses/MIT) + */ - setY( y ) { + /* promise states [Promises/A+ 2.1] */ + var STATE_PENDING = 0; /* [Promises/A+ 2.1.1] */ + var STATE_FULFILLED = 1; /* [Promises/A+ 2.1.2] */ + var STATE_REJECTED = 2; /* [Promises/A+ 2.1.3] */ + + /* promise object constructor */ + var api = function api(executor) { + /* optionally support non-constructor/plain-function call */ + if (!(this instanceof api)) return new api(executor); + + /* initialize object */ + this.id = 'Thenable/1.0.7'; + this.state = STATE_PENDING; /* initial state */ + this.fulfillValue = undefined; /* initial value */ /* [Promises/A+ 1.3, 2.1.2.2] */ + this.rejectReason = undefined; /* initial reason */ /* [Promises/A+ 1.5, 2.1.3.2] */ + this.onFulfilled = []; /* initial handlers */ + this.onRejected = []; /* initial handlers */ + + /* provide optional information-hiding proxy */ + this.proxy = { + then: this.then.bind(this) + }; + + /* support optional executor function */ + if (typeof executor === 'function') executor.call(this, this.fulfill.bind(this), this.reject.bind(this)); + }; - this.y = y; + /* promise API methods */ + api.prototype = { + /* promise resolving methods */ + fulfill: function fulfill(value) { + return deliver(this, STATE_FULFILLED, 'fulfillValue', value); + }, + reject: function reject(value) { + return deliver(this, STATE_REJECTED, 'rejectReason', value); + }, + /* "The then Method" [Promises/A+ 1.1, 1.2, 2.2] */ + then: function then(onFulfilled, onRejected) { + var curr = this; + var next = new api(); /* [Promises/A+ 2.2.7] */ + curr.onFulfilled.push(resolver(onFulfilled, next, 'fulfill')); /* [Promises/A+ 2.2.2/2.2.6] */ + curr.onRejected.push(resolver(onRejected, next, 'reject')); /* [Promises/A+ 2.2.3/2.2.6] */ + execute(curr); + return next.proxy; /* [Promises/A+ 2.2.7, 3.3] */ + } + }; - return this; + /* deliver an action */ + var deliver = function deliver(curr, state, name, value) { + if (curr.state === STATE_PENDING) { + curr.state = state; /* [Promises/A+ 2.1.2.1, 2.1.3.1] */ + curr[name] = value; /* [Promises/A+ 2.1.2.2, 2.1.3.2] */ + execute(curr); + } + return curr; + }; - } + /* execute all handlers */ + var execute = function execute(curr) { + if (curr.state === STATE_FULFILLED) execute_handlers(curr, 'onFulfilled', curr.fulfillValue);else if (curr.state === STATE_REJECTED) execute_handlers(curr, 'onRejected', curr.rejectReason); + }; - setComponent( index, value ) { + /* execute particular set of handlers */ + var execute_handlers = function execute_handlers(curr, name, value) { + /* global setImmediate: true */ + /* global setTimeout: true */ + + /* short-circuit processing */ + if (curr[name].length === 0) return; + + /* iterate over all handlers, exactly once */ + var handlers = curr[name]; + curr[name] = []; /* [Promises/A+ 2.2.2.3, 2.2.3.3] */ + var func = function func() { + for (var i = 0; i < handlers.length; i++) { + handlers[i](value); + } /* [Promises/A+ 2.2.5] */ + }; + + /* execute procedure asynchronously */ /* [Promises/A+ 2.2.4, 3.1] */ + if (typeof setImmediate === 'function') setImmediate(func);else setTimeout(func, 0); + }; - switch ( index ) { + /* generate a resolver function */ + var resolver = function resolver(cb, next, method) { + return function (value) { + if (typeof cb !== 'function') /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */ + next[method].call(next, value); /* [Promises/A+ 2.2.7.3, 2.2.7.4] */else { + var result; + try { + result = cb(value); + } /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */ catch (e) { + next.reject(e); /* [Promises/A+ 2.2.7.2] */ + return; + } + resolve(next, result); /* [Promises/A+ 2.2.7.1] */ + } + }; + }; - case 0: this.x = value; break; - case 1: this.y = value; break; - default: throw new Error( 'index is out of range: ' + index ); + /* "Promise Resolution Procedure" */ /* [Promises/A+ 2.3] */ + var resolve = function resolve(promise, x) { + /* sanity check arguments */ /* [Promises/A+ 2.3.1] */ + if (promise === x || promise.proxy === x) { + promise.reject(new TypeError('cannot resolve promise with itself')); + return; + } - } + /* surgically check for a "then" method + (mainly to just call the "getter" of "then" only once) */ + var then; + if (_typeof(x) === 'object' && x !== null || typeof x === 'function') { + try { + then = x.then; + } /* [Promises/A+ 2.3.3.1, 3.5] */ catch (e) { + promise.reject(e); /* [Promises/A+ 2.3.3.2] */ + return; + } + } - return this; + /* handle own Thenables [Promises/A+ 2.3.2] + and similar "thenables" [Promises/A+ 2.3.3] */ + if (typeof then === 'function') { + var resolved = false; + try { + /* call retrieved "then" method */ /* [Promises/A+ 2.3.3.3] */ + then.call(x, /* resolvePromise */ /* [Promises/A+ 2.3.3.3.1] */ + function (y) { + if (resolved) return; + resolved = true; /* [Promises/A+ 2.3.3.3.3] */ + if (y === x) /* [Promises/A+ 3.6] */ + promise.reject(new TypeError('circular thenable chain'));else resolve(promise, y); + }, /* rejectPromise */ /* [Promises/A+ 2.3.3.3.2] */ + function (r) { + if (resolved) return; + resolved = true; /* [Promises/A+ 2.3.3.3.3] */ + promise.reject(r); + }); + } catch (e) { + if (!resolved) /* [Promises/A+ 2.3.3.3.3] */ + promise.reject(e); /* [Promises/A+ 2.3.3.3.4] */ + } - } + return; + } - getComponent( index ) { + /* handle other values */ + promise.fulfill(x); /* [Promises/A+ 2.3.4, 2.3.3.4] */ + }; - switch ( index ) { + // so we always have Promise.all() + api.all = function (ps) { + return new api(function (resolveAll, rejectAll) { + var vals = new Array(ps.length); + var doneCount = 0; + var fulfill = function fulfill(i, val) { + vals[i] = val; + doneCount++; + if (doneCount === ps.length) { + resolveAll(vals); + } + }; + for (var i = 0; i < ps.length; i++) { + (function (i) { + var p = ps[i]; + var isPromise = p != null && p.then != null; + if (isPromise) { + p.then(function (val) { + fulfill(i, val); + }, function (err) { + rejectAll(err); + }); + } else { + var val = p; + fulfill(i, val); + } + })(i); + } + }); + }; + api.resolve = function (val) { + return new api(function (resolve, reject) { + resolve(val); + }); + }; + api.reject = function (val) { + return new api(function (resolve, reject) { + reject(val); + }); + }; + var Promise$1 = typeof Promise !== 'undefined' ? Promise : api; // eslint-disable-line no-undef + + var Animation = function Animation(target, opts, opts2) { + var isCore = core$1(target); + var isEle = !isCore; + var _p = this._private = extend$1({ + duration: 1000 + }, opts, opts2); + _p.target = target; + _p.style = _p.style || _p.css; + _p.started = false; + _p.playing = false; + _p.hooked = false; + _p.applying = false; + _p.progress = 0; + _p.completes = []; + _p.frames = []; + if (_p.complete && fn$6(_p.complete)) { + _p.completes.push(_p.complete); + } + if (isEle) { + var pos = target.position(); + _p.startPosition = _p.startPosition || { + x: pos.x, + y: pos.y + }; + _p.startStyle = _p.startStyle || target.cy().style().getAnimationStartStyle(target, _p.style); + } + if (isCore) { + var pan = target.pan(); + _p.startPan = { + x: pan.x, + y: pan.y + }; + _p.startZoom = target.zoom(); + } - case 0: return this.x; - case 1: return this.y; - default: throw new Error( 'index is out of range: ' + index ); + // for future timeline/animations impl + this.length = 1; + this[0] = this; + }; + var anifn = Animation.prototype; + extend$1(anifn, { + instanceString: function instanceString() { + return 'animation'; + }, + hook: function hook() { + var _p = this._private; + if (!_p.hooked) { + // add to target's animation queue + var q; + var tAni = _p.target._private.animation; + if (_p.queue) { + q = tAni.queue; + } else { + q = tAni.current; + } + q.push(this); + + // add to the animation loop pool + if (elementOrCollection(_p.target)) { + _p.target.cy().addToAnimationPool(_p.target); + } + _p.hooked = true; + } + return this; + }, + play: function play() { + var _p = this._private; + + // autorewind + if (_p.progress === 1) { + _p.progress = 0; + } + _p.playing = true; + _p.started = false; // needs to be started by animation loop + _p.stopped = false; + this.hook(); + + // the animation loop will start the animation... + + return this; + }, + playing: function playing() { + return this._private.playing; + }, + apply: function apply() { + var _p = this._private; + _p.applying = true; + _p.started = false; // needs to be started by animation loop + _p.stopped = false; + this.hook(); + + // the animation loop will apply the animation at this progress + + return this; + }, + applying: function applying() { + return this._private.applying; + }, + pause: function pause() { + var _p = this._private; + _p.playing = false; + _p.started = false; + return this; + }, + stop: function stop() { + var _p = this._private; + _p.playing = false; + _p.started = false; + _p.stopped = true; // to be removed from animation queues + + return this; + }, + rewind: function rewind() { + return this.progress(0); + }, + fastforward: function fastforward() { + return this.progress(1); + }, + time: function time(t) { + var _p = this._private; + if (t === undefined) { + return _p.progress * _p.duration; + } else { + return this.progress(t / _p.duration); + } + }, + progress: function progress(p) { + var _p = this._private; + var wasPlaying = _p.playing; + if (p === undefined) { + return _p.progress; + } else { + if (wasPlaying) { + this.pause(); + } + _p.progress = p; + _p.started = false; + if (wasPlaying) { + this.play(); + } + } + return this; + }, + completed: function completed() { + return this._private.progress === 1; + }, + reverse: function reverse() { + var _p = this._private; + var wasPlaying = _p.playing; + if (wasPlaying) { + this.pause(); + } + _p.progress = 1 - _p.progress; + _p.started = false; + var swap = function swap(a, b) { + var _pa = _p[a]; + if (_pa == null) { + return; + } + _p[a] = _p[b]; + _p[b] = _pa; + }; + swap('zoom', 'startZoom'); + swap('pan', 'startPan'); + swap('position', 'startPosition'); + + // swap styles + if (_p.style) { + for (var i = 0; i < _p.style.length; i++) { + var prop = _p.style[i]; + var name = prop.name; + var startStyleProp = _p.startStyle[name]; + _p.startStyle[name] = prop; + _p.style[i] = startStyleProp; + } + } + if (wasPlaying) { + this.play(); + } + return this; + }, + promise: function promise(type) { + var _p = this._private; + var arr; + switch (type) { + case 'frame': + arr = _p.frames; + break; + default: + case 'complete': + case 'completed': + arr = _p.completes; + } + return new Promise$1(function (resolve, reject) { + arr.push(function () { + resolve(); + }); + }); + } + }); + anifn.complete = anifn.completed; + anifn.run = anifn.play; + anifn.running = anifn.playing; + + var define$3 = { + animated: function animated() { + return function animatedImpl() { + var self = this; + var selfIsArrayLike = self.length !== undefined; + var all = selfIsArrayLike ? self : [self]; // put in array if not array-like + var cy = this._private.cy || this; + if (!cy.styleEnabled()) { + return false; + } + var ele = all[0]; + if (ele) { + return ele._private.animation.current.length > 0; + } + }; + }, + // animated + + clearQueue: function clearQueue() { + return function clearQueueImpl() { + var self = this; + var selfIsArrayLike = self.length !== undefined; + var all = selfIsArrayLike ? self : [self]; // put in array if not array-like + var cy = this._private.cy || this; + if (!cy.styleEnabled()) { + return this; + } + for (var i = 0; i < all.length; i++) { + var ele = all[i]; + ele._private.animation.queue = []; + } + return this; + }; + }, + // clearQueue + + delay: function delay() { + return function delayImpl(time, complete) { + var cy = this._private.cy || this; + if (!cy.styleEnabled()) { + return this; + } + return this.animate({ + delay: time, + duration: time, + complete: complete + }); + }; + }, + // delay + + delayAnimation: function delayAnimation() { + return function delayAnimationImpl(time, complete) { + var cy = this._private.cy || this; + if (!cy.styleEnabled()) { + return this; + } + return this.animation({ + delay: time, + duration: time, + complete: complete + }); + }; + }, + // delay + + animation: function animation() { + return function animationImpl(properties, params) { + var self = this; + var selfIsArrayLike = self.length !== undefined; + var all = selfIsArrayLike ? self : [self]; // put in array if not array-like + var cy = this._private.cy || this; + var isCore = !selfIsArrayLike; + var isEles = !isCore; + if (!cy.styleEnabled()) { + return this; + } + var style = cy.style(); + properties = extend$1({}, properties, params); + var propertiesEmpty = Object.keys(properties).length === 0; + if (propertiesEmpty) { + return new Animation(all[0], properties); // nothing to animate + } + + if (properties.duration === undefined) { + properties.duration = 400; + } + switch (properties.duration) { + case 'slow': + properties.duration = 600; + break; + case 'fast': + properties.duration = 200; + break; + } + if (isEles) { + properties.style = style.getPropsList(properties.style || properties.css); + properties.css = undefined; + } + if (isEles && properties.renderedPosition != null) { + var rpos = properties.renderedPosition; + var pan = cy.pan(); + var zoom = cy.zoom(); + properties.position = renderedToModelPosition(rpos, zoom, pan); + } + + // override pan w/ panBy if set + if (isCore && properties.panBy != null) { + var panBy = properties.panBy; + var cyPan = cy.pan(); + properties.pan = { + x: cyPan.x + panBy.x, + y: cyPan.y + panBy.y + }; + } + + // override pan w/ center if set + var center = properties.center || properties.centre; + if (isCore && center != null) { + var centerPan = cy.getCenterPan(center.eles, properties.zoom); + if (centerPan != null) { + properties.pan = centerPan; + } + } + + // override pan & zoom w/ fit if set + if (isCore && properties.fit != null) { + var fit = properties.fit; + var fitVp = cy.getFitViewport(fit.eles || fit.boundingBox, fit.padding); + if (fitVp != null) { + properties.pan = fitVp.pan; + properties.zoom = fitVp.zoom; + } + } + + // override zoom (& potentially pan) w/ zoom obj if set + if (isCore && plainObject(properties.zoom)) { + var vp = cy.getZoomedViewport(properties.zoom); + if (vp != null) { + if (vp.zoomed) { + properties.zoom = vp.zoom; + } + if (vp.panned) { + properties.pan = vp.pan; + } + } else { + properties.zoom = null; // an inavalid zoom (e.g. no delta) gets automatically destroyed + } + } - } + return new Animation(all[0], properties); + }; + }, + // animate + + animate: function animate() { + return function animateImpl(properties, params) { + var self = this; + var selfIsArrayLike = self.length !== undefined; + var all = selfIsArrayLike ? self : [self]; // put in array if not array-like + var cy = this._private.cy || this; + if (!cy.styleEnabled()) { + return this; + } + if (params) { + properties = extend$1({}, properties, params); + } + + // manually hook and run the animation + for (var i = 0; i < all.length; i++) { + var ele = all[i]; + var queue = ele.animated() && (properties.queue === undefined || properties.queue); + var ani = ele.animation(properties, queue ? { + queue: true + } : undefined); + ani.play(); + } + return this; // chaining + }; + }, + + // animate + + stop: function stop() { + return function stopImpl(clearQueue, jumpToEnd) { + var self = this; + var selfIsArrayLike = self.length !== undefined; + var all = selfIsArrayLike ? self : [self]; // put in array if not array-like + var cy = this._private.cy || this; + if (!cy.styleEnabled()) { + return this; + } + for (var i = 0; i < all.length; i++) { + var ele = all[i]; + var _p = ele._private; + var anis = _p.animation.current; + for (var j = 0; j < anis.length; j++) { + var ani = anis[j]; + var ani_p = ani._private; + if (jumpToEnd) { + // next iteration of the animation loop, the animation + // will go straight to the end and be removed + ani_p.duration = 0; + } + } - } + // clear the queue of future animations + if (clearQueue) { + _p.animation.queue = []; + } + if (!jumpToEnd) { + _p.animation.current = []; + } + } - clone() { + // we have to notify (the animation loop doesn't do it for us on `stop`) + cy.notify('draw'); + return this; + }; + } // stop + }; // define - return new this.constructor( this.x, this.y ); + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; - } + var isArray_1 = isArray; - copy( v ) { + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; - this.x = v.x; - this.y = v.y; + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray_1(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol_1(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } - return this; + var _isKey = isKey; - } + /** `Object#toString` result references. */ + var asyncTag = '[object AsyncFunction]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; - add( v ) { + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject_1$1(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = _baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } - this.x += v.x; - this.y += v.y; + var isFunction_1 = isFunction; - return this; + /** Used to detect overreaching core-js shims. */ + var coreJsData = _root['__core-js_shared__']; - } + var _coreJsData = coreJsData; - addScalar( s ) { + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(_coreJsData && _coreJsData.keys && _coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); - this.x += s; - this.y += s; + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } - return this; + var _isMasked = isMasked; - } + /** Used for built-in method references. */ + var funcProto$1 = Function.prototype; - addVectors( a, b ) { + /** Used to resolve the decompiled source of functions. */ + var funcToString$1 = funcProto$1.toString; - this.x = a.x + b.x; - this.y = a.y + b.y; + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString$1.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; + } - return this; + var _toSource = toSource; - } + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - addScaledVector( v, s ) { + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; - this.x += v.x * s; - this.y += v.y * s; + /** Used for built-in method references. */ + var funcProto = Function.prototype, + objectProto$3 = Object.prototype; - return this; + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; - } + /** Used to check objects for own properties. */ + var hasOwnProperty$3 = objectProto$3.hasOwnProperty; - sub( v ) { + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty$3).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); - this.x -= v.x; - this.y -= v.y; + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject_1$1(value) || _isMasked(value)) { + return false; + } + var pattern = isFunction_1(value) ? reIsNative : reIsHostCtor; + return pattern.test(_toSource(value)); + } - return this; + var _baseIsNative = baseIsNative; - } + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue$1(object, key) { + return object == null ? undefined : object[key]; + } - subScalar( s ) { + var _getValue = getValue$1; - this.x -= s; - this.y -= s; + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = _getValue(object, key); + return _baseIsNative(value) ? value : undefined; + } - return this; + var _getNative = getNative; - } + /* Built-in method references that are verified to be native. */ + var nativeCreate = _getNative(Object, 'create'); - subVectors( a, b ) { + var _nativeCreate = nativeCreate; - this.x = a.x - b.x; - this.y = a.y - b.y; + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = _nativeCreate ? _nativeCreate(null) : {}; + this.size = 0; + } - return this; + var _hashClear = hashClear; - } + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } - multiply( v ) { + var _hashDelete = hashDelete; - this.x *= v.x; - this.y *= v.y; + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; - return this; + /** Used for built-in method references. */ + var objectProto$2 = Object.prototype; - } + /** Used to check objects for own properties. */ + var hasOwnProperty$2 = objectProto$2.hasOwnProperty; - multiplyScalar( scalar ) { + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (_nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED$1 ? undefined : result; + } + return hasOwnProperty$2.call(data, key) ? data[key] : undefined; + } - this.x *= scalar; - this.y *= scalar; + var _hashGet = hashGet; - return this; + /** Used for built-in method references. */ + var objectProto$1 = Object.prototype; - } + /** Used to check objects for own properties. */ + var hasOwnProperty$1 = objectProto$1.hasOwnProperty; - divide( v ) { + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return _nativeCreate ? (data[key] !== undefined) : hasOwnProperty$1.call(data, key); + } - this.x /= v.x; - this.y /= v.y; + var _hashHas = hashHas; - return this; + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; - } + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (_nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; + } - divideScalar( scalar ) { + var _hashSet = hashSet; - return this.multiplyScalar( 1 / scalar ); + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } - } + // Add methods to `Hash`. + Hash.prototype.clear = _hashClear; + Hash.prototype['delete'] = _hashDelete; + Hash.prototype.get = _hashGet; + Hash.prototype.has = _hashHas; + Hash.prototype.set = _hashSet; - applyMatrix3( m ) { + var _Hash = Hash; - const x = this.x, y = this.y; - const e = m.elements; + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; + var _listCacheClear = listCacheClear; - return this; + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } - } + var eq_1 = eq; - min( v ) { + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq_1(array[length][0], key)) { + return length; + } + } + return -1; + } - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); + var _assocIndexOf = assocIndexOf; - return this; + /** Used for built-in method references. */ + var arrayProto = Array.prototype; - } + /** Built-in value references. */ + var splice = arrayProto.splice; - max( v ) { + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = _assocIndexOf(data, key); - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } - return this; + var _listCacheDelete = listCacheDelete; - } + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = _assocIndexOf(data, key); - clamp( min, max ) { + return index < 0 ? undefined : data[index][1]; + } - // assumes min < max, componentwise + var _listCacheGet = listCacheGet; - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return _assocIndexOf(this.__data__, key) > -1; + } - return this; + var _listCacheHas = listCacheHas; - } + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = _assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } - clampScalar( minVal, maxVal ) { + var _listCacheSet = listCacheSet; - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } - return this; + // Add methods to `ListCache`. + ListCache.prototype.clear = _listCacheClear; + ListCache.prototype['delete'] = _listCacheDelete; + ListCache.prototype.get = _listCacheGet; + ListCache.prototype.has = _listCacheHas; + ListCache.prototype.set = _listCacheSet; - } + var _ListCache = ListCache; - clampLength( min, max ) { + /* Built-in method references that are verified to be native. */ + var Map$1 = _getNative(_root, 'Map'); - const length = this.length(); + var _Map = Map$1; - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new _Hash, + 'map': new (_Map || _ListCache), + 'string': new _Hash + }; + } - } + var _mapCacheClear = mapCacheClear; - floor() { + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); + var _isKeyable = isKeyable; - return this; + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return _isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } - } + var _getMapData = getMapData; - ceil() { + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = _getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); + var _mapCacheDelete = mapCacheDelete; - return this; + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return _getMapData(this, key).get(key); + } - } + var _mapCacheGet = mapCacheGet; - round() { + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return _getMapData(this, key).has(key); + } - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); + var _mapCacheHas = mapCacheHas; - return this; + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = _getMapData(this, key), + size = data.size; - } + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } - roundToZero() { + var _mapCacheSet = mapCacheSet; - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } - return this; + // Add methods to `MapCache`. + MapCache.prototype.clear = _mapCacheClear; + MapCache.prototype['delete'] = _mapCacheDelete; + MapCache.prototype.get = _mapCacheGet; + MapCache.prototype.has = _mapCacheHas; + MapCache.prototype.set = _mapCacheSet; - } + var _MapCache = MapCache; - negate() { + /** Error message constants. */ + var FUNC_ERROR_TEXT = 'Expected a function'; - this.x = - this.x; - this.y = - this.y; + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; - return this; + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || _MapCache); + return memoized; + } - } + // Expose `MapCache`. + memoize.Cache = _MapCache; - dot( v ) { + var memoize_1 = memoize; - return this.x * v.x + this.y * v.y; + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; - } + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize_1(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); - cross( v ) { + var cache = result.cache; + return result; + } - return this.x * v.y - this.y * v.x; + var _memoizeCapped = memoizeCapped; - } + /** Used to match property names within property paths. */ + var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - lengthSq() { + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; - return this.x * this.x + this.y * this.y; + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = _memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); - } + var _stringToPath = stringToPath; - length() { + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); - return Math.sqrt( this.x * this.x + this.y * this.y ); + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } - } + var _arrayMap = arrayMap; - manhattanLength() { + /** Used as references for various `Number` constants. */ + var INFINITY$1 = 1 / 0; - return Math.abs( this.x ) + Math.abs( this.y ); + /** Used to convert symbols to primitives and strings. */ + var symbolProto = _Symbol ? _Symbol.prototype : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; - } + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray_1(value)) { + // Recursively convert values (susceptible to call stack limits). + return _arrayMap(value, baseToString) + ''; + } + if (isSymbol_1(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; + } - normalize() { + var _baseToString = baseToString; - return this.divideScalar( this.length() || 1 ); + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString$1(value) { + return value == null ? '' : _baseToString(value); + } - } + var toString_1 = toString$1; - angle() { + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray_1(value)) { + return value; + } + return _isKey(value, object) ? [value] : _stringToPath(toString_1(value)); + } - // computes the angle in radians with respect to the positive x-axis + var _castPath = castPath; - const angle = Math.atan2( - this.y, - this.x ) + Math.PI; + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0; - return angle; + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol_1(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } - } + var _toKey = toKey; - distanceTo( v ) { + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = _castPath(path, object); - return Math.sqrt( this.distanceToSquared( v ) ); + var index = 0, + length = path.length; - } + while (object != null && index < length) { + object = object[_toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } - distanceToSquared( v ) { + var _baseGet = baseGet; - const dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : _baseGet(object, path); + return result === undefined ? defaultValue : result; + } - } + var get_1 = get; - manhattanDistanceTo( v ) { + var defineProperty = (function() { + try { + var func = _getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); + var _defineProperty = defineProperty; - } + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && _defineProperty) { + _defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } - setLength( length ) { + var _baseAssignValue = baseAssignValue; - return this.normalize().multiplyScalar( length ); + /** Used for built-in method references. */ + var objectProto = Object.prototype; - } + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; - lerp( v, alpha ) { + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq_1(objValue, value)) || + (value === undefined && !(key in object))) { + _baseAssignValue(object, key, value); + } + } - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; + var _assignValue = assignValue; - return this; + /** Used as references for various `Number` constants. */ + var MAX_SAFE_INTEGER = 9007199254740991; - } + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; - lerpVectors( v1, v2, alpha ) { + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); + } - return this; + var _isIndex = isIndex; - } + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject_1$1(object)) { + return object; + } + path = _castPath(path, object); - equals( v ) { + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; - return ( ( v.x === this.x ) && ( v.y === this.y ) ); + while (nested != null && ++index < length) { + var key = _toKey(path[index]), + newValue = value; - } + if (key === '__proto__' || key === 'constructor' || key === 'prototype') { + return object; + } - fromArray( array, offset = 0 ) { + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject_1$1(objValue) + ? objValue + : (_isIndex(path[index + 1]) ? [] : {}); + } + } + _assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; + var _baseSet = baseSet; - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; + /** + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.set(object, 'a[0].b.c', 4); + * console.log(object.a[0].b.c); + * // => 4 + * + * _.set(object, ['x', '0', 'y', 'z'], 5); + * console.log(object.x[0].y.z); + * // => 5 + */ + function set$1(object, path, value) { + return object == null ? object : _baseSet(object, path, value); + } - return array; + var set_1 = set$1; - } + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray$2(source, array) { + var index = -1, + length = source.length; - fromBufferAttribute( attribute, index ) { + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); + var _copyArray = copyArray$2; - return this; + /** + * Converts `value` to a property path array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Util + * @param {*} value The value to convert. + * @returns {Array} Returns the new property path array. + * @example + * + * _.toPath('a.b.c'); + * // => ['a', 'b', 'c'] + * + * _.toPath('a[0].b.c'); + * // => ['a', '0', 'b', 'c'] + */ + function toPath(value) { + if (isArray_1(value)) { + return _arrayMap(value, _toKey); + } + return isSymbol_1(value) ? [value] : _copyArray(_stringToPath(toString_1(value))); + } + + var toPath_1 = toPath; + + var define$2 = { + // access data field + data: function data(params) { + var defaults = { + field: 'data', + bindingEvent: 'data', + allowBinding: false, + allowSetting: false, + allowGetting: false, + settingEvent: 'data', + settingTriggersEvent: false, + triggerFnName: 'trigger', + immutableKeys: {}, + // key => true if immutable + updateStyle: false, + beforeGet: function beforeGet(self) {}, + beforeSet: function beforeSet(self, obj) {}, + onSet: function onSet(self) {}, + canSet: function canSet(self) { + return true; + } + }; + params = extend$1({}, defaults, params); + return function dataImpl(name, value) { + var p = params; + var self = this; + var selfIsArrayLike = self.length !== undefined; + var all = selfIsArrayLike ? self : [self]; // put in array if not array-like + var single = selfIsArrayLike ? self[0] : self; + + // .data('foo', ...) + if (string(name)) { + // set or get property + var isPathLike = name.indexOf('.') !== -1; // there might be a normal field with a dot + var path = isPathLike && toPath_1(name); + + // .data('foo') + if (p.allowGetting && value === undefined) { + // get + + var ret; + if (single) { + p.beforeGet(single); + + // check if it's path and a field with the same name doesn't exist + if (path && single._private[p.field][name] === undefined) { + ret = get_1(single._private[p.field], path); + } else { + ret = single._private[p.field][name]; + } + } + return ret; + + // .data('foo', 'bar') + } else if (p.allowSetting && value !== undefined) { + // set + var valid = !p.immutableKeys[name]; + if (valid) { + var change = _defineProperty$1({}, name, value); + p.beforeSet(self, change); + for (var i = 0, l = all.length; i < l; i++) { + var ele = all[i]; + if (p.canSet(ele)) { + if (path && single._private[p.field][name] === undefined) { + set_1(ele._private[p.field], path, value); + } else { + ele._private[p.field][name] = value; + } + } + } - } + // update mappers if asked + if (p.updateStyle) { + self.updateStyle(); + } - rotateAround( center, angle ) { + // call onSet callback + p.onSet(self); + if (p.settingTriggersEvent) { + self[p.triggerFnName](p.settingEvent); + } + } + } - const c = Math.cos( angle ), s = Math.sin( angle ); + // .data({ 'foo': 'bar' }) + } else if (p.allowSetting && plainObject(name)) { + // extend + var obj = name; + var k, v; + var keys = Object.keys(obj); + p.beforeSet(self, obj); + for (var _i = 0; _i < keys.length; _i++) { + k = keys[_i]; + v = obj[k]; + var _valid = !p.immutableKeys[k]; + if (_valid) { + for (var j = 0; j < all.length; j++) { + var _ele = all[j]; + if (p.canSet(_ele)) { + _ele._private[p.field][k] = v; + } + } + } + } - const x = this.x - center.x; - const y = this.y - center.y; + // update mappers if asked + if (p.updateStyle) { + self.updateStyle(); + } - this.x = x * c - y * s + center.x; - this.y = x * s + y * c + center.y; + // call onSet callback + p.onSet(self); + if (p.settingTriggersEvent) { + self[p.triggerFnName](p.settingEvent); + } - return this; + // .data(function(){ ... }) + } else if (p.allowBinding && fn$6(name)) { + // bind to event + var fn = name; + self.on(p.bindingEvent, fn); + + // .data() + } else if (p.allowGetting && name === undefined) { + // get whole object + var _ret; + if (single) { + p.beforeGet(single); + _ret = single._private[p.field]; + } + return _ret; + } + return self; // maintain chainability + }; // function + }, + + // data + + // remove data field + removeData: function removeData(params) { + var defaults = { + field: 'data', + event: 'data', + triggerFnName: 'trigger', + triggerEvent: false, + immutableKeys: {} // key => true if immutable + }; - } + params = extend$1({}, defaults, params); + return function removeDataImpl(names) { + var p = params; + var self = this; + var selfIsArrayLike = self.length !== undefined; + var all = selfIsArrayLike ? self : [self]; // put in array if not array-like + + // .removeData('foo bar') + if (string(names)) { + // then get the list of keys, and delete them + var keys = names.split(/\s+/); + var l = keys.length; + for (var i = 0; i < l; i++) { + // delete each non-empty key + var key = keys[i]; + if (emptyString(key)) { + continue; + } + var valid = !p.immutableKeys[key]; // not valid if immutable + if (valid) { + for (var i_a = 0, l_a = all.length; i_a < l_a; i_a++) { + all[i_a]._private[p.field][key] = undefined; + } + } + } + if (p.triggerEvent) { + self[p.triggerFnName](p.event); + } - random() { + // .removeData() + } else if (names === undefined) { + // then delete all keys + + for (var _i_a = 0, _l_a = all.length; _i_a < _l_a; _i_a++) { + var _privateFields = all[_i_a]._private[p.field]; + var _keys = Object.keys(_privateFields); + for (var _i2 = 0; _i2 < _keys.length; _i2++) { + var _key = _keys[_i2]; + var validKeyToDelete = !p.immutableKeys[_key]; + if (validKeyToDelete) { + _privateFields[_key] = undefined; + } + } + } + if (p.triggerEvent) { + self[p.triggerFnName](p.event); + } + } + return self; // maintain chaining + }; // function + } // removeData + }; // define + + var define$1 = { + eventAliasesOn: function eventAliasesOn(proto) { + var p = proto; + p.addListener = p.listen = p.bind = p.on; + p.unlisten = p.unbind = p.off = p.removeListener; + p.trigger = p.emit; + + // this is just a wrapper alias of .on() + p.pon = p.promiseOn = function (events, selector) { + var self = this; + var args = Array.prototype.slice.call(arguments, 0); + return new Promise$1(function (resolve, reject) { + var callback = function callback(e) { + self.off.apply(self, offArgs); + resolve(e); + }; + var onArgs = args.concat([callback]); + var offArgs = onArgs.concat([]); + self.on.apply(self, onArgs); + }); + }; + } + }; // define - this.x = Math.random(); - this.y = Math.random(); + // use this module to cherry pick functions into your prototype + var define = {}; + [define$3, define$2, define$1].forEach(function (m) { + extend$1(define, m); + }); - return this; + var elesfn$i = { + animate: define.animate(), + animation: define.animation(), + animated: define.animated(), + clearQueue: define.clearQueue(), + delay: define.delay(), + delayAnimation: define.delayAnimation(), + stop: define.stop() + }; - } + var elesfn$h = { + classes: function classes(_classes) { + var self = this; + if (_classes === undefined) { + var ret = []; + self[0]._private.classes.forEach(function (cls) { + return ret.push(cls); + }); + return ret; + } else if (!array(_classes)) { + // extract classes from string + _classes = (_classes || '').match(/\S+/g) || []; + } + var changed = []; + var classesSet = new Set$1(_classes); + + // check and update each ele + for (var j = 0; j < self.length; j++) { + var ele = self[j]; + var _p = ele._private; + var eleClasses = _p.classes; + var changedEle = false; + + // check if ele has all of the passed classes + for (var i = 0; i < _classes.length; i++) { + var cls = _classes[i]; + var eleHasClass = eleClasses.has(cls); + if (!eleHasClass) { + changedEle = true; + break; + } + } + + // check if ele has classes outside of those passed + if (!changedEle) { + changedEle = eleClasses.size !== _classes.length; + } + if (changedEle) { + _p.classes = classesSet; + changed.push(ele); + } + } - *[ Symbol.iterator ]() { + // trigger update style on those eles that had class changes + if (changed.length > 0) { + this.spawn(changed).updateStyle().emit('class'); + } + return self; + }, + addClass: function addClass(classes) { + return this.toggleClass(classes, true); + }, + hasClass: function hasClass(className) { + var ele = this[0]; + return ele != null && ele._private.classes.has(className); + }, + toggleClass: function toggleClass(classes, toggle) { + if (!array(classes)) { + // extract classes from string + classes = classes.match(/\S+/g) || []; + } + var self = this; + var toggleUndefd = toggle === undefined; + var changed = []; // eles who had classes changed + + for (var i = 0, il = self.length; i < il; i++) { + var ele = self[i]; + var eleClasses = ele._private.classes; + var changedEle = false; + for (var j = 0; j < classes.length; j++) { + var cls = classes[j]; + var hasClass = eleClasses.has(cls); + var changedNow = false; + if (toggle || toggleUndefd && !hasClass) { + eleClasses.add(cls); + changedNow = true; + } else if (!toggle || toggleUndefd && hasClass) { + eleClasses["delete"](cls); + changedNow = true; + } + if (!changedEle && changedNow) { + changed.push(ele); + changedEle = true; + } + } // for j classes + } // for i eles - yield this.x; - yield this.y; + // trigger update style on those eles that had class changes + if (changed.length > 0) { + this.spawn(changed).updateStyle().emit('class'); + } + return self; + }, + removeClass: function removeClass(classes) { + return this.toggleClass(classes, false); + }, + flashClass: function flashClass(classes, duration) { + var self = this; + if (duration == null) { + duration = 250; + } else if (duration === 0) { + return self; // nothing to do really + } - } + self.addClass(classes); + setTimeout(function () { + self.removeClass(classes); + }, duration); + return self; + } + }; + elesfn$h.className = elesfn$h.classNames = elesfn$h.classes; + + // tokens in the query language + var tokens = { + metaChar: '[\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\]\\^\\`\\{\\|\\}\\~]', + // chars we need to escape in let names, etc + comparatorOp: '=|\\!=|>|>=|<|<=|\\$=|\\^=|\\*=', + // binary comparison op (used in data selectors) + boolOp: '\\?|\\!|\\^', + // boolean (unary) operators (used in data selectors) + string: '"(?:\\\\"|[^"])*"' + '|' + "'(?:\\\\'|[^'])*'", + // string literals (used in data selectors) -- doublequotes | singlequotes + number: number, + // number literal (used in data selectors) --- e.g. 0.1234, 1234, 12e123 + meta: 'degree|indegree|outdegree', + // allowed metadata fields (i.e. allowed functions to use from Collection) + separator: '\\s*,\\s*', + // queries are separated by commas, e.g. edge[foo = 'bar'], node.someClass + descendant: '\\s+', + child: '\\s+>\\s+', + subject: '\\$', + group: 'node|edge|\\*', + directedEdge: '\\s+->\\s+', + undirectedEdge: '\\s+<->\\s+' + }; + tokens.variable = '(?:[\\w-.]|(?:\\\\' + tokens.metaChar + '))+'; // a variable name can have letters, numbers, dashes, and periods + tokens.className = '(?:[\\w-]|(?:\\\\' + tokens.metaChar + '))+'; // a class name has the same rules as a variable except it can't have a '.' in the name + tokens.value = tokens.string + '|' + tokens.number; // a value literal, either a string or number + tokens.id = tokens.variable; // an element id (follows variable conventions) + + (function () { + var ops, op, i; + + // add @ variants to comparatorOp + ops = tokens.comparatorOp.split('|'); + for (i = 0; i < ops.length; i++) { + op = ops[i]; + tokens.comparatorOp += '|@' + op; + } - } + // add ! variants to comparatorOp + ops = tokens.comparatorOp.split('|'); + for (i = 0; i < ops.length; i++) { + op = ops[i]; + if (op.indexOf('!') >= 0) { + continue; + } // skip ops that explicitly contain ! + if (op === '=') { + continue; + } // skip = b/c != is explicitly defined + + tokens.comparatorOp += '|\\!' + op; + } + })(); - class Matrix3 { + /** + * Make a new query object + * + * @prop type {Type} The type enum (int) of the query + * @prop checks List of checks to make against an ele to test for a match + */ + var newQuery = function newQuery() { + return { + checks: [] + }; + }; - constructor() { + /** + * A check type enum-like object. Uses integer values for fast match() lookup. + * The ordering does not matter as long as the ints are unique. + */ + var Type$2 = { + /** E.g. node */ + GROUP: 0, + /** A collection of elements */ + COLLECTION: 1, + /** A filter(ele) function */ + FILTER: 2, + /** E.g. [foo > 1] */ + DATA_COMPARE: 3, + /** E.g. [foo] */ + DATA_EXIST: 4, + /** E.g. [?foo] */ + DATA_BOOL: 5, + /** E.g. [[degree > 2]] */ + META_COMPARE: 6, + /** E.g. :selected */ + STATE: 7, + /** E.g. #foo */ + ID: 8, + /** E.g. .foo */ + CLASS: 9, + /** E.g. #foo <-> #bar */ + UNDIRECTED_EDGE: 10, + /** E.g. #foo -> #bar */ + DIRECTED_EDGE: 11, + /** E.g. $#foo -> #bar */ + NODE_SOURCE: 12, + /** E.g. #foo -> $#bar */ + NODE_TARGET: 13, + /** E.g. $#foo <-> #bar */ + NODE_NEIGHBOR: 14, + /** E.g. #foo > #bar */ + CHILD: 15, + /** E.g. #foo #bar */ + DESCENDANT: 16, + /** E.g. $#foo > #bar */ + PARENT: 17, + /** E.g. $#foo #bar */ + ANCESTOR: 18, + /** E.g. #foo > $bar > #baz */ + COMPOUND_SPLIT: 19, + /** Always matches, useful placeholder for subject in `COMPOUND_SPLIT` */ + TRUE: 20 + }; - Matrix3.prototype.isMatrix3 = true; + var stateSelectors = [{ + selector: ':selected', + matches: function matches(ele) { + return ele.selected(); + } + }, { + selector: ':unselected', + matches: function matches(ele) { + return !ele.selected(); + } + }, { + selector: ':selectable', + matches: function matches(ele) { + return ele.selectable(); + } + }, { + selector: ':unselectable', + matches: function matches(ele) { + return !ele.selectable(); + } + }, { + selector: ':locked', + matches: function matches(ele) { + return ele.locked(); + } + }, { + selector: ':unlocked', + matches: function matches(ele) { + return !ele.locked(); + } + }, { + selector: ':visible', + matches: function matches(ele) { + return ele.visible(); + } + }, { + selector: ':hidden', + matches: function matches(ele) { + return !ele.visible(); + } + }, { + selector: ':transparent', + matches: function matches(ele) { + return ele.transparent(); + } + }, { + selector: ':grabbed', + matches: function matches(ele) { + return ele.grabbed(); + } + }, { + selector: ':free', + matches: function matches(ele) { + return !ele.grabbed(); + } + }, { + selector: ':removed', + matches: function matches(ele) { + return ele.removed(); + } + }, { + selector: ':inside', + matches: function matches(ele) { + return !ele.removed(); + } + }, { + selector: ':grabbable', + matches: function matches(ele) { + return ele.grabbable(); + } + }, { + selector: ':ungrabbable', + matches: function matches(ele) { + return !ele.grabbable(); + } + }, { + selector: ':animated', + matches: function matches(ele) { + return ele.animated(); + } + }, { + selector: ':unanimated', + matches: function matches(ele) { + return !ele.animated(); + } + }, { + selector: ':parent', + matches: function matches(ele) { + return ele.isParent(); + } + }, { + selector: ':childless', + matches: function matches(ele) { + return ele.isChildless(); + } + }, { + selector: ':child', + matches: function matches(ele) { + return ele.isChild(); + } + }, { + selector: ':orphan', + matches: function matches(ele) { + return ele.isOrphan(); + } + }, { + selector: ':nonorphan', + matches: function matches(ele) { + return ele.isChild(); + } + }, { + selector: ':compound', + matches: function matches(ele) { + if (ele.isNode()) { + return ele.isParent(); + } else { + return ele.source().isParent() || ele.target().isParent(); + } + } + }, { + selector: ':loop', + matches: function matches(ele) { + return ele.isLoop(); + } + }, { + selector: ':simple', + matches: function matches(ele) { + return ele.isSimple(); + } + }, { + selector: ':active', + matches: function matches(ele) { + return ele.active(); + } + }, { + selector: ':inactive', + matches: function matches(ele) { + return !ele.active(); + } + }, { + selector: ':backgrounding', + matches: function matches(ele) { + return ele.backgrounding(); + } + }, { + selector: ':nonbackgrounding', + matches: function matches(ele) { + return !ele.backgrounding(); + } + }].sort(function (a, b) { + // n.b. selectors that are starting substrings of others must have the longer ones first + return descending(a.selector, b.selector); + }); + var lookup = function () { + var selToFn = {}; + var s; + for (var i = 0; i < stateSelectors.length; i++) { + s = stateSelectors[i]; + selToFn[s.selector] = s.matches; + } + return selToFn; + }(); + var stateSelectorMatches = function stateSelectorMatches(sel, ele) { + return lookup[sel](ele); + }; + var stateSelectorRegex = '(' + stateSelectors.map(function (s) { + return s.selector; + }).join('|') + ')'; + + // when a token like a variable has escaped meta characters, we need to clean the backslashes out + // so that values get compared properly in Selector.filter() + var cleanMetaChars = function cleanMetaChars(str) { + return str.replace(new RegExp('\\\\(' + tokens.metaChar + ')', 'g'), function (match, $1) { + return $1; + }); + }; + var replaceLastQuery = function replaceLastQuery(selector, examiningQuery, replacementQuery) { + selector[selector.length - 1] = replacementQuery; + }; - this.elements = [ + // NOTE: add new expression syntax here to have it recognised by the parser; + // - a query contains all adjacent (i.e. no separator in between) expressions; + // - the current query is stored in selector[i] + // - you need to check the query objects in match() for it actually filter properly, but that's pretty straight forward + var exprs = [{ + name: 'group', + // just used for identifying when debugging + query: true, + regex: '(' + tokens.group + ')', + populate: function populate(selector, query, _ref) { + var _ref2 = _slicedToArray(_ref, 1), + group = _ref2[0]; + query.checks.push({ + type: Type$2.GROUP, + value: group === '*' ? group : group + 's' + }); + } + }, { + name: 'state', + query: true, + regex: stateSelectorRegex, + populate: function populate(selector, query, _ref3) { + var _ref4 = _slicedToArray(_ref3, 1), + state = _ref4[0]; + query.checks.push({ + type: Type$2.STATE, + value: state + }); + } + }, { + name: 'id', + query: true, + regex: '\\#(' + tokens.id + ')', + populate: function populate(selector, query, _ref5) { + var _ref6 = _slicedToArray(_ref5, 1), + id = _ref6[0]; + query.checks.push({ + type: Type$2.ID, + value: cleanMetaChars(id) + }); + } + }, { + name: 'className', + query: true, + regex: '\\.(' + tokens.className + ')', + populate: function populate(selector, query, _ref7) { + var _ref8 = _slicedToArray(_ref7, 1), + className = _ref8[0]; + query.checks.push({ + type: Type$2.CLASS, + value: cleanMetaChars(className) + }); + } + }, { + name: 'dataExists', + query: true, + regex: '\\[\\s*(' + tokens.variable + ')\\s*\\]', + populate: function populate(selector, query, _ref9) { + var _ref10 = _slicedToArray(_ref9, 1), + variable = _ref10[0]; + query.checks.push({ + type: Type$2.DATA_EXIST, + field: cleanMetaChars(variable) + }); + } + }, { + name: 'dataCompare', + query: true, + regex: '\\[\\s*(' + tokens.variable + ')\\s*(' + tokens.comparatorOp + ')\\s*(' + tokens.value + ')\\s*\\]', + populate: function populate(selector, query, _ref11) { + var _ref12 = _slicedToArray(_ref11, 3), + variable = _ref12[0], + comparatorOp = _ref12[1], + value = _ref12[2]; + var valueIsString = new RegExp('^' + tokens.string + '$').exec(value) != null; + if (valueIsString) { + value = value.substring(1, value.length - 1); + } else { + value = parseFloat(value); + } + query.checks.push({ + type: Type$2.DATA_COMPARE, + field: cleanMetaChars(variable), + operator: comparatorOp, + value: value + }); + } + }, { + name: 'dataBool', + query: true, + regex: '\\[\\s*(' + tokens.boolOp + ')\\s*(' + tokens.variable + ')\\s*\\]', + populate: function populate(selector, query, _ref13) { + var _ref14 = _slicedToArray(_ref13, 2), + boolOp = _ref14[0], + variable = _ref14[1]; + query.checks.push({ + type: Type$2.DATA_BOOL, + field: cleanMetaChars(variable), + operator: boolOp + }); + } + }, { + name: 'metaCompare', + query: true, + regex: '\\[\\[\\s*(' + tokens.meta + ')\\s*(' + tokens.comparatorOp + ')\\s*(' + tokens.number + ')\\s*\\]\\]', + populate: function populate(selector, query, _ref15) { + var _ref16 = _slicedToArray(_ref15, 3), + meta = _ref16[0], + comparatorOp = _ref16[1], + number = _ref16[2]; + query.checks.push({ + type: Type$2.META_COMPARE, + field: cleanMetaChars(meta), + operator: comparatorOp, + value: parseFloat(number) + }); + } + }, { + name: 'nextQuery', + separator: true, + regex: tokens.separator, + populate: function populate(selector, query) { + var currentSubject = selector.currentSubject; + var edgeCount = selector.edgeCount; + var compoundCount = selector.compoundCount; + var lastQ = selector[selector.length - 1]; + if (currentSubject != null) { + lastQ.subject = currentSubject; + selector.currentSubject = null; + } + lastQ.edgeCount = edgeCount; + lastQ.compoundCount = compoundCount; + selector.edgeCount = 0; + selector.compoundCount = 0; + + // go on to next query + var nextQuery = selector[selector.length++] = newQuery(); + return nextQuery; // this is the new query to be filled by the following exprs + } + }, { + name: 'directedEdge', + separator: true, + regex: tokens.directedEdge, + populate: function populate(selector, query) { + if (selector.currentSubject == null) { + // undirected edge + var edgeQuery = newQuery(); + var source = query; + var target = newQuery(); + edgeQuery.checks.push({ + type: Type$2.DIRECTED_EDGE, + source: source, + target: target + }); + + // the query in the selector should be the edge rather than the source + replaceLastQuery(selector, query, edgeQuery); + selector.edgeCount++; + + // we're now populating the target query with expressions that follow + return target; + } else { + // source/target + var srcTgtQ = newQuery(); + var _source = query; + var _target = newQuery(); + srcTgtQ.checks.push({ + type: Type$2.NODE_SOURCE, + source: _source, + target: _target + }); + + // the query in the selector should be the neighbourhood rather than the node + replaceLastQuery(selector, query, srcTgtQ); + selector.edgeCount++; + return _target; // now populating the target with the following expressions + } + } + }, { + name: 'undirectedEdge', + separator: true, + regex: tokens.undirectedEdge, + populate: function populate(selector, query) { + if (selector.currentSubject == null) { + // undirected edge + var edgeQuery = newQuery(); + var source = query; + var target = newQuery(); + edgeQuery.checks.push({ + type: Type$2.UNDIRECTED_EDGE, + nodes: [source, target] + }); + + // the query in the selector should be the edge rather than the source + replaceLastQuery(selector, query, edgeQuery); + selector.edgeCount++; + + // we're now populating the target query with expressions that follow + return target; + } else { + // neighbourhood + var nhoodQ = newQuery(); + var node = query; + var neighbor = newQuery(); + nhoodQ.checks.push({ + type: Type$2.NODE_NEIGHBOR, + node: node, + neighbor: neighbor + }); + + // the query in the selector should be the neighbourhood rather than the node + replaceLastQuery(selector, query, nhoodQ); + return neighbor; // now populating the neighbor with following expressions + } + } + }, { + name: 'child', + separator: true, + regex: tokens.child, + populate: function populate(selector, query) { + if (selector.currentSubject == null) { + // default: child query + var parentChildQuery = newQuery(); + var child = newQuery(); + var parent = selector[selector.length - 1]; + parentChildQuery.checks.push({ + type: Type$2.CHILD, + parent: parent, + child: child + }); + + // the query in the selector should be the '>' itself + replaceLastQuery(selector, query, parentChildQuery); + selector.compoundCount++; + + // we're now populating the child query with expressions that follow + return child; + } else if (selector.currentSubject === query) { + // compound split query + var compound = newQuery(); + var left = selector[selector.length - 1]; + var right = newQuery(); + var subject = newQuery(); + var _child = newQuery(); + var _parent = newQuery(); + + // set up the root compound q + compound.checks.push({ + type: Type$2.COMPOUND_SPLIT, + left: left, + right: right, + subject: subject + }); + + // populate the subject and replace the q at the old spot (within left) with TRUE + subject.checks = query.checks; // take the checks from the left + query.checks = [{ + type: Type$2.TRUE + }]; // checks under left refs the subject implicitly + + // set up the right q + _parent.checks.push({ + type: Type$2.TRUE + }); // parent implicitly refs the subject + right.checks.push({ + type: Type$2.PARENT, + // type is swapped on right side queries + parent: _parent, + child: _child // empty for now + }); + + replaceLastQuery(selector, left, compound); + + // update the ref since we moved things around for `query` + selector.currentSubject = subject; + selector.compoundCount++; + return _child; // now populating the right side's child + } else { + // parent query + // info for parent query + var _parent2 = newQuery(); + var _child2 = newQuery(); + var pcQChecks = [{ + type: Type$2.PARENT, + parent: _parent2, + child: _child2 + }]; + + // the parent-child query takes the place of the query previously being populated + _parent2.checks = query.checks; // the previous query contains the checks for the parent + query.checks = pcQChecks; // pc query takes over + + selector.compoundCount++; + return _child2; // we're now populating the child + } + } + }, { + name: 'descendant', + separator: true, + regex: tokens.descendant, + populate: function populate(selector, query) { + if (selector.currentSubject == null) { + // default: descendant query + var ancChQuery = newQuery(); + var descendant = newQuery(); + var ancestor = selector[selector.length - 1]; + ancChQuery.checks.push({ + type: Type$2.DESCENDANT, + ancestor: ancestor, + descendant: descendant + }); + + // the query in the selector should be the '>' itself + replaceLastQuery(selector, query, ancChQuery); + selector.compoundCount++; + + // we're now populating the descendant query with expressions that follow + return descendant; + } else if (selector.currentSubject === query) { + // compound split query + var compound = newQuery(); + var left = selector[selector.length - 1]; + var right = newQuery(); + var subject = newQuery(); + var _descendant = newQuery(); + var _ancestor = newQuery(); + + // set up the root compound q + compound.checks.push({ + type: Type$2.COMPOUND_SPLIT, + left: left, + right: right, + subject: subject + }); + + // populate the subject and replace the q at the old spot (within left) with TRUE + subject.checks = query.checks; // take the checks from the left + query.checks = [{ + type: Type$2.TRUE + }]; // checks under left refs the subject implicitly + + // set up the right q + _ancestor.checks.push({ + type: Type$2.TRUE + }); // ancestor implicitly refs the subject + right.checks.push({ + type: Type$2.ANCESTOR, + // type is swapped on right side queries + ancestor: _ancestor, + descendant: _descendant // empty for now + }); + + replaceLastQuery(selector, left, compound); + + // update the ref since we moved things around for `query` + selector.currentSubject = subject; + selector.compoundCount++; + return _descendant; // now populating the right side's descendant + } else { + // ancestor query + // info for parent query + var _ancestor2 = newQuery(); + var _descendant2 = newQuery(); + var adQChecks = [{ + type: Type$2.ANCESTOR, + ancestor: _ancestor2, + descendant: _descendant2 + }]; + + // the parent-child query takes the place of the query previously being populated + _ancestor2.checks = query.checks; // the previous query contains the checks for the parent + query.checks = adQChecks; // pc query takes over + + selector.compoundCount++; + return _descendant2; // we're now populating the child + } + } + }, { + name: 'subject', + modifier: true, + regex: tokens.subject, + populate: function populate(selector, query) { + if (selector.currentSubject != null && selector.currentSubject !== query) { + warn('Redefinition of subject in selector `' + selector.toString() + '`'); + return false; + } + selector.currentSubject = query; + var topQ = selector[selector.length - 1]; + var topChk = topQ.checks[0]; + var topType = topChk == null ? null : topChk.type; + if (topType === Type$2.DIRECTED_EDGE) { + // directed edge with subject on the target + + // change to target node check + topChk.type = Type$2.NODE_TARGET; + } else if (topType === Type$2.UNDIRECTED_EDGE) { + // undirected edge with subject on the second node + + // change to neighbor check + topChk.type = Type$2.NODE_NEIGHBOR; + topChk.node = topChk.nodes[1]; // second node is subject + topChk.neighbor = topChk.nodes[0]; + + // clean up unused fields for new type + topChk.nodes = null; + } + } + }]; + exprs.forEach(function (e) { + return e.regexObj = new RegExp('^' + e.regex); + }); - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 + /** + * Of all the expressions, find the first match in the remaining text. + * @param {string} remaining The remaining text to parse + * @returns The matched expression and the newly remaining text `{ expr, match, name, remaining }` + */ + var consumeExpr = function consumeExpr(remaining) { + var expr; + var match; + var name; + for (var j = 0; j < exprs.length; j++) { + var e = exprs[j]; + var n = e.name; + var m = remaining.match(e.regexObj); + if (m != null) { + match = m; + expr = e; + name = n; + var consumed = m[0]; + remaining = remaining.substring(consumed.length); + break; // we've consumed one expr, so we can return now + } + } - ]; + return { + expr: expr, + match: match, + name: name, + remaining: remaining + }; + }; - } + /** + * Consume all the leading whitespace + * @param {string} remaining The text to consume + * @returns The text with the leading whitespace removed + */ + var consumeWhitespace = function consumeWhitespace(remaining) { + var match = remaining.match(/^\s+/); + if (match) { + var consumed = match[0]; + remaining = remaining.substring(consumed.length); + } + return remaining; + }; - set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + /** + * Parse the string and store the parsed representation in the Selector. + * @param {string} selector The selector string + * @returns `true` if the selector was successfully parsed, `false` otherwise + */ + var parse = function parse(selector) { + var self = this; + var remaining = self.inputText = selector; + var currentQuery = self[0] = newQuery(); + self.length = 1; + remaining = consumeWhitespace(remaining); // get rid of leading whitespace + + for (;;) { + var exprInfo = consumeExpr(remaining); + if (exprInfo.expr == null) { + warn('The selector `' + selector + '`is invalid'); + return false; + } else { + var args = exprInfo.match.slice(1); + + // let the token populate the selector object in currentQuery + var ret = exprInfo.expr.populate(self, currentQuery, args); + if (ret === false) { + return false; // exit if population failed + } else if (ret != null) { + currentQuery = ret; // change the current query to be filled if the expr specifies + } + } - const te = this.elements; + remaining = exprInfo.remaining; - te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; - te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; - te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; + // we're done when there's nothing left to parse + if (remaining.match(/^\s*$/)) { + break; + } + } + var lastQ = self[self.length - 1]; + if (self.currentSubject != null) { + lastQ.subject = self.currentSubject; + } + lastQ.edgeCount = self.edgeCount; + lastQ.compoundCount = self.compoundCount; + for (var i = 0; i < self.length; i++) { + var q = self[i]; + + // in future, this could potentially be allowed if there were operator precedence and detection of invalid combinations + if (q.compoundCount > 0 && q.edgeCount > 0) { + warn('The selector `' + selector + '` is invalid because it uses both a compound selector and an edge selector'); + return false; + } + if (q.edgeCount > 1) { + warn('The selector `' + selector + '` is invalid because it uses multiple edge selectors'); + return false; + } else if (q.edgeCount === 1) { + warn('The selector `' + selector + '` is deprecated. Edge selectors do not take effect on changes to source and target nodes after an edge is added, for performance reasons. Use a class or data selector on edges instead, updating the class or data of an edge when your app detects a change in source or target nodes.'); + } + } + return true; // success + }; - return this; + /** + * Get the selector represented as a string. This value uses default formatting, + * so things like spacing may differ from the input text passed to the constructor. + * @returns {string} The selector string + */ + var toString = function toString() { + if (this.toStringCache != null) { + return this.toStringCache; + } + var clean = function clean(obj) { + if (obj == null) { + return ''; + } else { + return obj; + } + }; + var cleanVal = function cleanVal(val) { + if (string(val)) { + return '"' + val + '"'; + } else { + return clean(val); + } + }; + var space = function space(val) { + return ' ' + val + ' '; + }; + var checkToString = function checkToString(check, subject) { + var type = check.type, + value = check.value; + switch (type) { + case Type$2.GROUP: + { + var group = clean(value); + return group.substring(0, group.length - 1); + } + case Type$2.DATA_COMPARE: + { + var field = check.field, + operator = check.operator; + return '[' + field + space(clean(operator)) + cleanVal(value) + ']'; + } + case Type$2.DATA_BOOL: + { + var _operator = check.operator, + _field = check.field; + return '[' + clean(_operator) + _field + ']'; + } + case Type$2.DATA_EXIST: + { + var _field2 = check.field; + return '[' + _field2 + ']'; + } + case Type$2.META_COMPARE: + { + var _operator2 = check.operator, + _field3 = check.field; + return '[[' + _field3 + space(clean(_operator2)) + cleanVal(value) + ']]'; + } + case Type$2.STATE: + { + return value; + } + case Type$2.ID: + { + return '#' + value; + } + case Type$2.CLASS: + { + return '.' + value; + } + case Type$2.PARENT: + case Type$2.CHILD: + { + return queryToString(check.parent, subject) + space('>') + queryToString(check.child, subject); + } + case Type$2.ANCESTOR: + case Type$2.DESCENDANT: + { + return queryToString(check.ancestor, subject) + ' ' + queryToString(check.descendant, subject); + } + case Type$2.COMPOUND_SPLIT: + { + var lhs = queryToString(check.left, subject); + var sub = queryToString(check.subject, subject); + var rhs = queryToString(check.right, subject); + return lhs + (lhs.length > 0 ? ' ' : '') + sub + rhs; + } + case Type$2.TRUE: + { + return ''; + } + } + }; + var queryToString = function queryToString(query, subject) { + return query.checks.reduce(function (str, chk, i) { + return str + (subject === query && i === 0 ? '$' : '') + checkToString(chk, subject); + }, ''); + }; + var str = ''; + for (var i = 0; i < this.length; i++) { + var query = this[i]; + str += queryToString(query, query.subject); + if (this.length > 1 && i < this.length - 1) { + str += ', '; + } + } + this.toStringCache = str; + return str; + }; + var parse$1 = { + parse: parse, + toString: toString + }; - } + var valCmp = function valCmp(fieldVal, operator, value) { + var matches; + var isFieldStr = string(fieldVal); + var isFieldNum = number$1(fieldVal); + var isValStr = string(value); + var fieldStr, valStr; + var caseInsensitive = false; + var notExpr = false; + var isIneqCmp = false; + if (operator.indexOf('!') >= 0) { + operator = operator.replace('!', ''); + notExpr = true; + } + if (operator.indexOf('@') >= 0) { + operator = operator.replace('@', ''); + caseInsensitive = true; + } + if (isFieldStr || isValStr || caseInsensitive) { + fieldStr = !isFieldStr && !isFieldNum ? '' : '' + fieldVal; + valStr = '' + value; + } - identity() { + // if we're doing a case insensitive comparison, then we're using a STRING comparison + // even if we're comparing numbers + if (caseInsensitive) { + fieldVal = fieldStr = fieldStr.toLowerCase(); + value = valStr = valStr.toLowerCase(); + } + switch (operator) { + case '*=': + matches = fieldStr.indexOf(valStr) >= 0; + break; + case '$=': + matches = fieldStr.indexOf(valStr, fieldStr.length - valStr.length) >= 0; + break; + case '^=': + matches = fieldStr.indexOf(valStr) === 0; + break; + case '=': + matches = fieldVal === value; + break; + case '>': + isIneqCmp = true; + matches = fieldVal > value; + break; + case '>=': + isIneqCmp = true; + matches = fieldVal >= value; + break; + case '<': + isIneqCmp = true; + matches = fieldVal < value; + break; + case '<=': + isIneqCmp = true; + matches = fieldVal <= value; + break; + default: + matches = false; + break; + } - this.set( + // apply the not op, but null vals for inequalities should always stay non-matching + if (notExpr && (fieldVal != null || !isIneqCmp)) { + matches = !matches; + } + return matches; + }; + var boolCmp = function boolCmp(fieldVal, operator) { + switch (operator) { + case '?': + return fieldVal ? true : false; + case '!': + return fieldVal ? false : true; + case '^': + return fieldVal === undefined; + } + }; + var existCmp = function existCmp(fieldVal) { + return fieldVal !== undefined; + }; + var data$1 = function data(ele, field) { + return ele.data(field); + }; + var meta = function meta(ele, field) { + return ele[field](); + }; - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 + /** A lookup of `match(check, ele)` functions by `Type` int */ + var match = []; - ); + /** + * Returns whether the query matches for the element + * @param query The `{ type, value, ... }` query object + * @param ele The element to compare against + */ + var matches$1 = function matches(query, ele) { + return query.checks.every(function (chk) { + return match[chk.type](chk, ele); + }); + }; + match[Type$2.GROUP] = function (check, ele) { + var group = check.value; + return group === '*' || group === ele.group(); + }; + match[Type$2.STATE] = function (check, ele) { + var stateSelector = check.value; + return stateSelectorMatches(stateSelector, ele); + }; + match[Type$2.ID] = function (check, ele) { + var id = check.value; + return ele.id() === id; + }; + match[Type$2.CLASS] = function (check, ele) { + var cls = check.value; + return ele.hasClass(cls); + }; + match[Type$2.META_COMPARE] = function (check, ele) { + var field = check.field, + operator = check.operator, + value = check.value; + return valCmp(meta(ele, field), operator, value); + }; + match[Type$2.DATA_COMPARE] = function (check, ele) { + var field = check.field, + operator = check.operator, + value = check.value; + return valCmp(data$1(ele, field), operator, value); + }; + match[Type$2.DATA_BOOL] = function (check, ele) { + var field = check.field, + operator = check.operator; + return boolCmp(data$1(ele, field), operator); + }; + match[Type$2.DATA_EXIST] = function (check, ele) { + var field = check.field; + check.operator; + return existCmp(data$1(ele, field)); + }; + match[Type$2.UNDIRECTED_EDGE] = function (check, ele) { + var qA = check.nodes[0]; + var qB = check.nodes[1]; + var src = ele.source(); + var tgt = ele.target(); + return matches$1(qA, src) && matches$1(qB, tgt) || matches$1(qB, src) && matches$1(qA, tgt); + }; + match[Type$2.NODE_NEIGHBOR] = function (check, ele) { + return matches$1(check.node, ele) && ele.neighborhood().some(function (n) { + return n.isNode() && matches$1(check.neighbor, n); + }); + }; + match[Type$2.DIRECTED_EDGE] = function (check, ele) { + return matches$1(check.source, ele.source()) && matches$1(check.target, ele.target()); + }; + match[Type$2.NODE_SOURCE] = function (check, ele) { + return matches$1(check.source, ele) && ele.outgoers().some(function (n) { + return n.isNode() && matches$1(check.target, n); + }); + }; + match[Type$2.NODE_TARGET] = function (check, ele) { + return matches$1(check.target, ele) && ele.incomers().some(function (n) { + return n.isNode() && matches$1(check.source, n); + }); + }; + match[Type$2.CHILD] = function (check, ele) { + return matches$1(check.child, ele) && matches$1(check.parent, ele.parent()); + }; + match[Type$2.PARENT] = function (check, ele) { + return matches$1(check.parent, ele) && ele.children().some(function (c) { + return matches$1(check.child, c); + }); + }; + match[Type$2.DESCENDANT] = function (check, ele) { + return matches$1(check.descendant, ele) && ele.ancestors().some(function (a) { + return matches$1(check.ancestor, a); + }); + }; + match[Type$2.ANCESTOR] = function (check, ele) { + return matches$1(check.ancestor, ele) && ele.descendants().some(function (d) { + return matches$1(check.descendant, d); + }); + }; + match[Type$2.COMPOUND_SPLIT] = function (check, ele) { + return matches$1(check.subject, ele) && matches$1(check.left, ele) && matches$1(check.right, ele); + }; + match[Type$2.TRUE] = function () { + return true; + }; + match[Type$2.COLLECTION] = function (check, ele) { + var collection = check.value; + return collection.has(ele); + }; + match[Type$2.FILTER] = function (check, ele) { + var filter = check.value; + return filter(ele); + }; - return this; + // filter an existing collection + var filter = function filter(collection) { + var self = this; - } + // for 1 id #foo queries, just get the element + if (self.length === 1 && self[0].checks.length === 1 && self[0].checks[0].type === Type$2.ID) { + return collection.getElementById(self[0].checks[0].value).collection(); + } + var selectorFunction = function selectorFunction(element) { + for (var j = 0; j < self.length; j++) { + var query = self[j]; + if (matches$1(query, element)) { + return true; + } + } + return false; + }; + if (self.text() == null) { + selectorFunction = function selectorFunction() { + return true; + }; + } + return collection.filter(selectorFunction); + }; // filter + + // does selector match a single element? + var matches = function matches(ele) { + var self = this; + for (var j = 0; j < self.length; j++) { + var query = self[j]; + if (matches$1(query, ele)) { + return true; + } + } + return false; + }; // matches - copy( m ) { + var matching = { + matches: matches, + filter: filter + }; - const te = this.elements; - const me = m.elements; + var Selector = function Selector(selector) { + this.inputText = selector; + this.currentSubject = null; + this.compoundCount = 0; + this.edgeCount = 0; + this.length = 0; + if (selector == null || string(selector) && selector.match(/^\s*$/)) ; else if (elementOrCollection(selector)) { + this.addQuery({ + checks: [{ + type: Type$2.COLLECTION, + value: selector.collection() + }] + }); + } else if (fn$6(selector)) { + this.addQuery({ + checks: [{ + type: Type$2.FILTER, + value: selector + }] + }); + } else if (string(selector)) { + if (!this.parse(selector)) { + this.invalid = true; + } + } else { + error('A selector must be created from a string; found '); + } + }; + var selfn = Selector.prototype; + [parse$1, matching].forEach(function (p) { + return extend$1(selfn, p); + }); + selfn.text = function () { + return this.inputText; + }; + selfn.size = function () { + return this.length; + }; + selfn.eq = function (i) { + return this[i]; + }; + selfn.sameText = function (otherSel) { + return !this.invalid && !otherSel.invalid && this.text() === otherSel.text(); + }; + selfn.addQuery = function (q) { + this[this.length++] = q; + }; + selfn.selector = selfn.toString; - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; - te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; - te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; + var elesfn$g = { + allAre: function allAre(selector) { + var selObj = new Selector(selector); + return this.every(function (ele) { + return selObj.matches(ele); + }); + }, + is: function is(selector) { + var selObj = new Selector(selector); + return this.some(function (ele) { + return selObj.matches(ele); + }); + }, + some: function some(fn, thisArg) { + for (var i = 0; i < this.length; i++) { + var ret = !thisArg ? fn(this[i], i, this) : fn.apply(thisArg, [this[i], i, this]); + if (ret) { + return true; + } + } + return false; + }, + every: function every(fn, thisArg) { + for (var i = 0; i < this.length; i++) { + var ret = !thisArg ? fn(this[i], i, this) : fn.apply(thisArg, [this[i], i, this]); + if (!ret) { + return false; + } + } + return true; + }, + same: function same(collection) { + // cheap collection ref check + if (this === collection) { + return true; + } + collection = this.cy().collection(collection); + var thisLength = this.length; + var collectionLength = collection.length; - return this; + // cheap length check + if (thisLength !== collectionLength) { + return false; + } - } + // cheap element ref check + if (thisLength === 1) { + return this[0] === collection[0]; + } + return this.every(function (ele) { + return collection.hasElementWithId(ele.id()); + }); + }, + anySame: function anySame(collection) { + collection = this.cy().collection(collection); + return this.some(function (ele) { + return collection.hasElementWithId(ele.id()); + }); + }, + allAreNeighbors: function allAreNeighbors(collection) { + collection = this.cy().collection(collection); + var nhood = this.neighborhood(); + return collection.every(function (ele) { + return nhood.hasElementWithId(ele.id()); + }); + }, + contains: function contains(collection) { + collection = this.cy().collection(collection); + var self = this; + return collection.every(function (ele) { + return self.hasElementWithId(ele.id()); + }); + } + }; + elesfn$g.allAreNeighbours = elesfn$g.allAreNeighbors; + elesfn$g.has = elesfn$g.contains; + elesfn$g.equal = elesfn$g.equals = elesfn$g.same; + + var cache = function cache(fn, name) { + return function traversalCache(arg1, arg2, arg3, arg4) { + var selectorOrEles = arg1; + var eles = this; + var key; + if (selectorOrEles == null) { + key = ''; + } else if (elementOrCollection(selectorOrEles) && selectorOrEles.length === 1) { + key = selectorOrEles.id(); + } + if (eles.length === 1 && key) { + var _p = eles[0]._private; + var tch = _p.traversalCache = _p.traversalCache || {}; + var ch = tch[name] = tch[name] || []; + var hash = hashString(key); + var cacheHit = ch[hash]; + if (cacheHit) { + return cacheHit; + } else { + return ch[hash] = fn.call(eles, arg1, arg2, arg3, arg4); + } + } else { + return fn.call(eles, arg1, arg2, arg3, arg4); + } + }; + }; - extractBasis( xAxis, yAxis, zAxis ) { + var elesfn$f = { + parent: function parent(selector) { + var parents = []; - xAxis.setFromMatrix3Column( this, 0 ); - yAxis.setFromMatrix3Column( this, 1 ); - zAxis.setFromMatrix3Column( this, 2 ); + // optimisation for single ele call + if (this.length === 1) { + var parent = this[0]._private.parent; + if (parent) { + return parent; + } + } + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var _parent = ele._private.parent; + if (_parent) { + parents.push(_parent); + } + } + return this.spawn(parents, true).filter(selector); + }, + parents: function parents(selector) { + var parents = []; + var eles = this.parent(); + while (eles.nonempty()) { + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + parents.push(ele); + } + eles = eles.parent(); + } + return this.spawn(parents, true).filter(selector); + }, + commonAncestors: function commonAncestors(selector) { + var ancestors; + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var parents = ele.parents(); + ancestors = ancestors || parents; + ancestors = ancestors.intersect(parents); // current list must be common with current ele parents set + } - return this; + return ancestors.filter(selector); + }, + orphans: function orphans(selector) { + return this.stdFilter(function (ele) { + return ele.isOrphan(); + }).filter(selector); + }, + nonorphans: function nonorphans(selector) { + return this.stdFilter(function (ele) { + return ele.isChild(); + }).filter(selector); + }, + children: cache(function (selector) { + var children = []; + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var eleChildren = ele._private.children; + for (var j = 0; j < eleChildren.length; j++) { + children.push(eleChildren[j]); + } + } + return this.spawn(children, true).filter(selector); + }, 'children'), + siblings: function siblings(selector) { + return this.parent().children().not(this).filter(selector); + }, + isParent: function isParent() { + var ele = this[0]; + if (ele) { + return ele.isNode() && ele._private.children.length !== 0; + } + }, + isChildless: function isChildless() { + var ele = this[0]; + if (ele) { + return ele.isNode() && ele._private.children.length === 0; + } + }, + isChild: function isChild() { + var ele = this[0]; + if (ele) { + return ele.isNode() && ele._private.parent != null; + } + }, + isOrphan: function isOrphan() { + var ele = this[0]; + if (ele) { + return ele.isNode() && ele._private.parent == null; + } + }, + descendants: function descendants(selector) { + var elements = []; + function add(eles) { + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + elements.push(ele); + if (ele.children().nonempty()) { + add(ele.children()); + } + } + } + add(this.children()); + return this.spawn(elements, true).filter(selector); + } + }; + function forEachCompound(eles, fn, includeSelf, recursiveStep) { + var q = []; + var did = new Set$1(); + var cy = eles.cy(); + var hasCompounds = cy.hasCompoundNodes(); + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + if (includeSelf) { + q.push(ele); + } else if (hasCompounds) { + recursiveStep(q, did, ele); + } + } + while (q.length > 0) { + var _ele = q.shift(); + fn(_ele); + did.add(_ele.id()); + if (hasCompounds) { + recursiveStep(q, did, _ele); + } + } + return eles; + } + function addChildren(q, did, ele) { + if (ele.isParent()) { + var children = ele._private.children; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + if (!did.has(child.id())) { + q.push(child); + } + } + } + } - } + // very efficient version of eles.add( eles.descendants() ).forEach() + // for internal use + elesfn$f.forEachDown = function (fn) { + var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + return forEachCompound(this, fn, includeSelf, addChildren); + }; + function addParent(q, did, ele) { + if (ele.isChild()) { + var parent = ele._private.parent; + if (!did.has(parent.id())) { + q.push(parent); + } + } + } + elesfn$f.forEachUp = function (fn) { + var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + return forEachCompound(this, fn, includeSelf, addParent); + }; + function addParentAndChildren(q, did, ele) { + addParent(q, did, ele); + addChildren(q, did, ele); + } + elesfn$f.forEachUpAndDown = function (fn) { + var includeSelf = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + return forEachCompound(this, fn, includeSelf, addParentAndChildren); + }; - setFromMatrix4( m ) { + // aliases + elesfn$f.ancestors = elesfn$f.parents; + + var fn$5, elesfn$e; + fn$5 = elesfn$e = { + data: define.data({ + field: 'data', + bindingEvent: 'data', + allowBinding: true, + allowSetting: true, + settingEvent: 'data', + settingTriggersEvent: true, + triggerFnName: 'trigger', + allowGetting: true, + immutableKeys: { + 'id': true, + 'source': true, + 'target': true, + 'parent': true + }, + updateStyle: true + }), + removeData: define.removeData({ + field: 'data', + event: 'data', + triggerFnName: 'trigger', + triggerEvent: true, + immutableKeys: { + 'id': true, + 'source': true, + 'target': true, + 'parent': true + }, + updateStyle: true + }), + scratch: define.data({ + field: 'scratch', + bindingEvent: 'scratch', + allowBinding: true, + allowSetting: true, + settingEvent: 'scratch', + settingTriggersEvent: true, + triggerFnName: 'trigger', + allowGetting: true, + updateStyle: true + }), + removeScratch: define.removeData({ + field: 'scratch', + event: 'scratch', + triggerFnName: 'trigger', + triggerEvent: true, + updateStyle: true + }), + rscratch: define.data({ + field: 'rscratch', + allowBinding: false, + allowSetting: true, + settingTriggersEvent: false, + allowGetting: true + }), + removeRscratch: define.removeData({ + field: 'rscratch', + triggerEvent: false + }), + id: function id() { + var ele = this[0]; + if (ele) { + return ele._private.data.id; + } + } + }; - const me = m.elements; + // aliases + fn$5.attr = fn$5.data; + fn$5.removeAttr = fn$5.removeData; + var data = elesfn$e; + + var elesfn$d = {}; + function defineDegreeFunction(callback) { + return function (includeLoops) { + var self = this; + if (includeLoops === undefined) { + includeLoops = true; + } + if (self.length === 0) { + return; + } + if (self.isNode() && !self.removed()) { + var degree = 0; + var node = self[0]; + var connectedEdges = node._private.edges; + for (var i = 0; i < connectedEdges.length; i++) { + var edge = connectedEdges[i]; + if (!includeLoops && edge.isLoop()) { + continue; + } + degree += callback(node, edge); + } + return degree; + } else { + return; + } + }; + } + extend$1(elesfn$d, { + degree: defineDegreeFunction(function (node, edge) { + if (edge.source().same(edge.target())) { + return 2; + } else { + return 1; + } + }), + indegree: defineDegreeFunction(function (node, edge) { + if (edge.target().same(node)) { + return 1; + } else { + return 0; + } + }), + outdegree: defineDegreeFunction(function (node, edge) { + if (edge.source().same(node)) { + return 1; + } else { + return 0; + } + }) + }); + function defineDegreeBoundsFunction(degreeFn, callback) { + return function (includeLoops) { + var ret; + var nodes = this.nodes(); + for (var i = 0; i < nodes.length; i++) { + var ele = nodes[i]; + var degree = ele[degreeFn](includeLoops); + if (degree !== undefined && (ret === undefined || callback(degree, ret))) { + ret = degree; + } + } + return ret; + }; + } + extend$1(elesfn$d, { + minDegree: defineDegreeBoundsFunction('degree', function (degree, min) { + return degree < min; + }), + maxDegree: defineDegreeBoundsFunction('degree', function (degree, max) { + return degree > max; + }), + minIndegree: defineDegreeBoundsFunction('indegree', function (degree, min) { + return degree < min; + }), + maxIndegree: defineDegreeBoundsFunction('indegree', function (degree, max) { + return degree > max; + }), + minOutdegree: defineDegreeBoundsFunction('outdegree', function (degree, min) { + return degree < min; + }), + maxOutdegree: defineDegreeBoundsFunction('outdegree', function (degree, max) { + return degree > max; + }) + }); + extend$1(elesfn$d, { + totalDegree: function totalDegree(includeLoops) { + var total = 0; + var nodes = this.nodes(); + for (var i = 0; i < nodes.length; i++) { + total += nodes[i].degree(includeLoops); + } + return total; + } + }); - this.set( + var fn$4, elesfn$c; + var beforePositionSet = function beforePositionSet(eles, newPos, silent) { + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + if (!ele.locked()) { + var oldPos = ele._private.position; + var delta = { + x: newPos.x != null ? newPos.x - oldPos.x : 0, + y: newPos.y != null ? newPos.y - oldPos.y : 0 + }; + if (ele.isParent() && !(delta.x === 0 && delta.y === 0)) { + ele.children().shift(delta, silent); + } + ele.dirtyBoundingBoxCache(); + } + } + }; + var positionDef = { + field: 'position', + bindingEvent: 'position', + allowBinding: true, + allowSetting: true, + settingEvent: 'position', + settingTriggersEvent: true, + triggerFnName: 'emitAndNotify', + allowGetting: true, + validKeys: ['x', 'y'], + beforeGet: function beforeGet(ele) { + ele.updateCompoundBounds(); + }, + beforeSet: function beforeSet(eles, newPos) { + beforePositionSet(eles, newPos, false); + }, + onSet: function onSet(eles) { + eles.dirtyCompoundBoundsCache(); + }, + canSet: function canSet(ele) { + return !ele.locked(); + } + }; + fn$4 = elesfn$c = { + position: define.data(positionDef), + // position but no notification to renderer + silentPosition: define.data(extend$1({}, positionDef, { + allowBinding: false, + allowSetting: true, + settingTriggersEvent: false, + allowGetting: false, + beforeSet: function beforeSet(eles, newPos) { + beforePositionSet(eles, newPos, true); + }, + onSet: function onSet(eles) { + eles.dirtyCompoundBoundsCache(); + } + })), + positions: function positions(pos, silent) { + if (plainObject(pos)) { + if (silent) { + this.silentPosition(pos); + } else { + this.position(pos); + } + } else if (fn$6(pos)) { + var _fn = pos; + var cy = this.cy(); + cy.startBatch(); + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var _pos = void 0; + if (_pos = _fn(ele, i)) { + if (silent) { + ele.silentPosition(_pos); + } else { + ele.position(_pos); + } + } + } + cy.endBatch(); + } + return this; // chaining + }, + + silentPositions: function silentPositions(pos) { + return this.positions(pos, true); + }, + shift: function shift(dim, val, silent) { + var delta; + if (plainObject(dim)) { + delta = { + x: number$1(dim.x) ? dim.x : 0, + y: number$1(dim.y) ? dim.y : 0 + }; + silent = val; + } else if (string(dim) && number$1(val)) { + delta = { + x: 0, + y: 0 + }; + delta[dim] = val; + } + if (delta != null) { + var cy = this.cy(); + cy.startBatch(); + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + + // exclude any node that is a descendant of the calling collection + if (cy.hasCompoundNodes() && ele.isChild() && ele.ancestors().anySame(this)) { + continue; + } + var pos = ele.position(); + var newPos = { + x: pos.x + delta.x, + y: pos.y + delta.y + }; + if (silent) { + ele.silentPosition(newPos); + } else { + ele.position(newPos); + } + } + cy.endBatch(); + } + return this; + }, + silentShift: function silentShift(dim, val) { + if (plainObject(dim)) { + this.shift(dim, true); + } else if (string(dim) && number$1(val)) { + this.shift(dim, val, true); + } + return this; + }, + // get/set the rendered (i.e. on screen) positon of the element + renderedPosition: function renderedPosition(dim, val) { + var ele = this[0]; + var cy = this.cy(); + var zoom = cy.zoom(); + var pan = cy.pan(); + var rpos = plainObject(dim) ? dim : undefined; + var setting = rpos !== undefined || val !== undefined && string(dim); + if (ele && ele.isNode()) { + // must have an element and must be a node to return position + if (setting) { + for (var i = 0; i < this.length; i++) { + var _ele = this[i]; + if (val !== undefined) { + // set one dimension + _ele.position(dim, (val - pan[dim]) / zoom); + } else if (rpos !== undefined) { + // set whole position + _ele.position(renderedToModelPosition(rpos, zoom, pan)); + } + } + } else { + // getting + var pos = ele.position(); + rpos = modelToRenderedPosition(pos, zoom, pan); + if (dim === undefined) { + // then return the whole rendered position + return rpos; + } else { + // then return the specified dimension + return rpos[dim]; + } + } + } else if (!setting) { + return undefined; // for empty collection case + } - me[ 0 ], me[ 4 ], me[ 8 ], - me[ 1 ], me[ 5 ], me[ 9 ], - me[ 2 ], me[ 6 ], me[ 10 ] + return this; // chaining + }, + + // get/set the position relative to the parent + relativePosition: function relativePosition(dim, val) { + var ele = this[0]; + var cy = this.cy(); + var ppos = plainObject(dim) ? dim : undefined; + var setting = ppos !== undefined || val !== undefined && string(dim); + var hasCompoundNodes = cy.hasCompoundNodes(); + if (ele && ele.isNode()) { + // must have an element and must be a node to return position + if (setting) { + for (var i = 0; i < this.length; i++) { + var _ele2 = this[i]; + var parent = hasCompoundNodes ? _ele2.parent() : null; + var hasParent = parent && parent.length > 0; + var relativeToParent = hasParent; + if (hasParent) { + parent = parent[0]; + } + var origin = relativeToParent ? parent.position() : { + x: 0, + y: 0 + }; + if (val !== undefined) { + // set one dimension + _ele2.position(dim, val + origin[dim]); + } else if (ppos !== undefined) { + // set whole position + _ele2.position({ + x: ppos.x + origin.x, + y: ppos.y + origin.y + }); + } + } + } else { + // getting + var pos = ele.position(); + var _parent = hasCompoundNodes ? ele.parent() : null; + var _hasParent = _parent && _parent.length > 0; + var _relativeToParent = _hasParent; + if (_hasParent) { + _parent = _parent[0]; + } + var _origin = _relativeToParent ? _parent.position() : { + x: 0, + y: 0 + }; + ppos = { + x: pos.x - _origin.x, + y: pos.y - _origin.y + }; + if (dim === undefined) { + // then return the whole rendered position + return ppos; + } else { + // then return the specified dimension + return ppos[dim]; + } + } + } else if (!setting) { + return undefined; // for empty collection case + } - ); + return this; // chaining + } + }; - return this; + // aliases + fn$4.modelPosition = fn$4.point = fn$4.position; + fn$4.modelPositions = fn$4.points = fn$4.positions; + fn$4.renderedPoint = fn$4.renderedPosition; + fn$4.relativePoint = fn$4.relativePosition; + var position = elesfn$c; + + var fn$3, elesfn$b; + fn$3 = elesfn$b = {}; + elesfn$b.renderedBoundingBox = function (options) { + var bb = this.boundingBox(options); + var cy = this.cy(); + var zoom = cy.zoom(); + var pan = cy.pan(); + var x1 = bb.x1 * zoom + pan.x; + var x2 = bb.x2 * zoom + pan.x; + var y1 = bb.y1 * zoom + pan.y; + var y2 = bb.y2 * zoom + pan.y; + return { + x1: x1, + x2: x2, + y1: y1, + y2: y2, + w: x2 - x1, + h: y2 - y1 + }; + }; + elesfn$b.dirtyCompoundBoundsCache = function () { + var silent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var cy = this.cy(); + if (!cy.styleEnabled() || !cy.hasCompoundNodes()) { + return this; + } + this.forEachUp(function (ele) { + if (ele.isParent()) { + var _p = ele._private; + _p.compoundBoundsClean = false; + _p.bbCache = null; + if (!silent) { + ele.emitAndNotify('bounds'); + } + } + }); + return this; + }; + elesfn$b.updateCompoundBounds = function () { + var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var cy = this.cy(); - } + // not possible to do on non-compound graphs or with the style disabled + if (!cy.styleEnabled() || !cy.hasCompoundNodes()) { + return this; + } - multiply( m ) { + // save cycles when batching -- but bounds will be stale (or not exist yet) + if (!force && cy.batching()) { + return this; + } + function update(parent) { + if (!parent.isParent()) { + return; + } + var _p = parent._private; + var children = parent.children(); + var includeLabels = parent.pstyle('compound-sizing-wrt-labels').value === 'include'; + var min = { + width: { + val: parent.pstyle('min-width').pfValue, + left: parent.pstyle('min-width-bias-left'), + right: parent.pstyle('min-width-bias-right') + }, + height: { + val: parent.pstyle('min-height').pfValue, + top: parent.pstyle('min-height-bias-top'), + bottom: parent.pstyle('min-height-bias-bottom') + } + }; + var bb = children.boundingBox({ + includeLabels: includeLabels, + includeOverlays: false, + // updating the compound bounds happens outside of the regular + // cache cycle (i.e. before fired events) + useCache: false + }); + var pos = _p.position; + + // if children take up zero area then keep position and fall back on stylesheet w/h + if (bb.w === 0 || bb.h === 0) { + bb = { + w: parent.pstyle('width').pfValue, + h: parent.pstyle('height').pfValue + }; + bb.x1 = pos.x - bb.w / 2; + bb.x2 = pos.x + bb.w / 2; + bb.y1 = pos.y - bb.h / 2; + bb.y2 = pos.y + bb.h / 2; + } + function computeBiasValues(propDiff, propBias, propBiasComplement) { + var biasDiff = 0; + var biasComplementDiff = 0; + var biasTotal = propBias + propBiasComplement; + if (propDiff > 0 && biasTotal > 0) { + biasDiff = propBias / biasTotal * propDiff; + biasComplementDiff = propBiasComplement / biasTotal * propDiff; + } + return { + biasDiff: biasDiff, + biasComplementDiff: biasComplementDiff + }; + } + function computePaddingValues(width, height, paddingObject, relativeTo) { + // Assuming percentage is number from 0 to 1 + if (paddingObject.units === '%') { + switch (relativeTo) { + case 'width': + return width > 0 ? paddingObject.pfValue * width : 0; + case 'height': + return height > 0 ? paddingObject.pfValue * height : 0; + case 'average': + return width > 0 && height > 0 ? paddingObject.pfValue * (width + height) / 2 : 0; + case 'min': + return width > 0 && height > 0 ? width > height ? paddingObject.pfValue * height : paddingObject.pfValue * width : 0; + case 'max': + return width > 0 && height > 0 ? width > height ? paddingObject.pfValue * width : paddingObject.pfValue * height : 0; + default: + return 0; + } + } else if (paddingObject.units === 'px') { + return paddingObject.pfValue; + } else { + return 0; + } + } + var leftVal = min.width.left.value; + if (min.width.left.units === 'px' && min.width.val > 0) { + leftVal = leftVal * 100 / min.width.val; + } + var rightVal = min.width.right.value; + if (min.width.right.units === 'px' && min.width.val > 0) { + rightVal = rightVal * 100 / min.width.val; + } + var topVal = min.height.top.value; + if (min.height.top.units === 'px' && min.height.val > 0) { + topVal = topVal * 100 / min.height.val; + } + var bottomVal = min.height.bottom.value; + if (min.height.bottom.units === 'px' && min.height.val > 0) { + bottomVal = bottomVal * 100 / min.height.val; + } + var widthBiasDiffs = computeBiasValues(min.width.val - bb.w, leftVal, rightVal); + var diffLeft = widthBiasDiffs.biasDiff; + var diffRight = widthBiasDiffs.biasComplementDiff; + var heightBiasDiffs = computeBiasValues(min.height.val - bb.h, topVal, bottomVal); + var diffTop = heightBiasDiffs.biasDiff; + var diffBottom = heightBiasDiffs.biasComplementDiff; + _p.autoPadding = computePaddingValues(bb.w, bb.h, parent.pstyle('padding'), parent.pstyle('padding-relative-to').value); + _p.autoWidth = Math.max(bb.w, min.width.val); + pos.x = (-diffLeft + bb.x1 + bb.x2 + diffRight) / 2; + _p.autoHeight = Math.max(bb.h, min.height.val); + pos.y = (-diffTop + bb.y1 + bb.y2 + diffBottom) / 2; + } + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var _p = ele._private; + if (!_p.compoundBoundsClean || force) { + update(ele); + if (!cy.batching()) { + _p.compoundBoundsClean = true; + } + } + } + return this; + }; + var noninf = function noninf(x) { + if (x === Infinity || x === -Infinity) { + return 0; + } + return x; + }; + var updateBounds = function updateBounds(b, x1, y1, x2, y2) { + // don't update with zero area boxes + if (x2 - x1 === 0 || y2 - y1 === 0) { + return; + } - return this.multiplyMatrices( this, m ); + // don't update with null dim + if (x1 == null || y1 == null || x2 == null || y2 == null) { + return; + } + b.x1 = x1 < b.x1 ? x1 : b.x1; + b.x2 = x2 > b.x2 ? x2 : b.x2; + b.y1 = y1 < b.y1 ? y1 : b.y1; + b.y2 = y2 > b.y2 ? y2 : b.y2; + b.w = b.x2 - b.x1; + b.h = b.y2 - b.y1; + }; + var updateBoundsFromBox = function updateBoundsFromBox(b, b2) { + if (b2 == null) { + return b; + } + return updateBounds(b, b2.x1, b2.y1, b2.x2, b2.y2); + }; + var prefixedProperty = function prefixedProperty(obj, field, prefix) { + return getPrefixedProperty(obj, field, prefix); + }; + var updateBoundsFromArrow = function updateBoundsFromArrow(bounds, ele, prefix) { + if (ele.cy().headless()) { + return; + } + var _p = ele._private; + var rstyle = _p.rstyle; + var halfArW = rstyle.arrowWidth / 2; + var arrowType = ele.pstyle(prefix + '-arrow-shape').value; + var x; + var y; + if (arrowType !== 'none') { + if (prefix === 'source') { + x = rstyle.srcX; + y = rstyle.srcY; + } else if (prefix === 'target') { + x = rstyle.tgtX; + y = rstyle.tgtY; + } else { + x = rstyle.midX; + y = rstyle.midY; + } - } + // always store the individual arrow bounds + var bbs = _p.arrowBounds = _p.arrowBounds || {}; + var bb = bbs[prefix] = bbs[prefix] || {}; + bb.x1 = x - halfArW; + bb.y1 = y - halfArW; + bb.x2 = x + halfArW; + bb.y2 = y + halfArW; + bb.w = bb.x2 - bb.x1; + bb.h = bb.y2 - bb.y1; + expandBoundingBox(bb, 1); + updateBounds(bounds, bb.x1, bb.y1, bb.x2, bb.y2); + } + }; + var updateBoundsFromLabel = function updateBoundsFromLabel(bounds, ele, prefix) { + if (ele.cy().headless()) { + return; + } + var prefixDash; + if (prefix) { + prefixDash = prefix + '-'; + } else { + prefixDash = ''; + } + var _p = ele._private; + var rstyle = _p.rstyle; + var label = ele.pstyle(prefixDash + 'label').strValue; + if (label) { + var halign = ele.pstyle('text-halign'); + var valign = ele.pstyle('text-valign'); + var labelWidth = prefixedProperty(rstyle, 'labelWidth', prefix); + var labelHeight = prefixedProperty(rstyle, 'labelHeight', prefix); + var labelX = prefixedProperty(rstyle, 'labelX', prefix); + var labelY = prefixedProperty(rstyle, 'labelY', prefix); + var marginX = ele.pstyle(prefixDash + 'text-margin-x').pfValue; + var marginY = ele.pstyle(prefixDash + 'text-margin-y').pfValue; + var isEdge = ele.isEdge(); + var rotation = ele.pstyle(prefixDash + 'text-rotation'); + var outlineWidth = ele.pstyle('text-outline-width').pfValue; + var borderWidth = ele.pstyle('text-border-width').pfValue; + var halfBorderWidth = borderWidth / 2; + var padding = ele.pstyle('text-background-padding').pfValue; + var marginOfError = 2; // expand to work around browser dimension inaccuracies + + var lh = labelHeight; + var lw = labelWidth; + var lw_2 = lw / 2; + var lh_2 = lh / 2; + var lx1, lx2, ly1, ly2; + if (isEdge) { + lx1 = labelX - lw_2; + lx2 = labelX + lw_2; + ly1 = labelY - lh_2; + ly2 = labelY + lh_2; + } else { + switch (halign.value) { + case 'left': + lx1 = labelX - lw; + lx2 = labelX; + break; + case 'center': + lx1 = labelX - lw_2; + lx2 = labelX + lw_2; + break; + case 'right': + lx1 = labelX; + lx2 = labelX + lw; + break; + } + switch (valign.value) { + case 'top': + ly1 = labelY - lh; + ly2 = labelY; + break; + case 'center': + ly1 = labelY - lh_2; + ly2 = labelY + lh_2; + break; + case 'bottom': + ly1 = labelY; + ly2 = labelY + lh; + break; + } + } - premultiply( m ) { + // shift by margin and expand by outline and border + lx1 += marginX - Math.max(outlineWidth, halfBorderWidth) - padding - marginOfError; + lx2 += marginX + Math.max(outlineWidth, halfBorderWidth) + padding + marginOfError; + ly1 += marginY - Math.max(outlineWidth, halfBorderWidth) - padding - marginOfError; + ly2 += marginY + Math.max(outlineWidth, halfBorderWidth) + padding + marginOfError; + + // always store the unrotated label bounds separately + var bbPrefix = prefix || 'main'; + var bbs = _p.labelBounds; + var bb = bbs[bbPrefix] = bbs[bbPrefix] || {}; + bb.x1 = lx1; + bb.y1 = ly1; + bb.x2 = lx2; + bb.y2 = ly2; + bb.w = lx2 - lx1; + bb.h = ly2 - ly1; + var isAutorotate = isEdge && rotation.strValue === 'autorotate'; + var isPfValue = rotation.pfValue != null && rotation.pfValue !== 0; + if (isAutorotate || isPfValue) { + var theta = isAutorotate ? prefixedProperty(_p.rstyle, 'labelAngle', prefix) : rotation.pfValue; + var cos = Math.cos(theta); + var sin = Math.sin(theta); + + // rotation point (default value for center-center) + var xo = (lx1 + lx2) / 2; + var yo = (ly1 + ly2) / 2; + if (!isEdge) { + switch (halign.value) { + case 'left': + xo = lx2; + break; + case 'right': + xo = lx1; + break; + } + switch (valign.value) { + case 'top': + yo = ly2; + break; + case 'bottom': + yo = ly1; + break; + } + } + var rotate = function rotate(x, y) { + x = x - xo; + y = y - yo; + return { + x: x * cos - y * sin + xo, + y: x * sin + y * cos + yo + }; + }; + var px1y1 = rotate(lx1, ly1); + var px1y2 = rotate(lx1, ly2); + var px2y1 = rotate(lx2, ly1); + var px2y2 = rotate(lx2, ly2); + lx1 = Math.min(px1y1.x, px1y2.x, px2y1.x, px2y2.x); + lx2 = Math.max(px1y1.x, px1y2.x, px2y1.x, px2y2.x); + ly1 = Math.min(px1y1.y, px1y2.y, px2y1.y, px2y2.y); + ly2 = Math.max(px1y1.y, px1y2.y, px2y1.y, px2y2.y); + } + var bbPrefixRot = bbPrefix + 'Rot'; + var bbRot = bbs[bbPrefixRot] = bbs[bbPrefixRot] || {}; + bbRot.x1 = lx1; + bbRot.y1 = ly1; + bbRot.x2 = lx2; + bbRot.y2 = ly2; + bbRot.w = lx2 - lx1; + bbRot.h = ly2 - ly1; + updateBounds(bounds, lx1, ly1, lx2, ly2); + updateBounds(_p.labelBounds.all, lx1, ly1, lx2, ly2); + } + return bounds; + }; + var updateBoundsFromOutline = function updateBoundsFromOutline(bounds, ele) { + if (ele.cy().headless()) { + return; + } + var outlineOpacity = ele.pstyle('outline-opacity').value; + var outlineWidth = ele.pstyle('outline-width').value; + if (outlineOpacity > 0 && outlineWidth > 0) { + var outlineOffset = ele.pstyle('outline-offset').value; + var nodeShape = ele.pstyle('shape').value; + var outlineSize = outlineWidth + outlineOffset; + var scaleX = (bounds.w + outlineSize * 2) / bounds.w; + var scaleY = (bounds.h + outlineSize * 2) / bounds.h; + var xOffset = 0; + var yOffset = 0; + if (["diamond", "pentagon", "round-triangle"].includes(nodeShape)) { + scaleX = (bounds.w + outlineSize * 2.4) / bounds.w; + yOffset = -outlineSize / 3.6; + } else if (["concave-hexagon", "rhomboid", "right-rhomboid"].includes(nodeShape)) { + scaleX = (bounds.w + outlineSize * 2.4) / bounds.w; + } else if (nodeShape === "star") { + scaleX = (bounds.w + outlineSize * 2.8) / bounds.w; + scaleY = (bounds.h + outlineSize * 2.6) / bounds.h; + yOffset = -outlineSize / 3.8; + } else if (nodeShape === "triangle") { + scaleX = (bounds.w + outlineSize * 2.8) / bounds.w; + scaleY = (bounds.h + outlineSize * 2.4) / bounds.h; + yOffset = -outlineSize / 1.4; + } else if (nodeShape === "vee") { + scaleX = (bounds.w + outlineSize * 4.4) / bounds.w; + scaleY = (bounds.h + outlineSize * 3.8) / bounds.h; + yOffset = -outlineSize * .5; + } + var hDelta = bounds.h * scaleY - bounds.h; + var wDelta = bounds.w * scaleX - bounds.w; + expandBoundingBoxSides(bounds, [Math.ceil(hDelta / 2), Math.ceil(wDelta / 2)]); + if (xOffset != 0 || yOffset !== 0) { + var oBounds = shiftBoundingBox(bounds, xOffset, yOffset); + updateBoundingBox(bounds, oBounds); + } + } + }; - return this.multiplyMatrices( m, this ); + // get the bounding box of the elements (in raw model position) + var boundingBoxImpl = function boundingBoxImpl(ele, options) { + var cy = ele._private.cy; + var styleEnabled = cy.styleEnabled(); + var headless = cy.headless(); + var bounds = makeBoundingBox(); + var _p = ele._private; + var isNode = ele.isNode(); + var isEdge = ele.isEdge(); + var ex1, ex2, ey1, ey2; // extrema of body / lines + var x, y; // node pos + var rstyle = _p.rstyle; + var manualExpansion = isNode && styleEnabled ? ele.pstyle('bounds-expansion').pfValue : [0]; + + // must use `display` prop only, as reading `compound.width()` causes recursion + // (other factors like width values will be considered later in this function anyway) + var isDisplayed = function isDisplayed(ele) { + return ele.pstyle('display').value !== 'none'; + }; + var displayed = !styleEnabled || isDisplayed(ele) + + // must take into account connected nodes b/c of implicit edge hiding on display:none node + && (!isEdge || isDisplayed(ele.source()) && isDisplayed(ele.target())); + if (displayed) { + // displayed suffices, since we will find zero area eles anyway + var overlayOpacity = 0; + var overlayPadding = 0; + if (styleEnabled && options.includeOverlays) { + overlayOpacity = ele.pstyle('overlay-opacity').value; + if (overlayOpacity !== 0) { + overlayPadding = ele.pstyle('overlay-padding').value; + } + } + var underlayOpacity = 0; + var underlayPadding = 0; + if (styleEnabled && options.includeUnderlays) { + underlayOpacity = ele.pstyle('underlay-opacity').value; + if (underlayOpacity !== 0) { + underlayPadding = ele.pstyle('underlay-padding').value; + } + } + var padding = Math.max(overlayPadding, underlayPadding); + var w = 0; + var wHalf = 0; + if (styleEnabled) { + w = ele.pstyle('width').pfValue; + wHalf = w / 2; + } + if (isNode && options.includeNodes) { + var pos = ele.position(); + x = pos.x; + y = pos.y; + var _w = ele.outerWidth(); + var halfW = _w / 2; + var h = ele.outerHeight(); + var halfH = h / 2; + + // handle node dimensions + ///////////////////////// + + ex1 = x - halfW; + ex2 = x + halfW; + ey1 = y - halfH; + ey2 = y + halfH; + updateBounds(bounds, ex1, ey1, ex2, ey2); + if (styleEnabled && options.includeOutlines) { + updateBoundsFromOutline(bounds, ele); + } + } else if (isEdge && options.includeEdges) { + if (styleEnabled && !headless) { + var curveStyle = ele.pstyle('curve-style').strValue; + + // handle edge dimensions (rough box estimate) + ////////////////////////////////////////////// + + ex1 = Math.min(rstyle.srcX, rstyle.midX, rstyle.tgtX); + ex2 = Math.max(rstyle.srcX, rstyle.midX, rstyle.tgtX); + ey1 = Math.min(rstyle.srcY, rstyle.midY, rstyle.tgtY); + ey2 = Math.max(rstyle.srcY, rstyle.midY, rstyle.tgtY); + + // take into account edge width + ex1 -= wHalf; + ex2 += wHalf; + ey1 -= wHalf; + ey2 += wHalf; + updateBounds(bounds, ex1, ey1, ex2, ey2); + + // precise edges + //////////////// + + if (curveStyle === 'haystack') { + var hpts = rstyle.haystackPts; + if (hpts && hpts.length === 2) { + ex1 = hpts[0].x; + ey1 = hpts[0].y; + ex2 = hpts[1].x; + ey2 = hpts[1].y; + if (ex1 > ex2) { + var temp = ex1; + ex1 = ex2; + ex2 = temp; + } + if (ey1 > ey2) { + var _temp = ey1; + ey1 = ey2; + ey2 = _temp; + } + updateBounds(bounds, ex1 - wHalf, ey1 - wHalf, ex2 + wHalf, ey2 + wHalf); + } + } else if (curveStyle === 'bezier' || curveStyle === 'unbundled-bezier' || curveStyle.endsWith('segments') || curveStyle.endsWith('taxi')) { + var pts; + switch (curveStyle) { + case 'bezier': + case 'unbundled-bezier': + pts = rstyle.bezierPts; + break; + case 'segments': + case 'taxi': + case 'round-segments': + case 'round-taxi': + pts = rstyle.linePts; + break; + } + if (pts != null) { + for (var j = 0; j < pts.length; j++) { + var pt = pts[j]; + ex1 = pt.x - wHalf; + ex2 = pt.x + wHalf; + ey1 = pt.y - wHalf; + ey2 = pt.y + wHalf; + updateBounds(bounds, ex1, ey1, ex2, ey2); + } + } + } // bezier-like or segment-like edge + } else { + // headless or style disabled + + // fallback on source and target positions + ////////////////////////////////////////// + + var n1 = ele.source(); + var n1pos = n1.position(); + var n2 = ele.target(); + var n2pos = n2.position(); + ex1 = n1pos.x; + ex2 = n2pos.x; + ey1 = n1pos.y; + ey2 = n2pos.y; + if (ex1 > ex2) { + var _temp2 = ex1; + ex1 = ex2; + ex2 = _temp2; + } + if (ey1 > ey2) { + var _temp3 = ey1; + ey1 = ey2; + ey2 = _temp3; + } - } + // take into account edge width + ex1 -= wHalf; + ex2 += wHalf; + ey1 -= wHalf; + ey2 += wHalf; + updateBounds(bounds, ex1, ey1, ex2, ey2); + } // headless or style disabled + } // edges + + // handle edge arrow size + ///////////////////////// + + if (styleEnabled && options.includeEdges && isEdge) { + updateBoundsFromArrow(bounds, ele, 'mid-source'); + updateBoundsFromArrow(bounds, ele, 'mid-target'); + updateBoundsFromArrow(bounds, ele, 'source'); + updateBoundsFromArrow(bounds, ele, 'target'); + } - multiplyMatrices( a, b ) { + // ghost + //////// - const ae = a.elements; - const be = b.elements; - const te = this.elements; + if (styleEnabled) { + var ghost = ele.pstyle('ghost').value === 'yes'; + if (ghost) { + var gx = ele.pstyle('ghost-offset-x').pfValue; + var gy = ele.pstyle('ghost-offset-y').pfValue; + updateBounds(bounds, bounds.x1 + gx, bounds.y1 + gy, bounds.x2 + gx, bounds.y2 + gy); + } + } - const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; - const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; - const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; + // always store the body bounds separately from the labels + var bbBody = _p.bodyBounds = _p.bodyBounds || {}; + assignBoundingBox(bbBody, bounds); + expandBoundingBoxSides(bbBody, manualExpansion); + expandBoundingBox(bbBody, 1); // expand to work around browser dimension inaccuracies + + // overlay + ////////// + + if (styleEnabled) { + ex1 = bounds.x1; + ex2 = bounds.x2; + ey1 = bounds.y1; + ey2 = bounds.y2; + updateBounds(bounds, ex1 - padding, ey1 - padding, ex2 + padding, ey2 + padding); + } - const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; - const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; - const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; + // always store the body bounds separately from the labels + var bbOverlay = _p.overlayBounds = _p.overlayBounds || {}; + assignBoundingBox(bbOverlay, bounds); + expandBoundingBoxSides(bbOverlay, manualExpansion); + expandBoundingBox(bbOverlay, 1); // expand to work around browser dimension inaccuracies - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; - te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; - te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; + // handle label dimensions + ////////////////////////// - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; - te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; - te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; + var bbLabels = _p.labelBounds = _p.labelBounds || {}; + if (bbLabels.all != null) { + clearBoundingBox(bbLabels.all); + } else { + bbLabels.all = makeBoundingBox(); + } + if (styleEnabled && options.includeLabels) { + if (options.includeMainLabels) { + updateBoundsFromLabel(bounds, ele, null); + } + if (isEdge) { + if (options.includeSourceLabels) { + updateBoundsFromLabel(bounds, ele, 'source'); + } + if (options.includeTargetLabels) { + updateBoundsFromLabel(bounds, ele, 'target'); + } + } + } // style enabled for labels + } // if displayed + + bounds.x1 = noninf(bounds.x1); + bounds.y1 = noninf(bounds.y1); + bounds.x2 = noninf(bounds.x2); + bounds.y2 = noninf(bounds.y2); + bounds.w = noninf(bounds.x2 - bounds.x1); + bounds.h = noninf(bounds.y2 - bounds.y1); + if (bounds.w > 0 && bounds.h > 0 && displayed) { + expandBoundingBoxSides(bounds, manualExpansion); + + // expand bounds by 1 because antialiasing can increase the visual/effective size by 1 on all sides + expandBoundingBox(bounds, 1); + } + return bounds; + }; + var getKey = function getKey(opts) { + var i = 0; + var tf = function tf(val) { + return (val ? 1 : 0) << i++; + }; + var key = 0; + key += tf(opts.incudeNodes); + key += tf(opts.includeEdges); + key += tf(opts.includeLabels); + key += tf(opts.includeMainLabels); + key += tf(opts.includeSourceLabels); + key += tf(opts.includeTargetLabels); + key += tf(opts.includeOverlays); + key += tf(opts.includeOutlines); + return key; + }; + var getBoundingBoxPosKey = function getBoundingBoxPosKey(ele) { + if (ele.isEdge()) { + var p1 = ele.source().position(); + var p2 = ele.target().position(); + var r = function r(x) { + return Math.round(x); + }; + return hashIntsArray([r(p1.x), r(p1.y), r(p2.x), r(p2.y)]); + } else { + return 0; + } + }; + var cachedBoundingBoxImpl = function cachedBoundingBoxImpl(ele, opts) { + var _p = ele._private; + var bb; + var isEdge = ele.isEdge(); + var key = opts == null ? defBbOptsKey : getKey(opts); + var usingDefOpts = key === defBbOptsKey; + var currPosKey = getBoundingBoxPosKey(ele); + var isPosKeySame = _p.bbCachePosKey === currPosKey; + var useCache = opts.useCache && isPosKeySame; + var isDirty = function isDirty(ele) { + return ele._private.bbCache == null || ele._private.styleDirty; + }; + var needRecalc = !useCache || isDirty(ele) || isEdge && isDirty(ele.source()) || isDirty(ele.target()); + if (needRecalc) { + if (!isPosKeySame) { + ele.recalculateRenderedStyle(useCache); + } + bb = boundingBoxImpl(ele, defBbOpts); + _p.bbCache = bb; + _p.bbCachePosKey = currPosKey; + } else { + bb = _p.bbCache; + } - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; - te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; - te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; + // not using def opts => need to build up bb from combination of sub bbs + if (!usingDefOpts) { + var isNode = ele.isNode(); + bb = makeBoundingBox(); + if (opts.includeNodes && isNode || opts.includeEdges && !isNode) { + if (opts.includeOverlays) { + updateBoundsFromBox(bb, _p.overlayBounds); + } else { + updateBoundsFromBox(bb, _p.bodyBounds); + } + } + if (opts.includeLabels) { + if (opts.includeMainLabels && (!isEdge || opts.includeSourceLabels && opts.includeTargetLabels)) { + updateBoundsFromBox(bb, _p.labelBounds.all); + } else { + if (opts.includeMainLabels) { + updateBoundsFromBox(bb, _p.labelBounds.mainRot); + } + if (opts.includeSourceLabels) { + updateBoundsFromBox(bb, _p.labelBounds.sourceRot); + } + if (opts.includeTargetLabels) { + updateBoundsFromBox(bb, _p.labelBounds.targetRot); + } + } + } + bb.w = bb.x2 - bb.x1; + bb.h = bb.y2 - bb.y1; + } + return bb; + }; + var defBbOpts = { + includeNodes: true, + includeEdges: true, + includeLabels: true, + includeMainLabels: true, + includeSourceLabels: true, + includeTargetLabels: true, + includeOverlays: true, + includeUnderlays: true, + includeOutlines: true, + useCache: true + }; + var defBbOptsKey = getKey(defBbOpts); + var filledBbOpts = defaults$g(defBbOpts); + elesfn$b.boundingBox = function (options) { + var bounds; + + // the main usecase is ele.boundingBox() for a single element with no/def options + // specified s.t. the cache is used, so check for this case to make it faster by + // avoiding the overhead of the rest of the function + if (this.length === 1 && this[0]._private.bbCache != null && !this[0]._private.styleDirty && (options === undefined || options.useCache === undefined || options.useCache === true)) { + if (options === undefined) { + options = defBbOpts; + } else { + options = filledBbOpts(options); + } + bounds = cachedBoundingBoxImpl(this[0], options); + } else { + bounds = makeBoundingBox(); + options = options || defBbOpts; + var opts = filledBbOpts(options); + var eles = this; + var cy = eles.cy(); + var styleEnabled = cy.styleEnabled(); + if (styleEnabled) { + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var _p = ele._private; + var currPosKey = getBoundingBoxPosKey(ele); + var isPosKeySame = _p.bbCachePosKey === currPosKey; + var useCache = opts.useCache && isPosKeySame && !_p.styleDirty; + ele.recalculateRenderedStyle(useCache); + } + } + this.updateCompoundBounds(!options.useCache); + for (var _i = 0; _i < eles.length; _i++) { + var _ele = eles[_i]; + updateBoundsFromBox(bounds, cachedBoundingBoxImpl(_ele, opts)); + } + } + bounds.x1 = noninf(bounds.x1); + bounds.y1 = noninf(bounds.y1); + bounds.x2 = noninf(bounds.x2); + bounds.y2 = noninf(bounds.y2); + bounds.w = noninf(bounds.x2 - bounds.x1); + bounds.h = noninf(bounds.y2 - bounds.y1); + return bounds; + }; + elesfn$b.dirtyBoundingBoxCache = function () { + for (var i = 0; i < this.length; i++) { + var _p = this[i]._private; + _p.bbCache = null; + _p.bbCachePosKey = null; + _p.bodyBounds = null; + _p.overlayBounds = null; + _p.labelBounds.all = null; + _p.labelBounds.source = null; + _p.labelBounds.target = null; + _p.labelBounds.main = null; + _p.labelBounds.sourceRot = null; + _p.labelBounds.targetRot = null; + _p.labelBounds.mainRot = null; + _p.arrowBounds.source = null; + _p.arrowBounds.target = null; + _p.arrowBounds['mid-source'] = null; + _p.arrowBounds['mid-target'] = null; + } + this.emitAndNotify('bounds'); + return this; + }; - return this; + // private helper to get bounding box for custom node positions + // - good for perf in certain cases but currently requires dirtying the rendered style + // - would be better to not modify the nodes but the nodes are read directly everywhere in the renderer... + // - try to use for only things like discrete layouts where the node position would change anyway + elesfn$b.boundingBoxAt = function (fn) { + var nodes = this.nodes(); + var cy = this.cy(); + var hasCompoundNodes = cy.hasCompoundNodes(); + var parents = cy.collection(); + if (hasCompoundNodes) { + parents = nodes.filter(function (node) { + return node.isParent(); + }); + nodes = nodes.not(parents); + } + if (plainObject(fn)) { + var obj = fn; + fn = function fn() { + return obj; + }; + } + var storeOldPos = function storeOldPos(node, i) { + return node._private.bbAtOldPos = fn(node, i); + }; + var getOldPos = function getOldPos(node) { + return node._private.bbAtOldPos; + }; + cy.startBatch(); + nodes.forEach(storeOldPos).silentPositions(fn); + if (hasCompoundNodes) { + parents.dirtyCompoundBoundsCache(); + parents.dirtyBoundingBoxCache(); + parents.updateCompoundBounds(true); // force update b/c we're inside a batch cycle + } - } + var bb = copyBoundingBox(this.boundingBox({ + useCache: false + })); + nodes.silentPositions(getOldPos); + if (hasCompoundNodes) { + parents.dirtyCompoundBoundsCache(); + parents.dirtyBoundingBoxCache(); + parents.updateCompoundBounds(true); // force update b/c we're inside a batch cycle + } - multiplyScalar( s ) { - - const te = this.elements; - - te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; - te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; - te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; - - return this; + cy.endBatch(); + return bb; + }; + fn$3.boundingbox = fn$3.bb = fn$3.boundingBox; + fn$3.renderedBoundingbox = fn$3.renderedBoundingBox; + var bounds = elesfn$b; + + var fn$2, elesfn$a; + fn$2 = elesfn$a = {}; + var defineDimFns = function defineDimFns(opts) { + opts.uppercaseName = capitalize(opts.name); + opts.autoName = 'auto' + opts.uppercaseName; + opts.labelName = 'label' + opts.uppercaseName; + opts.outerName = 'outer' + opts.uppercaseName; + opts.uppercaseOuterName = capitalize(opts.outerName); + fn$2[opts.name] = function dimImpl() { + var ele = this[0]; + var _p = ele._private; + var cy = _p.cy; + var styleEnabled = cy._private.styleEnabled; + if (ele) { + if (styleEnabled) { + if (ele.isParent()) { + ele.updateCompoundBounds(); + return _p[opts.autoName] || 0; + } + var d = ele.pstyle(opts.name); + switch (d.strValue) { + case 'label': + ele.recalculateRenderedStyle(); + return _p.rstyle[opts.labelName] || 0; + default: + return d.pfValue; + } + } else { + return 1; + } + } + }; + fn$2['outer' + opts.uppercaseName] = function outerDimImpl() { + var ele = this[0]; + var _p = ele._private; + var cy = _p.cy; + var styleEnabled = cy._private.styleEnabled; + if (ele) { + if (styleEnabled) { + var dim = ele[opts.name](); + var border = ele.pstyle('border-width').pfValue; // n.b. 1/2 each side + var padding = 2 * ele.padding(); + return dim + border + padding; + } else { + return 1; + } + } + }; + fn$2['rendered' + opts.uppercaseName] = function renderedDimImpl() { + var ele = this[0]; + if (ele) { + var d = ele[opts.name](); + return d * this.cy().zoom(); + } + }; + fn$2['rendered' + opts.uppercaseOuterName] = function renderedOuterDimImpl() { + var ele = this[0]; + if (ele) { + var od = ele[opts.outerName](); + return od * this.cy().zoom(); + } + }; + }; + defineDimFns({ + name: 'width' + }); + defineDimFns({ + name: 'height' + }); + elesfn$a.padding = function () { + var ele = this[0]; + var _p = ele._private; + if (ele.isParent()) { + ele.updateCompoundBounds(); + if (_p.autoPadding !== undefined) { + return _p.autoPadding; + } else { + return ele.pstyle('padding').pfValue; + } + } else { + return ele.pstyle('padding').pfValue; + } + }; + elesfn$a.paddedHeight = function () { + var ele = this[0]; + return ele.height() + 2 * ele.padding(); + }; + elesfn$a.paddedWidth = function () { + var ele = this[0]; + return ele.width() + 2 * ele.padding(); + }; + var widthHeight = elesfn$a; - } + var ifEdge = function ifEdge(ele, getValue) { + if (ele.isEdge()) { + return getValue(ele); + } + }; + var ifEdgeRenderedPosition = function ifEdgeRenderedPosition(ele, getPoint) { + if (ele.isEdge()) { + var cy = ele.cy(); + return modelToRenderedPosition(getPoint(ele), cy.zoom(), cy.pan()); + } + }; + var ifEdgeRenderedPositions = function ifEdgeRenderedPositions(ele, getPoints) { + if (ele.isEdge()) { + var cy = ele.cy(); + var pan = cy.pan(); + var zoom = cy.zoom(); + return getPoints(ele).map(function (p) { + return modelToRenderedPosition(p, zoom, pan); + }); + } + }; + var controlPoints = function controlPoints(ele) { + return ele.renderer().getControlPoints(ele); + }; + var segmentPoints = function segmentPoints(ele) { + return ele.renderer().getSegmentPoints(ele); + }; + var sourceEndpoint = function sourceEndpoint(ele) { + return ele.renderer().getSourceEndpoint(ele); + }; + var targetEndpoint = function targetEndpoint(ele) { + return ele.renderer().getTargetEndpoint(ele); + }; + var midpoint = function midpoint(ele) { + return ele.renderer().getEdgeMidpoint(ele); + }; + var pts = { + controlPoints: { + get: controlPoints, + mult: true + }, + segmentPoints: { + get: segmentPoints, + mult: true + }, + sourceEndpoint: { + get: sourceEndpoint + }, + targetEndpoint: { + get: targetEndpoint + }, + midpoint: { + get: midpoint + } + }; + var renderedName = function renderedName(name) { + return 'rendered' + name[0].toUpperCase() + name.substr(1); + }; + var edgePoints = Object.keys(pts).reduce(function (obj, name) { + var spec = pts[name]; + var rName = renderedName(name); + obj[name] = function () { + return ifEdge(this, spec.get); + }; + if (spec.mult) { + obj[rName] = function () { + return ifEdgeRenderedPositions(this, spec.get); + }; + } else { + obj[rName] = function () { + return ifEdgeRenderedPosition(this, spec.get); + }; + } + return obj; + }, {}); - determinant() { + var dimensions = extend$1({}, position, bounds, widthHeight, edgePoints); - const te = this.elements; + /*! + Event object based on jQuery events, MIT license - const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], - d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], - g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; + https://jquery.org/license/ + https://tldrlegal.com/license/mit-license + https://github.com/jquery/jquery/blob/master/src/event.js + */ - return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; + var Event = function Event(src, props) { + this.recycle(src, props); + }; + function returnFalse() { + return false; + } + function returnTrue() { + return true; + } + + // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html + Event.prototype = { + instanceString: function instanceString() { + return 'event'; + }, + recycle: function recycle(src, props) { + this.isImmediatePropagationStopped = this.isPropagationStopped = this.isDefaultPrevented = returnFalse; + if (src != null && src.preventDefault) { + // Browser Event object + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented ? returnTrue : returnFalse; + } else if (src != null && src.type) { + // Plain object containing all event details + props = src; + } else { + // Event string + this.type = src; + } - } + // Put explicitly provided properties onto the event object + if (props != null) { + // more efficient to manually copy fields we use + this.originalEvent = props.originalEvent; + this.type = props.type != null ? props.type : this.type; + this.cy = props.cy; + this.target = props.target; + this.position = props.position; + this.renderedPosition = props.renderedPosition; + this.namespace = props.namespace; + this.layout = props.layout; + } + if (this.cy != null && this.position != null && this.renderedPosition == null) { + // create a rendered position based on the passed position + var pos = this.position; + var zoom = this.cy.zoom(); + var pan = this.cy.pan(); + this.renderedPosition = { + x: pos.x * zoom + pan.x, + y: pos.y * zoom + pan.y + }; + } - invert() { + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + }, + preventDefault: function preventDefault() { + this.isDefaultPrevented = returnTrue; + var e = this.originalEvent; + if (!e) { + return; + } - const te = this.elements, + // if preventDefault exists run it on the original event + if (e.preventDefault) { + e.preventDefault(); + } + }, + stopPropagation: function stopPropagation() { + this.isPropagationStopped = returnTrue; + var e = this.originalEvent; + if (!e) { + return; + } - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], - n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], - n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], + // if stopPropagation exists run it on the original event + if (e.stopPropagation) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function stopImmediatePropagation() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse + }; - t11 = n33 * n22 - n32 * n23, - t12 = n32 * n13 - n33 * n12, - t13 = n23 * n12 - n22 * n13, + var eventRegex = /^([^.]+)(\.(?:[^.]+))?$/; // regex for matching event strings (e.g. "click.namespace") + var universalNamespace = '.*'; // matches as if no namespace specified and prevents users from unbinding accidentally + + var defaults$8 = { + qualifierCompare: function qualifierCompare(q1, q2) { + return q1 === q2; + }, + eventMatches: function eventMatches( /*context, listener, eventObj*/ + ) { + return true; + }, + addEventFields: function addEventFields( /*context, evt*/ + ) {}, + callbackContext: function callbackContext(context /*, listener, eventObj*/) { + return context; + }, + beforeEmit: function beforeEmit( /* context, listener, eventObj */ + ) {}, + afterEmit: function afterEmit( /* context, listener, eventObj */ + ) {}, + bubble: function bubble( /*context*/ + ) { + return false; + }, + parent: function parent( /*context*/ + ) { + return null; + }, + context: null + }; + var defaultsKeys = Object.keys(defaults$8); + var emptyOpts = {}; + function Emitter() { + var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : emptyOpts; + var context = arguments.length > 1 ? arguments[1] : undefined; + // micro-optimisation vs Object.assign() -- reduces Element instantiation time + for (var i = 0; i < defaultsKeys.length; i++) { + var key = defaultsKeys[i]; + this[key] = opts[key] || defaults$8[key]; + } + this.context = context || this.context; + this.listeners = []; + this.emitting = 0; + } + var p = Emitter.prototype; + var forEachEvent = function forEachEvent(self, handler, events, qualifier, callback, conf, confOverrides) { + if (fn$6(qualifier)) { + callback = qualifier; + qualifier = null; + } + if (confOverrides) { + if (conf == null) { + conf = confOverrides; + } else { + conf = extend$1({}, conf, confOverrides); + } + } + var eventList = array(events) ? events : events.split(/\s+/); + for (var i = 0; i < eventList.length; i++) { + var evt = eventList[i]; + if (emptyString(evt)) { + continue; + } + var match = evt.match(eventRegex); // type[.namespace] + + if (match) { + var type = match[1]; + var namespace = match[2] ? match[2] : null; + var ret = handler(self, evt, type, namespace, qualifier, callback, conf); + if (ret === false) { + break; + } // allow exiting early + } + } + }; - det = n11 * t11 + n21 * t12 + n31 * t13; + var makeEventObj = function makeEventObj(self, obj) { + self.addEventFields(self.context, obj); + return new Event(obj.type, obj); + }; + var forEachEventObj = function forEachEventObj(self, handler, events) { + if (event(events)) { + handler(self, events); + return; + } else if (plainObject(events)) { + handler(self, makeEventObj(self, events)); + return; + } + var eventList = array(events) ? events : events.split(/\s+/); + for (var i = 0; i < eventList.length; i++) { + var evt = eventList[i]; + if (emptyString(evt)) { + continue; + } + var match = evt.match(eventRegex); // type[.namespace] + + if (match) { + var type = match[1]; + var namespace = match[2] ? match[2] : null; + var eventObj = makeEventObj(self, { + type: type, + namespace: namespace, + target: self.context + }); + handler(self, eventObj); + } + } + }; + p.on = p.addListener = function (events, qualifier, callback, conf, confOverrides) { + forEachEvent(this, function (self, event, type, namespace, qualifier, callback, conf) { + if (fn$6(callback)) { + self.listeners.push({ + event: event, + // full event string + callback: callback, + // callback to run + type: type, + // the event type (e.g. 'click') + namespace: namespace, + // the event namespace (e.g. ".foo") + qualifier: qualifier, + // a restriction on whether to match this emitter + conf: conf // additional configuration + }); + } + }, events, qualifier, callback, conf, confOverrides); + return this; + }; + p.one = function (events, qualifier, callback, conf) { + return this.on(events, qualifier, callback, conf, { + one: true + }); + }; + p.removeListener = p.off = function (events, qualifier, callback, conf) { + var _this = this; + if (this.emitting !== 0) { + this.listeners = copyArray$1(this.listeners); + } + var listeners = this.listeners; + var _loop = function _loop(i) { + var listener = listeners[i]; + forEachEvent(_this, function (self, event, type, namespace, qualifier, callback /*, conf*/) { + if ((listener.type === type || events === '*') && (!namespace && listener.namespace !== '.*' || listener.namespace === namespace) && (!qualifier || self.qualifierCompare(listener.qualifier, qualifier)) && (!callback || listener.callback === callback)) { + listeners.splice(i, 1); + return false; + } + }, events, qualifier, callback, conf); + }; + for (var i = listeners.length - 1; i >= 0; i--) { + _loop(i); + } + return this; + }; + p.removeAllListeners = function () { + return this.removeListener('*'); + }; + p.emit = p.trigger = function (events, extraParams, manualCallback) { + var listeners = this.listeners; + var numListenersBeforeEmit = listeners.length; + this.emitting++; + if (!array(extraParams)) { + extraParams = [extraParams]; + } + forEachEventObj(this, function (self, eventObj) { + if (manualCallback != null) { + listeners = [{ + event: eventObj.event, + type: eventObj.type, + namespace: eventObj.namespace, + callback: manualCallback + }]; + numListenersBeforeEmit = listeners.length; + } + var _loop2 = function _loop2(i) { + var listener = listeners[i]; + if (listener.type === eventObj.type && (!listener.namespace || listener.namespace === eventObj.namespace || listener.namespace === universalNamespace) && self.eventMatches(self.context, listener, eventObj)) { + var args = [eventObj]; + if (extraParams != null) { + push(args, extraParams); + } + self.beforeEmit(self.context, listener, eventObj); + if (listener.conf && listener.conf.one) { + self.listeners = self.listeners.filter(function (l) { + return l !== listener; + }); + } + var context = self.callbackContext(self.context, listener, eventObj); + var ret = listener.callback.apply(context, args); + self.afterEmit(self.context, listener, eventObj); + if (ret === false) { + eventObj.stopPropagation(); + eventObj.preventDefault(); + } + } // if listener matches + }; + for (var i = 0; i < numListenersBeforeEmit; i++) { + _loop2(i); + } // for listener - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + if (self.bubble(self.context) && !eventObj.isPropagationStopped()) { + self.parent(self.context).emit(eventObj, extraParams); + } + }, events); + this.emitting--; + return this; + }; - const detInv = 1 / det; + var emitterOptions$1 = { + qualifierCompare: function qualifierCompare(selector1, selector2) { + if (selector1 == null || selector2 == null) { + return selector1 == null && selector2 == null; + } else { + return selector1.sameText(selector2); + } + }, + eventMatches: function eventMatches(ele, listener, eventObj) { + var selector = listener.qualifier; + if (selector != null) { + return ele !== eventObj.target && element(eventObj.target) && selector.matches(eventObj.target); + } + return true; + }, + addEventFields: function addEventFields(ele, evt) { + evt.cy = ele.cy(); + evt.target = ele; + }, + callbackContext: function callbackContext(ele, listener, eventObj) { + return listener.qualifier != null ? eventObj.target : ele; + }, + beforeEmit: function beforeEmit(context, listener /*, eventObj*/) { + if (listener.conf && listener.conf.once) { + listener.conf.onceCollection.removeListener(listener.event, listener.qualifier, listener.callback); + } + }, + bubble: function bubble() { + return true; + }, + parent: function parent(ele) { + return ele.isChild() ? ele.parent() : ele.cy(); + } + }; + var argSelector$1 = function argSelector(arg) { + if (string(arg)) { + return new Selector(arg); + } else { + return arg; + } + }; + var elesfn$9 = { + createEmitter: function createEmitter() { + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var _p = ele._private; + if (!_p.emitter) { + _p.emitter = new Emitter(emitterOptions$1, ele); + } + } + return this; + }, + emitter: function emitter() { + return this._private.emitter; + }, + on: function on(events, selector, callback) { + var argSel = argSelector$1(selector); + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + ele.emitter().on(events, argSel, callback); + } + return this; + }, + removeListener: function removeListener(events, selector, callback) { + var argSel = argSelector$1(selector); + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + ele.emitter().removeListener(events, argSel, callback); + } + return this; + }, + removeAllListeners: function removeAllListeners() { + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + ele.emitter().removeAllListeners(); + } + return this; + }, + one: function one(events, selector, callback) { + var argSel = argSelector$1(selector); + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + ele.emitter().one(events, argSel, callback); + } + return this; + }, + once: function once(events, selector, callback) { + var argSel = argSelector$1(selector); + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + ele.emitter().on(events, argSel, callback, { + once: true, + onceCollection: this + }); + } + }, + emit: function emit(events, extraParams) { + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + ele.emitter().emit(events, extraParams); + } + return this; + }, + emitAndNotify: function emitAndNotify(event, extraParams) { + // for internal use only + if (this.length === 0) { + return; + } // empty collections don't need to notify anything + + // notify renderer + this.cy().notify(event, this); + this.emit(event, extraParams); + return this; + } + }; + define.eventAliasesOn(elesfn$9); + + var elesfn$8 = { + nodes: function nodes(selector) { + return this.filter(function (ele) { + return ele.isNode(); + }).filter(selector); + }, + edges: function edges(selector) { + return this.filter(function (ele) { + return ele.isEdge(); + }).filter(selector); + }, + // internal helper to get nodes and edges as separate collections with single iteration over elements + byGroup: function byGroup() { + var nodes = this.spawn(); + var edges = this.spawn(); + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + if (ele.isNode()) { + nodes.push(ele); + } else { + edges.push(ele); + } + } + return { + nodes: nodes, + edges: edges + }; + }, + filter: function filter(_filter, thisArg) { + if (_filter === undefined) { + // check this first b/c it's the most common/performant case + return this; + } else if (string(_filter) || elementOrCollection(_filter)) { + return new Selector(_filter).filter(this); + } else if (fn$6(_filter)) { + var filterEles = this.spawn(); + var eles = this; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var include = thisArg ? _filter.apply(thisArg, [ele, i, eles]) : _filter(ele, i, eles); + if (include) { + filterEles.push(ele); + } + } + return filterEles; + } + return this.spawn(); // if not handled by above, give 'em an empty collection + }, + + not: function not(toRemove) { + if (!toRemove) { + return this; + } else { + if (string(toRemove)) { + toRemove = this.filter(toRemove); + } + var elements = this.spawn(); + for (var i = 0; i < this.length; i++) { + var element = this[i]; + var remove = toRemove.has(element); + if (!remove) { + elements.push(element); + } + } + return elements; + } + }, + absoluteComplement: function absoluteComplement() { + var cy = this.cy(); + return cy.mutableElements().not(this); + }, + intersect: function intersect(other) { + // if a selector is specified, then filter by it instead + if (string(other)) { + var selector = other; + return this.filter(selector); + } + var elements = this.spawn(); + var col1 = this; + var col2 = other; + var col1Smaller = this.length < other.length; + var colS = col1Smaller ? col1 : col2; + var colL = col1Smaller ? col2 : col1; + for (var i = 0; i < colS.length; i++) { + var ele = colS[i]; + if (colL.has(ele)) { + elements.push(ele); + } + } + return elements; + }, + xor: function xor(other) { + var cy = this._private.cy; + if (string(other)) { + other = cy.$(other); + } + var elements = this.spawn(); + var col1 = this; + var col2 = other; + var add = function add(col, other) { + for (var i = 0; i < col.length; i++) { + var ele = col[i]; + var id = ele._private.data.id; + var inOther = other.hasElementWithId(id); + if (!inOther) { + elements.push(ele); + } + } + }; + add(col1, col2); + add(col2, col1); + return elements; + }, + diff: function diff(other) { + var cy = this._private.cy; + if (string(other)) { + other = cy.$(other); + } + var left = this.spawn(); + var right = this.spawn(); + var both = this.spawn(); + var col1 = this; + var col2 = other; + var add = function add(col, other, retEles) { + for (var i = 0; i < col.length; i++) { + var ele = col[i]; + var id = ele._private.data.id; + var inOther = other.hasElementWithId(id); + if (inOther) { + both.merge(ele); + } else { + retEles.push(ele); + } + } + }; + add(col1, col2, left); + add(col2, col1, right); + return { + left: left, + right: right, + both: both + }; + }, + add: function add(toAdd) { + var cy = this._private.cy; + if (!toAdd) { + return this; + } + if (string(toAdd)) { + var selector = toAdd; + toAdd = cy.mutableElements().filter(selector); + } + var elements = this.spawnSelf(); + for (var i = 0; i < toAdd.length; i++) { + var ele = toAdd[i]; + var add = !this.has(ele); + if (add) { + elements.push(ele); + } + } + return elements; + }, + // in place merge on calling collection + merge: function merge(toAdd) { + var _p = this._private; + var cy = _p.cy; + if (!toAdd) { + return this; + } + if (toAdd && string(toAdd)) { + var selector = toAdd; + toAdd = cy.mutableElements().filter(selector); + } + var map = _p.map; + for (var i = 0; i < toAdd.length; i++) { + var toAddEle = toAdd[i]; + var id = toAddEle._private.data.id; + var add = !map.has(id); + if (add) { + var index = this.length++; + this[index] = toAddEle; + map.set(id, { + ele: toAddEle, + index: index + }); + } + } + return this; // chaining + }, + + unmergeAt: function unmergeAt(i) { + var ele = this[i]; + var id = ele.id(); + var _p = this._private; + var map = _p.map; + + // remove ele + this[i] = undefined; + map["delete"](id); + var unmergedLastEle = i === this.length - 1; + + // replace empty spot with last ele in collection + if (this.length > 1 && !unmergedLastEle) { + var lastEleI = this.length - 1; + var lastEle = this[lastEleI]; + var lastEleId = lastEle._private.data.id; + this[lastEleI] = undefined; + this[i] = lastEle; + map.set(lastEleId, { + ele: lastEle, + index: i + }); + } - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; - te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; + // the collection is now 1 ele smaller + this.length--; + return this; + }, + // remove single ele in place in calling collection + unmergeOne: function unmergeOne(ele) { + ele = ele[0]; + var _p = this._private; + var id = ele._private.data.id; + var map = _p.map; + var entry = map.get(id); + if (!entry) { + return this; // no need to remove + } - te[ 3 ] = t12 * detInv; - te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; - te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; + var i = entry.index; + this.unmergeAt(i); + return this; + }, + // remove eles in place on calling collection + unmerge: function unmerge(toRemove) { + var cy = this._private.cy; + if (!toRemove) { + return this; + } + if (toRemove && string(toRemove)) { + var selector = toRemove; + toRemove = cy.mutableElements().filter(selector); + } + for (var i = 0; i < toRemove.length; i++) { + this.unmergeOne(toRemove[i]); + } + return this; // chaining + }, + + unmergeBy: function unmergeBy(toRmFn) { + for (var i = this.length - 1; i >= 0; i--) { + var ele = this[i]; + if (toRmFn(ele)) { + this.unmergeAt(i); + } + } + return this; + }, + map: function map(mapFn, thisArg) { + var arr = []; + var eles = this; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var ret = thisArg ? mapFn.apply(thisArg, [ele, i, eles]) : mapFn(ele, i, eles); + arr.push(ret); + } + return arr; + }, + reduce: function reduce(fn, initialValue) { + var val = initialValue; + var eles = this; + for (var i = 0; i < eles.length; i++) { + val = fn(val, eles[i], i, eles); + } + return val; + }, + max: function max(valFn, thisArg) { + var max = -Infinity; + var maxEle; + var eles = this; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var val = thisArg ? valFn.apply(thisArg, [ele, i, eles]) : valFn(ele, i, eles); + if (val > max) { + max = val; + maxEle = ele; + } + } + return { + value: max, + ele: maxEle + }; + }, + min: function min(valFn, thisArg) { + var min = Infinity; + var minEle; + var eles = this; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var val = thisArg ? valFn.apply(thisArg, [ele, i, eles]) : valFn(ele, i, eles); + if (val < min) { + min = val; + minEle = ele; + } + } + return { + value: min, + ele: minEle + }; + } + }; - te[ 6 ] = t13 * detInv; - te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; - te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; + // aliases + var fn$1 = elesfn$8; + fn$1['u'] = fn$1['|'] = fn$1['+'] = fn$1.union = fn$1.or = fn$1.add; + fn$1['\\'] = fn$1['!'] = fn$1['-'] = fn$1.difference = fn$1.relativeComplement = fn$1.subtract = fn$1.not; + fn$1['n'] = fn$1['&'] = fn$1['.'] = fn$1.and = fn$1.intersection = fn$1.intersect; + fn$1['^'] = fn$1['(+)'] = fn$1['(-)'] = fn$1.symmetricDifference = fn$1.symdiff = fn$1.xor; + fn$1.fnFilter = fn$1.filterFn = fn$1.stdFilter = fn$1.filter; + fn$1.complement = fn$1.abscomp = fn$1.absoluteComplement; + + var elesfn$7 = { + isNode: function isNode() { + return this.group() === 'nodes'; + }, + isEdge: function isEdge() { + return this.group() === 'edges'; + }, + isLoop: function isLoop() { + return this.isEdge() && this.source()[0] === this.target()[0]; + }, + isSimple: function isSimple() { + return this.isEdge() && this.source()[0] !== this.target()[0]; + }, + group: function group() { + var ele = this[0]; + if (ele) { + return ele._private.group; + } + } + }; - return this; + /** + * Elements are drawn in a specific order based on compound depth (low to high), the element type (nodes above edges), + * and z-index (low to high). These styles affect how this applies: + * + * z-compound-depth: May be `bottom | orphan | auto | top`. The first drawn is `bottom`, then `orphan` which is the + * same depth as the root of the compound graph, followed by the default value `auto` which draws in order from + * root to leaves of the compound graph. The last drawn is `top`. + * z-index-compare: May be `auto | manual`. The default value is `auto` which always draws edges under nodes. + * `manual` ignores this convention and draws based on the `z-index` value setting. + * z-index: An integer value that affects the relative draw order of elements. In general, an element with a higher + * `z-index` will be drawn on top of an element with a lower `z-index`. + */ + var zIndexSort = function zIndexSort(a, b) { + var cy = a.cy(); + var hasCompoundNodes = cy.hasCompoundNodes(); + function getDepth(ele) { + var style = ele.pstyle('z-compound-depth'); + if (style.value === 'auto') { + return hasCompoundNodes ? ele.zDepth() : 0; + } else if (style.value === 'bottom') { + return -1; + } else if (style.value === 'top') { + return MAX_INT$1; + } + // 'orphan' + return 0; + } + var depthDiff = getDepth(a) - getDepth(b); + if (depthDiff !== 0) { + return depthDiff; + } + function getEleDepth(ele) { + var style = ele.pstyle('z-index-compare'); + if (style.value === 'auto') { + return ele.isNode() ? 1 : 0; + } + // 'manual' + return 0; + } + var eleDiff = getEleDepth(a) - getEleDepth(b); + if (eleDiff !== 0) { + return eleDiff; + } + var zDiff = a.pstyle('z-index').value - b.pstyle('z-index').value; + if (zDiff !== 0) { + return zDiff; + } + // compare indices in the core (order added to graph w/ last on top) + return a.poolIndex() - b.poolIndex(); + }; - } + var elesfn$6 = { + forEach: function forEach(fn, thisArg) { + if (fn$6(fn)) { + var N = this.length; + for (var i = 0; i < N; i++) { + var ele = this[i]; + var ret = thisArg ? fn.apply(thisArg, [ele, i, this]) : fn(ele, i, this); + if (ret === false) { + break; + } // exit each early on return false + } + } - transpose() { + return this; + }, + toArray: function toArray() { + var array = []; + for (var i = 0; i < this.length; i++) { + array.push(this[i]); + } + return array; + }, + slice: function slice(start, end) { + var array = []; + var thisSize = this.length; + if (end == null) { + end = thisSize; + } + if (start == null) { + start = 0; + } + if (start < 0) { + start = thisSize + start; + } + if (end < 0) { + end = thisSize + end; + } + for (var i = start; i >= 0 && i < end && i < thisSize; i++) { + array.push(this[i]); + } + return this.spawn(array); + }, + size: function size() { + return this.length; + }, + eq: function eq(i) { + return this[i] || this.spawn(); + }, + first: function first() { + return this[0] || this.spawn(); + }, + last: function last() { + return this[this.length - 1] || this.spawn(); + }, + empty: function empty() { + return this.length === 0; + }, + nonempty: function nonempty() { + return !this.empty(); + }, + sort: function sort(sortFn) { + if (!fn$6(sortFn)) { + return this; + } + var sorted = this.toArray().sort(sortFn); + return this.spawn(sorted); + }, + sortByZIndex: function sortByZIndex() { + return this.sort(zIndexSort); + }, + zDepth: function zDepth() { + var ele = this[0]; + if (!ele) { + return undefined; + } - let tmp; - const m = this.elements; + // let cy = ele.cy(); + var _p = ele._private; + var group = _p.group; + if (group === 'nodes') { + var depth = _p.data.parent ? ele.parents().size() : 0; + if (!ele.isParent()) { + return MAX_INT$1 - 1; // childless nodes always on top + } + + return depth; + } else { + var src = _p.source; + var tgt = _p.target; + var srcDepth = src.zDepth(); + var tgtDepth = tgt.zDepth(); + return Math.max(srcDepth, tgtDepth, 0); // depth of deepest parent + } + } + }; - tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; - tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; - tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; + elesfn$6.each = elesfn$6.forEach; + var defineSymbolIterator = function defineSymbolIterator() { + var typeofUndef = "undefined" ; + var isIteratorSupported = (typeof Symbol === "undefined" ? "undefined" : _typeof(Symbol)) != typeofUndef && _typeof(Symbol.iterator) != typeofUndef; // eslint-disable-line no-undef + + if (isIteratorSupported) { + elesfn$6[Symbol.iterator] = function () { + var _this = this; + // eslint-disable-line no-undef + var entry = { + value: undefined, + done: false + }; + var i = 0; + var length = this.length; + return _defineProperty$1({ + next: function next() { + if (i < length) { + entry.value = _this[i++]; + } else { + entry.value = undefined; + entry.done = true; + } + return entry; + } + }, Symbol.iterator, function () { + // eslint-disable-line no-undef + return this; + }); + }; + } + }; + defineSymbolIterator(); - return this; + var getLayoutDimensionOptions = defaults$g({ + nodeDimensionsIncludeLabels: false + }); + var elesfn$5 = { + // Calculates and returns node dimensions { x, y } based on options given + layoutDimensions: function layoutDimensions(options) { + options = getLayoutDimensionOptions(options); + var dims; + if (!this.takesUpSpace()) { + dims = { + w: 0, + h: 0 + }; + } else if (options.nodeDimensionsIncludeLabels) { + var bbDim = this.boundingBox(); + dims = { + w: bbDim.w, + h: bbDim.h + }; + } else { + dims = { + w: this.outerWidth(), + h: this.outerHeight() + }; + } - } + // sanitise the dimensions for external layouts (avoid division by zero) + if (dims.w === 0 || dims.h === 0) { + dims.w = dims.h = 1; + } + return dims; + }, + // using standard layout options, apply position function (w/ or w/o animation) + layoutPositions: function layoutPositions(layout, options, fn) { + var nodes = this.nodes().filter(function (n) { + return !n.isParent(); + }); + var cy = this.cy(); + var layoutEles = options.eles; // nodes & edges + var getMemoizeKey = function getMemoizeKey(node) { + return node.id(); + }; + var fnMem = memoize$1(fn, getMemoizeKey); // memoized version of position function - getNormalMatrix( matrix4 ) { + layout.emit({ + type: 'layoutstart', + layout: layout + }); + layout.animations = []; + var calculateSpacing = function calculateSpacing(spacing, nodesBb, pos) { + var center = { + x: nodesBb.x1 + nodesBb.w / 2, + y: nodesBb.y1 + nodesBb.h / 2 + }; + var spacingVector = { + // scale from center of bounding box (not necessarily 0,0) + x: (pos.x - center.x) * spacing, + y: (pos.y - center.y) * spacing + }; + return { + x: center.x + spacingVector.x, + y: center.y + spacingVector.y + }; + }; + var useSpacingFactor = options.spacingFactor && options.spacingFactor !== 1; + var spacingBb = function spacingBb() { + if (!useSpacingFactor) { + return null; + } + var bb = makeBoundingBox(); + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var pos = fnMem(node, i); + expandBoundingBoxByPoint(bb, pos.x, pos.y); + } + return bb; + }; + var bb = spacingBb(); + var getFinalPos = memoize$1(function (node, i) { + var newPos = fnMem(node, i); + if (useSpacingFactor) { + var spacing = Math.abs(options.spacingFactor); + newPos = calculateSpacing(spacing, bb, newPos); + } + if (options.transform != null) { + newPos = options.transform(node, newPos); + } + return newPos; + }, getMemoizeKey); + if (options.animate) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var newPos = getFinalPos(node, i); + var animateNode = options.animateFilter == null || options.animateFilter(node, i); + if (animateNode) { + var ani = node.animation({ + position: newPos, + duration: options.animationDuration, + easing: options.animationEasing + }); + layout.animations.push(ani); + } else { + node.position(newPos); + } + } + if (options.fit) { + var fitAni = cy.animation({ + fit: { + boundingBox: layoutEles.boundingBoxAt(getFinalPos), + padding: options.padding + }, + duration: options.animationDuration, + easing: options.animationEasing + }); + layout.animations.push(fitAni); + } else if (options.zoom !== undefined && options.pan !== undefined) { + var zoomPanAni = cy.animation({ + zoom: options.zoom, + pan: options.pan, + duration: options.animationDuration, + easing: options.animationEasing + }); + layout.animations.push(zoomPanAni); + } + layout.animations.forEach(function (ani) { + return ani.play(); + }); + layout.one('layoutready', options.ready); + layout.emit({ + type: 'layoutready', + layout: layout + }); + Promise$1.all(layout.animations.map(function (ani) { + return ani.promise(); + })).then(function () { + layout.one('layoutstop', options.stop); + layout.emit({ + type: 'layoutstop', + layout: layout + }); + }); + } else { + nodes.positions(getFinalPos); + if (options.fit) { + cy.fit(options.eles, options.padding); + } + if (options.zoom != null) { + cy.zoom(options.zoom); + } + if (options.pan) { + cy.pan(options.pan); + } + layout.one('layoutready', options.ready); + layout.emit({ + type: 'layoutready', + layout: layout + }); + layout.one('layoutstop', options.stop); + layout.emit({ + type: 'layoutstop', + layout: layout + }); + } + return this; // chaining + }, + + layout: function layout(options) { + var cy = this.cy(); + return cy.makeLayout(extend$1({}, options, { + eles: this + })); + } + }; - return this.setFromMatrix4( matrix4 ).invert().transpose(); + // aliases: + elesfn$5.createLayout = elesfn$5.makeLayout = elesfn$5.layout; + + function styleCache(key, fn, ele) { + var _p = ele._private; + var cache = _p.styleCache = _p.styleCache || []; + var val; + if ((val = cache[key]) != null) { + return val; + } else { + val = cache[key] = fn(ele); + return val; + } + } + function cacheStyleFunction(key, fn) { + key = hashString(key); + return function cachedStyleFunction(ele) { + return styleCache(key, fn, ele); + }; + } + function cachePrototypeStyleFunction(key, fn) { + key = hashString(key); + var selfFn = function selfFn(ele) { + return fn.call(ele); + }; + return function cachedPrototypeStyleFunction() { + var ele = this[0]; + if (ele) { + return styleCache(key, selfFn, ele); + } + }; + } + var elesfn$4 = { + recalculateRenderedStyle: function recalculateRenderedStyle(useCache) { + var cy = this.cy(); + var renderer = cy.renderer(); + var styleEnabled = cy.styleEnabled(); + if (renderer && styleEnabled) { + renderer.recalculateRenderedStyle(this, useCache); + } + return this; + }, + dirtyStyleCache: function dirtyStyleCache() { + var cy = this.cy(); + var dirty = function dirty(ele) { + return ele._private.styleCache = null; + }; + if (cy.hasCompoundNodes()) { + var eles; + eles = this.spawnSelf().merge(this.descendants()).merge(this.parents()); + eles.merge(eles.connectedEdges()); + eles.forEach(dirty); + } else { + this.forEach(function (ele) { + dirty(ele); + ele.connectedEdges().forEach(dirty); + }); + } + return this; + }, + // fully updates (recalculates) the style for the elements + updateStyle: function updateStyle(notifyRenderer) { + var cy = this._private.cy; + if (!cy.styleEnabled()) { + return this; + } + if (cy.batching()) { + var bEles = cy._private.batchStyleEles; + bEles.merge(this); + return this; // chaining and exit early when batching + } - } + var hasCompounds = cy.hasCompoundNodes(); + var updatedEles = this; + notifyRenderer = notifyRenderer || notifyRenderer === undefined ? true : false; + if (hasCompounds) { + // then add everything up and down for compound selector checks + updatedEles = this.spawnSelf().merge(this.descendants()).merge(this.parents()); + } - transposeIntoArray( r ) { + // let changedEles = style.apply( updatedEles ); + var changedEles = updatedEles; + if (notifyRenderer) { + changedEles.emitAndNotify('style'); // let renderer know we changed style + } else { + changedEles.emit('style'); // just fire the event + } - const m = this.elements; + updatedEles.forEach(function (ele) { + return ele._private.styleDirty = true; + }); + return this; // chaining + }, + + // private: clears dirty flag and recalculates style + cleanStyle: function cleanStyle() { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return; + } + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + if (ele._private.styleDirty) { + // n.b. this flag should be set before apply() to avoid potential infinite recursion + ele._private.styleDirty = false; + cy.style().apply(ele); + } + } + }, + // get the internal parsed style object for the specified property + parsedStyle: function parsedStyle(property) { + var includeNonDefault = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var ele = this[0]; + var cy = ele.cy(); + if (!cy.styleEnabled()) { + return; + } + if (ele) { + this.cleanStyle(); + var overriddenStyle = ele._private.style[property]; + if (overriddenStyle != null) { + return overriddenStyle; + } else if (includeNonDefault) { + return cy.style().getDefaultProperty(property); + } else { + return null; + } + } + }, + numericStyle: function numericStyle(property) { + var ele = this[0]; + if (!ele.cy().styleEnabled()) { + return; + } + if (ele) { + var pstyle = ele.pstyle(property); + return pstyle.pfValue !== undefined ? pstyle.pfValue : pstyle.value; + } + }, + numericStyleUnits: function numericStyleUnits(property) { + var ele = this[0]; + if (!ele.cy().styleEnabled()) { + return; + } + if (ele) { + return ele.pstyle(property).units; + } + }, + // get the specified css property as a rendered value (i.e. on-screen value) + // or get the whole rendered style if no property specified (NB doesn't allow setting) + renderedStyle: function renderedStyle(property) { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return this; + } + var ele = this[0]; + if (ele) { + return cy.style().getRenderedStyle(ele, property); + } + }, + // read the calculated css style of the element or override the style (via a bypass) + style: function style(name, value) { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return this; + } + var updateTransitions = false; + var style = cy.style(); + if (plainObject(name)) { + // then extend the bypass + var props = name; + style.applyBypass(this, props, updateTransitions); + this.emitAndNotify('style'); // let the renderer know we've updated style + } else if (string(name)) { + if (value === undefined) { + // then get the property from the style + var ele = this[0]; + if (ele) { + return style.getStylePropertyValue(ele, name); + } else { + // empty collection => can't get any value + return; + } + } else { + // then set the bypass with the property value + style.applyBypass(this, name, value, updateTransitions); + this.emitAndNotify('style'); // let the renderer know we've updated style + } + } else if (name === undefined) { + var _ele = this[0]; + if (_ele) { + return style.getRawStyle(_ele); + } else { + // empty collection => can't get any value + return; + } + } + return this; // chaining + }, - r[ 0 ] = m[ 0 ]; - r[ 1 ] = m[ 3 ]; - r[ 2 ] = m[ 6 ]; - r[ 3 ] = m[ 1 ]; - r[ 4 ] = m[ 4 ]; - r[ 5 ] = m[ 7 ]; - r[ 6 ] = m[ 2 ]; - r[ 7 ] = m[ 5 ]; - r[ 8 ] = m[ 8 ]; + removeStyle: function removeStyle(names) { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return this; + } + var updateTransitions = false; + var style = cy.style(); + var eles = this; + if (names === undefined) { + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + style.removeAllBypasses(ele, updateTransitions); + } + } else { + names = names.split(/\s+/); + for (var _i = 0; _i < eles.length; _i++) { + var _ele2 = eles[_i]; + style.removeBypasses(_ele2, names, updateTransitions); + } + } + this.emitAndNotify('style'); // let the renderer know we've updated style - return this; + return this; // chaining + }, - } + show: function show() { + this.css('display', 'element'); + return this; // chaining + }, - setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { + hide: function hide() { + this.css('display', 'none'); + return this; // chaining + }, - const c = Math.cos( rotation ); - const s = Math.sin( rotation ); + effectiveOpacity: function effectiveOpacity() { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return 1; + } + var hasCompoundNodes = cy.hasCompoundNodes(); + var ele = this[0]; + if (ele) { + var _p = ele._private; + var parentOpacity = ele.pstyle('opacity').value; + if (!hasCompoundNodes) { + return parentOpacity; + } + var parents = !_p.data.parent ? null : ele.parents(); + if (parents) { + for (var i = 0; i < parents.length; i++) { + var parent = parents[i]; + var opacity = parent.pstyle('opacity').value; + parentOpacity = opacity * parentOpacity; + } + } + return parentOpacity; + } + }, + transparent: function transparent() { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return false; + } + var ele = this[0]; + var hasCompoundNodes = ele.cy().hasCompoundNodes(); + if (ele) { + if (!hasCompoundNodes) { + return ele.pstyle('opacity').value === 0; + } else { + return ele.effectiveOpacity() === 0; + } + } + }, + backgrounding: function backgrounding() { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return false; + } + var ele = this[0]; + return ele._private.backgrounding ? true : false; + } + }; + function checkCompound(ele, parentOk) { + var _p = ele._private; + var parents = _p.data.parent ? ele.parents() : null; + if (parents) { + for (var i = 0; i < parents.length; i++) { + var parent = parents[i]; + if (!parentOk(parent)) { + return false; + } + } + } + return true; + } + function defineDerivedStateFunction(specs) { + var ok = specs.ok; + var edgeOkViaNode = specs.edgeOkViaNode || specs.ok; + var parentOk = specs.parentOk || specs.ok; + return function () { + var cy = this.cy(); + if (!cy.styleEnabled()) { + return true; + } + var ele = this[0]; + var hasCompoundNodes = cy.hasCompoundNodes(); + if (ele) { + var _p = ele._private; + if (!ok(ele)) { + return false; + } + if (ele.isNode()) { + return !hasCompoundNodes || checkCompound(ele, parentOk); + } else { + var src = _p.source; + var tgt = _p.target; + return edgeOkViaNode(src) && (!hasCompoundNodes || checkCompound(src, edgeOkViaNode)) && (src === tgt || edgeOkViaNode(tgt) && (!hasCompoundNodes || checkCompound(tgt, edgeOkViaNode))); + } + } + }; + } + var eleTakesUpSpace = cacheStyleFunction('eleTakesUpSpace', function (ele) { + return ele.pstyle('display').value === 'element' && ele.width() !== 0 && (ele.isNode() ? ele.height() !== 0 : true); + }); + elesfn$4.takesUpSpace = cachePrototypeStyleFunction('takesUpSpace', defineDerivedStateFunction({ + ok: eleTakesUpSpace + })); + var eleInteractive = cacheStyleFunction('eleInteractive', function (ele) { + return ele.pstyle('events').value === 'yes' && ele.pstyle('visibility').value === 'visible' && eleTakesUpSpace(ele); + }); + var parentInteractive = cacheStyleFunction('parentInteractive', function (parent) { + return parent.pstyle('visibility').value === 'visible' && eleTakesUpSpace(parent); + }); + elesfn$4.interactive = cachePrototypeStyleFunction('interactive', defineDerivedStateFunction({ + ok: eleInteractive, + parentOk: parentInteractive, + edgeOkViaNode: eleTakesUpSpace + })); + elesfn$4.noninteractive = function () { + var ele = this[0]; + if (ele) { + return !ele.interactive(); + } + }; + var eleVisible = cacheStyleFunction('eleVisible', function (ele) { + return ele.pstyle('visibility').value === 'visible' && ele.pstyle('opacity').pfValue !== 0 && eleTakesUpSpace(ele); + }); + var edgeVisibleViaNode = eleTakesUpSpace; + elesfn$4.visible = cachePrototypeStyleFunction('visible', defineDerivedStateFunction({ + ok: eleVisible, + edgeOkViaNode: edgeVisibleViaNode + })); + elesfn$4.hidden = function () { + var ele = this[0]; + if (ele) { + return !ele.visible(); + } + }; + elesfn$4.isBundledBezier = cachePrototypeStyleFunction('isBundledBezier', function () { + if (!this.cy().styleEnabled()) { + return false; + } + return !this.removed() && this.pstyle('curve-style').value === 'bezier' && this.takesUpSpace(); + }); + elesfn$4.bypass = elesfn$4.css = elesfn$4.style; + elesfn$4.renderedCss = elesfn$4.renderedStyle; + elesfn$4.removeBypass = elesfn$4.removeCss = elesfn$4.removeStyle; + elesfn$4.pstyle = elesfn$4.parsedStyle; + + var elesfn$3 = {}; + function defineSwitchFunction(params) { + return function () { + var args = arguments; + var changedEles = []; + + // e.g. cy.nodes().select( data, handler ) + if (args.length === 2) { + var data = args[0]; + var handler = args[1]; + this.on(params.event, data, handler); + } - this.set( - sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, - - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, - 0, 0, 1 - ); + // e.g. cy.nodes().select( handler ) + else if (args.length === 1 && fn$6(args[0])) { + var _handler = args[0]; + this.on(params.event, _handler); + } - return this; + // e.g. cy.nodes().select() + // e.g. (private) cy.nodes().select(['tapselect']) + else if (args.length === 0 || args.length === 1 && array(args[0])) { + var addlEvents = args.length === 1 ? args[0] : null; + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var able = !params.ableField || ele._private[params.ableField]; + var changed = ele._private[params.field] != params.value; + if (params.overrideAble) { + var overrideAble = params.overrideAble(ele); + if (overrideAble !== undefined) { + able = overrideAble; + if (!overrideAble) { + return this; + } // to save cycles assume not able for all on override + } + } - } + if (able) { + ele._private[params.field] = params.value; + if (changed) { + changedEles.push(ele); + } + } + } + var changedColl = this.spawn(changedEles); + changedColl.updateStyle(); // change of state => possible change of style + changedColl.emit(params.event); + if (addlEvents) { + changedColl.emit(addlEvents); + } + } + return this; + }; + } + function defineSwitchSet(params) { + elesfn$3[params.field] = function () { + var ele = this[0]; + if (ele) { + if (params.overrideField) { + var val = params.overrideField(ele); + if (val !== undefined) { + return val; + } + } + return ele._private[params.field]; + } + }; + elesfn$3[params.on] = defineSwitchFunction({ + event: params.on, + field: params.field, + ableField: params.ableField, + overrideAble: params.overrideAble, + value: true + }); + elesfn$3[params.off] = defineSwitchFunction({ + event: params.off, + field: params.field, + ableField: params.ableField, + overrideAble: params.overrideAble, + value: false + }); + } + defineSwitchSet({ + field: 'locked', + overrideField: function overrideField(ele) { + return ele.cy().autolock() ? true : undefined; + }, + on: 'lock', + off: 'unlock' + }); + defineSwitchSet({ + field: 'grabbable', + overrideField: function overrideField(ele) { + return ele.cy().autoungrabify() || ele.pannable() ? false : undefined; + }, + on: 'grabify', + off: 'ungrabify' + }); + defineSwitchSet({ + field: 'selected', + ableField: 'selectable', + overrideAble: function overrideAble(ele) { + return ele.cy().autounselectify() ? false : undefined; + }, + on: 'select', + off: 'unselect' + }); + defineSwitchSet({ + field: 'selectable', + overrideField: function overrideField(ele) { + return ele.cy().autounselectify() ? false : undefined; + }, + on: 'selectify', + off: 'unselectify' + }); + elesfn$3.deselect = elesfn$3.unselect; + elesfn$3.grabbed = function () { + var ele = this[0]; + if (ele) { + return ele._private.grabbed; + } + }; + defineSwitchSet({ + field: 'active', + on: 'activate', + off: 'unactivate' + }); + defineSwitchSet({ + field: 'pannable', + on: 'panify', + off: 'unpanify' + }); + elesfn$3.inactive = function () { + var ele = this[0]; + if (ele) { + return !ele._private.active; + } + }; - scale( sx, sy ) { + var elesfn$2 = {}; + + // DAG functions + //////////////// + + var defineDagExtremity = function defineDagExtremity(params) { + return function dagExtremityImpl(selector) { + var eles = this; + var ret = []; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + if (!ele.isNode()) { + continue; + } + var disqualified = false; + var edges = ele.connectedEdges(); + for (var j = 0; j < edges.length; j++) { + var edge = edges[j]; + var src = edge.source(); + var tgt = edge.target(); + if (params.noIncomingEdges && tgt === ele && src !== ele || params.noOutgoingEdges && src === ele && tgt !== ele) { + disqualified = true; + break; + } + } + if (!disqualified) { + ret.push(ele); + } + } + return this.spawn(ret, true).filter(selector); + }; + }; + var defineDagOneHop = function defineDagOneHop(params) { + return function (selector) { + var eles = this; + var oEles = []; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + if (!ele.isNode()) { + continue; + } + var edges = ele.connectedEdges(); + for (var j = 0; j < edges.length; j++) { + var edge = edges[j]; + var src = edge.source(); + var tgt = edge.target(); + if (params.outgoing && src === ele) { + oEles.push(edge); + oEles.push(tgt); + } else if (params.incoming && tgt === ele) { + oEles.push(edge); + oEles.push(src); + } + } + } + return this.spawn(oEles, true).filter(selector); + }; + }; + var defineDagAllHops = function defineDagAllHops(params) { + return function (selector) { + var eles = this; + var sEles = []; + var sElesIds = {}; + for (;;) { + var next = params.outgoing ? eles.outgoers() : eles.incomers(); + if (next.length === 0) { + break; + } // done if none left + + var newNext = false; + for (var i = 0; i < next.length; i++) { + var n = next[i]; + var nid = n.id(); + if (!sElesIds[nid]) { + sElesIds[nid] = true; + sEles.push(n); + newNext = true; + } + } + if (!newNext) { + break; + } // done if touched all outgoers already - const te = this.elements; + eles = next; + } + return this.spawn(sEles, true).filter(selector); + }; + }; + elesfn$2.clearTraversalCache = function () { + for (var i = 0; i < this.length; i++) { + this[i]._private.traversalCache = null; + } + }; + extend$1(elesfn$2, { + // get the root nodes in the DAG + roots: defineDagExtremity({ + noIncomingEdges: true + }), + // get the leaf nodes in the DAG + leaves: defineDagExtremity({ + noOutgoingEdges: true + }), + // normally called children in graph theory + // these nodes =edges=> outgoing nodes + outgoers: cache(defineDagOneHop({ + outgoing: true + }), 'outgoers'), + // aka DAG descendants + successors: defineDagAllHops({ + outgoing: true + }), + // normally called parents in graph theory + // these nodes <=edges= incoming nodes + incomers: cache(defineDagOneHop({ + incoming: true + }), 'incomers'), + // aka DAG ancestors + predecessors: defineDagAllHops({ + incoming: true + }) + }); - te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx; - te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy; + // Neighbourhood functions + ////////////////////////// + + extend$1(elesfn$2, { + neighborhood: cache(function (selector) { + var elements = []; + var nodes = this.nodes(); + for (var i = 0; i < nodes.length; i++) { + // for all nodes + var node = nodes[i]; + var connectedEdges = node.connectedEdges(); + + // for each connected edge, add the edge and the other node + for (var j = 0; j < connectedEdges.length; j++) { + var edge = connectedEdges[j]; + var src = edge.source(); + var tgt = edge.target(); + var otherNode = node === src ? tgt : src; + + // need check in case of loop + if (otherNode.length > 0) { + elements.push(otherNode[0]); // add node 1 hop away + } - return this; + // add connected edge + elements.push(edge[0]); + } + } + return this.spawn(elements, true).filter(selector); + }, 'neighborhood'), + closedNeighborhood: function closedNeighborhood(selector) { + return this.neighborhood().add(this).filter(selector); + }, + openNeighborhood: function openNeighborhood(selector) { + return this.neighborhood(selector); + } + }); - } + // aliases + elesfn$2.neighbourhood = elesfn$2.neighborhood; + elesfn$2.closedNeighbourhood = elesfn$2.closedNeighborhood; + elesfn$2.openNeighbourhood = elesfn$2.openNeighborhood; - rotate( theta ) { + // Edge functions + ///////////////// - const c = Math.cos( theta ); - const s = Math.sin( theta ); + extend$1(elesfn$2, { + source: cache(function sourceImpl(selector) { + var ele = this[0]; + var src; + if (ele) { + src = ele._private.source || ele.cy().collection(); + } + return src && selector ? src.filter(selector) : src; + }, 'source'), + target: cache(function targetImpl(selector) { + var ele = this[0]; + var tgt; + if (ele) { + tgt = ele._private.target || ele.cy().collection(); + } + return tgt && selector ? tgt.filter(selector) : tgt; + }, 'target'), + sources: defineSourceFunction({ + attr: 'source' + }), + targets: defineSourceFunction({ + attr: 'target' + }) + }); + function defineSourceFunction(params) { + return function sourceImpl(selector) { + var sources = []; + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var src = ele._private[params.attr]; + if (src) { + sources.push(src); + } + } + return this.spawn(sources, true).filter(selector); + }; + } + extend$1(elesfn$2, { + edgesWith: cache(defineEdgesWithFunction(), 'edgesWith'), + edgesTo: cache(defineEdgesWithFunction({ + thisIsSrc: true + }), 'edgesTo') + }); + function defineEdgesWithFunction(params) { + return function edgesWithImpl(otherNodes) { + var elements = []; + var cy = this._private.cy; + var p = params || {}; + + // get elements if a selector is specified + if (string(otherNodes)) { + otherNodes = cy.$(otherNodes); + } + for (var h = 0; h < otherNodes.length; h++) { + var edges = otherNodes[h]._private.edges; + for (var i = 0; i < edges.length; i++) { + var edge = edges[i]; + var edgeData = edge._private.data; + var thisToOther = this.hasElementWithId(edgeData.source) && otherNodes.hasElementWithId(edgeData.target); + var otherToThis = otherNodes.hasElementWithId(edgeData.source) && this.hasElementWithId(edgeData.target); + var edgeConnectsThisAndOther = thisToOther || otherToThis; + if (!edgeConnectsThisAndOther) { + continue; + } + if (p.thisIsSrc || p.thisIsTgt) { + if (p.thisIsSrc && !thisToOther) { + continue; + } + if (p.thisIsTgt && !otherToThis) { + continue; + } + } + elements.push(edge); + } + } + return this.spawn(elements, true); + }; + } + extend$1(elesfn$2, { + connectedEdges: cache(function (selector) { + var retEles = []; + var eles = this; + for (var i = 0; i < eles.length; i++) { + var node = eles[i]; + if (!node.isNode()) { + continue; + } + var edges = node._private.edges; + for (var j = 0; j < edges.length; j++) { + var edge = edges[j]; + retEles.push(edge); + } + } + return this.spawn(retEles, true).filter(selector); + }, 'connectedEdges'), + connectedNodes: cache(function (selector) { + var retEles = []; + var eles = this; + for (var i = 0; i < eles.length; i++) { + var edge = eles[i]; + if (!edge.isEdge()) { + continue; + } + retEles.push(edge.source()[0]); + retEles.push(edge.target()[0]); + } + return this.spawn(retEles, true).filter(selector); + }, 'connectedNodes'), + parallelEdges: cache(defineParallelEdgesFunction(), 'parallelEdges'), + codirectedEdges: cache(defineParallelEdgesFunction({ + codirected: true + }), 'codirectedEdges') + }); + function defineParallelEdgesFunction(params) { + var defaults = { + codirected: false + }; + params = extend$1({}, defaults, params); + return function parallelEdgesImpl(selector) { + // micro-optimised for renderer + var elements = []; + var edges = this.edges(); + var p = params; + + // look at all the edges in the collection + for (var i = 0; i < edges.length; i++) { + var edge1 = edges[i]; + var edge1_p = edge1._private; + var src1 = edge1_p.source; + var srcid1 = src1._private.data.id; + var tgtid1 = edge1_p.data.target; + var srcEdges1 = src1._private.edges; + + // look at edges connected to the src node of this edge + for (var j = 0; j < srcEdges1.length; j++) { + var edge2 = srcEdges1[j]; + var edge2data = edge2._private.data; + var tgtid2 = edge2data.target; + var srcid2 = edge2data.source; + var codirected = tgtid2 === tgtid1 && srcid2 === srcid1; + var oppdirected = srcid1 === tgtid2 && tgtid1 === srcid2; + if (p.codirected && codirected || !p.codirected && (codirected || oppdirected)) { + elements.push(edge2); + } + } + } + return this.spawn(elements, true).filter(selector); + }; + } + + // Misc functions + ///////////////// + + extend$1(elesfn$2, { + components: function components(root) { + var self = this; + var cy = self.cy(); + var visited = cy.collection(); + var unvisited = root == null ? self.nodes() : root.nodes(); + var components = []; + if (root != null && unvisited.empty()) { + // root may contain only edges + unvisited = root.sources(); // doesn't matter which node to use (undirected), so just use the source sides + } - const te = this.elements; + var visitInComponent = function visitInComponent(node, component) { + visited.merge(node); + unvisited.unmerge(node); + component.merge(node); + }; + if (unvisited.empty()) { + return self.spawn(); + } + var _loop = function _loop() { + // each iteration yields a component + var cmpt = cy.collection(); + components.push(cmpt); + var root = unvisited[0]; + visitInComponent(root, cmpt); + self.bfs({ + directed: false, + roots: root, + visit: function visit(v) { + return visitInComponent(v, cmpt); + } + }); + cmpt.forEach(function (node) { + node.connectedEdges().forEach(function (e) { + // connectedEdges() usually cached + if (self.has(e) && cmpt.has(e.source()) && cmpt.has(e.target())) { + // has() is cheap + cmpt.merge(e); // forEach() only considers nodes -- sets N at call time + } + }); + }); + }; + do { + _loop(); + } while (unvisited.length > 0); + return components; + }, + component: function component() { + var ele = this[0]; + return ele.cy().mutableElements().components(ele)[0]; + } + }); + elesfn$2.componentsOf = elesfn$2.components; + + // represents a set of nodes, edges, or both together + var Collection = function Collection(cy, elements) { + var unique = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + var removed = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + if (cy === undefined) { + error('A collection must have a reference to the core'); + return; + } + var map = new Map$2(); + var createdElements = false; + if (!elements) { + elements = []; + } else if (elements.length > 0 && plainObject(elements[0]) && !element(elements[0])) { + createdElements = true; + + // make elements from json and restore all at once later + var eles = []; + var elesIds = new Set$1(); + for (var i = 0, l = elements.length; i < l; i++) { + var json = elements[i]; + if (json.data == null) { + json.data = {}; + } + var _data = json.data; + + // make sure newly created elements have valid ids + if (_data.id == null) { + _data.id = uuid(); + } else if (cy.hasElementWithId(_data.id) || elesIds.has(_data.id)) { + continue; // can't create element if prior id already exists + } + + var ele = new Element(cy, json, false); + eles.push(ele); + elesIds.add(_data.id); + } + elements = eles; + } + this.length = 0; + for (var _i = 0, _l = elements.length; _i < _l; _i++) { + var element$1 = elements[_i][0]; // [0] in case elements is an array of collections, rather than array of elements + if (element$1 == null) { + continue; + } + var id = element$1._private.data.id; + if (!unique || !map.has(id)) { + if (unique) { + map.set(id, { + index: this.length, + ele: element$1 + }); + } + this[this.length] = element$1; + this.length++; + } + } + this._private = { + eles: this, + cy: cy, + get map() { + if (this.lazyMap == null) { + this.rebuildMap(); + } + return this.lazyMap; + }, + set map(m) { + this.lazyMap = m; + }, + rebuildMap: function rebuildMap() { + var m = this.lazyMap = new Map$2(); + var eles = this.eles; + for (var _i2 = 0; _i2 < eles.length; _i2++) { + var _ele = eles[_i2]; + m.set(_ele.id(), { + index: _i2, + ele: _ele + }); + } + } + }; + if (unique) { + this._private.map = map; + } - const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ]; - const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ]; + // restore the elements if we created them from json + if (createdElements && !removed) { + this.restore(); + } + }; - te[ 0 ] = c * a11 + s * a21; - te[ 3 ] = c * a12 + s * a22; - te[ 6 ] = c * a13 + s * a23; + // Functions + //////////////////////////////////////////////////////////////////////////////////////////////////// - te[ 1 ] = - s * a11 + c * a21; - te[ 4 ] = - s * a12 + c * a22; - te[ 7 ] = - s * a13 + c * a23; + // keep the prototypes in sync (an element has the same functions as a collection) + // and use elefn and elesfn as shorthands to the prototypes + var elesfn$1 = Element.prototype = Collection.prototype = Object.create(Array.prototype); + elesfn$1.instanceString = function () { + return 'collection'; + }; + elesfn$1.spawn = function (eles, unique) { + return new Collection(this.cy(), eles, unique); + }; + elesfn$1.spawnSelf = function () { + return this.spawn(this); + }; + elesfn$1.cy = function () { + return this._private.cy; + }; + elesfn$1.renderer = function () { + return this._private.cy.renderer(); + }; + elesfn$1.element = function () { + return this[0]; + }; + elesfn$1.collection = function () { + if (collection(this)) { + return this; + } else { + // an element + return new Collection(this._private.cy, [this]); + } + }; + elesfn$1.unique = function () { + return new Collection(this._private.cy, this, true); + }; + elesfn$1.hasElementWithId = function (id) { + id = '' + id; // id must be string - return this; + return this._private.map.has(id); + }; + elesfn$1.getElementById = function (id) { + id = '' + id; // id must be string - } + var cy = this._private.cy; + var entry = this._private.map.get(id); + return entry ? entry.ele : new Collection(cy); // get ele or empty collection + }; - translate( tx, ty ) { + elesfn$1.$id = elesfn$1.getElementById; + elesfn$1.poolIndex = function () { + var cy = this._private.cy; + var eles = cy._private.elements; + var id = this[0]._private.data.id; + return eles._private.map.get(id).index; + }; + elesfn$1.indexOf = function (ele) { + var id = ele[0]._private.data.id; + return this._private.map.get(id).index; + }; + elesfn$1.indexOfId = function (id) { + id = '' + id; // id must be string - const te = this.elements; + return this._private.map.get(id).index; + }; + elesfn$1.json = function (obj) { + var ele = this.element(); + var cy = this.cy(); + if (ele == null && obj) { + return this; + } // can't set to no eles + + if (ele == null) { + return undefined; + } // can't get from no eles + + var p = ele._private; + if (plainObject(obj)) { + // set + + cy.startBatch(); + if (obj.data) { + ele.data(obj.data); + var _data2 = p.data; + if (ele.isEdge()) { + // source and target are immutable via data() + var move = false; + var spec = {}; + var src = obj.data.source; + var tgt = obj.data.target; + if (src != null && src != _data2.source) { + spec.source = '' + src; // id must be string + move = true; + } + if (tgt != null && tgt != _data2.target) { + spec.target = '' + tgt; // id must be string + move = true; + } + if (move) { + ele = ele.move(spec); + } + } else { + // parent is immutable via data() + var newParentValSpecd = ('parent' in obj.data); + var parent = obj.data.parent; + if (newParentValSpecd && (parent != null || _data2.parent != null) && parent != _data2.parent) { + if (parent === undefined) { + // can't set undefined imperatively, so use null + parent = null; + } + if (parent != null) { + parent = '' + parent; // id must be string + } + + ele = ele.move({ + parent: parent + }); + } + } + } + if (obj.position) { + ele.position(obj.position); + } - te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ]; - te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ]; + // ignore group -- immutable - return this; + var checkSwitch = function checkSwitch(k, trueFnName, falseFnName) { + var obj_k = obj[k]; + if (obj_k != null && obj_k !== p[k]) { + if (obj_k) { + ele[trueFnName](); + } else { + ele[falseFnName](); + } + } + }; + checkSwitch('removed', 'remove', 'restore'); + checkSwitch('selected', 'select', 'unselect'); + checkSwitch('selectable', 'selectify', 'unselectify'); + checkSwitch('locked', 'lock', 'unlock'); + checkSwitch('grabbable', 'grabify', 'ungrabify'); + checkSwitch('pannable', 'panify', 'unpanify'); + if (obj.classes != null) { + ele.classes(obj.classes); + } + cy.endBatch(); + return this; + } else if (obj === undefined) { + // get + + var json = { + data: copy(p.data), + position: copy(p.position), + group: p.group, + removed: p.removed, + selected: p.selected, + selectable: p.selectable, + locked: p.locked, + grabbable: p.grabbable, + pannable: p.pannable, + classes: null + }; + json.classes = ''; + var i = 0; + p.classes.forEach(function (cls) { + return json.classes += i++ === 0 ? cls : ' ' + cls; + }); + return json; + } + }; + elesfn$1.jsons = function () { + var jsons = []; + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var json = ele.json(); + jsons.push(json); + } + return jsons; + }; + elesfn$1.clone = function () { + var cy = this.cy(); + var elesArr = []; + for (var i = 0; i < this.length; i++) { + var ele = this[i]; + var json = ele.json(); + var clone = new Element(cy, json, false); // NB no restore + + elesArr.push(clone); + } + return new Collection(cy, elesArr); + }; + elesfn$1.copy = elesfn$1.clone; + elesfn$1.restore = function () { + var notifyRenderer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + var addToPool = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var self = this; + var cy = self.cy(); + var cy_p = cy._private; + + // create arrays of nodes and edges, since we need to + // restore the nodes first + var nodes = []; + var edges = []; + var elements; + for (var _i3 = 0, l = self.length; _i3 < l; _i3++) { + var ele = self[_i3]; + if (addToPool && !ele.removed()) { + // don't need to handle this ele + continue; + } - } + // keep nodes first in the array and edges after + if (ele.isNode()) { + // put to front of array if node + nodes.push(ele); + } else { + // put to end of array if edge + edges.push(ele); + } + } + elements = nodes.concat(edges); + var i; + var removeFromElements = function removeFromElements() { + elements.splice(i, 1); + i--; + }; + + // now, restore each element + for (i = 0; i < elements.length; i++) { + var _ele2 = elements[i]; + var _private = _ele2._private; + var _data3 = _private.data; + + // the traversal cache should start fresh when ele is added + _ele2.clearTraversalCache(); + + // set id and validate + if (!addToPool && !_private.removed) ; else if (_data3.id === undefined) { + _data3.id = uuid(); + } else if (number$1(_data3.id)) { + _data3.id = '' + _data3.id; // now it's a string + } else if (emptyString(_data3.id) || !string(_data3.id)) { + error('Can not create element with invalid string ID `' + _data3.id + '`'); + + // can't create element if it has empty string as id or non-string id + removeFromElements(); + continue; + } else if (cy.hasElementWithId(_data3.id)) { + error('Can not create second element with ID `' + _data3.id + '`'); + + // can't create element if one already has that id + removeFromElements(); + continue; + } + var id = _data3.id; // id is finalised, now let's keep a ref - equals( matrix ) { + if (_ele2.isNode()) { + // extra checks for nodes + var pos = _private.position; - const te = this.elements; - const me = matrix.elements; + // make sure the nodes have a defined position - for ( let i = 0; i < 9; i ++ ) { + if (pos.x == null) { + pos.x = 0; + } + if (pos.y == null) { + pos.y = 0; + } + } + if (_ele2.isEdge()) { + // extra checks for edges + + var edge = _ele2; + var fields = ['source', 'target']; + var fieldsLength = fields.length; + var badSourceOrTarget = false; + for (var j = 0; j < fieldsLength; j++) { + var field = fields[j]; + var val = _data3[field]; + if (number$1(val)) { + val = _data3[field] = '' + _data3[field]; // now string + } - if ( te[ i ] !== me[ i ] ) return false; + if (val == null || val === '') { + // can't create if source or target is not defined properly + error('Can not create edge `' + id + '` with unspecified ' + field); + badSourceOrTarget = true; + } else if (!cy.hasElementWithId(val)) { + // can't create edge if one of its nodes doesn't exist + error('Can not create edge `' + id + '` with nonexistant ' + field + ' `' + val + '`'); + badSourceOrTarget = true; + } + } + if (badSourceOrTarget) { + removeFromElements(); + continue; + } // can't create this + + var src = cy.getElementById(_data3.source); + var tgt = cy.getElementById(_data3.target); + + // only one edge in node if loop + if (src.same(tgt)) { + src._private.edges.push(edge); + } else { + src._private.edges.push(edge); + tgt._private.edges.push(edge); + } + edge._private.source = src; + edge._private.target = tgt; + } // if is edge + + // create mock ids / indexes maps for element so it can be used like collections + _private.map = new Map$2(); + _private.map.set(id, { + ele: _ele2, + index: 0 + }); + _private.removed = false; + if (addToPool) { + cy.addToPool(_ele2); + } + } // for each element + + // do compound node sanity checks + for (var _i4 = 0; _i4 < nodes.length; _i4++) { + // each node + var node = nodes[_i4]; + var _data4 = node._private.data; + if (number$1(_data4.parent)) { + // then automake string + _data4.parent = '' + _data4.parent; + } + var parentId = _data4.parent; + var specifiedParent = parentId != null; + if (specifiedParent || node._private.parent) { + var parent = node._private.parent ? cy.collection().merge(node._private.parent) : cy.getElementById(parentId); + if (parent.empty()) { + // non-existant parent; just remove it + _data4.parent = undefined; + } else if (parent[0].removed()) { + warn('Node added with missing parent, reference to parent removed'); + _data4.parent = undefined; + node._private.parent = null; + } else { + var selfAsParent = false; + var ancestor = parent; + while (!ancestor.empty()) { + if (node.same(ancestor)) { + // mark self as parent and remove from data + selfAsParent = true; + _data4.parent = undefined; // remove parent reference + + // exit or we loop forever + break; + } + ancestor = ancestor.parent(); + } + if (!selfAsParent) { + // connect with children + parent[0]._private.children.push(node); + node._private.parent = parent[0]; - } + // let the core know we have a compound graph + cy_p.hasCompoundNodes = true; + } + } // else + } // if specified parent + } // for each node + + if (elements.length > 0) { + var restored = elements.length === self.length ? self : new Collection(cy, elements); + for (var _i5 = 0; _i5 < restored.length; _i5++) { + var _ele3 = restored[_i5]; + if (_ele3.isNode()) { + continue; + } + + // adding an edge invalidates the traversal caches for the parallel edges + _ele3.parallelEdges().clearTraversalCache(); + + // adding an edge invalidates the traversal cache for the connected nodes + _ele3.source().clearTraversalCache(); + _ele3.target().clearTraversalCache(); + } + var toUpdateStyle; + if (cy_p.hasCompoundNodes) { + toUpdateStyle = cy.collection().merge(restored).merge(restored.connectedNodes()).merge(restored.parent()); + } else { + toUpdateStyle = restored; + } + toUpdateStyle.dirtyCompoundBoundsCache().dirtyBoundingBoxCache().updateStyle(notifyRenderer); + if (notifyRenderer) { + restored.emitAndNotify('add'); + } else if (addToPool) { + restored.emit('add'); + } + } + return self; // chainability + }; - return true; + elesfn$1.removed = function () { + var ele = this[0]; + return ele && ele._private.removed; + }; + elesfn$1.inside = function () { + var ele = this[0]; + return ele && !ele._private.removed; + }; + elesfn$1.remove = function () { + var notifyRenderer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + var removeFromPool = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var self = this; + var elesToRemove = []; + var elesToRemoveIds = {}; + var cy = self._private.cy; + + // add connected edges + function addConnectedEdges(node) { + var edges = node._private.edges; + for (var i = 0; i < edges.length; i++) { + add(edges[i]); + } + } - } + // add descendant nodes + function addChildren(node) { + var children = node._private.children; + for (var i = 0; i < children.length; i++) { + add(children[i]); + } + } + function add(ele) { + var alreadyAdded = elesToRemoveIds[ele.id()]; + if (removeFromPool && ele.removed() || alreadyAdded) { + return; + } else { + elesToRemoveIds[ele.id()] = true; + } + if (ele.isNode()) { + elesToRemove.push(ele); // nodes are removed last - fromArray( array, offset = 0 ) { + addConnectedEdges(ele); + addChildren(ele); + } else { + elesToRemove.unshift(ele); // edges are removed first + } + } - for ( let i = 0; i < 9; i ++ ) { + // make the list of elements to remove + // (may be removing more than specified due to connected edges etc) - this.elements[ i ] = array[ i + offset ]; + for (var i = 0, l = self.length; i < l; i++) { + var ele = self[i]; + add(ele); + } + function removeEdgeRef(node, edge) { + var connectedEdges = node._private.edges; + removeFromArray(connectedEdges, edge); - } + // removing an edges invalidates the traversal cache for its nodes + node.clearTraversalCache(); + } + function removeParallelRef(pllEdge) { + // removing an edge invalidates the traversal caches for the parallel edges + pllEdge.clearTraversalCache(); + } + var alteredParents = []; + alteredParents.ids = {}; + function removeChildRef(parent, ele) { + ele = ele[0]; + parent = parent[0]; + var children = parent._private.children; + var pid = parent.id(); + removeFromArray(children, ele); // remove parent => child ref + + ele._private.parent = null; // remove child => parent ref + + if (!alteredParents.ids[pid]) { + alteredParents.ids[pid] = true; + alteredParents.push(parent); + } + } + self.dirtyCompoundBoundsCache(); + if (removeFromPool) { + cy.removeFromPool(elesToRemove); // remove from core pool + } - return this; + for (var _i6 = 0; _i6 < elesToRemove.length; _i6++) { + var _ele4 = elesToRemove[_i6]; + if (_ele4.isEdge()) { + // remove references to this edge in its connected nodes + var src = _ele4.source()[0]; + var tgt = _ele4.target()[0]; + removeEdgeRef(src, _ele4); + removeEdgeRef(tgt, _ele4); + var pllEdges = _ele4.parallelEdges(); + for (var j = 0; j < pllEdges.length; j++) { + var pllEdge = pllEdges[j]; + removeParallelRef(pllEdge); + if (pllEdge.isBundledBezier()) { + pllEdge.dirtyBoundingBoxCache(); + } + } + } else { + // remove reference to parent + var parent = _ele4.parent(); + if (parent.length !== 0) { + removeChildRef(parent, _ele4); + } + } + if (removeFromPool) { + // mark as removed + _ele4._private.removed = true; + } + } - } + // check to see if we have a compound graph or not + var elesStillInside = cy._private.elements; + cy._private.hasCompoundNodes = false; + for (var _i7 = 0; _i7 < elesStillInside.length; _i7++) { + var _ele5 = elesStillInside[_i7]; + if (_ele5.isParent()) { + cy._private.hasCompoundNodes = true; + break; + } + } + var removedElements = new Collection(this.cy(), elesToRemove); + if (removedElements.size() > 0) { + // must manually notify since trigger won't do this automatically once removed + + if (notifyRenderer) { + removedElements.emitAndNotify('remove'); + } else if (removeFromPool) { + removedElements.emit('remove'); + } + } - toArray( array = [], offset = 0 ) { + // the parents who were modified by the removal need their style updated + for (var _i8 = 0; _i8 < alteredParents.length; _i8++) { + var _ele6 = alteredParents[_i8]; + if (!removeFromPool || !_ele6.removed()) { + _ele6.updateStyle(); + } + } + return removedElements; + }; + elesfn$1.move = function (struct) { + var cy = this._private.cy; + var eles = this; + + // just clean up refs, caches, etc. in the same way as when removing and then restoring + // (our calls to remove/restore do not remove from the graph or make events) + var notifyRenderer = false; + var modifyPool = false; + var toString = function toString(id) { + return id == null ? id : '' + id; + }; // id must be string + + if (struct.source !== undefined || struct.target !== undefined) { + var srcId = toString(struct.source); + var tgtId = toString(struct.target); + var srcExists = srcId != null && cy.hasElementWithId(srcId); + var tgtExists = tgtId != null && cy.hasElementWithId(tgtId); + if (srcExists || tgtExists) { + cy.batch(function () { + // avoid duplicate style updates + eles.remove(notifyRenderer, modifyPool); // clean up refs etc. + eles.emitAndNotify('moveout'); + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var _data5 = ele._private.data; + if (ele.isEdge()) { + if (srcExists) { + _data5.source = srcId; + } + if (tgtExists) { + _data5.target = tgtId; + } + } + } + eles.restore(notifyRenderer, modifyPool); // make new refs, style, etc. + }); - const te = this.elements; + eles.emitAndNotify('move'); + } + } else if (struct.parent !== undefined) { + // move node to new parent + var parentId = toString(struct.parent); + var parentExists = parentId === null || cy.hasElementWithId(parentId); + if (parentExists) { + var pidToAssign = parentId === null ? undefined : parentId; + cy.batch(function () { + // avoid duplicate style updates + var updated = eles.remove(notifyRenderer, modifyPool); // clean up refs etc. + updated.emitAndNotify('moveout'); + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var _data6 = ele._private.data; + if (ele.isNode()) { + _data6.parent = pidToAssign; + } + } + updated.restore(notifyRenderer, modifyPool); // make new refs, style, etc. + }); - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; + eles.emitAndNotify('move'); + } + } + return this; + }; + [elesfn$j, elesfn$i, elesfn$h, elesfn$g, elesfn$f, data, elesfn$d, dimensions, elesfn$9, elesfn$8, elesfn$7, elesfn$6, elesfn$5, elesfn$4, elesfn$3, elesfn$2].forEach(function (props) { + extend$1(elesfn$1, props); + }); - array[ offset + 3 ] = te[ 3 ]; - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; + var corefn$9 = { + add: function add(opts) { + var elements; + var cy = this; + + // add the elements + if (elementOrCollection(opts)) { + var eles = opts; + if (eles._private.cy === cy) { + // same instance => just restore + elements = eles.restore(); + } else { + // otherwise, copy from json + var jsons = []; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + jsons.push(ele.json()); + } + elements = new Collection(cy, jsons); + } + } - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; + // specify an array of options + else if (array(opts)) { + var _jsons = opts; + elements = new Collection(cy, _jsons); + } - return array; + // specify via opts.nodes and opts.edges + else if (plainObject(opts) && (array(opts.nodes) || array(opts.edges))) { + var elesByGroup = opts; + var _jsons2 = []; + var grs = ['nodes', 'edges']; + for (var _i = 0, il = grs.length; _i < il; _i++) { + var group = grs[_i]; + var elesArray = elesByGroup[group]; + if (array(elesArray)) { + for (var j = 0, jl = elesArray.length; j < jl; j++) { + var json = extend$1({ + group: group + }, elesArray[j]); + _jsons2.push(json); + } + } + } + elements = new Collection(cy, _jsons2); + } - } + // specify options for one element + else { + var _json = opts; + elements = new Element(cy, _json).collection(); + } + return elements; + }, + remove: function remove(collection) { + if (elementOrCollection(collection)) ; else if (string(collection)) { + var selector = collection; + collection = this.$(selector); + } + return collection.remove(); + } + }; - clone() { + /* global Float32Array */ + + /*! Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */ + function generateCubicBezier(mX1, mY1, mX2, mY2) { + var NEWTON_ITERATIONS = 4, + NEWTON_MIN_SLOPE = 0.001, + SUBDIVISION_PRECISION = 0.0000001, + SUBDIVISION_MAX_ITERATIONS = 10, + kSplineTableSize = 11, + kSampleStepSize = 1.0 / (kSplineTableSize - 1.0), + float32ArraySupported = typeof Float32Array !== 'undefined'; + + /* Must contain four arguments. */ + if (arguments.length !== 4) { + return false; + } - return new this.constructor().fromArray( this.elements ); + /* Arguments must be numbers. */ + for (var i = 0; i < 4; ++i) { + if (typeof arguments[i] !== "number" || isNaN(arguments[i]) || !isFinite(arguments[i])) { + return false; + } + } - } - - } - - function arrayNeedsUint32( array ) { - - // assumes larger values usually on last + /* X values must be in the [0, 1] range. */ + mX1 = Math.min(mX1, 1); + mX2 = Math.min(mX2, 1); + mX1 = Math.max(mX1, 0); + mX2 = Math.max(mX2, 0); + var mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); + function A(aA1, aA2) { + return 1.0 - 3.0 * aA2 + 3.0 * aA1; + } + function B(aA1, aA2) { + return 3.0 * aA2 - 6.0 * aA1; + } + function C(aA1) { + return 3.0 * aA1; + } + function calcBezier(aT, aA1, aA2) { + return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; + } + function getSlope(aT, aA1, aA2) { + return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); + } + function newtonRaphsonIterate(aX, aGuessT) { + for (var _i = 0; _i < NEWTON_ITERATIONS; ++_i) { + var currentSlope = getSlope(aGuessT, mX1, mX2); + if (currentSlope === 0.0) { + return aGuessT; + } + var currentX = calcBezier(aGuessT, mX1, mX2) - aX; + aGuessT -= currentX / currentSlope; + } + return aGuessT; + } + function calcSampleValues() { + for (var _i2 = 0; _i2 < kSplineTableSize; ++_i2) { + mSampleValues[_i2] = calcBezier(_i2 * kSampleStepSize, mX1, mX2); + } + } + function binarySubdivide(aX, aA, aB) { + var currentX, + currentT, + i = 0; + do { + currentT = aA + (aB - aA) / 2.0; + currentX = calcBezier(currentT, mX1, mX2) - aX; + if (currentX > 0.0) { + aB = currentT; + } else { + aA = currentT; + } + } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); + return currentT; + } + function getTForX(aX) { + var intervalStart = 0.0, + currentSample = 1, + lastSample = kSplineTableSize - 1; + for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) { + intervalStart += kSampleStepSize; + } + --currentSample; + var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample + 1] - mSampleValues[currentSample]), + guessForT = intervalStart + dist * kSampleStepSize, + initialSlope = getSlope(guessForT, mX1, mX2); + if (initialSlope >= NEWTON_MIN_SLOPE) { + return newtonRaphsonIterate(aX, guessForT); + } else if (initialSlope === 0.0) { + return guessForT; + } else { + return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize); + } + } + var _precomputed = false; + function precompute() { + _precomputed = true; + if (mX1 !== mY1 || mX2 !== mY2) { + calcSampleValues(); + } + } + var f = function f(aX) { + if (!_precomputed) { + precompute(); + } + if (mX1 === mY1 && mX2 === mY2) { + return aX; + } + if (aX === 0) { + return 0; + } + if (aX === 1) { + return 1; + } + return calcBezier(getTForX(aX), mY1, mY2); + }; + f.getControlPoints = function () { + return [{ + x: mX1, + y: mY1 + }, { + x: mX2, + y: mY2 + }]; + }; + var str = "generateBezier(" + [mX1, mY1, mX2, mY2] + ")"; + f.toString = function () { + return str; + }; + return f; + } + + /*! Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */ + /* Given a tension, friction, and duration, a simulation at 60FPS will first run without a defined duration in order to calculate the full path. A second pass + then adjusts the time delta -- using the relation between actual time and duration -- to calculate the path for the duration-constrained animation. */ + var generateSpringRK4 = function () { + function springAccelerationForState(state) { + return -state.tension * state.x - state.friction * state.v; + } + function springEvaluateStateWithDerivative(initialState, dt, derivative) { + var state = { + x: initialState.x + derivative.dx * dt, + v: initialState.v + derivative.dv * dt, + tension: initialState.tension, + friction: initialState.friction + }; + return { + dx: state.v, + dv: springAccelerationForState(state) + }; + } + function springIntegrateState(state, dt) { + var a = { + dx: state.v, + dv: springAccelerationForState(state) + }, + b = springEvaluateStateWithDerivative(state, dt * 0.5, a), + c = springEvaluateStateWithDerivative(state, dt * 0.5, b), + d = springEvaluateStateWithDerivative(state, dt, c), + dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx), + dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv); + state.x = state.x + dxdt * dt; + state.v = state.v + dvdt * dt; + return state; + } + return function springRK4Factory(tension, friction, duration) { + var initState = { + x: -1, + v: 0, + tension: null, + friction: null + }, + path = [0], + time_lapsed = 0, + tolerance = 1 / 10000, + DT = 16 / 1000, + have_duration, + dt, + last_state; + tension = parseFloat(tension) || 500; + friction = parseFloat(friction) || 20; + duration = duration || null; + initState.tension = tension; + initState.friction = friction; + have_duration = duration !== null; + + /* Calculate the actual time it takes for this animation to complete with the provided conditions. */ + if (have_duration) { + /* Run the simulation without a duration. */ + time_lapsed = springRK4Factory(tension, friction); + /* Compute the adjusted time delta. */ + dt = time_lapsed / duration * DT; + } else { + dt = DT; + } + for (;;) { + /* Next/step function .*/ + last_state = springIntegrateState(last_state || initState, dt); + /* Store the position. */ + path.push(1 + last_state.x); + time_lapsed += 16; + /* If the change threshold is reached, break. */ + if (!(Math.abs(last_state.x) > tolerance && Math.abs(last_state.v) > tolerance)) { + break; + } + } - for ( let i = array.length - 1; i >= 0; -- i ) { + /* If duration is not defined, return the actual time required for completing this animation. Otherwise, return a closure that holds the + computed path and returns a snapshot of the position according to a given percentComplete. */ + return !have_duration ? time_lapsed : function (percentComplete) { + return path[percentComplete * (path.length - 1) | 0]; + }; + }; + }(); + + var cubicBezier = function cubicBezier(t1, p1, t2, p2) { + var bezier = generateCubicBezier(t1, p1, t2, p2); + return function (start, end, percent) { + return start + (end - start) * bezier(percent); + }; + }; + var easings = { + 'linear': function linear(start, end, percent) { + return start + (end - start) * percent; + }, + // default easings + 'ease': cubicBezier(0.25, 0.1, 0.25, 1), + 'ease-in': cubicBezier(0.42, 0, 1, 1), + 'ease-out': cubicBezier(0, 0, 0.58, 1), + 'ease-in-out': cubicBezier(0.42, 0, 0.58, 1), + // sine + 'ease-in-sine': cubicBezier(0.47, 0, 0.745, 0.715), + 'ease-out-sine': cubicBezier(0.39, 0.575, 0.565, 1), + 'ease-in-out-sine': cubicBezier(0.445, 0.05, 0.55, 0.95), + // quad + 'ease-in-quad': cubicBezier(0.55, 0.085, 0.68, 0.53), + 'ease-out-quad': cubicBezier(0.25, 0.46, 0.45, 0.94), + 'ease-in-out-quad': cubicBezier(0.455, 0.03, 0.515, 0.955), + // cubic + 'ease-in-cubic': cubicBezier(0.55, 0.055, 0.675, 0.19), + 'ease-out-cubic': cubicBezier(0.215, 0.61, 0.355, 1), + 'ease-in-out-cubic': cubicBezier(0.645, 0.045, 0.355, 1), + // quart + 'ease-in-quart': cubicBezier(0.895, 0.03, 0.685, 0.22), + 'ease-out-quart': cubicBezier(0.165, 0.84, 0.44, 1), + 'ease-in-out-quart': cubicBezier(0.77, 0, 0.175, 1), + // quint + 'ease-in-quint': cubicBezier(0.755, 0.05, 0.855, 0.06), + 'ease-out-quint': cubicBezier(0.23, 1, 0.32, 1), + 'ease-in-out-quint': cubicBezier(0.86, 0, 0.07, 1), + // expo + 'ease-in-expo': cubicBezier(0.95, 0.05, 0.795, 0.035), + 'ease-out-expo': cubicBezier(0.19, 1, 0.22, 1), + 'ease-in-out-expo': cubicBezier(1, 0, 0, 1), + // circ + 'ease-in-circ': cubicBezier(0.6, 0.04, 0.98, 0.335), + 'ease-out-circ': cubicBezier(0.075, 0.82, 0.165, 1), + 'ease-in-out-circ': cubicBezier(0.785, 0.135, 0.15, 0.86), + // user param easings... + + 'spring': function spring(tension, friction, duration) { + if (duration === 0) { + // can't get a spring w/ duration 0 + return easings.linear; // duration 0 => jump to end so impl doesn't matter + } - if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 + var spring = generateSpringRK4(tension, friction, duration); + return function (start, end, percent) { + return start + (end - start) * spring(percent); + }; + }, + 'cubic-bezier': cubicBezier + }; - } + function getEasedValue(type, start, end, percent, easingFn) { + if (percent === 1) { + return end; + } + if (start === end) { + return end; + } + var val = easingFn(start, end, percent); + if (type == null) { + return val; + } + if (type.roundValue || type.color) { + val = Math.round(val); + } + if (type.min !== undefined) { + val = Math.max(val, type.min); + } + if (type.max !== undefined) { + val = Math.min(val, type.max); + } + return val; + } + function getValue(prop, spec) { + if (prop.pfValue != null || prop.value != null) { + if (prop.pfValue != null && (spec == null || spec.type.units !== '%')) { + return prop.pfValue; + } else { + return prop.value; + } + } else { + return prop; + } + } + function ease(startProp, endProp, percent, easingFn, propSpec) { + var type = propSpec != null ? propSpec.type : null; + if (percent < 0) { + percent = 0; + } else if (percent > 1) { + percent = 1; + } + var start = getValue(startProp, propSpec); + var end = getValue(endProp, propSpec); + if (number$1(start) && number$1(end)) { + return getEasedValue(type, start, end, percent, easingFn); + } else if (array(start) && array(end)) { + var easedArr = []; + for (var i = 0; i < end.length; i++) { + var si = start[i]; + var ei = end[i]; + if (si != null && ei != null) { + var val = getEasedValue(type, si, ei, percent, easingFn); + easedArr.push(val); + } else { + easedArr.push(ei); + } + } + return easedArr; + } + return undefined; + } + + function step$1(self, ani, now, isCore) { + var isEles = !isCore; + var _p = self._private; + var ani_p = ani._private; + var pEasing = ani_p.easing; + var startTime = ani_p.startTime; + var cy = isCore ? self : self.cy(); + var style = cy.style(); + if (!ani_p.easingImpl) { + if (pEasing == null) { + // use default + ani_p.easingImpl = easings['linear']; + } else { + // then define w/ name + var easingVals; + if (string(pEasing)) { + var easingProp = style.parse('transition-timing-function', pEasing); + easingVals = easingProp.value; + } else { + // then assume preparsed array + easingVals = pEasing; + } + var name, args; + if (string(easingVals)) { + name = easingVals; + args = []; + } else { + name = easingVals[1]; + args = easingVals.slice(2).map(function (n) { + return +n; + }); + } + if (args.length > 0) { + // create with args + if (name === 'spring') { + args.push(ani_p.duration); // need duration to generate spring + } - return false; + ani_p.easingImpl = easings[name].apply(null, args); + } else { + // static impl by name + ani_p.easingImpl = easings[name]; + } + } + } + var easing = ani_p.easingImpl; + var percent; + if (ani_p.duration === 0) { + percent = 1; + } else { + percent = (now - startTime) / ani_p.duration; + } + if (ani_p.applying) { + percent = ani_p.progress; + } + if (percent < 0) { + percent = 0; + } else if (percent > 1) { + percent = 1; + } + if (ani_p.delay == null) { + // then update + + var startPos = ani_p.startPosition; + var endPos = ani_p.position; + if (endPos && isEles && !self.locked()) { + var newPos = {}; + if (valid(startPos.x, endPos.x)) { + newPos.x = ease(startPos.x, endPos.x, percent, easing); + } + if (valid(startPos.y, endPos.y)) { + newPos.y = ease(startPos.y, endPos.y, percent, easing); + } + self.position(newPos); + } + var startPan = ani_p.startPan; + var endPan = ani_p.pan; + var pan = _p.pan; + var animatingPan = endPan != null && isCore; + if (animatingPan) { + if (valid(startPan.x, endPan.x)) { + pan.x = ease(startPan.x, endPan.x, percent, easing); + } + if (valid(startPan.y, endPan.y)) { + pan.y = ease(startPan.y, endPan.y, percent, easing); + } + self.emit('pan'); + } + var startZoom = ani_p.startZoom; + var endZoom = ani_p.zoom; + var animatingZoom = endZoom != null && isCore; + if (animatingZoom) { + if (valid(startZoom, endZoom)) { + _p.zoom = bound(_p.minZoom, ease(startZoom, endZoom, percent, easing), _p.maxZoom); + } + self.emit('zoom'); + } + if (animatingPan || animatingZoom) { + self.emit('viewport'); + } + var props = ani_p.style; + if (props && props.length > 0 && isEles) { + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + var _name = prop.name; + var end = prop; + var start = ani_p.startStyle[_name]; + var propSpec = style.properties[start.name]; + var easedVal = ease(start, end, percent, easing, propSpec); + style.overrideBypass(self, _name, easedVal); + } // for props + + self.emit('style'); + } // if + } + ani_p.progress = percent; + return percent; } + function valid(start, end) { + if (start == null || end == null) { + return false; + } + if (number$1(start) && number$1(end)) { + return true; + } else if (start && end) { + return true; + } + return false; + } + + function startAnimation(self, ani, now, isCore) { + var ani_p = ani._private; + ani_p.started = true; + ani_p.startTime = now - ani_p.progress * ani_p.duration; + } + + function stepAll(now, cy) { + var eles = cy._private.aniEles; + var doneEles = []; + function stepOne(ele, isCore) { + var _p = ele._private; + var current = _p.animation.current; + var queue = _p.animation.queue; + var ranAnis = false; + + // if nothing currently animating, get something from the queue + if (current.length === 0) { + var next = queue.shift(); + if (next) { + current.push(next); + } + } + var callbacks = function callbacks(_callbacks) { + for (var j = _callbacks.length - 1; j >= 0; j--) { + var cb = _callbacks[j]; + cb(); + } + _callbacks.splice(0, _callbacks.length); + }; - const TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - Uint8ClampedArray: Uint8ClampedArray, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array - }; - - function getTypedArray( type, buffer ) { + // step and remove if done + for (var i = current.length - 1; i >= 0; i--) { + var ani = current[i]; + var ani_p = ani._private; + if (ani_p.stopped) { + current.splice(i, 1); + ani_p.hooked = false; + ani_p.playing = false; + ani_p.started = false; + callbacks(ani_p.frames); + continue; + } + if (!ani_p.playing && !ani_p.applying) { + continue; + } + + // an apply() while playing shouldn't do anything + if (ani_p.playing && ani_p.applying) { + ani_p.applying = false; + } + if (!ani_p.started) { + startAnimation(ele, ani, now); + } + step$1(ele, ani, now, isCore); + if (ani_p.applying) { + ani_p.applying = false; + } + callbacks(ani_p.frames); + if (ani_p.step != null) { + ani_p.step(now); + } + if (ani.completed()) { + current.splice(i, 1); + ani_p.hooked = false; + ani_p.playing = false; + ani_p.started = false; + callbacks(ani_p.completes); + } + ranAnis = true; + } + if (!isCore && current.length === 0 && queue.length === 0) { + doneEles.push(ele); + } + return ranAnis; + } // stepElement + + // handle all eles + var ranEleAni = false; + for (var e = 0; e < eles.length; e++) { + var ele = eles[e]; + var handledThisEle = stepOne(ele); + ranEleAni = ranEleAni || handledThisEle; + } // each element + + var ranCoreAni = stepOne(cy, true); + + // notify renderer + if (ranEleAni || ranCoreAni) { + if (eles.length > 0) { + cy.notify('draw', eles); + } else { + cy.notify('draw'); + } + } - return new TYPED_ARRAYS[ type ]( buffer ); + // remove elements from list of currently animating if its queues are empty + eles.unmerge(doneEles); + cy.emit('step'); + } // stepAll + + var corefn$8 = { + // pull in animation functions + animate: define.animate(), + animation: define.animation(), + animated: define.animated(), + clearQueue: define.clearQueue(), + delay: define.delay(), + delayAnimation: define.delayAnimation(), + stop: define.stop(), + addToAnimationPool: function addToAnimationPool(eles) { + var cy = this; + if (!cy.styleEnabled()) { + return; + } // save cycles when no style used + + cy._private.aniEles.merge(eles); + }, + stopAnimationLoop: function stopAnimationLoop() { + this._private.animationsRunning = false; + }, + startAnimationLoop: function startAnimationLoop() { + var cy = this; + cy._private.animationsRunning = true; + if (!cy.styleEnabled()) { + return; + } // save cycles when no style used + + // NB the animation loop will exec in headless environments if style enabled + // and explicit cy.destroy() is necessary to stop the loop + + function headlessStep() { + if (!cy._private.animationsRunning) { + return; + } + requestAnimationFrame$1(function animationStep(now) { + stepAll(now, cy); + headlessStep(); + }); + } + var renderer = cy.renderer(); + if (renderer && renderer.beforeRender) { + // let the renderer schedule animations + renderer.beforeRender(function rendererAnimationStep(willDraw, now) { + stepAll(now, cy); + }, renderer.beforeRenderPriorities.animations); + } else { + // manage the animation loop ourselves + headlessStep(); // first call + } + } + }; - } + var emitterOptions = { + qualifierCompare: function qualifierCompare(selector1, selector2) { + if (selector1 == null || selector2 == null) { + return selector1 == null && selector2 == null; + } else { + return selector1.sameText(selector2); + } + }, + eventMatches: function eventMatches(cy, listener, eventObj) { + var selector = listener.qualifier; + if (selector != null) { + return cy !== eventObj.target && element(eventObj.target) && selector.matches(eventObj.target); + } + return true; + }, + addEventFields: function addEventFields(cy, evt) { + evt.cy = cy; + evt.target = cy; + }, + callbackContext: function callbackContext(cy, listener, eventObj) { + return listener.qualifier != null ? eventObj.target : cy; + } + }; + var argSelector = function argSelector(arg) { + if (string(arg)) { + return new Selector(arg); + } else { + return arg; + } + }; + var elesfn = { + createEmitter: function createEmitter() { + var _p = this._private; + if (!_p.emitter) { + _p.emitter = new Emitter(emitterOptions, this); + } + return this; + }, + emitter: function emitter() { + return this._private.emitter; + }, + on: function on(events, selector, callback) { + this.emitter().on(events, argSelector(selector), callback); + return this; + }, + removeListener: function removeListener(events, selector, callback) { + this.emitter().removeListener(events, argSelector(selector), callback); + return this; + }, + removeAllListeners: function removeAllListeners() { + this.emitter().removeAllListeners(); + return this; + }, + one: function one(events, selector, callback) { + this.emitter().one(events, argSelector(selector), callback); + return this; + }, + once: function once(events, selector, callback) { + this.emitter().one(events, argSelector(selector), callback); + return this; + }, + emit: function emit(events, extraParams) { + this.emitter().emit(events, extraParams); + return this; + }, + emitAndNotify: function emitAndNotify(event, eles) { + this.emit(event); + this.notify(event, eles); + return this; + } + }; + define.eventAliasesOn(elesfn); + + var corefn$7 = { + png: function png(options) { + var renderer = this._private.renderer; + options = options || {}; + return renderer.png(options); + }, + jpg: function jpg(options) { + var renderer = this._private.renderer; + options = options || {}; + options.bg = options.bg || '#fff'; + return renderer.jpg(options); + } + }; + corefn$7.jpeg = corefn$7.jpg; + + var corefn$6 = { + layout: function layout(options) { + var cy = this; + if (options == null) { + error('Layout options must be specified to make a layout'); + return; + } + if (options.name == null) { + error('A `name` must be specified to make a layout'); + return; + } + var name = options.name; + var Layout = cy.extension('layout', name); + if (Layout == null) { + error('No such layout `' + name + '` found. Did you forget to import it and `cytoscape.use()` it?'); + return; + } + var eles; + if (string(options.eles)) { + eles = cy.$(options.eles); + } else { + eles = options.eles != null ? options.eles : cy.$(); + } + var layout = new Layout(extend$1({}, options, { + cy: cy, + eles: eles + })); + return layout; + } + }; + corefn$6.createLayout = corefn$6.makeLayout = corefn$6.layout; + + var corefn$5 = { + notify: function notify(eventName, eventEles) { + var _p = this._private; + if (this.batching()) { + _p.batchNotifications = _p.batchNotifications || {}; + var eles = _p.batchNotifications[eventName] = _p.batchNotifications[eventName] || this.collection(); + if (eventEles != null) { + eles.merge(eventEles); + } + return; // notifications are disabled during batching + } - function createElementNS( name ) { + if (!_p.notificationsEnabled) { + return; + } // exit on disabled - return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); + var renderer = this.renderer(); - } + // exit if destroy() called on core or renderer in between frames #1499 #1528 + if (this.destroyed() || !renderer) { + return; + } + renderer.notify(eventName, eventEles); + }, + notifications: function notifications(bool) { + var p = this._private; + if (bool === undefined) { + return p.notificationsEnabled; + } else { + p.notificationsEnabled = bool ? true : false; + } + return this; + }, + noNotifications: function noNotifications(callback) { + this.notifications(false); + callback(); + this.notifications(true); + }, + batching: function batching() { + return this._private.batchCount > 0; + }, + startBatch: function startBatch() { + var _p = this._private; + if (_p.batchCount == null) { + _p.batchCount = 0; + } + if (_p.batchCount === 0) { + _p.batchStyleEles = this.collection(); + _p.batchNotifications = {}; + } + _p.batchCount++; + return this; + }, + endBatch: function endBatch() { + var _p = this._private; + if (_p.batchCount === 0) { + return this; + } + _p.batchCount--; + if (_p.batchCount === 0) { + // update style for dirty eles + _p.batchStyleEles.updateStyle(); + var renderer = this.renderer(); + + // notify the renderer of queued eles and event types + Object.keys(_p.batchNotifications).forEach(function (eventName) { + var eles = _p.batchNotifications[eventName]; + if (eles.empty()) { + renderer.notify(eventName); + } else { + renderer.notify(eventName, eles); + } + }); + } + return this; + }, + batch: function batch(callback) { + this.startBatch(); + callback(); + this.endBatch(); + return this; + }, + // for backwards compatibility + batchData: function batchData(map) { + var cy = this; + return this.batch(function () { + var ids = Object.keys(map); + for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + var data = map[id]; + var ele = cy.getElementById(id); + ele.data(data); + } + }); + } + }; - function SRGBToLinear( c ) { + var rendererDefaults = defaults$g({ + hideEdgesOnViewport: false, + textureOnViewport: false, + motionBlur: false, + motionBlurOpacity: 0.05, + pixelRatio: undefined, + desktopTapThreshold: 4, + touchTapThreshold: 8, + wheelSensitivity: 1, + debug: false, + showFps: false + }); + var corefn$4 = { + renderTo: function renderTo(context, zoom, pan, pxRatio) { + var r = this._private.renderer; + r.renderTo(context, zoom, pan, pxRatio); + return this; + }, + renderer: function renderer() { + return this._private.renderer; + }, + forceRender: function forceRender() { + this.notify('draw'); + return this; + }, + resize: function resize() { + this.invalidateSize(); + this.emitAndNotify('resize'); + return this; + }, + initRenderer: function initRenderer(options) { + var cy = this; + var RendererProto = cy.extension('renderer', options.name); + if (RendererProto == null) { + error("Can not initialise: No such renderer `".concat(options.name, "` found. Did you forget to import it and `cytoscape.use()` it?")); + return; + } + if (options.wheelSensitivity !== undefined) { + warn("You have set a custom wheel sensitivity. This will make your app zoom unnaturally when using mainstream mice. You should change this value from the default only if you can guarantee that all your users will use the same hardware and OS configuration as your current machine."); + } + var rOpts = rendererDefaults(options); + rOpts.cy = cy; + cy._private.renderer = new RendererProto(rOpts); + this.notify('init'); + }, + destroyRenderer: function destroyRenderer() { + var cy = this; + cy.notify('destroy'); // destroy the renderer + + var domEle = cy.container(); + if (domEle) { + domEle._cyreg = null; + while (domEle.childNodes.length > 0) { + domEle.removeChild(domEle.childNodes[0]); + } + } + cy._private.renderer = null; // to be extra safe, remove the ref + cy.mutableElements().forEach(function (ele) { + var _p = ele._private; + _p.rscratch = {}; + _p.rstyle = {}; + _p.animation.current = []; + _p.animation.queue = []; + }); + }, + onRender: function onRender(fn) { + return this.on('render', fn); + }, + offRender: function offRender(fn) { + return this.off('render', fn); + } + }; + corefn$4.invalidateDimensions = corefn$4.resize; + + var corefn$3 = { + // get a collection + // - empty collection on no args + // - collection of elements in the graph on selector arg + // - guarantee a returned collection when elements or collection specified + collection: function collection(eles, opts) { + if (string(eles)) { + return this.$(eles); + } else if (elementOrCollection(eles)) { + return eles.collection(); + } else if (array(eles)) { + if (!opts) { + opts = {}; + } + return new Collection(this, eles, opts.unique, opts.removed); + } + return new Collection(this); + }, + nodes: function nodes(selector) { + var nodes = this.$(function (ele) { + return ele.isNode(); + }); + if (selector) { + return nodes.filter(selector); + } + return nodes; + }, + edges: function edges(selector) { + var edges = this.$(function (ele) { + return ele.isEdge(); + }); + if (selector) { + return edges.filter(selector); + } + return edges; + }, + // search the graph like jQuery + $: function $(selector) { + var eles = this._private.elements; + if (selector) { + return eles.filter(selector); + } else { + return eles.spawnSelf(); + } + }, + mutableElements: function mutableElements() { + return this._private.elements; + } + }; - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); + // aliases + corefn$3.elements = corefn$3.filter = corefn$3.$; + + var styfn$8 = {}; + + // keys for style blocks, e.g. ttfftt + var TRUE = 't'; + var FALSE = 'f'; + + // (potentially expensive calculation) + // apply the style to the element based on + // - its bypass + // - what selectors match it + styfn$8.apply = function (eles) { + var self = this; + var _p = self._private; + var cy = _p.cy; + var updatedEles = cy.collection(); + for (var ie = 0; ie < eles.length; ie++) { + var ele = eles[ie]; + var cxtMeta = self.getContextMeta(ele); + if (cxtMeta.empty) { + continue; + } + var cxtStyle = self.getContextStyle(cxtMeta); + var app = self.applyContextStyle(cxtMeta, cxtStyle, ele); + if (ele._private.appliedInitStyle) { + self.updateTransitions(ele, app.diffProps); + } else { + ele._private.appliedInitStyle = true; + } + var hintsDiff = self.updateStyleHints(ele); + if (hintsDiff) { + updatedEles.push(ele); + } + } // for elements - } + return updatedEles; + }; + styfn$8.getPropertiesDiff = function (oldCxtKey, newCxtKey) { + var self = this; + var cache = self._private.propDiffs = self._private.propDiffs || {}; + var dualCxtKey = oldCxtKey + '-' + newCxtKey; + var cachedVal = cache[dualCxtKey]; + if (cachedVal) { + return cachedVal; + } + var diffProps = []; + var addedProp = {}; + for (var i = 0; i < self.length; i++) { + var cxt = self[i]; + var oldHasCxt = oldCxtKey[i] === TRUE; + var newHasCxt = newCxtKey[i] === TRUE; + var cxtHasDiffed = oldHasCxt !== newHasCxt; + var cxtHasMappedProps = cxt.mappedProperties.length > 0; + if (cxtHasDiffed || newHasCxt && cxtHasMappedProps) { + var props = void 0; + if (cxtHasDiffed && cxtHasMappedProps) { + props = cxt.properties; // suffices b/c mappedProperties is a subset of properties + } else if (cxtHasDiffed) { + props = cxt.properties; // need to check them all + } else if (cxtHasMappedProps) { + props = cxt.mappedProperties; // only need to check mapped + } + + for (var j = 0; j < props.length; j++) { + var prop = props[j]; + var name = prop.name; + + // if a later context overrides this property, then the fact that this context has switched/diffed doesn't matter + // (semi expensive check since it makes this function O(n^2) on context length, but worth it since overall result + // is cached) + var laterCxtOverrides = false; + for (var k = i + 1; k < self.length; k++) { + var laterCxt = self[k]; + var hasLaterCxt = newCxtKey[k] === TRUE; + if (!hasLaterCxt) { + continue; + } // can't override unless the context is active + + laterCxtOverrides = laterCxt.properties[prop.name] != null; + if (laterCxtOverrides) { + break; + } // exit early as long as one later context overrides + } - function LinearToSRGB( c ) { + if (!addedProp[name] && !laterCxtOverrides) { + addedProp[name] = true; + diffProps.push(name); + } + } // for props + } // if + } // for contexts - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; + cache[dualCxtKey] = diffProps; + return diffProps; + }; + styfn$8.getContextMeta = function (ele) { + var self = this; + var cxtKey = ''; + var diffProps; + var prevKey = ele._private.styleCxtKey || ''; + + // get the cxt key + for (var i = 0; i < self.length; i++) { + var context = self[i]; + var contextSelectorMatches = context.selector && context.selector.matches(ele); // NB: context.selector may be null for 'core' + + if (contextSelectorMatches) { + cxtKey += TRUE; + } else { + cxtKey += FALSE; + } + } // for context + + diffProps = self.getPropertiesDiff(prevKey, cxtKey); + ele._private.styleCxtKey = cxtKey; + return { + key: cxtKey, + diffPropNames: diffProps, + empty: diffProps.length === 0 + }; + }; - } + // gets a computed ele style object based on matched contexts + styfn$8.getContextStyle = function (cxtMeta) { + var cxtKey = cxtMeta.key; + var self = this; + var cxtStyles = this._private.contextStyles = this._private.contextStyles || {}; - // JavaScript RGB-to-RGB transforms, defined as - // FN[InputColorSpace][OutputColorSpace] callback functions. - const FN = { - [ SRGBColorSpace ]: { [ LinearSRGBColorSpace ]: SRGBToLinear }, - [ LinearSRGBColorSpace ]: { [ SRGBColorSpace ]: LinearToSRGB }, + // if already computed style, returned cached copy + if (cxtStyles[cxtKey]) { + return cxtStyles[cxtKey]; + } + var style = { + _private: { + key: cxtKey + } + }; + for (var i = 0; i < self.length; i++) { + var cxt = self[i]; + var hasCxt = cxtKey[i] === TRUE; + if (!hasCxt) { + continue; + } + for (var j = 0; j < cxt.properties.length; j++) { + var prop = cxt.properties[j]; + style[prop.name] = prop; + } + } + cxtStyles[cxtKey] = style; + return style; }; + styfn$8.applyContextStyle = function (cxtMeta, cxtStyle, ele) { + var self = this; + var diffProps = cxtMeta.diffPropNames; + var retDiffProps = {}; + var types = self.types; + for (var i = 0; i < diffProps.length; i++) { + var diffPropName = diffProps[i]; + var cxtProp = cxtStyle[diffPropName]; + var eleProp = ele.pstyle(diffPropName); + if (!cxtProp) { + // no context prop means delete + if (!eleProp) { + continue; // no existing prop means nothing needs to be removed + // nb affects initial application on mapped values like control-point-distances + } else if (eleProp.bypass) { + cxtProp = { + name: diffPropName, + deleteBypassed: true + }; + } else { + cxtProp = { + name: diffPropName, + "delete": true + }; + } + } - const ColorManagement = { + // save cycles when the context prop doesn't need to be applied + if (eleProp === cxtProp) { + continue; + } - legacyMode: true, + // save cycles when a mapped context prop doesn't need to be applied + if (cxtProp.mapped === types.fn // context prop is function mapper + && eleProp != null // some props can be null even by default (e.g. a prop that overrides another one) + && eleProp.mapping != null // ele prop is a concrete value from from a mapper + && eleProp.mapping.value === cxtProp.value // the current prop on the ele is a flat prop value for the function mapper + ) { + // NB don't write to cxtProp, as it's shared among eles (stored in stylesheet) + var mapping = eleProp.mapping; // can write to mapping, as it's a per-ele copy + var fnValue = mapping.fnValue = cxtProp.value(ele); // temporarily cache the value in case of a miss + + if (fnValue === mapping.prevFnValue) { + continue; + } + } + var retDiffProp = retDiffProps[diffPropName] = { + prev: eleProp + }; + self.applyParsedProperty(ele, cxtProp); + retDiffProp.next = ele.pstyle(diffPropName); + if (retDiffProp.next && retDiffProp.next.bypass) { + retDiffProp.next = retDiffProp.next.bypassed; + } + } + return { + diffProps: retDiffProps + }; + }; + styfn$8.updateStyleHints = function (ele) { + var _p = ele._private; + var self = this; + var propNames = self.propertyGroupNames; + var propGrKeys = self.propertyGroupKeys; + var propHash = function propHash(ele, propNames, seedKey) { + return self.getPropertiesHash(ele, propNames, seedKey); + }; + var oldStyleKey = _p.styleKey; + if (ele.removed()) { + return false; + } + var isNode = _p.group === 'nodes'; - get workingColorSpace() { + // get the style key hashes per prop group + // but lazily -- only use non-default prop values to reduce the number of hashes + // - return LinearSRGBColorSpace; + var overriddenStyles = ele._private.style; + propNames = Object.keys(overriddenStyles); + for (var i = 0; i < propGrKeys.length; i++) { + var grKey = propGrKeys[i]; + _p.styleKeys[grKey] = [DEFAULT_HASH_SEED, DEFAULT_HASH_SEED_ALT]; + } + var updateGrKey1 = function updateGrKey1(val, grKey) { + return _p.styleKeys[grKey][0] = hashInt(val, _p.styleKeys[grKey][0]); + }; + var updateGrKey2 = function updateGrKey2(val, grKey) { + return _p.styleKeys[grKey][1] = hashIntAlt(val, _p.styleKeys[grKey][1]); + }; + var updateGrKey = function updateGrKey(val, grKey) { + updateGrKey1(val, grKey); + updateGrKey2(val, grKey); + }; + var updateGrKeyWStr = function updateGrKeyWStr(strVal, grKey) { + for (var j = 0; j < strVal.length; j++) { + var ch = strVal.charCodeAt(j); + updateGrKey1(ch, grKey); + updateGrKey2(ch, grKey); + } + }; + + // - hashing works on 32 bit ints b/c we use bitwise ops + // - small numbers get cut off (e.g. 0.123 is seen as 0 by the hashing function) + // - raise up small numbers so more significant digits are seen by hashing + // - make small numbers larger than a normal value to avoid collisions + // - works in practice and it's relatively cheap + var N = 2000000000; + var cleanNum = function cleanNum(val) { + return -128 < val && val < 128 && Math.floor(val) !== val ? N - (val * 1024 | 0) : val; + }; + for (var _i = 0; _i < propNames.length; _i++) { + var name = propNames[_i]; + var parsedProp = overriddenStyles[name]; + if (parsedProp == null) { + continue; + } + var propInfo = this.properties[name]; + var type = propInfo.type; + var _grKey = propInfo.groupKey; + var normalizedNumberVal = void 0; + if (propInfo.hashOverride != null) { + normalizedNumberVal = propInfo.hashOverride(ele, parsedProp); + } else if (parsedProp.pfValue != null) { + normalizedNumberVal = parsedProp.pfValue; + } - }, + // might not be a number if it allows enums + var numberVal = propInfo.enums == null ? parsedProp.value : null; + var haveNormNum = normalizedNumberVal != null; + var haveUnitedNum = numberVal != null; + var haveNum = haveNormNum || haveUnitedNum; + var units = parsedProp.units; + + // numbers are cheaper to hash than strings + // 1 hash op vs n hash ops (for length n string) + if (type.number && haveNum && !type.multiple) { + var v = haveNormNum ? normalizedNumberVal : numberVal; + updateGrKey(cleanNum(v), _grKey); + if (!haveNormNum && units != null) { + updateGrKeyWStr(units, _grKey); + } + } else { + updateGrKeyWStr(parsedProp.strValue, _grKey); + } + } - set workingColorSpace( colorSpace ) { + // overall style key + // - console.warn( 'THREE.ColorManagement: .workingColorSpace is readonly.' ); + var hash = [DEFAULT_HASH_SEED, DEFAULT_HASH_SEED_ALT]; + for (var _i2 = 0; _i2 < propGrKeys.length; _i2++) { + var _grKey2 = propGrKeys[_i2]; + var grHash = _p.styleKeys[_grKey2]; + hash[0] = hashInt(grHash[0], hash[0]); + hash[1] = hashIntAlt(grHash[1], hash[1]); + } + _p.styleKey = combineHashes(hash[0], hash[1]); + + // label dims + // + + var sk = _p.styleKeys; + _p.labelDimsKey = combineHashesArray(sk.labelDimensions); + var labelKeys = propHash(ele, ['label'], sk.labelDimensions); + _p.labelKey = combineHashesArray(labelKeys); + _p.labelStyleKey = combineHashesArray(hashArrays(sk.commonLabel, labelKeys)); + if (!isNode) { + var sourceLabelKeys = propHash(ele, ['source-label'], sk.labelDimensions); + _p.sourceLabelKey = combineHashesArray(sourceLabelKeys); + _p.sourceLabelStyleKey = combineHashesArray(hashArrays(sk.commonLabel, sourceLabelKeys)); + var targetLabelKeys = propHash(ele, ['target-label'], sk.labelDimensions); + _p.targetLabelKey = combineHashesArray(targetLabelKeys); + _p.targetLabelStyleKey = combineHashesArray(hashArrays(sk.commonLabel, targetLabelKeys)); + } - }, + // node + // + + if (isNode) { + var _p$styleKeys = _p.styleKeys, + nodeBody = _p$styleKeys.nodeBody, + nodeBorder = _p$styleKeys.nodeBorder, + nodeOutline = _p$styleKeys.nodeOutline, + backgroundImage = _p$styleKeys.backgroundImage, + compound = _p$styleKeys.compound, + pie = _p$styleKeys.pie; + var nodeKeys = [nodeBody, nodeBorder, nodeOutline, backgroundImage, compound, pie].filter(function (k) { + return k != null; + }).reduce(hashArrays, [DEFAULT_HASH_SEED, DEFAULT_HASH_SEED_ALT]); + _p.nodeKey = combineHashesArray(nodeKeys); + _p.hasPie = pie != null && pie[0] !== DEFAULT_HASH_SEED && pie[1] !== DEFAULT_HASH_SEED_ALT; + } + return oldStyleKey !== _p.styleKey; + }; + styfn$8.clearStyleHints = function (ele) { + var _p = ele._private; + _p.styleCxtKey = ''; + _p.styleKeys = {}; + _p.styleKey = null; + _p.labelKey = null; + _p.labelStyleKey = null; + _p.sourceLabelKey = null; + _p.sourceLabelStyleKey = null; + _p.targetLabelKey = null; + _p.targetLabelStyleKey = null; + _p.nodeKey = null; + _p.hasPie = null; + }; - convert: function ( color, sourceColorSpace, targetColorSpace ) { + // apply a property to the style (for internal use) + // returns whether application was successful + // + // now, this function flattens the property, and here's how: + // + // for parsedProp:{ bypass: true, deleteBypass: true } + // no property is generated, instead the bypass property in the + // element's style is replaced by what's pointed to by the `bypassed` + // field in the bypass property (i.e. restoring the property the + // bypass was overriding) + // + // for parsedProp:{ mapped: truthy } + // the generated flattenedProp:{ mapping: prop } + // + // for parsedProp:{ bypass: true } + // the generated flattenedProp:{ bypassed: parsedProp } + styfn$8.applyParsedProperty = function (ele, parsedProp) { + var self = this; + var prop = parsedProp; + var style = ele._private.style; + var flatProp; + var types = self.types; + var type = self.properties[prop.name].type; + var propIsBypass = prop.bypass; + var origProp = style[prop.name]; + var origPropIsBypass = origProp && origProp.bypass; + var _p = ele._private; + var flatPropMapping = 'mapping'; + var getVal = function getVal(p) { + if (p == null) { + return null; + } else if (p.pfValue != null) { + return p.pfValue; + } else { + return p.value; + } + }; + var checkTriggers = function checkTriggers() { + var fromVal = getVal(origProp); + var toVal = getVal(prop); + self.checkTriggers(ele, prop.name, fromVal, toVal); + }; + + // edge sanity checks to prevent the client from making serious mistakes + if (parsedProp.name === 'curve-style' && ele.isEdge() && ( + // loops must be bundled beziers + parsedProp.value !== 'bezier' && ele.isLoop() || + // edges connected to compound nodes can not be haystacks + parsedProp.value === 'haystack' && (ele.source().isParent() || ele.target().isParent()))) { + prop = parsedProp = this.parse(parsedProp.name, 'bezier', propIsBypass); + } + if (prop["delete"]) { + // delete the property and use the default value on falsey value + style[prop.name] = undefined; + checkTriggers(); + return true; + } + if (prop.deleteBypassed) { + // delete the property that the + if (!origProp) { + checkTriggers(); + return true; // can't delete if no prop + } else if (origProp.bypass) { + // delete bypassed + origProp.bypassed = undefined; + checkTriggers(); + return true; + } else { + return false; // we're unsuccessful deleting the bypassed + } + } - if ( this.legacyMode || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { + // check if we need to delete the current bypass + if (prop.deleteBypass) { + // then this property is just here to indicate we need to delete + if (!origProp) { + checkTriggers(); + return true; // property is already not defined + } else if (origProp.bypass) { + // then replace the bypass property with the original + // because the bypassed property was already applied (and therefore parsed), we can just replace it (no reapplying necessary) + style[prop.name] = origProp.bypassed; + checkTriggers(); + return true; + } else { + return false; // we're unsuccessful deleting the bypass + } + } - return color; + var printMappingErr = function printMappingErr() { + warn('Do not assign mappings to elements without corresponding data (i.e. ele `' + ele.id() + '` has no mapping for property `' + prop.name + '` with data field `' + prop.field + '`); try a `[' + prop.field + ']` selector to limit scope to elements with `' + prop.field + '` defined'); + }; + + // put the property in the style objects + switch (prop.mapped) { + // flatten the property if mapped + case types.mapData: + { + // flatten the field (e.g. data.foo.bar) + var fields = prop.field.split('.'); + var fieldVal = _p.data; + for (var i = 0; i < fields.length && fieldVal; i++) { + var field = fields[i]; + fieldVal = fieldVal[field]; + } + if (fieldVal == null) { + printMappingErr(); + return false; + } + var percent; + if (!number$1(fieldVal)) { + // then don't apply and fall back on the existing style + warn('Do not use continuous mappers without specifying numeric data (i.e. `' + prop.field + ': ' + fieldVal + '` for `' + ele.id() + '` is non-numeric)'); + return false; + } else { + var fieldWidth = prop.fieldMax - prop.fieldMin; + if (fieldWidth === 0) { + // safety check -- not strictly necessary as no props of zero range should be passed here + percent = 0; + } else { + percent = (fieldVal - prop.fieldMin) / fieldWidth; + } + } - } + // make sure to bound percent value + if (percent < 0) { + percent = 0; + } else if (percent > 1) { + percent = 1; + } + if (type.color) { + var r1 = prop.valueMin[0]; + var r2 = prop.valueMax[0]; + var g1 = prop.valueMin[1]; + var g2 = prop.valueMax[1]; + var b1 = prop.valueMin[2]; + var b2 = prop.valueMax[2]; + var a1 = prop.valueMin[3] == null ? 1 : prop.valueMin[3]; + var a2 = prop.valueMax[3] == null ? 1 : prop.valueMax[3]; + var clr = [Math.round(r1 + (r2 - r1) * percent), Math.round(g1 + (g2 - g1) * percent), Math.round(b1 + (b2 - b1) * percent), Math.round(a1 + (a2 - a1) * percent)]; + flatProp = { + // colours are simple, so just create the flat property instead of expensive string parsing + bypass: prop.bypass, + // we're a bypass if the mapping property is a bypass + name: prop.name, + value: clr, + strValue: 'rgb(' + clr[0] + ', ' + clr[1] + ', ' + clr[2] + ')' + }; + } else if (type.number) { + var calcValue = prop.valueMin + (prop.valueMax - prop.valueMin) * percent; + flatProp = this.parse(prop.name, calcValue, prop.bypass, flatPropMapping); + } else { + return false; // can only map to colours and numbers + } - if ( FN[ sourceColorSpace ] && FN[ sourceColorSpace ][ targetColorSpace ] !== undefined ) { + if (!flatProp) { + // if we can't flatten the property, then don't apply the property and fall back on the existing style + printMappingErr(); + return false; + } + flatProp.mapping = prop; // keep a reference to the mapping + prop = flatProp; // the flattened (mapped) property is the one we want + + break; + } + + // direct mapping + case types.data: + { + // flatten the field (e.g. data.foo.bar) + var _fields = prop.field.split('.'); + var _fieldVal = _p.data; + for (var _i3 = 0; _i3 < _fields.length && _fieldVal; _i3++) { + var _field = _fields[_i3]; + _fieldVal = _fieldVal[_field]; + } + if (_fieldVal != null) { + flatProp = this.parse(prop.name, _fieldVal, prop.bypass, flatPropMapping); + } + if (!flatProp) { + // if we can't flatten the property, then don't apply and fall back on the existing style + printMappingErr(); + return false; + } + flatProp.mapping = prop; // keep a reference to the mapping + prop = flatProp; // the flattened (mapped) property is the one we want + + break; + } + case types.fn: + { + var fn = prop.value; + var fnRetVal = prop.fnValue != null ? prop.fnValue : fn(ele); // check for cached value before calling function + + prop.prevFnValue = fnRetVal; + if (fnRetVal == null) { + warn('Custom function mappers may not return null (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is null)'); + return false; + } + flatProp = this.parse(prop.name, fnRetVal, prop.bypass, flatPropMapping); + if (!flatProp) { + warn('Custom function mappers may not return invalid values for the property type (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is invalid)'); + return false; + } + flatProp.mapping = copy(prop); // keep a reference to the mapping + prop = flatProp; // the flattened (mapped) property is the one we want + + break; + } + case undefined: + break; + // just set the property + + default: + return false; + // not a valid mapping + } - const fn = FN[ sourceColorSpace ][ targetColorSpace ]; + // if the property is a bypass property, then link the resultant property to the original one + if (propIsBypass) { + if (origPropIsBypass) { + // then this bypass overrides the existing one + prop.bypassed = origProp.bypassed; // steal bypassed prop from old bypass + } else { + // then link the orig prop to the new bypass + prop.bypassed = origProp; + } + style[prop.name] = prop; // and set + } else { + // prop is not bypass + if (origPropIsBypass) { + // then keep the orig prop (since it's a bypass) and link to the new prop + origProp.bypassed = prop; + } else { + // then just replace the old prop with the new one + style[prop.name] = prop; + } + } + checkTriggers(); + return true; + }; + styfn$8.cleanElements = function (eles, keepBypasses) { + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + this.clearStyleHints(ele); + ele.dirtyCompoundBoundsCache(); + ele.dirtyBoundingBoxCache(); + if (!keepBypasses) { + ele._private.style = {}; + } else { + var style = ele._private.style; + var propNames = Object.keys(style); + for (var j = 0; j < propNames.length; j++) { + var propName = propNames[j]; + var eleProp = style[propName]; + if (eleProp != null) { + if (eleProp.bypass) { + eleProp.bypassed = null; + } else { + style[propName] = null; + } + } + } + } + } + }; - color.r = fn( color.r ); - color.g = fn( color.g ); - color.b = fn( color.b ); + // updates the visual style for all elements (useful for manual style modification after init) + styfn$8.update = function () { + var cy = this._private.cy; + var eles = cy.mutableElements(); + eles.updateStyle(); + }; - return color; + // diffProps : { name => { prev, next } } + styfn$8.updateTransitions = function (ele, diffProps) { + var self = this; + var _p = ele._private; + var props = ele.pstyle('transition-property').value; + var duration = ele.pstyle('transition-duration').pfValue; + var delay = ele.pstyle('transition-delay').pfValue; + if (props.length > 0 && duration > 0) { + var style = {}; + + // build up the style to animate towards + var anyPrev = false; + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + var styProp = ele.pstyle(prop); + var diffProp = diffProps[prop]; + if (!diffProp) { + continue; + } + var prevProp = diffProp.prev; + var fromProp = prevProp; + var toProp = diffProp.next != null ? diffProp.next : styProp; + var diff = false; + var initVal = void 0; + var initDt = 0.000001; // delta time % value for initVal (allows animating out of init zero opacity) + + if (!fromProp) { + continue; + } + + // consider px values + if (number$1(fromProp.pfValue) && number$1(toProp.pfValue)) { + diff = toProp.pfValue - fromProp.pfValue; // nonzero is truthy + initVal = fromProp.pfValue + initDt * diff; + + // consider numerical values + } else if (number$1(fromProp.value) && number$1(toProp.value)) { + diff = toProp.value - fromProp.value; // nonzero is truthy + initVal = fromProp.value + initDt * diff; + + // consider colour values + } else if (array(fromProp.value) && array(toProp.value)) { + diff = fromProp.value[0] !== toProp.value[0] || fromProp.value[1] !== toProp.value[1] || fromProp.value[2] !== toProp.value[2]; + initVal = fromProp.strValue; + } + + // the previous value is good for an animation only if it's different + if (diff) { + style[prop] = toProp.strValue; // to val + this.applyBypass(ele, prop, initVal); // from val + anyPrev = true; + } + } // end if props allow ani + + // can't transition if there's nothing previous to transition from + if (!anyPrev) { + return; + } + _p.transitioning = true; + new Promise$1(function (resolve) { + if (delay > 0) { + ele.delayAnimation(delay).play().promise().then(resolve); + } else { + resolve(); + } + }).then(function () { + return ele.animation({ + style: style, + duration: duration, + easing: ele.pstyle('transition-timing-function').value, + queue: false + }).play().promise(); + }).then(function () { + // if( !isBypass ){ + self.removeBypasses(ele, props); + ele.emitAndNotify('style'); + // } + + _p.transitioning = false; + }); + } else if (_p.transitioning) { + this.removeBypasses(ele, props); + ele.emitAndNotify('style'); + _p.transitioning = false; + } + }; + styfn$8.checkTrigger = function (ele, name, fromValue, toValue, getTrigger, onTrigger) { + var prop = this.properties[name]; + var triggerCheck = getTrigger(prop); + if (triggerCheck != null && triggerCheck(fromValue, toValue)) { + onTrigger(prop); + } + }; + styfn$8.checkZOrderTrigger = function (ele, name, fromValue, toValue) { + var _this = this; + this.checkTrigger(ele, name, fromValue, toValue, function (prop) { + return prop.triggersZOrder; + }, function () { + _this._private.cy.notify('zorder', ele); + }); + }; + styfn$8.checkBoundsTrigger = function (ele, name, fromValue, toValue) { + this.checkTrigger(ele, name, fromValue, toValue, function (prop) { + return prop.triggersBounds; + }, function (prop) { + ele.dirtyCompoundBoundsCache(); + ele.dirtyBoundingBoxCache(); + + // if the prop change makes the bb of pll bezier edges invalid, + // then dirty the pll edge bb cache as well + if ( + // only for beziers -- so performance of other edges isn't affected + prop.triggersBoundsOfParallelBeziers && name === 'curve-style' && (fromValue === 'bezier' || toValue === 'bezier')) { + ele.parallelEdges().forEach(function (pllEdge) { + if (pllEdge.isBundledBezier()) { + pllEdge.dirtyBoundingBoxCache(); + } + }); + } + if (prop.triggersBoundsOfConnectedEdges && name === 'display' && (fromValue === 'none' || toValue === 'none')) { + ele.connectedEdges().forEach(function (edge) { + edge.dirtyBoundingBoxCache(); + }); + } + }); + }; + styfn$8.checkTriggers = function (ele, name, fromValue, toValue) { + ele.dirtyStyleCache(); + this.checkZOrderTrigger(ele, name, fromValue, toValue); + this.checkBoundsTrigger(ele, name, fromValue, toValue); + }; - } + var styfn$7 = {}; + + // bypasses are applied to an existing style on an element, and just tacked on temporarily + // returns true iff application was successful for at least 1 specified property + styfn$7.applyBypass = function (eles, name, value, updateTransitions) { + var self = this; + var props = []; + var isBypass = true; + + // put all the properties (can specify one or many) in an array after parsing them + if (name === '*' || name === '**') { + // apply to all property names + + if (value !== undefined) { + for (var i = 0; i < self.properties.length; i++) { + var prop = self.properties[i]; + var _name = prop.name; + var parsedProp = this.parse(_name, value, true); + if (parsedProp) { + props.push(parsedProp); + } + } + } + } else if (string(name)) { + // then parse the single property + var _parsedProp = this.parse(name, value, true); + if (_parsedProp) { + props.push(_parsedProp); + } + } else if (plainObject(name)) { + // then parse each property + var specifiedProps = name; + updateTransitions = value; + var names = Object.keys(specifiedProps); + for (var _i = 0; _i < names.length; _i++) { + var _name2 = names[_i]; + var _value = specifiedProps[_name2]; + if (_value === undefined) { + // try camel case name too + _value = specifiedProps[dash2camel(_name2)]; + } + if (_value !== undefined) { + var _parsedProp2 = this.parse(_name2, _value, true); + if (_parsedProp2) { + props.push(_parsedProp2); + } + } + } + } else { + // can't do anything without well defined properties + return false; + } - throw new Error( 'Unsupported color space conversion.' ); + // we've failed if there are no valid properties + if (props.length === 0) { + return false; + } - }, + // now, apply the bypass properties on the elements + var ret = false; // return true if at least one succesful bypass applied + for (var _i2 = 0; _i2 < eles.length; _i2++) { + // for each ele + var ele = eles[_i2]; + var diffProps = {}; + var diffProp = void 0; + for (var j = 0; j < props.length; j++) { + // for each prop + var _prop = props[j]; + if (updateTransitions) { + var prevProp = ele.pstyle(_prop.name); + diffProp = diffProps[_prop.name] = { + prev: prevProp + }; + } + ret = this.applyParsedProperty(ele, copy(_prop)) || ret; + if (updateTransitions) { + diffProp.next = ele.pstyle(_prop.name); + } + } // for props + + if (ret) { + this.updateStyleHints(ele); + } + if (updateTransitions) { + this.updateTransitions(ele, diffProps, isBypass); + } + } // for eles - fromWorkingColorSpace: function ( color, targetColorSpace ) { + return ret; + }; - return this.convert( color, this.workingColorSpace, targetColorSpace ); + // only useful in specific cases like animation + styfn$7.overrideBypass = function (eles, name, value) { + name = camel2dash(name); + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var prop = ele._private.style[name]; + var type = this.properties[name].type; + var isColor = type.color; + var isMulti = type.mutiple; + var oldValue = !prop ? null : prop.pfValue != null ? prop.pfValue : prop.value; + if (!prop || !prop.bypass) { + // need a bypass if one doesn't exist + this.applyBypass(ele, name, value); + } else { + prop.value = value; + if (prop.pfValue != null) { + prop.pfValue = value; + } + if (isColor) { + prop.strValue = 'rgb(' + value.join(',') + ')'; + } else if (isMulti) { + prop.strValue = value.join(' '); + } else { + prop.strValue = '' + value; + } + this.updateStyleHints(ele); + } + this.checkTriggers(ele, name, oldValue, value); + } + }; + styfn$7.removeAllBypasses = function (eles, updateTransitions) { + return this.removeBypasses(eles, this.propertyNames, updateTransitions); + }; + styfn$7.removeBypasses = function (eles, props, updateTransitions) { + var isBypass = true; + for (var j = 0; j < eles.length; j++) { + var ele = eles[j]; + var diffProps = {}; + for (var i = 0; i < props.length; i++) { + var name = props[i]; + var prop = this.properties[name]; + var prevProp = ele.pstyle(prop.name); + if (!prevProp || !prevProp.bypass) { + // if a bypass doesn't exist for the prop, nothing needs to be removed + continue; + } + var value = ''; // empty => remove bypass + var parsedProp = this.parse(name, value, true); + var diffProp = diffProps[prop.name] = { + prev: prevProp + }; + this.applyParsedProperty(ele, parsedProp); + diffProp.next = ele.pstyle(prop.name); + } // for props + + this.updateStyleHints(ele); + if (updateTransitions) { + this.updateTransitions(ele, diffProps, isBypass); + } + } // for eles + }; - }, + var styfn$6 = {}; - toWorkingColorSpace: function ( color, sourceColorSpace ) { + // gets what an em size corresponds to in pixels relative to a dom element + styfn$6.getEmSizeInPixels = function () { + var px = this.containerCss('font-size'); + if (px != null) { + return parseFloat(px); + } else { + return 1; // for headless + } + }; - return this.convert( color, sourceColorSpace, this.workingColorSpace ); + // gets css property from the core container + styfn$6.containerCss = function (propName) { + var cy = this._private.cy; + var domElement = cy.container(); + var containerWindow = cy.window(); + if (containerWindow && domElement && containerWindow.getComputedStyle) { + return containerWindow.getComputedStyle(domElement).getPropertyValue(propName); + } + }; - }, + var styfn$5 = {}; + // gets the rendered style for an element + styfn$5.getRenderedStyle = function (ele, prop) { + if (prop) { + return this.getStylePropertyValue(ele, prop, true); + } else { + return this.getRawStyle(ele, true); + } }; - const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; + // gets the raw style for an element + styfn$5.getRawStyle = function (ele, isRenderedVal) { + var self = this; + ele = ele[0]; // insure it's an element + + if (ele) { + var rstyle = {}; + for (var i = 0; i < self.properties.length; i++) { + var prop = self.properties[i]; + var val = self.getStylePropertyValue(ele, prop.name, isRenderedVal); + if (val != null) { + rstyle[prop.name] = val; + rstyle[dash2camel(prop.name)] = val; + } + } + return rstyle; + } + }; + styfn$5.getIndexedStyle = function (ele, property, subproperty, index) { + var pstyle = ele.pstyle(property)[subproperty][index]; + return pstyle != null ? pstyle : ele.cy().style().getDefaultProperty(property)[subproperty][0]; + }; + styfn$5.getStylePropertyValue = function (ele, propName, isRenderedVal) { + var self = this; + ele = ele[0]; // insure it's an element + + if (ele) { + var prop = self.properties[propName]; + if (prop.alias) { + prop = prop.pointsTo; + } + var type = prop.type; + var styleProp = ele.pstyle(prop.name); + if (styleProp) { + var value = styleProp.value, + units = styleProp.units, + strValue = styleProp.strValue; + if (isRenderedVal && type.number && value != null && number$1(value)) { + var zoom = ele.cy().zoom(); + var getRenderedValue = function getRenderedValue(val) { + return val * zoom; + }; + var getValueStringWithUnits = function getValueStringWithUnits(val, units) { + return getRenderedValue(val) + units; + }; + var isArrayValue = array(value); + var haveUnits = isArrayValue ? units.every(function (u) { + return u != null; + }) : units != null; + if (haveUnits) { + if (isArrayValue) { + return value.map(function (v, i) { + return getValueStringWithUnits(v, units[i]); + }).join(' '); + } else { + return getValueStringWithUnits(value, units); + } + } else { + if (isArrayValue) { + return value.map(function (v) { + return string(v) ? v : '' + getRenderedValue(v); + }).join(' '); + } else { + return '' + getRenderedValue(value); + } + } + } else if (strValue != null) { + return strValue; + } + } + return null; + } + }; + styfn$5.getAnimationStartStyle = function (ele, aniProps) { + var rstyle = {}; + for (var i = 0; i < aniProps.length; i++) { + var aniProp = aniProps[i]; + var name = aniProp.name; + var styleProp = ele.pstyle(name); + if (styleProp !== undefined) { + // then make a prop of it + if (plainObject(styleProp)) { + styleProp = this.parse(name, styleProp.strValue); + } else { + styleProp = this.parse(name, styleProp); + } + } + if (styleProp) { + rstyle[name] = styleProp; + } + } + return rstyle; + }; + styfn$5.getPropsList = function (propsObj) { + var self = this; + var rstyle = []; + var style = propsObj; + var props = self.properties; + if (style) { + var names = Object.keys(style); + for (var i = 0; i < names.length; i++) { + var name = names[i]; + var val = style[name]; + var prop = props[name] || props[camel2dash(name)]; + var styleProp = this.parse(prop.name, val); + if (styleProp) { + rstyle.push(styleProp); + } + } + } + return rstyle; + }; + styfn$5.getNonDefaultPropertiesHash = function (ele, propNames, seed) { + var hash = seed.slice(); + var name, val, strVal, chVal; + var i, j; + for (i = 0; i < propNames.length; i++) { + name = propNames[i]; + val = ele.pstyle(name, false); + if (val == null) { + continue; + } else if (val.pfValue != null) { + hash[0] = hashInt(chVal, hash[0]); + hash[1] = hashIntAlt(chVal, hash[1]); + } else { + strVal = val.strValue; + for (j = 0; j < strVal.length; j++) { + chVal = strVal.charCodeAt(j); + hash[0] = hashInt(chVal, hash[0]); + hash[1] = hashIntAlt(chVal, hash[1]); + } + } + } + return hash; + }; + styfn$5.getPropertiesHash = styfn$5.getNonDefaultPropertiesHash; + + var styfn$4 = {}; + styfn$4.appendFromJson = function (json) { + var style = this; + for (var i = 0; i < json.length; i++) { + var context = json[i]; + var selector = context.selector; + var props = context.style || context.css; + var names = Object.keys(props); + style.selector(selector); // apply selector + + for (var j = 0; j < names.length; j++) { + var name = names[j]; + var value = props[name]; + style.css(name, value); // apply property + } + } - const _rgb = { r: 0, g: 0, b: 0 }; - const _hslA = { h: 0, s: 0, l: 0 }; - const _hslB = { h: 0, s: 0, l: 0 }; + return style; + }; - function hue2rgb( p, q, t ) { + // accessible cy.style() function + styfn$4.fromJson = function (json) { + var style = this; + style.resetToDefault(); + style.appendFromJson(json); + return style; + }; - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; + // get json from cy.style() api + styfn$4.json = function () { + var json = []; + for (var i = this.defaultLength; i < this.length; i++) { + var cxt = this[i]; + var selector = cxt.selector; + var props = cxt.properties; + var css = {}; + for (var j = 0; j < props.length; j++) { + var prop = props[j]; + css[prop.name] = prop.strValue; + } + json.push({ + selector: !selector ? 'core' : selector.toString(), + style: css + }); + } + return json; + }; - } + var styfn$3 = {}; + styfn$3.appendFromString = function (string) { + var self = this; + var style = this; + var remaining = '' + string; + var selAndBlockStr; + var blockRem; + var propAndValStr; + + // remove comments from the style string + remaining = remaining.replace(/[/][*](\s|.)+?[*][/]/g, ''); + function removeSelAndBlockFromRemaining() { + // remove the parsed selector and block from the remaining text to parse + if (remaining.length > selAndBlockStr.length) { + remaining = remaining.substr(selAndBlockStr.length); + } else { + remaining = ''; + } + } + function removePropAndValFromRem() { + // remove the parsed property and value from the remaining block text to parse + if (blockRem.length > propAndValStr.length) { + blockRem = blockRem.substr(propAndValStr.length); + } else { + blockRem = ''; + } + } + for (;;) { + var nothingLeftToParse = remaining.match(/^\s*$/); + if (nothingLeftToParse) { + break; + } + var selAndBlock = remaining.match(/^\s*((?:.|\s)+?)\s*\{((?:.|\s)+?)\}/); + if (!selAndBlock) { + warn('Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: ' + remaining); + break; + } + selAndBlockStr = selAndBlock[0]; + + // parse the selector + var selectorStr = selAndBlock[1]; + if (selectorStr !== 'core') { + var selector = new Selector(selectorStr); + if (selector.invalid) { + warn('Skipping parsing of block: Invalid selector found in string stylesheet: ' + selectorStr); + + // skip this selector and block + removeSelAndBlockFromRemaining(); + continue; + } + } - function toComponents( source, target ) { + // parse the block of properties and values + var blockStr = selAndBlock[2]; + var invalidBlock = false; + blockRem = blockStr; + var props = []; + for (;;) { + var _nothingLeftToParse = blockRem.match(/^\s*$/); + if (_nothingLeftToParse) { + break; + } + var propAndVal = blockRem.match(/^\s*(.+?)\s*:\s*(.+?)(?:\s*;|\s*$)/); + if (!propAndVal) { + warn('Skipping parsing of block: Invalid formatting of style property and value definitions found in:' + blockStr); + invalidBlock = true; + break; + } + propAndValStr = propAndVal[0]; + var propStr = propAndVal[1]; + var valStr = propAndVal[2]; + var prop = self.properties[propStr]; + if (!prop) { + warn('Skipping property: Invalid property name in: ' + propAndValStr); + + // skip this property in the block + removePropAndValFromRem(); + continue; + } + var parsedProp = style.parse(propStr, valStr); + if (!parsedProp) { + warn('Skipping property: Invalid property definition in: ' + propAndValStr); + + // skip this property in the block + removePropAndValFromRem(); + continue; + } + props.push({ + name: propStr, + val: valStr + }); + removePropAndValFromRem(); + } + if (invalidBlock) { + removeSelAndBlockFromRemaining(); + break; + } - target.r = source.r; - target.g = source.g; - target.b = source.b; + // put the parsed block in the style + style.selector(selectorStr); + for (var i = 0; i < props.length; i++) { + var _prop = props[i]; + style.css(_prop.name, _prop.val); + } + removeSelAndBlockFromRemaining(); + } + return style; + }; + styfn$3.fromString = function (string) { + var style = this; + style.resetToDefault(); + style.appendFromString(string); + return style; + }; - return target; + var styfn$2 = {}; + (function () { + var number$1 = number; + var rgba = rgbaNoBackRefs; + var hsla = hslaNoBackRefs; + var hex3$1 = hex3; + var hex6$1 = hex6; + var data = function data(prefix) { + return '^' + prefix + '\\s*\\(\\s*([\\w\\.]+)\\s*\\)$'; + }; + var mapData = function mapData(prefix) { + var mapArg = number$1 + '|\\w+|' + rgba + '|' + hsla + '|' + hex3$1 + '|' + hex6$1; + return '^' + prefix + '\\s*\\(([\\w\\.]+)\\s*\\,\\s*(' + number$1 + ')\\s*\\,\\s*(' + number$1 + ')\\s*,\\s*(' + mapArg + ')\\s*\\,\\s*(' + mapArg + ')\\)$'; + }; + var urlRegexes = ['^url\\s*\\(\\s*[\'"]?(.+?)[\'"]?\\s*\\)$', '^(none)$', '^(.+)$']; + + // each visual style property has a type and needs to be validated according to it + styfn$2.types = { + time: { + number: true, + min: 0, + units: 's|ms', + implicitUnits: 'ms' + }, + percent: { + number: true, + min: 0, + max: 100, + units: '%', + implicitUnits: '%' + }, + percentages: { + number: true, + min: 0, + max: 100, + units: '%', + implicitUnits: '%', + multiple: true + }, + zeroOneNumber: { + number: true, + min: 0, + max: 1, + unitless: true + }, + zeroOneNumbers: { + number: true, + min: 0, + max: 1, + unitless: true, + multiple: true + }, + nOneOneNumber: { + number: true, + min: -1, + max: 1, + unitless: true + }, + nonNegativeInt: { + number: true, + min: 0, + integer: true, + unitless: true + }, + nonNegativeNumber: { + number: true, + min: 0, + unitless: true + }, + position: { + enums: ['parent', 'origin'] + }, + nodeSize: { + number: true, + min: 0, + enums: ['label'] + }, + number: { + number: true, + unitless: true + }, + numbers: { + number: true, + unitless: true, + multiple: true + }, + positiveNumber: { + number: true, + unitless: true, + min: 0, + strictMin: true + }, + size: { + number: true, + min: 0 + }, + bidirectionalSize: { + number: true + }, + // allows negative + bidirectionalSizeMaybePercent: { + number: true, + allowPercent: true + }, + // allows negative + bidirectionalSizes: { + number: true, + multiple: true + }, + // allows negative + sizeMaybePercent: { + number: true, + min: 0, + allowPercent: true + }, + axisDirection: { + enums: ['horizontal', 'leftward', 'rightward', 'vertical', 'upward', 'downward', 'auto'] + }, + paddingRelativeTo: { + enums: ['width', 'height', 'average', 'min', 'max'] + }, + bgWH: { + number: true, + min: 0, + allowPercent: true, + enums: ['auto'], + multiple: true + }, + bgPos: { + number: true, + allowPercent: true, + multiple: true + }, + bgRelativeTo: { + enums: ['inner', 'include-padding'], + multiple: true + }, + bgRepeat: { + enums: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'], + multiple: true + }, + bgFit: { + enums: ['none', 'contain', 'cover'], + multiple: true + }, + bgCrossOrigin: { + enums: ['anonymous', 'use-credentials', 'null'], + multiple: true + }, + bgClip: { + enums: ['none', 'node'], + multiple: true + }, + bgContainment: { + enums: ['inside', 'over'], + multiple: true + }, + color: { + color: true + }, + colors: { + color: true, + multiple: true + }, + fill: { + enums: ['solid', 'linear-gradient', 'radial-gradient'] + }, + bool: { + enums: ['yes', 'no'] + }, + bools: { + enums: ['yes', 'no'], + multiple: true + }, + lineStyle: { + enums: ['solid', 'dotted', 'dashed'] + }, + lineCap: { + enums: ['butt', 'round', 'square'] + }, + linePosition: { + enums: ['center', 'inside', 'outside'] + }, + lineJoin: { + enums: ['round', 'bevel', 'miter'] + }, + borderStyle: { + enums: ['solid', 'dotted', 'dashed', 'double'] + }, + curveStyle: { + enums: ['bezier', 'unbundled-bezier', 'haystack', 'segments', 'straight', 'straight-triangle', 'taxi', 'round-segments', 'round-taxi'] + }, + radiusType: { + enums: ['arc-radius', 'influence-radius'], + multiple: true + }, + fontFamily: { + regex: '^([\\w- \\"]+(?:\\s*,\\s*[\\w- \\"]+)*)$' + }, + fontStyle: { + enums: ['italic', 'normal', 'oblique'] + }, + fontWeight: { + enums: ['normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '800', '900', 100, 200, 300, 400, 500, 600, 700, 800, 900] + }, + textDecoration: { + enums: ['none', 'underline', 'overline', 'line-through'] + }, + textTransform: { + enums: ['none', 'uppercase', 'lowercase'] + }, + textWrap: { + enums: ['none', 'wrap', 'ellipsis'] + }, + textOverflowWrap: { + enums: ['whitespace', 'anywhere'] + }, + textBackgroundShape: { + enums: ['rectangle', 'roundrectangle', 'round-rectangle'] + }, + nodeShape: { + enums: ['rectangle', 'roundrectangle', 'round-rectangle', 'cutrectangle', 'cut-rectangle', 'bottomroundrectangle', 'bottom-round-rectangle', 'barrel', 'ellipse', 'triangle', 'round-triangle', 'square', 'pentagon', 'round-pentagon', 'hexagon', 'round-hexagon', 'concavehexagon', 'concave-hexagon', 'heptagon', 'round-heptagon', 'octagon', 'round-octagon', 'tag', 'round-tag', 'star', 'diamond', 'round-diamond', 'vee', 'rhomboid', 'right-rhomboid', 'polygon'] + }, + overlayShape: { + enums: ['roundrectangle', 'round-rectangle', 'ellipse'] + }, + cornerRadius: { + number: true, + min: 0, + units: 'px|em', + implicitUnits: 'px', + enums: ['auto'] + }, + compoundIncludeLabels: { + enums: ['include', 'exclude'] + }, + arrowShape: { + enums: ['tee', 'triangle', 'triangle-tee', 'circle-triangle', 'triangle-cross', 'triangle-backcurve', 'vee', 'square', 'circle', 'diamond', 'chevron', 'none'] + }, + arrowFill: { + enums: ['filled', 'hollow'] + }, + arrowWidth: { + number: true, + units: '%|px|em', + implicitUnits: 'px', + enums: ['match-line'] + }, + display: { + enums: ['element', 'none'] + }, + visibility: { + enums: ['hidden', 'visible'] + }, + zCompoundDepth: { + enums: ['bottom', 'orphan', 'auto', 'top'] + }, + zIndexCompare: { + enums: ['auto', 'manual'] + }, + valign: { + enums: ['top', 'center', 'bottom'] + }, + halign: { + enums: ['left', 'center', 'right'] + }, + justification: { + enums: ['left', 'center', 'right', 'auto'] + }, + text: { + string: true + }, + data: { + mapping: true, + regex: data('data') + }, + layoutData: { + mapping: true, + regex: data('layoutData') + }, + scratch: { + mapping: true, + regex: data('scratch') + }, + mapData: { + mapping: true, + regex: mapData('mapData') + }, + mapLayoutData: { + mapping: true, + regex: mapData('mapLayoutData') + }, + mapScratch: { + mapping: true, + regex: mapData('mapScratch') + }, + fn: { + mapping: true, + fn: true + }, + url: { + regexes: urlRegexes, + singleRegexMatchValue: true + }, + urls: { + regexes: urlRegexes, + singleRegexMatchValue: true, + multiple: true + }, + propList: { + propList: true + }, + angle: { + number: true, + units: 'deg|rad', + implicitUnits: 'rad' + }, + textRotation: { + number: true, + units: 'deg|rad', + implicitUnits: 'rad', + enums: ['none', 'autorotate'] + }, + polygonPointList: { + number: true, + multiple: true, + evenMultiple: true, + min: -1, + max: 1, + unitless: true + }, + edgeDistances: { + enums: ['intersection', 'node-position', 'endpoints'] + }, + edgeEndpoint: { + number: true, + multiple: true, + units: '%|px|em|deg|rad', + implicitUnits: 'px', + enums: ['inside-to-node', 'outside-to-node', 'outside-to-node-or-label', 'outside-to-line', 'outside-to-line-or-label'], + singleEnum: true, + validate: function validate(valArr, unitsArr) { + switch (valArr.length) { + case 2: + // can be % or px only + return unitsArr[0] !== 'deg' && unitsArr[0] !== 'rad' && unitsArr[1] !== 'deg' && unitsArr[1] !== 'rad'; + case 1: + // can be enum, deg, or rad only + return string(valArr[0]) || unitsArr[0] === 'deg' || unitsArr[0] === 'rad'; + default: + return false; + } + } + }, + easing: { + regexes: ['^(spring)\\s*\\(\\s*(' + number$1 + ')\\s*,\\s*(' + number$1 + ')\\s*\\)$', '^(cubic-bezier)\\s*\\(\\s*(' + number$1 + ')\\s*,\\s*(' + number$1 + ')\\s*,\\s*(' + number$1 + ')\\s*,\\s*(' + number$1 + ')\\s*\\)$'], + enums: ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'ease-in-sine', 'ease-out-sine', 'ease-in-out-sine', 'ease-in-quad', 'ease-out-quad', 'ease-in-out-quad', 'ease-in-cubic', 'ease-out-cubic', 'ease-in-out-cubic', 'ease-in-quart', 'ease-out-quart', 'ease-in-out-quart', 'ease-in-quint', 'ease-out-quint', 'ease-in-out-quint', 'ease-in-expo', 'ease-out-expo', 'ease-in-out-expo', 'ease-in-circ', 'ease-out-circ', 'ease-in-out-circ'] + }, + gradientDirection: { + enums: ['to-bottom', 'to-top', 'to-left', 'to-right', 'to-bottom-right', 'to-bottom-left', 'to-top-right', 'to-top-left', 'to-right-bottom', 'to-left-bottom', 'to-right-top', 'to-left-top' // different order + ] + }, + + boundsExpansion: { + number: true, + multiple: true, + min: 0, + validate: function validate(valArr) { + var length = valArr.length; + return length === 1 || length === 2 || length === 4; + } + } + }; + var diff = { + zeroNonZero: function zeroNonZero(val1, val2) { + if ((val1 == null || val2 == null) && val1 !== val2) { + return true; // null cases could represent any value + } + if (val1 == 0 && val2 != 0) { + return true; + } else if (val1 != 0 && val2 == 0) { + return true; + } else { + return false; + } + }, + any: function any(val1, val2) { + return val1 != val2; + }, + emptyNonEmpty: function emptyNonEmpty(str1, str2) { + var empty1 = emptyString(str1); + var empty2 = emptyString(str2); + return empty1 && !empty2 || !empty1 && empty2; + } + }; + + // define visual style properties + // + // - n.b. adding a new group of props may require updates to updateStyleHints() + // - adding new props to an existing group gets handled automatically + + var t = styfn$2.types; + var mainLabel = [{ + name: 'label', + type: t.text, + triggersBounds: diff.any, + triggersZOrder: diff.emptyNonEmpty + }, { + name: 'text-rotation', + type: t.textRotation, + triggersBounds: diff.any + }, { + name: 'text-margin-x', + type: t.bidirectionalSize, + triggersBounds: diff.any + }, { + name: 'text-margin-y', + type: t.bidirectionalSize, + triggersBounds: diff.any + }]; + var sourceLabel = [{ + name: 'source-label', + type: t.text, + triggersBounds: diff.any + }, { + name: 'source-text-rotation', + type: t.textRotation, + triggersBounds: diff.any + }, { + name: 'source-text-margin-x', + type: t.bidirectionalSize, + triggersBounds: diff.any + }, { + name: 'source-text-margin-y', + type: t.bidirectionalSize, + triggersBounds: diff.any + }, { + name: 'source-text-offset', + type: t.size, + triggersBounds: diff.any + }]; + var targetLabel = [{ + name: 'target-label', + type: t.text, + triggersBounds: diff.any + }, { + name: 'target-text-rotation', + type: t.textRotation, + triggersBounds: diff.any + }, { + name: 'target-text-margin-x', + type: t.bidirectionalSize, + triggersBounds: diff.any + }, { + name: 'target-text-margin-y', + type: t.bidirectionalSize, + triggersBounds: diff.any + }, { + name: 'target-text-offset', + type: t.size, + triggersBounds: diff.any + }]; + var labelDimensions = [{ + name: 'font-family', + type: t.fontFamily, + triggersBounds: diff.any + }, { + name: 'font-style', + type: t.fontStyle, + triggersBounds: diff.any + }, { + name: 'font-weight', + type: t.fontWeight, + triggersBounds: diff.any + }, { + name: 'font-size', + type: t.size, + triggersBounds: diff.any + }, { + name: 'text-transform', + type: t.textTransform, + triggersBounds: diff.any + }, { + name: 'text-wrap', + type: t.textWrap, + triggersBounds: diff.any + }, { + name: 'text-overflow-wrap', + type: t.textOverflowWrap, + triggersBounds: diff.any + }, { + name: 'text-max-width', + type: t.size, + triggersBounds: diff.any + }, { + name: 'text-outline-width', + type: t.size, + triggersBounds: diff.any + }, { + name: 'line-height', + type: t.positiveNumber, + triggersBounds: diff.any + }]; + var commonLabel = [{ + name: 'text-valign', + type: t.valign, + triggersBounds: diff.any + }, { + name: 'text-halign', + type: t.halign, + triggersBounds: diff.any + }, { + name: 'color', + type: t.color + }, { + name: 'text-outline-color', + type: t.color + }, { + name: 'text-outline-opacity', + type: t.zeroOneNumber + }, { + name: 'text-background-color', + type: t.color + }, { + name: 'text-background-opacity', + type: t.zeroOneNumber + }, { + name: 'text-background-padding', + type: t.size, + triggersBounds: diff.any + }, { + name: 'text-border-opacity', + type: t.zeroOneNumber + }, { + name: 'text-border-color', + type: t.color + }, { + name: 'text-border-width', + type: t.size, + triggersBounds: diff.any + }, { + name: 'text-border-style', + type: t.borderStyle, + triggersBounds: diff.any + }, { + name: 'text-background-shape', + type: t.textBackgroundShape, + triggersBounds: diff.any + }, { + name: 'text-justification', + type: t.justification + }]; + var behavior = [{ + name: 'events', + type: t.bool, + triggersZOrder: diff.any + }, { + name: 'text-events', + type: t.bool, + triggersZOrder: diff.any + }]; + var visibility = [{ + name: 'display', + type: t.display, + triggersZOrder: diff.any, + triggersBounds: diff.any, + triggersBoundsOfConnectedEdges: true + }, { + name: 'visibility', + type: t.visibility, + triggersZOrder: diff.any + }, { + name: 'opacity', + type: t.zeroOneNumber, + triggersZOrder: diff.zeroNonZero + }, { + name: 'text-opacity', + type: t.zeroOneNumber + }, { + name: 'min-zoomed-font-size', + type: t.size + }, { + name: 'z-compound-depth', + type: t.zCompoundDepth, + triggersZOrder: diff.any + }, { + name: 'z-index-compare', + type: t.zIndexCompare, + triggersZOrder: diff.any + }, { + name: 'z-index', + type: t.number, + triggersZOrder: diff.any + }]; + var overlay = [{ + name: 'overlay-padding', + type: t.size, + triggersBounds: diff.any + }, { + name: 'overlay-color', + type: t.color + }, { + name: 'overlay-opacity', + type: t.zeroOneNumber, + triggersBounds: diff.zeroNonZero + }, { + name: 'overlay-shape', + type: t.overlayShape, + triggersBounds: diff.any + }, { + name: 'overlay-corner-radius', + type: t.cornerRadius + }]; + var underlay = [{ + name: 'underlay-padding', + type: t.size, + triggersBounds: diff.any + }, { + name: 'underlay-color', + type: t.color + }, { + name: 'underlay-opacity', + type: t.zeroOneNumber, + triggersBounds: diff.zeroNonZero + }, { + name: 'underlay-shape', + type: t.overlayShape, + triggersBounds: diff.any + }, { + name: 'underlay-corner-radius', + type: t.cornerRadius + }]; + var transition = [{ + name: 'transition-property', + type: t.propList + }, { + name: 'transition-duration', + type: t.time + }, { + name: 'transition-delay', + type: t.time + }, { + name: 'transition-timing-function', + type: t.easing + }]; + var nodeSizeHashOverride = function nodeSizeHashOverride(ele, parsedProp) { + if (parsedProp.value === 'label') { + return -ele.poolIndex(); // no hash key hits is using label size (hitrate for perf probably low anyway) + } else { + return parsedProp.pfValue; + } + }; + var nodeBody = [{ + name: 'height', + type: t.nodeSize, + triggersBounds: diff.any, + hashOverride: nodeSizeHashOverride + }, { + name: 'width', + type: t.nodeSize, + triggersBounds: diff.any, + hashOverride: nodeSizeHashOverride + }, { + name: 'shape', + type: t.nodeShape, + triggersBounds: diff.any + }, { + name: 'shape-polygon-points', + type: t.polygonPointList, + triggersBounds: diff.any + }, { + name: 'corner-radius', + type: t.cornerRadius + }, { + name: 'background-color', + type: t.color + }, { + name: 'background-fill', + type: t.fill + }, { + name: 'background-opacity', + type: t.zeroOneNumber + }, { + name: 'background-blacken', + type: t.nOneOneNumber + }, { + name: 'background-gradient-stop-colors', + type: t.colors + }, { + name: 'background-gradient-stop-positions', + type: t.percentages + }, { + name: 'background-gradient-direction', + type: t.gradientDirection + }, { + name: 'padding', + type: t.sizeMaybePercent, + triggersBounds: diff.any + }, { + name: 'padding-relative-to', + type: t.paddingRelativeTo, + triggersBounds: diff.any + }, { + name: 'bounds-expansion', + type: t.boundsExpansion, + triggersBounds: diff.any + }]; + var nodeBorder = [{ + name: 'border-color', + type: t.color + }, { + name: 'border-opacity', + type: t.zeroOneNumber + }, { + name: 'border-width', + type: t.size, + triggersBounds: diff.any + }, { + name: 'border-style', + type: t.borderStyle + }, { + name: 'border-cap', + type: t.lineCap + }, { + name: 'border-join', + type: t.lineJoin + }, { + name: 'border-dash-pattern', + type: t.numbers + }, { + name: 'border-dash-offset', + type: t.number + }, { + name: 'border-position', + type: t.linePosition + }]; + var nodeOutline = [{ + name: 'outline-color', + type: t.color + }, { + name: 'outline-opacity', + type: t.zeroOneNumber + }, { + name: 'outline-width', + type: t.size, + triggersBounds: diff.any + }, { + name: 'outline-style', + type: t.borderStyle + }, { + name: 'outline-offset', + type: t.size, + triggersBounds: diff.any + }]; + var backgroundImage = [{ + name: 'background-image', + type: t.urls + }, { + name: 'background-image-crossorigin', + type: t.bgCrossOrigin + }, { + name: 'background-image-opacity', + type: t.zeroOneNumbers + }, { + name: 'background-image-containment', + type: t.bgContainment + }, { + name: 'background-image-smoothing', + type: t.bools + }, { + name: 'background-position-x', + type: t.bgPos + }, { + name: 'background-position-y', + type: t.bgPos + }, { + name: 'background-width-relative-to', + type: t.bgRelativeTo + }, { + name: 'background-height-relative-to', + type: t.bgRelativeTo + }, { + name: 'background-repeat', + type: t.bgRepeat + }, { + name: 'background-fit', + type: t.bgFit + }, { + name: 'background-clip', + type: t.bgClip + }, { + name: 'background-width', + type: t.bgWH + }, { + name: 'background-height', + type: t.bgWH + }, { + name: 'background-offset-x', + type: t.bgPos + }, { + name: 'background-offset-y', + type: t.bgPos + }]; + var compound = [{ + name: 'position', + type: t.position, + triggersBounds: diff.any + }, { + name: 'compound-sizing-wrt-labels', + type: t.compoundIncludeLabels, + triggersBounds: diff.any + }, { + name: 'min-width', + type: t.size, + triggersBounds: diff.any + }, { + name: 'min-width-bias-left', + type: t.sizeMaybePercent, + triggersBounds: diff.any + }, { + name: 'min-width-bias-right', + type: t.sizeMaybePercent, + triggersBounds: diff.any + }, { + name: 'min-height', + type: t.size, + triggersBounds: diff.any + }, { + name: 'min-height-bias-top', + type: t.sizeMaybePercent, + triggersBounds: diff.any + }, { + name: 'min-height-bias-bottom', + type: t.sizeMaybePercent, + triggersBounds: diff.any + }]; + var edgeLine = [{ + name: 'line-style', + type: t.lineStyle + }, { + name: 'line-color', + type: t.color + }, { + name: 'line-fill', + type: t.fill + }, { + name: 'line-cap', + type: t.lineCap + }, { + name: 'line-opacity', + type: t.zeroOneNumber + }, { + name: 'line-dash-pattern', + type: t.numbers + }, { + name: 'line-dash-offset', + type: t.number + }, { + name: 'line-gradient-stop-colors', + type: t.colors + }, { + name: 'line-gradient-stop-positions', + type: t.percentages + }, { + name: 'curve-style', + type: t.curveStyle, + triggersBounds: diff.any, + triggersBoundsOfParallelBeziers: true + }, { + name: 'haystack-radius', + type: t.zeroOneNumber, + triggersBounds: diff.any + }, { + name: 'source-endpoint', + type: t.edgeEndpoint, + triggersBounds: diff.any + }, { + name: 'target-endpoint', + type: t.edgeEndpoint, + triggersBounds: diff.any + }, { + name: 'control-point-step-size', + type: t.size, + triggersBounds: diff.any + }, { + name: 'control-point-distances', + type: t.bidirectionalSizes, + triggersBounds: diff.any + }, { + name: 'control-point-weights', + type: t.numbers, + triggersBounds: diff.any + }, { + name: 'segment-distances', + type: t.bidirectionalSizes, + triggersBounds: diff.any + }, { + name: 'segment-weights', + type: t.numbers, + triggersBounds: diff.any + }, { + name: 'segment-radii', + type: t.numbers, + triggersBounds: diff.any + }, { + name: 'radius-type', + type: t.radiusType, + triggersBounds: diff.any + }, { + name: 'taxi-turn', + type: t.bidirectionalSizeMaybePercent, + triggersBounds: diff.any + }, { + name: 'taxi-turn-min-distance', + type: t.size, + triggersBounds: diff.any + }, { + name: 'taxi-direction', + type: t.axisDirection, + triggersBounds: diff.any + }, { + name: 'taxi-radius', + type: t.number, + triggersBounds: diff.any + }, { + name: 'edge-distances', + type: t.edgeDistances, + triggersBounds: diff.any + }, { + name: 'arrow-scale', + type: t.positiveNumber, + triggersBounds: diff.any + }, { + name: 'loop-direction', + type: t.angle, + triggersBounds: diff.any + }, { + name: 'loop-sweep', + type: t.angle, + triggersBounds: diff.any + }, { + name: 'source-distance-from-node', + type: t.size, + triggersBounds: diff.any + }, { + name: 'target-distance-from-node', + type: t.size, + triggersBounds: diff.any + }]; + var ghost = [{ + name: 'ghost', + type: t.bool, + triggersBounds: diff.any + }, { + name: 'ghost-offset-x', + type: t.bidirectionalSize, + triggersBounds: diff.any + }, { + name: 'ghost-offset-y', + type: t.bidirectionalSize, + triggersBounds: diff.any + }, { + name: 'ghost-opacity', + type: t.zeroOneNumber + }]; + var core = [{ + name: 'selection-box-color', + type: t.color + }, { + name: 'selection-box-opacity', + type: t.zeroOneNumber + }, { + name: 'selection-box-border-color', + type: t.color + }, { + name: 'selection-box-border-width', + type: t.size + }, { + name: 'active-bg-color', + type: t.color + }, { + name: 'active-bg-opacity', + type: t.zeroOneNumber + }, { + name: 'active-bg-size', + type: t.size + }, { + name: 'outside-texture-bg-color', + type: t.color + }, { + name: 'outside-texture-bg-opacity', + type: t.zeroOneNumber + }]; + + // pie backgrounds for nodes + var pie = []; + styfn$2.pieBackgroundN = 16; // because the pie properties are numbered, give access to a constant N (for renderer use) + pie.push({ + name: 'pie-size', + type: t.sizeMaybePercent + }); + for (var i = 1; i <= styfn$2.pieBackgroundN; i++) { + pie.push({ + name: 'pie-' + i + '-background-color', + type: t.color + }); + pie.push({ + name: 'pie-' + i + '-background-size', + type: t.percent + }); + pie.push({ + name: 'pie-' + i + '-background-opacity', + type: t.zeroOneNumber + }); + } - } + // edge arrows + var edgeArrow = []; + var arrowPrefixes = styfn$2.arrowPrefixes = ['source', 'mid-source', 'target', 'mid-target']; + [{ + name: 'arrow-shape', + type: t.arrowShape, + triggersBounds: diff.any + }, { + name: 'arrow-color', + type: t.color + }, { + name: 'arrow-fill', + type: t.arrowFill + }, { + name: 'arrow-width', + type: t.arrowWidth + }].forEach(function (prop) { + arrowPrefixes.forEach(function (prefix) { + var name = prefix + '-' + prop.name; + var type = prop.type, + triggersBounds = prop.triggersBounds; + edgeArrow.push({ + name: name, + type: type, + triggersBounds: triggersBounds + }); + }); + }, {}); + var props = styfn$2.properties = [].concat(behavior, transition, visibility, overlay, underlay, ghost, commonLabel, labelDimensions, mainLabel, sourceLabel, targetLabel, nodeBody, nodeBorder, nodeOutline, backgroundImage, pie, compound, edgeLine, edgeArrow, core); + var propGroups = styfn$2.propertyGroups = { + // common to all eles + behavior: behavior, + transition: transition, + visibility: visibility, + overlay: overlay, + underlay: underlay, + ghost: ghost, + // labels + commonLabel: commonLabel, + labelDimensions: labelDimensions, + mainLabel: mainLabel, + sourceLabel: sourceLabel, + targetLabel: targetLabel, + // node props + nodeBody: nodeBody, + nodeBorder: nodeBorder, + nodeOutline: nodeOutline, + backgroundImage: backgroundImage, + pie: pie, + compound: compound, + // edge props + edgeLine: edgeLine, + edgeArrow: edgeArrow, + core: core + }; + var propGroupNames = styfn$2.propertyGroupNames = {}; + var propGroupKeys = styfn$2.propertyGroupKeys = Object.keys(propGroups); + propGroupKeys.forEach(function (key) { + propGroupNames[key] = propGroups[key].map(function (prop) { + return prop.name; + }); + propGroups[key].forEach(function (prop) { + return prop.groupKey = key; + }); + }); + + // define aliases + var aliases = styfn$2.aliases = [{ + name: 'content', + pointsTo: 'label' + }, { + name: 'control-point-distance', + pointsTo: 'control-point-distances' + }, { + name: 'control-point-weight', + pointsTo: 'control-point-weights' + }, { + name: 'segment-distance', + pointsTo: 'segment-distances' + }, { + name: 'segment-weight', + pointsTo: 'segment-weights' + }, { + name: 'segment-radius', + pointsTo: 'segment-radii' + }, { + name: 'edge-text-rotation', + pointsTo: 'text-rotation' + }, { + name: 'padding-left', + pointsTo: 'padding' + }, { + name: 'padding-right', + pointsTo: 'padding' + }, { + name: 'padding-top', + pointsTo: 'padding' + }, { + name: 'padding-bottom', + pointsTo: 'padding' + }]; + + // list of property names + styfn$2.propertyNames = props.map(function (p) { + return p.name; + }); + + // allow access of properties by name ( e.g. style.properties.height ) + for (var _i = 0; _i < props.length; _i++) { + var prop = props[_i]; + props[prop.name] = prop; // allow lookup by name + } - class Color { + // map aliases + for (var _i2 = 0; _i2 < aliases.length; _i2++) { + var alias = aliases[_i2]; + var pointsToProp = props[alias.pointsTo]; + var aliasProp = { + name: alias.name, + alias: true, + pointsTo: pointsToProp + }; - constructor( r, g, b ) { + // add alias prop for parsing + props.push(aliasProp); + props[alias.name] = aliasProp; // allow lookup by name + } + })(); - this.isColor = true; + styfn$2.getDefaultProperty = function (name) { + return this.getDefaultProperties()[name]; + }; + styfn$2.getDefaultProperties = function () { + var _p = this._private; + if (_p.defaultProperties != null) { + return _p.defaultProperties; + } + var rawProps = extend$1({ + // core props + 'selection-box-color': '#ddd', + 'selection-box-opacity': 0.65, + 'selection-box-border-color': '#aaa', + 'selection-box-border-width': 1, + 'active-bg-color': 'black', + 'active-bg-opacity': 0.15, + 'active-bg-size': 30, + 'outside-texture-bg-color': '#000', + 'outside-texture-bg-opacity': 0.125, + // common node/edge props + 'events': 'yes', + 'text-events': 'no', + 'text-valign': 'top', + 'text-halign': 'center', + 'text-justification': 'auto', + 'line-height': 1, + 'color': '#000', + 'text-outline-color': '#000', + 'text-outline-width': 0, + 'text-outline-opacity': 1, + 'text-opacity': 1, + 'text-decoration': 'none', + 'text-transform': 'none', + 'text-wrap': 'none', + 'text-overflow-wrap': 'whitespace', + 'text-max-width': 9999, + 'text-background-color': '#000', + 'text-background-opacity': 0, + 'text-background-shape': 'rectangle', + 'text-background-padding': 0, + 'text-border-opacity': 0, + 'text-border-width': 0, + 'text-border-style': 'solid', + 'text-border-color': '#000', + 'font-family': 'Helvetica Neue, Helvetica, sans-serif', + 'font-style': 'normal', + 'font-weight': 'normal', + 'font-size': 16, + 'min-zoomed-font-size': 0, + 'text-rotation': 'none', + 'source-text-rotation': 'none', + 'target-text-rotation': 'none', + 'visibility': 'visible', + 'display': 'element', + 'opacity': 1, + 'z-compound-depth': 'auto', + 'z-index-compare': 'auto', + 'z-index': 0, + 'label': '', + 'text-margin-x': 0, + 'text-margin-y': 0, + 'source-label': '', + 'source-text-offset': 0, + 'source-text-margin-x': 0, + 'source-text-margin-y': 0, + 'target-label': '', + 'target-text-offset': 0, + 'target-text-margin-x': 0, + 'target-text-margin-y': 0, + 'overlay-opacity': 0, + 'overlay-color': '#000', + 'overlay-padding': 10, + 'overlay-shape': 'round-rectangle', + 'overlay-corner-radius': 'auto', + 'underlay-opacity': 0, + 'underlay-color': '#000', + 'underlay-padding': 10, + 'underlay-shape': 'round-rectangle', + 'underlay-corner-radius': 'auto', + 'transition-property': 'none', + 'transition-duration': 0, + 'transition-delay': 0, + 'transition-timing-function': 'linear', + // node props + 'background-blacken': 0, + 'background-color': '#999', + 'background-fill': 'solid', + 'background-opacity': 1, + 'background-image': 'none', + 'background-image-crossorigin': 'anonymous', + 'background-image-opacity': 1, + 'background-image-containment': 'inside', + 'background-image-smoothing': 'yes', + 'background-position-x': '50%', + 'background-position-y': '50%', + 'background-offset-x': 0, + 'background-offset-y': 0, + 'background-width-relative-to': 'include-padding', + 'background-height-relative-to': 'include-padding', + 'background-repeat': 'no-repeat', + 'background-fit': 'none', + 'background-clip': 'node', + 'background-width': 'auto', + 'background-height': 'auto', + 'border-color': '#000', + 'border-opacity': 1, + 'border-width': 0, + 'border-style': 'solid', + 'border-dash-pattern': [4, 2], + 'border-dash-offset': 0, + 'border-cap': 'butt', + 'border-join': 'miter', + 'border-position': 'center', + 'outline-color': '#999', + 'outline-opacity': 1, + 'outline-width': 0, + 'outline-offset': 0, + 'outline-style': 'solid', + 'height': 30, + 'width': 30, + 'shape': 'ellipse', + 'shape-polygon-points': '-1, -1, 1, -1, 1, 1, -1, 1', + 'corner-radius': 'auto', + 'bounds-expansion': 0, + // node gradient + 'background-gradient-direction': 'to-bottom', + 'background-gradient-stop-colors': '#999', + 'background-gradient-stop-positions': '0%', + // ghost props + 'ghost': 'no', + 'ghost-offset-y': 0, + 'ghost-offset-x': 0, + 'ghost-opacity': 0, + // compound props + 'padding': 0, + 'padding-relative-to': 'width', + 'position': 'origin', + 'compound-sizing-wrt-labels': 'include', + 'min-width': 0, + 'min-width-bias-left': 0, + 'min-width-bias-right': 0, + 'min-height': 0, + 'min-height-bias-top': 0, + 'min-height-bias-bottom': 0 + }, { + // node pie bg + 'pie-size': '100%' + }, [{ + name: 'pie-{{i}}-background-color', + value: 'black' + }, { + name: 'pie-{{i}}-background-size', + value: '0%' + }, { + name: 'pie-{{i}}-background-opacity', + value: 1 + }].reduce(function (css, prop) { + for (var i = 1; i <= styfn$2.pieBackgroundN; i++) { + var name = prop.name.replace('{{i}}', i); + var val = prop.value; + css[name] = val; + } + return css; + }, {}), { + // edge props + 'line-style': 'solid', + 'line-color': '#999', + 'line-fill': 'solid', + 'line-cap': 'butt', + 'line-opacity': 1, + 'line-gradient-stop-colors': '#999', + 'line-gradient-stop-positions': '0%', + 'control-point-step-size': 40, + 'control-point-weights': 0.5, + 'segment-weights': 0.5, + 'segment-distances': 20, + 'segment-radii': 15, + 'radius-type': 'arc-radius', + 'taxi-turn': '50%', + 'taxi-radius': 15, + 'taxi-turn-min-distance': 10, + 'taxi-direction': 'auto', + 'edge-distances': 'intersection', + 'curve-style': 'haystack', + 'haystack-radius': 0, + 'arrow-scale': 1, + 'loop-direction': '-45deg', + 'loop-sweep': '-90deg', + 'source-distance-from-node': 0, + 'target-distance-from-node': 0, + 'source-endpoint': 'outside-to-node', + 'target-endpoint': 'outside-to-node', + 'line-dash-pattern': [6, 3], + 'line-dash-offset': 0 + }, [{ + name: 'arrow-shape', + value: 'none' + }, { + name: 'arrow-color', + value: '#999' + }, { + name: 'arrow-fill', + value: 'filled' + }, { + name: 'arrow-width', + value: 1 + }].reduce(function (css, prop) { + styfn$2.arrowPrefixes.forEach(function (prefix) { + var name = prefix + '-' + prop.name; + var val = prop.value; + css[name] = val; + }); + return css; + }, {})); + var parsedProps = {}; + for (var i = 0; i < this.properties.length; i++) { + var prop = this.properties[i]; + if (prop.pointsTo) { + continue; + } + var name = prop.name; + var val = rawProps[name]; + var parsedProp = this.parse(name, val); + parsedProps[name] = parsedProp; + } + _p.defaultProperties = parsedProps; + return _p.defaultProperties; + }; + styfn$2.addDefaultStylesheet = function () { + this.selector(':parent').css({ + 'shape': 'rectangle', + 'padding': 10, + 'background-color': '#eee', + 'border-color': '#ccc', + 'border-width': 1 + }).selector('edge').css({ + 'width': 3 + }).selector(':loop').css({ + 'curve-style': 'bezier' + }).selector('edge:compound').css({ + 'curve-style': 'bezier', + 'source-endpoint': 'outside-to-line', + 'target-endpoint': 'outside-to-line' + }).selector(':selected').css({ + 'background-color': '#0169D9', + 'line-color': '#0169D9', + 'source-arrow-color': '#0169D9', + 'target-arrow-color': '#0169D9', + 'mid-source-arrow-color': '#0169D9', + 'mid-target-arrow-color': '#0169D9' + }).selector(':parent:selected').css({ + 'background-color': '#CCE1F9', + 'border-color': '#aec8e5' + }).selector(':active').css({ + 'overlay-color': 'black', + 'overlay-padding': 10, + 'overlay-opacity': 0.25 + }); + this.defaultLength = this.length; + }; - this.r = 1; - this.g = 1; - this.b = 1; + var styfn$1 = {}; - if ( g === undefined && b === undefined ) { + // a caching layer for property parsing + styfn$1.parse = function (name, value, propIsBypass, propIsFlat) { + var self = this; - // r is THREE.Color, hex or string - return this.set( r ); + // function values can't be cached in all cases, and there isn't much benefit of caching them anyway + if (fn$6(value)) { + return self.parseImplWarn(name, value, propIsBypass, propIsFlat); + } + var flatKey = propIsFlat === 'mapping' || propIsFlat === true || propIsFlat === false || propIsFlat == null ? 'dontcare' : propIsFlat; + var bypassKey = propIsBypass ? 't' : 'f'; + var valueKey = '' + value; + var argHash = hashStrings(name, valueKey, bypassKey, flatKey); + var propCache = self.propCache = self.propCache || []; + var ret; + if (!(ret = propCache[argHash])) { + ret = propCache[argHash] = self.parseImplWarn(name, value, propIsBypass, propIsFlat); + } - } + // - bypasses can't be shared b/c the value can be changed by animations or otherwise overridden + // - mappings can't be shared b/c mappings are per-element + if (propIsBypass || propIsFlat === 'mapping') { + // need a copy since props are mutated later in their lifecycles + ret = copy(ret); + if (ret) { + ret.value = copy(ret.value); // because it could be an array, e.g. colour + } + } - return this.setRGB( r, g, b ); + return ret; + }; + styfn$1.parseImplWarn = function (name, value, propIsBypass, propIsFlat) { + var prop = this.parseImpl(name, value, propIsBypass, propIsFlat); + if (!prop && value != null) { + warn("The style property `".concat(name, ": ").concat(value, "` is invalid")); + } + if (prop && (prop.name === 'width' || prop.name === 'height') && value === 'label') { + warn('The style value of `label` is deprecated for `' + prop.name + '`'); + } + return prop; + }; - } + // parse a property; return null on invalid; return parsed property otherwise + // fields : + // - name : the name of the property + // - value : the parsed, native-typed value of the property + // - strValue : a string value that represents the property value in valid css + // - bypass : true iff the property is a bypass property + styfn$1.parseImpl = function (name, value, propIsBypass, propIsFlat) { + var self = this; + name = camel2dash(name); // make sure the property name is in dash form (e.g. 'property-name' not 'propertyName') + + var property = self.properties[name]; + var passedValue = value; + var types = self.types; + if (!property) { + return null; + } // return null on property of unknown name + if (value === undefined) { + return null; + } // can't assign undefined + + // the property may be an alias + if (property.alias) { + property = property.pointsTo; + name = property.name; + } + var valueIsString = string(value); + if (valueIsString) { + // trim the value to make parsing easier + value = value.trim(); + } + var type = property.type; + if (!type) { + return null; + } // no type, no luck + + // check if bypass is null or empty string (i.e. indication to delete bypass property) + if (propIsBypass && (value === '' || value === null)) { + return { + name: name, + value: value, + bypass: true, + deleteBypass: true + }; + } - set( value ) { + // check if value is a function used as a mapper + if (fn$6(value)) { + return { + name: name, + value: value, + strValue: 'fn', + mapped: types.fn, + bypass: propIsBypass + }; + } - if ( value && value.isColor ) { + // check if value is mapped + var data, mapData; + if (!valueIsString || propIsFlat || value.length < 7 || value[1] !== 'a') ; else if (value.length >= 7 && value[0] === 'd' && (data = new RegExp(types.data.regex).exec(value))) { + if (propIsBypass) { + return false; + } // mappers not allowed in bypass + + var mapped = types.data; + return { + name: name, + value: data, + strValue: '' + value, + mapped: mapped, + field: data[1], + bypass: propIsBypass + }; + } else if (value.length >= 10 && value[0] === 'm' && (mapData = new RegExp(types.mapData.regex).exec(value))) { + if (propIsBypass) { + return false; + } // mappers not allowed in bypass + if (type.multiple) { + return false; + } // impossible to map to num + + var _mapped = types.mapData; + + // we can map only if the type is a colour or a number + if (!(type.color || type.number)) { + return false; + } + var valueMin = this.parse(name, mapData[4]); // parse to validate + if (!valueMin || valueMin.mapped) { + return false; + } // can't be invalid or mapped + + var valueMax = this.parse(name, mapData[5]); // parse to validate + if (!valueMax || valueMax.mapped) { + return false; + } // can't be invalid or mapped + + // check if valueMin and valueMax are the same + if (valueMin.pfValue === valueMax.pfValue || valueMin.strValue === valueMax.strValue) { + warn('`' + name + ': ' + value + '` is not a valid mapper because the output range is zero; converting to `' + name + ': ' + valueMin.strValue + '`'); + return this.parse(name, valueMin.strValue); // can't make much of a mapper without a range + } else if (type.color) { + var c1 = valueMin.value; + var c2 = valueMax.value; + var same = c1[0] === c2[0] // red + && c1[1] === c2[1] // green + && c1[2] === c2[2] // blue + && ( + // optional alpha + c1[3] === c2[3] // same alpha outright + || (c1[3] == null || c1[3] === 1 // full opacity for colour 1? + ) && (c2[3] == null || c2[3] === 1) // full opacity for colour 2? + ); + + if (same) { + return false; + } // can't make a mapper without a range + } - this.copy( value ); + return { + name: name, + value: mapData, + strValue: '' + value, + mapped: _mapped, + field: mapData[1], + fieldMin: parseFloat(mapData[2]), + // min & max are numeric + fieldMax: parseFloat(mapData[3]), + valueMin: valueMin.value, + valueMax: valueMax.value, + bypass: propIsBypass + }; + } + if (type.multiple && propIsFlat !== 'multiple') { + var vals; + if (valueIsString) { + vals = value.split(/\s+/); + } else if (array(value)) { + vals = value; + } else { + vals = [value]; + } + if (type.evenMultiple && vals.length % 2 !== 0) { + return null; + } + var valArr = []; + var unitsArr = []; + var pfValArr = []; + var strVal = ''; + var hasEnum = false; + for (var i = 0; i < vals.length; i++) { + var p = self.parse(name, vals[i], propIsBypass, 'multiple'); + hasEnum = hasEnum || string(p.value); + valArr.push(p.value); + pfValArr.push(p.pfValue != null ? p.pfValue : p.value); + unitsArr.push(p.units); + strVal += (i > 0 ? ' ' : '') + p.strValue; + } + if (type.validate && !type.validate(valArr, unitsArr)) { + return null; + } + if (type.singleEnum && hasEnum) { + if (valArr.length === 1 && string(valArr[0])) { + return { + name: name, + value: valArr[0], + strValue: valArr[0], + bypass: propIsBypass + }; + } else { + return null; + } + } + return { + name: name, + value: valArr, + pfValue: pfValArr, + strValue: strVal, + bypass: propIsBypass, + units: unitsArr + }; + } - } else if ( typeof value === 'number' ) { + // several types also allow enums + var checkEnums = function checkEnums() { + for (var _i = 0; _i < type.enums.length; _i++) { + var en = type.enums[_i]; + if (en === value) { + return { + name: name, + value: value, + strValue: '' + value, + bypass: propIsBypass + }; + } + } + return null; + }; - this.setHex( value ); + // check the type and return the appropriate object + if (type.number) { + var units; + var implicitUnits = 'px'; // not set => px - } else if ( typeof value === 'string' ) { + if (type.units) { + // use specified units if set + units = type.units; + } + if (type.implicitUnits) { + implicitUnits = type.implicitUnits; + } + if (!type.unitless) { + if (valueIsString) { + var unitsRegex = 'px|em' + (type.allowPercent ? '|\\%' : ''); + if (units) { + unitsRegex = units; + } // only allow explicit units if so set + var match = value.match('^(' + number + ')(' + unitsRegex + ')?' + '$'); + if (match) { + value = match[1]; + units = match[2] || implicitUnits; + } + } else if (!units || type.implicitUnits) { + units = implicitUnits; // implicitly px if unspecified + } + } - this.setStyle( value ); + value = parseFloat(value); - } + // if not a number and enums not allowed, then the value is invalid + if (isNaN(value) && type.enums === undefined) { + return null; + } - return this; + // check if this number type also accepts special keywords in place of numbers + // (i.e. `left`, `auto`, etc) + if (isNaN(value) && type.enums !== undefined) { + value = passedValue; + return checkEnums(); + } - } + // check if value must be an integer + if (type.integer && !integer(value)) { + return null; + } - setScalar( scalar ) { + // check value is within range + if (type.min !== undefined && (value < type.min || type.strictMin && value === type.min) || type.max !== undefined && (value > type.max || type.strictMax && value === type.max)) { + return null; + } + var ret = { + name: name, + value: value, + strValue: '' + value + (units ? units : ''), + units: units, + bypass: propIsBypass + }; - this.r = scalar; - this.g = scalar; - this.b = scalar; + // normalise value in pixels + if (type.unitless || units !== 'px' && units !== 'em') { + ret.pfValue = value; + } else { + ret.pfValue = units === 'px' || !units ? value : this.getEmSizeInPixels() * value; + } - return this; + // normalise value in ms + if (units === 'ms' || units === 's') { + ret.pfValue = units === 'ms' ? value : 1000 * value; + } - } + // normalise value in rad + if (units === 'deg' || units === 'rad') { + ret.pfValue = units === 'rad' ? value : deg2rad(value); + } - setHex( hex, colorSpace = SRGBColorSpace ) { + // normalize value in % + if (units === '%') { + ret.pfValue = value / 100; + } + return ret; + } else if (type.propList) { + var props = []; + var propsStr = '' + value; + if (propsStr === 'none') ; else { + // go over each prop + + var propsSplit = propsStr.split(/\s*,\s*|\s+/); + for (var _i2 = 0; _i2 < propsSplit.length; _i2++) { + var propName = propsSplit[_i2].trim(); + if (self.properties[propName]) { + props.push(propName); + } else { + warn('`' + propName + '` is not a valid property name'); + } + } + if (props.length === 0) { + return null; + } + } + return { + name: name, + value: props, + strValue: props.length === 0 ? 'none' : props.join(' '), + bypass: propIsBypass + }; + } else if (type.color) { + var tuple = color2tuple(value); + if (!tuple) { + return null; + } + return { + name: name, + value: tuple, + pfValue: tuple, + strValue: 'rgb(' + tuple[0] + ',' + tuple[1] + ',' + tuple[2] + ')', + // n.b. no spaces b/c of multiple support + bypass: propIsBypass + }; + } else if (type.regex || type.regexes) { + // first check enums + if (type.enums) { + var enumProp = checkEnums(); + if (enumProp) { + return enumProp; + } + } + var regexes = type.regexes ? type.regexes : [type.regex]; + for (var _i3 = 0; _i3 < regexes.length; _i3++) { + var regex = new RegExp(regexes[_i3]); // make a regex from the type string + var m = regex.exec(value); + if (m) { + // regex matches + return { + name: name, + value: type.singleRegexMatchValue ? m[1] : m, + strValue: '' + value, + bypass: propIsBypass + }; + } + } + return null; // didn't match any + } else if (type.string) { + // just return + return { + name: name, + value: '' + value, + strValue: '' + value, + bypass: propIsBypass + }; + } else if (type.enums) { + // check enums last because it's a combo type in others + return checkEnums(); + } else { + return null; // not a type we can handle + } + }; - hex = Math.floor( hex ); + var Style = function Style(cy) { + if (!(this instanceof Style)) { + return new Style(cy); + } + if (!core$1(cy)) { + error('A style must have a core reference'); + return; + } + this._private = { + cy: cy, + coreStyle: {} + }; + this.length = 0; + this.resetToDefault(); + }; + var styfn = Style.prototype; + styfn.instanceString = function () { + return 'style'; + }; - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + // remove all contexts + styfn.clear = function () { + var _p = this._private; + var cy = _p.cy; + var eles = cy.elements(); + for (var i = 0; i < this.length; i++) { + this[i] = undefined; + } + this.length = 0; + _p.contextStyles = {}; + _p.propDiffs = {}; + this.cleanElements(eles, true); + eles.forEach(function (ele) { + var ele_p = ele[0]._private; + ele_p.styleDirty = true; + ele_p.appliedInitStyle = false; + }); + return this; // chaining + }; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + styfn.resetToDefault = function () { + this.clear(); + this.addDefaultStylesheet(); + return this; + }; - return this; + // builds a style object for the 'core' selector + styfn.core = function (propName) { + return this._private.coreStyle[propName] || this.getDefaultProperty(propName); + }; - } + // create a new context from the specified selector string and switch to that context + styfn.selector = function (selectorStr) { + // 'core' is a special case and does not need a selector + var selector = selectorStr === 'core' ? null : new Selector(selectorStr); + var i = this.length++; // new context means new index + this[i] = { + selector: selector, + properties: [], + mappedProperties: [], + index: i + }; + return this; // chaining + }; - setRGB( r, g, b, colorSpace = LinearSRGBColorSpace ) { + // add one or many css rules to the current context + styfn.css = function () { + var self = this; + var args = arguments; + if (args.length === 1) { + var map = args[0]; + for (var i = 0; i < self.properties.length; i++) { + var prop = self.properties[i]; + var mapVal = map[prop.name]; + if (mapVal === undefined) { + mapVal = map[dash2camel(prop.name)]; + } + if (mapVal !== undefined) { + this.cssRule(prop.name, mapVal); + } + } + } else if (args.length === 2) { + this.cssRule(args[0], args[1]); + } - this.r = r; - this.g = g; - this.b = b; + // do nothing if args are invalid - ColorManagement.toWorkingColorSpace( this, colorSpace ); + return this; // chaining + }; - return this; + styfn.style = styfn.css; - } + // add a single css rule to the current context + styfn.cssRule = function (name, value) { + // name-value pair + var property = this.parse(name, value); - setHSL( h, s, l, colorSpace = LinearSRGBColorSpace ) { + // add property to current context if valid + if (property) { + var i = this.length - 1; + this[i].properties.push(property); + this[i].properties[property.name] = property; // allow access by name as well - // h,s,l ranges are in 0.0 - 1.0 - h = euclideanModulo( h, 1 ); - s = clamp( s, 0, 1 ); - l = clamp( l, 0, 1 ); + if (property.name.match(/pie-(\d+)-background-size/) && property.value) { + this._private.hasPie = true; + } + if (property.mapped) { + this[i].mappedProperties.push(property); + } - if ( s === 0 ) { + // add to core style if necessary + var currentSelectorIsCore = !this[i].selector; + if (currentSelectorIsCore) { + this._private.coreStyle[property.name] = property; + } + } + return this; // chaining + }; - this.r = this.g = this.b = l; + styfn.append = function (style) { + if (stylesheet(style)) { + style.appendToStyle(this); + } else if (array(style)) { + this.appendFromJson(style); + } else if (string(style)) { + this.appendFromString(style); + } // you probably wouldn't want to append a Style, since you'd duplicate the default parts - } else { + return this; + }; - const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - const q = ( 2 * l ) - p; - - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); - - } + // static function + Style.fromJson = function (cy, json) { + var style = new Style(cy); + style.fromJson(json); + return style; + }; + Style.fromString = function (cy, string) { + return new Style(cy).fromString(string); + }; + [styfn$8, styfn$7, styfn$6, styfn$5, styfn$4, styfn$3, styfn$2, styfn$1].forEach(function (props) { + extend$1(styfn, props); + }); + Style.types = styfn.types; + Style.properties = styfn.properties; + Style.propertyGroups = styfn.propertyGroups; + Style.propertyGroupNames = styfn.propertyGroupNames; + Style.propertyGroupKeys = styfn.propertyGroupKeys; + + var corefn$2 = { + style: function style(newStyle) { + if (newStyle) { + var s = this.setStyle(newStyle); + s.update(); + } + return this._private.style; + }, + setStyle: function setStyle(style) { + var _p = this._private; + if (stylesheet(style)) { + _p.style = style.generateStyle(this); + } else if (array(style)) { + _p.style = Style.fromJson(this, style); + } else if (string(style)) { + _p.style = Style.fromString(this, style); + } else { + _p.style = Style(this); + } + return _p.style; + }, + // e.g. cy.data() changed => recalc ele mappers + updateStyle: function updateStyle() { + this.mutableElements().updateStyle(); // just send to all eles + } + }; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + var defaultSelectionType = 'single'; + var corefn$1 = { + autolock: function autolock(bool) { + if (bool !== undefined) { + this._private.autolock = bool ? true : false; + } else { + return this._private.autolock; + } + return this; // chaining + }, + + autoungrabify: function autoungrabify(bool) { + if (bool !== undefined) { + this._private.autoungrabify = bool ? true : false; + } else { + return this._private.autoungrabify; + } + return this; // chaining + }, + + autounselectify: function autounselectify(bool) { + if (bool !== undefined) { + this._private.autounselectify = bool ? true : false; + } else { + return this._private.autounselectify; + } + return this; // chaining + }, - return this; + selectionType: function selectionType(selType) { + var _p = this._private; + if (_p.selectionType == null) { + _p.selectionType = defaultSelectionType; + } + if (selType !== undefined) { + if (selType === 'additive' || selType === 'single') { + _p.selectionType = selType; + } + } else { + return _p.selectionType; + } + return this; + }, + panningEnabled: function panningEnabled(bool) { + if (bool !== undefined) { + this._private.panningEnabled = bool ? true : false; + } else { + return this._private.panningEnabled; + } + return this; // chaining + }, + + userPanningEnabled: function userPanningEnabled(bool) { + if (bool !== undefined) { + this._private.userPanningEnabled = bool ? true : false; + } else { + return this._private.userPanningEnabled; + } + return this; // chaining + }, + + zoomingEnabled: function zoomingEnabled(bool) { + if (bool !== undefined) { + this._private.zoomingEnabled = bool ? true : false; + } else { + return this._private.zoomingEnabled; + } + return this; // chaining + }, + + userZoomingEnabled: function userZoomingEnabled(bool) { + if (bool !== undefined) { + this._private.userZoomingEnabled = bool ? true : false; + } else { + return this._private.userZoomingEnabled; + } + return this; // chaining + }, + + boxSelectionEnabled: function boxSelectionEnabled(bool) { + if (bool !== undefined) { + this._private.boxSelectionEnabled = bool ? true : false; + } else { + return this._private.boxSelectionEnabled; + } + return this; // chaining + }, + + pan: function pan() { + var args = arguments; + var pan = this._private.pan; + var dim, val, dims, x, y; + switch (args.length) { + case 0: + // .pan() + return pan; + case 1: + if (string(args[0])) { + // .pan('x') + dim = args[0]; + return pan[dim]; + } else if (plainObject(args[0])) { + // .pan({ x: 0, y: 100 }) + if (!this._private.panningEnabled) { + return this; + } + dims = args[0]; + x = dims.x; + y = dims.y; + if (number$1(x)) { + pan.x = x; + } + if (number$1(y)) { + pan.y = y; + } + this.emit('pan viewport'); + } + break; + case 2: + // .pan('x', 100) + if (!this._private.panningEnabled) { + return this; + } + dim = args[0]; + val = args[1]; + if ((dim === 'x' || dim === 'y') && number$1(val)) { + pan[dim] = val; + } + this.emit('pan viewport'); + break; + // invalid + } - } + this.notify('viewport'); + return this; // chaining + }, - setStyle( style, colorSpace = SRGBColorSpace ) { + panBy: function panBy(arg0, arg1) { + var args = arguments; + var pan = this._private.pan; + var dim, val, dims, x, y; + if (!this._private.panningEnabled) { + return this; + } + switch (args.length) { + case 1: + if (plainObject(arg0)) { + // .panBy({ x: 0, y: 100 }) + dims = args[0]; + x = dims.x; + y = dims.y; + if (number$1(x)) { + pan.x += x; + } + if (number$1(y)) { + pan.y += y; + } + this.emit('pan viewport'); + } + break; + case 2: + // .panBy('x', 100) + dim = arg0; + val = arg1; + if ((dim === 'x' || dim === 'y') && number$1(val)) { + pan[dim] += val; + } + this.emit('pan viewport'); + break; + // invalid + } - function handleAlpha( string ) { + this.notify('viewport'); + return this; // chaining + }, + + fit: function fit(elements, padding) { + var viewportState = this.getFitViewport(elements, padding); + if (viewportState) { + var _p = this._private; + _p.zoom = viewportState.zoom; + _p.pan = viewportState.pan; + this.emit('pan zoom viewport'); + this.notify('viewport'); + } + return this; // chaining + }, + + getFitViewport: function getFitViewport(elements, padding) { + if (number$1(elements) && padding === undefined) { + // elements is optional + padding = elements; + elements = undefined; + } + if (!this._private.panningEnabled || !this._private.zoomingEnabled) { + return; + } + var bb; + if (string(elements)) { + var sel = elements; + elements = this.$(sel); + } else if (boundingBox(elements)) { + // assume bb + var bbe = elements; + bb = { + x1: bbe.x1, + y1: bbe.y1, + x2: bbe.x2, + y2: bbe.y2 + }; + bb.w = bb.x2 - bb.x1; + bb.h = bb.y2 - bb.y1; + } else if (!elementOrCollection(elements)) { + elements = this.mutableElements(); + } + if (elementOrCollection(elements) && elements.empty()) { + return; + } // can't fit to nothing + + bb = bb || elements.boundingBox(); + var w = this.width(); + var h = this.height(); + var zoom; + padding = number$1(padding) ? padding : 0; + if (!isNaN(w) && !isNaN(h) && w > 0 && h > 0 && !isNaN(bb.w) && !isNaN(bb.h) && bb.w > 0 && bb.h > 0) { + zoom = Math.min((w - 2 * padding) / bb.w, (h - 2 * padding) / bb.h); + + // crop zoom + zoom = zoom > this._private.maxZoom ? this._private.maxZoom : zoom; + zoom = zoom < this._private.minZoom ? this._private.minZoom : zoom; + var pan = { + // now pan to middle + x: (w - zoom * (bb.x1 + bb.x2)) / 2, + y: (h - zoom * (bb.y1 + bb.y2)) / 2 + }; + return { + zoom: zoom, + pan: pan + }; + } + return; + }, + zoomRange: function zoomRange(min, max) { + var _p = this._private; + if (max == null) { + var opts = min; + min = opts.min; + max = opts.max; + } + if (number$1(min) && number$1(max) && min <= max) { + _p.minZoom = min; + _p.maxZoom = max; + } else if (number$1(min) && max === undefined && min <= _p.maxZoom) { + _p.minZoom = min; + } else if (number$1(max) && min === undefined && max >= _p.minZoom) { + _p.maxZoom = max; + } + return this; + }, + minZoom: function minZoom(zoom) { + if (zoom === undefined) { + return this._private.minZoom; + } else { + return this.zoomRange({ + min: zoom + }); + } + }, + maxZoom: function maxZoom(zoom) { + if (zoom === undefined) { + return this._private.maxZoom; + } else { + return this.zoomRange({ + max: zoom + }); + } + }, + getZoomedViewport: function getZoomedViewport(params) { + var _p = this._private; + var currentPan = _p.pan; + var currentZoom = _p.zoom; + var pos; // in rendered px + var zoom; + var bail = false; + if (!_p.zoomingEnabled) { + // zooming disabled + bail = true; + } + if (number$1(params)) { + // then set the zoom + zoom = params; + } else if (plainObject(params)) { + // then zoom about a point + zoom = params.level; + if (params.position != null) { + pos = modelToRenderedPosition(params.position, currentZoom, currentPan); + } else if (params.renderedPosition != null) { + pos = params.renderedPosition; + } + if (pos != null && !_p.panningEnabled) { + // panning disabled + bail = true; + } + } - if ( string === undefined ) return; + // crop zoom + zoom = zoom > _p.maxZoom ? _p.maxZoom : zoom; + zoom = zoom < _p.minZoom ? _p.minZoom : zoom; - if ( parseFloat( string ) < 1 ) { + // can't zoom with invalid params + if (bail || !number$1(zoom) || zoom === currentZoom || pos != null && (!number$1(pos.x) || !number$1(pos.y))) { + return null; + } + if (pos != null) { + // set zoom about position + var pan1 = currentPan; + var zoom1 = currentZoom; + var zoom2 = zoom; + var pan2 = { + x: -zoom2 / zoom1 * (pos.x - pan1.x) + pos.x, + y: -zoom2 / zoom1 * (pos.y - pan1.y) + pos.y + }; + return { + zoomed: true, + panned: true, + zoom: zoom2, + pan: pan2 + }; + } else { + // just set the zoom + return { + zoomed: true, + panned: false, + zoom: zoom, + pan: currentPan + }; + } + }, + zoom: function zoom(params) { + if (params === undefined) { + // get + return this._private.zoom; + } else { + // set + var vp = this.getZoomedViewport(params); + var _p = this._private; + if (vp == null || !vp.zoomed) { + return this; + } + _p.zoom = vp.zoom; + if (vp.panned) { + _p.pan.x = vp.pan.x; + _p.pan.y = vp.pan.y; + } + this.emit('zoom' + (vp.panned ? ' pan' : '') + ' viewport'); + this.notify('viewport'); + return this; // chaining + } + }, + + viewport: function viewport(opts) { + var _p = this._private; + var zoomDefd = true; + var panDefd = true; + var events = []; // to trigger + var zoomFailed = false; + var panFailed = false; + if (!opts) { + return this; + } + if (!number$1(opts.zoom)) { + zoomDefd = false; + } + if (!plainObject(opts.pan)) { + panDefd = false; + } + if (!zoomDefd && !panDefd) { + return this; + } + if (zoomDefd) { + var z = opts.zoom; + if (z < _p.minZoom || z > _p.maxZoom || !_p.zoomingEnabled) { + zoomFailed = true; + } else { + _p.zoom = z; + events.push('zoom'); + } + } + if (panDefd && (!zoomFailed || !opts.cancelOnFailedZoom) && _p.panningEnabled) { + var p = opts.pan; + if (number$1(p.x)) { + _p.pan.x = p.x; + panFailed = false; + } + if (number$1(p.y)) { + _p.pan.y = p.y; + panFailed = false; + } + if (!panFailed) { + events.push('pan'); + } + } + if (events.length > 0) { + events.push('viewport'); + this.emit(events.join(' ')); + this.notify('viewport'); + } + return this; // chaining + }, + + center: function center(elements) { + var pan = this.getCenterPan(elements); + if (pan) { + this._private.pan = pan; + this.emit('pan viewport'); + this.notify('viewport'); + } + return this; // chaining + }, - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + getCenterPan: function getCenterPan(elements, zoom) { + if (!this._private.panningEnabled) { + return; + } + if (string(elements)) { + var selector = elements; + elements = this.mutableElements().filter(selector); + } else if (!elementOrCollection(elements)) { + elements = this.mutableElements(); + } + if (elements.length === 0) { + return; + } // can't centre pan to nothing + + var bb = elements.boundingBox(); + var w = this.width(); + var h = this.height(); + zoom = zoom === undefined ? this._private.zoom : zoom; + var pan = { + // middle + x: (w - zoom * (bb.x1 + bb.x2)) / 2, + y: (h - zoom * (bb.y1 + bb.y2)) / 2 + }; + return pan; + }, + reset: function reset() { + if (!this._private.panningEnabled || !this._private.zoomingEnabled) { + return this; + } + this.viewport({ + pan: { + x: 0, + y: 0 + }, + zoom: 1 + }); + return this; // chaining + }, + + invalidateSize: function invalidateSize() { + this._private.sizeCache = null; + }, + size: function size() { + var _p = this._private; + var container = _p.container; + var cy = this; + return _p.sizeCache = _p.sizeCache || (container ? function () { + var style = cy.window().getComputedStyle(container); + var val = function val(name) { + return parseFloat(style.getPropertyValue(name)); + }; + return { + width: container.clientWidth - val('padding-left') - val('padding-right'), + height: container.clientHeight - val('padding-top') - val('padding-bottom') + }; + }() : { + // fallback if no container (not 0 b/c can be used for dividing etc) + width: 1, + height: 1 + }); + }, + width: function width() { + return this.size().width; + }, + height: function height() { + return this.size().height; + }, + extent: function extent() { + var pan = this._private.pan; + var zoom = this._private.zoom; + var rb = this.renderedExtent(); + var b = { + x1: (rb.x1 - pan.x) / zoom, + x2: (rb.x2 - pan.x) / zoom, + y1: (rb.y1 - pan.y) / zoom, + y2: (rb.y2 - pan.y) / zoom + }; + b.w = b.x2 - b.x1; + b.h = b.y2 - b.y1; + return b; + }, + renderedExtent: function renderedExtent() { + var width = this.width(); + var height = this.height(); + return { + x1: 0, + y1: 0, + x2: width, + y2: height, + w: width, + h: height + }; + }, + multiClickDebounceTime: function multiClickDebounceTime(_int) { + if (_int) this._private.multiClickDebounceTime = _int;else return this._private.multiClickDebounceTime; + return this; // chaining + } + }; - } + // aliases + corefn$1.centre = corefn$1.center; + + // backwards compatibility + corefn$1.autolockNodes = corefn$1.autolock; + corefn$1.autoungrabifyNodes = corefn$1.autoungrabify; + + var fn = { + data: define.data({ + field: 'data', + bindingEvent: 'data', + allowBinding: true, + allowSetting: true, + settingEvent: 'data', + settingTriggersEvent: true, + triggerFnName: 'trigger', + allowGetting: true, + updateStyle: true + }), + removeData: define.removeData({ + field: 'data', + event: 'data', + triggerFnName: 'trigger', + triggerEvent: true, + updateStyle: true + }), + scratch: define.data({ + field: 'scratch', + bindingEvent: 'scratch', + allowBinding: true, + allowSetting: true, + settingEvent: 'scratch', + settingTriggersEvent: true, + triggerFnName: 'trigger', + allowGetting: true, + updateStyle: true + }), + removeScratch: define.removeData({ + field: 'scratch', + event: 'scratch', + triggerFnName: 'trigger', + triggerEvent: true, + updateStyle: true + }) + }; - } + // aliases + fn.attr = fn.data; + fn.removeAttr = fn.removeData; + var Core = function Core(opts) { + var cy = this; + opts = extend$1({}, opts); + var container = opts.container; - let m; + // allow for passing a wrapped jquery object + // e.g. cytoscape({ container: $('#cy') }) + if (container && !htmlElement(container) && htmlElement(container[0])) { + container = container[0]; + } + var reg = container ? container._cyreg : null; // e.g. already registered some info (e.g. readies) via jquery + reg = reg || {}; + if (reg && reg.cy) { + reg.cy.destroy(); + reg = {}; // old instance => replace reg completely + } - if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) { + var readies = reg.readies = reg.readies || []; + if (container) { + container._cyreg = reg; + } // make sure container assoc'd reg points to this cy + reg.cy = cy; + var head = _window !== undefined && container !== undefined && !opts.headless; + var options = opts; + options.layout = extend$1({ + name: head ? 'grid' : 'null' + }, options.layout); + options.renderer = extend$1({ + name: head ? 'canvas' : 'null' + }, options.renderer); + var defVal = function defVal(def, val, altVal) { + if (val !== undefined) { + return val; + } else if (altVal !== undefined) { + return altVal; + } else { + return def; + } + }; + var _p = this._private = { + container: container, + // html dom ele container + ready: false, + // whether ready has been triggered + options: options, + // cached options + elements: new Collection(this), + // elements in the graph + listeners: [], + // list of listeners + aniEles: new Collection(this), + // elements being animated + data: options.data || {}, + // data for the core + scratch: {}, + // scratch object for core + layout: null, + renderer: null, + destroyed: false, + // whether destroy was called + notificationsEnabled: true, + // whether notifications are sent to the renderer + minZoom: 1e-50, + maxZoom: 1e50, + zoomingEnabled: defVal(true, options.zoomingEnabled), + userZoomingEnabled: defVal(true, options.userZoomingEnabled), + panningEnabled: defVal(true, options.panningEnabled), + userPanningEnabled: defVal(true, options.userPanningEnabled), + boxSelectionEnabled: defVal(true, options.boxSelectionEnabled), + autolock: defVal(false, options.autolock, options.autolockNodes), + autoungrabify: defVal(false, options.autoungrabify, options.autoungrabifyNodes), + autounselectify: defVal(false, options.autounselectify), + styleEnabled: options.styleEnabled === undefined ? head : options.styleEnabled, + zoom: number$1(options.zoom) ? options.zoom : 1, + pan: { + x: plainObject(options.pan) && number$1(options.pan.x) ? options.pan.x : 0, + y: plainObject(options.pan) && number$1(options.pan.y) ? options.pan.y : 0 + }, + animation: { + // object for currently-running animations + current: [], + queue: [] + }, + hasCompoundNodes: false, + multiClickDebounceTime: defVal(250, options.multiClickDebounceTime) + }; + this.createEmitter(); + + // set selection type + this.selectionType(options.selectionType); + + // init zoom bounds + this.zoomRange({ + min: options.minZoom, + max: options.maxZoom + }); + var loadExtData = function loadExtData(extData, next) { + var anyIsPromise = extData.some(promise); + if (anyIsPromise) { + return Promise$1.all(extData).then(next); // load all data asynchronously, then exec rest of init + } else { + next(extData); // exec synchronously for convenience + } + }; - // rgb / hsl + // start with the default stylesheet so we have something before loading an external stylesheet + if (_p.styleEnabled) { + cy.setStyle([]); + } - let color; - const name = m[ 1 ]; - const components = m[ 2 ]; + // create the renderer + var rendererOptions = extend$1({}, options, options.renderer); // allow rendering hints in top level options + cy.initRenderer(rendererOptions); + var setElesAndLayout = function setElesAndLayout(elements, onload, ondone) { + cy.notifications(false); - switch ( name ) { + // remove old elements + var oldEles = cy.mutableElements(); + if (oldEles.length > 0) { + oldEles.remove(); + } + if (elements != null) { + if (plainObject(elements) || array(elements)) { + cy.add(elements); + } + } + cy.one('layoutready', function (e) { + cy.notifications(true); + cy.emit(e); // we missed this event by turning notifications off, so pass it on + + cy.one('load', onload); + cy.emitAndNotify('load'); + }).one('layoutstop', function () { + cy.one('done', ondone); + cy.emit('done'); + }); + var layoutOpts = extend$1({}, cy._private.options.layout); + layoutOpts.eles = cy.elements(); + cy.layout(layoutOpts).run(); + }; + loadExtData([options.style, options.elements], function (thens) { + var initStyle = thens[0]; + var initEles = thens[1]; + + // init style + if (_p.styleEnabled) { + cy.style().append(initStyle); + } - case 'rgb': - case 'rgba': + // initial load + setElesAndLayout(initEles, function () { + // onready + cy.startAnimationLoop(); + _p.ready = true; + + // if a ready callback is specified as an option, the bind it + if (fn$6(options.ready)) { + cy.on('ready', options.ready); + } + + // bind all the ready handlers registered before creating this instance + for (var i = 0; i < readies.length; i++) { + var fn = readies[i]; + cy.on('ready', fn); + } + if (reg) { + reg.readies = []; + } // clear b/c we've bound them all and don't want to keep it around in case a new core uses the same div etc + + cy.emit('ready'); + }, options.done); + }); + }; + var corefn = Core.prototype; // short alias + + extend$1(corefn, { + instanceString: function instanceString() { + return 'core'; + }, + isReady: function isReady() { + return this._private.ready; + }, + destroyed: function destroyed() { + return this._private.destroyed; + }, + ready: function ready(fn) { + if (this.isReady()) { + this.emitter().emit('ready', [], fn); // just calls fn as though triggered via ready event + } else { + this.on('ready', fn); + } + return this; + }, + destroy: function destroy() { + var cy = this; + if (cy.destroyed()) return; + cy.stopAnimationLoop(); + cy.destroyRenderer(); + this.emit('destroy'); + cy._private.destroyed = true; + return cy; + }, + hasElementWithId: function hasElementWithId(id) { + return this._private.elements.hasElementWithId(id); + }, + getElementById: function getElementById(id) { + return this._private.elements.getElementById(id); + }, + hasCompoundNodes: function hasCompoundNodes() { + return this._private.hasCompoundNodes; + }, + headless: function headless() { + return this._private.renderer.isHeadless(); + }, + styleEnabled: function styleEnabled() { + return this._private.styleEnabled; + }, + addToPool: function addToPool(eles) { + this._private.elements.merge(eles); + return this; // chaining + }, + + removeFromPool: function removeFromPool(eles) { + this._private.elements.unmerge(eles); + return this; + }, + container: function container() { + return this._private.container || null; + }, + window: function window() { + var container = this._private.container; + if (container == null) return _window; + var ownerDocument = this._private.container.ownerDocument; + if (ownerDocument === undefined || ownerDocument == null) { + return _window; + } + return ownerDocument.defaultView || _window; + }, + mount: function mount(container) { + if (container == null) { + return; + } + var cy = this; + var _p = cy._private; + var options = _p.options; + if (!htmlElement(container) && htmlElement(container[0])) { + container = container[0]; + } + cy.stopAnimationLoop(); + cy.destroyRenderer(); + _p.container = container; + _p.styleEnabled = true; + cy.invalidateSize(); + cy.initRenderer(extend$1({}, options, options.renderer, { + // allow custom renderer name to be re-used, otherwise use canvas + name: options.renderer.name === 'null' ? 'canvas' : options.renderer.name + })); + cy.startAnimationLoop(); + cy.style(options.style); + cy.emit('mount'); + return cy; + }, + unmount: function unmount() { + var cy = this; + cy.stopAnimationLoop(); + cy.destroyRenderer(); + cy.initRenderer({ + name: 'null' + }); + cy.emit('unmount'); + return cy; + }, + options: function options() { + return copy(this._private.options); + }, + json: function json(obj) { + var cy = this; + var _p = cy._private; + var eles = cy.mutableElements(); + var getFreshRef = function getFreshRef(ele) { + return cy.getElementById(ele.id()); + }; + if (plainObject(obj)) { + // set + + cy.startBatch(); + if (obj.elements) { + var idInJson = {}; + var updateEles = function updateEles(jsons, gr) { + var toAdd = []; + var toMod = []; + for (var i = 0; i < jsons.length; i++) { + var json = jsons[i]; + if (!json.data.id) { + warn('cy.json() cannot handle elements without an ID attribute'); + continue; + } + var id = '' + json.data.id; // id must be string + var ele = cy.getElementById(id); + idInJson[id] = true; + if (ele.length !== 0) { + // existing element should be updated + toMod.push({ + ele: ele, + json: json + }); + } else { + // otherwise should be added + if (gr) { + json.group = gr; + toAdd.push(json); + } else { + toAdd.push(json); + } + } + } + cy.add(toAdd); + for (var _i = 0; _i < toMod.length; _i++) { + var _toMod$_i = toMod[_i], + _ele = _toMod$_i.ele, + _json = _toMod$_i.json; + _ele.json(_json); + } + }; + if (array(obj.elements)) { + // elements: [] + updateEles(obj.elements); + } else { + // elements: { nodes: [], edges: [] } + var grs = ['nodes', 'edges']; + for (var i = 0; i < grs.length; i++) { + var gr = grs[i]; + var elements = obj.elements[gr]; + if (array(elements)) { + updateEles(elements, gr); + } + } + } + var parentsToRemove = cy.collection(); + eles.filter(function (ele) { + return !idInJson[ele.id()]; + }).forEach(function (ele) { + if (ele.isParent()) { + parentsToRemove.merge(ele); + } else { + ele.remove(); + } + }); - if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + // so that children are not removed w/parent + parentsToRemove.forEach(function (ele) { + return ele.children().move({ + parent: null + }); + }); - // rgb(255,0,0) rgba(255,0,0,0.5) - this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; - this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; - this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + // intermediate parents may be moved by prior line, so make sure we remove by fresh refs + parentsToRemove.forEach(function (ele) { + return getFreshRef(ele).remove(); + }); + } + if (obj.style) { + cy.style(obj.style); + } + if (obj.zoom != null && obj.zoom !== _p.zoom) { + cy.zoom(obj.zoom); + } + if (obj.pan) { + if (obj.pan.x !== _p.pan.x || obj.pan.y !== _p.pan.y) { + cy.pan(obj.pan); + } + } + if (obj.data) { + cy.data(obj.data); + } + var fields = ['minZoom', 'maxZoom', 'zoomingEnabled', 'userZoomingEnabled', 'panningEnabled', 'userPanningEnabled', 'boxSelectionEnabled', 'autolock', 'autoungrabify', 'autounselectify', 'multiClickDebounceTime']; + for (var _i2 = 0; _i2 < fields.length; _i2++) { + var f = fields[_i2]; + if (obj[f] != null) { + cy[f](obj[f]); + } + } + cy.endBatch(); + return this; // chaining + } else { + // get + var flat = !!obj; + var json = {}; + if (flat) { + json.elements = this.elements().map(function (ele) { + return ele.json(); + }); + } else { + json.elements = {}; + eles.forEach(function (ele) { + var group = ele.group(); + if (!json.elements[group]) { + json.elements[group] = []; + } + json.elements[group].push(ele.json()); + }); + } + if (this._private.styleEnabled) { + json.style = cy.style().json(); + } + json.data = copy(cy.data()); + var options = _p.options; + json.zoomingEnabled = _p.zoomingEnabled; + json.userZoomingEnabled = _p.userZoomingEnabled; + json.zoom = _p.zoom; + json.minZoom = _p.minZoom; + json.maxZoom = _p.maxZoom; + json.panningEnabled = _p.panningEnabled; + json.userPanningEnabled = _p.userPanningEnabled; + json.pan = copy(_p.pan); + json.boxSelectionEnabled = _p.boxSelectionEnabled; + json.renderer = copy(options.renderer); + json.hideEdgesOnViewport = options.hideEdgesOnViewport; + json.textureOnViewport = options.textureOnViewport; + json.wheelSensitivity = options.wheelSensitivity; + json.motionBlur = options.motionBlur; + json.multiClickDebounceTime = options.multiClickDebounceTime; + return json; + } + } + }); + corefn.$id = corefn.getElementById; + [corefn$9, corefn$8, elesfn, corefn$7, corefn$6, corefn$5, corefn$4, corefn$3, corefn$2, corefn$1, fn].forEach(function (props) { + extend$1(corefn, props); + }); - ColorManagement.toWorkingColorSpace( this, colorSpace ); + /* eslint-disable no-unused-vars */ + var defaults$7 = { + fit: true, + // whether to fit the viewport to the graph + directed: false, + // whether the tree is directed downwards (or edges can point in any direction if false) + padding: 30, + // padding on fit + circle: false, + // put depths in concentric circles if true, put depths top down if false + grid: false, + // whether to create an even grid into which the DAG is placed (circle:false only) + spacingFactor: 1.75, + // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap) + boundingBox: undefined, + // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + avoidOverlap: true, + // prevents node overlap, may overflow boundingBox if not enough space + nodeDimensionsIncludeLabels: false, + // Excludes the label when calculating node bounding boxes for the layout algorithm + roots: undefined, + // the roots of the trees + depthSort: undefined, + // a sorting function to order nodes at equal depth. e.g. function(a, b){ return a.data('weight') - b.data('weight') } + animate: false, + // whether to transition the node positions + animationDuration: 500, + // duration of animation in ms if enabled + animationEasing: undefined, + // easing of animation if enabled, + animateFilter: function animateFilter(node, i) { + return true; + }, + // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts + ready: undefined, + // callback on layoutready + stop: undefined, + // callback on layoutstop + transform: function transform(node, position) { + return position; + } // transform a given node position. Useful for changing flow direction in discrete layouts + }; - handleAlpha( color[ 4 ] ); + var deprecatedOptionDefaults = { + maximal: false, + // whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only); setting acyclic to true sets maximal to true also + acyclic: false // whether the tree is acyclic and thus a node could be shifted (due to the maximal option) multiple times without causing an infinite loop; setting to true sets maximal to true also; if you are uncertain whether a tree is acyclic, set to false to avoid potential infinite loops + }; - return this; + /* eslint-enable */ - } + var getInfo = function getInfo(ele) { + return ele.scratch('breadthfirst'); + }; + var setInfo = function setInfo(ele, obj) { + return ele.scratch('breadthfirst', obj); + }; + function BreadthFirstLayout(options) { + this.options = extend$1({}, defaults$7, deprecatedOptionDefaults, options); + } + BreadthFirstLayout.prototype.run = function () { + var params = this.options; + var options = params; + var cy = params.cy; + var eles = options.eles; + var nodes = eles.nodes().filter(function (n) { + return !n.isParent(); + }); + var graph = eles; + var directed = options.directed; + var maximal = options.acyclic || options.maximal || options.maximalAdjustments > 0; // maximalAdjustments for compat. w/ old code; also, setting acyclic to true sets maximal to true + + var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : { + x1: 0, + y1: 0, + w: cy.width(), + h: cy.height() + }); + var roots; + if (elementOrCollection(options.roots)) { + roots = options.roots; + } else if (array(options.roots)) { + var rootsArray = []; + for (var i = 0; i < options.roots.length; i++) { + var id = options.roots[i]; + var ele = cy.getElementById(id); + rootsArray.push(ele); + } + roots = cy.collection(rootsArray); + } else if (string(options.roots)) { + roots = cy.$(options.roots); + } else { + if (directed) { + roots = nodes.roots(); + } else { + var components = eles.components(); + roots = cy.collection(); + var _loop = function _loop(_i) { + var comp = components[_i]; + var maxDegree = comp.maxDegree(false); + var compRoots = comp.filter(function (ele) { + return ele.degree(false) === maxDegree; + }); + roots = roots.add(compRoots); + }; + for (var _i = 0; _i < components.length; _i++) { + _loop(_i); + } + } + } + var depths = []; + var foundByBfs = {}; + var addToDepth = function addToDepth(ele, d) { + if (depths[d] == null) { + depths[d] = []; + } + var i = depths[d].length; + depths[d].push(ele); + setInfo(ele, { + index: i, + depth: d + }); + }; + var changeDepth = function changeDepth(ele, newDepth) { + var _getInfo = getInfo(ele), + depth = _getInfo.depth, + index = _getInfo.index; + depths[depth][index] = null; + addToDepth(ele, newDepth); + }; + + // find the depths of the nodes + graph.bfs({ + roots: roots, + directed: options.directed, + visit: function visit(node, edge, pNode, i, depth) { + var ele = node[0]; + var id = ele.id(); + addToDepth(ele, depth); + foundByBfs[id] = true; + } + }); + + // check for nodes not found by bfs + var orphanNodes = []; + for (var _i2 = 0; _i2 < nodes.length; _i2++) { + var _ele = nodes[_i2]; + if (foundByBfs[_ele.id()]) { + continue; + } else { + orphanNodes.push(_ele); + } + } - if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + // assign the nodes a depth and index + + var assignDepthsAt = function assignDepthsAt(i) { + var eles = depths[i]; + for (var j = 0; j < eles.length; j++) { + var _ele2 = eles[j]; + if (_ele2 == null) { + eles.splice(j, 1); + j--; + continue; + } + setInfo(_ele2, { + depth: i, + index: j + }); + } + }; + var assignDepths = function assignDepths() { + for (var _i3 = 0; _i3 < depths.length; _i3++) { + assignDepthsAt(_i3); + } + }; + var adjustMaximally = function adjustMaximally(ele, shifted) { + var eInfo = getInfo(ele); + var incomers = ele.incomers().filter(function (el) { + return el.isNode() && eles.has(el); + }); + var maxDepth = -1; + var id = ele.id(); + for (var k = 0; k < incomers.length; k++) { + var incmr = incomers[k]; + var iInfo = getInfo(incmr); + maxDepth = Math.max(maxDepth, iInfo.depth); + } + if (eInfo.depth <= maxDepth) { + if (!options.acyclic && shifted[id]) { + return null; + } + var newDepth = maxDepth + 1; + changeDepth(ele, newDepth); + shifted[id] = newDepth; + return true; + } + return false; + }; + + // for the directed case, try to make the edges all go down (i.e. depth i => depth i + 1) + if (directed && maximal) { + var Q = []; + var shifted = {}; + var enqueue = function enqueue(n) { + return Q.push(n); + }; + var dequeue = function dequeue() { + return Q.shift(); + }; + nodes.forEach(function (n) { + return Q.push(n); + }); + while (Q.length > 0) { + var _ele3 = dequeue(); + var didShift = adjustMaximally(_ele3, shifted); + if (didShift) { + _ele3.outgoers().filter(function (el) { + return el.isNode() && eles.has(el); + }).forEach(enqueue); + } else if (didShift === null) { + warn('Detected double maximal shift for node `' + _ele3.id() + '`. Bailing maximal adjustment due to cycle. Use `options.maximal: true` only on DAGs.'); + break; // exit on failure + } + } + } - // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + assignDepths(); // clear holes + + // find min distance we need to leave between nodes + var minDistance = 0; + if (options.avoidOverlap) { + for (var _i4 = 0; _i4 < nodes.length; _i4++) { + var n = nodes[_i4]; + var nbb = n.layoutDimensions(options); + var w = nbb.w; + var h = nbb.h; + minDistance = Math.max(minDistance, w, h); + } + } - ColorManagement.toWorkingColorSpace( this, colorSpace ); + // get the weighted percent for an element based on its connectivity to other levels + var cachedWeightedPercent = {}; + var getWeightedPercent = function getWeightedPercent(ele) { + if (cachedWeightedPercent[ele.id()]) { + return cachedWeightedPercent[ele.id()]; + } + var eleDepth = getInfo(ele).depth; + var neighbors = ele.neighborhood(); + var percent = 0; + var samples = 0; + for (var _i5 = 0; _i5 < neighbors.length; _i5++) { + var neighbor = neighbors[_i5]; + if (neighbor.isEdge() || neighbor.isParent() || !nodes.has(neighbor)) { + continue; + } + var bf = getInfo(neighbor); + if (bf == null) { + continue; + } + var index = bf.index; + var depth = bf.depth; + + // unassigned neighbours shouldn't affect the ordering + if (index == null || depth == null) { + continue; + } + var nDepth = depths[depth].length; + if (depth < eleDepth) { + // only get influenced by elements above + percent += index / nDepth; + samples++; + } + } + samples = Math.max(1, samples); + percent = percent / samples; + if (samples === 0) { + // put lone nodes at the start + percent = 0; + } + cachedWeightedPercent[ele.id()] = percent; + return percent; + }; + + // rearrange the indices in each depth level based on connectivity + + var sortFn = function sortFn(a, b) { + var apct = getWeightedPercent(a); + var bpct = getWeightedPercent(b); + var diff = apct - bpct; + if (diff === 0) { + return ascending(a.id(), b.id()); // make sure sort doesn't have don't-care comparisons + } else { + return diff; + } + }; + if (options.depthSort !== undefined) { + sortFn = options.depthSort; + } - handleAlpha( color[ 4 ] ); + // sort each level to make connected nodes closer + for (var _i6 = 0; _i6 < depths.length; _i6++) { + depths[_i6].sort(sortFn); + assignDepthsAt(_i6); + } - return this; + // assign orphan nodes to a new top-level depth + var orphanDepth = []; + for (var _i7 = 0; _i7 < orphanNodes.length; _i7++) { + orphanDepth.push(orphanNodes[_i7]); + } + depths.unshift(orphanDepth); + assignDepths(); + var biggestDepthSize = 0; + for (var _i8 = 0; _i8 < depths.length; _i8++) { + biggestDepthSize = Math.max(depths[_i8].length, biggestDepthSize); + } + var center = { + x: bb.x1 + bb.w / 2, + y: bb.x1 + bb.h / 2 + }; + var maxDepthSize = depths.reduce(function (max, eles) { + return Math.max(max, eles.length); + }, 0); + var getPosition = function getPosition(ele) { + var _getInfo2 = getInfo(ele), + depth = _getInfo2.depth, + index = _getInfo2.index; + var depthSize = depths[depth].length; + var distanceX = Math.max(bb.w / ((options.grid ? maxDepthSize : depthSize) + 1), minDistance); + var distanceY = Math.max(bb.h / (depths.length + 1), minDistance); + var radiusStepSize = Math.min(bb.w / 2 / depths.length, bb.h / 2 / depths.length); + radiusStepSize = Math.max(radiusStepSize, minDistance); + if (!options.circle) { + var epos = { + x: center.x + (index + 1 - (depthSize + 1) / 2) * distanceX, + y: (depth + 1) * distanceY + }; + return epos; + } else { + var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize / 2 : 0); + var theta = 2 * Math.PI / depths[depth].length * index; + if (depth === 0 && depths[0].length === 1) { + radius = 1; + } + return { + x: center.x + radius * Math.cos(theta), + y: center.y + radius * Math.sin(theta) + }; + } + }; + eles.nodes().layoutPositions(this, options, getPosition); + return this; // chaining + }; - } + var defaults$6 = { + fit: true, + // whether to fit the viewport to the graph + padding: 30, + // the padding on fit + boundingBox: undefined, + // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + avoidOverlap: true, + // prevents node overlap, may overflow boundingBox and radius if not enough space + nodeDimensionsIncludeLabels: false, + // Excludes the label when calculating node bounding boxes for the layout algorithm + spacingFactor: undefined, + // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up + radius: undefined, + // the radius of the circle + startAngle: 3 / 2 * Math.PI, + // where nodes start in radians + sweep: undefined, + // how many radians should be between the first and last node (defaults to full circle) + clockwise: true, + // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false) + sort: undefined, + // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') } + animate: false, + // whether to transition the node positions + animationDuration: 500, + // duration of animation in ms if enabled + animationEasing: undefined, + // easing of animation if enabled + animateFilter: function animateFilter(node, i) { + return true; + }, + // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts + ready: undefined, + // callback on layoutready + stop: undefined, + // callback on layoutstop + transform: function transform(node, position) { + return position; + } // transform a given node position. Useful for changing flow direction in discrete layouts + }; - break; + function CircleLayout(options) { + this.options = extend$1({}, defaults$6, options); + } + CircleLayout.prototype.run = function () { + var params = this.options; + var options = params; + var cy = params.cy; + var eles = options.eles; + var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise; + var nodes = eles.nodes().not(':parent'); + if (options.sort) { + nodes = nodes.sort(options.sort); + } + var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : { + x1: 0, + y1: 0, + w: cy.width(), + h: cy.height() + }); + var center = { + x: bb.x1 + bb.w / 2, + y: bb.y1 + bb.h / 2 + }; + var sweep = options.sweep === undefined ? 2 * Math.PI - 2 * Math.PI / nodes.length : options.sweep; + var dTheta = sweep / Math.max(1, nodes.length - 1); + var r; + var minDistance = 0; + for (var i = 0; i < nodes.length; i++) { + var n = nodes[i]; + var nbb = n.layoutDimensions(options); + var w = nbb.w; + var h = nbb.h; + minDistance = Math.max(minDistance, w, h); + } + if (number$1(options.radius)) { + r = options.radius; + } else if (nodes.length <= 1) { + r = 0; + } else { + r = Math.min(bb.h, bb.w) / 2 - minDistance; + } - case 'hsl': - case 'hsla': + // calculate the radius + if (nodes.length > 1 && options.avoidOverlap) { + // but only if more than one node (can't overlap) + minDistance *= 1.75; // just to have some nice spacing - if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + var dcos = Math.cos(dTheta) - Math.cos(0); + var dsin = Math.sin(dTheta) - Math.sin(0); + var rMin = Math.sqrt(minDistance * minDistance / (dcos * dcos + dsin * dsin)); // s.t. no nodes overlapping + r = Math.max(rMin, r); + } + var getPos = function getPos(ele, i) { + var theta = options.startAngle + i * dTheta * (clockwise ? 1 : -1); + var rx = r * Math.cos(theta); + var ry = r * Math.sin(theta); + var pos = { + x: center.x + rx, + y: center.y + ry + }; + return pos; + }; + eles.nodes().layoutPositions(this, options, getPos); + return this; // chaining + }; - // hsl(120,50%,50%) hsla(120,50%,50%,0.5) - const h = parseFloat( color[ 1 ] ) / 360; - const s = parseFloat( color[ 2 ] ) / 100; - const l = parseFloat( color[ 3 ] ) / 100; + var defaults$5 = { + fit: true, + // whether to fit the viewport to the graph + padding: 30, + // the padding on fit + startAngle: 3 / 2 * Math.PI, + // where nodes start in radians + sweep: undefined, + // how many radians should be between the first and last node (defaults to full circle) + clockwise: true, + // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false) + equidistant: false, + // whether levels have an equal radial distance betwen them, may cause bounding box overflow + minNodeSpacing: 10, + // min spacing between outside of nodes (used for radius adjustment) + boundingBox: undefined, + // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + avoidOverlap: true, + // prevents node overlap, may overflow boundingBox if not enough space + nodeDimensionsIncludeLabels: false, + // Excludes the label when calculating node bounding boxes for the layout algorithm + height: undefined, + // height of layout area (overrides container height) + width: undefined, + // width of layout area (overrides container width) + spacingFactor: undefined, + // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up + concentric: function concentric(node) { + // returns numeric value for each node, placing higher nodes in levels towards the centre + return node.degree(); + }, + levelWidth: function levelWidth(nodes) { + // the variation of concentric values in each level + return nodes.maxDegree() / 4; + }, + animate: false, + // whether to transition the node positions + animationDuration: 500, + // duration of animation in ms if enabled + animationEasing: undefined, + // easing of animation if enabled + animateFilter: function animateFilter(node, i) { + return true; + }, + // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts + ready: undefined, + // callback on layoutready + stop: undefined, + // callback on layoutstop + transform: function transform(node, position) { + return position; + } // transform a given node position. Useful for changing flow direction in discrete layouts + }; - handleAlpha( color[ 4 ] ); + function ConcentricLayout(options) { + this.options = extend$1({}, defaults$5, options); + } + ConcentricLayout.prototype.run = function () { + var params = this.options; + var options = params; + var clockwise = options.counterclockwise !== undefined ? !options.counterclockwise : options.clockwise; + var cy = params.cy; + var eles = options.eles; + var nodes = eles.nodes().not(':parent'); + var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : { + x1: 0, + y1: 0, + w: cy.width(), + h: cy.height() + }); + var center = { + x: bb.x1 + bb.w / 2, + y: bb.y1 + bb.h / 2 + }; + var nodeValues = []; // { node, value } + var maxNodeSize = 0; + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var value = void 0; + + // calculate the node value + value = options.concentric(node); + nodeValues.push({ + value: value, + node: node + }); - return this.setHSL( h, s, l, colorSpace ); + // for style mapping + node._private.scratch.concentric = value; + } - } + // in case we used the `concentric` in style + nodes.updateStyle(); - break; + // calculate max size now based on potentially updated mappers + for (var _i = 0; _i < nodes.length; _i++) { + var _node = nodes[_i]; + var nbb = _node.layoutDimensions(options); + maxNodeSize = Math.max(maxNodeSize, nbb.w, nbb.h); + } - } + // sort node values in descreasing order + nodeValues.sort(function (a, b) { + return b.value - a.value; + }); + var levelWidth = options.levelWidth(nodes); + + // put the values into levels + var levels = [[]]; + var currentLevel = levels[0]; + for (var _i2 = 0; _i2 < nodeValues.length; _i2++) { + var val = nodeValues[_i2]; + if (currentLevel.length > 0) { + var diff = Math.abs(currentLevel[0].value - val.value); + if (diff >= levelWidth) { + currentLevel = []; + levels.push(currentLevel); + } + } + currentLevel.push(val); + } - } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { + // create positions from levels - // hex color + var minDist = maxNodeSize + options.minNodeSpacing; // min dist between nodes - const hex = m[ 1 ]; - const size = hex.length; + if (!options.avoidOverlap) { + // then strictly constrain to bb + var firstLvlHasMulti = levels.length > 0 && levels[0].length > 1; + var maxR = Math.min(bb.w, bb.h) / 2 - minDist; + var rStep = maxR / (levels.length + firstLvlHasMulti ? 1 : 0); + minDist = Math.min(minDist, rStep); + } - if ( size === 3 ) { + // find the metrics for each level + var r = 0; + for (var _i3 = 0; _i3 < levels.length; _i3++) { + var level = levels[_i3]; + var sweep = options.sweep === undefined ? 2 * Math.PI - 2 * Math.PI / level.length : options.sweep; + var dTheta = level.dTheta = sweep / Math.max(1, level.length - 1); + + // calculate the radius + if (level.length > 1 && options.avoidOverlap) { + // but only if more than one node (can't overlap) + var dcos = Math.cos(dTheta) - Math.cos(0); + var dsin = Math.sin(dTheta) - Math.sin(0); + var rMin = Math.sqrt(minDist * minDist / (dcos * dcos + dsin * dsin)); // s.t. no nodes overlapping + + r = Math.max(rMin, r); + } + level.r = r; + r += minDist; + } + if (options.equidistant) { + var rDeltaMax = 0; + var _r = 0; + for (var _i4 = 0; _i4 < levels.length; _i4++) { + var _level = levels[_i4]; + var rDelta = _level.r - _r; + rDeltaMax = Math.max(rDeltaMax, rDelta); + } + _r = 0; + for (var _i5 = 0; _i5 < levels.length; _i5++) { + var _level2 = levels[_i5]; + if (_i5 === 0) { + _r = _level2.r; + } + _level2.r = _r; + _r += rDeltaMax; + } + } - // #ff0 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; + // calculate the node positions + var pos = {}; // id => position + for (var _i6 = 0; _i6 < levels.length; _i6++) { + var _level3 = levels[_i6]; + var _dTheta = _level3.dTheta; + var _r2 = _level3.r; + for (var j = 0; j < _level3.length; j++) { + var _val = _level3[j]; + var theta = options.startAngle + (clockwise ? 1 : -1) * _dTheta * j; + var p = { + x: center.x + _r2 * Math.cos(theta), + y: center.y + _r2 * Math.sin(theta) + }; + pos[_val.node.id()] = p; + } + } - ColorManagement.toWorkingColorSpace( this, colorSpace ); + // position the nodes + eles.nodes().layoutPositions(this, options, function (ele) { + var id = ele.id(); + return pos[id]; + }); + return this; // chaining + }; - return this; + /* + The CoSE layout was written by Gerardo Huck. + https://www.linkedin.com/in/gerardohuck/ - } else if ( size === 6 ) { + Based on the following article: + http://dl.acm.org/citation.cfm?id=1498047 - // #ff0000 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; + Modifications tracked on Github. + */ + var DEBUG; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + /** + * @brief : default layout options + */ + var defaults$4 = { + // Called on `layoutready` + ready: function ready() {}, + // Called on `layoutstop` + stop: function stop() {}, + // Whether to animate while running the layout + // true : Animate continuously as the layout is running + // false : Just show the end result + // 'end' : Animate with the end result, from the initial positions to the end positions + animate: true, + // Easing of the animation for animate:'end' + animationEasing: undefined, + // The duration of the animation for animate:'end' + animationDuration: undefined, + // A function that determines whether the node should be animated + // All nodes animated by default on animate enabled + // Non-animated nodes are positioned immediately when the layout starts + animateFilter: function animateFilter(node, i) { + return true; + }, + // The layout animates only after this many milliseconds for animate:true + // (prevents flashing on fast runs) + animationThreshold: 250, + // Number of iterations between consecutive screen positions update + refresh: 20, + // Whether to fit the network view after when done + fit: true, + // Padding on fit + padding: 30, + // Constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + boundingBox: undefined, + // Excludes the label when calculating node bounding boxes for the layout algorithm + nodeDimensionsIncludeLabels: false, + // Randomize the initial positions of the nodes (true) or use existing positions (false) + randomize: false, + // Extra spacing between components in non-compound graphs + componentSpacing: 40, + // Node repulsion (non overlapping) multiplier + nodeRepulsion: function nodeRepulsion(node) { + return 2048; + }, + // Node repulsion (overlapping) multiplier + nodeOverlap: 4, + // Ideal edge (non nested) length + idealEdgeLength: function idealEdgeLength(edge) { + return 32; + }, + // Divisor to compute edge forces + edgeElasticity: function edgeElasticity(edge) { + return 32; + }, + // Nesting factor (multiplier) to compute ideal edge length for nested edges + nestingFactor: 1.2, + // Gravity force (constant) + gravity: 1, + // Maximum number of iterations to perform + numIter: 1000, + // Initial temperature (maximum node displacement) + initialTemp: 1000, + // Cooling factor (how the temperature is reduced between consecutive iterations + coolingFactor: 0.99, + // Lower temperature threshold (below this point the layout will end) + minTemp: 1.0 + }; - return this; + /** + * @brief : constructor + * @arg options : object containing layout options + */ + function CoseLayout(options) { + this.options = extend$1({}, defaults$4, options); + this.options.layout = this; + + // Exclude any edge that has a source or target node that is not in the set of passed-in nodes + var nodes = this.options.eles.nodes(); + var edges = this.options.eles.edges(); + var notEdges = edges.filter(function (e) { + var sourceId = e.source().data('id'); + var targetId = e.target().data('id'); + var hasSource = nodes.some(function (n) { + return n.data('id') === sourceId; + }); + var hasTarget = nodes.some(function (n) { + return n.data('id') === targetId; + }); + return !hasSource || !hasTarget; + }); + this.options.eles = this.options.eles.not(notEdges); + } - } + /** + * @brief : runs the layout + */ + CoseLayout.prototype.run = function () { + var options = this.options; + var cy = options.cy; + var layout = this; + layout.stopped = false; + if (options.animate === true || options.animate === false) { + layout.emit({ + type: 'layoutstart', + layout: layout + }); + } - } + // Set DEBUG - Global variable + if (true === options.debug) { + DEBUG = true; + } else { + DEBUG = false; + } - if ( style && style.length > 0 ) { + // Initialize layout info + var layoutInfo = createLayoutInfo(cy, layout, options); - return this.setColorName( style, colorSpace ); + // Show LayoutInfo contents if debugging + if (DEBUG) { + printLayoutInfo(layoutInfo); + } - } + // If required, randomize node positions + if (options.randomize) { + randomizePositions(layoutInfo); + } + var startTime = performanceNow(); + var refresh = function refresh() { + refreshPositions(layoutInfo, cy, options); - return this; + // Fit the graph if necessary + if (true === options.fit) { + cy.fit(options.padding); + } + }; + var mainLoop = function mainLoop(i) { + if (layout.stopped || i >= options.numIter) { + // logDebug("Layout manually stopped. Stopping computation in step " + i); + return false; + } - } + // Do one step in the phisical simulation + step(layoutInfo, options); - setColorName( style, colorSpace = SRGBColorSpace ) { + // Update temperature + layoutInfo.temperature = layoutInfo.temperature * options.coolingFactor; + // logDebug("New temperature: " + layoutInfo.temperature); - // color keywords - const hex = _colorKeywords[ style.toLowerCase() ]; + if (layoutInfo.temperature < options.minTemp) { + // logDebug("Temperature drop below minimum threshold. Stopping computation in step " + i); + return false; + } + return true; + }; + var done = function done() { + if (options.animate === true || options.animate === false) { + refresh(); + + // Layout has finished + layout.one('layoutstop', options.stop); + layout.emit({ + type: 'layoutstop', + layout: layout + }); + } else { + var nodes = options.eles.nodes(); + var getScaledPos = getScaleInBoundsFn(layoutInfo, options, nodes); + nodes.layoutPositions(layout, options, getScaledPos); + } + }; + var i = 0; + var loopRet = true; + if (options.animate === true) { + var frame = function frame() { + var f = 0; + while (loopRet && f < options.refresh) { + loopRet = mainLoop(i); + i++; + f++; + } + if (!loopRet) { + // it's done + separateComponents(layoutInfo, options); + done(); + } else { + var now = performanceNow(); + if (now - startTime >= options.animationThreshold) { + refresh(); + } + requestAnimationFrame$1(frame); + } + }; + frame(); + } else { + while (loopRet) { + loopRet = mainLoop(i); + i++; + } + separateComponents(layoutInfo, options); + done(); + } + return this; // chaining + }; - if ( hex !== undefined ) { + /** + * @brief : called on continuous layouts to stop them before they finish + */ + CoseLayout.prototype.stop = function () { + this.stopped = true; + if (this.thread) { + this.thread.stop(); + } + this.emit('layoutstop'); + return this; // chaining + }; - // red - this.setHex( hex, colorSpace ); + CoseLayout.prototype.destroy = function () { + if (this.thread) { + this.thread.stop(); + } + return this; // chaining + }; - } else { + /** + * @brief : Creates an object which is contains all the data + * used in the layout process + * @arg cy : cytoscape.js object + * @return : layoutInfo object initialized + */ + var createLayoutInfo = function createLayoutInfo(cy, layout, options) { + // Shortcut + var edges = options.eles.edges(); + var nodes = options.eles.nodes(); + var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : { + x1: 0, + y1: 0, + w: cy.width(), + h: cy.height() + }); + var layoutInfo = { + isCompound: cy.hasCompoundNodes(), + layoutNodes: [], + idToIndex: {}, + nodeSize: nodes.size(), + graphSet: [], + indexToGraph: [], + layoutEdges: [], + edgeSize: edges.size(), + temperature: options.initialTemp, + clientWidth: bb.w, + clientHeight: bb.h, + boundingBox: bb + }; + var components = options.eles.components(); + var id2cmptId = {}; + for (var i = 0; i < components.length; i++) { + var component = components[i]; + for (var j = 0; j < component.length; j++) { + var node = component[j]; + id2cmptId[node.id()] = i; + } + } - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); + // Iterate over all nodes, creating layout nodes + for (var i = 0; i < layoutInfo.nodeSize; i++) { + var n = nodes[i]; + var nbb = n.layoutDimensions(options); + var tempNode = {}; + tempNode.isLocked = n.locked(); + tempNode.id = n.data('id'); + tempNode.parentId = n.data('parent'); + tempNode.cmptId = id2cmptId[n.id()]; + tempNode.children = []; + tempNode.positionX = n.position('x'); + tempNode.positionY = n.position('y'); + tempNode.offsetX = 0; + tempNode.offsetY = 0; + tempNode.height = nbb.w; + tempNode.width = nbb.h; + tempNode.maxX = tempNode.positionX + tempNode.width / 2; + tempNode.minX = tempNode.positionX - tempNode.width / 2; + tempNode.maxY = tempNode.positionY + tempNode.height / 2; + tempNode.minY = tempNode.positionY - tempNode.height / 2; + tempNode.padLeft = parseFloat(n.style('padding')); + tempNode.padRight = parseFloat(n.style('padding')); + tempNode.padTop = parseFloat(n.style('padding')); + tempNode.padBottom = parseFloat(n.style('padding')); + + // forces + tempNode.nodeRepulsion = fn$6(options.nodeRepulsion) ? options.nodeRepulsion(n) : options.nodeRepulsion; + + // Add new node + layoutInfo.layoutNodes.push(tempNode); + // Add entry to id-index map + layoutInfo.idToIndex[tempNode.id] = i; + } - } + // Inline implementation of a queue, used for traversing the graph in BFS order + var queue = []; + var start = 0; // Points to the start the queue + var end = -1; // Points to the end of the queue + + var tempGraph = []; + + // Second pass to add child information and + // initialize queue for hierarchical traversal + for (var i = 0; i < layoutInfo.nodeSize; i++) { + var n = layoutInfo.layoutNodes[i]; + var p_id = n.parentId; + // Check if node n has a parent node + if (null != p_id) { + // Add node Id to parent's list of children + layoutInfo.layoutNodes[layoutInfo.idToIndex[p_id]].children.push(n.id); + } else { + // If a node doesn't have a parent, then it's in the root graph + queue[++end] = n.id; + tempGraph.push(n.id); + } + } - return this; + // Add root graph to graphSet + layoutInfo.graphSet.push(tempGraph); + + // Traverse the graph, level by level, + while (start <= end) { + // Get the node to visit and remove it from queue + var node_id = queue[start++]; + var node_ix = layoutInfo.idToIndex[node_id]; + var node = layoutInfo.layoutNodes[node_ix]; + var children = node.children; + if (children.length > 0) { + // Add children nodes as a new graph to graph set + layoutInfo.graphSet.push(children); + // Add children to que queue to be visited + for (var i = 0; i < children.length; i++) { + queue[++end] = children[i]; + } + } + } - } + // Create indexToGraph map + for (var i = 0; i < layoutInfo.graphSet.length; i++) { + var graph = layoutInfo.graphSet[i]; + for (var j = 0; j < graph.length; j++) { + var index = layoutInfo.idToIndex[graph[j]]; + layoutInfo.indexToGraph[index] = i; + } + } - clone() { + // Iterate over all edges, creating Layout Edges + for (var i = 0; i < layoutInfo.edgeSize; i++) { + var e = edges[i]; + var tempEdge = {}; + tempEdge.id = e.data('id'); + tempEdge.sourceId = e.data('source'); + tempEdge.targetId = e.data('target'); + + // Compute ideal length + var idealLength = fn$6(options.idealEdgeLength) ? options.idealEdgeLength(e) : options.idealEdgeLength; + var elasticity = fn$6(options.edgeElasticity) ? options.edgeElasticity(e) : options.edgeElasticity; + + // Check if it's an inter graph edge + var sourceIx = layoutInfo.idToIndex[tempEdge.sourceId]; + var targetIx = layoutInfo.idToIndex[tempEdge.targetId]; + var sourceGraph = layoutInfo.indexToGraph[sourceIx]; + var targetGraph = layoutInfo.indexToGraph[targetIx]; + if (sourceGraph != targetGraph) { + // Find lowest common graph ancestor + var lca = findLCA(tempEdge.sourceId, tempEdge.targetId, layoutInfo); + + // Compute sum of node depths, relative to lca graph + var lcaGraph = layoutInfo.graphSet[lca]; + var depth = 0; + + // Source depth + var tempNode = layoutInfo.layoutNodes[sourceIx]; + while (-1 === lcaGraph.indexOf(tempNode.id)) { + tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]]; + depth++; + } + + // Target depth + tempNode = layoutInfo.layoutNodes[targetIx]; + while (-1 === lcaGraph.indexOf(tempNode.id)) { + tempNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[tempNode.parentId]]; + depth++; + } + + // logDebug('LCA of nodes ' + tempEdge.sourceId + ' and ' + tempEdge.targetId + + // ". Index: " + lca + " Contents: " + lcaGraph.toString() + + // ". Depth: " + depth); + + // Update idealLength + idealLength *= depth * options.nestingFactor; + } + tempEdge.idealLength = idealLength; + tempEdge.elasticity = elasticity; + layoutInfo.layoutEdges.push(tempEdge); + } - return new this.constructor( this.r, this.g, this.b ); + // Finally, return layoutInfo object + return layoutInfo; + }; - } + /** + * @brief : This function finds the index of the lowest common + * graph ancestor between 2 nodes in the subtree + * (from the graph hierarchy induced tree) whose + * root is graphIx + * + * @arg node1: node1's ID + * @arg node2: node2's ID + * @arg layoutInfo: layoutInfo object + * + */ + var findLCA = function findLCA(node1, node2, layoutInfo) { + // Find their common ancester, starting from the root graph + var res = findLCA_aux(node1, node2, 0, layoutInfo); + if (2 > res.count) { + // If aux function couldn't find the common ancester, + // then it is the root graph + return 0; + } else { + return res.graph; + } + }; - copy( color ) { + /** + * @brief : Auxiliary function used for LCA computation + * + * @arg node1 : node1's ID + * @arg node2 : node2's ID + * @arg graphIx : subgraph index + * @arg layoutInfo : layoutInfo object + * + * @return : object of the form {count: X, graph: Y}, where: + * X is the number of ancestors (max: 2) found in + * graphIx (and it's subgraphs), + * Y is the graph index of the lowest graph containing + * all X nodes + */ + var findLCA_aux = function findLCA_aux(node1, node2, graphIx, layoutInfo) { + var graph = layoutInfo.graphSet[graphIx]; + // If both nodes belongs to graphIx + if (-1 < graph.indexOf(node1) && -1 < graph.indexOf(node2)) { + return { + count: 2, + graph: graphIx + }; + } - this.r = color.r; - this.g = color.g; - this.b = color.b; + // Make recursive calls for all subgraphs + var c = 0; + for (var i = 0; i < graph.length; i++) { + var nodeId = graph[i]; + var nodeIx = layoutInfo.idToIndex[nodeId]; + var children = layoutInfo.layoutNodes[nodeIx].children; - return this; + // If the node has no child, skip it + if (0 === children.length) { + continue; + } + var childGraphIx = layoutInfo.indexToGraph[layoutInfo.idToIndex[children[0]]]; + var result = findLCA_aux(node1, node2, childGraphIx, layoutInfo); + if (0 === result.count) { + // Neither node1 nor node2 are present in this subgraph + continue; + } else if (1 === result.count) { + // One of (node1, node2) is present in this subgraph + c++; + if (2 === c) { + // We've already found both nodes, no need to keep searching + break; + } + } else { + // Both nodes are present in this subgraph + return result; + } + } + return { + count: c, + graph: graphIx + }; + }; - } + /** + * @brief: printsLayoutInfo into js console + * Only used for debbuging + */ + var printLayoutInfo; - copySRGBToLinear( color ) { + /** + * @brief : Randomizes the position of all nodes + */ + var randomizePositions = function randomizePositions(layoutInfo, cy) { + var width = layoutInfo.clientWidth; + var height = layoutInfo.clientHeight; + for (var i = 0; i < layoutInfo.nodeSize; i++) { + var n = layoutInfo.layoutNodes[i]; + + // No need to randomize compound nodes or locked nodes + if (0 === n.children.length && !n.isLocked) { + n.positionX = Math.random() * width; + n.positionY = Math.random() * height; + } + } + }; + var getScaleInBoundsFn = function getScaleInBoundsFn(layoutInfo, options, nodes) { + var bb = layoutInfo.boundingBox; + var coseBB = { + x1: Infinity, + x2: -Infinity, + y1: Infinity, + y2: -Infinity + }; + if (options.boundingBox) { + nodes.forEach(function (node) { + var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[node.data('id')]]; + coseBB.x1 = Math.min(coseBB.x1, lnode.positionX); + coseBB.x2 = Math.max(coseBB.x2, lnode.positionX); + coseBB.y1 = Math.min(coseBB.y1, lnode.positionY); + coseBB.y2 = Math.max(coseBB.y2, lnode.positionY); + }); + coseBB.w = coseBB.x2 - coseBB.x1; + coseBB.h = coseBB.y2 - coseBB.y1; + } + return function (ele, i) { + var lnode = layoutInfo.layoutNodes[layoutInfo.idToIndex[ele.data('id')]]; + if (options.boundingBox) { + // then add extra bounding box constraint + var pctX = (lnode.positionX - coseBB.x1) / coseBB.w; + var pctY = (lnode.positionY - coseBB.y1) / coseBB.h; + return { + x: bb.x1 + pctX * bb.w, + y: bb.y1 + pctY * bb.h + }; + } else { + return { + x: lnode.positionX, + y: lnode.positionY + }; + } + }; + }; - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); + /** + * @brief : Updates the positions of nodes in the network + * @arg layoutInfo : LayoutInfo object + * @arg cy : Cytoscape object + * @arg options : Layout options + */ + var refreshPositions = function refreshPositions(layoutInfo, cy, options) { + // var s = 'Refreshing positions'; + // logDebug(s); + + var layout = options.layout; + var nodes = options.eles.nodes(); + var getScaledPos = getScaleInBoundsFn(layoutInfo, options, nodes); + nodes.positions(getScaledPos); + + // Trigger layoutReady only on first call + if (true !== layoutInfo.ready) { + // s = 'Triggering layoutready'; + // logDebug(s); + layoutInfo.ready = true; + layout.one('layoutready', options.ready); + layout.emit({ + type: 'layoutready', + layout: this + }); + } + }; - return this; + /** + * @brief : Logs a debug message in JS console, if DEBUG is ON + */ + // var logDebug = function(text) { + // if (DEBUG) { + // console.debug(text); + // } + // }; - } + /** + * @brief : Performs one iteration of the physical simulation + * @arg layoutInfo : LayoutInfo object already initialized + * @arg cy : Cytoscape object + * @arg options : Layout options + */ + var step = function step(layoutInfo, options, _step) { + // var s = "\n\n###############################"; + // s += "\nSTEP: " + step; + // s += "\n###############################\n"; + // logDebug(s); + + // Calculate node repulsions + calculateNodeForces(layoutInfo, options); + // Calculate edge forces + calculateEdgeForces(layoutInfo); + // Calculate gravity forces + calculateGravityForces(layoutInfo, options); + // Propagate forces from parent to child + propagateForces(layoutInfo); + // Update positions based on calculated forces + updatePositions(layoutInfo); + }; - copyLinearToSRGB( color ) { + /** + * @brief : Computes the node repulsion forces + */ + var calculateNodeForces = function calculateNodeForces(layoutInfo, options) { + // Go through each of the graphs in graphSet + // Nodes only repel each other if they belong to the same graph + // var s = 'calculateNodeForces'; + // logDebug(s); + for (var i = 0; i < layoutInfo.graphSet.length; i++) { + var graph = layoutInfo.graphSet[i]; + var numNodes = graph.length; + + // s = "Set: " + graph.toString(); + // logDebug(s); + + // Now get all the pairs of nodes + // Only get each pair once, (A, B) = (B, A) + for (var j = 0; j < numNodes; j++) { + var node1 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]]; + for (var k = j + 1; k < numNodes; k++) { + var node2 = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[k]]]; + nodeRepulsion(node1, node2, layoutInfo, options); + } + } + } + }; + var randomDistance = function randomDistance(max) { + return -max + 2 * max * Math.random(); + }; - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); + /** + * @brief : Compute the node repulsion forces between a pair of nodes + */ + var nodeRepulsion = function nodeRepulsion(node1, node2, layoutInfo, options) { + // var s = "Node repulsion. Node1: " + node1.id + " Node2: " + node2.id; - return this; + var cmptId1 = node1.cmptId; + var cmptId2 = node2.cmptId; + if (cmptId1 !== cmptId2 && !layoutInfo.isCompound) { + return; + } - } + // Get direction of line connecting both node centers + var directionX = node2.positionX - node1.positionX; + var directionY = node2.positionY - node1.positionY; + var maxRandDist = 1; + // s += "\ndirectionX: " + directionX + ", directionY: " + directionY; - convertSRGBToLinear() { + // If both centers are the same, apply a random force + if (0 === directionX && 0 === directionY) { + directionX = randomDistance(maxRandDist); + directionY = randomDistance(maxRandDist); + } + var overlap = nodesOverlap(node1, node2, directionX, directionY); + if (overlap > 0) { + // s += "\nNodes DO overlap."; + // s += "\nOverlap: " + overlap; + // If nodes overlap, repulsion force is proportional + // to the overlap + var force = options.nodeOverlap * overlap; + + // Compute the module and components of the force vector + var distance = Math.sqrt(directionX * directionX + directionY * directionY); + // s += "\nDistance: " + distance; + var forceX = force * directionX / distance; + var forceY = force * directionY / distance; + } else { + // s += "\nNodes do NOT overlap."; + // If there's no overlap, force is inversely proportional + // to squared distance + + // Get clipping points for both nodes + var point1 = findClippingPoint(node1, directionX, directionY); + var point2 = findClippingPoint(node2, -1 * directionX, -1 * directionY); + + // Use clipping points to compute distance + var distanceX = point2.x - point1.x; + var distanceY = point2.y - point1.y; + var distanceSqr = distanceX * distanceX + distanceY * distanceY; + var distance = Math.sqrt(distanceSqr); + // s += "\nDistance: " + distance; + + // Compute the module and components of the force vector + var force = (node1.nodeRepulsion + node2.nodeRepulsion) / distanceSqr; + var forceX = force * distanceX / distance; + var forceY = force * distanceY / distance; + } - this.copySRGBToLinear( this ); + // Apply force + if (!node1.isLocked) { + node1.offsetX -= forceX; + node1.offsetY -= forceY; + } + if (!node2.isLocked) { + node2.offsetX += forceX; + node2.offsetY += forceY; + } - return this; + // s += "\nForceX: " + forceX + " ForceY: " + forceY; + // logDebug(s); - } + return; + }; - convertLinearToSRGB() { + /** + * @brief : Determines whether two nodes overlap or not + * @return : Amount of overlapping (0 => no overlap) + */ + var nodesOverlap = function nodesOverlap(node1, node2, dX, dY) { + if (dX > 0) { + var overlapX = node1.maxX - node2.minX; + } else { + var overlapX = node2.maxX - node1.minX; + } + if (dY > 0) { + var overlapY = node1.maxY - node2.minY; + } else { + var overlapY = node2.maxY - node1.minY; + } + if (overlapX >= 0 && overlapY >= 0) { + return Math.sqrt(overlapX * overlapX + overlapY * overlapY); + } else { + return 0; + } + }; - this.copyLinearToSRGB( this ); + /** + * @brief : Finds the point in which an edge (direction dX, dY) intersects + * the rectangular bounding box of it's source/target node + */ + var findClippingPoint = function findClippingPoint(node, dX, dY) { + // Shorcuts + var X = node.positionX; + var Y = node.positionY; + var H = node.height || 1; + var W = node.width || 1; + var dirSlope = dY / dX; + var nodeSlope = H / W; + + // var s = 'Computing clipping point of node ' + node.id + + // " . Height: " + H + ", Width: " + W + + // "\nDirection " + dX + ", " + dY; + // + // Compute intersection + var res = {}; + + // Case: Vertical direction (up) + if (0 === dX && 0 < dY) { + res.x = X; + // s += "\nUp direction"; + res.y = Y + H / 2; + return res; + } - return this; + // Case: Vertical direction (down) + if (0 === dX && 0 > dY) { + res.x = X; + res.y = Y + H / 2; + // s += "\nDown direction"; - } + return res; + } - getHex( colorSpace = SRGBColorSpace ) { + // Case: Intersects the right border + if (0 < dX && -1 * nodeSlope <= dirSlope && dirSlope <= nodeSlope) { + res.x = X + W / 2; + res.y = Y + W * dY / 2 / dX; + // s += "\nRightborder"; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); + return res; + } - return clamp( _rgb.r * 255, 0, 255 ) << 16 ^ clamp( _rgb.g * 255, 0, 255 ) << 8 ^ clamp( _rgb.b * 255, 0, 255 ) << 0; + // Case: Intersects the left border + if (0 > dX && -1 * nodeSlope <= dirSlope && dirSlope <= nodeSlope) { + res.x = X - W / 2; + res.y = Y - W * dY / 2 / dX; + // s += "\nLeftborder"; - } + return res; + } - getHexString( colorSpace = SRGBColorSpace ) { + // Case: Intersects the top border + if (0 < dY && (dirSlope <= -1 * nodeSlope || dirSlope >= nodeSlope)) { + res.x = X + H * dX / 2 / dY; + res.y = Y + H / 2; + // s += "\nTop border"; - return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); + return res; + } - } + // Case: Intersects the bottom border + if (0 > dY && (dirSlope <= -1 * nodeSlope || dirSlope >= nodeSlope)) { + res.x = X - H * dX / 2 / dY; + res.y = Y - H / 2; + // s += "\nBottom border"; - getHSL( target, colorSpace = LinearSRGBColorSpace ) { + return res; + } - // h,s,l ranges are in 0.0 - 1.0 + // s += "\nClipping point found at " + res.x + ", " + res.y; + // logDebug(s); + return res; + }; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); + /** + * @brief : Calculates all edge forces + */ + var calculateEdgeForces = function calculateEdgeForces(layoutInfo, options) { + // Iterate over all edges + for (var i = 0; i < layoutInfo.edgeSize; i++) { + // Get edge, source & target nodes + var edge = layoutInfo.layoutEdges[i]; + var sourceIx = layoutInfo.idToIndex[edge.sourceId]; + var source = layoutInfo.layoutNodes[sourceIx]; + var targetIx = layoutInfo.idToIndex[edge.targetId]; + var target = layoutInfo.layoutNodes[targetIx]; + + // Get direction of line connecting both node centers + var directionX = target.positionX - source.positionX; + var directionY = target.positionY - source.positionY; + + // If both centers are the same, do nothing. + // A random force has already been applied as node repulsion + if (0 === directionX && 0 === directionY) { + continue; + } - const r = _rgb.r, g = _rgb.g, b = _rgb.b; + // Get clipping points for both nodes + var point1 = findClippingPoint(source, directionX, directionY); + var point2 = findClippingPoint(target, -1 * directionX, -1 * directionY); + var lx = point2.x - point1.x; + var ly = point2.y - point1.y; + var l = Math.sqrt(lx * lx + ly * ly); + var force = Math.pow(edge.idealLength - l, 2) / edge.elasticity; + if (0 !== l) { + var forceX = force * lx / l; + var forceY = force * ly / l; + } else { + var forceX = 0; + var forceY = 0; + } - const max = Math.max( r, g, b ); - const min = Math.min( r, g, b ); + // Add this force to target and source nodes + if (!source.isLocked) { + source.offsetX += forceX; + source.offsetY += forceY; + } + if (!target.isLocked) { + target.offsetX -= forceX; + target.offsetY -= forceY; + } - let hue, saturation; - const lightness = ( min + max ) / 2.0; + // var s = 'Edge force between nodes ' + source.id + ' and ' + target.id; + // s += "\nDistance: " + l + " Force: (" + forceX + ", " + forceY + ")"; + // logDebug(s); + } + }; - if ( min === max ) { + /** + * @brief : Computes gravity forces for all nodes + */ + var calculateGravityForces = function calculateGravityForces(layoutInfo, options) { + if (options.gravity === 0) { + return; + } + var distThreshold = 1; + + // var s = 'calculateGravityForces'; + // logDebug(s); + for (var i = 0; i < layoutInfo.graphSet.length; i++) { + var graph = layoutInfo.graphSet[i]; + var numNodes = graph.length; + + // s = "Set: " + graph.toString(); + // logDebug(s); + + // Compute graph center + if (0 === i) { + var centerX = layoutInfo.clientHeight / 2; + var centerY = layoutInfo.clientWidth / 2; + } else { + // Get Parent node for this graph, and use its position as center + var temp = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[0]]]; + var parent = layoutInfo.layoutNodes[layoutInfo.idToIndex[temp.parentId]]; + var centerX = parent.positionX; + var centerY = parent.positionY; + } + // s = "Center found at: " + centerX + ", " + centerY; + // logDebug(s); + + // Apply force to all nodes in graph + for (var j = 0; j < numNodes; j++) { + var node = layoutInfo.layoutNodes[layoutInfo.idToIndex[graph[j]]]; + // s = "Node: " + node.id; + + if (node.isLocked) { + continue; + } + var dx = centerX - node.positionX; + var dy = centerY - node.positionY; + var d = Math.sqrt(dx * dx + dy * dy); + if (d > distThreshold) { + var fx = options.gravity * dx / d; + var fy = options.gravity * dy / d; + node.offsetX += fx; + node.offsetY += fy; + // s += ": Applied force: " + fx + ", " + fy; + } + // logDebug(s); + } + } + }; - hue = 0; - saturation = 0; + /** + * @brief : This function propagates the existing offsets from + * parent nodes to its descendents. + * @arg layoutInfo : layoutInfo Object + * @arg cy : cytoscape Object + * @arg options : Layout options + */ + var propagateForces = function propagateForces(layoutInfo, options) { + // Inline implementation of a queue, used for traversing the graph in BFS order + var queue = []; + var start = 0; // Points to the start the queue + var end = -1; // Points to the end of the queue + + // logDebug('propagateForces'); + + // Start by visiting the nodes in the root graph + queue.push.apply(queue, layoutInfo.graphSet[0]); + end += layoutInfo.graphSet[0].length; + + // Traverse the graph, level by level, + while (start <= end) { + // Get the node to visit and remove it from queue + var nodeId = queue[start++]; + var nodeIndex = layoutInfo.idToIndex[nodeId]; + var node = layoutInfo.layoutNodes[nodeIndex]; + var children = node.children; + + // We only need to process the node if it's compound + if (0 < children.length && !node.isLocked) { + var offX = node.offsetX; + var offY = node.offsetY; + + // var s = "Propagating offset from parent node : " + node.id + + // ". OffsetX: " + offX + ". OffsetY: " + offY; + // s += "\n Children: " + children.toString(); + // logDebug(s); + + for (var i = 0; i < children.length; i++) { + var childNode = layoutInfo.layoutNodes[layoutInfo.idToIndex[children[i]]]; + // Propagate offset + childNode.offsetX += offX; + childNode.offsetY += offY; + // Add children to queue to be visited + queue[++end] = children[i]; + } + + // Reset parent offsets + node.offsetX = 0; + node.offsetY = 0; + } + } + }; - } else { + /** + * @brief : Updates the layout model positions, based on + * the accumulated forces + */ + var updatePositions = function updatePositions(layoutInfo, options) { + // var s = 'Updating positions'; + // logDebug(s); + + // Reset boundaries for compound nodes + for (var i = 0; i < layoutInfo.nodeSize; i++) { + var n = layoutInfo.layoutNodes[i]; + if (0 < n.children.length) { + // logDebug("Resetting boundaries of compound node: " + n.id); + n.maxX = undefined; + n.minX = undefined; + n.maxY = undefined; + n.minY = undefined; + } + } + for (var i = 0; i < layoutInfo.nodeSize; i++) { + var n = layoutInfo.layoutNodes[i]; + if (0 < n.children.length || n.isLocked) { + // No need to set compound or locked node position + // logDebug("Skipping position update of node: " + n.id); + continue; + } + // s = "Node: " + n.id + " Previous position: (" + + // n.positionX + ", " + n.positionY + ")."; + + // Limit displacement in order to improve stability + var tempForce = limitForce(n.offsetX, n.offsetY, layoutInfo.temperature); + n.positionX += tempForce.x; + n.positionY += tempForce.y; + n.offsetX = 0; + n.offsetY = 0; + n.minX = n.positionX - n.width; + n.maxX = n.positionX + n.width; + n.minY = n.positionY - n.height; + n.maxY = n.positionY + n.height; + // s += " New Position: (" + n.positionX + ", " + n.positionY + ")."; + // logDebug(s); + + // Update ancestry boudaries + updateAncestryBoundaries(n, layoutInfo); + } - const delta = max - min; + // Update size, position of compund nodes + for (var i = 0; i < layoutInfo.nodeSize; i++) { + var n = layoutInfo.layoutNodes[i]; + if (0 < n.children.length && !n.isLocked) { + n.positionX = (n.maxX + n.minX) / 2; + n.positionY = (n.maxY + n.minY) / 2; + n.width = n.maxX - n.minX; + n.height = n.maxY - n.minY; + // s = "Updating position, size of compound node " + n.id; + // s += "\nPositionX: " + n.positionX + ", PositionY: " + n.positionY; + // s += "\nWidth: " + n.width + ", Height: " + n.height; + // logDebug(s); + } + } + }; - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + /** + * @brief : Limits a force (forceX, forceY) to be not + * greater (in modulo) than max. + 8 Preserves force direction. + */ + var limitForce = function limitForce(forceX, forceY, max) { + // var s = "Limiting force: (" + forceX + ", " + forceY + "). Max: " + max; + var force = Math.sqrt(forceX * forceX + forceY * forceY); + if (force > max) { + var res = { + x: max * forceX / force, + y: max * forceY / force + }; + } else { + var res = { + x: forceX, + y: forceY + }; + } - switch ( max ) { + // s += ".\nResult: (" + res.x + ", " + res.y + ")"; + // logDebug(s); - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; + return res; + }; - } + /** + * @brief : Function used for keeping track of compound node + * sizes, since they should bound all their subnodes. + */ + var updateAncestryBoundaries = function updateAncestryBoundaries(node, layoutInfo) { + // var s = "Propagating new position/size of node " + node.id; + var parentId = node.parentId; + if (null == parentId) { + // If there's no parent, we are done + // s += ". No parent node."; + // logDebug(s); + return; + } - hue /= 6; + // Get Parent Node + var p = layoutInfo.layoutNodes[layoutInfo.idToIndex[parentId]]; + var flag = false; - } + // MaxX + if (null == p.maxX || node.maxX + p.padRight > p.maxX) { + p.maxX = node.maxX + p.padRight; + flag = true; + // s += "\nNew maxX for parent node " + p.id + ": " + p.maxX; + } - target.h = hue; - target.s = saturation; - target.l = lightness; + // MinX + if (null == p.minX || node.minX - p.padLeft < p.minX) { + p.minX = node.minX - p.padLeft; + flag = true; + // s += "\nNew minX for parent node " + p.id + ": " + p.minX; + } - return target; + // MaxY + if (null == p.maxY || node.maxY + p.padBottom > p.maxY) { + p.maxY = node.maxY + p.padBottom; + flag = true; + // s += "\nNew maxY for parent node " + p.id + ": " + p.maxY; + } - } + // MinY + if (null == p.minY || node.minY - p.padTop < p.minY) { + p.minY = node.minY - p.padTop; + flag = true; + // s += "\nNew minY for parent node " + p.id + ": " + p.minY; + } - getRGB( target, colorSpace = LinearSRGBColorSpace ) { + // If updated boundaries, propagate changes upward + if (flag) { + // logDebug(s); + return updateAncestryBoundaries(p, layoutInfo); + } - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); + // s += ". No changes in boundaries/position of parent node " + p.id; + // logDebug(s); + return; + }; + var separateComponents = function separateComponents(layoutInfo, options) { + var nodes = layoutInfo.layoutNodes; + var components = []; + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var cid = node.cmptId; + var component = components[cid] = components[cid] || []; + component.push(node); + } + var totalA = 0; + for (var i = 0; i < components.length; i++) { + var c = components[i]; + if (!c) { + continue; + } + c.x1 = Infinity; + c.x2 = -Infinity; + c.y1 = Infinity; + c.y2 = -Infinity; + for (var j = 0; j < c.length; j++) { + var n = c[j]; + c.x1 = Math.min(c.x1, n.positionX - n.width / 2); + c.x2 = Math.max(c.x2, n.positionX + n.width / 2); + c.y1 = Math.min(c.y1, n.positionY - n.height / 2); + c.y2 = Math.max(c.y2, n.positionY + n.height / 2); + } + c.w = c.x2 - c.x1; + c.h = c.y2 - c.y1; + totalA += c.w * c.h; + } + components.sort(function (c1, c2) { + return c2.w * c2.h - c1.w * c1.h; + }); + var x = 0; + var y = 0; + var usedW = 0; + var rowH = 0; + var maxRowW = Math.sqrt(totalA) * layoutInfo.clientWidth / layoutInfo.clientHeight; + for (var i = 0; i < components.length; i++) { + var c = components[i]; + if (!c) { + continue; + } + for (var j = 0; j < c.length; j++) { + var n = c[j]; + if (!n.isLocked) { + n.positionX += x - c.x1; + n.positionY += y - c.y1; + } + } + x += c.w + options.componentSpacing; + usedW += c.w + options.componentSpacing; + rowH = Math.max(rowH, c.h); + if (usedW > maxRowW) { + y += rowH + options.componentSpacing; + x = 0; + usedW = 0; + rowH = 0; + } + } + }; - target.r = _rgb.r; - target.g = _rgb.g; - target.b = _rgb.b; + var defaults$3 = { + fit: true, + // whether to fit the viewport to the graph + padding: 30, + // padding used on fit + boundingBox: undefined, + // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + avoidOverlap: true, + // prevents node overlap, may overflow boundingBox if not enough space + avoidOverlapPadding: 10, + // extra spacing around nodes when avoidOverlap: true + nodeDimensionsIncludeLabels: false, + // Excludes the label when calculating node bounding boxes for the layout algorithm + spacingFactor: undefined, + // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up + condense: false, + // uses all available space on false, uses minimal space on true + rows: undefined, + // force num of rows in the grid + cols: undefined, + // force num of columns in the grid + position: function position(node) {}, + // returns { row, col } for element + sort: undefined, + // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') } + animate: false, + // whether to transition the node positions + animationDuration: 500, + // duration of animation in ms if enabled + animationEasing: undefined, + // easing of animation if enabled + animateFilter: function animateFilter(node, i) { + return true; + }, + // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts + ready: undefined, + // callback on layoutready + stop: undefined, + // callback on layoutstop + transform: function transform(node, position) { + return position; + } // transform a given node position. Useful for changing flow direction in discrete layouts + }; - return target; + function GridLayout(options) { + this.options = extend$1({}, defaults$3, options); + } + GridLayout.prototype.run = function () { + var params = this.options; + var options = params; + var cy = params.cy; + var eles = options.eles; + var nodes = eles.nodes().not(':parent'); + if (options.sort) { + nodes = nodes.sort(options.sort); + } + var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : { + x1: 0, + y1: 0, + w: cy.width(), + h: cy.height() + }); + if (bb.h === 0 || bb.w === 0) { + eles.nodes().layoutPositions(this, options, function (ele) { + return { + x: bb.x1, + y: bb.y1 + }; + }); + } else { + // width/height * splits^2 = cells where splits is number of times to split width + var cells = nodes.size(); + var splits = Math.sqrt(cells * bb.h / bb.w); + var rows = Math.round(splits); + var cols = Math.round(bb.w / bb.h * splits); + var small = function small(val) { + if (val == null) { + return Math.min(rows, cols); + } else { + var min = Math.min(rows, cols); + if (min == rows) { + rows = val; + } else { + cols = val; + } + } + }; + var large = function large(val) { + if (val == null) { + return Math.max(rows, cols); + } else { + var max = Math.max(rows, cols); + if (max == rows) { + rows = val; + } else { + cols = val; + } + } + }; + var oRows = options.rows; + var oCols = options.cols != null ? options.cols : options.columns; + + // if rows or columns were set in options, use those values + if (oRows != null && oCols != null) { + rows = oRows; + cols = oCols; + } else if (oRows != null && oCols == null) { + rows = oRows; + cols = Math.ceil(cells / rows); + } else if (oRows == null && oCols != null) { + cols = oCols; + rows = Math.ceil(cells / cols); + } - } + // otherwise use the automatic values and adjust accordingly + + // if rounding was up, see if we can reduce rows or columns + else if (cols * rows > cells) { + var sm = small(); + var lg = large(); + + // reducing the small side takes away the most cells, so try it first + if ((sm - 1) * lg >= cells) { + small(sm - 1); + } else if ((lg - 1) * sm >= cells) { + large(lg - 1); + } + } else { + // if rounding was too low, add rows or columns + while (cols * rows < cells) { + var _sm = small(); + var _lg = large(); + + // try to add to larger side first (adds less in multiplication) + if ((_lg + 1) * _sm >= cells) { + large(_lg + 1); + } else { + small(_sm + 1); + } + } + } + var cellWidth = bb.w / cols; + var cellHeight = bb.h / rows; + if (options.condense) { + cellWidth = 0; + cellHeight = 0; + } + if (options.avoidOverlap) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var pos = node._private.position; + if (pos.x == null || pos.y == null) { + // for bb + pos.x = 0; + pos.y = 0; + } + var nbb = node.layoutDimensions(options); + var p = options.avoidOverlapPadding; + var w = nbb.w + p; + var h = nbb.h + p; + cellWidth = Math.max(cellWidth, w); + cellHeight = Math.max(cellHeight, h); + } + } + var cellUsed = {}; // e.g. 'c-0-2' => true - getStyle( colorSpace = SRGBColorSpace ) { + var used = function used(row, col) { + return cellUsed['c-' + row + '-' + col] ? true : false; + }; + var use = function use(row, col) { + cellUsed['c-' + row + '-' + col] = true; + }; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); + // to keep track of current cell position + var row = 0; + var col = 0; + var moveToNextCell = function moveToNextCell() { + col++; + if (col >= cols) { + col = 0; + row++; + } + }; - if ( colorSpace !== SRGBColorSpace ) { + // get a cache of all the manual positions + var id2manPos = {}; + for (var _i = 0; _i < nodes.length; _i++) { + var _node = nodes[_i]; + var rcPos = options.position(_node); + if (rcPos && (rcPos.row !== undefined || rcPos.col !== undefined)) { + // must have at least row or col def'd + var _pos = { + row: rcPos.row, + col: rcPos.col + }; + if (_pos.col === undefined) { + // find unused col + _pos.col = 0; + while (used(_pos.row, _pos.col)) { + _pos.col++; + } + } else if (_pos.row === undefined) { + // find unused row + _pos.row = 0; + while (used(_pos.row, _pos.col)) { + _pos.row++; + } + } + id2manPos[_node.id()] = _pos; + use(_pos.row, _pos.col); + } + } + var getPos = function getPos(element, i) { + var x, y; + if (element.locked() || element.isParent()) { + return false; + } + + // see if we have a manual position set + var rcPos = id2manPos[element.id()]; + if (rcPos) { + x = rcPos.col * cellWidth + cellWidth / 2 + bb.x1; + y = rcPos.row * cellHeight + cellHeight / 2 + bb.y1; + } else { + // otherwise set automatically + + while (used(row, col)) { + moveToNextCell(); + } + x = col * cellWidth + cellWidth / 2 + bb.x1; + y = row * cellHeight + cellHeight / 2 + bb.y1; + use(row, col); + moveToNextCell(); + } + return { + x: x, + y: y + }; + }; + nodes.layoutPositions(this, options, getPos); + } + return this; // chaining + }; - // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). - return `color(${ colorSpace } ${ _rgb.r } ${ _rgb.g } ${ _rgb.b })`; + // default layout options + var defaults$2 = { + ready: function ready() {}, + // on layoutready + stop: function stop() {} // on layoutstop + }; - } + // constructor + // options : object containing layout options + function NullLayout(options) { + this.options = extend$1({}, defaults$2, options); + } + + // runs the layout + NullLayout.prototype.run = function () { + var options = this.options; + var eles = options.eles; // elements to consider in the layout + var layout = this; + + // cy is automatically populated for us in the constructor + // (disable eslint for next line as this serves as example layout code to external developers) + // eslint-disable-next-line no-unused-vars + options.cy; + layout.emit('layoutstart'); + + // puts all nodes at (0, 0) + // n.b. most layouts would use layoutPositions(), instead of positions() and manual events + eles.nodes().positions(function () { + return { + x: 0, + y: 0 + }; + }); - return `rgb(${( _rgb.r * 255 ) | 0},${( _rgb.g * 255 ) | 0},${( _rgb.b * 255 ) | 0})`; + // trigger layoutready when each node has had its position set at least once + layout.one('layoutready', options.ready); + layout.emit('layoutready'); - } + // trigger layoutstop when the layout stops (e.g. finishes) + layout.one('layoutstop', options.stop); + layout.emit('layoutstop'); + return this; // chaining + }; - offsetHSL( h, s, l ) { + // called on continuous layouts to stop them before they finish + NullLayout.prototype.stop = function () { + return this; // chaining + }; - this.getHSL( _hslA ); + var defaults$1 = { + positions: undefined, + // map of (node id) => (position obj); or function(node){ return somPos; } + zoom: undefined, + // the zoom level to set (prob want fit = false if set) + pan: undefined, + // the pan level to set (prob want fit = false if set) + fit: true, + // whether to fit to viewport + padding: 30, + // padding on fit + spacingFactor: undefined, + // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up + animate: false, + // whether to transition the node positions + animationDuration: 500, + // duration of animation in ms if enabled + animationEasing: undefined, + // easing of animation if enabled + animateFilter: function animateFilter(node, i) { + return true; + }, + // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts + ready: undefined, + // callback on layoutready + stop: undefined, + // callback on layoutstop + transform: function transform(node, position) { + return position; + } // transform a given node position. Useful for changing flow direction in discrete layouts + }; - _hslA.h += h; _hslA.s += s; _hslA.l += l; + function PresetLayout(options) { + this.options = extend$1({}, defaults$1, options); + } + PresetLayout.prototype.run = function () { + var options = this.options; + var eles = options.eles; + var nodes = eles.nodes(); + var posIsFn = fn$6(options.positions); + function getPosition(node) { + if (options.positions == null) { + return copyPosition(node.position()); + } + if (posIsFn) { + return options.positions(node); + } + var pos = options.positions[node._private.data.id]; + if (pos == null) { + return null; + } + return pos; + } + nodes.layoutPositions(this, options, function (node, i) { + var position = getPosition(node); + if (node.locked() || position == null) { + return false; + } + return position; + }); + return this; // chaining + }; - this.setHSL( _hslA.h, _hslA.s, _hslA.l ); + var defaults = { + fit: true, + // whether to fit to viewport + padding: 30, + // fit padding + boundingBox: undefined, + // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + animate: false, + // whether to transition the node positions + animationDuration: 500, + // duration of animation in ms if enabled + animationEasing: undefined, + // easing of animation if enabled + animateFilter: function animateFilter(node, i) { + return true; + }, + // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts + ready: undefined, + // callback on layoutready + stop: undefined, + // callback on layoutstop + transform: function transform(node, position) { + return position; + } // transform a given node position. Useful for changing flow direction in discrete layouts + }; - return this; + function RandomLayout(options) { + this.options = extend$1({}, defaults, options); + } + RandomLayout.prototype.run = function () { + var options = this.options; + var cy = options.cy; + var eles = options.eles; + var bb = makeBoundingBox(options.boundingBox ? options.boundingBox : { + x1: 0, + y1: 0, + w: cy.width(), + h: cy.height() + }); + var getPos = function getPos(node, i) { + return { + x: bb.x1 + Math.round(Math.random() * bb.w), + y: bb.y1 + Math.round(Math.random() * bb.h) + }; + }; + eles.nodes().layoutPositions(this, options, getPos); + return this; // chaining + }; - } + var layout = [{ + name: 'breadthfirst', + impl: BreadthFirstLayout + }, { + name: 'circle', + impl: CircleLayout + }, { + name: 'concentric', + impl: ConcentricLayout + }, { + name: 'cose', + impl: CoseLayout + }, { + name: 'grid', + impl: GridLayout + }, { + name: 'null', + impl: NullLayout + }, { + name: 'preset', + impl: PresetLayout + }, { + name: 'random', + impl: RandomLayout + }]; + + function NullRenderer(options) { + this.options = options; + this.notifications = 0; // for testing + } + + var noop = function noop() {}; + var throwImgErr = function throwImgErr() { + throw new Error('A headless instance can not render images'); + }; + NullRenderer.prototype = { + recalculateRenderedStyle: noop, + notify: function notify() { + this.notifications++; + }, + init: noop, + isHeadless: function isHeadless() { + return true; + }, + png: throwImgErr, + jpg: throwImgErr + }; - add( color ) { + var BRp$f = {}; + BRp$f.arrowShapeWidth = 0.3; + BRp$f.registerArrowShapes = function () { + var arrowShapes = this.arrowShapes = {}; + var renderer = this; + + // Contract for arrow shapes: + // 0, 0 is arrow tip + // (0, 1) is direction towards node + // (1, 0) is right + // + // functional api: + // collide: check x, y in shape + // roughCollide: called before collide, no false negatives + // draw: draw + // spacing: dist(arrowTip, nodeBoundary) + // gap: dist(edgeTip, nodeBoundary), edgeTip may != arrowTip + + var bbCollide = function bbCollide(x, y, size, angle, translation, edgeWidth, padding) { + var x1 = translation.x - size / 2 - padding; + var x2 = translation.x + size / 2 + padding; + var y1 = translation.y - size / 2 - padding; + var y2 = translation.y + size / 2 + padding; + var inside = x1 <= x && x <= x2 && y1 <= y && y <= y2; + return inside; + }; + var transform = function transform(x, y, size, angle, translation) { + var xRotated = x * Math.cos(angle) - y * Math.sin(angle); + var yRotated = x * Math.sin(angle) + y * Math.cos(angle); + var xScaled = xRotated * size; + var yScaled = yRotated * size; + var xTranslated = xScaled + translation.x; + var yTranslated = yScaled + translation.y; + return { + x: xTranslated, + y: yTranslated + }; + }; + var transformPoints = function transformPoints(pts, size, angle, translation) { + var retPts = []; + for (var i = 0; i < pts.length; i += 2) { + var x = pts[i]; + var y = pts[i + 1]; + retPts.push(transform(x, y, size, angle, translation)); + } + return retPts; + }; + var pointsToArr = function pointsToArr(pts) { + var ret = []; + for (var i = 0; i < pts.length; i++) { + var p = pts[i]; + ret.push(p.x, p.y); + } + return ret; + }; + var standardGap = function standardGap(edge) { + return edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').pfValue * 2; + }; + var defineArrowShape = function defineArrowShape(name, defn) { + if (string(defn)) { + defn = arrowShapes[defn]; + } + arrowShapes[name] = extend$1({ + name: name, + points: [-0.15, -0.3, 0.15, -0.3, 0.15, 0.3, -0.15, 0.3], + collide: function collide(x, y, size, angle, translation, padding) { + var points = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation)); + var inside = pointInsidePolygonPoints(x, y, points); + return inside; + }, + roughCollide: bbCollide, + draw: function draw(context, size, angle, translation) { + var points = transformPoints(this.points, size, angle, translation); + renderer.arrowShapeImpl('polygon')(context, points); + }, + spacing: function spacing(edge) { + return 0; + }, + gap: standardGap + }, defn); + }; + defineArrowShape('none', { + collide: falsify, + roughCollide: falsify, + draw: noop$1, + spacing: zeroify, + gap: zeroify + }); + defineArrowShape('triangle', { + points: [-0.15, -0.3, 0, 0, 0.15, -0.3] + }); + defineArrowShape('arrow', 'triangle'); + defineArrowShape('triangle-backcurve', { + points: arrowShapes['triangle'].points, + controlPoint: [0, -0.15], + roughCollide: bbCollide, + draw: function draw(context, size, angle, translation, edgeWidth) { + var ptsTrans = transformPoints(this.points, size, angle, translation); + var ctrlPt = this.controlPoint; + var ctrlPtTrans = transform(ctrlPt[0], ctrlPt[1], size, angle, translation); + renderer.arrowShapeImpl(this.name)(context, ptsTrans, ctrlPtTrans); + }, + gap: function gap(edge) { + return standardGap(edge) * 0.8; + } + }); + defineArrowShape('triangle-tee', { + points: [0, 0, 0.15, -0.3, -0.15, -0.3, 0, 0], + pointsTee: [-0.15, -0.4, -0.15, -0.5, 0.15, -0.5, 0.15, -0.4], + collide: function collide(x, y, size, angle, translation, edgeWidth, padding) { + var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation)); + var teePts = pointsToArr(transformPoints(this.pointsTee, size + 2 * padding, angle, translation)); + var inside = pointInsidePolygonPoints(x, y, triPts) || pointInsidePolygonPoints(x, y, teePts); + return inside; + }, + draw: function draw(context, size, angle, translation, edgeWidth) { + var triPts = transformPoints(this.points, size, angle, translation); + var teePts = transformPoints(this.pointsTee, size, angle, translation); + renderer.arrowShapeImpl(this.name)(context, triPts, teePts); + } + }); + defineArrowShape('circle-triangle', { + radius: 0.15, + pointsTr: [0, -0.15, 0.15, -0.45, -0.15, -0.45, 0, -0.15], + collide: function collide(x, y, size, angle, translation, edgeWidth, padding) { + var t = translation; + var circleInside = Math.pow(t.x - x, 2) + Math.pow(t.y - y, 2) <= Math.pow((size + 2 * padding) * this.radius, 2); + var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation)); + return pointInsidePolygonPoints(x, y, triPts) || circleInside; + }, + draw: function draw(context, size, angle, translation, edgeWidth) { + var triPts = transformPoints(this.pointsTr, size, angle, translation); + renderer.arrowShapeImpl(this.name)(context, triPts, translation.x, translation.y, this.radius * size); + }, + spacing: function spacing(edge) { + return renderer.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.radius; + } + }); + defineArrowShape('triangle-cross', { + points: [0, 0, 0.15, -0.3, -0.15, -0.3, 0, 0], + baseCrossLinePts: [-0.15, -0.4, + // first half of the rectangle + -0.15, -0.4, 0.15, -0.4, + // second half of the rectangle + 0.15, -0.4], + crossLinePts: function crossLinePts(size, edgeWidth) { + // shift points so that the distance between the cross points matches edge width + var p = this.baseCrossLinePts.slice(); + var shiftFactor = edgeWidth / size; + var y0 = 3; + var y1 = 5; + p[y0] = p[y0] - shiftFactor; + p[y1] = p[y1] - shiftFactor; + return p; + }, + collide: function collide(x, y, size, angle, translation, edgeWidth, padding) { + var triPts = pointsToArr(transformPoints(this.points, size + 2 * padding, angle, translation)); + var teePts = pointsToArr(transformPoints(this.crossLinePts(size, edgeWidth), size + 2 * padding, angle, translation)); + var inside = pointInsidePolygonPoints(x, y, triPts) || pointInsidePolygonPoints(x, y, teePts); + return inside; + }, + draw: function draw(context, size, angle, translation, edgeWidth) { + var triPts = transformPoints(this.points, size, angle, translation); + var crossLinePts = transformPoints(this.crossLinePts(size, edgeWidth), size, angle, translation); + renderer.arrowShapeImpl(this.name)(context, triPts, crossLinePts); + } + }); + defineArrowShape('vee', { + points: [-0.15, -0.3, 0, 0, 0.15, -0.3, 0, -0.15], + gap: function gap(edge) { + return standardGap(edge) * 0.525; + } + }); + defineArrowShape('circle', { + radius: 0.15, + collide: function collide(x, y, size, angle, translation, edgeWidth, padding) { + var t = translation; + var inside = Math.pow(t.x - x, 2) + Math.pow(t.y - y, 2) <= Math.pow((size + 2 * padding) * this.radius, 2); + return inside; + }, + draw: function draw(context, size, angle, translation, edgeWidth) { + renderer.arrowShapeImpl(this.name)(context, translation.x, translation.y, this.radius * size); + }, + spacing: function spacing(edge) { + return renderer.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.radius; + } + }); + defineArrowShape('tee', { + points: [-0.15, 0, -0.15, -0.1, 0.15, -0.1, 0.15, 0], + spacing: function spacing(edge) { + return 1; + }, + gap: function gap(edge) { + return 1; + } + }); + defineArrowShape('square', { + points: [-0.15, 0.00, 0.15, 0.00, 0.15, -0.3, -0.15, -0.3] + }); + defineArrowShape('diamond', { + points: [-0.15, -0.15, 0, -0.3, 0.15, -0.15, 0, 0], + gap: function gap(edge) { + return edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').value; + } + }); + defineArrowShape('chevron', { + points: [0, 0, -0.15, -0.15, -0.1, -0.2, 0, -0.1, 0.1, -0.2, 0.15, -0.15], + gap: function gap(edge) { + return 0.95 * edge.pstyle('width').pfValue * edge.pstyle('arrow-scale').value; + } + }); + }; - this.r += color.r; - this.g += color.g; - this.b += color.b; + var BRp$e = {}; + + // Project mouse + BRp$e.projectIntoViewport = function (clientX, clientY) { + var cy = this.cy; + var offsets = this.findContainerClientCoords(); + var offsetLeft = offsets[0]; + var offsetTop = offsets[1]; + var scale = offsets[4]; + var pan = cy.pan(); + var zoom = cy.zoom(); + var x = ((clientX - offsetLeft) / scale - pan.x) / zoom; + var y = ((clientY - offsetTop) / scale - pan.y) / zoom; + return [x, y]; + }; + BRp$e.findContainerClientCoords = function () { + if (this.containerBB) { + return this.containerBB; + } + var container = this.container; + var rect = container.getBoundingClientRect(); + var style = this.cy.window().getComputedStyle(container); + var styleValue = function styleValue(name) { + return parseFloat(style.getPropertyValue(name)); + }; + var padding = { + left: styleValue('padding-left'), + right: styleValue('padding-right'), + top: styleValue('padding-top'), + bottom: styleValue('padding-bottom') + }; + var border = { + left: styleValue('border-left-width'), + right: styleValue('border-right-width'), + top: styleValue('border-top-width'), + bottom: styleValue('border-bottom-width') + }; + var clientWidth = container.clientWidth; + var clientHeight = container.clientHeight; + var paddingHor = padding.left + padding.right; + var paddingVer = padding.top + padding.bottom; + var borderHor = border.left + border.right; + var scale = rect.width / (clientWidth + borderHor); + var unscaledW = clientWidth - paddingHor; + var unscaledH = clientHeight - paddingVer; + var left = rect.left + padding.left + border.left; + var top = rect.top + padding.top + border.top; + return this.containerBB = [left, top, unscaledW, unscaledH, scale]; + }; + BRp$e.invalidateContainerClientCoordsCache = function () { + this.containerBB = null; + }; + BRp$e.findNearestElement = function (x, y, interactiveElementsOnly, isTouch) { + return this.findNearestElements(x, y, interactiveElementsOnly, isTouch)[0]; + }; + BRp$e.findNearestElements = function (x, y, interactiveElementsOnly, isTouch) { + var self = this; + var r = this; + var eles = r.getCachedZSortedEles(); + var near = []; // 1 node max, 1 edge max + var zoom = r.cy.zoom(); + var hasCompounds = r.cy.hasCompoundNodes(); + var edgeThreshold = (isTouch ? 24 : 8) / zoom; + var nodeThreshold = (isTouch ? 8 : 2) / zoom; + var labelThreshold = (isTouch ? 8 : 2) / zoom; + var minSqDist = Infinity; + var nearEdge; + var nearNode; + if (interactiveElementsOnly) { + eles = eles.interactive; + } + function addEle(ele, sqDist) { + if (ele.isNode()) { + if (nearNode) { + return; // can't replace node + } else { + nearNode = ele; + near.push(ele); + } + } + if (ele.isEdge() && (sqDist == null || sqDist < minSqDist)) { + if (nearEdge) { + // then replace existing edge + // can replace only if same z-index + if (nearEdge.pstyle('z-compound-depth').value === ele.pstyle('z-compound-depth').value && nearEdge.pstyle('z-compound-depth').value === ele.pstyle('z-compound-depth').value) { + for (var i = 0; i < near.length; i++) { + if (near[i].isEdge()) { + near[i] = ele; + nearEdge = ele; + minSqDist = sqDist != null ? sqDist : minSqDist; + break; + } + } + } + } else { + near.push(ele); + nearEdge = ele; + minSqDist = sqDist != null ? sqDist : minSqDist; + } + } + } + function checkNode(node) { + var width = node.outerWidth() + 2 * nodeThreshold; + var height = node.outerHeight() + 2 * nodeThreshold; + var hw = width / 2; + var hh = height / 2; + var pos = node.position(); + var cornerRadius = node.pstyle('corner-radius').value === 'auto' ? 'auto' : node.pstyle('corner-radius').pfValue; + var rs = node._private.rscratch; + if (pos.x - hw <= x && x <= pos.x + hw // bb check x + && pos.y - hh <= y && y <= pos.y + hh // bb check y + ) { + var shape = r.nodeShapes[self.getNodeShape(node)]; + if (shape.checkPoint(x, y, 0, width, height, pos.x, pos.y, cornerRadius, rs)) { + addEle(node, 0); + return true; + } + } + } + function checkEdge(edge) { + var _p = edge._private; + var rs = _p.rscratch; + var styleWidth = edge.pstyle('width').pfValue; + var scale = edge.pstyle('arrow-scale').value; + var width = styleWidth / 2 + edgeThreshold; // more like a distance radius from centre + var widthSq = width * width; + var width2 = width * 2; + var src = _p.source; + var tgt = _p.target; + var sqDist; + if (rs.edgeType === 'segments' || rs.edgeType === 'straight' || rs.edgeType === 'haystack') { + var pts = rs.allpts; + for (var i = 0; i + 3 < pts.length; i += 2) { + if (inLineVicinity(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], width2) && widthSq > (sqDist = sqdistToFiniteLine(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3]))) { + addEle(edge, sqDist); + return true; + } + } + } else if (rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound') { + var pts = rs.allpts; + for (var i = 0; i + 5 < rs.allpts.length; i += 4) { + if (inBezierVicinity(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], pts[i + 4], pts[i + 5], width2) && widthSq > (sqDist = sqdistToQuadraticBezier(x, y, pts[i], pts[i + 1], pts[i + 2], pts[i + 3], pts[i + 4], pts[i + 5]))) { + addEle(edge, sqDist); + return true; + } + } + } - return this; + // if we're close to the edge but didn't hit it, maybe we hit its arrows + + var src = src || _p.source; + var tgt = tgt || _p.target; + var arSize = self.getArrowWidth(styleWidth, scale); + var arrows = [{ + name: 'source', + x: rs.arrowStartX, + y: rs.arrowStartY, + angle: rs.srcArrowAngle + }, { + name: 'target', + x: rs.arrowEndX, + y: rs.arrowEndY, + angle: rs.tgtArrowAngle + }, { + name: 'mid-source', + x: rs.midX, + y: rs.midY, + angle: rs.midsrcArrowAngle + }, { + name: 'mid-target', + x: rs.midX, + y: rs.midY, + angle: rs.midtgtArrowAngle + }]; + for (var i = 0; i < arrows.length; i++) { + var ar = arrows[i]; + var shape = r.arrowShapes[edge.pstyle(ar.name + '-arrow-shape').value]; + var edgeWidth = edge.pstyle('width').pfValue; + if (shape.roughCollide(x, y, arSize, ar.angle, { + x: ar.x, + y: ar.y + }, edgeWidth, edgeThreshold) && shape.collide(x, y, arSize, ar.angle, { + x: ar.x, + y: ar.y + }, edgeWidth, edgeThreshold)) { + addEle(edge); + return true; + } + } - } + // for compound graphs, hitting edge may actually want a connected node instead (b/c edge may have greater z-index precedence) + if (hasCompounds && near.length > 0) { + checkNode(src); + checkNode(tgt); + } + } + function preprop(obj, name, pre) { + return getPrefixedProperty(obj, name, pre); + } + function checkLabel(ele, prefix) { + var _p = ele._private; + var th = labelThreshold; + var prefixDash; + if (prefix) { + prefixDash = prefix + '-'; + } else { + prefixDash = ''; + } + ele.boundingBox(); + var bb = _p.labelBounds[prefix || 'main']; + var text = ele.pstyle(prefixDash + 'label').value; + var eventsEnabled = ele.pstyle('text-events').strValue === 'yes'; + if (!eventsEnabled || !text) { + return; + } + var lx = preprop(_p.rscratch, 'labelX', prefix); + var ly = preprop(_p.rscratch, 'labelY', prefix); + var theta = preprop(_p.rscratch, 'labelAngle', prefix); + var ox = ele.pstyle(prefixDash + 'text-margin-x').pfValue; + var oy = ele.pstyle(prefixDash + 'text-margin-y').pfValue; + var lx1 = bb.x1 - th - ox; // (-ox, -oy) as bb already includes margin + var lx2 = bb.x2 + th - ox; // and rotation is about (lx, ly) + var ly1 = bb.y1 - th - oy; + var ly2 = bb.y2 + th - oy; + if (theta) { + var cos = Math.cos(theta); + var sin = Math.sin(theta); + var rotate = function rotate(x, y) { + x = x - lx; + y = y - ly; + return { + x: x * cos - y * sin + lx, + y: x * sin + y * cos + ly + }; + }; + var px1y1 = rotate(lx1, ly1); + var px1y2 = rotate(lx1, ly2); + var px2y1 = rotate(lx2, ly1); + var px2y2 = rotate(lx2, ly2); + var points = [ + // with the margin added after the rotation is applied + px1y1.x + ox, px1y1.y + oy, px2y1.x + ox, px2y1.y + oy, px2y2.x + ox, px2y2.y + oy, px1y2.x + ox, px1y2.y + oy]; + if (pointInsidePolygonPoints(x, y, points)) { + addEle(ele); + return true; + } + } else { + // do a cheaper bb check + if (inBoundingBox(bb, x, y)) { + addEle(ele); + return true; + } + } + } + for (var i = eles.length - 1; i >= 0; i--) { + // reverse order for precedence + var ele = eles[i]; + if (ele.isNode()) { + checkNode(ele) || checkLabel(ele); + } else { + // then edge + checkEdge(ele) || checkLabel(ele) || checkLabel(ele, 'source') || checkLabel(ele, 'target'); + } + } + return near; + }; - addColors( color1, color2 ) { + // 'Give me everything from this box' + BRp$e.getAllInBox = function (x1, y1, x2, y2) { + var eles = this.getCachedZSortedEles().interactive; + var box = []; + var x1c = Math.min(x1, x2); + var x2c = Math.max(x1, x2); + var y1c = Math.min(y1, y2); + var y2c = Math.max(y1, y2); + x1 = x1c; + x2 = x2c; + y1 = y1c; + y2 = y2c; + var boxBb = makeBoundingBox({ + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }); + for (var e = 0; e < eles.length; e++) { + var ele = eles[e]; + if (ele.isNode()) { + var node = ele; + var nodeBb = node.boundingBox({ + includeNodes: true, + includeEdges: false, + includeLabels: false + }); + if (boundingBoxesIntersect(boxBb, nodeBb) && !boundingBoxInBoundingBox(nodeBb, boxBb)) { + box.push(node); + } + } else { + var edge = ele; + var _p = edge._private; + var rs = _p.rscratch; + if (rs.startX != null && rs.startY != null && !inBoundingBox(boxBb, rs.startX, rs.startY)) { + continue; + } + if (rs.endX != null && rs.endY != null && !inBoundingBox(boxBb, rs.endX, rs.endY)) { + continue; + } + if (rs.edgeType === 'bezier' || rs.edgeType === 'multibezier' || rs.edgeType === 'self' || rs.edgeType === 'compound' || rs.edgeType === 'segments' || rs.edgeType === 'haystack') { + var pts = _p.rstyle.bezierPts || _p.rstyle.linePts || _p.rstyle.haystackPts; + var allInside = true; + for (var i = 0; i < pts.length; i++) { + if (!pointInBoundingBox(boxBb, pts[i])) { + allInside = false; + break; + } + } + if (allInside) { + box.push(edge); + } + } else if (rs.edgeType === 'haystack' || rs.edgeType === 'straight') { + box.push(edge); + } + } + } + return box; + }; - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + var BRp$d = {}; + BRp$d.calculateArrowAngles = function (edge) { + var rs = edge._private.rscratch; + var isHaystack = rs.edgeType === 'haystack'; + var isBezier = rs.edgeType === 'bezier'; + var isMultibezier = rs.edgeType === 'multibezier'; + var isSegments = rs.edgeType === 'segments'; + var isCompound = rs.edgeType === 'compound'; + var isSelf = rs.edgeType === 'self'; + + // Displacement gives direction for arrowhead orientation + var dispX, dispY; + var startX, startY, endX, endY, midX, midY; + if (isHaystack) { + startX = rs.haystackPts[0]; + startY = rs.haystackPts[1]; + endX = rs.haystackPts[2]; + endY = rs.haystackPts[3]; + } else { + startX = rs.arrowStartX; + startY = rs.arrowStartY; + endX = rs.arrowEndX; + endY = rs.arrowEndY; + } + midX = rs.midX; + midY = rs.midY; + + // source + // + + if (isSegments) { + dispX = startX - rs.segpts[0]; + dispY = startY - rs.segpts[1]; + } else if (isMultibezier || isCompound || isSelf || isBezier) { + var pts = rs.allpts; + var bX = qbezierAt(pts[0], pts[2], pts[4], 0.1); + var bY = qbezierAt(pts[1], pts[3], pts[5], 0.1); + dispX = startX - bX; + dispY = startY - bY; + } else { + dispX = startX - midX; + dispY = startY - midY; + } + rs.srcArrowAngle = getAngleFromDisp(dispX, dispY); - return this; + // mid target + // - } + var midX = rs.midX; + var midY = rs.midY; + if (isHaystack) { + midX = (startX + endX) / 2; + midY = (startY + endY) / 2; + } + dispX = endX - startX; + dispY = endY - startY; + if (isSegments) { + var pts = rs.allpts; + if (pts.length / 2 % 2 === 0) { + var i2 = pts.length / 2; + var i1 = i2 - 2; + dispX = pts[i2] - pts[i1]; + dispY = pts[i2 + 1] - pts[i1 + 1]; + } else if (rs.isRound) { + dispX = rs.midVector[1]; + dispY = -rs.midVector[0]; + } else { + var i2 = pts.length / 2 - 1; + var i1 = i2 - 2; + dispX = pts[i2] - pts[i1]; + dispY = pts[i2 + 1] - pts[i1 + 1]; + } + } else if (isMultibezier || isCompound || isSelf) { + var pts = rs.allpts; + var cpts = rs.ctrlpts; + var bp0x, bp0y; + var bp1x, bp1y; + if (cpts.length / 2 % 2 === 0) { + var p0 = pts.length / 2 - 1; // startpt + var ic = p0 + 2; + var p1 = ic + 2; + bp0x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.0); + bp0y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.0); + bp1x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.0001); + bp1y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.0001); + } else { + var ic = pts.length / 2 - 1; // ctrpt + var p0 = ic - 2; // startpt + var p1 = ic + 2; // endpt + + bp0x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.4999); + bp0y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.4999); + bp1x = qbezierAt(pts[p0], pts[ic], pts[p1], 0.5); + bp1y = qbezierAt(pts[p0 + 1], pts[ic + 1], pts[p1 + 1], 0.5); + } + dispX = bp1x - bp0x; + dispY = bp1y - bp0y; + } + rs.midtgtArrowAngle = getAngleFromDisp(dispX, dispY); + rs.midDispX = dispX; + rs.midDispY = dispY; + + // mid source + // + + dispX *= -1; + dispY *= -1; + if (isSegments) { + var pts = rs.allpts; + if (pts.length / 2 % 2 === 0) ; else if (!rs.isRound) { + var i2 = pts.length / 2 - 1; + var i3 = i2 + 2; + dispX = -(pts[i3] - pts[i2]); + dispY = -(pts[i3 + 1] - pts[i2 + 1]); + } + } + rs.midsrcArrowAngle = getAngleFromDisp(dispX, dispY); + + // target + // + + if (isSegments) { + dispX = endX - rs.segpts[rs.segpts.length - 2]; + dispY = endY - rs.segpts[rs.segpts.length - 1]; + } else if (isMultibezier || isCompound || isSelf || isBezier) { + var pts = rs.allpts; + var l = pts.length; + var bX = qbezierAt(pts[l - 6], pts[l - 4], pts[l - 2], 0.9); + var bY = qbezierAt(pts[l - 5], pts[l - 3], pts[l - 1], 0.9); + dispX = endX - bX; + dispY = endY - bY; + } else { + dispX = endX - midX; + dispY = endY - midY; + } + rs.tgtArrowAngle = getAngleFromDisp(dispX, dispY); + }; + BRp$d.getArrowWidth = BRp$d.getArrowHeight = function (edgeWidth, scale) { + var cache = this.arrowWidthCache = this.arrowWidthCache || {}; + var cachedVal = cache[edgeWidth + ', ' + scale]; + if (cachedVal) { + return cachedVal; + } + cachedVal = Math.max(Math.pow(edgeWidth * 13.37, 0.9), 29) * scale; + cache[edgeWidth + ', ' + scale] = cachedVal; + return cachedVal; + }; - addScalar( s ) { + /** + * Explained by Blindman67 at https://stackoverflow.com/a/44856925/11028828 + */ - this.r += s; - this.g += s; - this.b += s; + // Declare reused variable to avoid reallocating variables every time the function is called + var x, + y, + v1 = {}, + v2 = {}, + sinA, + sinA90, + radDirection, + drawDirection, + angle, + halfAngle, + cRadius, + lenOut, + radius, + limit; + var startX, startY, stopX, stopY; + var lastPoint; + + // convert 2 points into vector form, polar form, and normalised + var asVec = function asVec(p, pp, v) { + v.x = pp.x - p.x; + v.y = pp.y - p.y; + v.len = Math.sqrt(v.x * v.x + v.y * v.y); + v.nx = v.x / v.len; + v.ny = v.y / v.len; + v.ang = Math.atan2(v.ny, v.nx); + }; + var invertVec = function invertVec(originalV, invertedV) { + invertedV.x = originalV.x * -1; + invertedV.y = originalV.y * -1; + invertedV.nx = originalV.nx * -1; + invertedV.ny = originalV.ny * -1; + invertedV.ang = originalV.ang > 0 ? -(Math.PI - originalV.ang) : Math.PI + originalV.ang; + }; + var calcCornerArc = function calcCornerArc(previousPoint, currentPoint, nextPoint, radiusMax, isArcRadius) { + //----------------------------------------- + // Part 1 + previousPoint !== lastPoint ? asVec(currentPoint, previousPoint, v1) : invertVec(v2, v1); // Avoid recalculating vec if it is the invert of the last one calculated + asVec(currentPoint, nextPoint, v2); + sinA = v1.nx * v2.ny - v1.ny * v2.nx; + sinA90 = v1.nx * v2.nx - v1.ny * -v2.ny; + angle = Math.asin(Math.max(-1, Math.min(1, sinA))); + if (Math.abs(angle) < 1e-6) { + x = currentPoint.x; + y = currentPoint.y; + cRadius = radius = 0; + return; + } + //----------------------------------------- + radDirection = 1; + drawDirection = false; + if (sinA90 < 0) { + if (angle < 0) { + angle = Math.PI + angle; + } else { + angle = Math.PI - angle; + radDirection = -1; + drawDirection = true; + } + } else { + if (angle > 0) { + radDirection = -1; + drawDirection = true; + } + } + if (currentPoint.radius !== undefined) { + radius = currentPoint.radius; + } else { + radius = radiusMax; + } + //----------------------------------------- + // Part 2 + halfAngle = angle / 2; + //----------------------------------------- + + limit = Math.min(v1.len / 2, v2.len / 2); + if (isArcRadius) { + //----------------------------------------- + // Part 3 + lenOut = Math.abs(Math.cos(halfAngle) * radius / Math.sin(halfAngle)); + + //----------------------------------------- + // Special part A + if (lenOut > limit) { + lenOut = limit; + cRadius = Math.abs(lenOut * Math.sin(halfAngle) / Math.cos(halfAngle)); + } else { + cRadius = radius; + } + } else { + lenOut = Math.min(limit, radius); + cRadius = Math.abs(lenOut * Math.sin(halfAngle) / Math.cos(halfAngle)); + } + //----------------------------------------- + + //----------------------------------------- + // Part 4 + stopX = currentPoint.x + v2.nx * lenOut; + stopY = currentPoint.y + v2.ny * lenOut; + //----------------------------------------- + // Part 5 + x = stopX - v2.ny * cRadius * radDirection; + y = stopY + v2.nx * cRadius * radDirection; + //----------------------------------------- + // Additional Part : calculate start point E + startX = currentPoint.x + v1.nx * lenOut; + startY = currentPoint.y + v1.ny * lenOut; + + // Save last point to avoid recalculating vector when not needed + lastPoint = currentPoint; + }; - return this; + /** + * Draw corner provided by {@link getRoundCorner} + * + * @param ctx :CanvasRenderingContext2D + * @param roundCorner {{cx:number, cy:number, radius:number, endAngle: number, startAngle: number, counterClockwise: boolean}} + */ + function drawPreparedRoundCorner(ctx, roundCorner) { + if (roundCorner.radius === 0) ctx.lineTo(roundCorner.cx, roundCorner.cy);else ctx.arc(roundCorner.cx, roundCorner.cy, roundCorner.radius, roundCorner.startAngle, roundCorner.endAngle, roundCorner.counterClockwise); + } - } + /** + * Get round corner from a point and its previous and next neighbours in a path + * + * @param previousPoint {{x: number, y:number, radius: number?}} + * @param currentPoint {{x: number, y:number, radius: number?}} + * @param nextPoint {{x: number, y:number, radius: number?}} + * @param radiusMax :number + * @param isArcRadius :boolean + * @return {{ + * cx:number, cy:number, radius:number, + * startX:number, startY:number, + * stopX:number, stopY: number, + * endAngle: number, startAngle: number, counterClockwise: boolean + * }} + */ + function getRoundCorner(previousPoint, currentPoint, nextPoint, radiusMax) { + var isArcRadius = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; + if (radiusMax === 0 || currentPoint.radius === 0) return { + cx: currentPoint.x, + cy: currentPoint.y, + radius: 0, + startX: currentPoint.x, + startY: currentPoint.y, + stopX: currentPoint.x, + stopY: currentPoint.y, + startAngle: undefined, + endAngle: undefined, + counterClockwise: undefined + }; + calcCornerArc(previousPoint, currentPoint, nextPoint, radiusMax, isArcRadius); + return { + cx: x, + cy: y, + radius: cRadius, + startX: startX, + startY: startY, + stopX: stopX, + stopY: stopY, + startAngle: v1.ang + Math.PI / 2 * radDirection, + endAngle: v2.ang - Math.PI / 2 * radDirection, + counterClockwise: drawDirection + }; + } + + var BRp$c = {}; + BRp$c.findMidptPtsEtc = function (edge, pairInfo) { + var posPts = pairInfo.posPts, + intersectionPts = pairInfo.intersectionPts, + vectorNormInverse = pairInfo.vectorNormInverse; + var midptPts; + + // n.b. assumes all edges in bezier bundle have same endpoints specified + var srcManEndpt = edge.pstyle('source-endpoint'); + var tgtManEndpt = edge.pstyle('target-endpoint'); + var haveManualEndPts = srcManEndpt.units != null && tgtManEndpt.units != null; + var recalcVectorNormInverse = function recalcVectorNormInverse(x1, y1, x2, y2) { + var dy = y2 - y1; + var dx = x2 - x1; + var l = Math.sqrt(dx * dx + dy * dy); + return { + x: -dy / l, + y: dx / l + }; + }; + var edgeDistances = edge.pstyle('edge-distances').value; + switch (edgeDistances) { + case 'node-position': + midptPts = posPts; + break; + case 'intersection': + midptPts = intersectionPts; + break; + case 'endpoints': + { + if (haveManualEndPts) { + var _this$manualEndptToPx = this.manualEndptToPx(edge.source()[0], srcManEndpt), + _this$manualEndptToPx2 = _slicedToArray(_this$manualEndptToPx, 2), + x1 = _this$manualEndptToPx2[0], + y1 = _this$manualEndptToPx2[1]; + var _this$manualEndptToPx3 = this.manualEndptToPx(edge.target()[0], tgtManEndpt), + _this$manualEndptToPx4 = _slicedToArray(_this$manualEndptToPx3, 2), + x2 = _this$manualEndptToPx4[0], + y2 = _this$manualEndptToPx4[1]; + var endPts = { + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }; + vectorNormInverse = recalcVectorNormInverse(x1, y1, x2, y2); + midptPts = endPts; + } else { + warn("Edge ".concat(edge.id(), " has edge-distances:endpoints specified without manual endpoints specified via source-endpoint and target-endpoint. Falling back on edge-distances:intersection (default).")); + midptPts = intersectionPts; // back to default + } - sub( color ) { + break; + } + } + return { + midptPts: midptPts, + vectorNormInverse: vectorNormInverse + }; + }; + BRp$c.findHaystackPoints = function (edges) { + for (var i = 0; i < edges.length; i++) { + var edge = edges[i]; + var _p = edge._private; + var rs = _p.rscratch; + if (!rs.haystack) { + var angle = Math.random() * 2 * Math.PI; + rs.source = { + x: Math.cos(angle), + y: Math.sin(angle) + }; + angle = Math.random() * 2 * Math.PI; + rs.target = { + x: Math.cos(angle), + y: Math.sin(angle) + }; + } + var src = _p.source; + var tgt = _p.target; + var srcPos = src.position(); + var tgtPos = tgt.position(); + var srcW = src.width(); + var tgtW = tgt.width(); + var srcH = src.height(); + var tgtH = tgt.height(); + var radius = edge.pstyle('haystack-radius').value; + var halfRadius = radius / 2; // b/c have to half width/height + + rs.haystackPts = rs.allpts = [rs.source.x * srcW * halfRadius + srcPos.x, rs.source.y * srcH * halfRadius + srcPos.y, rs.target.x * tgtW * halfRadius + tgtPos.x, rs.target.y * tgtH * halfRadius + tgtPos.y]; + rs.midX = (rs.allpts[0] + rs.allpts[2]) / 2; + rs.midY = (rs.allpts[1] + rs.allpts[3]) / 2; + + // always override as haystack in case set to different type previously + rs.edgeType = 'haystack'; + rs.haystack = true; + this.storeEdgeProjections(edge); + this.calculateArrowAngles(edge); + this.recalculateEdgeLabelProjections(edge); + this.calculateLabelAngles(edge); + } + }; + BRp$c.findSegmentsPoints = function (edge, pairInfo) { + // Segments (multiple straight lines) + + var rs = edge._private.rscratch; + var segmentWs = edge.pstyle('segment-weights'); + var segmentDs = edge.pstyle('segment-distances'); + var segmentRs = edge.pstyle('segment-radii'); + var segmentTs = edge.pstyle('radius-type'); + var segmentsN = Math.min(segmentWs.pfValue.length, segmentDs.pfValue.length); + var lastRadius = segmentRs.pfValue[segmentRs.pfValue.length - 1]; + var lastRadiusType = segmentTs.pfValue[segmentTs.pfValue.length - 1]; + rs.edgeType = 'segments'; + rs.segpts = []; + rs.radii = []; + rs.isArcRadius = []; + for (var s = 0; s < segmentsN; s++) { + var w = segmentWs.pfValue[s]; + var d = segmentDs.pfValue[s]; + var w1 = 1 - w; + var w2 = w; + var _this$findMidptPtsEtc = this.findMidptPtsEtc(edge, pairInfo), + midptPts = _this$findMidptPtsEtc.midptPts, + vectorNormInverse = _this$findMidptPtsEtc.vectorNormInverse; + var adjustedMidpt = { + x: midptPts.x1 * w1 + midptPts.x2 * w2, + y: midptPts.y1 * w1 + midptPts.y2 * w2 + }; + rs.segpts.push(adjustedMidpt.x + vectorNormInverse.x * d, adjustedMidpt.y + vectorNormInverse.y * d); + rs.radii.push(segmentRs.pfValue[s] !== undefined ? segmentRs.pfValue[s] : lastRadius); + rs.isArcRadius.push((segmentTs.pfValue[s] !== undefined ? segmentTs.pfValue[s] : lastRadiusType) === 'arc-radius'); + } + }; + BRp$c.findLoopPoints = function (edge, pairInfo, i, edgeIsUnbundled) { + // Self-edge + + var rs = edge._private.rscratch; + var dirCounts = pairInfo.dirCounts, + srcPos = pairInfo.srcPos; + var ctrlptDists = edge.pstyle('control-point-distances'); + var ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[0] : undefined; + var loopDir = edge.pstyle('loop-direction').pfValue; + var loopSwp = edge.pstyle('loop-sweep').pfValue; + var stepSize = edge.pstyle('control-point-step-size').pfValue; + rs.edgeType = 'self'; + var j = i; + var loopDist = stepSize; + if (edgeIsUnbundled) { + j = 0; + loopDist = ctrlptDist; + } + var loopAngle = loopDir - Math.PI / 2; + var outAngle = loopAngle - loopSwp / 2; + var inAngle = loopAngle + loopSwp / 2; + + // increase by step size for overlapping loops, keyed on direction and sweep values + var dc = String(loopDir + '_' + loopSwp); + j = dirCounts[dc] === undefined ? dirCounts[dc] = 0 : ++dirCounts[dc]; + rs.ctrlpts = [srcPos.x + Math.cos(outAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.y + Math.sin(outAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.x + Math.cos(inAngle) * 1.4 * loopDist * (j / 3 + 1), srcPos.y + Math.sin(inAngle) * 1.4 * loopDist * (j / 3 + 1)]; + }; + BRp$c.findCompoundLoopPoints = function (edge, pairInfo, i, edgeIsUnbundled) { + // Compound edge + + var rs = edge._private.rscratch; + rs.edgeType = 'compound'; + var srcPos = pairInfo.srcPos, + tgtPos = pairInfo.tgtPos, + srcW = pairInfo.srcW, + srcH = pairInfo.srcH, + tgtW = pairInfo.tgtW, + tgtH = pairInfo.tgtH; + var stepSize = edge.pstyle('control-point-step-size').pfValue; + var ctrlptDists = edge.pstyle('control-point-distances'); + var ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[0] : undefined; + var j = i; + var loopDist = stepSize; + if (edgeIsUnbundled) { + j = 0; + loopDist = ctrlptDist; + } + var loopW = 50; + var loopaPos = { + x: srcPos.x - srcW / 2, + y: srcPos.y - srcH / 2 + }; + var loopbPos = { + x: tgtPos.x - tgtW / 2, + y: tgtPos.y - tgtH / 2 + }; + var loopPos = { + x: Math.min(loopaPos.x, loopbPos.x), + y: Math.min(loopaPos.y, loopbPos.y) + }; + + // avoids cases with impossible beziers + var minCompoundStretch = 0.5; + var compoundStretchA = Math.max(minCompoundStretch, Math.log(srcW * 0.01)); + var compoundStretchB = Math.max(minCompoundStretch, Math.log(tgtW * 0.01)); + rs.ctrlpts = [loopPos.x, loopPos.y - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchA, loopPos.x - (1 + Math.pow(loopW, 1.12) / 100) * loopDist * (j / 3 + 1) * compoundStretchB, loopPos.y]; + }; + BRp$c.findStraightEdgePoints = function (edge) { + // Straight edge within bundle - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); + edge._private.rscratch.edgeType = 'straight'; + }; + BRp$c.findBezierPoints = function (edge, pairInfo, i, edgeIsUnbundled, edgeIsSwapped) { + var rs = edge._private.rscratch; + var stepSize = edge.pstyle('control-point-step-size').pfValue; + var ctrlptDists = edge.pstyle('control-point-distances'); + var ctrlptWs = edge.pstyle('control-point-weights'); + var bezierN = ctrlptDists && ctrlptWs ? Math.min(ctrlptDists.value.length, ctrlptWs.value.length) : 1; + var ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[0] : undefined; + var ctrlptWeight = ctrlptWs.value[0]; + + // (Multi)bezier + + var multi = edgeIsUnbundled; + rs.edgeType = multi ? 'multibezier' : 'bezier'; + rs.ctrlpts = []; + for (var b = 0; b < bezierN; b++) { + var normctrlptDist = (0.5 - pairInfo.eles.length / 2 + i) * stepSize * (edgeIsSwapped ? -1 : 1); + var manctrlptDist = void 0; + var sign = signum(normctrlptDist); + if (multi) { + ctrlptDist = ctrlptDists ? ctrlptDists.pfValue[b] : stepSize; // fall back on step size + ctrlptWeight = ctrlptWs.value[b]; + } + if (edgeIsUnbundled) { + // multi or single unbundled + manctrlptDist = ctrlptDist; + } else { + manctrlptDist = ctrlptDist !== undefined ? sign * ctrlptDist : undefined; + } + var distanceFromMidpoint = manctrlptDist !== undefined ? manctrlptDist : normctrlptDist; + var w1 = 1 - ctrlptWeight; + var w2 = ctrlptWeight; + var _this$findMidptPtsEtc2 = this.findMidptPtsEtc(edge, pairInfo), + midptPts = _this$findMidptPtsEtc2.midptPts, + vectorNormInverse = _this$findMidptPtsEtc2.vectorNormInverse; + var adjustedMidpt = { + x: midptPts.x1 * w1 + midptPts.x2 * w2, + y: midptPts.y1 * w1 + midptPts.y2 * w2 + }; + rs.ctrlpts.push(adjustedMidpt.x + vectorNormInverse.x * distanceFromMidpoint, adjustedMidpt.y + vectorNormInverse.y * distanceFromMidpoint); + } + }; + BRp$c.findTaxiPoints = function (edge, pairInfo) { + // Taxicab geometry with two turns maximum + + var rs = edge._private.rscratch; + rs.edgeType = 'segments'; + var VERTICAL = 'vertical'; + var HORIZONTAL = 'horizontal'; + var LEFTWARD = 'leftward'; + var RIGHTWARD = 'rightward'; + var DOWNWARD = 'downward'; + var UPWARD = 'upward'; + var AUTO = 'auto'; + var posPts = pairInfo.posPts, + srcW = pairInfo.srcW, + srcH = pairInfo.srcH, + tgtW = pairInfo.tgtW, + tgtH = pairInfo.tgtH; + var edgeDistances = edge.pstyle('edge-distances').value; + var dIncludesNodeBody = edgeDistances !== 'node-position'; + var taxiDir = edge.pstyle('taxi-direction').value; + var rawTaxiDir = taxiDir; // unprocessed value + var taxiTurn = edge.pstyle('taxi-turn'); + var turnIsPercent = taxiTurn.units === '%'; + var taxiTurnPfVal = taxiTurn.pfValue; + var turnIsNegative = taxiTurnPfVal < 0; // i.e. from target side + var minD = edge.pstyle('taxi-turn-min-distance').pfValue; + var dw = dIncludesNodeBody ? (srcW + tgtW) / 2 : 0; + var dh = dIncludesNodeBody ? (srcH + tgtH) / 2 : 0; + var pdx = posPts.x2 - posPts.x1; + var pdy = posPts.y2 - posPts.y1; + + // take away the effective w/h from the magnitude of the delta value + var subDWH = function subDWH(dxy, dwh) { + if (dxy > 0) { + return Math.max(dxy - dwh, 0); + } else { + return Math.min(dxy + dwh, 0); + } + }; + var dx = subDWH(pdx, dw); + var dy = subDWH(pdy, dh); + var isExplicitDir = false; + if (rawTaxiDir === AUTO) { + taxiDir = Math.abs(dx) > Math.abs(dy) ? HORIZONTAL : VERTICAL; + } else if (rawTaxiDir === UPWARD || rawTaxiDir === DOWNWARD) { + taxiDir = VERTICAL; + isExplicitDir = true; + } else if (rawTaxiDir === LEFTWARD || rawTaxiDir === RIGHTWARD) { + taxiDir = HORIZONTAL; + isExplicitDir = true; + } + var isVert = taxiDir === VERTICAL; + var l = isVert ? dy : dx; + var pl = isVert ? pdy : pdx; + var sgnL = signum(pl); + var forcedDir = false; + if (!(isExplicitDir && (turnIsPercent || turnIsNegative)) // forcing in this case would cause weird growing in the opposite direction + && (rawTaxiDir === DOWNWARD && pl < 0 || rawTaxiDir === UPWARD && pl > 0 || rawTaxiDir === LEFTWARD && pl > 0 || rawTaxiDir === RIGHTWARD && pl < 0)) { + sgnL *= -1; + l = sgnL * Math.abs(l); + forcedDir = true; + } + var d; + if (turnIsPercent) { + var p = taxiTurnPfVal < 0 ? 1 + taxiTurnPfVal : taxiTurnPfVal; + d = p * l; + } else { + var k = taxiTurnPfVal < 0 ? l : 0; + d = k + taxiTurnPfVal * sgnL; + } + var getIsTooClose = function getIsTooClose(d) { + return Math.abs(d) < minD || Math.abs(d) >= Math.abs(l); + }; + var isTooCloseSrc = getIsTooClose(d); + var isTooCloseTgt = getIsTooClose(Math.abs(l) - Math.abs(d)); + var isTooClose = isTooCloseSrc || isTooCloseTgt; + if (isTooClose && !forcedDir) { + // non-ideal routing + if (isVert) { + // vertical fallbacks + var lShapeInsideSrc = Math.abs(pl) <= srcH / 2; + var lShapeInsideTgt = Math.abs(pdx) <= tgtW / 2; + if (lShapeInsideSrc) { + // horizontal Z-shape (direction not respected) + var x = (posPts.x1 + posPts.x2) / 2; + var y1 = posPts.y1, + y2 = posPts.y2; + rs.segpts = [x, y1, x, y2]; + } else if (lShapeInsideTgt) { + // vertical Z-shape (distance not respected) + var y = (posPts.y1 + posPts.y2) / 2; + var x1 = posPts.x1, + x2 = posPts.x2; + rs.segpts = [x1, y, x2, y]; + } else { + // L-shape fallback (turn distance not respected, but works well with tree siblings) + rs.segpts = [posPts.x1, posPts.y2]; + } + } else { + // horizontal fallbacks + var _lShapeInsideSrc = Math.abs(pl) <= srcW / 2; + var _lShapeInsideTgt = Math.abs(pdy) <= tgtH / 2; + if (_lShapeInsideSrc) { + // vertical Z-shape (direction not respected) + var _y = (posPts.y1 + posPts.y2) / 2; + var _x = posPts.x1, + _x2 = posPts.x2; + rs.segpts = [_x, _y, _x2, _y]; + } else if (_lShapeInsideTgt) { + // horizontal Z-shape (turn distance not respected) + var _x3 = (posPts.x1 + posPts.x2) / 2; + var _y2 = posPts.y1, + _y3 = posPts.y2; + rs.segpts = [_x3, _y2, _x3, _y3]; + } else { + // L-shape (turn distance not respected, but works well for tree siblings) + rs.segpts = [posPts.x2, posPts.y1]; + } + } + } else { + // ideal routing + if (isVert) { + var _y4 = posPts.y1 + d + (dIncludesNodeBody ? srcH / 2 * sgnL : 0); + var _x4 = posPts.x1, + _x5 = posPts.x2; + rs.segpts = [_x4, _y4, _x5, _y4]; + } else { + // horizontal + var _x6 = posPts.x1 + d + (dIncludesNodeBody ? srcW / 2 * sgnL : 0); + var _y5 = posPts.y1, + _y6 = posPts.y2; + rs.segpts = [_x6, _y5, _x6, _y6]; + } + } + if (rs.isRound) { + var radius = edge.pstyle('taxi-radius').value; + var isArcRadius = edge.pstyle('radius-type').value[0] === 'arc-radius'; + rs.radii = new Array(rs.segpts.length / 2).fill(radius); + rs.isArcRadius = new Array(rs.segpts.length / 2).fill(isArcRadius); + } + }; + BRp$c.tryToCorrectInvalidPoints = function (edge, pairInfo) { + var rs = edge._private.rscratch; + + // can only correct beziers for now... + if (rs.edgeType === 'bezier') { + var srcPos = pairInfo.srcPos, + tgtPos = pairInfo.tgtPos, + srcW = pairInfo.srcW, + srcH = pairInfo.srcH, + tgtW = pairInfo.tgtW, + tgtH = pairInfo.tgtH, + srcShape = pairInfo.srcShape, + tgtShape = pairInfo.tgtShape, + srcCornerRadius = pairInfo.srcCornerRadius, + tgtCornerRadius = pairInfo.tgtCornerRadius, + srcRs = pairInfo.srcRs, + tgtRs = pairInfo.tgtRs; + var badStart = !number$1(rs.startX) || !number$1(rs.startY); + var badAStart = !number$1(rs.arrowStartX) || !number$1(rs.arrowStartY); + var badEnd = !number$1(rs.endX) || !number$1(rs.endY); + var badAEnd = !number$1(rs.arrowEndX) || !number$1(rs.arrowEndY); + var minCpADistFactor = 3; + var arrowW = this.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.arrowShapeWidth; + var minCpADist = minCpADistFactor * arrowW; + var startACpDist = dist({ + x: rs.ctrlpts[0], + y: rs.ctrlpts[1] + }, { + x: rs.startX, + y: rs.startY + }); + var closeStartACp = startACpDist < minCpADist; + var endACpDist = dist({ + x: rs.ctrlpts[0], + y: rs.ctrlpts[1] + }, { + x: rs.endX, + y: rs.endY + }); + var closeEndACp = endACpDist < minCpADist; + var overlapping = false; + if (badStart || badAStart || closeStartACp) { + overlapping = true; + + // project control point along line from src centre to outside the src shape + // (otherwise intersection will yield nothing) + var cpD = { + // delta + x: rs.ctrlpts[0] - srcPos.x, + y: rs.ctrlpts[1] - srcPos.y + }; + var cpL = Math.sqrt(cpD.x * cpD.x + cpD.y * cpD.y); // length of line + var cpM = { + // normalised delta + x: cpD.x / cpL, + y: cpD.y / cpL + }; + var radius = Math.max(srcW, srcH); + var cpProj = { + // *2 radius guarantees outside shape + x: rs.ctrlpts[0] + cpM.x * 2 * radius, + y: rs.ctrlpts[1] + cpM.y * 2 * radius + }; + var srcCtrlPtIntn = srcShape.intersectLine(srcPos.x, srcPos.y, srcW, srcH, cpProj.x, cpProj.y, 0, srcCornerRadius, srcRs); + if (closeStartACp) { + rs.ctrlpts[0] = rs.ctrlpts[0] + cpM.x * (minCpADist - startACpDist); + rs.ctrlpts[1] = rs.ctrlpts[1] + cpM.y * (minCpADist - startACpDist); + } else { + rs.ctrlpts[0] = srcCtrlPtIntn[0] + cpM.x * minCpADist; + rs.ctrlpts[1] = srcCtrlPtIntn[1] + cpM.y * minCpADist; + } + } + if (badEnd || badAEnd || closeEndACp) { + overlapping = true; + + // project control point along line from tgt centre to outside the tgt shape + // (otherwise intersection will yield nothing) + var _cpD = { + // delta + x: rs.ctrlpts[0] - tgtPos.x, + y: rs.ctrlpts[1] - tgtPos.y + }; + var _cpL = Math.sqrt(_cpD.x * _cpD.x + _cpD.y * _cpD.y); // length of line + var _cpM = { + // normalised delta + x: _cpD.x / _cpL, + y: _cpD.y / _cpL + }; + var _radius = Math.max(srcW, srcH); + var _cpProj = { + // *2 radius guarantees outside shape + x: rs.ctrlpts[0] + _cpM.x * 2 * _radius, + y: rs.ctrlpts[1] + _cpM.y * 2 * _radius + }; + var tgtCtrlPtIntn = tgtShape.intersectLine(tgtPos.x, tgtPos.y, tgtW, tgtH, _cpProj.x, _cpProj.y, 0, tgtCornerRadius, tgtRs); + if (closeEndACp) { + rs.ctrlpts[0] = rs.ctrlpts[0] + _cpM.x * (minCpADist - endACpDist); + rs.ctrlpts[1] = rs.ctrlpts[1] + _cpM.y * (minCpADist - endACpDist); + } else { + rs.ctrlpts[0] = tgtCtrlPtIntn[0] + _cpM.x * minCpADist; + rs.ctrlpts[1] = tgtCtrlPtIntn[1] + _cpM.y * minCpADist; + } + } + if (overlapping) { + // recalc endpts + this.findEndpoints(edge); + } + } + }; + BRp$c.storeAllpts = function (edge) { + var rs = edge._private.rscratch; + if (rs.edgeType === 'multibezier' || rs.edgeType === 'bezier' || rs.edgeType === 'self' || rs.edgeType === 'compound') { + rs.allpts = []; + rs.allpts.push(rs.startX, rs.startY); + for (var b = 0; b + 1 < rs.ctrlpts.length; b += 2) { + // ctrl pt itself + rs.allpts.push(rs.ctrlpts[b], rs.ctrlpts[b + 1]); + + // the midpt between ctrlpts as intermediate destination pts + if (b + 3 < rs.ctrlpts.length) { + rs.allpts.push((rs.ctrlpts[b] + rs.ctrlpts[b + 2]) / 2, (rs.ctrlpts[b + 1] + rs.ctrlpts[b + 3]) / 2); + } + } + rs.allpts.push(rs.endX, rs.endY); + var m, mt; + if (rs.ctrlpts.length / 2 % 2 === 0) { + m = rs.allpts.length / 2 - 1; + rs.midX = rs.allpts[m]; + rs.midY = rs.allpts[m + 1]; + } else { + m = rs.allpts.length / 2 - 3; + mt = 0.5; + rs.midX = qbezierAt(rs.allpts[m], rs.allpts[m + 2], rs.allpts[m + 4], mt); + rs.midY = qbezierAt(rs.allpts[m + 1], rs.allpts[m + 3], rs.allpts[m + 5], mt); + } + } else if (rs.edgeType === 'straight') { + // need to calc these after endpts + rs.allpts = [rs.startX, rs.startY, rs.endX, rs.endY]; + + // default midpt for labels etc + rs.midX = (rs.startX + rs.endX + rs.arrowStartX + rs.arrowEndX) / 4; + rs.midY = (rs.startY + rs.endY + rs.arrowStartY + rs.arrowEndY) / 4; + } else if (rs.edgeType === 'segments') { + rs.allpts = []; + rs.allpts.push(rs.startX, rs.startY); + rs.allpts.push.apply(rs.allpts, rs.segpts); + rs.allpts.push(rs.endX, rs.endY); + if (rs.isRound) { + rs.roundCorners = []; + for (var i = 2; i + 3 < rs.allpts.length; i += 2) { + var radius = rs.radii[i / 2 - 1]; + var isArcRadius = rs.isArcRadius[i / 2 - 1]; + rs.roundCorners.push(getRoundCorner({ + x: rs.allpts[i - 2], + y: rs.allpts[i - 1] + }, { + x: rs.allpts[i], + y: rs.allpts[i + 1], + radius: radius + }, { + x: rs.allpts[i + 2], + y: rs.allpts[i + 3] + }, radius, isArcRadius)); + } + } + if (rs.segpts.length % 4 === 0) { + var i2 = rs.segpts.length / 2; + var i1 = i2 - 2; + rs.midX = (rs.segpts[i1] + rs.segpts[i2]) / 2; + rs.midY = (rs.segpts[i1 + 1] + rs.segpts[i2 + 1]) / 2; + } else { + var _i = rs.segpts.length / 2 - 1; + if (!rs.isRound) { + rs.midX = rs.segpts[_i]; + rs.midY = rs.segpts[_i + 1]; + } else { + var point = { + x: rs.segpts[_i], + y: rs.segpts[_i + 1] + }; + var corner = rs.roundCorners[_i / 2]; + var v = [point.x - corner.cx, point.y - corner.cy]; + var factor = corner.radius / Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2)); + v = v.map(function (c) { + return c * factor; + }); + rs.midX = corner.cx + v[0]; + rs.midY = corner.cy + v[1]; + rs.midVector = v; + } + } + } + }; + BRp$c.checkForInvalidEdgeWarning = function (edge) { + var rs = edge[0]._private.rscratch; + if (rs.nodesOverlap || number$1(rs.startX) && number$1(rs.startY) && number$1(rs.endX) && number$1(rs.endY)) { + rs.loggedErr = false; + } else { + if (!rs.loggedErr) { + rs.loggedErr = true; + warn('Edge `' + edge.id() + '` has invalid endpoints and so it is impossible to draw. Adjust your edge style (e.g. control points) accordingly or use an alternative edge type. This is expected behaviour when the source node and the target node overlap.'); + } + } + }; + BRp$c.findEdgeControlPoints = function (edges) { + var _this = this; + if (!edges || edges.length === 0) { + return; + } + var r = this; + var cy = r.cy; + var hasCompounds = cy.hasCompoundNodes(); + var hashTable = { + map: new Map$2(), + get: function get(pairId) { + var map2 = this.map.get(pairId[0]); + if (map2 != null) { + return map2.get(pairId[1]); + } else { + return null; + } + }, + set: function set(pairId, val) { + var map2 = this.map.get(pairId[0]); + if (map2 == null) { + map2 = new Map$2(); + this.map.set(pairId[0], map2); + } + map2.set(pairId[1], val); + } + }; + var pairIds = []; + var haystackEdges = []; + + // create a table of edge (src, tgt) => list of edges between them + for (var i = 0; i < edges.length; i++) { + var edge = edges[i]; + var _p = edge._private; + var curveStyle = edge.pstyle('curve-style').value; + + // ignore edges who are not to be displayed + // they shouldn't take up space + if (edge.removed() || !edge.takesUpSpace()) { + continue; + } + if (curveStyle === 'haystack') { + haystackEdges.push(edge); + continue; + } + var edgeIsUnbundled = curveStyle === 'unbundled-bezier' || curveStyle.endsWith('segments') || curveStyle === 'straight' || curveStyle === 'straight-triangle' || curveStyle.endsWith('taxi'); + var edgeIsBezier = curveStyle === 'unbundled-bezier' || curveStyle === 'bezier'; + var src = _p.source; + var tgt = _p.target; + var srcIndex = src.poolIndex(); + var tgtIndex = tgt.poolIndex(); + var pairId = [srcIndex, tgtIndex].sort(); + var tableEntry = hashTable.get(pairId); + if (tableEntry == null) { + tableEntry = { + eles: [] + }; + hashTable.set(pairId, tableEntry); + pairIds.push(pairId); + } + tableEntry.eles.push(edge); + if (edgeIsUnbundled) { + tableEntry.hasUnbundled = true; + } + if (edgeIsBezier) { + tableEntry.hasBezier = true; + } + } - return this; + // for each pair (src, tgt), create the ctrl pts + // Nested for loop is OK; total number of iterations for both loops = edgeCount + var _loop = function _loop(p) { + var pairId = pairIds[p]; + var pairInfo = hashTable.get(pairId); + var swappedpairInfo = void 0; + if (!pairInfo.hasUnbundled) { + var pllEdges = pairInfo.eles[0].parallelEdges().filter(function (e) { + return e.isBundledBezier(); + }); + clearArray(pairInfo.eles); + pllEdges.forEach(function (edge) { + return pairInfo.eles.push(edge); + }); + + // for each pair id, the edges should be sorted by index + pairInfo.eles.sort(function (edge1, edge2) { + return edge1.poolIndex() - edge2.poolIndex(); + }); + } + var firstEdge = pairInfo.eles[0]; + var src = firstEdge.source(); + var tgt = firstEdge.target(); + + // make sure src/tgt distinction is consistent w.r.t. pairId + if (src.poolIndex() > tgt.poolIndex()) { + var temp = src; + src = tgt; + tgt = temp; + } + var srcPos = pairInfo.srcPos = src.position(); + var tgtPos = pairInfo.tgtPos = tgt.position(); + var srcW = pairInfo.srcW = src.outerWidth(); + var srcH = pairInfo.srcH = src.outerHeight(); + var tgtW = pairInfo.tgtW = tgt.outerWidth(); + var tgtH = pairInfo.tgtH = tgt.outerHeight(); + var srcShape = pairInfo.srcShape = r.nodeShapes[_this.getNodeShape(src)]; + var tgtShape = pairInfo.tgtShape = r.nodeShapes[_this.getNodeShape(tgt)]; + var srcCornerRadius = pairInfo.srcCornerRadius = src.pstyle('corner-radius').value === 'auto' ? 'auto' : src.pstyle('corner-radius').pfValue; + var tgtCornerRadius = pairInfo.tgtCornerRadius = tgt.pstyle('corner-radius').value === 'auto' ? 'auto' : tgt.pstyle('corner-radius').pfValue; + var tgtRs = pairInfo.tgtRs = tgt._private.rscratch; + var srcRs = pairInfo.srcRs = src._private.rscratch; + pairInfo.dirCounts = { + 'north': 0, + 'west': 0, + 'south': 0, + 'east': 0, + 'northwest': 0, + 'southwest': 0, + 'northeast': 0, + 'southeast': 0 + }; + for (var _i2 = 0; _i2 < pairInfo.eles.length; _i2++) { + var _edge = pairInfo.eles[_i2]; + var rs = _edge[0]._private.rscratch; + var _curveStyle = _edge.pstyle('curve-style').value; + var _edgeIsUnbundled = _curveStyle === 'unbundled-bezier' || _curveStyle.endsWith('segments') || _curveStyle.endsWith('taxi'); + + // whether the normalised pair order is the reverse of the edge's src-tgt order + var edgeIsSwapped = !src.same(_edge.source()); + if (!pairInfo.calculatedIntersection && src !== tgt && (pairInfo.hasBezier || pairInfo.hasUnbundled)) { + pairInfo.calculatedIntersection = true; + + // pt outside src shape to calc distance/displacement from src to tgt + var srcOutside = srcShape.intersectLine(srcPos.x, srcPos.y, srcW, srcH, tgtPos.x, tgtPos.y, 0, srcCornerRadius, srcRs); + var srcIntn = pairInfo.srcIntn = srcOutside; + + // pt outside tgt shape to calc distance/displacement from src to tgt + var tgtOutside = tgtShape.intersectLine(tgtPos.x, tgtPos.y, tgtW, tgtH, srcPos.x, srcPos.y, 0, tgtCornerRadius, tgtRs); + var tgtIntn = pairInfo.tgtIntn = tgtOutside; + var intersectionPts = pairInfo.intersectionPts = { + x1: srcOutside[0], + x2: tgtOutside[0], + y1: srcOutside[1], + y2: tgtOutside[1] + }; + var posPts = pairInfo.posPts = { + x1: srcPos.x, + x2: tgtPos.x, + y1: srcPos.y, + y2: tgtPos.y + }; + var dy = tgtOutside[1] - srcOutside[1]; + var dx = tgtOutside[0] - srcOutside[0]; + var l = Math.sqrt(dx * dx + dy * dy); + var vector = pairInfo.vector = { + x: dx, + y: dy + }; + var vectorNorm = pairInfo.vectorNorm = { + x: vector.x / l, + y: vector.y / l + }; + var vectorNormInverse = { + x: -vectorNorm.y, + y: vectorNorm.x + }; - } + // if node shapes overlap, then no ctrl pts to draw + pairInfo.nodesOverlap = !number$1(l) || tgtShape.checkPoint(srcOutside[0], srcOutside[1], 0, tgtW, tgtH, tgtPos.x, tgtPos.y, tgtCornerRadius, tgtRs) || srcShape.checkPoint(tgtOutside[0], tgtOutside[1], 0, srcW, srcH, srcPos.x, srcPos.y, srcCornerRadius, srcRs); + pairInfo.vectorNormInverse = vectorNormInverse; + swappedpairInfo = { + nodesOverlap: pairInfo.nodesOverlap, + dirCounts: pairInfo.dirCounts, + calculatedIntersection: true, + hasBezier: pairInfo.hasBezier, + hasUnbundled: pairInfo.hasUnbundled, + eles: pairInfo.eles, + srcPos: tgtPos, + tgtPos: srcPos, + srcW: tgtW, + srcH: tgtH, + tgtW: srcW, + tgtH: srcH, + srcIntn: tgtIntn, + tgtIntn: srcIntn, + srcShape: tgtShape, + tgtShape: srcShape, + posPts: { + x1: posPts.x2, + y1: posPts.y2, + x2: posPts.x1, + y2: posPts.y1 + }, + intersectionPts: { + x1: intersectionPts.x2, + y1: intersectionPts.y2, + x2: intersectionPts.x1, + y2: intersectionPts.y1 + }, + vector: { + x: -vector.x, + y: -vector.y + }, + vectorNorm: { + x: -vectorNorm.x, + y: -vectorNorm.y + }, + vectorNormInverse: { + x: -vectorNormInverse.x, + y: -vectorNormInverse.y + } + }; + } + var passedPairInfo = edgeIsSwapped ? swappedpairInfo : pairInfo; + rs.nodesOverlap = passedPairInfo.nodesOverlap; + rs.srcIntn = passedPairInfo.srcIntn; + rs.tgtIntn = passedPairInfo.tgtIntn; + rs.isRound = _curveStyle.startsWith('round'); + if (hasCompounds && (src.isParent() || src.isChild() || tgt.isParent() || tgt.isChild()) && (src.parents().anySame(tgt) || tgt.parents().anySame(src) || src.same(tgt) && src.isParent())) { + _this.findCompoundLoopPoints(_edge, passedPairInfo, _i2, _edgeIsUnbundled); + } else if (src === tgt) { + _this.findLoopPoints(_edge, passedPairInfo, _i2, _edgeIsUnbundled); + } else if (_curveStyle.endsWith('segments')) { + _this.findSegmentsPoints(_edge, passedPairInfo); + } else if (_curveStyle.endsWith('taxi')) { + _this.findTaxiPoints(_edge, passedPairInfo); + } else if (_curveStyle === 'straight' || !_edgeIsUnbundled && pairInfo.eles.length % 2 === 1 && _i2 === Math.floor(pairInfo.eles.length / 2)) { + _this.findStraightEdgePoints(_edge); + } else { + _this.findBezierPoints(_edge, passedPairInfo, _i2, _edgeIsUnbundled, edgeIsSwapped); + } + _this.findEndpoints(_edge); + _this.tryToCorrectInvalidPoints(_edge, passedPairInfo); + _this.checkForInvalidEdgeWarning(_edge); + _this.storeAllpts(_edge); + _this.storeEdgeProjections(_edge); + _this.calculateArrowAngles(_edge); + _this.recalculateEdgeLabelProjections(_edge); + _this.calculateLabelAngles(_edge); + } // for pair edges + }; + for (var p = 0; p < pairIds.length; p++) { + _loop(p); + } // for pair ids + + // haystacks avoid the expense of pairInfo stuff (intersections etc.) + this.findHaystackPoints(haystackEdges); + }; + function getPts(pts) { + var retPts = []; + if (pts == null) { + return; + } + for (var i = 0; i < pts.length; i += 2) { + var x = pts[i]; + var y = pts[i + 1]; + retPts.push({ + x: x, + y: y + }); + } + return retPts; + } + BRp$c.getSegmentPoints = function (edge) { + var rs = edge[0]._private.rscratch; + var type = rs.edgeType; + if (type === 'segments') { + this.recalculateRenderedStyle(edge); + return getPts(rs.segpts); + } + }; + BRp$c.getControlPoints = function (edge) { + var rs = edge[0]._private.rscratch; + var type = rs.edgeType; + if (type === 'bezier' || type === 'multibezier' || type === 'self' || type === 'compound') { + this.recalculateRenderedStyle(edge); + return getPts(rs.ctrlpts); + } + }; + BRp$c.getEdgeMidpoint = function (edge) { + var rs = edge[0]._private.rscratch; + this.recalculateRenderedStyle(edge); + return { + x: rs.midX, + y: rs.midY + }; + }; - multiply( color ) { + var BRp$b = {}; + BRp$b.manualEndptToPx = function (node, prop) { + var r = this; + var npos = node.position(); + var w = node.outerWidth(); + var h = node.outerHeight(); + var rs = node._private.rscratch; + if (prop.value.length === 2) { + var p = [prop.pfValue[0], prop.pfValue[1]]; + if (prop.units[0] === '%') { + p[0] = p[0] * w; + } + if (prop.units[1] === '%') { + p[1] = p[1] * h; + } + p[0] += npos.x; + p[1] += npos.y; + return p; + } else { + var angle = prop.pfValue[0]; + angle = -Math.PI / 2 + angle; // start at 12 o'clock + + var l = 2 * Math.max(w, h); + var _p = [npos.x + Math.cos(angle) * l, npos.y + Math.sin(angle) * l]; + return r.nodeShapes[this.getNodeShape(node)].intersectLine(npos.x, npos.y, w, h, _p[0], _p[1], 0, node.pstyle('corner-radius').value === 'auto' ? 'auto' : node.pstyle('corner-radius').pfValue, rs); + } + }; + BRp$b.findEndpoints = function (edge) { + var r = this; + var intersect; + var source = edge.source()[0]; + var target = edge.target()[0]; + var srcPos = source.position(); + var tgtPos = target.position(); + var tgtArShape = edge.pstyle('target-arrow-shape').value; + var srcArShape = edge.pstyle('source-arrow-shape').value; + var tgtDist = edge.pstyle('target-distance-from-node').pfValue; + var srcDist = edge.pstyle('source-distance-from-node').pfValue; + var srcRs = source._private.rscratch; + var tgtRs = target._private.rscratch; + var curveStyle = edge.pstyle('curve-style').value; + var rs = edge._private.rscratch; + var et = rs.edgeType; + var taxi = curveStyle === 'taxi'; + var self = et === 'self' || et === 'compound'; + var bezier = et === 'bezier' || et === 'multibezier' || self; + var multi = et !== 'bezier'; + var lines = et === 'straight' || et === 'segments'; + var segments = et === 'segments'; + var hasEndpts = bezier || multi || lines; + var overrideEndpts = self || taxi; + var srcManEndpt = edge.pstyle('source-endpoint'); + var srcManEndptVal = overrideEndpts ? 'outside-to-node' : srcManEndpt.value; + var srcCornerRadius = source.pstyle('corner-radius').value === 'auto' ? 'auto' : source.pstyle('corner-radius').pfValue; + var tgtManEndpt = edge.pstyle('target-endpoint'); + var tgtManEndptVal = overrideEndpts ? 'outside-to-node' : tgtManEndpt.value; + var tgtCornerRadius = target.pstyle('corner-radius').value === 'auto' ? 'auto' : target.pstyle('corner-radius').pfValue; + rs.srcManEndpt = srcManEndpt; + rs.tgtManEndpt = tgtManEndpt; + var p1; // last known point of edge on target side + var p2; // last known point of edge on source side + + var p1_i; // point to intersect with target shape + var p2_i; // point to intersect with source shape + + if (bezier) { + var cpStart = [rs.ctrlpts[0], rs.ctrlpts[1]]; + var cpEnd = multi ? [rs.ctrlpts[rs.ctrlpts.length - 2], rs.ctrlpts[rs.ctrlpts.length - 1]] : cpStart; + p1 = cpEnd; + p2 = cpStart; + } else if (lines) { + var srcArrowFromPt = !segments ? [tgtPos.x, tgtPos.y] : rs.segpts.slice(0, 2); + var tgtArrowFromPt = !segments ? [srcPos.x, srcPos.y] : rs.segpts.slice(rs.segpts.length - 2); + p1 = tgtArrowFromPt; + p2 = srcArrowFromPt; + } + if (tgtManEndptVal === 'inside-to-node') { + intersect = [tgtPos.x, tgtPos.y]; + } else if (tgtManEndpt.units) { + intersect = this.manualEndptToPx(target, tgtManEndpt); + } else if (tgtManEndptVal === 'outside-to-line') { + intersect = rs.tgtIntn; // use cached value from ctrlpt calc + } else { + if (tgtManEndptVal === 'outside-to-node' || tgtManEndptVal === 'outside-to-node-or-label') { + p1_i = p1; + } else if (tgtManEndptVal === 'outside-to-line' || tgtManEndptVal === 'outside-to-line-or-label') { + p1_i = [srcPos.x, srcPos.y]; + } + intersect = r.nodeShapes[this.getNodeShape(target)].intersectLine(tgtPos.x, tgtPos.y, target.outerWidth(), target.outerHeight(), p1_i[0], p1_i[1], 0, tgtCornerRadius, tgtRs); + if (tgtManEndptVal === 'outside-to-node-or-label' || tgtManEndptVal === 'outside-to-line-or-label') { + var trs = target._private.rscratch; + var lw = trs.labelWidth; + var lh = trs.labelHeight; + var lx = trs.labelX; + var ly = trs.labelY; + var lw2 = lw / 2; + var lh2 = lh / 2; + var va = target.pstyle('text-valign').value; + if (va === 'top') { + ly -= lh2; + } else if (va === 'bottom') { + ly += lh2; + } + var ha = target.pstyle('text-halign').value; + if (ha === 'left') { + lx -= lw2; + } else if (ha === 'right') { + lx += lw2; + } + var labelIntersect = polygonIntersectLine(p1_i[0], p1_i[1], [lx - lw2, ly - lh2, lx + lw2, ly - lh2, lx + lw2, ly + lh2, lx - lw2, ly + lh2], tgtPos.x, tgtPos.y); + if (labelIntersect.length > 0) { + var refPt = srcPos; + var intSqdist = sqdist(refPt, array2point(intersect)); + var labIntSqdist = sqdist(refPt, array2point(labelIntersect)); + var minSqDist = intSqdist; + if (labIntSqdist < intSqdist) { + intersect = labelIntersect; + minSqDist = labIntSqdist; + } + if (labelIntersect.length > 2) { + var labInt2SqDist = sqdist(refPt, { + x: labelIntersect[2], + y: labelIntersect[3] + }); + if (labInt2SqDist < minSqDist) { + intersect = [labelIntersect[2], labelIntersect[3]]; + } + } + } + } + } + var arrowEnd = shortenIntersection(intersect, p1, r.arrowShapes[tgtArShape].spacing(edge) + tgtDist); + var edgeEnd = shortenIntersection(intersect, p1, r.arrowShapes[tgtArShape].gap(edge) + tgtDist); + rs.endX = edgeEnd[0]; + rs.endY = edgeEnd[1]; + rs.arrowEndX = arrowEnd[0]; + rs.arrowEndY = arrowEnd[1]; + if (srcManEndptVal === 'inside-to-node') { + intersect = [srcPos.x, srcPos.y]; + } else if (srcManEndpt.units) { + intersect = this.manualEndptToPx(source, srcManEndpt); + } else if (srcManEndptVal === 'outside-to-line') { + intersect = rs.srcIntn; // use cached value from ctrlpt calc + } else { + if (srcManEndptVal === 'outside-to-node' || srcManEndptVal === 'outside-to-node-or-label') { + p2_i = p2; + } else if (srcManEndptVal === 'outside-to-line' || srcManEndptVal === 'outside-to-line-or-label') { + p2_i = [tgtPos.x, tgtPos.y]; + } + intersect = r.nodeShapes[this.getNodeShape(source)].intersectLine(srcPos.x, srcPos.y, source.outerWidth(), source.outerHeight(), p2_i[0], p2_i[1], 0, srcCornerRadius, srcRs); + if (srcManEndptVal === 'outside-to-node-or-label' || srcManEndptVal === 'outside-to-line-or-label') { + var srs = source._private.rscratch; + var _lw = srs.labelWidth; + var _lh = srs.labelHeight; + var _lx = srs.labelX; + var _ly = srs.labelY; + var _lw2 = _lw / 2; + var _lh2 = _lh / 2; + var _va = source.pstyle('text-valign').value; + if (_va === 'top') { + _ly -= _lh2; + } else if (_va === 'bottom') { + _ly += _lh2; + } + var _ha = source.pstyle('text-halign').value; + if (_ha === 'left') { + _lx -= _lw2; + } else if (_ha === 'right') { + _lx += _lw2; + } + var _labelIntersect = polygonIntersectLine(p2_i[0], p2_i[1], [_lx - _lw2, _ly - _lh2, _lx + _lw2, _ly - _lh2, _lx + _lw2, _ly + _lh2, _lx - _lw2, _ly + _lh2], srcPos.x, srcPos.y); + if (_labelIntersect.length > 0) { + var _refPt = tgtPos; + var _intSqdist = sqdist(_refPt, array2point(intersect)); + var _labIntSqdist = sqdist(_refPt, array2point(_labelIntersect)); + var _minSqDist = _intSqdist; + if (_labIntSqdist < _intSqdist) { + intersect = [_labelIntersect[0], _labelIntersect[1]]; + _minSqDist = _labIntSqdist; + } + if (_labelIntersect.length > 2) { + var _labInt2SqDist = sqdist(_refPt, { + x: _labelIntersect[2], + y: _labelIntersect[3] + }); + if (_labInt2SqDist < _minSqDist) { + intersect = [_labelIntersect[2], _labelIntersect[3]]; + } + } + } + } + } + var arrowStart = shortenIntersection(intersect, p2, r.arrowShapes[srcArShape].spacing(edge) + srcDist); + var edgeStart = shortenIntersection(intersect, p2, r.arrowShapes[srcArShape].gap(edge) + srcDist); + rs.startX = edgeStart[0]; + rs.startY = edgeStart[1]; + rs.arrowStartX = arrowStart[0]; + rs.arrowStartY = arrowStart[1]; + if (hasEndpts) { + if (!number$1(rs.startX) || !number$1(rs.startY) || !number$1(rs.endX) || !number$1(rs.endY)) { + rs.badLine = true; + } else { + rs.badLine = false; + } + } + }; + BRp$b.getSourceEndpoint = function (edge) { + var rs = edge[0]._private.rscratch; + this.recalculateRenderedStyle(edge); + switch (rs.edgeType) { + case 'haystack': + return { + x: rs.haystackPts[0], + y: rs.haystackPts[1] + }; + default: + return { + x: rs.arrowStartX, + y: rs.arrowStartY + }; + } + }; + BRp$b.getTargetEndpoint = function (edge) { + var rs = edge[0]._private.rscratch; + this.recalculateRenderedStyle(edge); + switch (rs.edgeType) { + case 'haystack': + return { + x: rs.haystackPts[2], + y: rs.haystackPts[3] + }; + default: + return { + x: rs.arrowEndX, + y: rs.arrowEndY + }; + } + }; - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + var BRp$a = {}; + function pushBezierPts(r, edge, pts) { + var qbezierAt$1 = function qbezierAt$1(p1, p2, p3, t) { + return qbezierAt(p1, p2, p3, t); + }; + var _p = edge._private; + var bpts = _p.rstyle.bezierPts; + for (var i = 0; i < r.bezierProjPcts.length; i++) { + var p = r.bezierProjPcts[i]; + bpts.push({ + x: qbezierAt$1(pts[0], pts[2], pts[4], p), + y: qbezierAt$1(pts[1], pts[3], pts[5], p) + }); + } + } + BRp$a.storeEdgeProjections = function (edge) { + var _p = edge._private; + var rs = _p.rscratch; + var et = rs.edgeType; + + // clear the cached points state + _p.rstyle.bezierPts = null; + _p.rstyle.linePts = null; + _p.rstyle.haystackPts = null; + if (et === 'multibezier' || et === 'bezier' || et === 'self' || et === 'compound') { + _p.rstyle.bezierPts = []; + for (var i = 0; i + 5 < rs.allpts.length; i += 4) { + pushBezierPts(this, edge, rs.allpts.slice(i, i + 6)); + } + } else if (et === 'segments') { + var lpts = _p.rstyle.linePts = []; + for (var i = 0; i + 1 < rs.allpts.length; i += 2) { + lpts.push({ + x: rs.allpts[i], + y: rs.allpts[i + 1] + }); + } + } else if (et === 'haystack') { + var hpts = rs.haystackPts; + _p.rstyle.haystackPts = [{ + x: hpts[0], + y: hpts[1] + }, { + x: hpts[2], + y: hpts[3] + }]; + } + _p.rstyle.arrowWidth = this.getArrowWidth(edge.pstyle('width').pfValue, edge.pstyle('arrow-scale').value) * this.arrowShapeWidth; + }; + BRp$a.recalculateEdgeProjections = function (edges) { + this.findEdgeControlPoints(edges); + }; - return this; + /* global document */ - } + var BRp$9 = {}; + BRp$9.recalculateNodeLabelProjection = function (node) { + var content = node.pstyle('label').strValue; + if (emptyString(content)) { + return; + } + var textX, textY; + var _p = node._private; + var nodeWidth = node.width(); + var nodeHeight = node.height(); + var padding = node.padding(); + var nodePos = node.position(); + var textHalign = node.pstyle('text-halign').strValue; + var textValign = node.pstyle('text-valign').strValue; + var rs = _p.rscratch; + var rstyle = _p.rstyle; + switch (textHalign) { + case 'left': + textX = nodePos.x - nodeWidth / 2 - padding; + break; + case 'right': + textX = nodePos.x + nodeWidth / 2 + padding; + break; + default: + // e.g. center + textX = nodePos.x; + } + switch (textValign) { + case 'top': + textY = nodePos.y - nodeHeight / 2 - padding; + break; + case 'bottom': + textY = nodePos.y + nodeHeight / 2 + padding; + break; + default: + // e.g. middle + textY = nodePos.y; + } + rs.labelX = textX; + rs.labelY = textY; + rstyle.labelX = textX; + rstyle.labelY = textY; + this.calculateLabelAngles(node); + this.applyLabelDimensions(node); + }; + var lineAngleFromDelta = function lineAngleFromDelta(dx, dy) { + var angle = Math.atan(dy / dx); + if (dx === 0 && angle < 0) { + angle = angle * -1; + } + return angle; + }; + var lineAngle = function lineAngle(p0, p1) { + var dx = p1.x - p0.x; + var dy = p1.y - p0.y; + return lineAngleFromDelta(dx, dy); + }; + var bezierAngle = function bezierAngle(p0, p1, p2, t) { + var t0 = bound(0, t - 0.001, 1); + var t1 = bound(0, t + 0.001, 1); + var lp0 = qbezierPtAt(p0, p1, p2, t0); + var lp1 = qbezierPtAt(p0, p1, p2, t1); + return lineAngle(lp0, lp1); + }; + BRp$9.recalculateEdgeLabelProjections = function (edge) { + var p; + var _p = edge._private; + var rs = _p.rscratch; + var r = this; + var content = { + mid: edge.pstyle('label').strValue, + source: edge.pstyle('source-label').strValue, + target: edge.pstyle('target-label').strValue + }; + if (content.mid || content.source || content.target) ; else { + return; // no labels => no calcs + } - multiplyScalar( s ) { + // add center point to style so bounding box calculations can use it + // + p = { + x: rs.midX, + y: rs.midY + }; + var setRs = function setRs(propName, prefix, value) { + setPrefixedProperty(_p.rscratch, propName, prefix, value); + setPrefixedProperty(_p.rstyle, propName, prefix, value); + }; + setRs('labelX', null, p.x); + setRs('labelY', null, p.y); + var midAngle = lineAngleFromDelta(rs.midDispX, rs.midDispY); + setRs('labelAutoAngle', null, midAngle); + var createControlPointInfo = function createControlPointInfo() { + if (createControlPointInfo.cache) { + return createControlPointInfo.cache; + } // use cache so only 1x per edge + + var ctrlpts = []; + + // store each ctrlpt info init + for (var i = 0; i + 5 < rs.allpts.length; i += 4) { + var p0 = { + x: rs.allpts[i], + y: rs.allpts[i + 1] + }; + var p1 = { + x: rs.allpts[i + 2], + y: rs.allpts[i + 3] + }; // ctrlpt + var p2 = { + x: rs.allpts[i + 4], + y: rs.allpts[i + 5] + }; + ctrlpts.push({ + p0: p0, + p1: p1, + p2: p2, + startDist: 0, + length: 0, + segments: [] + }); + } + var bpts = _p.rstyle.bezierPts; + var nProjs = r.bezierProjPcts.length; + function addSegment(cp, p0, p1, t0, t1) { + var length = dist(p0, p1); + var prevSegment = cp.segments[cp.segments.length - 1]; + var segment = { + p0: p0, + p1: p1, + t0: t0, + t1: t1, + startDist: prevSegment ? prevSegment.startDist + prevSegment.length : 0, + length: length + }; + cp.segments.push(segment); + cp.length += length; + } - this.r *= s; - this.g *= s; - this.b *= s; + // update each ctrlpt with segment info + for (var _i = 0; _i < ctrlpts.length; _i++) { + var cp = ctrlpts[_i]; + var prevCp = ctrlpts[_i - 1]; + if (prevCp) { + cp.startDist = prevCp.startDist + prevCp.length; + } + addSegment(cp, cp.p0, bpts[_i * nProjs], 0, r.bezierProjPcts[0]); // first + + for (var j = 0; j < nProjs - 1; j++) { + addSegment(cp, bpts[_i * nProjs + j], bpts[_i * nProjs + j + 1], r.bezierProjPcts[j], r.bezierProjPcts[j + 1]); + } + addSegment(cp, bpts[_i * nProjs + nProjs - 1], cp.p2, r.bezierProjPcts[nProjs - 1], 1); // last + } - return this; + return createControlPointInfo.cache = ctrlpts; + }; + var calculateEndProjection = function calculateEndProjection(prefix) { + var angle; + var isSrc = prefix === 'source'; + if (!content[prefix]) { + return; + } + var offset = edge.pstyle(prefix + '-text-offset').pfValue; + switch (rs.edgeType) { + case 'self': + case 'compound': + case 'bezier': + case 'multibezier': + { + var cps = createControlPointInfo(); + var selected; + var startDist = 0; + var totalDist = 0; + + // find the segment we're on + for (var i = 0; i < cps.length; i++) { + var _cp = cps[isSrc ? i : cps.length - 1 - i]; + for (var j = 0; j < _cp.segments.length; j++) { + var _seg = _cp.segments[isSrc ? j : _cp.segments.length - 1 - j]; + var lastSeg = i === cps.length - 1 && j === _cp.segments.length - 1; + startDist = totalDist; + totalDist += _seg.length; + if (totalDist >= offset || lastSeg) { + selected = { + cp: _cp, + segment: _seg + }; + break; + } + } + if (selected) { + break; + } + } + var cp = selected.cp; + var seg = selected.segment; + var tSegment = (offset - startDist) / seg.length; + var segDt = seg.t1 - seg.t0; + var t = isSrc ? seg.t0 + segDt * tSegment : seg.t1 - segDt * tSegment; + t = bound(0, t, 1); + p = qbezierPtAt(cp.p0, cp.p1, cp.p2, t); + angle = bezierAngle(cp.p0, cp.p1, cp.p2, t); + break; + } + case 'straight': + case 'segments': + case 'haystack': + { + var d = 0, + di, + d0; + var p0, p1; + var l = rs.allpts.length; + for (var _i2 = 0; _i2 + 3 < l; _i2 += 2) { + if (isSrc) { + p0 = { + x: rs.allpts[_i2], + y: rs.allpts[_i2 + 1] + }; + p1 = { + x: rs.allpts[_i2 + 2], + y: rs.allpts[_i2 + 3] + }; + } else { + p0 = { + x: rs.allpts[l - 2 - _i2], + y: rs.allpts[l - 1 - _i2] + }; + p1 = { + x: rs.allpts[l - 4 - _i2], + y: rs.allpts[l - 3 - _i2] + }; + } + di = dist(p0, p1); + d0 = d; + d += di; + if (d >= offset) { + break; + } + } + var pD = offset - d0; + var _t = pD / di; + _t = bound(0, _t, 1); + p = lineAt(p0, p1, _t); + angle = lineAngle(p0, p1); + break; + } + } + setRs('labelX', prefix, p.x); + setRs('labelY', prefix, p.y); + setRs('labelAutoAngle', prefix, angle); + }; + calculateEndProjection('source'); + calculateEndProjection('target'); + this.applyLabelDimensions(edge); + }; + BRp$9.applyLabelDimensions = function (ele) { + this.applyPrefixedLabelDimensions(ele); + if (ele.isEdge()) { + this.applyPrefixedLabelDimensions(ele, 'source'); + this.applyPrefixedLabelDimensions(ele, 'target'); + } + }; + BRp$9.applyPrefixedLabelDimensions = function (ele, prefix) { + var _p = ele._private; + var text = this.getLabelText(ele, prefix); + var labelDims = this.calculateLabelDimensions(ele, text); + var lineHeight = ele.pstyle('line-height').pfValue; + var textWrap = ele.pstyle('text-wrap').strValue; + var lines = getPrefixedProperty(_p.rscratch, 'labelWrapCachedLines', prefix) || []; + var numLines = textWrap !== 'wrap' ? 1 : Math.max(lines.length, 1); + var normPerLineHeight = labelDims.height / numLines; + var labelLineHeight = normPerLineHeight * lineHeight; + var width = labelDims.width; + var height = labelDims.height + (numLines - 1) * (lineHeight - 1) * normPerLineHeight; + setPrefixedProperty(_p.rstyle, 'labelWidth', prefix, width); + setPrefixedProperty(_p.rscratch, 'labelWidth', prefix, width); + setPrefixedProperty(_p.rstyle, 'labelHeight', prefix, height); + setPrefixedProperty(_p.rscratch, 'labelHeight', prefix, height); + setPrefixedProperty(_p.rscratch, 'labelLineHeight', prefix, labelLineHeight); + }; + BRp$9.getLabelText = function (ele, prefix) { + var _p = ele._private; + var pfd = prefix ? prefix + '-' : ''; + var text = ele.pstyle(pfd + 'label').strValue; + var textTransform = ele.pstyle('text-transform').value; + var rscratch = function rscratch(propName, value) { + if (value) { + setPrefixedProperty(_p.rscratch, propName, prefix, value); + return value; + } else { + return getPrefixedProperty(_p.rscratch, propName, prefix); + } + }; - } + // for empty text, skip all processing + if (!text) { + return ''; + } + if (textTransform == 'none') ; else if (textTransform == 'uppercase') { + text = text.toUpperCase(); + } else if (textTransform == 'lowercase') { + text = text.toLowerCase(); + } + var wrapStyle = ele.pstyle('text-wrap').value; + if (wrapStyle === 'wrap') { + var labelKey = rscratch('labelKey'); - lerp( color, alpha ) { + // save recalc if the label is the same as before + if (labelKey != null && rscratch('labelWrapKey') === labelKey) { + return rscratch('labelWrapCachedText'); + } + var zwsp = "\u200B"; + var lines = text.split('\n'); + var maxW = ele.pstyle('text-max-width').pfValue; + var overflow = ele.pstyle('text-overflow-wrap').value; + var overflowAny = overflow === 'anywhere'; + var wrappedLines = []; + var wordsRegex = /[\s\u200b]+/; + var wordSeparator = overflowAny ? '' : ' '; + for (var l = 0; l < lines.length; l++) { + var line = lines[l]; + var lineDims = this.calculateLabelDimensions(ele, line); + var lineW = lineDims.width; + if (overflowAny) { + var processedLine = line.split('').join(zwsp); + line = processedLine; + } + if (lineW > maxW) { + // line is too long + var words = line.split(wordsRegex); + var subline = ''; + for (var w = 0; w < words.length; w++) { + var word = words[w]; + var testLine = subline.length === 0 ? word : subline + wordSeparator + word; + var testDims = this.calculateLabelDimensions(ele, testLine); + var testW = testDims.width; + if (testW <= maxW) { + // word fits on current line + subline += word + wordSeparator; + } else { + // word starts new line + if (subline) { + wrappedLines.push(subline); + } + subline = word + wordSeparator; + } + } - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + // if there's remaining text, put it in a wrapped line + if (!subline.match(/^[\s\u200b]+$/)) { + wrappedLines.push(subline); + } + } else { + // line is already short enough + wrappedLines.push(line); + } + } // for + + rscratch('labelWrapCachedLines', wrappedLines); + text = rscratch('labelWrapCachedText', wrappedLines.join('\n')); + rscratch('labelWrapKey', labelKey); + } else if (wrapStyle === 'ellipsis') { + var _maxW = ele.pstyle('text-max-width').pfValue; + var ellipsized = ''; + var ellipsis = "\u2026"; + var incLastCh = false; + if (this.calculateLabelDimensions(ele, text).width < _maxW) { + // the label already fits + return text; + } + for (var i = 0; i < text.length; i++) { + var widthWithNextCh = this.calculateLabelDimensions(ele, ellipsized + text[i] + ellipsis).width; + if (widthWithNextCh > _maxW) { + break; + } + ellipsized += text[i]; + if (i === text.length - 1) { + incLastCh = true; + } + } + if (!incLastCh) { + ellipsized += ellipsis; + } + return ellipsized; + } // if ellipsize - return this; + return text; + }; + BRp$9.getLabelJustification = function (ele) { + var justification = ele.pstyle('text-justification').strValue; + var textHalign = ele.pstyle('text-halign').strValue; + if (justification === 'auto') { + if (ele.isNode()) { + switch (textHalign) { + case 'left': + return 'right'; + case 'right': + return 'left'; + default: + return 'center'; + } + } else { + return 'center'; + } + } else { + return justification; + } + }; + BRp$9.calculateLabelDimensions = function (ele, text) { + var r = this; + var cacheKey = hashString(text, ele._private.labelDimsKey); + var cache = r.labelDimCache || (r.labelDimCache = []); + var existingVal = cache[cacheKey]; + if (existingVal != null) { + return existingVal; + } + var padding = 0; // add padding around text dims, as the measurement isn't that accurate + var fStyle = ele.pstyle('font-style').strValue; + var size = ele.pstyle('font-size').pfValue; + var family = ele.pstyle('font-family').strValue; + var weight = ele.pstyle('font-weight').strValue; + var canvas = this.labelCalcCanvas; + var c2d = this.labelCalcCanvasContext; + if (!canvas) { + canvas = this.labelCalcCanvas = document.createElement('canvas'); + c2d = this.labelCalcCanvasContext = canvas.getContext('2d'); + var ds = canvas.style; + ds.position = 'absolute'; + ds.left = '-9999px'; + ds.top = '-9999px'; + ds.zIndex = '-1'; + ds.visibility = 'hidden'; + ds.pointerEvents = 'none'; + } + c2d.font = "".concat(fStyle, " ").concat(weight, " ").concat(size, "px ").concat(family); + var width = 0; + var height = 0; + var lines = text.split('\n'); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + var metrics = c2d.measureText(line); + var w = Math.ceil(metrics.width); + var h = size; + width = Math.max(w, width); + height += h; + } + width += padding; + height += padding; + return cache[cacheKey] = { + width: width, + height: height + }; + }; + BRp$9.calculateLabelAngle = function (ele, prefix) { + var _p = ele._private; + var rs = _p.rscratch; + var isEdge = ele.isEdge(); + var prefixDash = prefix ? prefix + '-' : ''; + var rot = ele.pstyle(prefixDash + 'text-rotation'); + var rotStr = rot.strValue; + if (rotStr === 'none') { + return 0; + } else if (isEdge && rotStr === 'autorotate') { + return rs.labelAutoAngle; + } else if (rotStr === 'autorotate') { + return 0; + } else { + return rot.pfValue; + } + }; + BRp$9.calculateLabelAngles = function (ele) { + var r = this; + var isEdge = ele.isEdge(); + var _p = ele._private; + var rs = _p.rscratch; + rs.labelAngle = r.calculateLabelAngle(ele); + if (isEdge) { + rs.sourceLabelAngle = r.calculateLabelAngle(ele, 'source'); + rs.targetLabelAngle = r.calculateLabelAngle(ele, 'target'); + } + }; - } + var BRp$8 = {}; + var TOO_SMALL_CUT_RECT = 28; + var warnedCutRect = false; + BRp$8.getNodeShape = function (node) { + var r = this; + var shape = node.pstyle('shape').value; + if (shape === 'cutrectangle' && (node.width() < TOO_SMALL_CUT_RECT || node.height() < TOO_SMALL_CUT_RECT)) { + if (!warnedCutRect) { + warn('The `cutrectangle` node shape can not be used at small sizes so `rectangle` is used instead'); + warnedCutRect = true; + } + return 'rectangle'; + } + if (node.isParent()) { + if (shape === 'rectangle' || shape === 'roundrectangle' || shape === 'round-rectangle' || shape === 'cutrectangle' || shape === 'cut-rectangle' || shape === 'barrel') { + return shape; + } else { + return 'rectangle'; + } + } + if (shape === 'polygon') { + var points = node.pstyle('shape-polygon-points').value; + return r.nodeShapes.makePolygon(points).name; + } + return shape; + }; - lerpColors( color1, color2, alpha ) { + var BRp$7 = {}; + BRp$7.registerCalculationListeners = function () { + var cy = this.cy; + var elesToUpdate = cy.collection(); + var r = this; + var enqueue = function enqueue(eles) { + var dirtyStyleCaches = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + elesToUpdate.merge(eles); + if (dirtyStyleCaches) { + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var _p = ele._private; + var rstyle = _p.rstyle; + rstyle.clean = false; + rstyle.cleanConnected = false; + } + } + }; + r.binder(cy).on('bounds.* dirty.*', function onDirtyBounds(e) { + var ele = e.target; + enqueue(ele); + }).on('style.* background.*', function onDirtyStyle(e) { + var ele = e.target; + enqueue(ele, false); + }); + var updateEleCalcs = function updateEleCalcs(willDraw) { + if (willDraw) { + var fns = r.onUpdateEleCalcsFns; + + // because we need to have up-to-date style (e.g. stylesheet mappers) + // before calculating rendered style (and pstyle might not be called yet) + elesToUpdate.cleanStyle(); + for (var i = 0; i < elesToUpdate.length; i++) { + var ele = elesToUpdate[i]; + var rstyle = ele._private.rstyle; + if (ele.isNode() && !rstyle.cleanConnected) { + enqueue(ele.connectedEdges()); + rstyle.cleanConnected = true; + } + } + if (fns) { + for (var _i = 0; _i < fns.length; _i++) { + var fn = fns[_i]; + fn(willDraw, elesToUpdate); + } + } + r.recalculateRenderedStyle(elesToUpdate); + elesToUpdate = cy.collection(); + } + }; + r.flushRenderedStyleQueue = function () { + updateEleCalcs(true); + }; + r.beforeRender(updateEleCalcs, r.beforeRenderPriorities.eleCalcs); + }; + BRp$7.onUpdateEleCalcs = function (fn) { + var fns = this.onUpdateEleCalcsFns = this.onUpdateEleCalcsFns || []; + fns.push(fn); + }; + BRp$7.recalculateRenderedStyle = function (eles, useCache) { + var isCleanConnected = function isCleanConnected(ele) { + return ele._private.rstyle.cleanConnected; + }; + var edges = []; + var nodes = []; + + // the renderer can't be used for calcs when destroyed, e.g. ele.boundingBox() + if (this.destroyed) { + return; + } - this.r = color1.r + ( color2.r - color1.r ) * alpha; - this.g = color1.g + ( color2.g - color1.g ) * alpha; - this.b = color1.b + ( color2.b - color1.b ) * alpha; + // use cache by default for perf + if (useCache === undefined) { + useCache = true; + } + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var _p = ele._private; + var rstyle = _p.rstyle; + + // an edge may be implicitly dirty b/c of one of its connected nodes + // (and a request for recalc may come in between frames) + if (ele.isEdge() && (!isCleanConnected(ele.source()) || !isCleanConnected(ele.target()))) { + rstyle.clean = false; + } - return this; + // only update if dirty and in graph + if (useCache && rstyle.clean || ele.removed()) { + continue; + } - } + // only update if not display: none + if (ele.pstyle('display').value === 'none') { + continue; + } + if (_p.group === 'nodes') { + nodes.push(ele); + } else { + // edges + edges.push(ele); + } + rstyle.clean = true; + } - lerpHSL( color, alpha ) { + // update node data from projections + for (var _i2 = 0; _i2 < nodes.length; _i2++) { + var _ele = nodes[_i2]; + var _p2 = _ele._private; + var _rstyle = _p2.rstyle; + var pos = _ele.position(); + this.recalculateNodeLabelProjection(_ele); + _rstyle.nodeX = pos.x; + _rstyle.nodeY = pos.y; + _rstyle.nodeW = _ele.pstyle('width').pfValue; + _rstyle.nodeH = _ele.pstyle('height').pfValue; + } + this.recalculateEdgeProjections(edges); + + // update edge data from projections + for (var _i3 = 0; _i3 < edges.length; _i3++) { + var _ele2 = edges[_i3]; + var _p3 = _ele2._private; + var _rstyle2 = _p3.rstyle; + var rs = _p3.rscratch; + + // update rstyle positions + _rstyle2.srcX = rs.arrowStartX; + _rstyle2.srcY = rs.arrowStartY; + _rstyle2.tgtX = rs.arrowEndX; + _rstyle2.tgtY = rs.arrowEndY; + _rstyle2.midX = rs.midX; + _rstyle2.midY = rs.midY; + _rstyle2.labelAngle = rs.labelAngle; + _rstyle2.sourceLabelAngle = rs.sourceLabelAngle; + _rstyle2.targetLabelAngle = rs.targetLabelAngle; + } + }; - this.getHSL( _hslA ); - color.getHSL( _hslB ); + var BRp$6 = {}; + BRp$6.updateCachedGrabbedEles = function () { + var eles = this.cachedZSortedEles; + if (!eles) { + // just let this be recalculated on the next z sort tick + return; + } + eles.drag = []; + eles.nondrag = []; + var grabTargets = []; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var rs = ele._private.rscratch; + if (ele.grabbed() && !ele.isParent()) { + grabTargets.push(ele); + } else if (rs.inDragLayer) { + eles.drag.push(ele); + } else { + eles.nondrag.push(ele); + } + } - const h = lerp( _hslA.h, _hslB.h, alpha ); - const s = lerp( _hslA.s, _hslB.s, alpha ); - const l = lerp( _hslA.l, _hslB.l, alpha ); + // put the grab target nodes last so it's on top of its neighbourhood + for (var i = 0; i < grabTargets.length; i++) { + var ele = grabTargets[i]; + eles.drag.push(ele); + } + }; + BRp$6.invalidateCachedZSortedEles = function () { + this.cachedZSortedEles = null; + }; + BRp$6.getCachedZSortedEles = function (forceRecalc) { + if (forceRecalc || !this.cachedZSortedEles) { + var eles = this.cy.mutableElements().toArray(); + eles.sort(zIndexSort); + eles.interactive = eles.filter(function (ele) { + return ele.interactive(); + }); + this.cachedZSortedEles = eles; + this.updateCachedGrabbedEles(); + } else { + eles = this.cachedZSortedEles; + } + return eles; + }; - this.setHSL( h, s, l ); + var BRp$5 = {}; + [BRp$e, BRp$d, BRp$c, BRp$b, BRp$a, BRp$9, BRp$8, BRp$7, BRp$6].forEach(function (props) { + extend$1(BRp$5, props); + }); - return this; + var BRp$4 = {}; + BRp$4.getCachedImage = function (url, crossOrigin, onLoad) { + var r = this; + var imageCache = r.imageCache = r.imageCache || {}; + var cache = imageCache[url]; + if (cache) { + if (!cache.image.complete) { + cache.image.addEventListener('load', onLoad); + } + return cache.image; + } else { + cache = imageCache[url] = imageCache[url] || {}; + var image = cache.image = new Image(); // eslint-disable-line no-undef + + image.addEventListener('load', onLoad); + image.addEventListener('error', function () { + image.error = true; + }); - } + // #1582 safari doesn't load data uris with crossOrigin properly + // https://bugs.webkit.org/show_bug.cgi?id=123978 + var dataUriPrefix = 'data:'; + var isDataUri = url.substring(0, dataUriPrefix.length).toLowerCase() === dataUriPrefix; + if (!isDataUri) { + // if crossorigin is 'null'(stringified), then manually set it to null + crossOrigin = crossOrigin === 'null' ? null : crossOrigin; + image.crossOrigin = crossOrigin; // prevent tainted canvas + } - equals( c ) { + image.src = url; + return image; + } + }; - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + var BRp$3 = {}; - } + /* global document, window, ResizeObserver, MutationObserver */ - fromArray( array, offset = 0 ) { + BRp$3.registerBinding = function (target, event, handler, useCapture) { + // eslint-disable-line no-unused-vars + var args = Array.prototype.slice.apply(arguments, [1]); // copy + var b = this.binder(target); + return b.on.apply(b, args); + }; + BRp$3.binder = function (tgt) { + var r = this; + var containerWindow = r.cy.window(); + var tgtIsDom = tgt === containerWindow || tgt === containerWindow.document || tgt === containerWindow.document.body || domElement(tgt); + if (r.supportsPassiveEvents == null) { + // from https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection + var supportsPassive = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function get() { + supportsPassive = true; + return true; + } + }); + containerWindow.addEventListener('test', null, opts); + } catch (err) { + // not supported + } + r.supportsPassiveEvents = supportsPassive; + } + var on = function on(event, handler, useCapture) { + var args = Array.prototype.slice.call(arguments); + if (tgtIsDom && r.supportsPassiveEvents) { + // replace useCapture w/ opts obj + args[2] = { + capture: useCapture != null ? useCapture : false, + passive: false, + once: false + }; + } + r.bindings.push({ + target: tgt, + args: args + }); + (tgt.addEventListener || tgt.on).apply(tgt, args); + return this; + }; + return { + on: on, + addEventListener: on, + addListener: on, + bind: on + }; + }; + BRp$3.nodeIsDraggable = function (node) { + return node && node.isNode() && !node.locked() && node.grabbable(); + }; + BRp$3.nodeIsGrabbable = function (node) { + return this.nodeIsDraggable(node) && node.interactive(); + }; + BRp$3.load = function () { + var r = this; + var containerWindow = r.cy.window(); + var isSelected = function isSelected(ele) { + return ele.selected(); + }; + var triggerEvents = function triggerEvents(target, names, e, position) { + if (target == null) { + target = r.cy; + } + for (var i = 0; i < names.length; i++) { + var name = names[i]; + target.emit({ + originalEvent: e, + type: name, + position: position + }); + } + }; + var isMultSelKeyDown = function isMultSelKeyDown(e) { + return e.shiftKey || e.metaKey || e.ctrlKey; // maybe e.altKey + }; + + var allowPanningPassthrough = function allowPanningPassthrough(down, downs) { + var allowPassthrough = true; + if (r.cy.hasCompoundNodes() && down && down.pannable()) { + // a grabbable compound node below the ele => no passthrough panning + for (var i = 0; downs && i < downs.length; i++) { + var down = downs[i]; + + //if any parent node in event hierarchy isn't pannable, reject passthrough + if (down.isNode() && down.isParent() && !down.pannable()) { + allowPassthrough = false; + break; + } + } + } else { + allowPassthrough = true; + } + return allowPassthrough; + }; + var setGrabbed = function setGrabbed(ele) { + ele[0]._private.grabbed = true; + }; + var setFreed = function setFreed(ele) { + ele[0]._private.grabbed = false; + }; + var setInDragLayer = function setInDragLayer(ele) { + ele[0]._private.rscratch.inDragLayer = true; + }; + var setOutDragLayer = function setOutDragLayer(ele) { + ele[0]._private.rscratch.inDragLayer = false; + }; + var setGrabTarget = function setGrabTarget(ele) { + ele[0]._private.rscratch.isGrabTarget = true; + }; + var removeGrabTarget = function removeGrabTarget(ele) { + ele[0]._private.rscratch.isGrabTarget = false; + }; + var addToDragList = function addToDragList(ele, opts) { + var list = opts.addToList; + var listHasEle = list.has(ele); + if (!listHasEle && ele.grabbable() && !ele.locked()) { + list.merge(ele); + setGrabbed(ele); + } + }; - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; + // helper function to determine which child nodes and inner edges + // of a compound node to be dragged as well as the grabbed and selected nodes + var addDescendantsToDrag = function addDescendantsToDrag(node, opts) { + if (!node.cy().hasCompoundNodes()) { + return; + } + if (opts.inDragLayer == null && opts.addToList == null) { + return; + } // nothing to do + + var innerNodes = node.descendants(); + if (opts.inDragLayer) { + innerNodes.forEach(setInDragLayer); + innerNodes.connectedEdges().forEach(setInDragLayer); + } + if (opts.addToList) { + addToDragList(innerNodes, opts); + } + }; + + // adds the given nodes and its neighbourhood to the drag layer + var addNodesToDrag = function addNodesToDrag(nodes, opts) { + opts = opts || {}; + var hasCompoundNodes = nodes.cy().hasCompoundNodes(); + if (opts.inDragLayer) { + nodes.forEach(setInDragLayer); + nodes.neighborhood().stdFilter(function (ele) { + return !hasCompoundNodes || ele.isEdge(); + }).forEach(setInDragLayer); + } + if (opts.addToList) { + nodes.forEach(function (ele) { + addToDragList(ele, opts); + }); + } + addDescendantsToDrag(nodes, opts); // always add to drag - return this; + // also add nodes and edges related to the topmost ancestor + updateAncestorsInDragLayer(nodes, { + inDragLayer: opts.inDragLayer + }); + r.updateCachedGrabbedEles(); + }; + var addNodeToDrag = addNodesToDrag; + var freeDraggedElements = function freeDraggedElements(grabbedEles) { + if (!grabbedEles) { + return; + } - } + // just go over all elements rather than doing a bunch of (possibly expensive) traversals + r.getCachedZSortedEles().forEach(function (ele) { + setFreed(ele); + setOutDragLayer(ele); + removeGrabTarget(ele); + }); + r.updateCachedGrabbedEles(); + }; + + // helper function to determine which ancestor nodes and edges should go + // to the drag layer (or should be removed from drag layer). + var updateAncestorsInDragLayer = function updateAncestorsInDragLayer(node, opts) { + if (opts.inDragLayer == null && opts.addToList == null) { + return; + } // nothing to do + + if (!node.cy().hasCompoundNodes()) { + return; + } - toArray( array = [], offset = 0 ) { + // find top-level parent + var parent = node.ancestors().orphans(); - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; + // no parent node: no nodes to add to the drag layer + if (parent.same(node)) { + return; + } + var nodes = parent.descendants().spawnSelf().merge(parent).unmerge(node).unmerge(node.descendants()); + var edges = nodes.connectedEdges(); + if (opts.inDragLayer) { + edges.forEach(setInDragLayer); + nodes.forEach(setInDragLayer); + } + if (opts.addToList) { + nodes.forEach(function (ele) { + addToDragList(ele, opts); + }); + } + }; + var blurActiveDomElement = function blurActiveDomElement() { + if (document.activeElement != null && document.activeElement.blur != null) { + document.activeElement.blur(); + } + }; + var haveMutationsApi = typeof MutationObserver !== 'undefined'; + var haveResizeObserverApi = typeof ResizeObserver !== 'undefined'; + + // watch for when the cy container is removed from the dom + if (haveMutationsApi) { + r.removeObserver = new MutationObserver(function (mutns) { + // eslint-disable-line no-undef + for (var i = 0; i < mutns.length; i++) { + var mutn = mutns[i]; + var rNodes = mutn.removedNodes; + if (rNodes) { + for (var j = 0; j < rNodes.length; j++) { + var rNode = rNodes[j]; + if (rNode === r.container) { + r.destroy(); + break; + } + } + } + } + }); + if (r.container.parentNode) { + r.removeObserver.observe(r.container.parentNode, { + childList: true + }); + } + } else { + r.registerBinding(r.container, 'DOMNodeRemoved', function (e) { + // eslint-disable-line no-unused-vars + r.destroy(); + }); + } + var onResize = debounce_1(function () { + r.cy.resize(); + }, 100); + if (haveMutationsApi) { + r.styleObserver = new MutationObserver(onResize); // eslint-disable-line no-undef + + r.styleObserver.observe(r.container, { + attributes: true + }); + } - return array; + // auto resize + r.registerBinding(containerWindow, 'resize', onResize); // eslint-disable-line no-undef - } + if (haveResizeObserverApi) { + r.resizeObserver = new ResizeObserver(onResize); // eslint-disable-line no-undef - fromBufferAttribute( attribute, index ) { + r.resizeObserver.observe(r.container); + } + var forEachUp = function forEachUp(domEle, fn) { + while (domEle != null) { + fn(domEle); + domEle = domEle.parentNode; + } + }; + var invalidateCoords = function invalidateCoords() { + r.invalidateContainerClientCoordsCache(); + }; + forEachUp(r.container, function (domEle) { + r.registerBinding(domEle, 'transitionend', invalidateCoords); + r.registerBinding(domEle, 'animationend', invalidateCoords); + r.registerBinding(domEle, 'scroll', invalidateCoords); + }); + + // stop right click menu from appearing on cy + r.registerBinding(r.container, 'contextmenu', function (e) { + e.preventDefault(); + }); + var inBoxSelection = function inBoxSelection() { + return r.selection[4] !== 0; + }; + var eventInContainer = function eventInContainer(e) { + // save cycles if mouse events aren't to be captured + var containerPageCoords = r.findContainerClientCoords(); + var x = containerPageCoords[0]; + var y = containerPageCoords[1]; + var width = containerPageCoords[2]; + var height = containerPageCoords[3]; + var positions = e.touches ? e.touches : [e]; + var atLeastOnePosInside = false; + for (var i = 0; i < positions.length; i++) { + var p = positions[i]; + if (x <= p.clientX && p.clientX <= x + width && y <= p.clientY && p.clientY <= y + height) { + atLeastOnePosInside = true; + break; + } + } + if (!atLeastOnePosInside) { + return false; + } + var container = r.container; + var target = e.target; + var tParent = target.parentNode; + var containerIsTarget = false; + while (tParent) { + if (tParent === container) { + containerIsTarget = true; + break; + } + tParent = tParent.parentNode; + } + if (!containerIsTarget) { + return false; + } // if target is outisde cy container, then this event is not for us - this.r = attribute.getX( index ); - this.g = attribute.getY( index ); - this.b = attribute.getZ( index ); + return true; + }; - return this; + // Primary key + r.registerBinding(r.container, 'mousedown', function mousedownHandler(e) { + if (!eventInContainer(e)) { + return; + } + e.preventDefault(); + blurActiveDomElement(); + r.hoverData.capture = true; + r.hoverData.which = e.which; + var cy = r.cy; + var gpos = [e.clientX, e.clientY]; + var pos = r.projectIntoViewport(gpos[0], gpos[1]); + var select = r.selection; + var nears = r.findNearestElements(pos[0], pos[1], true, false); + var near = nears[0]; + var draggedElements = r.dragData.possibleDragElements; + r.hoverData.mdownPos = pos; + r.hoverData.mdownGPos = gpos; + var checkForTaphold = function checkForTaphold() { + r.hoverData.tapholdCancelled = false; + clearTimeout(r.hoverData.tapholdTimeout); + r.hoverData.tapholdTimeout = setTimeout(function () { + if (r.hoverData.tapholdCancelled) { + return; + } else { + var ele = r.hoverData.down; + if (ele) { + ele.emit({ + originalEvent: e, + type: 'taphold', + position: { + x: pos[0], + y: pos[1] + } + }); + } else { + cy.emit({ + originalEvent: e, + type: 'taphold', + position: { + x: pos[0], + y: pos[1] + } + }); + } + } + }, r.tapholdDuration); + }; - } + // Right click button + if (e.which == 3) { + r.hoverData.cxtStarted = true; + var cxtEvt = { + originalEvent: e, + type: 'cxttapstart', + position: { + x: pos[0], + y: pos[1] + } + }; + if (near) { + near.activate(); + near.emit(cxtEvt); + r.hoverData.down = near; + } else { + cy.emit(cxtEvt); + } + r.hoverData.downTime = new Date().getTime(); + r.hoverData.cxtDragged = false; + + // Primary button + } else if (e.which == 1) { + if (near) { + near.activate(); + } + + // Element dragging + { + // If something is under the cursor and it is draggable, prepare to grab it + if (near != null) { + if (r.nodeIsGrabbable(near)) { + var makeEvent = function makeEvent(type) { + return { + originalEvent: e, + type: type, + position: { + x: pos[0], + y: pos[1] + } + }; + }; + var triggerGrab = function triggerGrab(ele) { + ele.emit(makeEvent('grab')); + }; + setGrabTarget(near); + if (!near.selected()) { + draggedElements = r.dragData.possibleDragElements = cy.collection(); + addNodeToDrag(near, { + addToList: draggedElements + }); + near.emit(makeEvent('grabon')).emit(makeEvent('grab')); + } else { + draggedElements = r.dragData.possibleDragElements = cy.collection(); + var selectedNodes = cy.$(function (ele) { + return ele.isNode() && ele.selected() && r.nodeIsGrabbable(ele); + }); + addNodesToDrag(selectedNodes, { + addToList: draggedElements + }); + near.emit(makeEvent('grabon')); + selectedNodes.forEach(triggerGrab); + } + r.redrawHint('eles', true); + r.redrawHint('drag', true); + } + } + r.hoverData.down = near; + r.hoverData.downs = nears; + r.hoverData.downTime = new Date().getTime(); + } + triggerEvents(near, ['mousedown', 'tapstart', 'vmousedown'], e, { + x: pos[0], + y: pos[1] + }); + if (near == null) { + select[4] = 1; + r.data.bgActivePosistion = { + x: pos[0], + y: pos[1] + }; + r.redrawHint('select', true); + r.redraw(); + } else if (near.pannable()) { + select[4] = 1; // for future pan + } - toJSON() { + checkForTaphold(); + } - return this.getHex(); + // Initialize selection box coordinates + select[0] = select[2] = pos[0]; + select[1] = select[3] = pos[1]; + }, false); + r.registerBinding(containerWindow, 'mousemove', function mousemoveHandler(e) { + // eslint-disable-line no-undef + var capture = r.hoverData.capture; + if (!capture && !eventInContainer(e)) { + return; + } + var preventDefault = false; + var cy = r.cy; + var zoom = cy.zoom(); + var gpos = [e.clientX, e.clientY]; + var pos = r.projectIntoViewport(gpos[0], gpos[1]); + var mdownPos = r.hoverData.mdownPos; + var mdownGPos = r.hoverData.mdownGPos; + var select = r.selection; + var near = null; + if (!r.hoverData.draggingEles && !r.hoverData.dragging && !r.hoverData.selecting) { + near = r.findNearestElement(pos[0], pos[1], true, false); + } + var last = r.hoverData.last; + var down = r.hoverData.down; + var disp = [pos[0] - select[2], pos[1] - select[3]]; + var draggedElements = r.dragData.possibleDragElements; + var isOverThresholdDrag; + if (mdownGPos) { + var dx = gpos[0] - mdownGPos[0]; + var dx2 = dx * dx; + var dy = gpos[1] - mdownGPos[1]; + var dy2 = dy * dy; + var dist2 = dx2 + dy2; + r.hoverData.isOverThresholdDrag = isOverThresholdDrag = dist2 >= r.desktopTapThreshold2; + } + var multSelKeyDown = isMultSelKeyDown(e); + if (isOverThresholdDrag) { + r.hoverData.tapholdCancelled = true; + } + var updateDragDelta = function updateDragDelta() { + var dragDelta = r.hoverData.dragDelta = r.hoverData.dragDelta || []; + if (dragDelta.length === 0) { + dragDelta.push(disp[0]); + dragDelta.push(disp[1]); + } else { + dragDelta[0] += disp[0]; + dragDelta[1] += disp[1]; + } + }; + preventDefault = true; + triggerEvents(near, ['mousemove', 'vmousemove', 'tapdrag'], e, { + x: pos[0], + y: pos[1] + }); + var goIntoBoxMode = function goIntoBoxMode() { + r.data.bgActivePosistion = undefined; + if (!r.hoverData.selecting) { + cy.emit({ + originalEvent: e, + type: 'boxstart', + position: { + x: pos[0], + y: pos[1] + } + }); + } + select[4] = 1; + r.hoverData.selecting = true; + r.redrawHint('select', true); + r.redraw(); + }; - } + // trigger context drag if rmouse down + if (r.hoverData.which === 3) { + // but only if over threshold + if (isOverThresholdDrag) { + var cxtEvt = { + originalEvent: e, + type: 'cxtdrag', + position: { + x: pos[0], + y: pos[1] + } + }; + if (down) { + down.emit(cxtEvt); + } else { + cy.emit(cxtEvt); + } + r.hoverData.cxtDragged = true; + if (!r.hoverData.cxtOver || near !== r.hoverData.cxtOver) { + if (r.hoverData.cxtOver) { + r.hoverData.cxtOver.emit({ + originalEvent: e, + type: 'cxtdragout', + position: { + x: pos[0], + y: pos[1] + } + }); + } + r.hoverData.cxtOver = near; + if (near) { + near.emit({ + originalEvent: e, + type: 'cxtdragover', + position: { + x: pos[0], + y: pos[1] + } + }); + } + } + } + + // Check if we are drag panning the entire graph + } else if (r.hoverData.dragging) { + preventDefault = true; + if (cy.panningEnabled() && cy.userPanningEnabled()) { + var deltaP; + if (r.hoverData.justStartedPan) { + var mdPos = r.hoverData.mdownPos; + deltaP = { + x: (pos[0] - mdPos[0]) * zoom, + y: (pos[1] - mdPos[1]) * zoom + }; + r.hoverData.justStartedPan = false; + } else { + deltaP = { + x: disp[0] * zoom, + y: disp[1] * zoom + }; + } + cy.panBy(deltaP); + cy.emit('dragpan'); + r.hoverData.dragged = true; + } + + // Needs reproject due to pan changing viewport + pos = r.projectIntoViewport(e.clientX, e.clientY); + + // Checks primary button down & out of time & mouse not moved much + } else if (select[4] == 1 && (down == null || down.pannable())) { + if (isOverThresholdDrag) { + if (!r.hoverData.dragging && cy.boxSelectionEnabled() && (multSelKeyDown || !cy.panningEnabled() || !cy.userPanningEnabled())) { + goIntoBoxMode(); + } else if (!r.hoverData.selecting && cy.panningEnabled() && cy.userPanningEnabled()) { + var allowPassthrough = allowPanningPassthrough(down, r.hoverData.downs); + if (allowPassthrough) { + r.hoverData.dragging = true; + r.hoverData.justStartedPan = true; + select[4] = 0; + r.data.bgActivePosistion = array2point(mdownPos); + r.redrawHint('select', true); + r.redraw(); + } + } + if (down && down.pannable() && down.active()) { + down.unactivate(); + } + } + } else { + if (down && down.pannable() && down.active()) { + down.unactivate(); + } + if ((!down || !down.grabbed()) && near != last) { + if (last) { + triggerEvents(last, ['mouseout', 'tapdragout'], e, { + x: pos[0], + y: pos[1] + }); + } + if (near) { + triggerEvents(near, ['mouseover', 'tapdragover'], e, { + x: pos[0], + y: pos[1] + }); + } + r.hoverData.last = near; + } + if (down) { + if (isOverThresholdDrag) { + // then we can take action + + if (cy.boxSelectionEnabled() && multSelKeyDown) { + // then selection overrides + if (down && down.grabbed()) { + freeDraggedElements(draggedElements); + down.emit('freeon'); + draggedElements.emit('free'); + if (r.dragData.didDrag) { + down.emit('dragfreeon'); + draggedElements.emit('dragfree'); + } + } + goIntoBoxMode(); + } else if (down && down.grabbed() && r.nodeIsDraggable(down)) { + // drag node + var justStartedDrag = !r.dragData.didDrag; + if (justStartedDrag) { + r.redrawHint('eles', true); + } + r.dragData.didDrag = true; // indicate that we actually did drag the node - *[ Symbol.iterator ]() { + // now, add the elements to the drag layer if not done already + if (!r.hoverData.draggingEles) { + addNodesToDrag(draggedElements, { + inDragLayer: true + }); + } + var totalShift = { + x: 0, + y: 0 + }; + if (number$1(disp[0]) && number$1(disp[1])) { + totalShift.x += disp[0]; + totalShift.y += disp[1]; + if (justStartedDrag) { + var dragDelta = r.hoverData.dragDelta; + if (dragDelta && number$1(dragDelta[0]) && number$1(dragDelta[1])) { + totalShift.x += dragDelta[0]; + totalShift.y += dragDelta[1]; + } + } + } + r.hoverData.draggingEles = true; + draggedElements.silentShift(totalShift).emit('position drag'); + r.redrawHint('drag', true); + r.redraw(); + } + } else { + // otherwise save drag delta for when we actually start dragging so the relative grab pos is constant + updateDragDelta(); + } + } - yield this.r; - yield this.g; - yield this.b; + // prevent the dragging from triggering text selection on the page + preventDefault = true; + } + select[2] = pos[0]; + select[3] = pos[1]; + if (preventDefault) { + if (e.stopPropagation) e.stopPropagation(); + if (e.preventDefault) e.preventDefault(); + return false; + } + }, false); + var clickTimeout, didDoubleClick, prevClickTimeStamp; + r.registerBinding(containerWindow, 'mouseup', function mouseupHandler(e) { + // eslint-disable-line no-undef + var capture = r.hoverData.capture; + if (!capture) { + return; + } + r.hoverData.capture = false; + var cy = r.cy; + var pos = r.projectIntoViewport(e.clientX, e.clientY); + var select = r.selection; + var near = r.findNearestElement(pos[0], pos[1], true, false); + var draggedElements = r.dragData.possibleDragElements; + var down = r.hoverData.down; + var multSelKeyDown = isMultSelKeyDown(e); + if (r.data.bgActivePosistion) { + r.redrawHint('select', true); + r.redraw(); + } + r.hoverData.tapholdCancelled = true; + r.data.bgActivePosistion = undefined; // not active bg now - } + if (down) { + down.unactivate(); + } + if (r.hoverData.which === 3) { + var cxtEvt = { + originalEvent: e, + type: 'cxttapend', + position: { + x: pos[0], + y: pos[1] + } + }; + if (down) { + down.emit(cxtEvt); + } else { + cy.emit(cxtEvt); + } + if (!r.hoverData.cxtDragged) { + var cxtTap = { + originalEvent: e, + type: 'cxttap', + position: { + x: pos[0], + y: pos[1] + } + }; + if (down) { + down.emit(cxtTap); + } else { + cy.emit(cxtTap); + } + } + r.hoverData.cxtDragged = false; + r.hoverData.which = null; + } else if (r.hoverData.which === 1) { + triggerEvents(near, ['mouseup', 'tapend', 'vmouseup'], e, { + x: pos[0], + y: pos[1] + }); + if (!r.dragData.didDrag && + // didn't move a node around + !r.hoverData.dragged && + // didn't pan + !r.hoverData.selecting && + // not box selection + !r.hoverData.isOverThresholdDrag // didn't move too much + ) { + triggerEvents(down, ["click", "tap", "vclick"], e, { + x: pos[0], + y: pos[1] + }); + didDoubleClick = false; + if (e.timeStamp - prevClickTimeStamp <= cy.multiClickDebounceTime()) { + clickTimeout && clearTimeout(clickTimeout); + didDoubleClick = true; + prevClickTimeStamp = null; + triggerEvents(down, ["dblclick", "dbltap", "vdblclick"], e, { + x: pos[0], + y: pos[1] + }); + } else { + clickTimeout = setTimeout(function () { + if (didDoubleClick) return; + triggerEvents(down, ["oneclick", "onetap", "voneclick"], e, { + x: pos[0], + y: pos[1] + }); + }, cy.multiClickDebounceTime()); + prevClickTimeStamp = e.timeStamp; + } + } + + // Deselect all elements if nothing is currently under the mouse cursor and we aren't dragging something + if (down == null // not mousedown on node + && !r.dragData.didDrag // didn't move the node around + && !r.hoverData.selecting // not box selection + && !r.hoverData.dragged // didn't pan + && !isMultSelKeyDown(e)) { + cy.$(isSelected).unselect(['tapunselect']); + if (draggedElements.length > 0) { + r.redrawHint('eles', true); + } + r.dragData.possibleDragElements = draggedElements = cy.collection(); + } + + // Single selection + if (near == down && !r.dragData.didDrag && !r.hoverData.selecting) { + if (near != null && near._private.selectable) { + if (r.hoverData.dragging) ; else if (cy.selectionType() === 'additive' || multSelKeyDown) { + if (near.selected()) { + near.unselect(['tapunselect']); + } else { + near.select(['tapselect']); + } + } else { + if (!multSelKeyDown) { + cy.$(isSelected).unmerge(near).unselect(['tapunselect']); + near.select(['tapselect']); + } + } + r.redrawHint('eles', true); + } + } + if (r.hoverData.selecting) { + var box = cy.collection(r.getAllInBox(select[0], select[1], select[2], select[3])); + r.redrawHint('select', true); + if (box.length > 0) { + r.redrawHint('eles', true); + } + cy.emit({ + type: 'boxend', + originalEvent: e, + position: { + x: pos[0], + y: pos[1] + } + }); + var eleWouldBeSelected = function eleWouldBeSelected(ele) { + return ele.selectable() && !ele.selected(); + }; + if (cy.selectionType() === 'additive') { + box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect'); + } else { + if (!multSelKeyDown) { + cy.$(isSelected).unmerge(box).unselect(); + } + box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect'); + } - } + // always need redraw in case eles unselectable + r.redraw(); + } + + // Cancel drag pan + if (r.hoverData.dragging) { + r.hoverData.dragging = false; + r.redrawHint('select', true); + r.redrawHint('eles', true); + r.redraw(); + } + if (!select[4]) { + r.redrawHint('drag', true); + r.redrawHint('eles', true); + var downWasGrabbed = down && down.grabbed(); + freeDraggedElements(draggedElements); + if (downWasGrabbed) { + down.emit('freeon'); + draggedElements.emit('free'); + if (r.dragData.didDrag) { + down.emit('dragfreeon'); + draggedElements.emit('dragfree'); + } + } + } + } // else not right mouse + + select[4] = 0; + r.hoverData.down = null; + r.hoverData.cxtStarted = false; + r.hoverData.draggingEles = false; + r.hoverData.selecting = false; + r.hoverData.isOverThresholdDrag = false; + r.dragData.didDrag = false; + r.hoverData.dragged = false; + r.hoverData.dragDelta = []; + r.hoverData.mdownPos = null; + r.hoverData.mdownGPos = null; + }, false); + var wheelHandler = function wheelHandler(e) { + if (r.scrollingPage) { + return; + } // while scrolling, ignore wheel-to-zoom + + var cy = r.cy; + var zoom = cy.zoom(); + var pan = cy.pan(); + var pos = r.projectIntoViewport(e.clientX, e.clientY); + var rpos = [pos[0] * zoom + pan.x, pos[1] * zoom + pan.y]; + if (r.hoverData.draggingEles || r.hoverData.dragging || r.hoverData.cxtStarted || inBoxSelection()) { + // if pan dragging or cxt dragging, wheel movements make no zoom + e.preventDefault(); + return; + } + if (cy.panningEnabled() && cy.userPanningEnabled() && cy.zoomingEnabled() && cy.userZoomingEnabled()) { + e.preventDefault(); + r.data.wheelZooming = true; + clearTimeout(r.data.wheelTimeout); + r.data.wheelTimeout = setTimeout(function () { + r.data.wheelZooming = false; + r.redrawHint('eles', true); + r.redraw(); + }, 150); + var diff; + if (e.deltaY != null) { + diff = e.deltaY / -250; + } else if (e.wheelDeltaY != null) { + diff = e.wheelDeltaY / 1000; + } else { + diff = e.wheelDelta / 1000; + } + diff = diff * r.wheelSensitivity; + var needsWheelFix = e.deltaMode === 1; + if (needsWheelFix) { + // fixes slow wheel events on ff/linux and ff/windows + diff *= 33; + } + var newZoom = cy.zoom() * Math.pow(10, diff); + if (e.type === 'gesturechange') { + newZoom = r.gestureStartZoom * e.scale; + } + cy.zoom({ + level: newZoom, + renderedPosition: { + x: rpos[0], + y: rpos[1] + } + }); + cy.emit(e.type === 'gesturechange' ? 'pinchzoom' : 'scrollzoom'); + } + }; + + // Functions to help with whether mouse wheel should trigger zooming + // -- + r.registerBinding(r.container, 'wheel', wheelHandler, true); + + // disable nonstandard wheel events + // r.registerBinding(r.container, 'mousewheel', wheelHandler, true); + // r.registerBinding(r.container, 'DOMMouseScroll', wheelHandler, true); + // r.registerBinding(r.container, 'MozMousePixelScroll', wheelHandler, true); // older firefox + + r.registerBinding(containerWindow, 'scroll', function scrollHandler(e) { + // eslint-disable-line no-unused-vars + r.scrollingPage = true; + clearTimeout(r.scrollingPageTimeout); + r.scrollingPageTimeout = setTimeout(function () { + r.scrollingPage = false; + }, 250); + }, true); + + // desktop safari pinch to zoom start + r.registerBinding(r.container, 'gesturestart', function gestureStartHandler(e) { + r.gestureStartZoom = r.cy.zoom(); + if (!r.hasTouchStarted) { + // don't affect touch devices like iphone + e.preventDefault(); + } + }, true); + r.registerBinding(r.container, 'gesturechange', function (e) { + if (!r.hasTouchStarted) { + // don't affect touch devices like iphone + wheelHandler(e); + } + }, true); + + // Functions to help with handling mouseout/mouseover on the Cytoscape container + // Handle mouseout on Cytoscape container + r.registerBinding(r.container, 'mouseout', function mouseOutHandler(e) { + var pos = r.projectIntoViewport(e.clientX, e.clientY); + r.cy.emit({ + originalEvent: e, + type: 'mouseout', + position: { + x: pos[0], + y: pos[1] + } + }); + }, false); + r.registerBinding(r.container, 'mouseover', function mouseOverHandler(e) { + var pos = r.projectIntoViewport(e.clientX, e.clientY); + r.cy.emit({ + originalEvent: e, + type: 'mouseover', + position: { + x: pos[0], + y: pos[1] + } + }); + }, false); + var f1x1, f1y1, f2x1, f2y1; // starting points for pinch-to-zoom + var distance1, distance1Sq; // initial distance between finger 1 and finger 2 for pinch-to-zoom + var center1, modelCenter1; // center point on start pinch to zoom + var offsetLeft, offsetTop; + var containerWidth, containerHeight; + var twoFingersStartInside; + var distance = function distance(x1, y1, x2, y2) { + return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); + }; + var distanceSq = function distanceSq(x1, y1, x2, y2) { + return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); + }; + var touchstartHandler; + r.registerBinding(r.container, 'touchstart', touchstartHandler = function touchstartHandler(e) { + r.hasTouchStarted = true; + if (!eventInContainer(e)) { + return; + } + blurActiveDomElement(); + r.touchData.capture = true; + r.data.bgActivePosistion = undefined; + var cy = r.cy; + var now = r.touchData.now; + var earlier = r.touchData.earlier; + if (e.touches[0]) { + var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); + now[0] = pos[0]; + now[1] = pos[1]; + } + if (e.touches[1]) { + var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); + now[2] = pos[0]; + now[3] = pos[1]; + } + if (e.touches[2]) { + var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); + now[4] = pos[0]; + now[5] = pos[1]; + } - Color.NAMES = _colorKeywords; + // record starting points for pinch-to-zoom + if (e.touches[1]) { + r.touchData.singleTouchMoved = true; + freeDraggedElements(r.dragData.touchDragEles); + var offsets = r.findContainerClientCoords(); + offsetLeft = offsets[0]; + offsetTop = offsets[1]; + containerWidth = offsets[2]; + containerHeight = offsets[3]; + f1x1 = e.touches[0].clientX - offsetLeft; + f1y1 = e.touches[0].clientY - offsetTop; + f2x1 = e.touches[1].clientX - offsetLeft; + f2y1 = e.touches[1].clientY - offsetTop; + twoFingersStartInside = 0 <= f1x1 && f1x1 <= containerWidth && 0 <= f2x1 && f2x1 <= containerWidth && 0 <= f1y1 && f1y1 <= containerHeight && 0 <= f2y1 && f2y1 <= containerHeight; + var pan = cy.pan(); + var zoom = cy.zoom(); + distance1 = distance(f1x1, f1y1, f2x1, f2y1); + distance1Sq = distanceSq(f1x1, f1y1, f2x1, f2y1); + center1 = [(f1x1 + f2x1) / 2, (f1y1 + f2y1) / 2]; + modelCenter1 = [(center1[0] - pan.x) / zoom, (center1[1] - pan.y) / zoom]; + + // consider context tap + var cxtDistThreshold = 200; + var cxtDistThresholdSq = cxtDistThreshold * cxtDistThreshold; + if (distance1Sq < cxtDistThresholdSq && !e.touches[2]) { + var near1 = r.findNearestElement(now[0], now[1], true, true); + var near2 = r.findNearestElement(now[2], now[3], true, true); + if (near1 && near1.isNode()) { + near1.activate().emit({ + originalEvent: e, + type: 'cxttapstart', + position: { + x: now[0], + y: now[1] + } + }); + r.touchData.start = near1; + } else if (near2 && near2.isNode()) { + near2.activate().emit({ + originalEvent: e, + type: 'cxttapstart', + position: { + x: now[0], + y: now[1] + } + }); + r.touchData.start = near2; + } else { + cy.emit({ + originalEvent: e, + type: 'cxttapstart', + position: { + x: now[0], + y: now[1] + } + }); + } + if (r.touchData.start) { + r.touchData.start._private.grabbed = false; + } + r.touchData.cxt = true; + r.touchData.cxtDragged = false; + r.data.bgActivePosistion = undefined; + r.redraw(); + return; + } + } + if (e.touches[2]) { + // ignore + + // safari on ios pans the page otherwise (normally you should be able to preventdefault on touchmove...) + if (cy.boxSelectionEnabled()) { + e.preventDefault(); + } + } else if (e.touches[1]) ; else if (e.touches[0]) { + var nears = r.findNearestElements(now[0], now[1], true, true); + var near = nears[0]; + if (near != null) { + near.activate(); + r.touchData.start = near; + r.touchData.starts = nears; + if (r.nodeIsGrabbable(near)) { + var draggedEles = r.dragData.touchDragEles = cy.collection(); + var selectedNodes = null; + r.redrawHint('eles', true); + r.redrawHint('drag', true); + if (near.selected()) { + // reset drag elements, since near will be added again + + selectedNodes = cy.$(function (ele) { + return ele.selected() && r.nodeIsGrabbable(ele); + }); + addNodesToDrag(selectedNodes, { + addToList: draggedEles + }); + } else { + addNodeToDrag(near, { + addToList: draggedEles + }); + } + setGrabTarget(near); + var makeEvent = function makeEvent(type) { + return { + originalEvent: e, + type: type, + position: { + x: now[0], + y: now[1] + } + }; + }; + near.emit(makeEvent('grabon')); + if (selectedNodes) { + selectedNodes.forEach(function (n) { + n.emit(makeEvent('grab')); + }); + } else { + near.emit(makeEvent('grab')); + } + } + } + triggerEvents(near, ['touchstart', 'tapstart', 'vmousedown'], e, { + x: now[0], + y: now[1] + }); + if (near == null) { + r.data.bgActivePosistion = { + x: pos[0], + y: pos[1] + }; + r.redrawHint('select', true); + r.redraw(); + } + + // Tap, taphold + // ----- + + r.touchData.singleTouchMoved = false; + r.touchData.singleTouchStartTime = +new Date(); + clearTimeout(r.touchData.tapholdTimeout); + r.touchData.tapholdTimeout = setTimeout(function () { + if (r.touchData.singleTouchMoved === false && !r.pinching // if pinching, then taphold unselect shouldn't take effect + && !r.touchData.selecting // box selection shouldn't allow taphold through + ) { + triggerEvents(r.touchData.start, ['taphold'], e, { + x: now[0], + y: now[1] + }); + } + }, r.tapholdDuration); + } + if (e.touches.length >= 1) { + var sPos = r.touchData.startPosition = [null, null, null, null, null, null]; + for (var i = 0; i < now.length; i++) { + sPos[i] = earlier[i] = now[i]; + } + var touch0 = e.touches[0]; + r.touchData.startGPosition = [touch0.clientX, touch0.clientY]; + } + }, false); + var touchmoveHandler; + r.registerBinding(window, 'touchmove', touchmoveHandler = function touchmoveHandler(e) { + // eslint-disable-line no-undef + var capture = r.touchData.capture; + if (!capture && !eventInContainer(e)) { + return; + } + var select = r.selection; + var cy = r.cy; + var now = r.touchData.now; + var earlier = r.touchData.earlier; + var zoom = cy.zoom(); + if (e.touches[0]) { + var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); + now[0] = pos[0]; + now[1] = pos[1]; + } + if (e.touches[1]) { + var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); + now[2] = pos[0]; + now[3] = pos[1]; + } + if (e.touches[2]) { + var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); + now[4] = pos[0]; + now[5] = pos[1]; + } + var startGPos = r.touchData.startGPosition; + var isOverThresholdDrag; + if (capture && e.touches[0] && startGPos) { + var disp = []; + for (var j = 0; j < now.length; j++) { + disp[j] = now[j] - earlier[j]; + } + var dx = e.touches[0].clientX - startGPos[0]; + var dx2 = dx * dx; + var dy = e.touches[0].clientY - startGPos[1]; + var dy2 = dy * dy; + var dist2 = dx2 + dy2; + isOverThresholdDrag = dist2 >= r.touchTapThreshold2; + } - let _canvas; + // context swipe cancelling + if (capture && r.touchData.cxt) { + e.preventDefault(); + var f1x2 = e.touches[0].clientX - offsetLeft, + f1y2 = e.touches[0].clientY - offsetTop; + var f2x2 = e.touches[1].clientX - offsetLeft, + f2y2 = e.touches[1].clientY - offsetTop; + // var distance2 = distance( f1x2, f1y2, f2x2, f2y2 ); + var distance2Sq = distanceSq(f1x2, f1y2, f2x2, f2y2); + var factorSq = distance2Sq / distance1Sq; + var distThreshold = 150; + var distThresholdSq = distThreshold * distThreshold; + var factorThreshold = 1.5; + var factorThresholdSq = factorThreshold * factorThreshold; + + // cancel ctx gestures if the distance b/t the fingers increases + if (factorSq >= factorThresholdSq || distance2Sq >= distThresholdSq) { + r.touchData.cxt = false; + r.data.bgActivePosistion = undefined; + r.redrawHint('select', true); + var cxtEvt = { + originalEvent: e, + type: 'cxttapend', + position: { + x: now[0], + y: now[1] + } + }; + if (r.touchData.start) { + r.touchData.start.unactivate().emit(cxtEvt); + r.touchData.start = null; + } else { + cy.emit(cxtEvt); + } + } + } - class ImageUtils { + // context swipe + if (capture && r.touchData.cxt) { + var cxtEvt = { + originalEvent: e, + type: 'cxtdrag', + position: { + x: now[0], + y: now[1] + } + }; + r.data.bgActivePosistion = undefined; + r.redrawHint('select', true); + if (r.touchData.start) { + r.touchData.start.emit(cxtEvt); + } else { + cy.emit(cxtEvt); + } + if (r.touchData.start) { + r.touchData.start._private.grabbed = false; + } + r.touchData.cxtDragged = true; + var near = r.findNearestElement(now[0], now[1], true, true); + if (!r.touchData.cxtOver || near !== r.touchData.cxtOver) { + if (r.touchData.cxtOver) { + r.touchData.cxtOver.emit({ + originalEvent: e, + type: 'cxtdragout', + position: { + x: now[0], + y: now[1] + } + }); + } + r.touchData.cxtOver = near; + if (near) { + near.emit({ + originalEvent: e, + type: 'cxtdragover', + position: { + x: now[0], + y: now[1] + } + }); + } + } + + // box selection + } else if (capture && e.touches[2] && cy.boxSelectionEnabled()) { + e.preventDefault(); + r.data.bgActivePosistion = undefined; + this.lastThreeTouch = +new Date(); + if (!r.touchData.selecting) { + cy.emit({ + originalEvent: e, + type: 'boxstart', + position: { + x: now[0], + y: now[1] + } + }); + } + r.touchData.selecting = true; + r.touchData.didSelect = true; + select[4] = 1; + if (!select || select.length === 0 || select[0] === undefined) { + select[0] = (now[0] + now[2] + now[4]) / 3; + select[1] = (now[1] + now[3] + now[5]) / 3; + select[2] = (now[0] + now[2] + now[4]) / 3 + 1; + select[3] = (now[1] + now[3] + now[5]) / 3 + 1; + } else { + select[2] = (now[0] + now[2] + now[4]) / 3; + select[3] = (now[1] + now[3] + now[5]) / 3; + } + r.redrawHint('select', true); + r.redraw(); + + // pinch to zoom + } else if (capture && e.touches[1] && !r.touchData.didSelect // don't allow box selection to degrade to pinch-to-zoom + && cy.zoomingEnabled() && cy.panningEnabled() && cy.userZoomingEnabled() && cy.userPanningEnabled()) { + // two fingers => pinch to zoom + e.preventDefault(); + r.data.bgActivePosistion = undefined; + r.redrawHint('select', true); + var draggedEles = r.dragData.touchDragEles; + if (draggedEles) { + r.redrawHint('drag', true); + for (var i = 0; i < draggedEles.length; i++) { + var de_p = draggedEles[i]._private; + de_p.grabbed = false; + de_p.rscratch.inDragLayer = false; + } + } + var _start = r.touchData.start; + + // (x2, y2) for fingers 1 and 2 + var f1x2 = e.touches[0].clientX - offsetLeft, + f1y2 = e.touches[0].clientY - offsetTop; + var f2x2 = e.touches[1].clientX - offsetLeft, + f2y2 = e.touches[1].clientY - offsetTop; + var distance2 = distance(f1x2, f1y2, f2x2, f2y2); + // var distance2Sq = distanceSq( f1x2, f1y2, f2x2, f2y2 ); + // var factor = Math.sqrt( distance2Sq ) / Math.sqrt( distance1Sq ); + var factor = distance2 / distance1; + if (twoFingersStartInside) { + // delta finger1 + var df1x = f1x2 - f1x1; + var df1y = f1y2 - f1y1; + + // delta finger 2 + var df2x = f2x2 - f2x1; + var df2y = f2y2 - f2y1; + + // translation is the normalised vector of the two fingers movement + // i.e. so pinching cancels out and moving together pans + var tx = (df1x + df2x) / 2; + var ty = (df1y + df2y) / 2; + + // now calculate the zoom + var zoom1 = cy.zoom(); + var zoom2 = zoom1 * factor; + var pan1 = cy.pan(); + + // the model center point converted to the current rendered pos + var ctrx = modelCenter1[0] * zoom1 + pan1.x; + var ctry = modelCenter1[1] * zoom1 + pan1.y; + var pan2 = { + x: -zoom2 / zoom1 * (ctrx - pan1.x - tx) + ctrx, + y: -zoom2 / zoom1 * (ctry - pan1.y - ty) + ctry + }; - static getDataURL( image ) { - - if ( /^data:/i.test( image.src ) ) { - - return image.src; - - } - - if ( typeof HTMLCanvasElement == 'undefined' ) { - - return image.src; - - } - - let canvas; - - if ( image instanceof HTMLCanvasElement ) { - - canvas = image; - - } else { + // remove dragged eles + if (_start && _start.active()) { + var draggedEles = r.dragData.touchDragEles; + freeDraggedElements(draggedEles); + r.redrawHint('drag', true); + r.redrawHint('eles', true); + _start.unactivate().emit('freeon'); + draggedEles.emit('free'); + if (r.dragData.didDrag) { + _start.emit('dragfreeon'); + draggedEles.emit('dragfree'); + } + } + cy.viewport({ + zoom: zoom2, + pan: pan2, + cancelOnFailedZoom: true + }); + cy.emit('pinchzoom'); + distance1 = distance2; + f1x1 = f1x2; + f1y1 = f1y2; + f2x1 = f2x2; + f2y1 = f2y2; + r.pinching = true; + } + + // Re-project + if (e.touches[0]) { + var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); + now[0] = pos[0]; + now[1] = pos[1]; + } + if (e.touches[1]) { + var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); + now[2] = pos[0]; + now[3] = pos[1]; + } + if (e.touches[2]) { + var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); + now[4] = pos[0]; + now[5] = pos[1]; + } + } else if (e.touches[0] && !r.touchData.didSelect // don't allow box selection to degrade to single finger events like panning + ) { + var start = r.touchData.start; + var last = r.touchData.last; + var near; + if (!r.hoverData.draggingEles && !r.swipePanning) { + near = r.findNearestElement(now[0], now[1], true, true); + } + if (capture && start != null) { + e.preventDefault(); + } + + // dragging nodes + if (capture && start != null && r.nodeIsDraggable(start)) { + if (isOverThresholdDrag) { + // then dragging can happen + var draggedEles = r.dragData.touchDragEles; + var justStartedDrag = !r.dragData.didDrag; + if (justStartedDrag) { + addNodesToDrag(draggedEles, { + inDragLayer: true + }); + } + r.dragData.didDrag = true; + var totalShift = { + x: 0, + y: 0 + }; + if (number$1(disp[0]) && number$1(disp[1])) { + totalShift.x += disp[0]; + totalShift.y += disp[1]; + if (justStartedDrag) { + r.redrawHint('eles', true); + var dragDelta = r.touchData.dragDelta; + if (dragDelta && number$1(dragDelta[0]) && number$1(dragDelta[1])) { + totalShift.x += dragDelta[0]; + totalShift.y += dragDelta[1]; + } + } + } + r.hoverData.draggingEles = true; + draggedEles.silentShift(totalShift).emit('position drag'); + r.redrawHint('drag', true); + if (r.touchData.startPosition[0] == earlier[0] && r.touchData.startPosition[1] == earlier[1]) { + r.redrawHint('eles', true); + } + r.redraw(); + } else { + // otherwise keep track of drag delta for later + var dragDelta = r.touchData.dragDelta = r.touchData.dragDelta || []; + if (dragDelta.length === 0) { + dragDelta.push(disp[0]); + dragDelta.push(disp[1]); + } else { + dragDelta[0] += disp[0]; + dragDelta[1] += disp[1]; + } + } + } - if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); + // touchmove + { + triggerEvents(start || near, ['touchmove', 'tapdrag', 'vmousemove'], e, { + x: now[0], + y: now[1] + }); + if ((!start || !start.grabbed()) && near != last) { + if (last) { + last.emit({ + originalEvent: e, + type: 'tapdragout', + position: { + x: now[0], + y: now[1] + } + }); + } + if (near) { + near.emit({ + originalEvent: e, + type: 'tapdragover', + position: { + x: now[0], + y: now[1] + } + }); + } + } + r.touchData.last = near; + } + + // check to cancel taphold + if (capture) { + for (var i = 0; i < now.length; i++) { + if (now[i] && r.touchData.startPosition[i] && isOverThresholdDrag) { + r.touchData.singleTouchMoved = true; + } + } + } + + // panning + if (capture && (start == null || start.pannable()) && cy.panningEnabled() && cy.userPanningEnabled()) { + var allowPassthrough = allowPanningPassthrough(start, r.touchData.starts); + if (allowPassthrough) { + e.preventDefault(); + if (!r.data.bgActivePosistion) { + r.data.bgActivePosistion = array2point(r.touchData.startPosition); + } + if (r.swipePanning) { + cy.panBy({ + x: disp[0] * zoom, + y: disp[1] * zoom + }); + cy.emit('dragpan'); + } else if (isOverThresholdDrag) { + r.swipePanning = true; + cy.panBy({ + x: dx * zoom, + y: dy * zoom + }); + cy.emit('dragpan'); + if (start) { + start.unactivate(); + r.redrawHint('select', true); + r.touchData.start = null; + } + } + } - _canvas.width = image.width; - _canvas.height = image.height; + // Re-project + var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); + now[0] = pos[0]; + now[1] = pos[1]; + } + } + for (var j = 0; j < now.length; j++) { + earlier[j] = now[j]; + } - const context = _canvas.getContext( '2d' ); + // the active bg indicator should be removed when making a swipe that is neither for dragging nodes or panning + if (capture && e.touches.length > 0 && !r.hoverData.draggingEles && !r.swipePanning && r.data.bgActivePosistion != null) { + r.data.bgActivePosistion = undefined; + r.redrawHint('select', true); + r.redraw(); + } + }, false); + var touchcancelHandler; + r.registerBinding(containerWindow, 'touchcancel', touchcancelHandler = function touchcancelHandler(e) { + // eslint-disable-line no-unused-vars + var start = r.touchData.start; + r.touchData.capture = false; + if (start) { + start.unactivate(); + } + }); + var touchendHandler, didDoubleTouch, touchTimeout, prevTouchTimeStamp; + r.registerBinding(containerWindow, 'touchend', touchendHandler = function touchendHandler(e) { + // eslint-disable-line no-unused-vars + var start = r.touchData.start; + var capture = r.touchData.capture; + if (capture) { + if (e.touches.length === 0) { + r.touchData.capture = false; + } + e.preventDefault(); + } else { + return; + } + var select = r.selection; + r.swipePanning = false; + r.hoverData.draggingEles = false; + var cy = r.cy; + var zoom = cy.zoom(); + var now = r.touchData.now; + var earlier = r.touchData.earlier; + if (e.touches[0]) { + var pos = r.projectIntoViewport(e.touches[0].clientX, e.touches[0].clientY); + now[0] = pos[0]; + now[1] = pos[1]; + } + if (e.touches[1]) { + var pos = r.projectIntoViewport(e.touches[1].clientX, e.touches[1].clientY); + now[2] = pos[0]; + now[3] = pos[1]; + } + if (e.touches[2]) { + var pos = r.projectIntoViewport(e.touches[2].clientX, e.touches[2].clientY); + now[4] = pos[0]; + now[5] = pos[1]; + } + if (start) { + start.unactivate(); + } + var ctxTapend; + if (r.touchData.cxt) { + ctxTapend = { + originalEvent: e, + type: 'cxttapend', + position: { + x: now[0], + y: now[1] + } + }; + if (start) { + start.emit(ctxTapend); + } else { + cy.emit(ctxTapend); + } + if (!r.touchData.cxtDragged) { + var ctxTap = { + originalEvent: e, + type: 'cxttap', + position: { + x: now[0], + y: now[1] + } + }; + if (start) { + start.emit(ctxTap); + } else { + cy.emit(ctxTap); + } + } + if (r.touchData.start) { + r.touchData.start._private.grabbed = false; + } + r.touchData.cxt = false; + r.touchData.start = null; + r.redraw(); + return; + } - if ( image instanceof ImageData ) { + // no more box selection if we don't have three fingers + if (!e.touches[2] && cy.boxSelectionEnabled() && r.touchData.selecting) { + r.touchData.selecting = false; + var box = cy.collection(r.getAllInBox(select[0], select[1], select[2], select[3])); + select[0] = undefined; + select[1] = undefined; + select[2] = undefined; + select[3] = undefined; + select[4] = 0; + r.redrawHint('select', true); + cy.emit({ + type: 'boxend', + originalEvent: e, + position: { + x: now[0], + y: now[1] + } + }); + var eleWouldBeSelected = function eleWouldBeSelected(ele) { + return ele.selectable() && !ele.selected(); + }; + box.emit('box').stdFilter(eleWouldBeSelected).select().emit('boxselect'); + if (box.nonempty()) { + r.redrawHint('eles', true); + } + r.redraw(); + } + if (start != null) { + start.unactivate(); + } + if (e.touches[2]) { + r.data.bgActivePosistion = undefined; + r.redrawHint('select', true); + } else if (e.touches[1]) ; else if (e.touches[0]) ; else if (!e.touches[0]) { + r.data.bgActivePosistion = undefined; + r.redrawHint('select', true); + var draggedEles = r.dragData.touchDragEles; + if (start != null) { + var startWasGrabbed = start._private.grabbed; + freeDraggedElements(draggedEles); + r.redrawHint('drag', true); + r.redrawHint('eles', true); + if (startWasGrabbed) { + start.emit('freeon'); + draggedEles.emit('free'); + if (r.dragData.didDrag) { + start.emit('dragfreeon'); + draggedEles.emit('dragfree'); + } + } + triggerEvents(start, ['touchend', 'tapend', 'vmouseup', 'tapdragout'], e, { + x: now[0], + y: now[1] + }); + start.unactivate(); + r.touchData.start = null; + } else { + var near = r.findNearestElement(now[0], now[1], true, true); + triggerEvents(near, ['touchend', 'tapend', 'vmouseup', 'tapdragout'], e, { + x: now[0], + y: now[1] + }); + } + var dx = r.touchData.startPosition[0] - now[0]; + var dx2 = dx * dx; + var dy = r.touchData.startPosition[1] - now[1]; + var dy2 = dy * dy; + var dist2 = dx2 + dy2; + var rdist2 = dist2 * zoom * zoom; + + // Tap event, roughly same as mouse click event for touch + if (!r.touchData.singleTouchMoved) { + if (!start) { + cy.$(':selected').unselect(['tapunselect']); + } + triggerEvents(start, ['tap', 'vclick'], e, { + x: now[0], + y: now[1] + }); + didDoubleTouch = false; + if (e.timeStamp - prevTouchTimeStamp <= cy.multiClickDebounceTime()) { + touchTimeout && clearTimeout(touchTimeout); + didDoubleTouch = true; + prevTouchTimeStamp = null; + triggerEvents(start, ['dbltap', 'vdblclick'], e, { + x: now[0], + y: now[1] + }); + } else { + touchTimeout = setTimeout(function () { + if (didDoubleTouch) return; + triggerEvents(start, ['onetap', 'voneclick'], e, { + x: now[0], + y: now[1] + }); + }, cy.multiClickDebounceTime()); + prevTouchTimeStamp = e.timeStamp; + } + } + + // Prepare to select the currently touched node, only if it hasn't been dragged past a certain distance + if (start != null && !r.dragData.didDrag // didn't drag nodes around + && start._private.selectable && rdist2 < r.touchTapThreshold2 && !r.pinching // pinch to zoom should not affect selection + ) { + if (cy.selectionType() === 'single') { + cy.$(isSelected).unmerge(start).unselect(['tapunselect']); + start.select(['tapselect']); + } else { + if (start.selected()) { + start.unselect(['tapunselect']); + } else { + start.select(['tapselect']); + } + } + r.redrawHint('eles', true); + } + r.touchData.singleTouchMoved = true; + } + for (var j = 0; j < now.length; j++) { + earlier[j] = now[j]; + } + r.dragData.didDrag = false; // reset for next touchstart - context.putImageData( image, 0, 0 ); + if (e.touches.length === 0) { + r.touchData.dragDelta = []; + r.touchData.startPosition = [null, null, null, null, null, null]; + r.touchData.startGPosition = null; + r.touchData.didSelect = false; + } + if (e.touches.length < 2) { + if (e.touches.length === 1) { + // the old start global pos'n may not be the same finger that remains + r.touchData.startGPosition = [e.touches[0].clientX, e.touches[0].clientY]; + } + r.pinching = false; + r.redrawHint('eles', true); + r.redraw(); + } - } else { + //r.redraw(); + }, false); + + // fallback compatibility layer for ms pointer events + if (typeof TouchEvent === 'undefined') { + var pointers = []; + var makeTouch = function makeTouch(e) { + return { + clientX: e.clientX, + clientY: e.clientY, + force: 1, + identifier: e.pointerId, + pageX: e.pageX, + pageY: e.pageY, + radiusX: e.width / 2, + radiusY: e.height / 2, + screenX: e.screenX, + screenY: e.screenY, + target: e.target + }; + }; + var makePointer = function makePointer(e) { + return { + event: e, + touch: makeTouch(e) + }; + }; + var addPointer = function addPointer(e) { + pointers.push(makePointer(e)); + }; + var removePointer = function removePointer(e) { + for (var i = 0; i < pointers.length; i++) { + var p = pointers[i]; + if (p.event.pointerId === e.pointerId) { + pointers.splice(i, 1); + return; + } + } + }; + var updatePointer = function updatePointer(e) { + var p = pointers.filter(function (p) { + return p.event.pointerId === e.pointerId; + })[0]; + p.event = e; + p.touch = makeTouch(e); + }; + var addTouchesToEvent = function addTouchesToEvent(e) { + e.touches = pointers.map(function (p) { + return p.touch; + }); + }; + var pointerIsMouse = function pointerIsMouse(e) { + return e.pointerType === 'mouse' || e.pointerType === 4; + }; + r.registerBinding(r.container, 'pointerdown', function (e) { + if (pointerIsMouse(e)) { + return; + } // mouse already handled - context.drawImage( image, 0, 0, image.width, image.height ); + e.preventDefault(); + addPointer(e); + addTouchesToEvent(e); + touchstartHandler(e); + }); + r.registerBinding(r.container, 'pointerup', function (e) { + if (pointerIsMouse(e)) { + return; + } // mouse already handled - } + removePointer(e); + addTouchesToEvent(e); + touchendHandler(e); + }); + r.registerBinding(r.container, 'pointercancel', function (e) { + if (pointerIsMouse(e)) { + return; + } // mouse already handled - canvas = _canvas; + removePointer(e); + addTouchesToEvent(e); + touchcancelHandler(e); + }); + r.registerBinding(r.container, 'pointermove', function (e) { + if (pointerIsMouse(e)) { + return; + } // mouse already handled - } + e.preventDefault(); + updatePointer(e); + addTouchesToEvent(e); + touchmoveHandler(e); + }); + } + }; - if ( canvas.width > 2048 || canvas.height > 2048 ) { + var BRp$2 = {}; + BRp$2.generatePolygon = function (name, points) { + return this.nodeShapes[name] = { + renderer: this, + name: name, + points: points, + draw: function draw(context, centerX, centerY, width, height, cornerRadius) { + this.renderer.nodeShapeImpl('polygon', context, centerX, centerY, width, height, this.points); + }, + intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding, cornerRadius) { + return polygonIntersectLine(x, y, this.points, nodeX, nodeY, width / 2, height / 2, padding); + }, + checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY, cornerRadius) { + return pointInsidePolygon(x, y, this.points, centerX, centerY, width, height, [0, -1], padding); + } + }; + }; + BRp$2.generateEllipse = function () { + return this.nodeShapes['ellipse'] = { + renderer: this, + name: 'ellipse', + draw: function draw(context, centerX, centerY, width, height, cornerRadius) { + this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height); + }, + intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding, cornerRadius) { + return intersectLineEllipse(x, y, nodeX, nodeY, width / 2 + padding, height / 2 + padding); + }, + checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY, cornerRadius) { + return checkInEllipse(x, y, width, height, centerX, centerY, padding); + } + }; + }; + BRp$2.generateRoundPolygon = function (name, points) { + return this.nodeShapes[name] = { + renderer: this, + name: name, + points: points, + getOrCreateCorners: function getOrCreateCorners(centerX, centerY, width, height, cornerRadius, rs, field) { + if (rs[field] !== undefined && rs[field + '-cx'] === centerX && rs[field + '-cy'] === centerY) { + return rs[field]; + } + rs[field] = new Array(points.length / 2); + rs[field + '-cx'] = centerX; + rs[field + '-cy'] = centerY; + var halfW = width / 2; + var halfH = height / 2; + cornerRadius = cornerRadius === 'auto' ? getRoundPolygonRadius(width, height) : cornerRadius; + var p = new Array(points.length / 2); + for (var _i = 0; _i < points.length / 2; _i++) { + p[_i] = { + x: centerX + halfW * points[_i * 2], + y: centerY + halfH * points[_i * 2 + 1] + }; + } + var i, + p1, + p2, + p3, + len = p.length; + p1 = p[len - 1]; + // for each point + for (i = 0; i < len; i++) { + p2 = p[i % len]; + p3 = p[(i + 1) % len]; + rs[field][i] = getRoundCorner(p1, p2, p3, cornerRadius); + p1 = p2; + p2 = p3; + } + return rs[field]; + }, + draw: function draw(context, centerX, centerY, width, height, cornerRadius, rs) { + this.renderer.nodeShapeImpl('round-polygon', context, centerX, centerY, width, height, this.points, this.getOrCreateCorners(centerX, centerY, width, height, cornerRadius, rs, 'drawCorners')); + }, + intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding, cornerRadius, rs) { + return roundPolygonIntersectLine(x, y, this.points, nodeX, nodeY, width, height, padding, this.getOrCreateCorners(nodeX, nodeY, width, height, cornerRadius, rs, 'corners')); + }, + checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY, cornerRadius, rs) { + return pointInsideRoundPolygon(x, y, this.points, centerX, centerY, width, height, this.getOrCreateCorners(centerX, centerY, width, height, cornerRadius, rs, 'corners')); + } + }; + }; + BRp$2.generateRoundRectangle = function () { + return this.nodeShapes['round-rectangle'] = this.nodeShapes['roundrectangle'] = { + renderer: this, + name: 'round-rectangle', + points: generateUnitNgonPointsFitToSquare(4, 0), + draw: function draw(context, centerX, centerY, width, height, cornerRadius) { + this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height, this.points, cornerRadius); + }, + intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding, cornerRadius) { + return roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding, cornerRadius); + }, + checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY, cornerRadius) { + var halfWidth = width / 2; + var halfHeight = height / 2; + cornerRadius = cornerRadius === 'auto' ? getRoundRectangleRadius(width, height) : cornerRadius; + cornerRadius = Math.min(halfWidth, halfHeight, cornerRadius); + var diam = cornerRadius * 2; + + // Check hBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - diam, [0, -1], padding)) { + return true; + } - console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); + // Check vBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - diam, height, [0, -1], padding)) { + return true; + } - return canvas.toDataURL( 'image/jpeg', 0.6 ); + // Check top left quarter circle + if (checkInEllipse(x, y, diam, diam, centerX - halfWidth + cornerRadius, centerY - halfHeight + cornerRadius, padding)) { + return true; + } - } else { + // Check top right quarter circle + if (checkInEllipse(x, y, diam, diam, centerX + halfWidth - cornerRadius, centerY - halfHeight + cornerRadius, padding)) { + return true; + } - return canvas.toDataURL( 'image/png' ); + // Check bottom right quarter circle + if (checkInEllipse(x, y, diam, diam, centerX + halfWidth - cornerRadius, centerY + halfHeight - cornerRadius, padding)) { + return true; + } - } + // Check bottom left quarter circle + if (checkInEllipse(x, y, diam, diam, centerX - halfWidth + cornerRadius, centerY + halfHeight - cornerRadius, padding)) { + return true; + } + return false; + } + }; + }; + BRp$2.generateCutRectangle = function () { + return this.nodeShapes['cut-rectangle'] = this.nodeShapes['cutrectangle'] = { + renderer: this, + name: 'cut-rectangle', + cornerLength: getCutRectangleCornerLength(), + points: generateUnitNgonPointsFitToSquare(4, 0), + draw: function draw(context, centerX, centerY, width, height, cornerRadius) { + this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height, null, cornerRadius); + }, + generateCutTrianglePts: function generateCutTrianglePts(width, height, centerX, centerY, cornerRadius) { + var cl = cornerRadius === 'auto' ? this.cornerLength : cornerRadius; + var hh = height / 2; + var hw = width / 2; + var xBegin = centerX - hw; + var xEnd = centerX + hw; + var yBegin = centerY - hh; + var yEnd = centerY + hh; + + // points are in clockwise order, inner (imaginary) triangle pt on [4, 5] + return { + topLeft: [xBegin, yBegin + cl, xBegin + cl, yBegin, xBegin + cl, yBegin + cl], + topRight: [xEnd - cl, yBegin, xEnd, yBegin + cl, xEnd - cl, yBegin + cl], + bottomRight: [xEnd, yEnd - cl, xEnd - cl, yEnd, xEnd - cl, yEnd - cl], + bottomLeft: [xBegin + cl, yEnd, xBegin, yEnd - cl, xBegin + cl, yEnd - cl] + }; + }, + intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding, cornerRadius) { + var cPts = this.generateCutTrianglePts(width + 2 * padding, height + 2 * padding, nodeX, nodeY, cornerRadius); + var pts = [].concat.apply([], [cPts.topLeft.splice(0, 4), cPts.topRight.splice(0, 4), cPts.bottomRight.splice(0, 4), cPts.bottomLeft.splice(0, 4)]); + return polygonIntersectLine(x, y, pts, nodeX, nodeY); + }, + checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY, cornerRadius) { + var cl = cornerRadius === 'auto' ? this.cornerLength : cornerRadius; + // Check hBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - 2 * cl, [0, -1], padding)) { + return true; + } - } + // Check vBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - 2 * cl, height, [0, -1], padding)) { + return true; + } + var cutTrianglePts = this.generateCutTrianglePts(width, height, centerX, centerY); + return pointInsidePolygonPoints(x, y, cutTrianglePts.topLeft) || pointInsidePolygonPoints(x, y, cutTrianglePts.topRight) || pointInsidePolygonPoints(x, y, cutTrianglePts.bottomRight) || pointInsidePolygonPoints(x, y, cutTrianglePts.bottomLeft); + } + }; + }; + BRp$2.generateBarrel = function () { + return this.nodeShapes['barrel'] = { + renderer: this, + name: 'barrel', + points: generateUnitNgonPointsFitToSquare(4, 0), + draw: function draw(context, centerX, centerY, width, height, cornerRadius) { + this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height); + }, + intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding, cornerRadius) { + // use two fixed t values for the bezier curve approximation + + var t0 = 0.15; + var t1 = 0.5; + var t2 = 0.85; + var bPts = this.generateBarrelBezierPts(width + 2 * padding, height + 2 * padding, nodeX, nodeY); + var approximateBarrelCurvePts = function approximateBarrelCurvePts(pts) { + // approximate curve pts based on the two t values + var m0 = qbezierPtAt({ + x: pts[0], + y: pts[1] + }, { + x: pts[2], + y: pts[3] + }, { + x: pts[4], + y: pts[5] + }, t0); + var m1 = qbezierPtAt({ + x: pts[0], + y: pts[1] + }, { + x: pts[2], + y: pts[3] + }, { + x: pts[4], + y: pts[5] + }, t1); + var m2 = qbezierPtAt({ + x: pts[0], + y: pts[1] + }, { + x: pts[2], + y: pts[3] + }, { + x: pts[4], + y: pts[5] + }, t2); + return [pts[0], pts[1], m0.x, m0.y, m1.x, m1.y, m2.x, m2.y, pts[4], pts[5]]; + }; + var pts = [].concat(approximateBarrelCurvePts(bPts.topLeft), approximateBarrelCurvePts(bPts.topRight), approximateBarrelCurvePts(bPts.bottomRight), approximateBarrelCurvePts(bPts.bottomLeft)); + return polygonIntersectLine(x, y, pts, nodeX, nodeY); + }, + generateBarrelBezierPts: function generateBarrelBezierPts(width, height, centerX, centerY) { + var hh = height / 2; + var hw = width / 2; + var xBegin = centerX - hw; + var xEnd = centerX + hw; + var yBegin = centerY - hh; + var yEnd = centerY + hh; + var curveConstants = getBarrelCurveConstants(width, height); + var hOffset = curveConstants.heightOffset; + var wOffset = curveConstants.widthOffset; + var ctrlPtXOffset = curveConstants.ctrlPtOffsetPct * width; + + // points are in clockwise order, inner (imaginary) control pt on [4, 5] + var pts = { + topLeft: [xBegin, yBegin + hOffset, xBegin + ctrlPtXOffset, yBegin, xBegin + wOffset, yBegin], + topRight: [xEnd - wOffset, yBegin, xEnd - ctrlPtXOffset, yBegin, xEnd, yBegin + hOffset], + bottomRight: [xEnd, yEnd - hOffset, xEnd - ctrlPtXOffset, yEnd, xEnd - wOffset, yEnd], + bottomLeft: [xBegin + wOffset, yEnd, xBegin + ctrlPtXOffset, yEnd, xBegin, yEnd - hOffset] + }; + pts.topLeft.isTop = true; + pts.topRight.isTop = true; + pts.bottomLeft.isBottom = true; + pts.bottomRight.isBottom = true; + return pts; + }, + checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY, cornerRadius) { + var curveConstants = getBarrelCurveConstants(width, height); + var hOffset = curveConstants.heightOffset; + var wOffset = curveConstants.widthOffset; + + // Check hBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - 2 * hOffset, [0, -1], padding)) { + return true; + } - static sRGBToLinear( image ) { + // Check vBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - 2 * wOffset, height, [0, -1], padding)) { + return true; + } + var barrelCurvePts = this.generateBarrelBezierPts(width, height, centerX, centerY); + var getCurveT = function getCurveT(x, y, curvePts) { + var x0 = curvePts[4]; + var x1 = curvePts[2]; + var x2 = curvePts[0]; + var y0 = curvePts[5]; + // var y1 = curvePts[ 3 ]; + var y2 = curvePts[1]; + var xMin = Math.min(x0, x2); + var xMax = Math.max(x0, x2); + var yMin = Math.min(y0, y2); + var yMax = Math.max(y0, y2); + if (xMin <= x && x <= xMax && yMin <= y && y <= yMax) { + var coeff = bezierPtsToQuadCoeff(x0, x1, x2); + var roots = solveQuadratic(coeff[0], coeff[1], coeff[2], x); + var validRoots = roots.filter(function (r) { + return 0 <= r && r <= 1; + }); + if (validRoots.length > 0) { + return validRoots[0]; + } + } + return null; + }; + var curveRegions = Object.keys(barrelCurvePts); + for (var i = 0; i < curveRegions.length; i++) { + var corner = curveRegions[i]; + var cornerPts = barrelCurvePts[corner]; + var t = getCurveT(x, y, cornerPts); + if (t == null) { + continue; + } + var y0 = cornerPts[5]; + var y1 = cornerPts[3]; + var y2 = cornerPts[1]; + var bezY = qbezierAt(y0, y1, y2, t); + if (cornerPts.isTop && bezY <= y) { + return true; + } + if (cornerPts.isBottom && y <= bezY) { + return true; + } + } + return false; + } + }; + }; + BRp$2.generateBottomRoundrectangle = function () { + return this.nodeShapes['bottom-round-rectangle'] = this.nodeShapes['bottomroundrectangle'] = { + renderer: this, + name: 'bottom-round-rectangle', + points: generateUnitNgonPointsFitToSquare(4, 0), + draw: function draw(context, centerX, centerY, width, height, cornerRadius) { + this.renderer.nodeShapeImpl(this.name, context, centerX, centerY, width, height, this.points, cornerRadius); + }, + intersectLine: function intersectLine(nodeX, nodeY, width, height, x, y, padding, cornerRadius) { + var topStartX = nodeX - (width / 2 + padding); + var topStartY = nodeY - (height / 2 + padding); + var topEndY = topStartY; + var topEndX = nodeX + (width / 2 + padding); + var topIntersections = finiteLinesIntersect(x, y, nodeX, nodeY, topStartX, topStartY, topEndX, topEndY, false); + if (topIntersections.length > 0) { + return topIntersections; + } + return roundRectangleIntersectLine(x, y, nodeX, nodeY, width, height, padding, cornerRadius); + }, + checkPoint: function checkPoint(x, y, padding, width, height, centerX, centerY, cornerRadius) { + cornerRadius = cornerRadius === 'auto' ? getRoundRectangleRadius(width, height) : cornerRadius; + var diam = 2 * cornerRadius; + + // Check hBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width, height - diam, [0, -1], padding)) { + return true; + } - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + // Check vBox + if (pointInsidePolygon(x, y, this.points, centerX, centerY, width - diam, height, [0, -1], padding)) { + return true; + } - const canvas = createElementNS( 'canvas' ); + // check non-rounded top side + var outerWidth = width / 2 + 2 * padding; + var outerHeight = height / 2 + 2 * padding; + var points = [centerX - outerWidth, centerY - outerHeight, centerX - outerWidth, centerY, centerX + outerWidth, centerY, centerX + outerWidth, centerY - outerHeight]; + if (pointInsidePolygonPoints(x, y, points)) { + return true; + } - canvas.width = image.width; - canvas.height = image.height; + // Check bottom right quarter circle + if (checkInEllipse(x, y, diam, diam, centerX + width / 2 - cornerRadius, centerY + height / 2 - cornerRadius, padding)) { + return true; + } - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height ); + // Check bottom left quarter circle + if (checkInEllipse(x, y, diam, diam, centerX - width / 2 + cornerRadius, centerY + height / 2 - cornerRadius, padding)) { + return true; + } + return false; + } + }; + }; + BRp$2.registerNodeShapes = function () { + var nodeShapes = this.nodeShapes = {}; + var renderer = this; + this.generateEllipse(); + this.generatePolygon('triangle', generateUnitNgonPointsFitToSquare(3, 0)); + this.generateRoundPolygon('round-triangle', generateUnitNgonPointsFitToSquare(3, 0)); + this.generatePolygon('rectangle', generateUnitNgonPointsFitToSquare(4, 0)); + nodeShapes['square'] = nodeShapes['rectangle']; + this.generateRoundRectangle(); + this.generateCutRectangle(); + this.generateBarrel(); + this.generateBottomRoundrectangle(); + { + var diamondPoints = [0, 1, 1, 0, 0, -1, -1, 0]; + this.generatePolygon('diamond', diamondPoints); + this.generateRoundPolygon('round-diamond', diamondPoints); + } + this.generatePolygon('pentagon', generateUnitNgonPointsFitToSquare(5, 0)); + this.generateRoundPolygon('round-pentagon', generateUnitNgonPointsFitToSquare(5, 0)); + this.generatePolygon('hexagon', generateUnitNgonPointsFitToSquare(6, 0)); + this.generateRoundPolygon('round-hexagon', generateUnitNgonPointsFitToSquare(6, 0)); + this.generatePolygon('heptagon', generateUnitNgonPointsFitToSquare(7, 0)); + this.generateRoundPolygon('round-heptagon', generateUnitNgonPointsFitToSquare(7, 0)); + this.generatePolygon('octagon', generateUnitNgonPointsFitToSquare(8, 0)); + this.generateRoundPolygon('round-octagon', generateUnitNgonPointsFitToSquare(8, 0)); + var star5Points = new Array(20); + { + var outerPoints = generateUnitNgonPoints(5, 0); + var innerPoints = generateUnitNgonPoints(5, Math.PI / 5); + + // Outer radius is 1; inner radius of star is smaller + var innerRadius = 0.5 * (3 - Math.sqrt(5)); + innerRadius *= 1.57; + for (var i = 0; i < innerPoints.length / 2; i++) { + innerPoints[i * 2] *= innerRadius; + innerPoints[i * 2 + 1] *= innerRadius; + } + for (var i = 0; i < 20 / 4; i++) { + star5Points[i * 4] = outerPoints[i * 2]; + star5Points[i * 4 + 1] = outerPoints[i * 2 + 1]; + star5Points[i * 4 + 2] = innerPoints[i * 2]; + star5Points[i * 4 + 3] = innerPoints[i * 2 + 1]; + } + } + star5Points = fitPolygonToSquare(star5Points); + this.generatePolygon('star', star5Points); + this.generatePolygon('vee', [-1, -1, 0, -0.333, 1, -1, 0, 1]); + this.generatePolygon('rhomboid', [-1, -1, 0.333, -1, 1, 1, -0.333, 1]); + this.generatePolygon('right-rhomboid', [-0.333, -1, 1, -1, 0.333, 1, -1, 1]); + this.nodeShapes['concavehexagon'] = this.generatePolygon('concave-hexagon', [-1, -0.95, -0.75, 0, -1, 0.95, 1, 0.95, 0.75, 0, 1, -0.95]); + { + var tagPoints = [-1, -1, 0.25, -1, 1, 0, 0.25, 1, -1, 1]; + this.generatePolygon('tag', tagPoints); + this.generateRoundPolygon('round-tag', tagPoints); + } + nodeShapes.makePolygon = function (points) { + // use caching on user-specified polygons so they are as fast as native shapes + + var key = points.join('$'); + var name = 'polygon-' + key; + var shape; + if (shape = this[name]) { + // got cached shape + return shape; + } - const imageData = context.getImageData( 0, 0, image.width, image.height ); - const data = imageData.data; + // create and cache new shape + return renderer.generatePolygon(name, points); + }; + }; - for ( let i = 0; i < data.length; i ++ ) { + var BRp$1 = {}; + BRp$1.timeToRender = function () { + return this.redrawTotalTime / this.redrawCount; + }; + BRp$1.redraw = function (options) { + options = options || staticEmptyObject(); + var r = this; + if (r.averageRedrawTime === undefined) { + r.averageRedrawTime = 0; + } + if (r.lastRedrawTime === undefined) { + r.lastRedrawTime = 0; + } + if (r.lastDrawTime === undefined) { + r.lastDrawTime = 0; + } + r.requestedFrame = true; + r.renderOptions = options; + }; + BRp$1.beforeRender = function (fn, priority) { + // the renderer can't add tick callbacks when destroyed + if (this.destroyed) { + return; + } + if (priority == null) { + error('Priority is not optional for beforeRender'); + } + var cbs = this.beforeRenderCallbacks; + cbs.push({ + fn: fn, + priority: priority + }); + + // higher priority callbacks executed first + cbs.sort(function (a, b) { + return b.priority - a.priority; + }); + }; + var beforeRenderCallbacks = function beforeRenderCallbacks(r, willDraw, startTime) { + var cbs = r.beforeRenderCallbacks; + for (var i = 0; i < cbs.length; i++) { + cbs[i].fn(willDraw, startTime); + } + }; + BRp$1.startRenderLoop = function () { + var r = this; + var cy = r.cy; + if (r.renderLoopStarted) { + return; + } else { + r.renderLoopStarted = true; + } + var renderFn = function renderFn(requestTime) { + if (r.destroyed) { + return; + } + if (cy.batching()) ; else if (r.requestedFrame && !r.skipFrame) { + beforeRenderCallbacks(r, true, requestTime); + var startTime = performanceNow(); + r.render(r.renderOptions); + var endTime = r.lastDrawTime = performanceNow(); + if (r.averageRedrawTime === undefined) { + r.averageRedrawTime = endTime - startTime; + } + if (r.redrawCount === undefined) { + r.redrawCount = 0; + } + r.redrawCount++; + if (r.redrawTotalTime === undefined) { + r.redrawTotalTime = 0; + } + var duration = endTime - startTime; + r.redrawTotalTime += duration; + r.lastRedrawTime = duration; + + // use a weighted average with a bias from the previous average so we don't spike so easily + r.averageRedrawTime = r.averageRedrawTime / 2 + duration / 2; + r.requestedFrame = false; + } else { + beforeRenderCallbacks(r, false, requestTime); + } + r.skipFrame = false; + requestAnimationFrame$1(renderFn); + }; + requestAnimationFrame$1(renderFn); + }; - data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; + var BaseRenderer = function BaseRenderer(options) { + this.init(options); + }; + var BR = BaseRenderer; + var BRp = BR.prototype; + BRp.clientFunctions = ['redrawHint', 'render', 'renderTo', 'matchCanvasSize', 'nodeShapeImpl', 'arrowShapeImpl']; + BRp.init = function (options) { + var r = this; + r.options = options; + r.cy = options.cy; + var ctr = r.container = options.cy.container(); + var containerWindow = r.cy.window(); + + // prepend a stylesheet in the head such that + if (containerWindow) { + var document = containerWindow.document; + var head = document.head; + var stylesheetId = '__________cytoscape_stylesheet'; + var className = '__________cytoscape_container'; + var stylesheetAlreadyExists = document.getElementById(stylesheetId) != null; + if (ctr.className.indexOf(className) < 0) { + ctr.className = (ctr.className || '') + ' ' + className; + } + if (!stylesheetAlreadyExists) { + var stylesheet = document.createElement('style'); + stylesheet.id = stylesheetId; + stylesheet.textContent = '.' + className + ' { position: relative; }'; + head.insertBefore(stylesheet, head.children[0]); // first so lowest priority + } - } + var computedStyle = containerWindow.getComputedStyle(ctr); + var position = computedStyle.getPropertyValue('position'); + if (position === 'static') { + warn('A Cytoscape container has style position:static and so can not use UI extensions properly'); + } + } + r.selection = [undefined, undefined, undefined, undefined, 0]; // Coordinates for selection box, plus enabled flag + + r.bezierProjPcts = [0.05, 0.225, 0.4, 0.5, 0.6, 0.775, 0.95]; + + //--Pointer-related data + r.hoverData = { + down: null, + last: null, + downTime: null, + triggerMode: null, + dragging: false, + initialPan: [null, null], + capture: false + }; + r.dragData = { + possibleDragElements: [] + }; + r.touchData = { + start: null, + capture: false, + // These 3 fields related to tap, taphold events + startPosition: [null, null, null, null, null, null], + singleTouchStartTime: null, + singleTouchMoved: true, + now: [null, null, null, null, null, null], + earlier: [null, null, null, null, null, null] + }; + r.redraws = 0; + r.showFps = options.showFps; + r.debug = options.debug; + r.hideEdgesOnViewport = options.hideEdgesOnViewport; + r.textureOnViewport = options.textureOnViewport; + r.wheelSensitivity = options.wheelSensitivity; + r.motionBlurEnabled = options.motionBlur; // on by default + r.forcedPixelRatio = number$1(options.pixelRatio) ? options.pixelRatio : null; + r.motionBlur = options.motionBlur; // for initial kick off + r.motionBlurOpacity = options.motionBlurOpacity; + r.motionBlurTransparency = 1 - r.motionBlurOpacity; + r.motionBlurPxRatio = 1; + r.mbPxRBlurry = 1; //0.8; + r.minMbLowQualFrames = 4; + r.fullQualityMb = false; + r.clearedForMotionBlur = []; + r.desktopTapThreshold = options.desktopTapThreshold; + r.desktopTapThreshold2 = options.desktopTapThreshold * options.desktopTapThreshold; + r.touchTapThreshold = options.touchTapThreshold; + r.touchTapThreshold2 = options.touchTapThreshold * options.touchTapThreshold; + r.tapholdDuration = 500; + r.bindings = []; + r.beforeRenderCallbacks = []; + r.beforeRenderPriorities = { + // higher priority execs before lower one + animations: 400, + eleCalcs: 300, + eleTxrDeq: 200, + lyrTxrDeq: 150, + lyrTxrSkip: 100 + }; + r.registerNodeShapes(); + r.registerArrowShapes(); + r.registerCalculationListeners(); + }; + BRp.notify = function (eventName, eles) { + var r = this; + var cy = r.cy; - context.putImageData( imageData, 0, 0 ); + // the renderer can't be notified after it's destroyed + if (this.destroyed) { + return; + } + if (eventName === 'init') { + r.load(); + return; + } + if (eventName === 'destroy') { + r.destroy(); + return; + } + if (eventName === 'add' || eventName === 'remove' || eventName === 'move' && cy.hasCompoundNodes() || eventName === 'load' || eventName === 'zorder' || eventName === 'mount') { + r.invalidateCachedZSortedEles(); + } + if (eventName === 'viewport') { + r.redrawHint('select', true); + } + if (eventName === 'load' || eventName === 'resize' || eventName === 'mount') { + r.invalidateContainerClientCoordsCache(); + r.matchCanvasSize(r.container); + } + r.redrawHint('eles', true); + r.redrawHint('drag', true); + this.startRenderLoop(); + this.redraw(); + }; + BRp.destroy = function () { + var r = this; + r.destroyed = true; + r.cy.stopAnimationLoop(); + for (var i = 0; i < r.bindings.length; i++) { + var binding = r.bindings[i]; + var b = binding; + var tgt = b.target; + (tgt.off || tgt.removeEventListener).apply(tgt, b.args); + } + r.bindings = []; + r.beforeRenderCallbacks = []; + r.onUpdateEleCalcsFns = []; + if (r.removeObserver) { + r.removeObserver.disconnect(); + } + if (r.styleObserver) { + r.styleObserver.disconnect(); + } + if (r.resizeObserver) { + r.resizeObserver.disconnect(); + } + if (r.labelCalcDiv) { + try { + document.body.removeChild(r.labelCalcDiv); // eslint-disable-line no-undef + } catch (e) { + // ie10 issue #1014 + } + } + }; + BRp.isHeadless = function () { + return false; + }; + [BRp$f, BRp$5, BRp$4, BRp$3, BRp$2, BRp$1].forEach(function (props) { + extend$1(BRp, props); + }); - return canvas; + var fullFpsTime = 1000 / 60; // assume 60 frames per second - } else if ( image.data ) { + var defs = { + setupDequeueing: function setupDequeueing(opts) { + return function setupDequeueingImpl() { + var self = this; + var r = this.renderer; + if (self.dequeueingSetup) { + return; + } else { + self.dequeueingSetup = true; + } + var queueRedraw = debounce_1(function () { + r.redrawHint('eles', true); + r.redrawHint('drag', true); + r.redraw(); + }, opts.deqRedrawThreshold); + var dequeue = function dequeue(willDraw, frameStartTime) { + var startTime = performanceNow(); + var avgRenderTime = r.averageRedrawTime; + var renderTime = r.lastRedrawTime; + var deqd = []; + var extent = r.cy.extent(); + var pixelRatio = r.getPixelRatio(); + + // if we aren't in a tick that causes a draw, then the rendered style + // queue won't automatically be flushed before dequeueing starts + if (!willDraw) { + r.flushRenderedStyleQueue(); + } + while (true) { + // eslint-disable-line no-constant-condition + var now = performanceNow(); + var duration = now - startTime; + var frameDuration = now - frameStartTime; + if (renderTime < fullFpsTime) { + // if we're rendering faster than the ideal fps, then do dequeueing + // during all of the remaining frame time + + var timeAvailable = fullFpsTime - (willDraw ? avgRenderTime : 0); + if (frameDuration >= opts.deqFastCost * timeAvailable) { + break; + } + } else { + if (willDraw) { + if (duration >= opts.deqCost * renderTime || duration >= opts.deqAvgCost * avgRenderTime) { + break; + } + } else if (frameDuration >= opts.deqNoDrawCost * fullFpsTime) { + break; + } + } + var thisDeqd = opts.deq(self, pixelRatio, extent); + if (thisDeqd.length > 0) { + for (var i = 0; i < thisDeqd.length; i++) { + deqd.push(thisDeqd[i]); + } + } else { + break; + } + } - const data = image.data.slice( 0 ); + // callbacks on dequeue + if (deqd.length > 0) { + opts.onDeqd(self, deqd); + if (!willDraw && opts.shouldRedraw(self, deqd, pixelRatio, extent)) { + queueRedraw(); + } + } + }; + var priority = opts.priority || noop$1; + r.beforeRender(dequeue, priority(self)); + }; + } + }; - for ( let i = 0; i < data.length; i ++ ) { + // Allows lookups for (ele, lvl) => cache. + // Uses keys so elements may share the same cache. + var ElementTextureCacheLookup = /*#__PURE__*/function () { + function ElementTextureCacheLookup(getKey) { + var doesEleInvalidateKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : falsify; + _classCallCheck(this, ElementTextureCacheLookup); + this.idsByKey = new Map$2(); + this.keyForId = new Map$2(); + this.cachesByLvl = new Map$2(); + this.lvls = []; + this.getKey = getKey; + this.doesEleInvalidateKey = doesEleInvalidateKey; + } + _createClass(ElementTextureCacheLookup, [{ + key: "getIdsFor", + value: function getIdsFor(key) { + if (key == null) { + error("Can not get id list for null key"); + } + var idsByKey = this.idsByKey; + var ids = this.idsByKey.get(key); + if (!ids) { + ids = new Set$1(); + idsByKey.set(key, ids); + } + return ids; + } + }, { + key: "addIdForKey", + value: function addIdForKey(key, id) { + if (key != null) { + this.getIdsFor(key).add(id); + } + } + }, { + key: "deleteIdForKey", + value: function deleteIdForKey(key, id) { + if (key != null) { + this.getIdsFor(key)["delete"](id); + } + } + }, { + key: "getNumberOfIdsForKey", + value: function getNumberOfIdsForKey(key) { + if (key == null) { + return 0; + } else { + return this.getIdsFor(key).size; + } + } + }, { + key: "updateKeyMappingFor", + value: function updateKeyMappingFor(ele) { + var id = ele.id(); + var prevKey = this.keyForId.get(id); + var currKey = this.getKey(ele); + this.deleteIdForKey(prevKey, id); + this.addIdForKey(currKey, id); + this.keyForId.set(id, currKey); + } + }, { + key: "deleteKeyMappingFor", + value: function deleteKeyMappingFor(ele) { + var id = ele.id(); + var prevKey = this.keyForId.get(id); + this.deleteIdForKey(prevKey, id); + this.keyForId["delete"](id); + } + }, { + key: "keyHasChangedFor", + value: function keyHasChangedFor(ele) { + var id = ele.id(); + var prevKey = this.keyForId.get(id); + var newKey = this.getKey(ele); + return prevKey !== newKey; + } + }, { + key: "isInvalid", + value: function isInvalid(ele) { + return this.keyHasChangedFor(ele) || this.doesEleInvalidateKey(ele); + } + }, { + key: "getCachesAt", + value: function getCachesAt(lvl) { + var cachesByLvl = this.cachesByLvl, + lvls = this.lvls; + var caches = cachesByLvl.get(lvl); + if (!caches) { + caches = new Map$2(); + cachesByLvl.set(lvl, caches); + lvls.push(lvl); + } + return caches; + } + }, { + key: "getCache", + value: function getCache(key, lvl) { + return this.getCachesAt(lvl).get(key); + } + }, { + key: "get", + value: function get(ele, lvl) { + var key = this.getKey(ele); + var cache = this.getCache(key, lvl); + + // getting for an element may need to add to the id list b/c eles can share keys + if (cache != null) { + this.updateKeyMappingFor(ele); + } + return cache; + } + }, { + key: "getForCachedKey", + value: function getForCachedKey(ele, lvl) { + var key = this.keyForId.get(ele.id()); // n.b. use cached key, not newly computed key + var cache = this.getCache(key, lvl); + return cache; + } + }, { + key: "hasCache", + value: function hasCache(key, lvl) { + return this.getCachesAt(lvl).has(key); + } + }, { + key: "has", + value: function has(ele, lvl) { + var key = this.getKey(ele); + return this.hasCache(key, lvl); + } + }, { + key: "setCache", + value: function setCache(key, lvl, cache) { + cache.key = key; + this.getCachesAt(lvl).set(key, cache); + } + }, { + key: "set", + value: function set(ele, lvl, cache) { + var key = this.getKey(ele); + this.setCache(key, lvl, cache); + this.updateKeyMappingFor(ele); + } + }, { + key: "deleteCache", + value: function deleteCache(key, lvl) { + this.getCachesAt(lvl)["delete"](key); + } + }, { + key: "delete", + value: function _delete(ele, lvl) { + var key = this.getKey(ele); + this.deleteCache(key, lvl); + } + }, { + key: "invalidateKey", + value: function invalidateKey(key) { + var _this = this; + this.lvls.forEach(function (lvl) { + return _this.deleteCache(key, lvl); + }); + } - if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { + // returns true if no other eles reference the invalidated cache (n.b. other eles may need the cache with the same key) + }, { + key: "invalidate", + value: function invalidate(ele) { + var id = ele.id(); + var key = this.keyForId.get(id); // n.b. use stored key rather than current (potential key) + + this.deleteKeyMappingFor(ele); + var entireKeyInvalidated = this.doesEleInvalidateKey(ele); + if (entireKeyInvalidated) { + // clear mapping for current key + this.invalidateKey(key); + } + return entireKeyInvalidated || this.getNumberOfIdsForKey(key) === 0; + } + }]); + return ElementTextureCacheLookup; + }(); + + var minTxrH = 25; // the size of the texture cache for small height eles (special case) + var txrStepH = 50; // the min size of the regular cache, and the size it increases with each step up + var minLvl$1 = -4; // when scaling smaller than that we don't need to re-render + var maxLvl$1 = 3; // when larger than this scale just render directly (caching is not helpful) + var maxZoom$1 = 7.99; // beyond this zoom level, layered textures are not used + var eleTxrSpacing = 8; // spacing between elements on textures to avoid blitting overlaps + var defTxrWidth = 1024; // default/minimum texture width + var maxTxrW = 1024; // the maximum width of a texture + var maxTxrH = 1024; // the maximum height of a texture + var minUtility = 0.2; // if usage of texture is less than this, it is retired + var maxFullness = 0.8; // fullness of texture after which queue removal is checked + var maxFullnessChecks = 10; // dequeued after this many checks + var deqCost$1 = 0.15; // % of add'l rendering cost allowed for dequeuing ele caches each frame + var deqAvgCost$1 = 0.1; // % of add'l rendering cost compared to average overall redraw time + var deqNoDrawCost$1 = 0.9; // % of avg frame time that can be used for dequeueing when not drawing + var deqFastCost$1 = 0.9; // % of frame time to be used when >60fps + var deqRedrawThreshold$1 = 100; // time to batch redraws together from dequeueing to allow more dequeueing calcs to happen in the meanwhile + var maxDeqSize$1 = 1; // number of eles to dequeue and render at higher texture in each batch + + var getTxrReasons = { + dequeue: 'dequeue', + downscale: 'downscale', + highQuality: 'highQuality' + }; + var initDefaults = defaults$g({ + getKey: null, + doesEleInvalidateKey: falsify, + drawElement: null, + getBoundingBox: null, + getRotationPoint: null, + getRotationOffset: null, + isVisible: trueify, + allowEdgeTxrCaching: true, + allowParentTxrCaching: true + }); + var ElementTextureCache = function ElementTextureCache(renderer, initOptions) { + var self = this; + self.renderer = renderer; + self.onDequeues = []; + var opts = initDefaults(initOptions); + extend$1(self, opts); + self.lookup = new ElementTextureCacheLookup(opts.getKey, opts.doesEleInvalidateKey); + self.setupDequeueing(); + }; + var ETCp = ElementTextureCache.prototype; + ETCp.reasons = getTxrReasons; + + // the list of textures in which new subtextures for elements can be placed + ETCp.getTextureQueue = function (txrH) { + var self = this; + self.eleImgCaches = self.eleImgCaches || {}; + return self.eleImgCaches[txrH] = self.eleImgCaches[txrH] || []; + }; - data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); + // the list of usused textures which can be recycled (in use in texture queue) + ETCp.getRetiredTextureQueue = function (txrH) { + var self = this; + var rtxtrQs = self.eleImgCaches.retired = self.eleImgCaches.retired || {}; + var rtxtrQ = rtxtrQs[txrH] = rtxtrQs[txrH] || []; + return rtxtrQ; + }; - } else { + // queue of element draw requests at different scale levels + ETCp.getElementQueue = function () { + var self = this; + var q = self.eleCacheQueue = self.eleCacheQueue || new heap(function (a, b) { + return b.reqs - a.reqs; + }); + return q; + }; - // assuming float + // queue of element draw requests at different scale levels (element id lookup) + ETCp.getElementKeyToQueue = function () { + var self = this; + var k2q = self.eleKeyToCacheQueue = self.eleKeyToCacheQueue || {}; + return k2q; + }; + ETCp.getElement = function (ele, bb, pxRatio, lvl, reason) { + var self = this; + var r = this.renderer; + var zoom = r.cy.zoom(); + var lookup = this.lookup; + if (!bb || bb.w === 0 || bb.h === 0 || isNaN(bb.w) || isNaN(bb.h) || !ele.visible() || ele.removed()) { + return null; + } + if (!self.allowEdgeTxrCaching && ele.isEdge() || !self.allowParentTxrCaching && ele.isParent()) { + return null; + } + if (lvl == null) { + lvl = Math.ceil(log2(zoom * pxRatio)); + } + if (lvl < minLvl$1) { + lvl = minLvl$1; + } else if (zoom >= maxZoom$1 || lvl > maxLvl$1) { + return null; + } + var scale = Math.pow(2, lvl); + var eleScaledH = bb.h * scale; + var eleScaledW = bb.w * scale; + var scaledLabelShown = r.eleTextBiggerThanMin(ele, scale); + if (!this.isVisible(ele, scaledLabelShown)) { + return null; + } + var eleCache = lookup.get(ele, lvl); - data[ i ] = SRGBToLinear( data[ i ] ); + // if this get was on an unused/invalidated cache, then restore the texture usage metric + if (eleCache && eleCache.invalidated) { + eleCache.invalidated = false; + eleCache.texture.invalidatedWidth -= eleCache.width; + } + if (eleCache) { + return eleCache; + } + var txrH; // which texture height this ele belongs to + + if (eleScaledH <= minTxrH) { + txrH = minTxrH; + } else if (eleScaledH <= txrStepH) { + txrH = txrStepH; + } else { + txrH = Math.ceil(eleScaledH / txrStepH) * txrStepH; + } + if (eleScaledH > maxTxrH || eleScaledW > maxTxrW) { + return null; // caching large elements is not efficient + } - } + var txrQ = self.getTextureQueue(txrH); - } + // first try the second last one in case it has space at the end + var txr = txrQ[txrQ.length - 2]; + var addNewTxr = function addNewTxr() { + return self.recycleTexture(txrH, eleScaledW) || self.addTexture(txrH, eleScaledW); + }; - return { - data: data, - width: image.width, - height: image.height - }; + // try the last one if there is no second last one + if (!txr) { + txr = txrQ[txrQ.length - 1]; + } - } else { + // if the last one doesn't exist, we need a first one + if (!txr) { + txr = addNewTxr(); + } - console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); - return image; + // if there's no room in the current texture, we need a new one + if (txr.width - txr.usedWidth < eleScaledW) { + txr = addNewTxr(); + } + var scalableFrom = function scalableFrom(otherCache) { + return otherCache && otherCache.scaledLabelShown === scaledLabelShown; + }; + var deqing = reason && reason === getTxrReasons.dequeue; + var highQualityReq = reason && reason === getTxrReasons.highQuality; + var downscaleReq = reason && reason === getTxrReasons.downscale; + var higherCache; // the nearest cache with a higher level + for (var l = lvl + 1; l <= maxLvl$1; l++) { + var c = lookup.get(ele, l); + if (c) { + higherCache = c; + break; + } + } + var oneUpCache = higherCache && higherCache.level === lvl + 1 ? higherCache : null; + var downscale = function downscale() { + txr.context.drawImage(oneUpCache.texture.canvas, oneUpCache.x, 0, oneUpCache.width, oneUpCache.height, txr.usedWidth, 0, eleScaledW, eleScaledH); + }; + + // reset ele area in texture + txr.context.setTransform(1, 0, 0, 1, 0, 0); + txr.context.clearRect(txr.usedWidth, 0, eleScaledW, txrH); + if (scalableFrom(oneUpCache)) { + // then we can relatively cheaply rescale the existing image w/o rerendering + downscale(); + } else if (scalableFrom(higherCache)) { + // then use the higher cache for now and queue the next level down + // to cheaply scale towards the smaller level + + if (highQualityReq) { + for (var _l = higherCache.level; _l > lvl; _l--) { + oneUpCache = self.getElement(ele, bb, pxRatio, _l, getTxrReasons.downscale); + } + downscale(); + } else { + self.queueElement(ele, higherCache.level - 1); + return higherCache; + } + } else { + var lowerCache; // the nearest cache with a lower level + if (!deqing && !highQualityReq && !downscaleReq) { + for (var _l2 = lvl - 1; _l2 >= minLvl$1; _l2--) { + var _c = lookup.get(ele, _l2); + if (_c) { + lowerCache = _c; + break; + } + } + } + if (scalableFrom(lowerCache)) { + // then use the lower quality cache for now and queue the better one for later - } + self.queueElement(ele, lvl); + return lowerCache; + } + txr.context.translate(txr.usedWidth, 0); + txr.context.scale(scale, scale); + this.drawElement(txr.context, ele, bb, scaledLabelShown, false); + txr.context.scale(1 / scale, 1 / scale); + txr.context.translate(-txr.usedWidth, 0); + } + eleCache = { + x: txr.usedWidth, + texture: txr, + level: lvl, + scale: scale, + width: eleScaledW, + height: eleScaledH, + scaledLabelShown: scaledLabelShown + }; + txr.usedWidth += Math.ceil(eleScaledW + eleTxrSpacing); + txr.eleCaches.push(eleCache); + lookup.set(ele, lvl, eleCache); + self.checkTextureFullness(txr); + return eleCache; + }; + ETCp.invalidateElements = function (eles) { + for (var i = 0; i < eles.length; i++) { + this.invalidateElement(eles[i]); + } + }; + ETCp.invalidateElement = function (ele) { + var self = this; + var lookup = self.lookup; + var caches = []; + var invalid = lookup.isInvalid(ele); + if (!invalid) { + return; // override the invalidation request if the element key has not changed + } - } + for (var lvl = minLvl$1; lvl <= maxLvl$1; lvl++) { + var cache = lookup.getForCachedKey(ele, lvl); + if (cache) { + caches.push(cache); + } + } + var noOtherElesUseCache = lookup.invalidate(ele); + if (noOtherElesUseCache) { + for (var i = 0; i < caches.length; i++) { + var _cache = caches[i]; + var txr = _cache.texture; - } + // remove space from the texture it belongs to + txr.invalidatedWidth += _cache.width; - class Source { + // mark the cache as invalidated + _cache.invalidated = true; - constructor( data = null ) { + // retire the texture if its utility is low + self.checkTextureUtility(txr); + } + } - this.isSource = true; + // remove from queue since the old req was for the old state + self.removeFromQueue(ele); + }; + ETCp.checkTextureUtility = function (txr) { + // invalidate all entries in the cache if the cache size is small + if (txr.invalidatedWidth >= minUtility * txr.width) { + this.retireTexture(txr); + } + }; + ETCp.checkTextureFullness = function (txr) { + // if texture has been mostly filled and passed over several times, remove + // it from the queue so we don't need to waste time looking at it to put new things + + var self = this; + var txrQ = self.getTextureQueue(txr.height); + if (txr.usedWidth / txr.width > maxFullness && txr.fullnessChecks >= maxFullnessChecks) { + removeFromArray(txrQ, txr); + } else { + txr.fullnessChecks++; + } + }; + ETCp.retireTexture = function (txr) { + var self = this; + var txrH = txr.height; + var txrQ = self.getTextureQueue(txrH); + var lookup = this.lookup; - this.uuid = generateUUID(); + // retire the texture from the active / searchable queue: - this.data = data; + removeFromArray(txrQ, txr); + txr.retired = true; - this.version = 0; + // remove the refs from the eles to the caches: - } + var eleCaches = txr.eleCaches; + for (var i = 0; i < eleCaches.length; i++) { + var eleCache = eleCaches[i]; + lookup.deleteCache(eleCache.key, eleCache.level); + } + clearArray(eleCaches); - set needsUpdate( value ) { + // add the texture to a retired queue so it can be recycled in future: - if ( value === true ) this.version ++; + var rtxtrQ = self.getRetiredTextureQueue(txrH); + rtxtrQ.push(txr); + }; + ETCp.addTexture = function (txrH, minW) { + var self = this; + var txrQ = self.getTextureQueue(txrH); + var txr = {}; + txrQ.push(txr); + txr.eleCaches = []; + txr.height = txrH; + txr.width = Math.max(defTxrWidth, minW); + txr.usedWidth = 0; + txr.invalidatedWidth = 0; + txr.fullnessChecks = 0; + txr.canvas = self.renderer.makeOffscreenCanvas(txr.width, txr.height); + txr.context = txr.canvas.getContext('2d'); + return txr; + }; + ETCp.recycleTexture = function (txrH, minW) { + var self = this; + var txrQ = self.getTextureQueue(txrH); + var rtxtrQ = self.getRetiredTextureQueue(txrH); + for (var i = 0; i < rtxtrQ.length; i++) { + var txr = rtxtrQ[i]; + if (txr.width >= minW) { + txr.retired = false; + txr.usedWidth = 0; + txr.invalidatedWidth = 0; + txr.fullnessChecks = 0; + clearArray(txr.eleCaches); + txr.context.setTransform(1, 0, 0, 1, 0, 0); + txr.context.clearRect(0, 0, txr.width, txr.height); + removeFromArray(rtxtrQ, txr); + txrQ.push(txr); + return txr; + } + } + }; + ETCp.queueElement = function (ele, lvl) { + var self = this; + var q = self.getElementQueue(); + var k2q = self.getElementKeyToQueue(); + var key = this.getKey(ele); + var existingReq = k2q[key]; + if (existingReq) { + // use the max lvl b/c in between lvls are cheap to make + existingReq.level = Math.max(existingReq.level, lvl); + existingReq.eles.merge(ele); + existingReq.reqs++; + q.updateItem(existingReq); + } else { + var req = { + eles: ele.spawn().merge(ele), + level: lvl, + reqs: 1, + key: key + }; + q.push(req); + k2q[key] = req; + } + }; + ETCp.dequeue = function (pxRatio /*, extent*/) { + var self = this; + var q = self.getElementQueue(); + var k2q = self.getElementKeyToQueue(); + var dequeued = []; + var lookup = self.lookup; + for (var i = 0; i < maxDeqSize$1; i++) { + if (q.size() > 0) { + var req = q.pop(); + var key = req.key; + var ele = req.eles[0]; // all eles have the same key + var cacheExists = lookup.hasCache(ele, req.level); + + // clear out the key to req lookup + k2q[key] = null; + + // dequeueing isn't necessary with an existing cache + if (cacheExists) { + continue; + } + dequeued.push(req); + var bb = self.getBoundingBox(ele); + self.getElement(ele, bb, pxRatio, req.level, getTxrReasons.dequeue); + } else { + break; + } + } + return dequeued; + }; + ETCp.removeFromQueue = function (ele) { + var self = this; + var q = self.getElementQueue(); + var k2q = self.getElementKeyToQueue(); + var key = this.getKey(ele); + var req = k2q[key]; + if (req != null) { + if (req.eles.length === 1) { + // remove if last ele in the req + // bring to front of queue + req.reqs = MAX_INT$1; + q.updateItem(req); + q.pop(); // remove from queue + + k2q[key] = null; // remove from lookup map + } else { + // otherwise just remove ele from req + req.eles.unmerge(ele); + } + } + }; + ETCp.onDequeue = function (fn) { + this.onDequeues.push(fn); + }; + ETCp.offDequeue = function (fn) { + removeFromArray(this.onDequeues, fn); + }; + ETCp.setupDequeueing = defs.setupDequeueing({ + deqRedrawThreshold: deqRedrawThreshold$1, + deqCost: deqCost$1, + deqAvgCost: deqAvgCost$1, + deqNoDrawCost: deqNoDrawCost$1, + deqFastCost: deqFastCost$1, + deq: function deq(self, pxRatio, extent) { + return self.dequeue(pxRatio, extent); + }, + onDeqd: function onDeqd(self, deqd) { + for (var i = 0; i < self.onDequeues.length; i++) { + var fn = self.onDequeues[i]; + fn(deqd); + } + }, + shouldRedraw: function shouldRedraw(self, deqd, pxRatio, extent) { + for (var i = 0; i < deqd.length; i++) { + var eles = deqd[i].eles; + for (var j = 0; j < eles.length; j++) { + var bb = eles[j].boundingBox(); + if (boundingBoxesIntersect(bb, extent)) { + return true; + } + } + } + return false; + }, + priority: function priority(self) { + return self.renderer.beforeRenderPriorities.eleTxrDeq; + } + }); - } + var defNumLayers = 1; // default number of layers to use + var minLvl = -4; // when scaling smaller than that we don't need to re-render + var maxLvl = 2; // when larger than this scale just render directly (caching is not helpful) + var maxZoom = 3.99; // beyond this zoom level, layered textures are not used + var deqRedrawThreshold = 50; // time to batch redraws together from dequeueing to allow more dequeueing calcs to happen in the meanwhile + var refineEleDebounceTime = 50; // time to debounce sharper ele texture updates + var deqCost = 0.15; // % of add'l rendering cost allowed for dequeuing ele caches each frame + var deqAvgCost = 0.1; // % of add'l rendering cost compared to average overall redraw time + var deqNoDrawCost = 0.9; // % of avg frame time that can be used for dequeueing when not drawing + var deqFastCost = 0.9; // % of frame time to be used when >60fps + var maxDeqSize = 1; // number of eles to dequeue and render at higher texture in each batch + var invalidThreshold = 250; // time threshold for disabling b/c of invalidations + var maxLayerArea = 4000 * 4000; // layers can't be bigger than this + var useHighQualityEleTxrReqs = true; // whether to use high quality ele txr requests (generally faster and cheaper in the longterm) + + // var log = function(){ console.log.apply( console, arguments ); }; + + var LayeredTextureCache = function LayeredTextureCache(renderer) { + var self = this; + var r = self.renderer = renderer; + var cy = r.cy; + self.layersByLevel = {}; // e.g. 2 => [ layer1, layer2, ..., layerN ] + + self.firstGet = true; + self.lastInvalidationTime = performanceNow() - 2 * invalidThreshold; + self.skipping = false; + self.eleTxrDeqs = cy.collection(); + self.scheduleElementRefinement = debounce_1(function () { + self.refineElementTextures(self.eleTxrDeqs); + self.eleTxrDeqs.unmerge(self.eleTxrDeqs); + }, refineEleDebounceTime); + r.beforeRender(function (willDraw, now) { + if (now - self.lastInvalidationTime <= invalidThreshold) { + self.skipping = true; + } else { + self.skipping = false; + } + }, r.beforeRenderPriorities.lyrTxrSkip); + var qSort = function qSort(a, b) { + return b.reqs - a.reqs; + }; + self.layersQueue = new heap(qSort); + self.setupDequeueing(); + }; + var LTCp = LayeredTextureCache.prototype; + var layerIdPool = 0; + var MAX_INT = Math.pow(2, 53) - 1; + LTCp.makeLayer = function (bb, lvl) { + var scale = Math.pow(2, lvl); + var w = Math.ceil(bb.w * scale); + var h = Math.ceil(bb.h * scale); + var canvas = this.renderer.makeOffscreenCanvas(w, h); + var layer = { + id: layerIdPool = ++layerIdPool % MAX_INT, + bb: bb, + level: lvl, + width: w, + height: h, + canvas: canvas, + context: canvas.getContext('2d'), + eles: [], + elesQueue: [], + reqs: 0 + }; + + // log('make layer %s with w %s and h %s and lvl %s', layer.id, layer.width, layer.height, layer.level); + + var cxt = layer.context; + var dx = -layer.bb.x1; + var dy = -layer.bb.y1; + + // do the transform on creation to save cycles (it's the same for all eles) + cxt.scale(scale, scale); + cxt.translate(dx, dy); + return layer; + }; + LTCp.getLayers = function (eles, pxRatio, lvl) { + var self = this; + var r = self.renderer; + var cy = r.cy; + var zoom = cy.zoom(); + var firstGet = self.firstGet; + self.firstGet = false; + + // log('--\nget layers with %s eles', eles.length); + //log eles.map(function(ele){ return ele.id() }) ); + + if (lvl == null) { + lvl = Math.ceil(log2(zoom * pxRatio)); + if (lvl < minLvl) { + lvl = minLvl; + } else if (zoom >= maxZoom || lvl > maxLvl) { + return null; + } + } + self.validateLayersElesOrdering(lvl, eles); + var layersByLvl = self.layersByLevel; + var scale = Math.pow(2, lvl); + var layers = layersByLvl[lvl] = layersByLvl[lvl] || []; + var bb; + var lvlComplete = self.levelIsComplete(lvl, eles); + var tmpLayers; + var checkTempLevels = function checkTempLevels() { + var canUseAsTmpLvl = function canUseAsTmpLvl(l) { + self.validateLayersElesOrdering(l, eles); + if (self.levelIsComplete(l, eles)) { + tmpLayers = layersByLvl[l]; + return true; + } + }; + var checkLvls = function checkLvls(dir) { + if (tmpLayers) { + return; + } + for (var l = lvl + dir; minLvl <= l && l <= maxLvl; l += dir) { + if (canUseAsTmpLvl(l)) { + break; + } + } + }; + checkLvls(+1); + checkLvls(-1); + + // remove the invalid layers; they will be replaced as needed later in this function + for (var i = layers.length - 1; i >= 0; i--) { + var layer = layers[i]; + if (layer.invalid) { + removeFromArray(layers, layer); + } + } + }; + if (!lvlComplete) { + // if the current level is incomplete, then use the closest, best quality layerset temporarily + // and later queue the current layerset so we can get the proper quality level soon + + checkTempLevels(); + } else { + // log('level complete, using existing layers\n--'); + return layers; + } + var getBb = function getBb() { + if (!bb) { + bb = makeBoundingBox(); + for (var i = 0; i < eles.length; i++) { + updateBoundingBox(bb, eles[i].boundingBox()); + } + } + return bb; + }; + var makeLayer = function makeLayer(opts) { + opts = opts || {}; + var after = opts.after; + getBb(); + var area = bb.w * scale * (bb.h * scale); + if (area > maxLayerArea) { + return null; + } + var layer = self.makeLayer(bb, lvl); + if (after != null) { + var index = layers.indexOf(after) + 1; + layers.splice(index, 0, layer); + } else if (opts.insert === undefined || opts.insert) { + // no after specified => first layer made so put at start + layers.unshift(layer); + } - toJSON( meta ) { + // if( tmpLayers ){ + //self.queueLayer( layer ); + // } - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + return layer; + }; + if (self.skipping && !firstGet) { + // log('skip layers'); + return null; + } - if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { + // log('do layers'); - return meta.images[ this.uuid ]; + var layer = null; + var maxElesPerLayer = eles.length / defNumLayers; + var allowLazyQueueing = !firstGet; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + var rs = ele._private.rscratch; + var caches = rs.imgLayerCaches = rs.imgLayerCaches || {}; - } + // log('look at ele', ele.id()); - const output = { - uuid: this.uuid, - url: '' - }; + var existingLayer = caches[lvl]; + if (existingLayer) { + // reuse layer for later eles + // log('reuse layer for', ele.id()); + layer = existingLayer; + continue; + } + if (!layer || layer.eles.length >= maxElesPerLayer || !boundingBoxInBoundingBox(layer.bb, ele.boundingBox())) { + // log('make new layer for ele %s', ele.id()); - const data = this.data; + layer = makeLayer({ + insert: true, + after: layer + }); - if ( data !== null ) { + // if now layer can be built then we can't use layers at this level + if (!layer) { + return null; + } - let url; + // log('new layer with id %s', layer.id); + } - if ( Array.isArray( data ) ) { + if (tmpLayers || allowLazyQueueing) { + // log('queue ele %s in layer %s', ele.id(), layer.id); + self.queueLayer(layer, ele); + } else { + // log('draw ele %s in layer %s', ele.id(), layer.id); + self.drawEleInLayer(layer, ele, lvl, pxRatio); + } + layer.eles.push(ele); + caches[lvl] = layer; + } - // cube texture + // log('--'); - url = []; + if (tmpLayers) { + // then we only queued the current layerset and can't draw it yet + return tmpLayers; + } + if (allowLazyQueueing) { + // log('lazy queue level', lvl); + return null; + } + return layers; + }; - for ( let i = 0, l = data.length; i < l; i ++ ) { + // a layer may want to use an ele cache of a higher level to avoid blurriness + // so the layer level might not equal the ele level + LTCp.getEleLevelForLayerLevel = function (lvl, pxRatio) { + return lvl; + }; + LTCp.drawEleInLayer = function (layer, ele, lvl, pxRatio) { + var self = this; + var r = this.renderer; + var context = layer.context; + var bb = ele.boundingBox(); + if (bb.w === 0 || bb.h === 0 || !ele.visible()) { + return; + } + lvl = self.getEleLevelForLayerLevel(lvl, pxRatio); + { + r.setImgSmoothing(context, false); + } + { + r.drawCachedElement(context, ele, null, null, lvl, useHighQualityEleTxrReqs); + } + { + r.setImgSmoothing(context, true); + } + }; + LTCp.levelIsComplete = function (lvl, eles) { + var self = this; + var layers = self.layersByLevel[lvl]; + if (!layers || layers.length === 0) { + return false; + } + var numElesInLayers = 0; + for (var i = 0; i < layers.length; i++) { + var layer = layers[i]; - if ( data[ i ].isDataTexture ) { + // if there are any eles needed to be drawn yet, the level is not complete + if (layer.reqs > 0) { + return false; + } - url.push( serializeImage( data[ i ].image ) ); + // if the layer is invalid, the level is not complete + if (layer.invalid) { + return false; + } + numElesInLayers += layer.eles.length; + } - } else { + // we should have exactly the number of eles passed in to be complete + if (numElesInLayers !== eles.length) { + return false; + } + return true; + }; + LTCp.validateLayersElesOrdering = function (lvl, eles) { + var layers = this.layersByLevel[lvl]; + if (!layers) { + return; + } - url.push( serializeImage( data[ i ] ) ); + // if in a layer the eles are not in the same order, then the layer is invalid + // (i.e. there is an ele in between the eles in the layer) - } + for (var i = 0; i < layers.length; i++) { + var layer = layers[i]; + var offset = -1; - } + // find the offset + for (var j = 0; j < eles.length; j++) { + if (layer.eles[0] === eles[j]) { + offset = j; + break; + } + } + if (offset < 0) { + // then the layer has nonexistent elements and is invalid + this.invalidateLayer(layer); + continue; + } - } else { + // the eles in the layer must be in the same continuous order, else the layer is invalid - // texture + var o = offset; + for (var j = 0; j < layer.eles.length; j++) { + if (layer.eles[j] !== eles[o + j]) { + // log('invalidate based on ordering', layer.id); - url = serializeImage( data ); + this.invalidateLayer(layer); + break; + } + } + } + }; + LTCp.updateElementsInLayers = function (eles, update) { + var self = this; + var isEles = element(eles[0]); + + // collect udpated elements (cascaded from the layers) and update each + // layer itself along the way + for (var i = 0; i < eles.length; i++) { + var req = isEles ? null : eles[i]; + var ele = isEles ? eles[i] : eles[i].ele; + var rs = ele._private.rscratch; + var caches = rs.imgLayerCaches = rs.imgLayerCaches || {}; + for (var l = minLvl; l <= maxLvl; l++) { + var layer = caches[l]; + if (!layer) { + continue; + } + + // if update is a request from the ele cache, then it affects only + // the matching level + if (req && self.getEleLevelForLayerLevel(layer.level) !== req.level) { + continue; + } + update(layer, ele, req); + } + } + }; + LTCp.haveLayers = function () { + var self = this; + var haveLayers = false; + for (var l = minLvl; l <= maxLvl; l++) { + var layers = self.layersByLevel[l]; + if (layers && layers.length > 0) { + haveLayers = true; + break; + } + } + return haveLayers; + }; + LTCp.invalidateElements = function (eles) { + var self = this; + if (eles.length === 0) { + return; + } + self.lastInvalidationTime = performanceNow(); - } + // log('update invalidate layer time from eles'); - output.url = url; + if (eles.length === 0 || !self.haveLayers()) { + return; + } + self.updateElementsInLayers(eles, function invalAssocLayers(layer, ele, req) { + self.invalidateLayer(layer); + }); + }; + LTCp.invalidateLayer = function (layer) { + // log('update invalidate layer time'); - } + this.lastInvalidationTime = performanceNow(); + if (layer.invalid) { + return; + } // save cycles - if ( ! isRootObject ) { + var lvl = layer.level; + var eles = layer.eles; + var layers = this.layersByLevel[lvl]; - meta.images[ this.uuid ] = output; + // log('invalidate layer', layer.id ); - } + removeFromArray(layers, layer); + // layer.eles = []; - return output; + layer.elesQueue = []; + layer.invalid = true; + if (layer.replacement) { + layer.replacement.invalid = true; + } + for (var i = 0; i < eles.length; i++) { + var caches = eles[i]._private.rscratch.imgLayerCaches; + if (caches) { + caches[lvl] = null; + } + } + }; + LTCp.refineElementTextures = function (eles) { + var self = this; - } + // log('refine', eles.length); - } + self.updateElementsInLayers(eles, function refineEachEle(layer, ele, req) { + var rLyr = layer.replacement; + if (!rLyr) { + rLyr = layer.replacement = self.makeLayer(layer.bb, layer.level); + rLyr.replaces = layer; + rLyr.eles = layer.eles; - function serializeImage( image ) { + // log('make replacement layer %s for %s with level %s', rLyr.id, layer.id, rLyr.level); + } - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + if (!rLyr.reqs) { + for (var i = 0; i < rLyr.eles.length; i++) { + self.queueLayer(rLyr, rLyr.eles[i]); + } - // default images + // log('queue replacement layer refinement', rLyr.id); + } + }); + }; - return ImageUtils.getDataURL( image ); + LTCp.enqueueElementRefinement = function (ele) { + this.eleTxrDeqs.merge(ele); + this.scheduleElementRefinement(); + }; + LTCp.queueLayer = function (layer, ele) { + var self = this; + var q = self.layersQueue; + var elesQ = layer.elesQueue; + var hasId = elesQ.hasId = elesQ.hasId || {}; + + // if a layer is going to be replaced, queuing is a waste of time + if (layer.replacement) { + return; + } + if (ele) { + if (hasId[ele.id()]) { + return; + } + elesQ.push(ele); + hasId[ele.id()] = true; + } + if (layer.reqs) { + layer.reqs++; + q.updateItem(layer); + } else { + layer.reqs = 1; + q.push(layer); + } + }; + LTCp.dequeue = function (pxRatio) { + var self = this; + var q = self.layersQueue; + var deqd = []; + var eleDeqs = 0; + while (eleDeqs < maxDeqSize) { + if (q.size() === 0) { + break; + } + var layer = q.peek(); - } else { + // if a layer has been or will be replaced, then don't waste time with it + if (layer.replacement) { + // log('layer %s in queue skipped b/c it already has a replacement', layer.id); + q.pop(); + continue; + } - if ( image.data ) { + // if this is a replacement layer that has been superceded, then forget it + if (layer.replaces && layer !== layer.replaces.replacement) { + // log('layer is no longer the most uptodate replacement; dequeued', layer.id) + q.pop(); + continue; + } + if (layer.invalid) { + // log('replacement layer %s is invalid; dequeued', layer.id); + q.pop(); + continue; + } + var ele = layer.elesQueue.shift(); + if (ele) { + // log('dequeue layer %s', layer.id); - // images of DataTexture + self.drawEleInLayer(layer, ele, layer.level, pxRatio); + eleDeqs++; + } + if (deqd.length === 0) { + // we need only one entry in deqd to queue redrawing etc + deqd.push(true); + } - return { - data: Array.from( image.data ), - width: image.width, - height: image.height, - type: image.data.constructor.name - }; + // if the layer has all its eles done, then remove from the queue + if (layer.elesQueue.length === 0) { + q.pop(); + layer.reqs = 0; - } else { + // log('dequeue of layer %s complete', layer.id); - console.warn( 'THREE.Texture: Unable to serialize Texture.' ); - return {}; + // when a replacement layer is dequeued, it replaces the old layer in the level + if (layer.replaces) { + self.applyLayerReplacement(layer); + } + self.requestRedraw(); + } + } + return deqd; + }; + LTCp.applyLayerReplacement = function (layer) { + var self = this; + var layersInLevel = self.layersByLevel[layer.level]; + var replaced = layer.replaces; + var index = layersInLevel.indexOf(replaced); + + // if the replaced layer is not in the active list for the level, then replacing + // refs would be a mistake (i.e. overwriting the true active layer) + if (index < 0 || replaced.invalid) { + // log('replacement layer would have no effect', layer.id); + return; + } + layersInLevel[index] = layer; // replace level ref + + // replace refs in eles + for (var i = 0; i < layer.eles.length; i++) { + var _p = layer.eles[i]._private; + var cache = _p.imgLayerCaches = _p.imgLayerCaches || {}; + if (cache) { + cache[layer.level] = layer; + } + } - } + // log('apply replacement layer %s over %s', layer.id, replaced.id); - } + self.requestRedraw(); + }; + LTCp.requestRedraw = debounce_1(function () { + var r = this.renderer; + r.redrawHint('eles', true); + r.redrawHint('drag', true); + r.redraw(); + }, 100); + LTCp.setupDequeueing = defs.setupDequeueing({ + deqRedrawThreshold: deqRedrawThreshold, + deqCost: deqCost, + deqAvgCost: deqAvgCost, + deqNoDrawCost: deqNoDrawCost, + deqFastCost: deqFastCost, + deq: function deq(self, pxRatio) { + return self.dequeue(pxRatio); + }, + onDeqd: noop$1, + shouldRedraw: trueify, + priority: function priority(self) { + return self.renderer.beforeRenderPriorities.lyrTxrDeq; + } + }); + var CRp$a = {}; + var impl; + function polygon(context, points) { + for (var i = 0; i < points.length; i++) { + var pt = points[i]; + context.lineTo(pt.x, pt.y); + } } + function triangleBackcurve(context, points, controlPoint) { + var firstPt; + for (var i = 0; i < points.length; i++) { + var pt = points[i]; + if (i === 0) { + firstPt = pt; + } + context.lineTo(pt.x, pt.y); + } + context.quadraticCurveTo(controlPoint.x, controlPoint.y, firstPt.x, firstPt.y); + } + function triangleTee(context, trianglePoints, teePoints) { + if (context.beginPath) { + context.beginPath(); + } + var triPts = trianglePoints; + for (var i = 0; i < triPts.length; i++) { + var pt = triPts[i]; + context.lineTo(pt.x, pt.y); + } + var teePts = teePoints; + var firstTeePt = teePoints[0]; + context.moveTo(firstTeePt.x, firstTeePt.y); + for (var i = 1; i < teePts.length; i++) { + var pt = teePts[i]; + context.lineTo(pt.x, pt.y); + } + if (context.closePath) { + context.closePath(); + } + } + function circleTriangle(context, trianglePoints, rx, ry, r) { + if (context.beginPath) { + context.beginPath(); + } + context.arc(rx, ry, r, 0, Math.PI * 2, false); + var triPts = trianglePoints; + var firstTrPt = triPts[0]; + context.moveTo(firstTrPt.x, firstTrPt.y); + for (var i = 0; i < triPts.length; i++) { + var pt = triPts[i]; + context.lineTo(pt.x, pt.y); + } + if (context.closePath) { + context.closePath(); + } + } + function circle(context, rx, ry, r) { + context.arc(rx, ry, r, 0, Math.PI * 2, false); + } + CRp$a.arrowShapeImpl = function (name) { + return (impl || (impl = { + 'polygon': polygon, + 'triangle-backcurve': triangleBackcurve, + 'triangle-tee': triangleTee, + 'circle-triangle': circleTriangle, + 'triangle-cross': triangleTee, + 'circle': circle + }))[name]; + }; - let textureId = 0; - - class Texture extends EventDispatcher { - - constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding ) { - - super(); - - this.isTexture = true; + var CRp$9 = {}; + CRp$9.drawElement = function (context, ele, shiftToOriginWithBb, showLabel, showOverlay, showOpacity) { + var r = this; + if (ele.isNode()) { + r.drawNode(context, ele, shiftToOriginWithBb, showLabel, showOverlay, showOpacity); + } else { + r.drawEdge(context, ele, shiftToOriginWithBb, showLabel, showOverlay, showOpacity); + } + }; + CRp$9.drawElementOverlay = function (context, ele) { + var r = this; + if (ele.isNode()) { + r.drawNodeOverlay(context, ele); + } else { + r.drawEdgeOverlay(context, ele); + } + }; + CRp$9.drawElementUnderlay = function (context, ele) { + var r = this; + if (ele.isNode()) { + r.drawNodeUnderlay(context, ele); + } else { + r.drawEdgeUnderlay(context, ele); + } + }; + CRp$9.drawCachedElementPortion = function (context, ele, eleTxrCache, pxRatio, lvl, reason, getRotation, getOpacity) { + var r = this; + var bb = eleTxrCache.getBoundingBox(ele); + if (bb.w === 0 || bb.h === 0) { + return; + } // ignore zero size case + + var eleCache = eleTxrCache.getElement(ele, bb, pxRatio, lvl, reason); + if (eleCache != null) { + var opacity = getOpacity(r, ele); + if (opacity === 0) { + return; + } + var theta = getRotation(r, ele); + var x1 = bb.x1, + y1 = bb.y1, + w = bb.w, + h = bb.h; + var x, y, sx, sy, smooth; + if (theta !== 0) { + var rotPt = eleTxrCache.getRotationPoint(ele); + sx = rotPt.x; + sy = rotPt.y; + context.translate(sx, sy); + context.rotate(theta); + smooth = r.getImgSmoothing(context); + if (!smooth) { + r.setImgSmoothing(context, true); + } + var off = eleTxrCache.getRotationOffset(ele); + x = off.x; + y = off.y; + } else { + x = x1; + y = y1; + } + var oldGlobalAlpha; + if (opacity !== 1) { + oldGlobalAlpha = context.globalAlpha; + context.globalAlpha = oldGlobalAlpha * opacity; + } + context.drawImage(eleCache.texture.canvas, eleCache.x, 0, eleCache.width, eleCache.height, x, y, w, h); + if (opacity !== 1) { + context.globalAlpha = oldGlobalAlpha; + } + if (theta !== 0) { + context.rotate(-theta); + context.translate(-sx, -sy); + if (!smooth) { + r.setImgSmoothing(context, false); + } + } + } else { + eleTxrCache.drawElement(context, ele); // direct draw fallback + } + }; - Object.defineProperty( this, 'id', { value: textureId ++ } ); + var getZeroRotation = function getZeroRotation() { + return 0; + }; + var getLabelRotation = function getLabelRotation(r, ele) { + return r.getTextAngle(ele, null); + }; + var getSourceLabelRotation = function getSourceLabelRotation(r, ele) { + return r.getTextAngle(ele, 'source'); + }; + var getTargetLabelRotation = function getTargetLabelRotation(r, ele) { + return r.getTextAngle(ele, 'target'); + }; + var getOpacity = function getOpacity(r, ele) { + return ele.effectiveOpacity(); + }; + var getTextOpacity = function getTextOpacity(e, ele) { + return ele.pstyle('text-opacity').pfValue * ele.effectiveOpacity(); + }; + CRp$9.drawCachedElement = function (context, ele, pxRatio, extent, lvl, requestHighQuality) { + var r = this; + var _r$data = r.data, + eleTxrCache = _r$data.eleTxrCache, + lblTxrCache = _r$data.lblTxrCache, + slbTxrCache = _r$data.slbTxrCache, + tlbTxrCache = _r$data.tlbTxrCache; + var bb = ele.boundingBox(); + var reason = requestHighQuality === true ? eleTxrCache.reasons.highQuality : null; + if (bb.w === 0 || bb.h === 0 || !ele.visible()) { + return; + } + if (!extent || boundingBoxesIntersect(bb, extent)) { + var isEdge = ele.isEdge(); + var badLine = ele.element()._private.rscratch.badLine; + r.drawElementUnderlay(context, ele); + r.drawCachedElementPortion(context, ele, eleTxrCache, pxRatio, lvl, reason, getZeroRotation, getOpacity); + if (!isEdge || !badLine) { + r.drawCachedElementPortion(context, ele, lblTxrCache, pxRatio, lvl, reason, getLabelRotation, getTextOpacity); + } + if (isEdge && !badLine) { + r.drawCachedElementPortion(context, ele, slbTxrCache, pxRatio, lvl, reason, getSourceLabelRotation, getTextOpacity); + r.drawCachedElementPortion(context, ele, tlbTxrCache, pxRatio, lvl, reason, getTargetLabelRotation, getTextOpacity); + } + r.drawElementOverlay(context, ele); + } + }; + CRp$9.drawElements = function (context, eles) { + var r = this; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + r.drawElement(context, ele); + } + }; + CRp$9.drawCachedElements = function (context, eles, pxRatio, extent) { + var r = this; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + r.drawCachedElement(context, ele, pxRatio, extent); + } + }; + CRp$9.drawCachedNodes = function (context, eles, pxRatio, extent) { + var r = this; + for (var i = 0; i < eles.length; i++) { + var ele = eles[i]; + if (!ele.isNode()) { + continue; + } + r.drawCachedElement(context, ele, pxRatio, extent); + } + }; + CRp$9.drawLayeredElements = function (context, eles, pxRatio, extent) { + var r = this; + var layers = r.data.lyrTxrCache.getLayers(eles, pxRatio); + if (layers) { + for (var i = 0; i < layers.length; i++) { + var layer = layers[i]; + var bb = layer.bb; + if (bb.w === 0 || bb.h === 0) { + continue; + } + context.drawImage(layer.canvas, bb.x1, bb.y1, bb.w, bb.h); + } + } else { + // fall back on plain caching if no layers + r.drawCachedElements(context, eles, pxRatio, extent); + } + }; - this.uuid = generateUUID(); + var CRp$8 = {}; + CRp$8.drawEdge = function (context, edge, shiftToOriginWithBb) { + var drawLabel = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; + var shouldDrawOverlay = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; + var shouldDrawOpacity = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; + var r = this; + var rs = edge._private.rscratch; + if (shouldDrawOpacity && !edge.visible()) { + return; + } - this.name = ''; + // if bezier ctrl pts can not be calculated, then die + if (rs.badLine || rs.allpts == null || isNaN(rs.allpts[0])) { + // isNaN in case edge is impossible and browser bugs (e.g. safari) + return; + } + var bb; + if (shiftToOriginWithBb) { + bb = shiftToOriginWithBb; + context.translate(-bb.x1, -bb.y1); + } + var opacity = shouldDrawOpacity ? edge.pstyle('opacity').value : 1; + var lineOpacity = shouldDrawOpacity ? edge.pstyle('line-opacity').value : 1; + var curveStyle = edge.pstyle('curve-style').value; + var lineStyle = edge.pstyle('line-style').value; + var edgeWidth = edge.pstyle('width').pfValue; + var lineCap = edge.pstyle('line-cap').value; + var effectiveLineOpacity = opacity * lineOpacity; + // separate arrow opacity would require arrow-opacity property + var effectiveArrowOpacity = opacity * lineOpacity; + var drawLine = function drawLine() { + var strokeOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : effectiveLineOpacity; + if (curveStyle === 'straight-triangle') { + r.eleStrokeStyle(context, edge, strokeOpacity); + r.drawEdgeTrianglePath(edge, context, rs.allpts); + } else { + context.lineWidth = edgeWidth; + context.lineCap = lineCap; + r.eleStrokeStyle(context, edge, strokeOpacity); + r.drawEdgePath(edge, context, rs.allpts, lineStyle); + context.lineCap = 'butt'; // reset for other drawing functions + } + }; - this.source = new Source( image ); - this.mipmaps = []; - - this.mapping = mapping; + var drawOverlay = function drawOverlay() { + if (!shouldDrawOverlay) { + return; + } + r.drawEdgeOverlay(context, edge); + }; + var drawUnderlay = function drawUnderlay() { + if (!shouldDrawOverlay) { + return; + } + r.drawEdgeUnderlay(context, edge); + }; + var drawArrows = function drawArrows() { + var arrowOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : effectiveArrowOpacity; + r.drawArrowheads(context, edge, arrowOpacity); + }; + var drawText = function drawText() { + r.drawElementText(context, edge, null, drawLabel); + }; + context.lineJoin = 'round'; + var ghost = edge.pstyle('ghost').value === 'yes'; + if (ghost) { + var gx = edge.pstyle('ghost-offset-x').pfValue; + var gy = edge.pstyle('ghost-offset-y').pfValue; + var ghostOpacity = edge.pstyle('ghost-opacity').value; + var effectiveGhostOpacity = effectiveLineOpacity * ghostOpacity; + context.translate(gx, gy); + drawLine(effectiveGhostOpacity); + drawArrows(effectiveGhostOpacity); + context.translate(-gx, -gy); + } + drawUnderlay(); + drawLine(); + drawArrows(); + drawOverlay(); + drawText(); + if (shiftToOriginWithBb) { + context.translate(bb.x1, bb.y1); + } + }; + var drawEdgeOverlayUnderlay = function drawEdgeOverlayUnderlay(overlayOrUnderlay) { + if (!['overlay', 'underlay'].includes(overlayOrUnderlay)) { + throw new Error('Invalid state'); + } + return function (context, edge) { + if (!edge.visible()) { + return; + } + var opacity = edge.pstyle("".concat(overlayOrUnderlay, "-opacity")).value; + if (opacity === 0) { + return; + } + var r = this; + var usePaths = r.usePaths(); + var rs = edge._private.rscratch; + var padding = edge.pstyle("".concat(overlayOrUnderlay, "-padding")).pfValue; + var width = 2 * padding; + var color = edge.pstyle("".concat(overlayOrUnderlay, "-color")).value; + context.lineWidth = width; + if (rs.edgeType === 'self' && !usePaths) { + context.lineCap = 'butt'; + } else { + context.lineCap = 'round'; + } + r.colorStrokeStyle(context, color[0], color[1], color[2], opacity); + r.drawEdgePath(edge, context, rs.allpts, 'solid'); + }; + }; + CRp$8.drawEdgeOverlay = drawEdgeOverlayUnderlay('overlay'); + CRp$8.drawEdgeUnderlay = drawEdgeOverlayUnderlay('underlay'); + CRp$8.drawEdgePath = function (edge, context, pts, type) { + var rs = edge._private.rscratch; + var canvasCxt = context; + var path; + var pathCacheHit = false; + var usePaths = this.usePaths(); + var lineDashPattern = edge.pstyle('line-dash-pattern').pfValue; + var lineDashOffset = edge.pstyle('line-dash-offset').pfValue; + if (usePaths) { + var pathCacheKey = pts.join('$'); + var keyMatches = rs.pathCacheKey && rs.pathCacheKey === pathCacheKey; + if (keyMatches) { + path = context = rs.pathCache; + pathCacheHit = true; + } else { + path = context = new Path2D(); + rs.pathCacheKey = pathCacheKey; + rs.pathCache = path; + } + } + if (canvasCxt.setLineDash) { + // for very outofdate browsers + switch (type) { + case 'dotted': + canvasCxt.setLineDash([1, 1]); + break; + case 'dashed': + canvasCxt.setLineDash(lineDashPattern); + canvasCxt.lineDashOffset = lineDashOffset; + break; + case 'solid': + canvasCxt.setLineDash([]); + break; + } + } + if (!pathCacheHit && !rs.badLine) { + if (context.beginPath) { + context.beginPath(); + } + context.moveTo(pts[0], pts[1]); + switch (rs.edgeType) { + case 'bezier': + case 'self': + case 'compound': + case 'multibezier': + for (var i = 2; i + 3 < pts.length; i += 4) { + context.quadraticCurveTo(pts[i], pts[i + 1], pts[i + 2], pts[i + 3]); + } + break; + case 'straight': + case 'haystack': + for (var _i = 2; _i + 1 < pts.length; _i += 2) { + context.lineTo(pts[_i], pts[_i + 1]); + } + break; + case 'segments': + if (rs.isRound) { + var _iterator = _createForOfIteratorHelper(rs.roundCorners), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var corner = _step.value; + drawPreparedRoundCorner(context, corner); + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + context.lineTo(pts[pts.length - 2], pts[pts.length - 1]); + } else { + for (var _i2 = 2; _i2 + 1 < pts.length; _i2 += 2) { + context.lineTo(pts[_i2], pts[_i2 + 1]); + } + } + break; + } + } + context = canvasCxt; + if (usePaths) { + context.stroke(path); + } else { + context.stroke(); + } - this.wrapS = wrapS; - this.wrapT = wrapT; + // reset any line dashes + if (context.setLineDash) { + // for very outofdate browsers + context.setLineDash([]); + } + }; + CRp$8.drawEdgeTrianglePath = function (edge, context, pts) { + // use line stroke style for triangle fill style + context.fillStyle = context.strokeStyle; + var edgeWidth = edge.pstyle('width').pfValue; + for (var i = 0; i + 1 < pts.length; i += 2) { + var vector = [pts[i + 2] - pts[i], pts[i + 3] - pts[i + 1]]; + var length = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]); + var normal = [vector[1] / length, -vector[0] / length]; + var triangleHead = [normal[0] * edgeWidth / 2, normal[1] * edgeWidth / 2]; + context.beginPath(); + context.moveTo(pts[i] - triangleHead[0], pts[i + 1] - triangleHead[1]); + context.lineTo(pts[i] + triangleHead[0], pts[i + 1] + triangleHead[1]); + context.lineTo(pts[i + 2], pts[i + 3]); + context.closePath(); + context.fill(); + } + }; + CRp$8.drawArrowheads = function (context, edge, opacity) { + var rs = edge._private.rscratch; + var isHaystack = rs.edgeType === 'haystack'; + if (!isHaystack) { + this.drawArrowhead(context, edge, 'source', rs.arrowStartX, rs.arrowStartY, rs.srcArrowAngle, opacity); + } + this.drawArrowhead(context, edge, 'mid-target', rs.midX, rs.midY, rs.midtgtArrowAngle, opacity); + this.drawArrowhead(context, edge, 'mid-source', rs.midX, rs.midY, rs.midsrcArrowAngle, opacity); + if (!isHaystack) { + this.drawArrowhead(context, edge, 'target', rs.arrowEndX, rs.arrowEndY, rs.tgtArrowAngle, opacity); + } + }; + CRp$8.drawArrowhead = function (context, edge, prefix, x, y, angle, opacity) { + if (isNaN(x) || x == null || isNaN(y) || y == null || isNaN(angle) || angle == null) { + return; + } + var self = this; + var arrowShape = edge.pstyle(prefix + '-arrow-shape').value; + if (arrowShape === 'none') { + return; + } + var arrowClearFill = edge.pstyle(prefix + '-arrow-fill').value === 'hollow' ? 'both' : 'filled'; + var arrowFill = edge.pstyle(prefix + '-arrow-fill').value; + var edgeWidth = edge.pstyle('width').pfValue; + var pArrowWidth = edge.pstyle(prefix + '-arrow-width'); + var arrowWidth = pArrowWidth.value === 'match-line' ? edgeWidth : pArrowWidth.pfValue; + if (pArrowWidth.units === '%') arrowWidth *= edgeWidth; + var edgeOpacity = edge.pstyle('opacity').value; + if (opacity === undefined) { + opacity = edgeOpacity; + } + var gco = context.globalCompositeOperation; + if (opacity !== 1 || arrowFill === 'hollow') { + // then extra clear is needed + context.globalCompositeOperation = 'destination-out'; + self.colorFillStyle(context, 255, 255, 255, 1); + self.colorStrokeStyle(context, 255, 255, 255, 1); + self.drawArrowShape(edge, context, arrowClearFill, edgeWidth, arrowShape, arrowWidth, x, y, angle); + context.globalCompositeOperation = gco; + } // otherwise, the opaque arrow clears it for free :) + + var color = edge.pstyle(prefix + '-arrow-color').value; + self.colorFillStyle(context, color[0], color[1], color[2], opacity); + self.colorStrokeStyle(context, color[0], color[1], color[2], opacity); + self.drawArrowShape(edge, context, arrowFill, edgeWidth, arrowShape, arrowWidth, x, y, angle); + }; + CRp$8.drawArrowShape = function (edge, context, fill, edgeWidth, shape, shapeWidth, x, y, angle) { + var r = this; + var usePaths = this.usePaths() && shape !== 'triangle-cross'; + var pathCacheHit = false; + var path; + var canvasContext = context; + var translation = { + x: x, + y: y + }; + var scale = edge.pstyle('arrow-scale').value; + var size = this.getArrowWidth(edgeWidth, scale); + var shapeImpl = r.arrowShapes[shape]; + if (usePaths) { + var cache = r.arrowPathCache = r.arrowPathCache || []; + var key = hashString(shape); + var cachedPath = cache[key]; + if (cachedPath != null) { + path = context = cachedPath; + pathCacheHit = true; + } else { + path = context = new Path2D(); + cache[key] = path; + } + } + if (!pathCacheHit) { + if (context.beginPath) { + context.beginPath(); + } + if (usePaths) { + // store in the path cache with values easily manipulated later + shapeImpl.draw(context, 1, 0, { + x: 0, + y: 0 + }, 1); + } else { + shapeImpl.draw(context, size, angle, translation, edgeWidth); + } + if (context.closePath) { + context.closePath(); + } + } + context = canvasContext; + if (usePaths) { + // set transform to arrow position/orientation + context.translate(x, y); + context.rotate(angle); + context.scale(size, size); + } + if (fill === 'filled' || fill === 'both') { + if (usePaths) { + context.fill(path); + } else { + context.fill(); + } + } + if (fill === 'hollow' || fill === 'both') { + context.lineWidth = shapeWidth / (usePaths ? size : 1); + context.lineJoin = 'miter'; + if (usePaths) { + context.stroke(path); + } else { + context.stroke(); + } + } + if (usePaths) { + // reset transform by applying inverse + context.scale(1 / size, 1 / size); + context.rotate(-angle); + context.translate(-x, -y); + } + }; - this.magFilter = magFilter; - this.minFilter = minFilter; + var CRp$7 = {}; + CRp$7.safeDrawImage = function (context, img, ix, iy, iw, ih, x, y, w, h) { + // detect problematic cases for old browsers with bad images (cheaper than try-catch) + if (iw <= 0 || ih <= 0 || w <= 0 || h <= 0) { + return; + } + try { + context.drawImage(img, ix, iy, iw, ih, x, y, w, h); + } catch (e) { + warn(e); + } + }; + CRp$7.drawInscribedImage = function (context, img, node, index, nodeOpacity) { + var r = this; + var pos = node.position(); + var nodeX = pos.x; + var nodeY = pos.y; + var styleObj = node.cy().style(); + var getIndexedStyle = styleObj.getIndexedStyle.bind(styleObj); + var fit = getIndexedStyle(node, 'background-fit', 'value', index); + var repeat = getIndexedStyle(node, 'background-repeat', 'value', index); + var nodeW = node.width(); + var nodeH = node.height(); + var paddingX2 = node.padding() * 2; + var nodeTW = nodeW + (getIndexedStyle(node, 'background-width-relative-to', 'value', index) === 'inner' ? 0 : paddingX2); + var nodeTH = nodeH + (getIndexedStyle(node, 'background-height-relative-to', 'value', index) === 'inner' ? 0 : paddingX2); + var rs = node._private.rscratch; + var clip = getIndexedStyle(node, 'background-clip', 'value', index); + var shouldClip = clip === 'node'; + var imgOpacity = getIndexedStyle(node, 'background-image-opacity', 'value', index) * nodeOpacity; + var smooth = getIndexedStyle(node, 'background-image-smoothing', 'value', index); + var cornerRadius = node.pstyle('corner-radius').value; + if (cornerRadius !== 'auto') cornerRadius = node.pstyle('corner-radius').pfValue; + var imgW = img.width || img.cachedW; + var imgH = img.height || img.cachedH; + + // workaround for broken browsers like ie + if (null == imgW || null == imgH) { + document.body.appendChild(img); // eslint-disable-line no-undef + + imgW = img.cachedW = img.width || img.offsetWidth; + imgH = img.cachedH = img.height || img.offsetHeight; + document.body.removeChild(img); // eslint-disable-line no-undef + } - this.anisotropy = anisotropy; + var w = imgW; + var h = imgH; + if (getIndexedStyle(node, 'background-width', 'value', index) !== 'auto') { + if (getIndexedStyle(node, 'background-width', 'units', index) === '%') { + w = getIndexedStyle(node, 'background-width', 'pfValue', index) * nodeTW; + } else { + w = getIndexedStyle(node, 'background-width', 'pfValue', index); + } + } + if (getIndexedStyle(node, 'background-height', 'value', index) !== 'auto') { + if (getIndexedStyle(node, 'background-height', 'units', index) === '%') { + h = getIndexedStyle(node, 'background-height', 'pfValue', index) * nodeTH; + } else { + h = getIndexedStyle(node, 'background-height', 'pfValue', index); + } + } + if (w === 0 || h === 0) { + return; // no point in drawing empty image (and chrome is broken in this case) + } - this.format = format; - this.internalFormat = null; - this.type = type; + if (fit === 'contain') { + var scale = Math.min(nodeTW / w, nodeTH / h); + w *= scale; + h *= scale; + } else if (fit === 'cover') { + var scale = Math.max(nodeTW / w, nodeTH / h); + w *= scale; + h *= scale; + } + var x = nodeX - nodeTW / 2; // left + var posXUnits = getIndexedStyle(node, 'background-position-x', 'units', index); + var posXPfVal = getIndexedStyle(node, 'background-position-x', 'pfValue', index); + if (posXUnits === '%') { + x += (nodeTW - w) * posXPfVal; + } else { + x += posXPfVal; + } + var offXUnits = getIndexedStyle(node, 'background-offset-x', 'units', index); + var offXPfVal = getIndexedStyle(node, 'background-offset-x', 'pfValue', index); + if (offXUnits === '%') { + x += (nodeTW - w) * offXPfVal; + } else { + x += offXPfVal; + } + var y = nodeY - nodeTH / 2; // top + var posYUnits = getIndexedStyle(node, 'background-position-y', 'units', index); + var posYPfVal = getIndexedStyle(node, 'background-position-y', 'pfValue', index); + if (posYUnits === '%') { + y += (nodeTH - h) * posYPfVal; + } else { + y += posYPfVal; + } + var offYUnits = getIndexedStyle(node, 'background-offset-y', 'units', index); + var offYPfVal = getIndexedStyle(node, 'background-offset-y', 'pfValue', index); + if (offYUnits === '%') { + y += (nodeTH - h) * offYPfVal; + } else { + y += offYPfVal; + } + if (rs.pathCache) { + x -= nodeX; + y -= nodeY; + nodeX = 0; + nodeY = 0; + } + var gAlpha = context.globalAlpha; + context.globalAlpha = imgOpacity; + var smoothingEnabled = r.getImgSmoothing(context); + var isSmoothingSwitched = false; + if (smooth === 'no' && smoothingEnabled) { + r.setImgSmoothing(context, false); + isSmoothingSwitched = true; + } else if (smooth === 'yes' && !smoothingEnabled) { + r.setImgSmoothing(context, true); + isSmoothingSwitched = true; + } + if (repeat === 'no-repeat') { + if (shouldClip) { + context.save(); + if (rs.pathCache) { + context.clip(rs.pathCache); + } else { + r.nodeShapes[r.getNodeShape(node)].draw(context, nodeX, nodeY, nodeTW, nodeTH, cornerRadius, rs); + context.clip(); + } + } + r.safeDrawImage(context, img, 0, 0, imgW, imgH, x, y, w, h); + if (shouldClip) { + context.restore(); + } + } else { + var pattern = context.createPattern(img, repeat); + context.fillStyle = pattern; + r.nodeShapes[r.getNodeShape(node)].draw(context, nodeX, nodeY, nodeTW, nodeTH, cornerRadius, rs); + context.translate(x, y); + context.fill(); + context.translate(-x, -y); + } + context.globalAlpha = gAlpha; + if (isSmoothingSwitched) { + r.setImgSmoothing(context, smoothingEnabled); + } + }; - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; + var CRp$6 = {}; + CRp$6.eleTextBiggerThanMin = function (ele, scale) { + if (!scale) { + var zoom = ele.cy().zoom(); + var pxRatio = this.getPixelRatio(); + var lvl = Math.ceil(log2(zoom * pxRatio)); // the effective texture level - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); + scale = Math.pow(2, lvl); + } + var computedSize = ele.pstyle('font-size').pfValue * scale; + var minSize = ele.pstyle('min-zoomed-font-size').pfValue; + if (computedSize < minSize) { + return false; + } + return true; + }; + CRp$6.drawElementText = function (context, ele, shiftToOriginWithBb, force, prefix) { + var useEleOpacity = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; + var r = this; + if (force == null) { + if (useEleOpacity && !r.eleTextBiggerThanMin(ele)) { + return; + } + } else if (force === false) { + return; + } + if (ele.isNode()) { + var label = ele.pstyle('label'); + if (!label || !label.value) { + return; + } + var justification = r.getLabelJustification(ele); + context.textAlign = justification; + context.textBaseline = 'bottom'; + } else { + var badLine = ele.element()._private.rscratch.badLine; + var _label = ele.pstyle('label'); + var srcLabel = ele.pstyle('source-label'); + var tgtLabel = ele.pstyle('target-label'); + if (badLine || (!_label || !_label.value) && (!srcLabel || !srcLabel.value) && (!tgtLabel || !tgtLabel.value)) { + return; + } + context.textAlign = 'center'; + context.textBaseline = 'bottom'; + } + var applyRotation = !shiftToOriginWithBb; + var bb; + if (shiftToOriginWithBb) { + bb = shiftToOriginWithBb; + context.translate(-bb.x1, -bb.y1); + } + if (prefix == null) { + r.drawText(context, ele, null, applyRotation, useEleOpacity); + if (ele.isEdge()) { + r.drawText(context, ele, 'source', applyRotation, useEleOpacity); + r.drawText(context, ele, 'target', applyRotation, useEleOpacity); + } + } else { + r.drawText(context, ele, prefix, applyRotation, useEleOpacity); + } + if (shiftToOriginWithBb) { + context.translate(bb.x1, bb.y1); + } + }; + CRp$6.getFontCache = function (context) { + var cache; + this.fontCaches = this.fontCaches || []; + for (var i = 0; i < this.fontCaches.length; i++) { + cache = this.fontCaches[i]; + if (cache.context === context) { + return cache; + } + } + cache = { + context: context + }; + this.fontCaches.push(cache); + return cache; + }; - this.generateMipmaps = true; - this.premultiplyAlpha = false; - this.flipY = true; - this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) + // set up canvas context with font + // returns transformed text string + CRp$6.setupTextStyle = function (context, ele) { + var useEleOpacity = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + // Font style + var labelStyle = ele.pstyle('font-style').strValue; + var labelSize = ele.pstyle('font-size').pfValue + 'px'; + var labelFamily = ele.pstyle('font-family').strValue; + var labelWeight = ele.pstyle('font-weight').strValue; + var opacity = useEleOpacity ? ele.effectiveOpacity() * ele.pstyle('text-opacity').value : 1; + var outlineOpacity = ele.pstyle('text-outline-opacity').value * opacity; + var color = ele.pstyle('color').value; + var outlineColor = ele.pstyle('text-outline-color').value; + context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily; + context.lineJoin = 'round'; // so text outlines aren't jagged + + this.colorFillStyle(context, color[0], color[1], color[2], opacity); + this.colorStrokeStyle(context, outlineColor[0], outlineColor[1], outlineColor[2], outlineOpacity); + }; - // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. - // - // Also changing the encoding after already used by a Material will not automatically make the Material - // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. - this.encoding = encoding; + // TODO ensure re-used + function roundRect(ctx, x, y, width, height) { + var radius = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 5; + var stroke = arguments.length > 6 ? arguments[6] : undefined; + ctx.beginPath(); + ctx.moveTo(x + radius, y); + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + if (stroke) ctx.stroke();else ctx.fill(); + } + CRp$6.getTextAngle = function (ele, prefix) { + var theta; + var _p = ele._private; + var rscratch = _p.rscratch; + var pdash = prefix ? prefix + '-' : ''; + var rotation = ele.pstyle(pdash + 'text-rotation'); + var textAngle = getPrefixedProperty(rscratch, 'labelAngle', prefix); + if (rotation.strValue === 'autorotate') { + theta = ele.isEdge() ? textAngle : 0; + } else if (rotation.strValue === 'none') { + theta = 0; + } else { + theta = rotation.pfValue; + } + return theta; + }; + CRp$6.drawText = function (context, ele, prefix) { + var applyRotation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; + var useEleOpacity = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; + var _p = ele._private; + var rscratch = _p.rscratch; + var parentOpacity = useEleOpacity ? ele.effectiveOpacity() : 1; + if (useEleOpacity && (parentOpacity === 0 || ele.pstyle('text-opacity').value === 0)) { + return; + } - this.userData = {}; + // use 'main' as an alias for the main label (i.e. null prefix) + if (prefix === 'main') { + prefix = null; + } + var textX = getPrefixedProperty(rscratch, 'labelX', prefix); + var textY = getPrefixedProperty(rscratch, 'labelY', prefix); + var orgTextX, orgTextY; // used for rotation + var text = this.getLabelText(ele, prefix); + if (text != null && text !== '' && !isNaN(textX) && !isNaN(textY)) { + this.setupTextStyle(context, ele, useEleOpacity); + var pdash = prefix ? prefix + '-' : ''; + var textW = getPrefixedProperty(rscratch, 'labelWidth', prefix); + var textH = getPrefixedProperty(rscratch, 'labelHeight', prefix); + var marginX = ele.pstyle(pdash + 'text-margin-x').pfValue; + var marginY = ele.pstyle(pdash + 'text-margin-y').pfValue; + var isEdge = ele.isEdge(); + var halign = ele.pstyle('text-halign').value; + var valign = ele.pstyle('text-valign').value; + if (isEdge) { + halign = 'center'; + valign = 'center'; + } + textX += marginX; + textY += marginY; + var theta; + if (!applyRotation) { + theta = 0; + } else { + theta = this.getTextAngle(ele, prefix); + } + if (theta !== 0) { + orgTextX = textX; + orgTextY = textY; + context.translate(orgTextX, orgTextY); + context.rotate(theta); + textX = 0; + textY = 0; + } + switch (valign) { + case 'top': + break; + case 'center': + textY += textH / 2; + break; + case 'bottom': + textY += textH; + break; + } + var backgroundOpacity = ele.pstyle('text-background-opacity').value; + var borderOpacity = ele.pstyle('text-border-opacity').value; + var textBorderWidth = ele.pstyle('text-border-width').pfValue; + var backgroundPadding = ele.pstyle('text-background-padding').pfValue; + var styleShape = ele.pstyle('text-background-shape').strValue; + var rounded = styleShape.indexOf('round') === 0; + var roundRadius = 2; + if (backgroundOpacity > 0 || textBorderWidth > 0 && borderOpacity > 0) { + var bgX = textX - backgroundPadding; + switch (halign) { + case 'left': + bgX -= textW; + break; + case 'center': + bgX -= textW / 2; + break; + } + var bgY = textY - textH - backgroundPadding; + var bgW = textW + 2 * backgroundPadding; + var bgH = textH + 2 * backgroundPadding; + if (backgroundOpacity > 0) { + var textFill = context.fillStyle; + var textBackgroundColor = ele.pstyle('text-background-color').value; + context.fillStyle = 'rgba(' + textBackgroundColor[0] + ',' + textBackgroundColor[1] + ',' + textBackgroundColor[2] + ',' + backgroundOpacity * parentOpacity + ')'; + if (rounded) { + roundRect(context, bgX, bgY, bgW, bgH, roundRadius); + } else { + context.fillRect(bgX, bgY, bgW, bgH); + } + context.fillStyle = textFill; + } + if (textBorderWidth > 0 && borderOpacity > 0) { + var textStroke = context.strokeStyle; + var textLineWidth = context.lineWidth; + var textBorderColor = ele.pstyle('text-border-color').value; + var textBorderStyle = ele.pstyle('text-border-style').value; + context.strokeStyle = 'rgba(' + textBorderColor[0] + ',' + textBorderColor[1] + ',' + textBorderColor[2] + ',' + borderOpacity * parentOpacity + ')'; + context.lineWidth = textBorderWidth; + if (context.setLineDash) { + // for very outofdate browsers + switch (textBorderStyle) { + case 'dotted': + context.setLineDash([1, 1]); + break; + case 'dashed': + context.setLineDash([4, 2]); + break; + case 'double': + context.lineWidth = textBorderWidth / 4; // 50% reserved for white between the two borders + context.setLineDash([]); + break; + case 'solid': + context.setLineDash([]); + break; + } + } + if (rounded) { + roundRect(context, bgX, bgY, bgW, bgH, roundRadius, 'stroke'); + } else { + context.strokeRect(bgX, bgY, bgW, bgH); + } + if (textBorderStyle === 'double') { + var whiteWidth = textBorderWidth / 2; + if (rounded) { + roundRect(context, bgX + whiteWidth, bgY + whiteWidth, bgW - whiteWidth * 2, bgH - whiteWidth * 2, roundRadius, 'stroke'); + } else { + context.strokeRect(bgX + whiteWidth, bgY + whiteWidth, bgW - whiteWidth * 2, bgH - whiteWidth * 2); + } + } + if (context.setLineDash) { + // for very outofdate browsers + context.setLineDash([]); + } + context.lineWidth = textLineWidth; + context.strokeStyle = textStroke; + } + } + var lineWidth = 2 * ele.pstyle('text-outline-width').pfValue; // *2 b/c the stroke is drawn centred on the middle - this.version = 0; - this.onUpdate = null; + if (lineWidth > 0) { + context.lineWidth = lineWidth; + } + if (ele.pstyle('text-wrap').value === 'wrap') { + var lines = getPrefixedProperty(rscratch, 'labelWrapCachedLines', prefix); + var lineHeight = getPrefixedProperty(rscratch, 'labelLineHeight', prefix); + var halfTextW = textW / 2; + var justification = this.getLabelJustification(ele); + if (justification === 'auto') ; else if (halign === 'left') { + // auto justification : right + if (justification === 'left') { + textX += -textW; + } else if (justification === 'center') { + textX += -halfTextW; + } // else same as auto + } else if (halign === 'center') { + // auto justfication : center + if (justification === 'left') { + textX += -halfTextW; + } else if (justification === 'right') { + textX += halfTextW; + } // else same as auto + } else if (halign === 'right') { + // auto justification : left + if (justification === 'center') { + textX += halfTextW; + } else if (justification === 'right') { + textX += textW; + } // else same as auto + } + + switch (valign) { + case 'top': + textY -= (lines.length - 1) * lineHeight; + break; + case 'center': + case 'bottom': + textY -= (lines.length - 1) * lineHeight; + break; + } + for (var l = 0; l < lines.length; l++) { + if (lineWidth > 0) { + context.strokeText(lines[l], textX, textY); + } + context.fillText(lines[l], textX, textY); + textY += lineHeight; + } + } else { + if (lineWidth > 0) { + context.strokeText(text, textX, textY); + } + context.fillText(text, textX, textY); + } + if (theta !== 0) { + context.rotate(-theta); + context.translate(-orgTextX, -orgTextY); + } + } + }; - this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not - this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) + /* global Path2D */ + var CRp$5 = {}; + CRp$5.drawNode = function (context, node, shiftToOriginWithBb) { + var drawLabel = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true; + var shouldDrawOverlay = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; + var shouldDrawOpacity = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; + var r = this; + var nodeWidth, nodeHeight; + var _p = node._private; + var rs = _p.rscratch; + var pos = node.position(); + if (!number$1(pos.x) || !number$1(pos.y)) { + return; // can't draw node with undefined position + } - } + if (shouldDrawOpacity && !node.visible()) { + return; + } + var eleOpacity = shouldDrawOpacity ? node.effectiveOpacity() : 1; + var usePaths = r.usePaths(); + var path; + var pathCacheHit = false; + var padding = node.padding(); + nodeWidth = node.width() + 2 * padding; + nodeHeight = node.height() + 2 * padding; + + // + // setup shift + + var bb; + if (shiftToOriginWithBb) { + bb = shiftToOriginWithBb; + context.translate(-bb.x1, -bb.y1); + } - get image() { + // + // load bg image + + var bgImgProp = node.pstyle('background-image'); + var urls = bgImgProp.value; + var urlDefined = new Array(urls.length); + var image = new Array(urls.length); + var numImages = 0; + for (var i = 0; i < urls.length; i++) { + var url = urls[i]; + var defd = urlDefined[i] = url != null && url !== 'none'; + if (defd) { + var bgImgCrossOrigin = node.cy().style().getIndexedStyle(node, 'background-image-crossorigin', 'value', i); + numImages++; + + // get image, and if not loaded then ask to redraw when later loaded + image[i] = r.getCachedImage(url, bgImgCrossOrigin, function () { + _p.backgroundTimestamp = Date.now(); + node.emitAndNotify('background'); + }); + } + } - return this.source.data; + // + // setup styles + + var darkness = node.pstyle('background-blacken').value; + var borderWidth = node.pstyle('border-width').pfValue; + var bgOpacity = node.pstyle('background-opacity').value * eleOpacity; + var borderColor = node.pstyle('border-color').value; + var borderStyle = node.pstyle('border-style').value; + var borderJoin = node.pstyle('border-join').value; + var borderCap = node.pstyle('border-cap').value; + var borderPosition = node.pstyle('border-position').value; + var borderPattern = node.pstyle('border-dash-pattern').pfValue; + var borderOffset = node.pstyle('border-dash-offset').pfValue; + var borderOpacity = node.pstyle('border-opacity').value * eleOpacity; + var outlineWidth = node.pstyle('outline-width').pfValue; + var outlineColor = node.pstyle('outline-color').value; + var outlineStyle = node.pstyle('outline-style').value; + var outlineOpacity = node.pstyle('outline-opacity').value * eleOpacity; + var outlineOffset = node.pstyle('outline-offset').value; + var cornerRadius = node.pstyle('corner-radius').value; + if (cornerRadius !== 'auto') cornerRadius = node.pstyle('corner-radius').pfValue; + var setupShapeColor = function setupShapeColor() { + var bgOpy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : bgOpacity; + r.eleFillStyle(context, node, bgOpy); + }; + var setupBorderColor = function setupBorderColor() { + var bdrOpy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : borderOpacity; + r.colorStrokeStyle(context, borderColor[0], borderColor[1], borderColor[2], bdrOpy); + }; + var setupOutlineColor = function setupOutlineColor() { + var otlnOpy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : outlineOpacity; + r.colorStrokeStyle(context, outlineColor[0], outlineColor[1], outlineColor[2], otlnOpy); + }; + + // + // setup shape + + var getPath = function getPath(width, height, shape, points) { + var pathCache = r.nodePathCache = r.nodePathCache || []; + var key = hashStrings(shape === 'polygon' ? shape + ',' + points.join(',') : shape, '' + height, '' + width, '' + cornerRadius); + var cachedPath = pathCache[key]; + var path; + var cacheHit = false; + if (cachedPath != null) { + path = cachedPath; + cacheHit = true; + rs.pathCache = path; + } else { + path = new Path2D(); + pathCache[key] = rs.pathCache = path; + } + return { + path: path, + cacheHit: cacheHit + }; + }; + var styleShape = node.pstyle('shape').strValue; + var shapePts = node.pstyle('shape-polygon-points').pfValue; + if (usePaths) { + context.translate(pos.x, pos.y); + var shapePath = getPath(nodeWidth, nodeHeight, styleShape, shapePts); + path = shapePath.path; + pathCacheHit = shapePath.cacheHit; + } + var drawShape = function drawShape() { + if (!pathCacheHit) { + var npos = pos; + if (usePaths) { + npos = { + x: 0, + y: 0 + }; + } + r.nodeShapes[r.getNodeShape(node)].draw(path || context, npos.x, npos.y, nodeWidth, nodeHeight, cornerRadius, rs); + } + if (usePaths) { + context.fill(path); + } else { + context.fill(); + } + }; + var drawImages = function drawImages() { + var nodeOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : eleOpacity; + var inside = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var prevBging = _p.backgrounding; + var totalCompleted = 0; + for (var _i = 0; _i < image.length; _i++) { + var bgContainment = node.cy().style().getIndexedStyle(node, 'background-image-containment', 'value', _i); + if (inside && bgContainment === 'over' || !inside && bgContainment === 'inside') { + totalCompleted++; + continue; + } + if (urlDefined[_i] && image[_i].complete && !image[_i].error) { + totalCompleted++; + r.drawInscribedImage(context, image[_i], node, _i, nodeOpacity); + } + } + _p.backgrounding = !(totalCompleted === numImages); + if (prevBging !== _p.backgrounding) { + // update style b/c :backgrounding state changed + node.updateStyle(false); + } + }; + var drawPie = function drawPie() { + var redrawShape = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var pieOpacity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : eleOpacity; + if (r.hasPie(node)) { + r.drawPie(context, node, pieOpacity); + + // redraw/restore path if steps after pie need it + if (redrawShape) { + if (!usePaths) { + r.nodeShapes[r.getNodeShape(node)].draw(context, pos.x, pos.y, nodeWidth, nodeHeight, cornerRadius, rs); + } + } + } + }; + var darken = function darken() { + var darkenOpacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : eleOpacity; + var opacity = (darkness > 0 ? darkness : -darkness) * darkenOpacity; + var c = darkness > 0 ? 0 : 255; + if (darkness !== 0) { + r.colorFillStyle(context, c, c, c, opacity); + if (usePaths) { + context.fill(path); + } else { + context.fill(); + } + } + }; + var drawBorder = function drawBorder() { + if (borderWidth > 0) { + context.lineWidth = borderWidth; + context.lineCap = borderCap; + context.lineJoin = borderJoin; + if (context.setLineDash) { + // for very outofdate browsers + switch (borderStyle) { + case 'dotted': + context.setLineDash([1, 1]); + break; + case 'dashed': + context.setLineDash(borderPattern); + context.lineDashOffset = borderOffset; + break; + case 'solid': + case 'double': + context.setLineDash([]); + break; + } + } + if (borderPosition !== 'center') { + context.save(); + context.lineWidth *= 2; + if (borderPosition === 'inside') { + usePaths ? context.clip(path) : context.clip(); + } else { + var region = new Path2D(); + region.rect(-nodeWidth / 2 - borderWidth, -nodeHeight / 2 - borderWidth, nodeWidth + 2 * borderWidth, nodeHeight + 2 * borderWidth); + region.addPath(path); + context.clip(region, 'evenodd'); + } + usePaths ? context.stroke(path) : context.stroke(); + context.restore(); + } else { + usePaths ? context.stroke(path) : context.stroke(); + } + if (borderStyle === 'double') { + context.lineWidth = borderWidth / 3; + var gco = context.globalCompositeOperation; + context.globalCompositeOperation = 'destination-out'; + if (usePaths) { + context.stroke(path); + } else { + context.stroke(); + } + context.globalCompositeOperation = gco; + } + + // reset in case we changed the border style + if (context.setLineDash) { + // for very outofdate browsers + context.setLineDash([]); + } + } + }; + var drawOutline = function drawOutline() { + if (outlineWidth > 0) { + context.lineWidth = outlineWidth; + context.lineCap = 'butt'; + if (context.setLineDash) { + // for very outofdate browsers + switch (outlineStyle) { + case 'dotted': + context.setLineDash([1, 1]); + break; + case 'dashed': + context.setLineDash([4, 2]); + break; + case 'solid': + case 'double': + context.setLineDash([]); + break; + } + } + var npos = pos; + if (usePaths) { + npos = { + x: 0, + y: 0 + }; + } + var shape = r.getNodeShape(node); + var bWidth = borderWidth; + if (borderPosition === 'inside') bWidth = 0; + if (borderPosition === 'outside') bWidth *= 2; + var scaleX = (nodeWidth + bWidth + (outlineWidth + outlineOffset)) / nodeWidth; + var scaleY = (nodeHeight + bWidth + (outlineWidth + outlineOffset)) / nodeHeight; + var sWidth = nodeWidth * scaleX; + var sHeight = nodeHeight * scaleY; + var points = r.nodeShapes[shape].points; + var _path; + if (usePaths) { + var outlinePath = getPath(sWidth, sHeight, shape, points); + _path = outlinePath.path; + } + + // draw the outline path, either by using expanded points or by scaling + // the dimensions, depending on shape + if (shape === "ellipse") { + r.drawEllipsePath(_path || context, npos.x, npos.y, sWidth, sHeight); + } else if (['round-diamond', 'round-heptagon', 'round-hexagon', 'round-octagon', 'round-pentagon', 'round-polygon', 'round-triangle', 'round-tag'].includes(shape)) { + var sMult = 0; + var offsetX = 0; + var offsetY = 0; + if (shape === 'round-diamond') { + sMult = (bWidth + outlineOffset + outlineWidth) * 1.4; + } else if (shape === 'round-heptagon') { + sMult = (bWidth + outlineOffset + outlineWidth) * 1.075; + offsetY = -(bWidth / 2 + outlineOffset + outlineWidth) / 35; + } else if (shape === 'round-hexagon') { + sMult = (bWidth + outlineOffset + outlineWidth) * 1.12; + } else if (shape === 'round-pentagon') { + sMult = (bWidth + outlineOffset + outlineWidth) * 1.13; + offsetY = -(bWidth / 2 + outlineOffset + outlineWidth) / 15; + } else if (shape === 'round-tag') { + sMult = (bWidth + outlineOffset + outlineWidth) * 1.12; + offsetX = (bWidth / 2 + outlineWidth + outlineOffset) * .07; + } else if (shape === 'round-triangle') { + sMult = (bWidth + outlineOffset + outlineWidth) * (Math.PI / 2); + offsetY = -(bWidth + outlineOffset / 2 + outlineWidth) / Math.PI; + } + if (sMult !== 0) { + scaleX = (nodeWidth + sMult) / nodeWidth; + sWidth = nodeWidth * scaleX; + if (!['round-hexagon', 'round-tag'].includes(shape)) { + scaleY = (nodeHeight + sMult) / nodeHeight; + sHeight = nodeHeight * scaleY; + } + } + cornerRadius = cornerRadius === 'auto' ? getRoundPolygonRadius(sWidth, sHeight) : cornerRadius; + var halfW = sWidth / 2; + var halfH = sHeight / 2; + var radius = cornerRadius + (bWidth + outlineWidth + outlineOffset) / 2; + var p = new Array(points.length / 2); + var corners = new Array(points.length / 2); + for (var _i3 = 0; _i3 < points.length / 2; _i3++) { + p[_i3] = { + x: npos.x + offsetX + halfW * points[_i3 * 2], + y: npos.y + offsetY + halfH * points[_i3 * 2 + 1] + }; + } + var _i2, + p1, + p2, + p3, + len = p.length; + p1 = p[len - 1]; + // for each point + for (_i2 = 0; _i2 < len; _i2++) { + p2 = p[_i2 % len]; + p3 = p[(_i2 + 1) % len]; + corners[_i2] = getRoundCorner(p1, p2, p3, radius); + p1 = p2; + p2 = p3; + } + r.drawRoundPolygonPath(_path || context, npos.x + offsetX, npos.y + offsetY, nodeWidth * scaleX, nodeHeight * scaleY, points, corners); + } else if (['roundrectangle', 'round-rectangle'].includes(shape)) { + cornerRadius = cornerRadius === 'auto' ? getRoundRectangleRadius(sWidth, sHeight) : cornerRadius; + r.drawRoundRectanglePath(_path || context, npos.x, npos.y, sWidth, sHeight, cornerRadius + (bWidth + outlineWidth + outlineOffset) / 2); + } else if (['cutrectangle', 'cut-rectangle'].includes(shape)) { + cornerRadius = cornerRadius === 'auto' ? getCutRectangleCornerLength() : cornerRadius; + r.drawCutRectanglePath(_path || context, npos.x, npos.y, sWidth, sHeight, null, cornerRadius + (bWidth + outlineWidth + outlineOffset) / 4); + } else if (['bottomroundrectangle', 'bottom-round-rectangle'].includes(shape)) { + cornerRadius = cornerRadius === 'auto' ? getRoundRectangleRadius(sWidth, sHeight) : cornerRadius; + r.drawBottomRoundRectanglePath(_path || context, npos.x, npos.y, sWidth, sHeight, cornerRadius + (bWidth + outlineWidth + outlineOffset) / 2); + } else if (shape === "barrel") { + r.drawBarrelPath(_path || context, npos.x, npos.y, sWidth, sHeight); + } else if (shape.startsWith("polygon") || ['rhomboid', 'right-rhomboid', 'round-tag', 'tag', 'vee'].includes(shape)) { + var pad = (bWidth + outlineWidth + outlineOffset) / nodeWidth; + points = joinLines(expandPolygon(points, pad)); + r.drawPolygonPath(_path || context, npos.x, npos.y, nodeWidth, nodeHeight, points); + } else { + var _pad = (bWidth + outlineWidth + outlineOffset) / nodeWidth; + points = joinLines(expandPolygon(points, -_pad)); + r.drawPolygonPath(_path || context, npos.x, npos.y, nodeWidth, nodeHeight, points); + } + if (usePaths) { + context.stroke(_path); + } else { + context.stroke(); + } + if (outlineStyle === 'double') { + context.lineWidth = bWidth / 3; + var gco = context.globalCompositeOperation; + context.globalCompositeOperation = 'destination-out'; + if (usePaths) { + context.stroke(_path); + } else { + context.stroke(); + } + context.globalCompositeOperation = gco; + } + + // reset in case we changed the border style + if (context.setLineDash) { + // for very outofdate browsers + context.setLineDash([]); + } + } + }; + var drawOverlay = function drawOverlay() { + if (shouldDrawOverlay) { + r.drawNodeOverlay(context, node, pos, nodeWidth, nodeHeight); + } + }; + var drawUnderlay = function drawUnderlay() { + if (shouldDrawOverlay) { + r.drawNodeUnderlay(context, node, pos, nodeWidth, nodeHeight); + } + }; + var drawText = function drawText() { + r.drawElementText(context, node, null, drawLabel); + }; + var ghost = node.pstyle('ghost').value === 'yes'; + if (ghost) { + var gx = node.pstyle('ghost-offset-x').pfValue; + var gy = node.pstyle('ghost-offset-y').pfValue; + var ghostOpacity = node.pstyle('ghost-opacity').value; + var effGhostOpacity = ghostOpacity * eleOpacity; + context.translate(gx, gy); + setupOutlineColor(); + drawOutline(); + setupShapeColor(ghostOpacity * bgOpacity); + drawShape(); + drawImages(effGhostOpacity, true); + setupBorderColor(ghostOpacity * borderOpacity); + drawBorder(); + drawPie(darkness !== 0 || borderWidth !== 0); + drawImages(effGhostOpacity, false); + darken(effGhostOpacity); + context.translate(-gx, -gy); + } + if (usePaths) { + context.translate(-pos.x, -pos.y); + } + drawUnderlay(); + if (usePaths) { + context.translate(pos.x, pos.y); + } + setupOutlineColor(); + drawOutline(); + setupShapeColor(); + drawShape(); + drawImages(eleOpacity, true); + setupBorderColor(); + drawBorder(); + drawPie(darkness !== 0 || borderWidth !== 0); + drawImages(eleOpacity, false); + darken(); + if (usePaths) { + context.translate(-pos.x, -pos.y); + } + drawText(); + drawOverlay(); - } + // + // clean up shift - set image( value ) { + if (shiftToOriginWithBb) { + context.translate(bb.x1, bb.y1); + } + }; + var drawNodeOverlayUnderlay = function drawNodeOverlayUnderlay(overlayOrUnderlay) { + if (!['overlay', 'underlay'].includes(overlayOrUnderlay)) { + throw new Error('Invalid state'); + } + return function (context, node, pos, nodeWidth, nodeHeight) { + var r = this; + if (!node.visible()) { + return; + } + var padding = node.pstyle("".concat(overlayOrUnderlay, "-padding")).pfValue; + var opacity = node.pstyle("".concat(overlayOrUnderlay, "-opacity")).value; + var color = node.pstyle("".concat(overlayOrUnderlay, "-color")).value; + var shape = node.pstyle("".concat(overlayOrUnderlay, "-shape")).value; + var radius = node.pstyle("".concat(overlayOrUnderlay, "-corner-radius")).value; + if (opacity > 0) { + pos = pos || node.position(); + if (nodeWidth == null || nodeHeight == null) { + var _padding = node.padding(); + nodeWidth = node.width() + 2 * _padding; + nodeHeight = node.height() + 2 * _padding; + } + r.colorFillStyle(context, color[0], color[1], color[2], opacity); + r.nodeShapes[shape].draw(context, pos.x, pos.y, nodeWidth + padding * 2, nodeHeight + padding * 2, radius); + context.fill(); + } + }; + }; + CRp$5.drawNodeOverlay = drawNodeOverlayUnderlay('overlay'); + CRp$5.drawNodeUnderlay = drawNodeOverlayUnderlay('underlay'); - this.source.data = value; + // does the node have at least one pie piece? + CRp$5.hasPie = function (node) { + node = node[0]; // ensure ele ref - } + return node._private.hasPie; + }; + CRp$5.drawPie = function (context, node, nodeOpacity, pos) { + node = node[0]; // ensure ele ref + pos = pos || node.position(); + var cyStyle = node.cy().style(); + var pieSize = node.pstyle('pie-size'); + var x = pos.x; + var y = pos.y; + var nodeW = node.width(); + var nodeH = node.height(); + var radius = Math.min(nodeW, nodeH) / 2; // must fit in node + var lastPercent = 0; // what % to continue drawing pie slices from on [0, 1] + var usePaths = this.usePaths(); + if (usePaths) { + x = 0; + y = 0; + } + if (pieSize.units === '%') { + radius = radius * pieSize.pfValue; + } else if (pieSize.pfValue !== undefined) { + radius = pieSize.pfValue / 2; + } + for (var i = 1; i <= cyStyle.pieBackgroundN; i++) { + // 1..N + var size = node.pstyle('pie-' + i + '-background-size').value; + var color = node.pstyle('pie-' + i + '-background-color').value; + var opacity = node.pstyle('pie-' + i + '-background-opacity').value * nodeOpacity; + var percent = size / 100; // map integer range [0, 100] to [0, 1] + + // percent can't push beyond 1 + if (percent + lastPercent > 1) { + percent = 1 - lastPercent; + } + var angleStart = 1.5 * Math.PI + 2 * Math.PI * lastPercent; // start at 12 o'clock and go clockwise + var angleDelta = 2 * Math.PI * percent; + var angleEnd = angleStart + angleDelta; + + // ignore if + // - zero size + // - we're already beyond the full circle + // - adding the current slice would go beyond the full circle + if (size === 0 || lastPercent >= 1 || lastPercent + percent > 1) { + continue; + } + context.beginPath(); + context.moveTo(x, y); + context.arc(x, y, radius, angleStart, angleEnd); + context.closePath(); + this.colorFillStyle(context, color[0], color[1], color[2], opacity); + context.fill(); + lastPercent += percent; + } + }; - updateMatrix() { + var CRp$4 = {}; + var motionBlurDelay = 100; - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); + // var isFirefox = typeof InstallTrigger !== 'undefined'; - } + CRp$4.getPixelRatio = function () { + var context = this.data.contexts[0]; + if (this.forcedPixelRatio != null) { + return this.forcedPixelRatio; + } + var backingStore = context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1; + return (window.devicePixelRatio || 1) / backingStore; // eslint-disable-line no-undef + }; - clone() { + CRp$4.paintCache = function (context) { + var caches = this.paintCaches = this.paintCaches || []; + var needToCreateCache = true; + var cache; + for (var i = 0; i < caches.length; i++) { + cache = caches[i]; + if (cache.context === context) { + needToCreateCache = false; + break; + } + } + if (needToCreateCache) { + cache = { + context: context + }; + caches.push(cache); + } + return cache; + }; + CRp$4.createGradientStyleFor = function (context, shapeStyleName, ele, fill, opacity) { + var gradientStyle; + var usePaths = this.usePaths(); + var colors = ele.pstyle(shapeStyleName + '-gradient-stop-colors').value, + positions = ele.pstyle(shapeStyleName + '-gradient-stop-positions').pfValue; + if (fill === 'radial-gradient') { + if (ele.isEdge()) { + var start = ele.sourceEndpoint(), + end = ele.targetEndpoint(), + mid = ele.midpoint(); + var d1 = dist(start, mid); + var d2 = dist(end, mid); + gradientStyle = context.createRadialGradient(mid.x, mid.y, 0, mid.x, mid.y, Math.max(d1, d2)); + } else { + var pos = usePaths ? { + x: 0, + y: 0 + } : ele.position(), + width = ele.paddedWidth(), + height = ele.paddedHeight(); + gradientStyle = context.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, Math.max(width, height)); + } + } else { + if (ele.isEdge()) { + var _start = ele.sourceEndpoint(), + _end = ele.targetEndpoint(); + gradientStyle = context.createLinearGradient(_start.x, _start.y, _end.x, _end.y); + } else { + var _pos = usePaths ? { + x: 0, + y: 0 + } : ele.position(), + _width = ele.paddedWidth(), + _height = ele.paddedHeight(), + halfWidth = _width / 2, + halfHeight = _height / 2; + var direction = ele.pstyle('background-gradient-direction').value; + switch (direction) { + case 'to-bottom': + gradientStyle = context.createLinearGradient(_pos.x, _pos.y - halfHeight, _pos.x, _pos.y + halfHeight); + break; + case 'to-top': + gradientStyle = context.createLinearGradient(_pos.x, _pos.y + halfHeight, _pos.x, _pos.y - halfHeight); + break; + case 'to-left': + gradientStyle = context.createLinearGradient(_pos.x + halfWidth, _pos.y, _pos.x - halfWidth, _pos.y); + break; + case 'to-right': + gradientStyle = context.createLinearGradient(_pos.x - halfWidth, _pos.y, _pos.x + halfWidth, _pos.y); + break; + case 'to-bottom-right': + case 'to-right-bottom': + gradientStyle = context.createLinearGradient(_pos.x - halfWidth, _pos.y - halfHeight, _pos.x + halfWidth, _pos.y + halfHeight); + break; + case 'to-top-right': + case 'to-right-top': + gradientStyle = context.createLinearGradient(_pos.x - halfWidth, _pos.y + halfHeight, _pos.x + halfWidth, _pos.y - halfHeight); + break; + case 'to-bottom-left': + case 'to-left-bottom': + gradientStyle = context.createLinearGradient(_pos.x + halfWidth, _pos.y - halfHeight, _pos.x - halfWidth, _pos.y + halfHeight); + break; + case 'to-top-left': + case 'to-left-top': + gradientStyle = context.createLinearGradient(_pos.x + halfWidth, _pos.y + halfHeight, _pos.x - halfWidth, _pos.y - halfHeight); + break; + } + } + } + if (!gradientStyle) return null; // invalid gradient style - return new this.constructor().copy( this ); + var hasPositions = positions.length === colors.length; + var length = colors.length; + for (var i = 0; i < length; i++) { + gradientStyle.addColorStop(hasPositions ? positions[i] : i / (length - 1), 'rgba(' + colors[i][0] + ',' + colors[i][1] + ',' + colors[i][2] + ',' + opacity + ')'); + } + return gradientStyle; + }; + CRp$4.gradientFillStyle = function (context, ele, fill, opacity) { + var gradientStyle = this.createGradientStyleFor(context, 'background', ele, fill, opacity); + if (!gradientStyle) return null; // error + context.fillStyle = gradientStyle; + }; + CRp$4.colorFillStyle = function (context, r, g, b, a) { + context.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; + // turn off for now, seems context does its own caching - } + // var cache = this.paintCache(context); - copy( source ) { + // var fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; - this.name = source.name; + // if( cache.fillStyle !== fillStyle ){ + // context.fillStyle = cache.fillStyle = fillStyle; + // } + }; - this.source = source.source; - this.mipmaps = source.mipmaps.slice( 0 ); + CRp$4.eleFillStyle = function (context, ele, opacity) { + var backgroundFill = ele.pstyle('background-fill').value; + if (backgroundFill === 'linear-gradient' || backgroundFill === 'radial-gradient') { + this.gradientFillStyle(context, ele, backgroundFill, opacity); + } else { + var backgroundColor = ele.pstyle('background-color').value; + this.colorFillStyle(context, backgroundColor[0], backgroundColor[1], backgroundColor[2], opacity); + } + }; + CRp$4.gradientStrokeStyle = function (context, ele, fill, opacity) { + var gradientStyle = this.createGradientStyleFor(context, 'line', ele, fill, opacity); + if (!gradientStyle) return null; // error + context.strokeStyle = gradientStyle; + }; + CRp$4.colorStrokeStyle = function (context, r, g, b, a) { + context.strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; + // turn off for now, seems context does its own caching - this.mapping = source.mapping; + // var cache = this.paintCache(context); - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; + // var strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; + // if( cache.strokeStyle !== strokeStyle ){ + // context.strokeStyle = cache.strokeStyle = strokeStyle; + // } + }; - this.anisotropy = source.anisotropy; + CRp$4.eleStrokeStyle = function (context, ele, opacity) { + var lineFill = ele.pstyle('line-fill').value; + if (lineFill === 'linear-gradient' || lineFill === 'radial-gradient') { + this.gradientStrokeStyle(context, ele, lineFill, opacity); + } else { + var lineColor = ele.pstyle('line-color').value; + this.colorStrokeStyle(context, lineColor[0], lineColor[1], lineColor[2], opacity); + } + }; - this.format = source.format; - this.internalFormat = source.internalFormat; - this.type = source.type; + // Resize canvas + CRp$4.matchCanvasSize = function (container) { + var r = this; + var data = r.data; + var bb = r.findContainerClientCoords(); + var width = bb[2]; + var height = bb[3]; + var pixelRatio = r.getPixelRatio(); + var mbPxRatio = r.motionBlurPxRatio; + if (container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_NODE] || container === r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_DRAG]) { + pixelRatio = mbPxRatio; + } + var canvasWidth = width * pixelRatio; + var canvasHeight = height * pixelRatio; + var canvas; + if (canvasWidth === r.canvasWidth && canvasHeight === r.canvasHeight) { + return; // save cycles if same + } - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; + r.fontCaches = null; // resizing resets the style + + var canvasContainer = data.canvasContainer; + canvasContainer.style.width = width + 'px'; + canvasContainer.style.height = height + 'px'; + for (var i = 0; i < r.CANVAS_LAYERS; i++) { + canvas = data.canvases[i]; + canvas.width = canvasWidth; + canvas.height = canvasHeight; + canvas.style.width = width + 'px'; + canvas.style.height = height + 'px'; + } + for (var i = 0; i < r.BUFFER_COUNT; i++) { + canvas = data.bufferCanvases[i]; + canvas.width = canvasWidth; + canvas.height = canvasHeight; + canvas.style.width = width + 'px'; + canvas.style.height = height + 'px'; + } + r.textureMult = 1; + if (pixelRatio <= 1) { + canvas = data.bufferCanvases[r.TEXTURE_BUFFER]; + r.textureMult = 2; + canvas.width = canvasWidth * r.textureMult; + canvas.height = canvasHeight * r.textureMult; + } + r.canvasWidth = canvasWidth; + r.canvasHeight = canvasHeight; + }; + CRp$4.renderTo = function (cxt, zoom, pan, pxRatio) { + this.render({ + forcedContext: cxt, + forcedZoom: zoom, + forcedPan: pan, + drawAllLayers: true, + forcedPxRatio: pxRatio + }); + }; + CRp$4.render = function (options) { + options = options || staticEmptyObject(); + var forcedContext = options.forcedContext; + var drawAllLayers = options.drawAllLayers; + var drawOnlyNodeLayer = options.drawOnlyNodeLayer; + var forcedZoom = options.forcedZoom; + var forcedPan = options.forcedPan; + var r = this; + var pixelRatio = options.forcedPxRatio === undefined ? this.getPixelRatio() : options.forcedPxRatio; + var cy = r.cy; + var data = r.data; + var needDraw = data.canvasNeedsRedraw; + var textureDraw = r.textureOnViewport && !forcedContext && (r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming); + var motionBlur = options.motionBlur !== undefined ? options.motionBlur : r.motionBlur; + var mbPxRatio = r.motionBlurPxRatio; + var hasCompoundNodes = cy.hasCompoundNodes(); + var inNodeDragGesture = r.hoverData.draggingEles; + var inBoxSelection = r.hoverData.selecting || r.touchData.selecting ? true : false; + motionBlur = motionBlur && !forcedContext && r.motionBlurEnabled && !inBoxSelection; + var motionBlurFadeEffect = motionBlur; + if (!forcedContext) { + if (r.prevPxRatio !== pixelRatio) { + r.invalidateContainerClientCoordsCache(); + r.matchCanvasSize(r.container); + r.redrawHint('eles', true); + r.redrawHint('drag', true); + } + r.prevPxRatio = pixelRatio; + } + if (!forcedContext && r.motionBlurTimeout) { + clearTimeout(r.motionBlurTimeout); + } + if (motionBlur) { + if (r.mbFrames == null) { + r.mbFrames = 0; + } + r.mbFrames++; + if (r.mbFrames < 3) { + // need several frames before even high quality motionblur + motionBlurFadeEffect = false; + } - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrix.copy( source.matrix ); + // go to lower quality blurry frames when several m/b frames have been rendered (avoids flashing) + if (r.mbFrames > r.minMbLowQualFrames) { + //r.fullQualityMb = false; + r.motionBlurPxRatio = r.mbPxRBlurry; + } + } + if (r.clearingMotionBlur) { + r.motionBlurPxRatio = 1; + } - this.generateMipmaps = source.generateMipmaps; - this.premultiplyAlpha = source.premultiplyAlpha; - this.flipY = source.flipY; - this.unpackAlignment = source.unpackAlignment; - this.encoding = source.encoding; + // b/c drawToContext() may be async w.r.t. redraw(), keep track of last texture frame + // because a rogue async texture frame would clear needDraw + if (r.textureDrawLastFrame && !textureDraw) { + needDraw[r.NODE] = true; + needDraw[r.SELECT_BOX] = true; + } + var style = cy.style(); + var zoom = cy.zoom(); + var effectiveZoom = forcedZoom !== undefined ? forcedZoom : zoom; + var pan = cy.pan(); + var effectivePan = { + x: pan.x, + y: pan.y + }; + var vp = { + zoom: zoom, + pan: { + x: pan.x, + y: pan.y + } + }; + var prevVp = r.prevViewport; + var viewportIsDiff = prevVp === undefined || vp.zoom !== prevVp.zoom || vp.pan.x !== prevVp.pan.x || vp.pan.y !== prevVp.pan.y; - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + // we want the low quality motionblur only when the viewport is being manipulated etc (where it's not noticed) + if (!viewportIsDiff && !(inNodeDragGesture && !hasCompoundNodes)) { + r.motionBlurPxRatio = 1; + } + if (forcedPan) { + effectivePan = forcedPan; + } - this.needsUpdate = true; + // apply pixel ratio + + effectiveZoom *= pixelRatio; + effectivePan.x *= pixelRatio; + effectivePan.y *= pixelRatio; + var eles = r.getCachedZSortedEles(); + function mbclear(context, x, y, w, h) { + var gco = context.globalCompositeOperation; + context.globalCompositeOperation = 'destination-out'; + r.colorFillStyle(context, 255, 255, 255, r.motionBlurTransparency); + context.fillRect(x, y, w, h); + context.globalCompositeOperation = gco; + } + function setContextTransform(context, clear) { + var ePan, eZoom, w, h; + if (!r.clearingMotionBlur && (context === data.bufferContexts[r.MOTIONBLUR_BUFFER_NODE] || context === data.bufferContexts[r.MOTIONBLUR_BUFFER_DRAG])) { + ePan = { + x: pan.x * mbPxRatio, + y: pan.y * mbPxRatio + }; + eZoom = zoom * mbPxRatio; + w = r.canvasWidth * mbPxRatio; + h = r.canvasHeight * mbPxRatio; + } else { + ePan = effectivePan; + eZoom = effectiveZoom; + w = r.canvasWidth; + h = r.canvasHeight; + } + context.setTransform(1, 0, 0, 1, 0, 0); + if (clear === 'motionBlur') { + mbclear(context, 0, 0, w, h); + } else if (!forcedContext && (clear === undefined || clear)) { + context.clearRect(0, 0, w, h); + } + if (!drawAllLayers) { + context.translate(ePan.x, ePan.y); + context.scale(eZoom, eZoom); + } + if (forcedPan) { + context.translate(forcedPan.x, forcedPan.y); + } + if (forcedZoom) { + context.scale(forcedZoom, forcedZoom); + } + } + if (!textureDraw) { + r.textureDrawLastFrame = false; + } + if (textureDraw) { + r.textureDrawLastFrame = true; + if (!r.textureCache) { + r.textureCache = {}; + r.textureCache.bb = cy.mutableElements().boundingBox(); + r.textureCache.texture = r.data.bufferCanvases[r.TEXTURE_BUFFER]; + var cxt = r.data.bufferContexts[r.TEXTURE_BUFFER]; + cxt.setTransform(1, 0, 0, 1, 0, 0); + cxt.clearRect(0, 0, r.canvasWidth * r.textureMult, r.canvasHeight * r.textureMult); + r.render({ + forcedContext: cxt, + drawOnlyNodeLayer: true, + forcedPxRatio: pixelRatio * r.textureMult + }); + var vp = r.textureCache.viewport = { + zoom: cy.zoom(), + pan: cy.pan(), + width: r.canvasWidth, + height: r.canvasHeight + }; + vp.mpan = { + x: (0 - vp.pan.x) / vp.zoom, + y: (0 - vp.pan.y) / vp.zoom + }; + } + needDraw[r.DRAG] = false; + needDraw[r.NODE] = false; + var context = data.contexts[r.NODE]; + var texture = r.textureCache.texture; + var vp = r.textureCache.viewport; + context.setTransform(1, 0, 0, 1, 0, 0); + if (motionBlur) { + mbclear(context, 0, 0, vp.width, vp.height); + } else { + context.clearRect(0, 0, vp.width, vp.height); + } + var outsideBgColor = style.core('outside-texture-bg-color').value; + var outsideBgOpacity = style.core('outside-texture-bg-opacity').value; + r.colorFillStyle(context, outsideBgColor[0], outsideBgColor[1], outsideBgColor[2], outsideBgOpacity); + context.fillRect(0, 0, vp.width, vp.height); + var zoom = cy.zoom(); + setContextTransform(context, false); + context.clearRect(vp.mpan.x, vp.mpan.y, vp.width / vp.zoom / pixelRatio, vp.height / vp.zoom / pixelRatio); + context.drawImage(texture, vp.mpan.x, vp.mpan.y, vp.width / vp.zoom / pixelRatio, vp.height / vp.zoom / pixelRatio); + } else if (r.textureOnViewport && !forcedContext) { + // clear the cache since we don't need it + r.textureCache = null; + } + var extent = cy.extent(); + var vpManip = r.pinching || r.hoverData.dragging || r.swipePanning || r.data.wheelZooming || r.hoverData.draggingEles || r.cy.animated(); + var hideEdges = r.hideEdgesOnViewport && vpManip; + var needMbClear = []; + needMbClear[r.NODE] = !needDraw[r.NODE] && motionBlur && !r.clearedForMotionBlur[r.NODE] || r.clearingMotionBlur; + if (needMbClear[r.NODE]) { + r.clearedForMotionBlur[r.NODE] = true; + } + needMbClear[r.DRAG] = !needDraw[r.DRAG] && motionBlur && !r.clearedForMotionBlur[r.DRAG] || r.clearingMotionBlur; + if (needMbClear[r.DRAG]) { + r.clearedForMotionBlur[r.DRAG] = true; + } + if (needDraw[r.NODE] || drawAllLayers || drawOnlyNodeLayer || needMbClear[r.NODE]) { + var useBuffer = motionBlur && !needMbClear[r.NODE] && mbPxRatio !== 1; + var context = forcedContext || (useBuffer ? r.data.bufferContexts[r.MOTIONBLUR_BUFFER_NODE] : data.contexts[r.NODE]); + var clear = motionBlur && !useBuffer ? 'motionBlur' : undefined; + setContextTransform(context, clear); + if (hideEdges) { + r.drawCachedNodes(context, eles.nondrag, pixelRatio, extent); + } else { + r.drawLayeredElements(context, eles.nondrag, pixelRatio, extent); + } + if (r.debug) { + r.drawDebugPoints(context, eles.nondrag); + } + if (!drawAllLayers && !motionBlur) { + needDraw[r.NODE] = false; + } + } + if (!drawOnlyNodeLayer && (needDraw[r.DRAG] || drawAllLayers || needMbClear[r.DRAG])) { + var useBuffer = motionBlur && !needMbClear[r.DRAG] && mbPxRatio !== 1; + var context = forcedContext || (useBuffer ? r.data.bufferContexts[r.MOTIONBLUR_BUFFER_DRAG] : data.contexts[r.DRAG]); + setContextTransform(context, motionBlur && !useBuffer ? 'motionBlur' : undefined); + if (hideEdges) { + r.drawCachedNodes(context, eles.drag, pixelRatio, extent); + } else { + r.drawCachedElements(context, eles.drag, pixelRatio, extent); + } + if (r.debug) { + r.drawDebugPoints(context, eles.drag); + } + if (!drawAllLayers && !motionBlur) { + needDraw[r.DRAG] = false; + } + } + if (r.showFps || !drawOnlyNodeLayer && needDraw[r.SELECT_BOX] && !drawAllLayers) { + var context = forcedContext || data.contexts[r.SELECT_BOX]; + setContextTransform(context); + if (r.selection[4] == 1 && (r.hoverData.selecting || r.touchData.selecting)) { + var zoom = r.cy.zoom(); + var borderWidth = style.core('selection-box-border-width').value / zoom; + context.lineWidth = borderWidth; + context.fillStyle = 'rgba(' + style.core('selection-box-color').value[0] + ',' + style.core('selection-box-color').value[1] + ',' + style.core('selection-box-color').value[2] + ',' + style.core('selection-box-opacity').value + ')'; + context.fillRect(r.selection[0], r.selection[1], r.selection[2] - r.selection[0], r.selection[3] - r.selection[1]); + if (borderWidth > 0) { + context.strokeStyle = 'rgba(' + style.core('selection-box-border-color').value[0] + ',' + style.core('selection-box-border-color').value[1] + ',' + style.core('selection-box-border-color').value[2] + ',' + style.core('selection-box-opacity').value + ')'; + context.strokeRect(r.selection[0], r.selection[1], r.selection[2] - r.selection[0], r.selection[3] - r.selection[1]); + } + } + if (data.bgActivePosistion && !r.hoverData.selecting) { + var zoom = r.cy.zoom(); + var pos = data.bgActivePosistion; + context.fillStyle = 'rgba(' + style.core('active-bg-color').value[0] + ',' + style.core('active-bg-color').value[1] + ',' + style.core('active-bg-color').value[2] + ',' + style.core('active-bg-opacity').value + ')'; + context.beginPath(); + context.arc(pos.x, pos.y, style.core('active-bg-size').pfValue / zoom, 0, 2 * Math.PI); + context.fill(); + } + var timeToRender = r.lastRedrawTime; + if (r.showFps && timeToRender) { + timeToRender = Math.round(timeToRender); + var fps = Math.round(1000 / timeToRender); + context.setTransform(1, 0, 0, 1, 0, 0); + context.fillStyle = 'rgba(255, 0, 0, 0.75)'; + context.strokeStyle = 'rgba(255, 0, 0, 0.75)'; + context.lineWidth = 1; + context.fillText('1 frame = ' + timeToRender + ' ms = ' + fps + ' fps', 0, 20); + var maxFps = 60; + context.strokeRect(0, 30, 250, 20); + context.fillRect(0, 30, 250 * Math.min(fps / maxFps, 1), 20); + } + if (!drawAllLayers) { + needDraw[r.SELECT_BOX] = false; + } + } - return this; + // motionblur: blit rendered blurry frames + if (motionBlur && mbPxRatio !== 1) { + var cxtNode = data.contexts[r.NODE]; + var txtNode = r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_NODE]; + var cxtDrag = data.contexts[r.DRAG]; + var txtDrag = r.data.bufferCanvases[r.MOTIONBLUR_BUFFER_DRAG]; + var drawMotionBlur = function drawMotionBlur(cxt, txt, needClear) { + cxt.setTransform(1, 0, 0, 1, 0, 0); + if (needClear || !motionBlurFadeEffect) { + cxt.clearRect(0, 0, r.canvasWidth, r.canvasHeight); + } else { + mbclear(cxt, 0, 0, r.canvasWidth, r.canvasHeight); + } + var pxr = mbPxRatio; + cxt.drawImage(txt, + // img + 0, 0, + // sx, sy + r.canvasWidth * pxr, r.canvasHeight * pxr, + // sw, sh + 0, 0, + // x, y + r.canvasWidth, r.canvasHeight // w, h + ); + }; - } + if (needDraw[r.NODE] || needMbClear[r.NODE]) { + drawMotionBlur(cxtNode, txtNode, needMbClear[r.NODE]); + needDraw[r.NODE] = false; + } + if (needDraw[r.DRAG] || needMbClear[r.DRAG]) { + drawMotionBlur(cxtDrag, txtDrag, needMbClear[r.DRAG]); + needDraw[r.DRAG] = false; + } + } + r.prevViewport = vp; + if (r.clearingMotionBlur) { + r.clearingMotionBlur = false; + r.motionBlurCleared = true; + r.motionBlur = true; + } + if (motionBlur) { + r.motionBlurTimeout = setTimeout(function () { + r.motionBlurTimeout = null; + r.clearedForMotionBlur[r.NODE] = false; + r.clearedForMotionBlur[r.DRAG] = false; + r.motionBlur = false; + r.clearingMotionBlur = !textureDraw; + r.mbFrames = 0; + needDraw[r.NODE] = true; + needDraw[r.DRAG] = true; + r.redraw(); + }, motionBlurDelay); + } + if (!forcedContext) { + cy.emit('render'); + } + }; - toJSON( meta ) { + var CRp$3 = {}; - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + // @O Polygon drawing + CRp$3.drawPolygonPath = function (context, x, y, width, height, points) { + var halfW = width / 2; + var halfH = height / 2; + if (context.beginPath) { + context.beginPath(); + } + context.moveTo(x + halfW * points[0], y + halfH * points[1]); + for (var i = 1; i < points.length / 2; i++) { + context.lineTo(x + halfW * points[i * 2], y + halfH * points[i * 2 + 1]); + } + context.closePath(); + }; + CRp$3.drawRoundPolygonPath = function (context, x, y, width, height, points, corners) { + corners.forEach(function (corner) { + return drawPreparedRoundCorner(context, corner); + }); + context.closePath(); + }; - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { + // Round rectangle drawing + CRp$3.drawRoundRectanglePath = function (context, x, y, width, height, radius) { + var halfWidth = width / 2; + var halfHeight = height / 2; + var cornerRadius = radius === 'auto' ? getRoundRectangleRadius(width, height) : Math.min(radius, halfHeight, halfWidth); + if (context.beginPath) { + context.beginPath(); + } - return meta.textures[ this.uuid ]; + // Start at top middle + context.moveTo(x, y - halfHeight); + // Arc from middle top to right side + context.arcTo(x + halfWidth, y - halfHeight, x + halfWidth, y, cornerRadius); + // Arc from right side to bottom + context.arcTo(x + halfWidth, y + halfHeight, x, y + halfHeight, cornerRadius); + // Arc from bottom to left side + context.arcTo(x - halfWidth, y + halfHeight, x - halfWidth, y, cornerRadius); + // Arc from left side to topBorder + context.arcTo(x - halfWidth, y - halfHeight, x, y - halfHeight, cornerRadius); + // Join line + context.lineTo(x, y - halfHeight); + context.closePath(); + }; + CRp$3.drawBottomRoundRectanglePath = function (context, x, y, width, height, radius) { + var halfWidth = width / 2; + var halfHeight = height / 2; + var cornerRadius = radius === 'auto' ? getRoundRectangleRadius(width, height) : radius; + if (context.beginPath) { + context.beginPath(); + } - } + // Start at top middle + context.moveTo(x, y - halfHeight); + context.lineTo(x + halfWidth, y - halfHeight); + context.lineTo(x + halfWidth, y); + context.arcTo(x + halfWidth, y + halfHeight, x, y + halfHeight, cornerRadius); + context.arcTo(x - halfWidth, y + halfHeight, x - halfWidth, y, cornerRadius); + context.lineTo(x - halfWidth, y - halfHeight); + context.lineTo(x, y - halfHeight); + context.closePath(); + }; + CRp$3.drawCutRectanglePath = function (context, x, y, width, height, points, corners) { + var halfWidth = width / 2; + var halfHeight = height / 2; + var cornerLength = corners === 'auto' ? getCutRectangleCornerLength() : corners; + if (context.beginPath) { + context.beginPath(); + } + context.moveTo(x - halfWidth + cornerLength, y - halfHeight); + context.lineTo(x + halfWidth - cornerLength, y - halfHeight); + context.lineTo(x + halfWidth, y - halfHeight + cornerLength); + context.lineTo(x + halfWidth, y + halfHeight - cornerLength); + context.lineTo(x + halfWidth - cornerLength, y + halfHeight); + context.lineTo(x - halfWidth + cornerLength, y + halfHeight); + context.lineTo(x - halfWidth, y + halfHeight - cornerLength); + context.lineTo(x - halfWidth, y - halfHeight + cornerLength); + context.closePath(); + }; + CRp$3.drawBarrelPath = function (context, x, y, width, height) { + var halfWidth = width / 2; + var halfHeight = height / 2; + var xBegin = x - halfWidth; + var xEnd = x + halfWidth; + var yBegin = y - halfHeight; + var yEnd = y + halfHeight; + var barrelCurveConstants = getBarrelCurveConstants(width, height); + var wOffset = barrelCurveConstants.widthOffset; + var hOffset = barrelCurveConstants.heightOffset; + var ctrlPtXOffset = barrelCurveConstants.ctrlPtOffsetPct * wOffset; + if (context.beginPath) { + context.beginPath(); + } + context.moveTo(xBegin, yBegin + hOffset); + context.lineTo(xBegin, yEnd - hOffset); + context.quadraticCurveTo(xBegin + ctrlPtXOffset, yEnd, xBegin + wOffset, yEnd); + context.lineTo(xEnd - wOffset, yEnd); + context.quadraticCurveTo(xEnd - ctrlPtXOffset, yEnd, xEnd, yEnd - hOffset); + context.lineTo(xEnd, yBegin + hOffset); + context.quadraticCurveTo(xEnd - ctrlPtXOffset, yBegin, xEnd - wOffset, yBegin); + context.lineTo(xBegin + wOffset, yBegin); + context.quadraticCurveTo(xBegin + ctrlPtXOffset, yBegin, xBegin, yBegin + hOffset); + context.closePath(); + }; + var sin0 = Math.sin(0); + var cos0 = Math.cos(0); + var sin = {}; + var cos = {}; + var ellipseStepSize = Math.PI / 40; + for (var i$1 = 0 * Math.PI; i$1 < 2 * Math.PI; i$1 += ellipseStepSize) { + sin[i$1] = Math.sin(i$1); + cos[i$1] = Math.cos(i$1); + } + CRp$3.drawEllipsePath = function (context, centerX, centerY, width, height) { + if (context.beginPath) { + context.beginPath(); + } + if (context.ellipse) { + context.ellipse(centerX, centerY, width / 2, height / 2, 0, 0, 2 * Math.PI); + } else { + var xPos, yPos; + var rw = width / 2; + var rh = height / 2; + for (var i = 0 * Math.PI; i < 2 * Math.PI; i += ellipseStepSize) { + xPos = centerX - rw * sin[i] * sin0 + rw * cos[i] * cos0; + yPos = centerY + rh * cos[i] * sin0 + rh * sin[i] * cos0; + if (i === 0) { + context.moveTo(xPos, yPos); + } else { + context.lineTo(xPos, yPos); + } + } + } + context.closePath(); + }; - const output = { + /* global atob, ArrayBuffer, Uint8Array, Blob */ + var CRp$2 = {}; + CRp$2.createBuffer = function (w, h) { + var buffer = document.createElement('canvas'); // eslint-disable-line no-undef + buffer.width = w; + buffer.height = h; + return [buffer, buffer.getContext('2d')]; + }; + CRp$2.bufferCanvasImage = function (options) { + var cy = this.cy; + var eles = cy.mutableElements(); + var bb = eles.boundingBox(); + var ctrRect = this.findContainerClientCoords(); + var width = options.full ? Math.ceil(bb.w) : ctrRect[2]; + var height = options.full ? Math.ceil(bb.h) : ctrRect[3]; + var specdMaxDims = number$1(options.maxWidth) || number$1(options.maxHeight); + var pxRatio = this.getPixelRatio(); + var scale = 1; + if (options.scale !== undefined) { + width *= options.scale; + height *= options.scale; + scale = options.scale; + } else if (specdMaxDims) { + var maxScaleW = Infinity; + var maxScaleH = Infinity; + if (number$1(options.maxWidth)) { + maxScaleW = scale * options.maxWidth / width; + } + if (number$1(options.maxHeight)) { + maxScaleH = scale * options.maxHeight / height; + } + scale = Math.min(maxScaleW, maxScaleH); + width *= scale; + height *= scale; + } + if (!specdMaxDims) { + width *= pxRatio; + height *= pxRatio; + scale *= pxRatio; + } + var buffCanvas = document.createElement('canvas'); // eslint-disable-line no-undef + + buffCanvas.width = width; + buffCanvas.height = height; + buffCanvas.style.width = width + 'px'; + buffCanvas.style.height = height + 'px'; + var buffCxt = buffCanvas.getContext('2d'); + + // Rasterize the layers, but only if container has nonzero size + if (width > 0 && height > 0) { + buffCxt.clearRect(0, 0, width, height); + buffCxt.globalCompositeOperation = 'source-over'; + var zsortedEles = this.getCachedZSortedEles(); + if (options.full) { + // draw the full bounds of the graph + buffCxt.translate(-bb.x1 * scale, -bb.y1 * scale); + buffCxt.scale(scale, scale); + this.drawElements(buffCxt, zsortedEles); + buffCxt.scale(1 / scale, 1 / scale); + buffCxt.translate(bb.x1 * scale, bb.y1 * scale); + } else { + // draw the current view + var pan = cy.pan(); + var translation = { + x: pan.x * scale, + y: pan.y * scale + }; + scale *= cy.zoom(); + buffCxt.translate(translation.x, translation.y); + buffCxt.scale(scale, scale); + this.drawElements(buffCxt, zsortedEles); + buffCxt.scale(1 / scale, 1 / scale); + buffCxt.translate(-translation.x, -translation.y); + } - metadata: { - version: 4.5, - type: 'Texture', - generator: 'Texture.toJSON' - }, + // need to fill bg at end like this in order to fill cleared transparent pixels in jpgs + if (options.bg) { + buffCxt.globalCompositeOperation = 'destination-over'; + buffCxt.fillStyle = options.bg; + buffCxt.rect(0, 0, width, height); + buffCxt.fill(); + } + } + return buffCanvas; + }; + function b64ToBlob(b64, mimeType) { + var bytes = atob(b64); + var buff = new ArrayBuffer(bytes.length); + var buffUint8 = new Uint8Array(buff); + for (var i = 0; i < bytes.length; i++) { + buffUint8[i] = bytes.charCodeAt(i); + } + return new Blob([buff], { + type: mimeType + }); + } + function b64UriToB64(b64uri) { + var i = b64uri.indexOf(','); + return b64uri.substr(i + 1); + } + function output(options, canvas, mimeType) { + var getB64Uri = function getB64Uri() { + return canvas.toDataURL(mimeType, options.quality); + }; + switch (options.output) { + case 'blob-promise': + return new Promise$1(function (resolve, reject) { + try { + canvas.toBlob(function (blob) { + if (blob != null) { + resolve(blob); + } else { + reject(new Error('`canvas.toBlob()` sent a null value in its callback')); + } + }, mimeType, options.quality); + } catch (err) { + reject(err); + } + }); + case 'blob': + return b64ToBlob(b64UriToB64(getB64Uri()), mimeType); + case 'base64': + return b64UriToB64(getB64Uri()); + case 'base64uri': + default: + return getB64Uri(); + } + } + CRp$2.png = function (options) { + return output(options, this.bufferCanvasImage(options), 'image/png'); + }; + CRp$2.jpg = function (options) { + return output(options, this.bufferCanvasImage(options), 'image/jpeg'); + }; - uuid: this.uuid, - name: this.name, + var CRp$1 = {}; + CRp$1.nodeShapeImpl = function (name, context, centerX, centerY, width, height, points, corners) { + switch (name) { + case 'ellipse': + return this.drawEllipsePath(context, centerX, centerY, width, height); + case 'polygon': + return this.drawPolygonPath(context, centerX, centerY, width, height, points); + case 'round-polygon': + return this.drawRoundPolygonPath(context, centerX, centerY, width, height, points, corners); + case 'roundrectangle': + case 'round-rectangle': + return this.drawRoundRectanglePath(context, centerX, centerY, width, height, corners); + case 'cutrectangle': + case 'cut-rectangle': + return this.drawCutRectanglePath(context, centerX, centerY, width, height, points, corners); + case 'bottomroundrectangle': + case 'bottom-round-rectangle': + return this.drawBottomRoundRectanglePath(context, centerX, centerY, width, height, corners); + case 'barrel': + return this.drawBarrelPath(context, centerX, centerY, width, height); + } + }; - image: this.source.toJSON( meta ).uuid, + var CR = CanvasRenderer; + var CRp = CanvasRenderer.prototype; + CRp.CANVAS_LAYERS = 3; + // + CRp.SELECT_BOX = 0; + CRp.DRAG = 1; + CRp.NODE = 2; + CRp.BUFFER_COUNT = 3; + // + CRp.TEXTURE_BUFFER = 0; + CRp.MOTIONBLUR_BUFFER_NODE = 1; + CRp.MOTIONBLUR_BUFFER_DRAG = 2; + function CanvasRenderer(options) { + var r = this; + r.data = { + canvases: new Array(CRp.CANVAS_LAYERS), + contexts: new Array(CRp.CANVAS_LAYERS), + canvasNeedsRedraw: new Array(CRp.CANVAS_LAYERS), + bufferCanvases: new Array(CRp.BUFFER_COUNT), + bufferContexts: new Array(CRp.CANVAS_LAYERS) + }; + var tapHlOffAttr = '-webkit-tap-highlight-color'; + var tapHlOffStyle = 'rgba(0,0,0,0)'; + r.data.canvasContainer = document.createElement('div'); // eslint-disable-line no-undef + var containerStyle = r.data.canvasContainer.style; + r.data.canvasContainer.style[tapHlOffAttr] = tapHlOffStyle; + containerStyle.position = 'relative'; + containerStyle.zIndex = '0'; + containerStyle.overflow = 'hidden'; + var container = options.cy.container(); + container.appendChild(r.data.canvasContainer); + container.style[tapHlOffAttr] = tapHlOffStyle; + var styleMap = { + '-webkit-user-select': 'none', + '-moz-user-select': '-moz-none', + 'user-select': 'none', + '-webkit-tap-highlight-color': 'rgba(0,0,0,0)', + 'outline-style': 'none' + }; + if (ms()) { + styleMap['-ms-touch-action'] = 'none'; + styleMap['touch-action'] = 'none'; + } + for (var i = 0; i < CRp.CANVAS_LAYERS; i++) { + var canvas = r.data.canvases[i] = document.createElement('canvas'); // eslint-disable-line no-undef + r.data.contexts[i] = canvas.getContext('2d'); + Object.keys(styleMap).forEach(function (k) { + canvas.style[k] = styleMap[k]; + }); + canvas.style.position = 'absolute'; + canvas.setAttribute('data-id', 'layer' + i); + canvas.style.zIndex = String(CRp.CANVAS_LAYERS - i); + r.data.canvasContainer.appendChild(canvas); + r.data.canvasNeedsRedraw[i] = false; + } + r.data.topCanvas = r.data.canvases[0]; + r.data.canvases[CRp.NODE].setAttribute('data-id', 'layer' + CRp.NODE + '-node'); + r.data.canvases[CRp.SELECT_BOX].setAttribute('data-id', 'layer' + CRp.SELECT_BOX + '-selectbox'); + r.data.canvases[CRp.DRAG].setAttribute('data-id', 'layer' + CRp.DRAG + '-drag'); + for (var i = 0; i < CRp.BUFFER_COUNT; i++) { + r.data.bufferCanvases[i] = document.createElement('canvas'); // eslint-disable-line no-undef + r.data.bufferContexts[i] = r.data.bufferCanvases[i].getContext('2d'); + r.data.bufferCanvases[i].style.position = 'absolute'; + r.data.bufferCanvases[i].setAttribute('data-id', 'buffer' + i); + r.data.bufferCanvases[i].style.zIndex = String(-i - 1); + r.data.bufferCanvases[i].style.visibility = 'hidden'; + //r.data.canvasContainer.appendChild(r.data.bufferCanvases[i]); + } - mapping: this.mapping, + r.pathsEnabled = true; + var emptyBb = makeBoundingBox(); + var getBoxCenter = function getBoxCenter(bb) { + return { + x: (bb.x1 + bb.x2) / 2, + y: (bb.y1 + bb.y2) / 2 + }; + }; + var getCenterOffset = function getCenterOffset(bb) { + return { + x: -bb.w / 2, + y: -bb.h / 2 + }; + }; + var backgroundTimestampHasChanged = function backgroundTimestampHasChanged(ele) { + var _p = ele[0]._private; + var same = _p.oldBackgroundTimestamp === _p.backgroundTimestamp; + return !same; + }; + var getStyleKey = function getStyleKey(ele) { + return ele[0]._private.nodeKey; + }; + var getLabelKey = function getLabelKey(ele) { + return ele[0]._private.labelStyleKey; + }; + var getSourceLabelKey = function getSourceLabelKey(ele) { + return ele[0]._private.sourceLabelStyleKey; + }; + var getTargetLabelKey = function getTargetLabelKey(ele) { + return ele[0]._private.targetLabelStyleKey; + }; + var drawElement = function drawElement(context, ele, bb, scaledLabelShown, useEleOpacity) { + return r.drawElement(context, ele, bb, false, false, useEleOpacity); + }; + var drawLabel = function drawLabel(context, ele, bb, scaledLabelShown, useEleOpacity) { + return r.drawElementText(context, ele, bb, scaledLabelShown, 'main', useEleOpacity); + }; + var drawSourceLabel = function drawSourceLabel(context, ele, bb, scaledLabelShown, useEleOpacity) { + return r.drawElementText(context, ele, bb, scaledLabelShown, 'source', useEleOpacity); + }; + var drawTargetLabel = function drawTargetLabel(context, ele, bb, scaledLabelShown, useEleOpacity) { + return r.drawElementText(context, ele, bb, scaledLabelShown, 'target', useEleOpacity); + }; + var getElementBox = function getElementBox(ele) { + ele.boundingBox(); + return ele[0]._private.bodyBounds; + }; + var getLabelBox = function getLabelBox(ele) { + ele.boundingBox(); + return ele[0]._private.labelBounds.main || emptyBb; + }; + var getSourceLabelBox = function getSourceLabelBox(ele) { + ele.boundingBox(); + return ele[0]._private.labelBounds.source || emptyBb; + }; + var getTargetLabelBox = function getTargetLabelBox(ele) { + ele.boundingBox(); + return ele[0]._private.labelBounds.target || emptyBb; + }; + var isLabelVisibleAtScale = function isLabelVisibleAtScale(ele, scaledLabelShown) { + return scaledLabelShown; + }; + var getElementRotationPoint = function getElementRotationPoint(ele) { + return getBoxCenter(getElementBox(ele)); + }; + var addTextMargin = function addTextMargin(prefix, pt, ele) { + var pre = prefix ? prefix + '-' : ''; + return { + x: pt.x + ele.pstyle(pre + 'text-margin-x').pfValue, + y: pt.y + ele.pstyle(pre + 'text-margin-y').pfValue + }; + }; + var getRsPt = function getRsPt(ele, x, y) { + var rs = ele[0]._private.rscratch; + return { + x: rs[x], + y: rs[y] + }; + }; + var getLabelRotationPoint = function getLabelRotationPoint(ele) { + return addTextMargin('', getRsPt(ele, 'labelX', 'labelY'), ele); + }; + var getSourceLabelRotationPoint = function getSourceLabelRotationPoint(ele) { + return addTextMargin('source', getRsPt(ele, 'sourceLabelX', 'sourceLabelY'), ele); + }; + var getTargetLabelRotationPoint = function getTargetLabelRotationPoint(ele) { + return addTextMargin('target', getRsPt(ele, 'targetLabelX', 'targetLabelY'), ele); + }; + var getElementRotationOffset = function getElementRotationOffset(ele) { + return getCenterOffset(getElementBox(ele)); + }; + var getSourceLabelRotationOffset = function getSourceLabelRotationOffset(ele) { + return getCenterOffset(getSourceLabelBox(ele)); + }; + var getTargetLabelRotationOffset = function getTargetLabelRotationOffset(ele) { + return getCenterOffset(getTargetLabelBox(ele)); + }; + var getLabelRotationOffset = function getLabelRotationOffset(ele) { + var bb = getLabelBox(ele); + var p = getCenterOffset(getLabelBox(ele)); + if (ele.isNode()) { + switch (ele.pstyle('text-halign').value) { + case 'left': + p.x = -bb.w; + break; + case 'right': + p.x = 0; + break; + } + switch (ele.pstyle('text-valign').value) { + case 'top': + p.y = -bb.h; + break; + case 'bottom': + p.y = 0; + break; + } + } + return p; + }; + var eleTxrCache = r.data.eleTxrCache = new ElementTextureCache(r, { + getKey: getStyleKey, + doesEleInvalidateKey: backgroundTimestampHasChanged, + drawElement: drawElement, + getBoundingBox: getElementBox, + getRotationPoint: getElementRotationPoint, + getRotationOffset: getElementRotationOffset, + allowEdgeTxrCaching: false, + allowParentTxrCaching: false + }); + var lblTxrCache = r.data.lblTxrCache = new ElementTextureCache(r, { + getKey: getLabelKey, + drawElement: drawLabel, + getBoundingBox: getLabelBox, + getRotationPoint: getLabelRotationPoint, + getRotationOffset: getLabelRotationOffset, + isVisible: isLabelVisibleAtScale + }); + var slbTxrCache = r.data.slbTxrCache = new ElementTextureCache(r, { + getKey: getSourceLabelKey, + drawElement: drawSourceLabel, + getBoundingBox: getSourceLabelBox, + getRotationPoint: getSourceLabelRotationPoint, + getRotationOffset: getSourceLabelRotationOffset, + isVisible: isLabelVisibleAtScale + }); + var tlbTxrCache = r.data.tlbTxrCache = new ElementTextureCache(r, { + getKey: getTargetLabelKey, + drawElement: drawTargetLabel, + getBoundingBox: getTargetLabelBox, + getRotationPoint: getTargetLabelRotationPoint, + getRotationOffset: getTargetLabelRotationOffset, + isVisible: isLabelVisibleAtScale + }); + var lyrTxrCache = r.data.lyrTxrCache = new LayeredTextureCache(r); + r.onUpdateEleCalcs(function invalidateTextureCaches(willDraw, eles) { + // each cache should check for sub-key diff to see that the update affects that cache particularly + eleTxrCache.invalidateElements(eles); + lblTxrCache.invalidateElements(eles); + slbTxrCache.invalidateElements(eles); + tlbTxrCache.invalidateElements(eles); + + // any change invalidates the layers + lyrTxrCache.invalidateElements(eles); + + // update the old bg timestamp so diffs can be done in the ele txr caches + for (var _i = 0; _i < eles.length; _i++) { + var _p = eles[_i]._private; + _p.oldBackgroundTimestamp = _p.backgroundTimestamp; + } + }); + var refineInLayers = function refineInLayers(reqs) { + for (var i = 0; i < reqs.length; i++) { + lyrTxrCache.enqueueElementRefinement(reqs[i].ele); + } + }; + eleTxrCache.onDequeue(refineInLayers); + lblTxrCache.onDequeue(refineInLayers); + slbTxrCache.onDequeue(refineInLayers); + tlbTxrCache.onDequeue(refineInLayers); + } + CRp.redrawHint = function (group, bool) { + var r = this; + switch (group) { + case 'eles': + r.data.canvasNeedsRedraw[CRp.NODE] = bool; + break; + case 'drag': + r.data.canvasNeedsRedraw[CRp.DRAG] = bool; + break; + case 'select': + r.data.canvasNeedsRedraw[CRp.SELECT_BOX] = bool; + break; + } + }; - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - center: [ this.center.x, this.center.y ], - rotation: this.rotation, + // whether to use Path2D caching for drawing + var pathsImpld = typeof Path2D !== 'undefined'; + CRp.path2dEnabled = function (on) { + if (on === undefined) { + return this.pathsEnabled; + } + this.pathsEnabled = on ? true : false; + }; + CRp.usePaths = function () { + return pathsImpld && this.pathsEnabled; + }; + CRp.setImgSmoothing = function (context, bool) { + if (context.imageSmoothingEnabled != null) { + context.imageSmoothingEnabled = bool; + } else { + context.webkitImageSmoothingEnabled = bool; + context.mozImageSmoothingEnabled = bool; + context.msImageSmoothingEnabled = bool; + } + }; + CRp.getImgSmoothing = function (context) { + if (context.imageSmoothingEnabled != null) { + return context.imageSmoothingEnabled; + } else { + return context.webkitImageSmoothingEnabled || context.mozImageSmoothingEnabled || context.msImageSmoothingEnabled; + } + }; + CRp.makeOffscreenCanvas = function (width, height) { + var canvas; + if ((typeof OffscreenCanvas === "undefined" ? "undefined" : _typeof(OffscreenCanvas)) !== ("undefined" )) { + canvas = new OffscreenCanvas(width, height); + } else { + canvas = document.createElement('canvas'); // eslint-disable-line no-undef + canvas.width = width; + canvas.height = height; + } + return canvas; + }; + [CRp$a, CRp$9, CRp$8, CRp$7, CRp$6, CRp$5, CRp$4, CRp$3, CRp$2, CRp$1].forEach(function (props) { + extend$1(CRp, props); + }); - wrap: [ this.wrapS, this.wrapT ], + var renderer = [{ + name: 'null', + impl: NullRenderer + }, { + name: 'base', + impl: BR + }, { + name: 'canvas', + impl: CR + }]; + + var incExts = [{ + type: 'layout', + extensions: layout + }, { + type: 'renderer', + extensions: renderer + }]; + + // registered extensions to cytoscape, indexed by name + var extensions = {}; + + // registered modules for extensions, indexed by name + var modules = {}; + function setExtension(type, name, registrant) { + var ext = registrant; + var overrideErr = function overrideErr(field) { + warn('Can not register `' + name + '` for `' + type + '` since `' + field + '` already exists in the prototype and can not be overridden'); + }; + if (type === 'core') { + if (Core.prototype[name]) { + return overrideErr(name); + } else { + Core.prototype[name] = registrant; + } + } else if (type === 'collection') { + if (Collection.prototype[name]) { + return overrideErr(name); + } else { + Collection.prototype[name] = registrant; + } + } else if (type === 'layout') { + // fill in missing layout functions in the prototype + + var Layout = function Layout(options) { + this.options = options; + registrant.call(this, options); + + // make sure layout has _private for use w/ std apis like .on() + if (!plainObject(this._private)) { + this._private = {}; + } + this._private.cy = options.cy; + this._private.listeners = []; + this.createEmitter(); + }; + var layoutProto = Layout.prototype = Object.create(registrant.prototype); + var optLayoutFns = []; + for (var i = 0; i < optLayoutFns.length; i++) { + var fnName = optLayoutFns[i]; + layoutProto[fnName] = layoutProto[fnName] || function () { + return this; + }; + } - format: this.format, - type: this.type, - encoding: this.encoding, + // either .start() or .run() is defined, so autogen the other + if (layoutProto.start && !layoutProto.run) { + layoutProto.run = function () { + this.start(); + return this; + }; + } else if (!layoutProto.start && layoutProto.run) { + layoutProto.start = function () { + this.run(); + return this; + }; + } + var regStop = registrant.prototype.stop; + layoutProto.stop = function () { + var opts = this.options; + if (opts && opts.animate) { + var anis = this.animations; + if (anis) { + for (var _i = 0; _i < anis.length; _i++) { + anis[_i].stop(); + } + } + } + if (regStop) { + regStop.call(this); + } else { + this.emit('layoutstop'); + } + return this; + }; + if (!layoutProto.destroy) { + layoutProto.destroy = function () { + return this; + }; + } + layoutProto.cy = function () { + return this._private.cy; + }; + var getCy = function getCy(layout) { + return layout._private.cy; + }; + var emitterOpts = { + addEventFields: function addEventFields(layout, evt) { + evt.layout = layout; + evt.cy = getCy(layout); + evt.target = layout; + }, + bubble: function bubble() { + return true; + }, + parent: function parent(layout) { + return getCy(layout); + } + }; + extend$1(layoutProto, { + createEmitter: function createEmitter() { + this._private.emitter = new Emitter(emitterOpts, this); + return this; + }, + emitter: function emitter() { + return this._private.emitter; + }, + on: function on(evt, cb) { + this.emitter().on(evt, cb); + return this; + }, + one: function one(evt, cb) { + this.emitter().one(evt, cb); + return this; + }, + once: function once(evt, cb) { + this.emitter().one(evt, cb); + return this; + }, + removeListener: function removeListener(evt, cb) { + this.emitter().removeListener(evt, cb); + return this; + }, + removeAllListeners: function removeAllListeners() { + this.emitter().removeAllListeners(); + return this; + }, + emit: function emit(evt, params) { + this.emitter().emit(evt, params); + return this; + } + }); + define.eventAliasesOn(layoutProto); + ext = Layout; // replace with our wrapped layout + } else if (type === 'renderer' && name !== 'null' && name !== 'base') { + // user registered renderers inherit from base + + var BaseRenderer = getExtension('renderer', 'base'); + var bProto = BaseRenderer.prototype; + var RegistrantRenderer = registrant; + var rProto = registrant.prototype; + var Renderer = function Renderer() { + BaseRenderer.apply(this, arguments); + RegistrantRenderer.apply(this, arguments); + }; + var proto = Renderer.prototype; + for (var pName in bProto) { + var pVal = bProto[pName]; + var existsInR = rProto[pName] != null; + if (existsInR) { + return overrideErr(pName); + } + proto[pName] = pVal; // take impl from base + } - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, + for (var _pName in rProto) { + proto[_pName] = rProto[_pName]; // take impl from registrant + } - flipY: this.flipY, + bProto.clientFunctions.forEach(function (name) { + proto[name] = proto[name] || function () { + error('Renderer does not implement `renderer.' + name + '()` on its prototype'); + }; + }); + ext = Renderer; + } else if (type === '__proto__' || type === 'constructor' || type === 'prototype') { + // to avoid potential prototype pollution + return error(type + ' is an illegal type to be registered, possibly lead to prototype pollutions'); + } + return setMap({ + map: extensions, + keys: [type, name], + value: ext + }); + } + function getExtension(type, name) { + return getMap({ + map: extensions, + keys: [type, name] + }); + } + function setModule(type, name, moduleType, moduleName, registrant) { + return setMap({ + map: modules, + keys: [type, name, moduleType, moduleName], + value: registrant + }); + } + function getModule(type, name, moduleType, moduleName) { + return getMap({ + map: modules, + keys: [type, name, moduleType, moduleName] + }); + } + var extension = function extension() { + // e.g. extension('renderer', 'svg') + if (arguments.length === 2) { + return getExtension.apply(null, arguments); + } - premultiplyAlpha: this.premultiplyAlpha, - unpackAlignment: this.unpackAlignment + // e.g. extension('renderer', 'svg', { ... }) + else if (arguments.length === 3) { + return setExtension.apply(null, arguments); + } - }; + // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse') + else if (arguments.length === 4) { + return getModule.apply(null, arguments); + } - if ( JSON.stringify( this.userData ) !== '{}' ) output.userData = this.userData; + // e.g. extension('renderer', 'svg', 'nodeShape', 'ellipse', { ... }) + else if (arguments.length === 5) { + return setModule.apply(null, arguments); + } else { + error('Invalid extension access syntax'); + } + }; - if ( ! isRootObject ) { + // allows a core instance to access extensions internally + Core.prototype.extension = extension; - meta.textures[ this.uuid ] = output; + // included extensions + incExts.forEach(function (group) { + group.extensions.forEach(function (ext) { + setExtension(group.type, ext.name, ext.impl); + }); + }); - } + // a dummy stylesheet object that doesn't need a reference to the core + // (useful for init) + var Stylesheet = function Stylesheet() { + if (!(this instanceof Stylesheet)) { + return new Stylesheet(); + } + this.length = 0; + }; + var sheetfn = Stylesheet.prototype; + sheetfn.instanceString = function () { + return 'stylesheet'; + }; - return output; + // just store the selector to be parsed later + sheetfn.selector = function (selector) { + var i = this.length++; + this[i] = { + selector: selector, + properties: [] + }; + return this; // chaining + }; - } + // just store the property to be parsed later + sheetfn.css = function (name, value) { + var i = this.length - 1; + if (string(name)) { + this[i].properties.push({ + name: name, + value: value + }); + } else if (plainObject(name)) { + var map = name; + var propNames = Object.keys(map); + for (var j = 0; j < propNames.length; j++) { + var key = propNames[j]; + var mapVal = map[key]; + if (mapVal == null) { + continue; + } + var prop = Style.properties[key] || Style.properties[dash2camel(key)]; + if (prop == null) { + continue; + } + var _name = prop.name; + var _value = mapVal; + this[i].properties.push({ + name: _name, + value: _value + }); + } + } + return this; // chaining + }; - dispose() { + sheetfn.style = sheetfn.css; - this.dispatchEvent( { type: 'dispose' } ); + // generate a real style object from the dummy stylesheet + sheetfn.generateStyle = function (cy) { + var style = new Style(cy); + return this.appendToStyle(style); + }; - } + // append a dummy stylesheet object on a real style object + sheetfn.appendToStyle = function (style) { + for (var i = 0; i < this.length; i++) { + var context = this[i]; + var selector = context.selector; + var props = context.properties; + style.selector(selector); // apply selector + + for (var j = 0; j < props.length; j++) { + var prop = props[j]; + style.css(prop.name, prop.value); // apply property + } + } - transformUv( uv ) { + return style; + }; - if ( this.mapping !== UVMapping ) return uv; + var version = "3.29.2"; - uv.applyMatrix3( this.matrix ); + var cytoscape = function cytoscape(options) { + // if no options specified, use default + if (options === undefined) { + options = {}; + } - if ( uv.x < 0 || uv.x > 1 ) { + // create instance + if (plainObject(options)) { + return new Core(options); + } - switch ( this.wrapS ) { + // allow for registration of extensions + else if (string(options)) { + return extension.apply(extension, arguments); + } + }; - case RepeatWrapping: + // e.g. cytoscape.use( require('cytoscape-foo'), bar ) + cytoscape.use = function (ext) { + var args = Array.prototype.slice.call(arguments, 1); // args to pass to ext - uv.x = uv.x - Math.floor( uv.x ); - break; + args.unshift(cytoscape); // cytoscape is first arg to ext - case ClampToEdgeWrapping: + ext.apply(null, args); + return this; + }; + cytoscape.warnings = function (bool) { + return warnings(bool); + }; - uv.x = uv.x < 0 ? 0 : 1; - break; + // replaced by build system + cytoscape.version = version; - case MirroredRepeatWrapping: + // expose public apis (mostly for extensions) + cytoscape.stylesheet = cytoscape.Stylesheet = Stylesheet; - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - uv.x = Math.ceil( uv.x ) - uv.x; + function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } - } else { + function commonjsRequire(path) { + throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); + } - uv.x = uv.x - Math.floor( uv.x ); + var jszip_min = {exports: {}}; - } + /*! - break; + JSZip v3.10.1 - A JavaScript class for generating and reading zip files + - } + (c) 2009-2016 Stuart Knightley + Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown. - } + JSZip uses the library pako released under the MIT license : + https://github.com/nodeca/pako/blob/main/LICENSE + */ - if ( uv.y < 0 || uv.y > 1 ) { + (function (module, exports) { + !function(e){module.exports=e();}(function(){return function s(a,o,h){function u(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof commonjsRequire&&commonjsRequire;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return u(t||e)},i,i.exports,s,a,o,h);}return o[r].exports}for(var l="function"==typeof commonjsRequire&&commonjsRequire,e=0;e>2,s=(3&t)<<4|r>>4,a=1>6:64,o=2>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),l[h++]=t,64!==s&&(l[h++]=r),64!==a&&(l[h++]=n);return l};},{"./support":30,"./utils":32}],2:[function(e,t,r){var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i;}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o;},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate");},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){var n=e("./utils");var o=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e;}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return -1^e}(0|t,e,e.length,0):function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t.charCodeAt(a))];return -1^e}(0|t,e,e.length,0):0};},{"./utils":32}],5:[function(e,t,r){r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null;},{}],6:[function(e,t,r){var n=null;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n};},{lie:37}],7:[function(e,t,r){var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function h(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={};}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1);},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0);},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null;},h.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta});};},r.compressWorker=function(e){return new h("Deflate",e)},r.uncompressWorker=function(){return new h("Inflate",{})};},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,r){function A(e,t){var r,n="";for(r=0;r>>=8;return n}function n(e,t,r,n,i,s){var a,o,h=e.file,u=e.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),c=I.transformTo("string",O.utf8encode(h.name)),d=h.comment,p=I.transformTo("string",s(d)),m=I.transformTo("string",O.utf8encode(d)),_=c.length!==h.name.length,g=m.length!==d.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};t&&!r||(x.crc32=e.crc32,x.compressedSize=e.compressedSize,x.uncompressedSize=e.uncompressedSize);var S=0;t&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===i?(C=798,z|=function(e,t){var r=e;return e||(r=t?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(e){return 63&(e||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+c,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(n,4)+f+b+p}}var I=e("../utils"),i=e("../stream/GenericWorker"),O=e("../utf8"),B=e("../crc32"),R=e("../signature");function s(e,t,r,n){i.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=t,this.zipPlatform=r,this.encodeFileName=n,this.streamFiles=e,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[];}I.inherits(s,i),s.prototype.push=function(e){var t=e.meta.percent||0,r=this.entriesCount,n=this._sources.length;this.accumulate?this.contentBuffer.push(e):(this.bytesWritten+=e.data.length,i.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:r?(t+100*(r-n-1))/r:100}}));},s.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten,this.currentFile=e.file.name;var t=this.streamFiles&&!e.file.dir;if(t){var r=n(e,t,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}});}else this.accumulate=!0;},s.prototype.closedSource=function(e){this.accumulate=!1;var t=this.streamFiles&&!e.file.dir,r=n(e,t,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),t)this.push({data:function(e){return R.DATA_DESCRIPTOR+A(e.crc32,4)+A(e.compressedSize,4)+A(e.uncompressedSize,4)}(e),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null;},s.prototype.flush=function(){for(var e=this.bytesWritten,t=0;t=this.index;t--)r=(r<<8)+this.byteAt(t);return this.index+=e,r},readString:function(e){return n.transformTo("string",this.readData(e))},readData:function(){},lastIndexOfSignature:function(){},readAndCheckSignature:function(){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC(1980+(e>>25&127),(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(31&e)<<1))}},t.exports=i;},{"../utils":32}],19:[function(e,t,r){var n=e("./Uint8ArrayReader");function i(e){n.call(this,e);}e("../utils").inherits(i,n),i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i;},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){var n=e("./DataReader");function i(e){n.call(this,e);}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i;},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){var n=e("./ArrayReader");function i(e){n.call(this,e);}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i;},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),h=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new h(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)};},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b";},{}],24:[function(e,t,r){var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e;}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta});},t.exports=s;},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0);}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e);},t.exports=s;},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0);}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length;}i.prototype.processChunk.call(this,e);},t.exports=s;},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat();},function(e){t.error(e);});}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null;},s.prototype.resume=function(){return !!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0));},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return !1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t);}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s;},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null;}n.prototype={push:function(e){this.emit("data",e);},end:function(){if(this.isFinished)return !1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0;}catch(e){this.emit("error",e);}return !0},error:function(e){return !this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[];},emit:function(e,t){if(this._listeners[e])for(var r=0;r "+e:e}},t.exports=n;},{}],29:[function(e,t,r){var h=e("../utils"),i=e("./ConvertWorker"),s=e("./GenericWorker"),u=e("../base64"),n=e("../support"),a=e("../external"),o=null;if(n.nodestream)try{o=e("../nodejs/NodejsStreamOutputAdapter");}catch(e){}function l(e,o){return new a.Promise(function(t,r){var n=[],i=e._internalType,s=e._outputType,a=e._mimeType;e.on("data",function(e,t){n.push(e),o&&o(t);}).on("error",function(e){n=[],r(e);}).on("end",function(){try{var e=function(e,t,r){switch(e){case"blob":return h.newBlob(h.transformTo("arraybuffer",t),r);case"base64":return u.encode(t);default:return h.transformTo(e,t)}}(s,function(e,t){var r,n=0,i=null,s=0;for(r=0;r>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t}(e)},s.utf8decode=function(e){return h.nodebuffer?o.transformTo("nodebuffer",e).toString("utf-8"):function(e){var t,r,n,i,s=e.length,a=new Array(2*s);for(t=r=0;t>10&1023,a[r++]=56320|1023&n);}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(h.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length);}else t=this.leftOver.concat(t);this.leftOver=null;}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}(t),i=t;n!==t.length&&(h.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta});},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null);},s.Utf8DecodeWorker=a,o.inherits(l,n),l.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta});},s.Utf8EncodeWorker=l;},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,a){var o=e("./support"),h=e("./base64"),r=e("./nodejsUtils"),u=e("./external");function n(e){return e}function l(e,t){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0);},parseZIP64ExtraField:function(){if(this.extraFields[1]){var e=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4));}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t},r.buf2binstring=function(e){return l(e,e.length)},r.binstring2buf=function(e){for(var t=new h.Buf8(e.length),r=0,n=t.length;r>10&1023,o[n++]=56320|1023&i);}return l(o,n)},r.utf8border=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t};},{"./common":41}],43:[function(e,t,r){t.exports=function(e,t,r,n){for(var i=65535&e|0,s=e>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:e>>>1;t[r]=e;}return t}();t.exports=function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return -1^e};},{}],46:[function(e,t,r){var h,c=e("../utils/common"),u=e("./trees"),d=e("./adler32"),p=e("./crc32"),n=e("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,i=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(e,t){return e.msg=n[t],t}function T(e){return (e<<1)-(4e.avail_out&&(r=e.avail_out),0!==r&&(c.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0));}function N(e,t){u._tr_flush_block(e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,F(e.strm);}function U(e,t){e.pending_buf[e.pending++]=t;}function P(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t;}function L(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,h=e.strstart>e.w_size-z?e.strstart-(e.w_size-z):0,u=e.window,l=e.w_mask,f=e.prev,c=e.strstart+S,d=u[s+a-1],p=u[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(u[(r=t)+a]===p&&u[r+a-1]===d&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--i);return a<=e.lookahead?a:e.lookahead}function j(e){var t,r,n,i,s,a,o,h,u,l,f=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-z)){for(c.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;n=e.head[--t],e.head[t]=f<=n?n-f:0,--r;);for(t=r=f;n=e.prev[--t],e.prev[t]=f<=n?n-f:0,--r;);i+=f;}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,h=e.strstart+e.lookahead,u=i,l=void 0,l=a.avail_in,u=x)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x)if(n=u._tr_tally(e,e.strstart-e.match_start,e.match_length-x),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=x){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-x,n=u._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-x),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(j(e),0===e.lookahead&&t===l)return A;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+r;if((0===e.strstart||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,N(e,!1),0===e.strm.avail_out))return A;if(e.strstart-e.block_start>=e.w_size-z&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):(e.strstart>e.block_start&&(N(e,!1),e.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(e,t){return Y(e,t,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?_:(e.state.gzhead=t,m):_},r.deflate=function(e,t){var r,n,i,s;if(!e||!e.state||5>8&255),U(n,n.gzhead.time>>16&255),U(n,n.gzhead.time>>24&255),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(U(n,255&n.gzhead.extra.length),U(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=p(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(U(n,0),U(n,0),U(n,0),U(n,0),U(n,0),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,3),n.status=E);else {var a=v+(n.w_bits-8<<4)<<8;a|=(2<=n.strategy||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(a|=32),a+=31-a%31,n.status=E,P(n,a),0!==n.strstart&&(P(n,e.adler>>>16),P(n,65535&e.adler)),e.adler=1;}if(69===n.status)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending!==n.pending_buf_size));)U(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73);}else n.status=73;if(73===n.status)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.gzindex=0,n.status=91);}else n.status=91;if(91===n.status)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103);}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&F(e),n.pending+2<=n.pending_buf_size&&(U(n,255&e.adler),U(n,e.adler>>8&255),e.adler=0,n.status=E)):n.status=E),0!==n.pending){if(F(e),0===e.avail_out)return n.last_flush=-1,m}else if(0===e.avail_in&&T(t)<=T(r)&&t!==f)return R(e,-5);if(666===n.status&&0!==e.avail_in)return R(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==l&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(j(e),0===e.lookahead)){if(t===l)return A;break}if(e.match_length=0,r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=S){if(j(e),e.lookahead<=S&&t===l)return A;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=x&&0e.lookahead&&(e.match_length=e.lookahead);}if(e.match_length>=x?(r=u._tr_tally(e,1,e.match_length-x),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):h[n.level].func(n,t);if(o!==O&&o!==B||(n.status=666),o===A||o===O)return 0===e.avail_out&&(n.last_flush=-1),m;if(o===I&&(1===t?u._tr_align(n):5!==t&&(u._tr_stored_block(n,0,0,!1),3===t&&(D(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),F(e),0===e.avail_out))return n.last_flush=-1,m}return t!==f?m:n.wrap<=0?1:(2===n.wrap?(U(n,255&e.adler),U(n,e.adler>>8&255),U(n,e.adler>>16&255),U(n,e.adler>>24&255),U(n,255&e.total_in),U(n,e.total_in>>8&255),U(n,e.total_in>>16&255),U(n,e.total_in>>24&255)):(P(n,e.adler>>>16),P(n,65535&e.adler)),F(e),0=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new c.Buf8(r.w_size),c.arraySet(u,t,l-r.w_size,r.w_size,0),t=u,l=r.w_size),a=e.avail_in,o=e.next_in,h=e.input,e.avail_in=l,e.next_in=0,e.input=t,j(r);r.lookahead>=x;){for(n=r.strstart,i=r.lookahead-(x-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else {if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(d&(1<>>=y,p-=y),p<15&&(d+=z[n++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(d&(1<>>=y,p-=y,(y=s-a)>3,d&=(1<<(p-=w<<3))-1,e.next_in=n,e.next_out=s,e.avail_in=n>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0;}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=P,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new I.Buf32(n),t.distcode=t.distdyn=new I.Buf32(i),t.sane=1,t.back=-1,N):U}function o(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,a(e)):U}function h(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||15=s.wsize?(I.arraySet(s.window,t,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(n<(i=s.wsize-s.wnext)&&(i=n),I.arraySet(s.window,t,r-n,i,s.wnext),(n-=i)?(I.arraySet(s.window,t,r-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=i,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){e.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0;}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(d=r.length)&&(d=o),d&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,n,s,d,k)),512&r.flags&&(r.check=B(r.check,n,d,s)),o-=d,s+=d,r.length-=d),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(d=0;k=n[s+d++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&d>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break e;o--,u+=n[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;u>>>=2,l-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30;}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break e;o--,u+=n[s++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(d=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3;}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=_,l-=_,r.lens[r.have++]=b;else {if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],d=3+(3&u),u>>>=2,l-=2;}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3;}else {for(z=_+7;l>>=_)),u>>>=7,l-=7;}if(r.have+d>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;d--;)r.lens[r.have++]=k;}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=h){e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,R(e,c),a=e.next_out,i=e.output,h=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v;}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra;}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v;}if(u>>>=_,l-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra;}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break e;if(d=c-h,r.offset>d){if((d=r.offset-d)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}p=d>r.wnext?(d-=r.wnext,r.wsize-d):r.wnext-d,d>r.length&&(d=r.length),m=r.window;}else m=i,p=a-r.offset,d=r.length;for(hd?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=t[r+a[v]];}if(k>>7)]}function U(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255;}function P(e,t,r){e.bi_valid>d-r?(e.bi_buf|=t<>d-e.bi_valid,e.bi_valid+=r-d):(e.bi_buf|=t<>>=1,r<<=1,0<--t;);return r>>>1}function Z(e,t,r){var n,i,s=new Array(g+1),a=0;for(n=1;n<=g;n++)s[n]=a=a+r[n-1]<<1;for(i=0;i<=t;i++){var o=e[2*i+1];0!==o&&(e[2*i]=j(s[o]++,o));}}function W(e){var t;for(t=0;t>1;1<=r;r--)G(e,s,r);for(i=h;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],G(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,G(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,h=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,f=t.stat_desc.has_stree,c=t.stat_desc.extra_bits,d=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=g;s++)e.bl_count[s]=0;for(h[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<_;r++)p<(s=h[2*h[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),h[2*n+1]=s,u>=7;n>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return o;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return h;for(t=32;t>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?J(e,t,r,n):4===e.strategy||s===i?(P(e,2+(n?1:0),3),K(e,z,C)):(P(e,4+(n?1:0),3),function(e,t,r,n){var i;for(P(e,t-257,5),P(e,r-1,5),P(e,n-4,4),i=0;i>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(A[r]+u+1)]++,e.dyn_dtree[2*N(t)]++),e.last_lit===e.lit_bufsize-1},r._tr_align=function(e){P(e,2,3),L(e,m,z),function(e){16===e.bi_valid?(U(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):8<=e.bi_valid&&(e.pending_buf[e.pending++]=255&e.bi_buf,e.bi_buf>>=8,e.bi_valid-=8);}(e);};},{"../utils/common":41}],53:[function(e,t,r){t.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0;};},{}],54:[function(e,t,r){(function(e){!function(r,n){if(!r.setImmediate){var i,s,t,a,o=1,h={},u=!1,l=r.document,e=Object.getPrototypeOf&&Object.getPrototypeOf(r);e=e&&e.setTimeout?e:r,i="[object process]"==={}.toString.call(r.process)?function(e){process.nextTick(function(){c(e);});}:function(){if(r.postMessage&&!r.importScripts){var e=!0,t=r.onmessage;return r.onmessage=function(){e=!1;},r.postMessage("","*"),r.onmessage=t,e}}()?(a="setImmediate$"+Math.random()+"$",r.addEventListener?r.addEventListener("message",d,!1):r.attachEvent("onmessage",d),function(e){r.postMessage(a+e,"*");}):r.MessageChannel?((t=new MessageChannel).port1.onmessage=function(e){c(e.data);},function(e){t.port2.postMessage(e);}):l&&"onreadystatechange"in l.createElement("script")?(s=l.documentElement,function(e){var t=l.createElement("script");t.onreadystatechange=function(){c(e),t.onreadystatechange=null,s.removeChild(t),t=null;},s.appendChild(t);}):function(e){setTimeout(c,0,e);},e.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),r=0;r /*select0_change_handler*/ ctx[29].call(select0)); + add_location(select0, file$l, 1448, 8, 54721); + add_location(button9, file$l, 1454, 8, 55053); + add_location(br12, file$l, 1457, 8, 55152); + add_location(br13, file$l, 1457, 13, 55157); + attr_dev(input5, "type", "text"); + attr_dev(input5, "placeholder", "Edge ID"); + add_location(input5, file$l, 1459, 8, 55191); + option3.__value = ""; + option3.value = option3.__value; + option3.disabled = true; + option3.selected = true; + add_location(option3, file$l, 1461, 12, 55316); + if (/*newEdgeSource*/ ctx[6] === void 0) add_render_callback(() => /*select1_change_handler*/ ctx[31].call(select1)); + add_location(select1, file$l, 1460, 8, 55267); + option4.__value = ""; + option4.value = option4.__value; + option4.disabled = true; + option4.selected = true; + add_location(option4, file$l, 1467, 12, 55566); + if (/*newEdgeTarget*/ ctx[7] === void 0) add_render_callback(() => /*select2_change_handler*/ ctx[32].call(select2)); + add_location(select2, file$l, 1466, 8, 55517); + add_location(button10, file$l, 1472, 8, 55767); + add_location(br14, file$l, 1474, 8, 55831); + add_location(br15, file$l, 1474, 13, 55836); + add_location(button11, file$l, 1475, 8, 55850); + add_location(br16, file$l, 1477, 8, 55954); + add_location(div3, file$l, 1444, 4, 54528); + attr_dev(div4, "class", "grid-Container svelte-gj972u"); + add_location(div4, file$l, 1416, 0, 52826); + attr_dev(div5, "id", "cy"); + attr_dev(div5, "class", "svelte-gj972u"); + add_location(div5, file$l, 1481, 0, 56004); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div0, anchor); + append_dev(div0, t0); + append_dev(div0, br0); + append_dev(div0, t1); + append_dev(div0, br1); + append_dev(div0, t2); + append_dev(div0, button0); + insert_dev(target, t4, anchor); + insert_dev(target, div4, anchor); + append_dev(div4, div1); + append_dev(div1, t5); + append_dev(div1, input0); + append_dev(div1, t6); + append_dev(div1, br2); + append_dev(div1, t7); + append_dev(div1, br3); + append_dev(div1, t8); + append_dev(div1, button1); + append_dev(div1, t10); + append_dev(div1, button2); + append_dev(div1, t12); + append_dev(div1, br4); + append_dev(div1, br5); + append_dev(div1, t13); + append_dev(div1, button3); + append_dev(div1, t15); + append_dev(div1, hr); + append_dev(div1, t16); + append_dev(div1, button4); + append_dev(div1, t18); + append_dev(div1, button5); + append_dev(div1, t20); + append_dev(div1, br6); + append_dev(div1, br7); + append_dev(div1, t21); + append_dev(div1, input1); + set_input_value(input1, /*autonodes*/ ctx[8]); + append_dev(div1, t22); + append_dev(div1, input2); + set_input_value(input2, /*autoedges*/ ctx[9]); + append_dev(div1, t23); + append_dev(div1, button6); + append_dev(div4, t25); + append_dev(div4, div2); + append_dev(div2, t26); + append_dev(div2, br8); + append_dev(div2, t27); + append_dev(div2, br9); + append_dev(div2, t28); + append_dev(div2, button7); + append_dev(div2, t30); + append_dev(div2, textarea); + set_input_value(textarea, /*currentautoGeneratedGraphDataAugmented*/ ctx[10]); + append_dev(div2, t31); + append_dev(div2, br10); + append_dev(div2, t32); + append_dev(div2, button8); + append_dev(div2, t34); + append_dev(div2, br11); + append_dev(div2, t35); + append_dev(div4, t36); + append_dev(div4, div3); + append_dev(div3, t37); + append_dev(div3, input3); + set_input_value(input3, /*newNodeId*/ ctx[2]); + append_dev(div3, t38); + append_dev(div3, input4); + set_input_value(input4, /*newNodeLabel*/ ctx[3]); + append_dev(div3, t39); + append_dev(div3, select0); + append_dev(select0, option0); + append_dev(select0, option1); + append_dev(select0, option2); + select_option(select0, /*newNodeType*/ ctx[4], true); + append_dev(div3, t43); + append_dev(div3, button9); + append_dev(div3, t45); + append_dev(div3, br12); + append_dev(div3, t46); + append_dev(div3, br13); + append_dev(div3, t47); + append_dev(div3, input5); + set_input_value(input5, /*newEdgeId*/ ctx[5]); + append_dev(div3, t48); + append_dev(div3, select1); + append_dev(select1, option3); - setScalar( scalar ) { + for (let i = 0; i < each_blocks_1.length; i += 1) { + if (each_blocks_1[i]) { + each_blocks_1[i].m(select1, null); + } + } - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; + select_option(select1, /*newEdgeSource*/ ctx[6], true); + append_dev(div3, t50); + append_dev(div3, select2); + append_dev(select2, option4); - return this; + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(select2, null); + } + } - } + select_option(select2, /*newEdgeTarget*/ ctx[7], true); + append_dev(div3, t52); + append_dev(div3, button10); + append_dev(div3, t54); + append_dev(div3, br14); + append_dev(div3, t55); + append_dev(div3, br15); + append_dev(div3, t56); + append_dev(div3, button11); + append_dev(div3, t58); + append_dev(div3, br16); + append_dev(div3, t59); + insert_dev(target, t60, anchor); + insert_dev(target, div5, anchor); + /*div5_binding*/ ctx[33](div5); - setX( x ) { + if (!mounted) { + dispose = [ + listen_dev(button0, "click", /*click_handler*/ ctx[23], false, false, false, false), + listen_dev(input0, "change", /*loadGraph*/ ctx[16], false, false, false, false), + listen_dev(button1, "click", /*saveGraph*/ ctx[15], false, false, false, false), + listen_dev(button3, "click", /*resetGraph*/ ctx[21], false, false, false, false), + listen_dev(button4, "click", /*traverseAndGenerateStoryData*/ ctx[14], false, false, false, false), + listen_dev(button5, "click", /*generateAndLoadGraphData*/ ctx[17], false, false, false, false), + listen_dev(input1, "input", /*input1_input_handler*/ ctx[24]), + listen_dev(input2, "input", /*input2_input_handler*/ ctx[25]), + listen_dev(button6, "click", /*createAutoGenGraphdata*/ ctx[19], false, false, false, false), + listen_dev(button7, "click", /*copycurrentautoGeneratedGraphData*/ ctx[22], false, false, false, false), + listen_dev(textarea, "input", /*textarea_input_handler*/ ctx[26]), + listen_dev(button8, "click", /*createLinearPathAutoGenstoryload*/ ctx[20], false, false, false, false), + listen_dev(input3, "input", /*input3_input_handler*/ ctx[27]), + listen_dev(input4, "input", /*input4_input_handler*/ ctx[28]), + listen_dev(select0, "change", /*select0_change_handler*/ ctx[29]), + listen_dev(button9, "click", /*addNode*/ ctx[12], false, false, false, false), + listen_dev(input5, "input", /*input5_input_handler*/ ctx[30]), + listen_dev(select1, "change", /*select1_change_handler*/ ctx[31]), + listen_dev(select2, "change", /*select2_change_handler*/ ctx[32]), + listen_dev(button10, "click", /*addEdge*/ ctx[13], false, false, false, false), + listen_dev(button11, "click", /*createBranchingPathadditive*/ ctx[18], false, false, false, false) + ]; - this.x = x; + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*autonodes*/ 256 && to_number(input1.value) !== /*autonodes*/ ctx[8]) { + set_input_value(input1, /*autonodes*/ ctx[8]); + } - return this; + if (dirty[0] & /*autoedges*/ 512 && to_number(input2.value) !== /*autoedges*/ ctx[9]) { + set_input_value(input2, /*autoedges*/ ctx[9]); + } - } + if (dirty[0] & /*currentautoGeneratedGraphDataAugmented*/ 1024) { + set_input_value(textarea, /*currentautoGeneratedGraphDataAugmented*/ ctx[10]); + } - setY( y ) { + if (dirty[0] & /*newNodeId*/ 4 && input3.value !== /*newNodeId*/ ctx[2]) { + set_input_value(input3, /*newNodeId*/ ctx[2]); + } - this.y = y; + if (dirty[0] & /*newNodeLabel*/ 8 && input4.value !== /*newNodeLabel*/ ctx[3]) { + set_input_value(input4, /*newNodeLabel*/ ctx[3]); + } - return this; + if (dirty[0] & /*newNodeType*/ 16) { + select_option(select0, /*newNodeType*/ ctx[4]); + } - } + if (dirty[0] & /*newEdgeId*/ 32 && input5.value !== /*newEdgeId*/ ctx[5]) { + set_input_value(input5, /*newEdgeId*/ ctx[5]); + } - setZ( z ) { + if (dirty[0] & /*nodes*/ 2048) { + each_value_1 = /*nodes*/ ctx[11]; + validate_each_argument(each_value_1); + let i; - this.z = z; + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1$8(ctx, each_value_1, i); - return this; + if (each_blocks_1[i]) { + each_blocks_1[i].p(child_ctx, dirty); + } else { + each_blocks_1[i] = create_each_block_1$8(child_ctx); + each_blocks_1[i].c(); + each_blocks_1[i].m(select1, null); + } + } - } + for (; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].d(1); + } - setW( w ) { + each_blocks_1.length = each_value_1.length; + } - this.w = w; + if (dirty[0] & /*newEdgeSource, nodes*/ 2112) { + select_option(select1, /*newEdgeSource*/ ctx[6]); + } - return this; + if (dirty[0] & /*nodes*/ 2048) { + each_value = /*nodes*/ ctx[11]; + validate_each_argument(each_value); + let i; - } + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$f(ctx, each_value, i); - setComponent( index, value ) { + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$f(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(select2, null); + } + } - switch ( index ) { + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); + each_blocks.length = each_value.length; + } + if (dirty[0] & /*newEdgeTarget, nodes*/ 2176) { + select_option(select2, /*newEdgeTarget*/ ctx[7]); + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div0); + if (detaching) detach_dev(t4); + if (detaching) detach_dev(div4); + destroy_each(each_blocks_1, detaching); + destroy_each(each_blocks, detaching); + if (detaching) detach_dev(t60); + if (detaching) detach_dev(div5); + /*div5_binding*/ ctx[33](null); + mounted = false; + run_all(dispose); } + }; - return this; - - } + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$l.name, + type: "component", + source: "", + ctx + }); - getComponent( index ) { + return block; + } - switch ( index ) { + function autoGenerateGraphData(numNodes, numEdges) { + const nodeTypes = ['character', 'item', 'location']; + const characterNames = ['Alex', 'Elara', 'Draven', 'Luna', 'Orin']; - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); + const itemNames = [ + 'Ancient Relic', + 'Mystic Amulet', + 'Cursed Artifact', + 'Golden Sword', + 'Healing Potion' + ]; - } + const locationNames = ['Hidden Temple', 'Village of Eldoria', 'Ancient Ruins']; + const nodes = []; + const edges = []; + const usedEdges = new Set(); + function getRandomItem(arr) { + return arr[Math.floor(Math.random() * arr.length)]; } - clone() { + function generateNode(id) { + const type = getRandomItem(nodeTypes); + let label; - return new this.constructor( this.x, this.y, this.z, this.w ); + if (type === 'character') { + label = getRandomItem(characterNames); + } else if (type === 'item') { + label = getRandomItem(itemNames); + } else { + label = getRandomItem(locationNames); + } + return { data: { id, label, type, degree: 0 } }; } - copy( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; - - return this; - + function generateEdge(id, source, target) { + return { data: { id, source, target } }; } - add( v ) { - - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; - - return this; - + // Generate unique node IDs + for (let i = 1; i <= numNodes; i++) { + nodes.push(generateNode(`node${i}`)); } - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; - this.w += s; + // Generate unique edges + for (let i = 1; i <= numEdges; i++) { + let source, target, edgeId; - return this; + do { + source = getRandomItem(nodes).data.id; + target = getRandomItem(nodes).data.id; + edgeId = `edge${i}`; + } while (source === target || usedEdges.has(`${source}-${target}`)); + usedEdges.add(`${source}-${target}`); + edges.push(generateEdge(edgeId, source, target)); } - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; + return { nodes, edges }; + } - return this; + function generateTimelineinGraph(nNodes, nEdges) { + const nodes = []; + const edges = []; + // Generate nodes + for (let i = 0; i < nNodes; i++) { + nodes.push({ + data: { + id: String.fromCharCode(65 + i), // Generate ID as A, B, C, ... + label: `Event ${i + 1}`, + type: 'event', + degree: i + 1 + } + }); } - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - this.w += v.w * s; + // Generate edges + for (let i = 0; i < nEdges; i++) { + const sourceIndex = Math.floor(Math.random() * nNodes); + let targetIndex = Math.floor(Math.random() * nNodes); - return this; + // Ensure target is different from source + while (targetIndex === sourceIndex) { + targetIndex = Math.floor(Math.random() * nNodes); + } + edges.push({ + data: { + id: `edge${i + 1}`, + source: String.fromCharCode(65 + sourceIndex), + target: String.fromCharCode(65 + targetIndex) + } + }); } - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; - - return this; + return { nodes, edges }; + } - } + function createStoryParts(graphData) { + const nodeMap = new Map(); + console.log(graphData); - subScalar( s ) { + graphData.nodes.forEach((node, index) => { + nodeMap.set(node.data.id, { ...node.data, part: index }); + }); - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; + const story = graphData.edges.map((edge, index) => { + const sourceNode = nodeMap.get(edge.data.source); - return this; + return { + part: index, + objectives: [], + targets: [ + { + name: `placeholder ${index}`, + x: 500, + y: 400, + collisionType: "alert", + collisiontext: sourceNode.label + } + ], + actions: {} + }; + }); - } + return { story }; + } - subVectors( a, b ) { + function GraphtoJSONConfig() { + const storyJSONgraphdata = generateTimelineinGraph(7, 10); + const storyJSON = createStoryParts(storyJSONgraphdata); //.nodes, storyJSONgraphdata.edges); + console.log(storyJSONgraphdata); + console.log(storyJSON); + } - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; + function createStateMachine(graphData) { + const nodes = new Map(); - return this; + graphData.nodes.forEach(node => { + nodes.set(node.data.id, { + id: node.data.id, + label: node.data.label, + type: node.data.type, + degree: node.data.degree, + transitions: [] + }); + }); - } + // Add transitions from edges + graphData.edges.forEach(edge => { + const sourceNode = nodes.get(edge.data.source); + const targetNode = nodes.get(edge.data.target); - multiply( v ) { + sourceNode.transitions.push({ + label: `To ${targetNode.label}`, + action: targetNode.id, + collisionType: "alert", + collisiontext: `Transition from ${sourceNode.label} to ${targetNode.label}` + }); + }); - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - this.w *= v.w; + // Define the linear progression + const linearOrder = graphData.nodes.map(node => node.data.id); - return this; + // Add default transitions for linear progression + for (let i = 0; i < linearOrder.length - 1; i++) { + const currentNode = nodes.get(linearOrder[i]); + const nextNode = nodes.get(linearOrder[i + 1]); + currentNode.transitions.push({ + label: `Next: ${nextNode.label}`, + action: nextNode.id, + collisionType: "alert", + collisiontext: `Default transition from ${currentNode.label} to ${nextNode.label}` + }); } - multiplyScalar( scalar ) { + const modalStates = {}; - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + nodes.forEach(node => { + const state = { + title: node.label, + content: `You are at ${node.label}. What would you like to do next?`, + items: node.transitions.map(transition => ({ + label: transition.label, + action: transition.action + })), + consequences: [] + }; - return this; + modalStates[node.id] = state; + }); - } + const smmodaldata = { + name: "substory1", + x: 600, + y: 600, + collisionType: "smmodal", + modalStates + }; - applyMatrix4( m ) { + return smmodaldata; + } - const x = this.x, y = this.y, z = this.z, w = this.w; - const e = m.elements; + function GraphtoJSONConfigStatemachineModal() { + const storyJSONgraphdata = generateTimelineinGraph(7, 10); + const stateMachinewithquotes = createStateMachine(storyJSONgraphdata); - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; - this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; + //const json = JSON.parse(stateMachinewithquotes); + //const stateMachine = JSON.stringify(stateMachinewithquotes, null, 2).replace(/"([^"]+)":/g, '$1:'); // Remove quotes from keys + //console.log(stateMachine); + function customSerialize(obj, indent = 2, depth = 0) { + const pad = (' ').repeat(depth * indent); + const padInner = (' ').repeat((depth + 1) * indent); - return this; + if (Array.isArray(obj)) { + return '[\n' + obj.map(value => padInner + customSerialize(value, indent, depth + 1)).join(',\n') + '\n' + pad + ']'; + } else if (typeof obj === 'object' && obj !== null) { + const entries = Object.entries(obj).map(([key, value]) => { + const formattedValue = customSerialize(value, indent, depth + 1); + return `${padInner}${key}: ${formattedValue}`; + }); + return '{\n' + entries.join(',\n') + '\n' + pad + '}'; + } else { + return JSON.stringify(obj); + } } - divideScalar( scalar ) { + document.getElementById('smmodalconfigdownload-btn').addEventListener('click', () => { + // const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(stateMachine, null, 2)); + const customSerializedData = customSerialize(stateMachinewithquotes); - return this.multiplyScalar( 1 / scalar ); + const dataStr = "data:text/plain;charset=utf-8," + encodeURIComponent(customSerializedData); + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", "stateMachineconfig.txt"); + document.body.appendChild(downloadAnchorNode); // required for firefox + downloadAnchorNode.click(); + downloadAnchorNode.remove(); + }); + } + async function copydatatoclipboard(dataToCopy) { + try { + await navigator.clipboard.writeText(JSON.stringify(dataToCopy, 2, null)); + } catch(error) { + console.error('Failed to copy text: ', err); // console.log('Text copied to clipboard'); } + } - setAxisAngleFromQuaternion( q ) { + function instance$l($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('GraphwithStoryStructureIdeas', slots, []); + let cy; + let graphcontainer; + + // let scrollgraphContainer; + // Data to hold the new node and edge details + let newNodeId = ''; + + let newNodeLabel = ''; + let newNodeType = 'character'; + let newEdgeId = ''; + let newEdgeSource = ''; + let newEdgeTarget = ''; + + let resetGraphData = { + nodes: [ + { + data: { + id: 'Alex', + label: 'Protagonist', + type: 'character', + degree: 0 + } + } + ], + edges: [] + }; - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + let autonodes = 30; + let autoedges = 40; + let currentautoGeneratedGraphData; + let currentautoGeneratedGraphDataAugmented; + let nodes = []; + let currentautoexpandGraphData = { nodes: [], edges: [] }; + + // Initial graph data + let graphData = { + nodes: [ + // Characters + { + data: { + id: 'Alex', + label: 'Protagonist', + type: 'character', + degree: 0 + } + }, + { + data: { + id: 'Elara', + label: 'Mage', + type: 'character', + degree: 0 + } + }, + { + data: { + id: 'Draven', + label: 'Rogue', + type: 'character', + degree: 0 + } + }, + { + data: { + id: 'Luna', + label: 'Warrior', + type: 'character', + degree: 0 + } + }, + { + data: { + id: 'Orin', + label: 'Healer', + type: 'character', + degree: 0 + } + }, + // Items + { + data: { + id: 'Ancient Relic', + label: 'Ancient Relic', + type: 'item', + degree: 0 + } + }, + { + data: { + id: 'Mystic Amulet', + label: 'Mystic Amulet', + type: 'item', + degree: 0 + } + }, + { + data: { + id: 'Cursed Artifact', + label: 'Cursed Artifact', + type: 'item', + degree: 0 + } + }, + { + data: { + id: 'Golden Sword', + label: 'Golden Sword', + type: 'item', + degree: 0 + } + }, + { + data: { + id: 'Healing Potion', + label: 'Healing Potion', + type: 'item', + degree: 0 + } + }, + // Locations + { + data: { + id: 'Hidden Temple', + label: 'Hidden Temple', + type: 'location', + degree: 0 + } + }, + { + data: { + id: 'Village of Eldoria', + label: 'Village of Eldoria', + type: 'location', + degree: 0 + } + }, + { + data: { + id: 'Ancient Ruins', + label: 'Ancient Ruins', + type: 'location', + degree: 0 + } + } + ], + edges: [ + // Relationships + { + data: { + id: 'edge1', + source: 'Alex', + target: 'Ancient Relic' + } + }, + { + data: { + id: 'edge2', + source: 'Elara', + target: 'Mystic Amulet' + } + }, + { + data: { + id: 'edge3', + source: 'Draven', + target: 'Cursed Artifact' + } + }, + { + data: { + id: 'edge4', + source: 'Ancient Relic', + target: 'Mystic Amulet' + } + }, + { + data: { + id: 'edge5', + source: 'Luna', + target: 'Golden Sword' + } + }, + { + data: { + id: 'edge6', + source: 'Orin', + target: 'Healing Potion' + } + }, + // Quests + { + data: { + id: 'edge7', + source: 'Alex', + target: 'Hidden Temple' + } + }, + { + data: { + id: 'edge8', + source: 'Elara', + target: 'Village of Eldoria' + } + }, + { + data: { + id: 'edge9', + source: 'Draven', + target: 'Ancient Ruins' + } + }, + { + data: { + id: 'edge10', + source: 'Luna', + target: 'Hidden Temple' + } + }, + { + data: { + id: 'edge11', + source: 'Orin', + target: 'Village of Eldoria' + } + } + ] + }; - // q is assumed to be normalized + // Story data will be generated dynamically + let autostoryData = {}; - this.w = 2 * Math.acos( q.w ); + onMount(() => { + // scrollgraphContainer.scrollLeft = scrollgraphContainer.scrollWidth; + // Initialize Cytoscape + setTimeout( + () => { + $$invalidate(0, cy = cytoscape({ + container: graphcontainer, + elements: graphData, + style: [ + { + selector: 'node[type="character"]', + style: { + 'background-color': '#FFDDC1', + 'label': 'data(label)' + } + }, + { + selector: 'node[type="item"]', + style: { + 'background-color': '#C1FFC1', + 'label': 'data(label)' + } + }, + { + selector: 'node', + style: { + 'width': 'mapData(degree, 0, 4, 20, 50)', + 'height': 'mapData(degree, 0, 4, 20, 50)', + 'background-color': 'mapData(degree, 0, 4, #FFDDC1, #FF0000)' + } + }, + { + selector: 'node[isValid="false"]', + style: { + 'border-width': 2, + 'border-color': '#FF0000' + } + }, + { + selector: 'edge', + style: { + 'width': 3, + 'line-color': '#ccc', + 'target-arrow-color': '#ccc', + 'target-arrow-shape': 'triangle' + } + } + ], + layout: { + name: 'cose', + nodeRepulsion: 8000, + idealEdgeLength: 100, + fit: true, + padding: 30, + animate: true, + animationDuration: 1000 + } + })); - const s = Math.sqrt( 1 - q.w * q.w ); + updateNodeDegreesAndStyles(); + updateNodesList(); + }, + 500 + ); // Delay to ensure container is fully rendered + }); - if ( s < 0.0001 ) { + // Function to update the list of nodes for the dropdowns + function updateNodesList() { + $$invalidate(11, nodes = cy.nodes().map(node => node.data('id'))); + } - this.x = 1; - this.y = 0; - this.z = 0; + // Function to update node degrees and styles + function updateNodeDegreesAndStyles() { + cy.nodes().forEach(node => { + const outDegree = node.outgoers('edge').length; + const inDegree = node.incomers('edge').length; - } else { + // Mark node as invalid if it doesn't meet the minimum connectivity criteria + if (outDegree < 2 || inDegree < 1) { + node.data('isValid', 'false'); + } - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; + // Update the degree in node data for styling purposes + node.data('degree', outDegree + inDegree); + }); - } + // Refresh styles + cy.style().update(); - return this; + // Fit the graph to the viewable area after layout + cy.on('layoutstop', () => { + cy.fit(); + }); + cy.layout({ name: 'cose' }).run(); } - setAxisAngleFromRotationMatrix( m ) { + // Function to add a new node + function addNode() { + cy.add({ + group: 'nodes', + data: { + id: newNodeId, + label: newNodeLabel, + type: newNodeType, + degree: 0 + } + }); - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + updateNodesList(); + updateNodeDegreesAndStyles(); + } - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + // Function to add a new edge and generate story data + function addEdge() { + cy.add({ + group: 'edges', + data: { + id: newEdgeId, + source: newEdgeSource, + target: newEdgeTarget + } + }); - let angle, x, y, z; // variables for result - const epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + autostoryData[newEdgeId] = generateStoryData(newEdgeId, newEdgeSource, newEdgeTarget); + updateNodeDegreesAndStyles(); + } - te = m.elements, + // Function to generate story data based on the source and target nodes + function generateStoryData(edgeId, sourceId, targetId) { + const sourceNode = cy.getElementById(sourceId).data(); + const targetNode = cy.getElementById(targetId).data(); - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + return { + storyPart: `${sourceNode.label || sourceId} interacts with ${targetNode.label || targetId}.`, + requirements: [`Have ${sourceNode.label || sourceId} and ${targetNode.label || targetId}`], + outcomes: [ + `Outcome of ${sourceNode.label || sourceId} and ${targetNode.label || targetId} interaction` + ] + }; + } - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { + // Function to traverse the graph and generate story data for all nodes + function traverseAndGenerateStoryData() { + graphData.edges.forEach(edge => { + const { id, source, target } = edge.data; + autostoryData[id] = generateStoryData(id, source, target); + }); - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms + console.log(autostoryData); + } - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + // Function to save the graph and story data to a ZIP file + async function saveGraph() { + const elements = cy.json().elements; + const zip = new JSZip(); + zip.file("graph.json", JSON.stringify(elements, null, 2)); - // this singularity is identity matrix so angle = 0 + //TODO placeholder for populate the story variable below + zip.file("story.json", JSON.stringify(autostoryData, null, 2)); - this.set( 1, 0, 0, 0 ); + const content = await zip.generateAsync({ type: "blob" }); - return this; // zero angle, arbitrary axis + // Generate a timestamped filename + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); - } + const zipFilename = `graph-story-${timestamp}.zip`; + const a = document.createElement('a'); + a.href = URL.createObjectURL(content); + a.download = zipFilename; + a.click(); + } - // otherwise this singularity is angle = 180 + // Function to load the graph and story data from JSON or ZIP + async function loadGraph(event) { + const file = event.target.files[0]; + const reader = new FileReader(); - angle = Math.PI; + if (file.name.endsWith('.zip')) { + reader.onload = async e => { + const zip = await JSZip.loadAsync(e.target.result); + const graphData = await zip.file("graph.json").async("string"); + const storyData = await zip.file("story.json").async("string"); + cy.json({ elements: JSON.parse(graphData) }); + autostoryData = JSON.parse(storyData); + updateNodesList(); + updateNodeDegreesAndStyles(); + }; - const xx = ( m11 + 1 ) / 2; - const yy = ( m22 + 1 ) / 2; - const zz = ( m33 + 1 ) / 2; - const xy = ( m12 + m21 ) / 4; - const xz = ( m13 + m31 ) / 4; - const yz = ( m23 + m32 ) / 4; + reader.readAsArrayBuffer(file); + } else { + reader.onload = e => { + const data = JSON.parse(e.target.result); - if ( ( xx > yy ) && ( xx > zz ) ) { + if (file.name.includes('graph')) { + cy.json({ elements: data }); + updateNodesList(); + updateNodeDegreesAndStyles(); + } else if (file.name.includes('story')) { + autostoryData = data; + } + }; - // m11 is the largest diagonal term + reader.readAsText(file); + } + } - if ( xx < epsilon ) { + // Example usage: + const timeline = generateTimelineinGraph(7, 10); - x = 0; - y = 0.707106781; - z = 0.707106781; + console.log(timeline.nodes); + console.log(timeline.edges); - } else { + //const practicegraphData = autoGenerateGraphData(10, 15); + //console.log(practicegraphData); + // Function to generate and load graph data + function generateAndLoadGraphData() { + const generatedData = autoGenerateGraphData(10, 15); + cy.json({ elements: generatedData }); + updateNodesList(); + updateNodeDegreesAndStyles(); + console.log(generatedData); + } - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; + // Assume the cytoscape initialization and other required functions are already defined + function createBranchingPath() { + const nodes = [ + { + data: { + id: 'A', + label: 'Beginning', + type: 'event', + degree: 1 + } + }, + { + data: { + id: 'B', + label: 'Choice 1', + type: 'event', + degree: 2 + } + }, + { + data: { + id: 'C1', + label: 'Path 1A', + type: 'event', + degree: 3 + } + }, + { + data: { + id: 'C2', + label: 'Path 1B', + type: 'event', + degree: 3 + } + }, + { + data: { + id: 'D', + label: 'Rejoin Main Path', + type: 'event', + degree: 4 + } + }, + { + data: { + id: 'E', + label: 'Climax', + type: 'event', + degree: 5 + } + }, + { + data: { + id: 'F', + label: 'End', + type: 'event', + degree: 6 + } + } + ]; + + const edges = [ + { + data: { id: 'edge1', source: 'A', target: 'B' } + }, + { + data: { id: 'edge2', source: 'B', target: 'C1' } + }, + { + data: { id: 'edge3', source: 'B', target: 'C2' } + }, + { + data: { id: 'edge4', source: 'C1', target: 'D' } + }, + { + data: { id: 'edge5', source: 'C2', target: 'D' } + }, + { + data: { id: 'edge6', source: 'D', target: 'E' } + }, + { + data: { id: 'edge7', source: 'E', target: 'F' } + } + ]; + console.log(currentautoexpandGraphData); + currentautoexpandGraphData.nodes = [...currentautoexpandGraphData.nodes, ...nodes]; + currentautoexpandGraphData.edges = [...currentautoexpandGraphData.edges, ...edges]; + console.log(currentautoexpandGraphData); + cy.json({ elements: currentautoexpandGraphData }); + + // nodes.forEach((node, index) => { + // cy.add({ + // group: 'nodes', + // data: { ...node.data, id: `${node.data.id}_${Date.now()}_${index}` } + // }); + // }); + // edges.forEach((edge, index) => { + // cy.add({ + // group: 'edges', + // data: { ...edge.data, id: `${edge.data.id}_${Date.now()}_${index}` } + // }); + // }); + updateNodesList(); + + updateNodeDegreesAndStyles(); + } + + function createBranchingPathadditive() { + const nodes = [ + { + data: { + id: 'A', + label: 'Beginning', + type: 'event', + degree: 1 + } + }, + { + data: { + id: 'B', + label: 'Choice 1', + type: 'event', + degree: 2 + } + }, + { + data: { + id: 'C1', + label: 'Path 1A', + type: 'event', + degree: 3 + } + }, + { + data: { + id: 'C2', + label: 'Path 1B', + type: 'event', + degree: 3 + } + }, + { + data: { + id: 'D', + label: 'Rejoin Main Path', + type: 'event', + degree: 4 + } + }, + { + data: { + id: 'E', + label: 'Climax', + type: 'event', + degree: 5 + } + }, + { + data: { + id: 'F', + label: 'End', + type: 'event', + degree: 6 } + } + ]; - } else if ( yy > zz ) { + const edges = [ + { + data: { id: 'edge1', source: 'A', target: 'B' } + }, + { + data: { id: 'edge2', source: 'B', target: 'C1' } + }, + { + data: { id: 'edge3', source: 'B', target: 'C2' } + }, + { + data: { id: 'edge4', source: 'C1', target: 'D' } + }, + { + data: { id: 'edge5', source: 'C2', target: 'D' } + }, + { + data: { id: 'edge6', source: 'D', target: 'E' } + }, + { + data: { id: 'edge7', source: 'E', target: 'F' } + } + ]; - // m22 is the largest diagonal term + // Adding nodes to the current graph data + currentautoexpandGraphData.nodes = [...currentautoexpandGraphData.nodes, ...nodes]; - if ( yy < epsilon ) { + currentautoexpandGraphData.edges = [...currentautoexpandGraphData.edges, ...edges]; - x = 0.707106781; - y = 0; - z = 0.707106781; + // Map to store the original node IDs and their new unique IDs + const nodeIdMap = {}; - } else { + // Adding nodes one by one with unique IDs + nodes.forEach((node, index) => { + const newId = `${node.data.id}_${Date.now()}_${index}`; + nodeIdMap[node.data.id] = newId; - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; + cy.add({ + group: 'nodes', + data: { ...node.data, id: newId } + }); + }); + // Adding edges one by one with unique IDs and updated source/target IDs + edges.forEach((edge, index) => { + const newEdgeId = `${edge.data.id}_${Date.now()}_${index}`; + const newSource = nodeIdMap[edge.data.source]; + const newTarget = nodeIdMap[edge.data.target]; + + cy.add({ + group: 'edges', + data: { + ...edge.data, + id: newEdgeId, + source: newSource, + target: newTarget } + }); + }); - } else { + updateNodesList(); + updateNodeDegreesAndStyles(); + } - // m33 is the largest diagonal term so base result on this + function createLinearPath() { + const nodes = [ + { + data: { + id: 'A', + label: 'Beginning', + type: 'event', + degree: 0 + } + }, + { + data: { + id: 'B', + label: 'Middle', + type: 'event', + degree: 0 + } + }, + { + data: { + id: 'C', + label: 'Climax', + type: 'event', + degree: 0 + } + }, + { + data: { + id: 'D', + label: 'End', + type: 'event', + degree: 0 + } + } + ]; - if ( zz < epsilon ) { + const edges = [ + { + data: { id: 'edge1', source: 'A', target: 'B' } + }, + { + data: { id: 'edge2', source: 'B', target: 'C' } + }, + { + data: { id: 'edge3', source: 'C', target: 'D' } + } + ]; - x = 0.707106781; - y = 0.707106781; - z = 0; + //currentautoexpandGraphData = { nodes, edges }; + currentautoexpandGraphData.nodes = [...currentautoexpandGraphData.nodes, ...nodes]; - } else { + currentautoexpandGraphData.edges = [...currentautoexpandGraphData.edges, ...edges]; + cy.json({ elements: currentautoexpandGraphData }); ////elements: { nodes, edges } }); + updateNodesList(); + updateNodeDegreesAndStyles(); + } - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; + function createAutoGenGraphdata() { + currentautoGeneratedGraphData = generateTimelineinGraph(autonodes, autoedges); + console.log(currentautoGeneratedGraphData); + cy.json({ + elements: currentautoGeneratedGraphData, + style: [ + { + selector: 'node', + style: { + 'label': 'data(label)', + 'text-valign': 'center', + 'color': '#000', + 'background-color': '#61bffc', + 'text-outline-width': 2, + 'text-outline-color': '#fff' + } + }, + { + selector: 'edge', + style: { + 'width': 3, + 'line-color': '#ccc', + 'target-arrow-color': '#ccc', + 'target-arrow-shape': 'triangle', + 'curve-style': 'bezier' + } } - + ], + layout: { + name: 'grid', + rows: Math.ceil(Math.sqrt(timeline.nodes.length)) } + }); ////elements: { nodes, edges } }); - this.set( x, y, z, angle ); + updateNodesList(); + updateNodeDegreesAndStyles(); + } - return this; // return 180 deg rotation + function createLinearPathAutoGenstoryload() { + let tempgraph; + if (currentautoGeneratedGraphDataAugmented) { + tempgraph = JSON.parse(currentautoGeneratedGraphDataAugmented); + } else { + tempgraph = { + "nodes": [ + { + "data": { + "id": "A", + "label": "A mysterious artifact is discovered by a local villager.", + "type": "event", + "degree": 1 + } + }, + { + "data": { + "id": "B", + "label": "The artifact emits a strange glow and attracts the attention of scholars.", + "type": "event", + "degree": 2 + } + }, + { + "data": { + "id": "C", + "label": "A renowned archaeologist uncovers ancient runes on the artifact.", + "type": "event", + "degree": 3 + } + }, + { + "data": { + "id": "D", + "label": "The runes reveal a hidden map to a long-lost city of treasures.", + "type": "event", + "degree": 4 + } + }, + { + "data": { + "id": "E", + "label": "News of the map spreads, attracting adventurers and treasure hunters.", + "type": "event", + "degree": 5 + } + }, + { + "data": { + "id": "F", + "label": "Alex, a young treasure hunter, decides to find the lost city.", + "type": "event", + "degree": 6 + } + }, + { + "data": { + "id": "G", + "label": "Alex encounters an old mentor who warns of the dangers ahead.", + "type": "event", + "degree": 7 + } + }, + { + "data": { + "id": "H", + "label": "Despite the warning, Alex continues the journey.", + "type": "event", + "degree": 8 + } + }, + { + "data": { + "id": "I", + "label": "Alex stumbles upon a hidden village with tales of the cursed city.", + "type": "event", + "degree": 9 + } + }, + { + "data": { + "id": "J", + "label": "Alex learns the village elder has a key to deciphering the runes.", + "type": "event", + "degree": 10 + } + }, + { + "data": { + "id": "K", + "label": "The elder agrees to help if Alex can prove their worth through trials.", + "type": "event", + "degree": 11 + } + }, + { + "data": { + "id": "L", + "label": "Alex completes the trials, earning the elder’s trust and the key.", + "type": "event", + "degree": 12 + } + }, + { + "data": { + "id": "M", + "label": "With the key, Alex deciphers the runes, revealing the path to the lost city.", + "type": "event", + "degree": 13 + } + }, + { + "data": { + "id": "N", + "label": "Alex is joined by adventurers with their own motives.", + "type": "event", + "degree": 14 + } + }, + { + "data": { + "id": "O", + "label": "They face numerous challenges including treacherous terrain and wild beasts.", + "type": "event", + "degree": 15 + } + }, + { + "data": { + "id": "P", + "label": "The group encounters a rival faction led by Zara.", + "type": "event", + "degree": 16 + } + }, + { + "data": { + "id": "Q", + "label": "A fierce battle ensues for the treasure and secrets of the lost city.", + "type": "event", + "degree": 17 + } + }, + { + "data": { + "id": "R", + "label": "Alex's group narrowly escapes, but Zara vows to claim the treasure.", + "type": "event", + "degree": 18 + } + }, + { + "data": { + "id": "S", + "label": "Alex discovers an ancient temple with the final clue to the lost city.", + "type": "event", + "degree": 19 + } + }, + { + "data": { + "id": "T", + "label": "Inside the temple, they solve puzzles and avoid traps to retrieve the clue.", + "type": "event", + "degree": 20 + } + }, + { + "data": { + "id": "U", + "label": "The clue leads them to the jungle where the city's entrance is concealed.", + "type": "event", + "degree": 21 + } + }, + { + "data": { + "id": "V", + "label": "They face a guardian spirit protecting the city's entrance.", + "type": "event", + "degree": 22 + } + }, + { + "data": { + "id": "W", + "label": "They outwit the guardian and gain access to the city.", + "type": "event", + "degree": 23 + } + }, + { + "data": { + "id": "X", + "label": "Inside the city, they uncover treasures and secrets of an ancient civilization.", + "type": "event", + "degree": 24 + } + }, + { + "data": { + "id": "Y", + "label": "Zara and her faction reappear, leading to a final showdown.", + "type": "event", + "degree": 25 + } + }, + { + "data": { + "id": "Z", + "label": "In a climactic battle, Alex’s group triumphs but at great cost.", + "type": "event", + "degree": 26 + } + }, + { + "data": { + "id": "[", + "label": "Alex reflects on the journey and the value of friendships.", + "type": "event", + "degree": 27 + } + }, + { + "data": { + "id": "\\", + "label": "They decide to leave the treasure, protecting the city's secrets.", + "type": "event", + "degree": 28 + } + }, + { + "data": { + "id": "]", + "label": "Alex and the adventurers return to the village, hailed as heroes.", + "type": "event", + "degree": 29 + } + }, + { + "data": { + "id": "^", + "label": "The village celebrates their return, and the artifact is placed in a museum.", + "type": "event", + "degree": 30 + } + } + ], + "edges": [ + { + "data": { + "id": "edge1", + "source": "S", + "target": "X" + } + }, + { + "data": { + "id": "edge2", + "source": "[", + "target": "Z" + } + }, + { + "data": { + "id": "edge3", + "source": "Y", + "target": "W" + } + }, + { + "data": { + "id": "edge4", + "source": "M", + "target": "L" + } + }, + { + "data": { + "id": "edge5", + "source": "P", + "target": "\\" + } + }, + { + "data": { + "id": "edge6", + "source": "Z", + "target": "W" + } + }, + { + "data": { + "id": "edge7", + "source": "M", + "target": "[" + } + }, + { + "data": { + "id": "edge8", + "source": "G", + "target": "V" + } + }, + { + "data": { + "id": "edge9", + "source": "O", + "target": "Y" + } + }, + { + "data": { + "id": "edge10", + "source": "W", + "target": "C" + } + }, + { + "data": { + "id": "edge11", + "source": "F", + "target": "P" + } + }, + { + "data": { + "id": "edge12", + "source": "Z", + "target": "N" + } + }, + { + "data": { + "id": "edge13", + "source": "X", + "target": "U" + } + }, + { + "data": { + "id": "edge14", + "source": "J", + "target": "X" + } + }, + { + "data": { + "id": "edge15", + "source": "G", + "target": "F" + } + }, + { + "data": { + "id": "edge16", + "source": "W", + "target": "K" + } + }, + { + "data": { + "id": "edge17", + "source": "B", + "target": "Z" + } + }, + { + "data": { + "id": "edge18", + "source": "W", + "target": "H" + } + }, + { + "data": { + "id": "edge19", + "source": "N", + "target": "F" + } + }, + { + "data": { + "id": "edge20", + "source": "H", + "target": "W" + } + }, + { + "data": { + "id": "edge21", + "source": "Q", + "target": "O" + } + }, + { + "data": { + "id": "edge22", + "source": "F", + "target": "A" + } + }, + { + "data": { + "id": "edge23", + "source": "]", + "target": "I" + } + }, + { + "data": { + "id": "edge24", + "source": "W", + "target": "X" + } + }, + { + "data": { + "id": "edge25", + "source": "[", + "target": "N" + } + }, + { + "data": { + "id": "edge26", + "source": "M", + "target": "R" + } + }, + { + "data": { + "id": "edge27", + "source": "K", + "target": "V" + } + }, + { + "data": { + "id": "edge28", + "source": "P", + "target": "A" + } + }, + { + "data": { + "id": "edge29", + "source": "U", + "target": "D" + } + }, + { + "data": { + "id": "edge30", + "source": "S", + "target": "O" + } + }, + { + "data": { + "id": "edge31", + "source": "N", + "target": "M" + } + }, + { + "data": { + "id": "edge32", + "source": "V", + "target": "B" + } + }, + { + "data": { + "id": "edge33", + "source": "P", + "target": "U" + } + }, + { + "data": { + "id": "edge34", + "source": "T", + "target": "R" + } + }, + { + "data": { + "id": "edge35", + "source": "P", + "target": "M" + } + }, + { + "data": { + "id": "edge36", + "source": "U", + "target": "H" + } + }, + { + "data": { + "id": "edge37", + "source": "[", + "target": "A" + } + }, + { + "data": { + "id": "edge38", + "source": "[", + "target": "E" + } + }, + { + "data": { + "id": "edge39", + "source": "^", + "target": "D" + } + }, + { + "data": { + "id": "edge40", + "source": "P", + "target": "A" + } + } + ] + }; } - // as we have reached here there are no singularities so we can handle normally - - let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + cy.json({ + elements: tempgraph, + style: [ + { + selector: 'node', + style: { + 'label': 'data(label)', + 'text-valign': 'center', + 'color': '#000', + 'background-color': '#61bffc', + 'text-outline-width': 2, + 'text-outline-color': '#fff' + } + }, + { + selector: 'edge', + style: { + 'width': 3, + 'line-color': '#ccc', + 'target-arrow-color': '#ccc', + 'target-arrow-shape': 'triangle', + 'curve-style': 'bezier' + } + } + ], + layout: { + //rows: Math.ceil(Math.sqrt(timeline.nodes.length)), + name: 'cose', + animate: true, // Set to true for smooth transitions + fit: true, // Whether to fit the network view after when done + padding: 30, // Padding on fit + nodeRepulsion: 400000, // Node repulsion (non overlapping) multiplier + idealEdgeLength: 100, // Ideal edge (non nested) length + edgeElasticity: 100, // Divisor to compute edge forces + gravity: 80, // Gravity force (constant) + numIter: 1000, // Number of iterations to perform + initialTemp: 200, // Initial temperature for cooling + coolingFactor: 0.95, // Cooling factor (how much to reduce temperature each iteration) + minTemp: 1.0, // Minimum temperature for cooling + + } + }); ////elements: { nodes, edges } }); + + cy.nodes().on('grab', function (event) { + const node = event.target; + + node.on('free', function (event) { + cy.layout({ + name: 'cose', + animate: false, + fit: true, + padding: 30, + nodeRepulsion: 400000, + idealEdgeLength: 100, + edgeElasticity: 100, + gravity: 80, + numIter: 1000, + initialTemp: 200, + coolingFactor: 0.95, + minTemp: 1.0 + }).run(); + }); + }); - if ( Math.abs( s ) < 0.001 ) s = 1; + // cy.nodes().forEach(function(node){ + // node.qtip({ + // content: node.data('label'), + // position: { + // my: 'top center', + // at: 'bottom center' + // }, + // style: { + // classes: 'qtip-bootstrap', + // tip: { + // width: 16, + // height: 8 + // } + // } + // }); + // }); + updateNodesList(); + + updateNodeDegreesAndStyles(); + + //const storyJSONgraphdata = generateTimelineinGraph(7, 10); + console.log(tempgraph); + + const storyJSON = createStoryParts(tempgraph); //.nodes, storyJSONgraphdata.edges); + + //console.log(storyJSONgraphdata); + console.log(storyJSON); + + const stateMachineModalConfig = createStateMachine(tempgraph); + console.log(stateMachineModalConfig); - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case + try { + autogenconfigtestsmmdoalfromgraph.update(currentstoreconfig => { + return { + ...currentstoreconfig, + story: [ + { + ...currentstoreconfig.story[0], + targets: [...currentstoreconfig.story[0].targets, stateMachineModalConfig] + }, + ...currentstoreconfig.story.slice(1) + ] + }; + }); + } catch(e) { + alert('Error updating config object'); + } - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + console.log(get_store_value(autogenconfigtestsmmdoalfromgraph)); + } - return this; + function resetGraph() { + cy.json({ + elements: resetGraphData, + style: [ + { + selector: 'node', + style: { + 'label': 'data(label)', + 'text-valign': 'center', + 'color': '#000', + 'background-color': '#61bffc', + 'text-outline-width': 2, + 'text-outline-color': '#fff' + } + }, + { + selector: 'edge', + style: { + 'width': 3, + 'line-color': '#ccc', + 'target-arrow-color': '#ccc', + 'target-arrow-shape': 'triangle', + 'curve-style': 'bezier' + } + } + ], + layout: { + //rows: Math.ceil(Math.sqrt(timeline.nodes.length)), + name: 'cose', + animate: true, // Set to true for smooth transitions + fit: true, // Whether to fit the network view after when done + padding: 30, // Padding on fit + nodeRepulsion: 400000, // Node repulsion (non overlapping) multiplier + idealEdgeLength: 100, // Ideal edge (non nested) length + edgeElasticity: 100, // Divisor to compute edge forces + gravity: 80, // Gravity force (constant) + numIter: 1000, // Number of iterations to perform + initialTemp: 200, // Initial temperature for cooling + coolingFactor: 0.95, // Cooling factor (how much to reduce temperature each iteration) + minTemp: 1.0, // Minimum temperature for cooling + + } + }); ////elements: { nodes, edges } }); + + cy.nodes().on('grab', function (event) { + const node = event.target; + + node.on('free', function (event) { + cy.layout({ + name: 'cose', + animate: false, + fit: true, + padding: 30, + nodeRepulsion: 400000, + idealEdgeLength: 100, + edgeElasticity: 100, + gravity: 80, + numIter: 1000, + initialTemp: 200, + coolingFactor: 0.95, + minTemp: 1.0 + }).run(); + }); + }); + } + function copycurrentautoGeneratedGraphData() { + copydatatoclipboard(currentautoGeneratedGraphData); + alert('Graph data copied to clipboard'); } - min( v ) { + const writable_props = []; - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - this.w = Math.min( this.w, v.w ); + Object_1$4.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$8.warn(` was created with unknown prop '${key}'`); + }); - return this; + const click_handler = () => cy.fit(); + function input1_input_handler() { + autonodes = to_number(this.value); + $$invalidate(8, autonodes); } - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); + function input2_input_handler() { + autoedges = to_number(this.value); + $$invalidate(9, autoedges); + } - return this; + function textarea_input_handler() { + currentautoGeneratedGraphDataAugmented = this.value; + $$invalidate(10, currentautoGeneratedGraphDataAugmented); + } + function input3_input_handler() { + newNodeId = this.value; + $$invalidate(2, newNodeId); } - clamp( min, max ) { + function input4_input_handler() { + newNodeLabel = this.value; + $$invalidate(3, newNodeLabel); + } - // assumes min < max, componentwise + function select0_change_handler() { + newNodeType = select_value(this); + $$invalidate(4, newNodeType); + } - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); + function input5_input_handler() { + newEdgeId = this.value; + $$invalidate(5, newEdgeId); + } - return this; + function select1_change_handler() { + newEdgeSource = select_value(this); + $$invalidate(6, newEdgeSource); + $$invalidate(11, nodes); + } + function select2_change_handler() { + newEdgeTarget = select_value(this); + $$invalidate(7, newEdgeTarget); + $$invalidate(11, nodes); } - clampScalar( minVal, maxVal ) { + function div5_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + graphcontainer = $$value; + $$invalidate(1, graphcontainer); + }); + } - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); + $$self.$capture_state = () => ({ + onMount, + cytoscape, + JSZip, + autogenconfigtestsmmdoalfromgraph, + get: get_store_value, + cy, + graphcontainer, + newNodeId, + newNodeLabel, + newNodeType, + newEdgeId, + newEdgeSource, + newEdgeTarget, + resetGraphData, + autonodes, + autoedges, + currentautoGeneratedGraphData, + currentautoGeneratedGraphDataAugmented, + nodes, + currentautoexpandGraphData, + graphData, + autostoryData, + updateNodesList, + updateNodeDegreesAndStyles, + addNode, + addEdge, + generateStoryData, + traverseAndGenerateStoryData, + saveGraph, + loadGraph, + autoGenerateGraphData, + generateTimelineinGraph, + timeline, + generateAndLoadGraphData, + createBranchingPath, + createBranchingPathadditive, + createLinearPath, + createAutoGenGraphdata, + createLinearPathAutoGenstoryload, + createStoryParts, + GraphtoJSONConfig, + createStateMachine, + GraphtoJSONConfigStatemachineModal, + resetGraph, + copydatatoclipboard, + copycurrentautoGeneratedGraphData + }); - return this; + $$self.$inject_state = $$props => { + if ('cy' in $$props) $$invalidate(0, cy = $$props.cy); + if ('graphcontainer' in $$props) $$invalidate(1, graphcontainer = $$props.graphcontainer); + if ('newNodeId' in $$props) $$invalidate(2, newNodeId = $$props.newNodeId); + if ('newNodeLabel' in $$props) $$invalidate(3, newNodeLabel = $$props.newNodeLabel); + if ('newNodeType' in $$props) $$invalidate(4, newNodeType = $$props.newNodeType); + if ('newEdgeId' in $$props) $$invalidate(5, newEdgeId = $$props.newEdgeId); + if ('newEdgeSource' in $$props) $$invalidate(6, newEdgeSource = $$props.newEdgeSource); + if ('newEdgeTarget' in $$props) $$invalidate(7, newEdgeTarget = $$props.newEdgeTarget); + if ('resetGraphData' in $$props) resetGraphData = $$props.resetGraphData; + if ('autonodes' in $$props) $$invalidate(8, autonodes = $$props.autonodes); + if ('autoedges' in $$props) $$invalidate(9, autoedges = $$props.autoedges); + if ('currentautoGeneratedGraphData' in $$props) currentautoGeneratedGraphData = $$props.currentautoGeneratedGraphData; + if ('currentautoGeneratedGraphDataAugmented' in $$props) $$invalidate(10, currentautoGeneratedGraphDataAugmented = $$props.currentautoGeneratedGraphDataAugmented); + if ('nodes' in $$props) $$invalidate(11, nodes = $$props.nodes); + if ('currentautoexpandGraphData' in $$props) currentautoexpandGraphData = $$props.currentautoexpandGraphData; + if ('graphData' in $$props) graphData = $$props.graphData; + if ('autostoryData' in $$props) autostoryData = $$props.autostoryData; + }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); } - clampLength( min, max ) { - - const length = this.length(); + return [ + cy, + graphcontainer, + newNodeId, + newNodeLabel, + newNodeType, + newEdgeId, + newEdgeSource, + newEdgeTarget, + autonodes, + autoedges, + currentautoGeneratedGraphDataAugmented, + nodes, + addNode, + addEdge, + traverseAndGenerateStoryData, + saveGraph, + loadGraph, + generateAndLoadGraphData, + createBranchingPathadditive, + createAutoGenGraphdata, + createLinearPathAutoGenstoryload, + resetGraph, + copycurrentautoGeneratedGraphData, + click_handler, + input1_input_handler, + input2_input_handler, + textarea_input_handler, + input3_input_handler, + input4_input_handler, + select0_change_handler, + input5_input_handler, + select1_change_handler, + select2_change_handler, + div5_binding + ]; + } - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + class GraphwithStoryStructureIdeas extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$l, create_fragment$l, safe_not_equal, {}, null, [-1, -1]); + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "GraphwithStoryStructureIdeas", + options, + id: create_fragment$l.name + }); } + } - floor() { + /* src\MovingDotSpaceThemeManager.svelte generated by Svelte v3.59.2 */ + const file$k = "src\\MovingDotSpaceThemeManager.svelte"; - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); + // (98:4) + function create_default_slot_4$1(ctx) { + let customgameconfighelper; + let current; + customgameconfighelper = new CustomGameConfigHelper({ $$inline: true }); - return this; + const block = { + c: function create() { + create_component(customgameconfighelper.$$.fragment); + }, + m: function mount(target, anchor) { + mount_component(customgameconfighelper, target, anchor); + current = true; + }, + i: function intro(local) { + if (current) return; + transition_in(customgameconfighelper.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(customgameconfighelper.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(customgameconfighelper, detaching); + } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_4$1.name, + type: "slot", + source: "(98:4) ", + ctx + }); - ceil() { + return block; + } - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); + // (102:4) + function create_default_slot_3$1(ctx) { + let hr; + let t0; + let br0; + let t1; + let br1; + let t2; + let brainstormstatetransitionsrandom; + let current; + brainstormstatetransitionsrandom = new BrainstormStateTransitionsRandom({ $$inline: true }); - return this; + const block = { + c: function create() { + hr = element$1("hr"); + t0 = text("\r\n Early Sequence examples - \r\n "); + br0 = element$1("br"); + t1 = text("Write a story where the main event are in this order: gosomewhere getsomething makeobservation getsomething talktosomeone makeobservation getsomething talktosomeone gosomewhere fight talktosomeone fight fight talktosomeone talktosomeone talktosomeone gosomewhere talktosomeone\r\n "); + br1 = element$1("br"); + t2 = text("lets write the story to fit this order - stats location stats inventory stats location location skills inventory stats inventory skills skills skills stats stats skills\r\n \r\n "); + create_component(brainstormstatetransitionsrandom.$$.fragment); + add_location(hr, file$k, 102, 8, 4757); + add_location(br0, file$k, 104, 8, 4807); + add_location(br1, file$k, 105, 8, 5097); + }, + m: function mount(target, anchor) { + insert_dev(target, hr, anchor); + insert_dev(target, t0, anchor); + insert_dev(target, br0, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, br1, anchor); + insert_dev(target, t2, anchor); + mount_component(brainstormstatetransitionsrandom, target, anchor); + current = true; + }, + p: noop$2, + i: function intro(local) { + if (current) return; + transition_in(brainstormstatetransitionsrandom.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(brainstormstatetransitionsrandom.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + if (detaching) detach_dev(hr); + if (detaching) detach_dev(t0); + if (detaching) detach_dev(br0); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(br1); + if (detaching) detach_dev(t2); + destroy_component(brainstormstatetransitionsrandom, detaching); + } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_3$1.name, + type: "slot", + source: "(102:4) ", + ctx + }); - round() { + return block; + } - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); + // (111:4) + function create_default_slot_2$1(ctx) { + let graphwithstorystructureideas; + let current; + graphwithstorystructureideas = new GraphwithStoryStructureIdeas({ $$inline: true }); - return this; + const block = { + c: function create() { + create_component(graphwithstorystructureideas.$$.fragment); + }, + m: function mount(target, anchor) { + mount_component(graphwithstorystructureideas, target, anchor); + current = true; + }, + i: function intro(local) { + if (current) return; + transition_in(graphwithstorystructureideas.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(graphwithstorystructureideas.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(graphwithstorystructureideas, detaching); + } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_2$1.name, + type: "slot", + source: "(111:4) ", + ctx + }); - roundToZero() { + return block; + } - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); + // (73:0) + function create_default_slot_1$1(ctx) { + let t0; + let hr; + let t1; + let simplecollapsible0; + let t2; + let simplecollapsible1; + let t3; + let simplecollapsible2; + let current; - return this; + simplecollapsible0 = new SimpleCollapsible({ + props: { + title: "Streamlined Config Steps", + $$slots: { default: [create_default_slot_4$1] }, + $$scope: { ctx } + }, + $$inline: true + }); - } + simplecollapsible1 = new SimpleCollapsible({ + props: { + title: "Incomplete Story structure and Timeline suggestion engines", + $$slots: { default: [create_default_slot_3$1] }, + $$scope: { ctx } + }, + $$inline: true + }); - negate() { + simplecollapsible2 = new SimpleCollapsible({ + props: { + title: "Incomplete Graph based story structure planner", + $$slots: { default: [create_default_slot_2$1] }, + $$scope: { ctx } + }, + $$inline: true + }); - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; + const block = { + c: function create() { + t0 = text("Currently the state machine is the json config - Story parts / target type controlled by switch case for collisions and smmodal (state machine modal as the targets all have to a transitions field) (modals and smmodals not yet part of randomisers below)\r\n "); + hr = element$1("hr"); + t1 = text("\r\n Incomplete/Unpolished Custom game setting assistant\r\n \r\n \r\n\r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n "); + create_component(simplecollapsible0.$$.fragment); + t2 = space(); + create_component(simplecollapsible1.$$.fragment); + t3 = space(); + create_component(simplecollapsible2.$$.fragment); + add_location(hr, file$k, 74, 4, 3427); + }, + m: function mount(target, anchor) { + insert_dev(target, t0, anchor); + insert_dev(target, hr, anchor); + insert_dev(target, t1, anchor); + mount_component(simplecollapsible0, target, anchor); + insert_dev(target, t2, anchor); + mount_component(simplecollapsible1, target, anchor); + insert_dev(target, t3, anchor); + mount_component(simplecollapsible2, target, anchor); + current = true; + }, + p: function update(ctx, dirty) { + const simplecollapsible0_changes = {}; - return this; + if (dirty & /*$$scope*/ 8192) { + simplecollapsible0_changes.$$scope = { dirty, ctx }; + } - } + simplecollapsible0.$set(simplecollapsible0_changes); + const simplecollapsible1_changes = {}; - dot( v ) { + if (dirty & /*$$scope*/ 8192) { + simplecollapsible1_changes.$$scope = { dirty, ctx }; + } - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + simplecollapsible1.$set(simplecollapsible1_changes); + const simplecollapsible2_changes = {}; - } + if (dirty & /*$$scope*/ 8192) { + simplecollapsible2_changes.$$scope = { dirty, ctx }; + } - lengthSq() { + simplecollapsible2.$set(simplecollapsible2_changes); + }, + i: function intro(local) { + if (current) return; + transition_in(simplecollapsible0.$$.fragment, local); + transition_in(simplecollapsible1.$$.fragment, local); + transition_in(simplecollapsible2.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(simplecollapsible0.$$.fragment, local); + transition_out(simplecollapsible1.$$.fragment, local); + transition_out(simplecollapsible2.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + if (detaching) detach_dev(t0); + if (detaching) detach_dev(hr); + if (detaching) detach_dev(t1); + destroy_component(simplecollapsible0, detaching); + if (detaching) detach_dev(t2); + destroy_component(simplecollapsible1, detaching); + if (detaching) detach_dev(t3); + destroy_component(simplecollapsible2, detaching); + } + }; - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_1$1.name, + type: "slot", + source: "(73:0) ", + ctx + }); - } + return block; + } - length() { + // (117:0) + function create_default_slot$2(ctx) { + let t0; + let br; + let t1; - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + const block = { + c: function create() { + t0 = text("Steps (Order not optimised yet)\r\n "); + br = element$1("br"); + t1 = text("Story (order of events) random order generator as strating point, foreshadowing points added back after story finished --- Game Mechanics (order of UI elements and off screen controls for corresponding story event, esp. every significant verb in the story) --- User driven Attributes (Skills/Stats/Inventory)"); + add_location(br, file$k, 118, 4, 5634); + }, + m: function mount(target, anchor) { + insert_dev(target, t0, anchor); + insert_dev(target, br, anchor); + insert_dev(target, t1, anchor); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(t0); + if (detaching) detach_dev(br); + if (detaching) detach_dev(t1); + } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot$2.name, + type: "slot", + source: "(117:0) ", + ctx + }); - manhattanLength() { + return block; + } - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + function create_fragment$k(ctx) { + let simplecollapsible0; + let t0; + let simplecollapsible1; + let t1; + let hr0; + let t2; + let hr1; + let t3; + let div3; + let div0; + let t4; + let br0; + let t5; + let br1; + let t6; + let br2; + let t7; + let br3; + let t8; + let t9; + let div1; + let t10; + let br4; + let t11; + let br5; + let t12; + let t13; + let div2; + let t14; + let t15; + let br6; + let t16; + let current; - } + simplecollapsible0 = new SimpleCollapsible({ + props: { + title: "Config Customisation Assistant - Semi Automated - WIP", + $$slots: { default: [create_default_slot_1$1] }, + $$scope: { ctx } + }, + $$inline: true + }); - normalize() { + simplecollapsible1 = new SimpleCollapsible({ + props: { + title: "Config Manual Considerations - WIP", + $$slots: { default: [create_default_slot$2] }, + $$scope: { ctx } + }, + $$inline: true + }); - return this.divideScalar( this.length() || 1 ); + const block = { + c: function create() { + create_component(simplecollapsible0.$$.fragment); + t0 = space(); + create_component(simplecollapsible1.$$.fragment); + t1 = space(); + hr0 = element$1("hr"); + t2 = text("\r\n\r\nCan turn vibe / adjectives of songs into character ideas -- existing or make song with AI as player theme \r\n\r\n"); + hr1 = element$1("hr"); + t3 = text("\r\nNext Is autogenerate + extract + llm api call for the JSON snippet + Merge in one button press + load into game component for testing + Sequence generate built into autogenerate json as an option (sequence becomes the placeholder text)\r\n\r\n"); + div3 = element$1("div"); + div0 = element$1("div"); + t4 = text("TODO - "); + br0 = element$1("br"); + t5 = text(" Simplify Theme Manager "); + br1 = element$1("br"); + t6 = text(" Fix state transition and game mechanic integration "); + br2 = element$1("br"); + t7 = text(" Flesh out Iframe modal gameplay eg. youtube video as an item and llm judge "); + br3 = element$1("br"); + t8 = text(" each transition = new picture and any custom setup for components"); + t9 = space(); + div1 = element$1("div"); + t10 = text("Website = multilingual support in chrome (when running locally) "); + br4 = element$1("br"); + t11 = text("\r\n The mechanics here are location based so story should be location based "); + br5 = element$1("br"); + t12 = text("\r\n Simultaneous relationships between multiple items = complexity - eg. player location and objectives"); + t13 = space(); + div2 = element$1("div"); + t14 = text(/*ChangedContentPlaceholder*/ ctx[0]); + t15 = space(); + br6 = element$1("br"); + t16 = text("\r\n Most stories for games are about a character that lacks something to beat their problems and the 90% inbetween the begining and the end is acquiring"); + add_location(hr0, file$k, 121, 0, 5973); + add_location(hr1, file$k, 125, 0, 6091); + add_location(br0, file$k, 131, 15, 6403); + add_location(br1, file$k, 131, 43, 6431); + add_location(br2, file$k, 131, 99, 6487); + add_location(br3, file$k, 131, 179, 6567); + add_location(div0, file$k, 130, 4, 6381); + add_location(br4, file$k, 135, 72, 6736); + add_location(br5, file$k, 136, 80, 6822); + add_location(div1, file$k, 134, 4, 6657); + add_location(br6, file$k, 141, 38, 7000); + add_location(div2, file$k, 140, 4, 6955); + attr_dev(div3, "class", "grid-themegridContainer svelte-qg4vfk"); + add_location(div3, file$k, 128, 0, 6336); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + mount_component(simplecollapsible0, target, anchor); + insert_dev(target, t0, anchor); + mount_component(simplecollapsible1, target, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, hr0, anchor); + insert_dev(target, t2, anchor); + insert_dev(target, hr1, anchor); + insert_dev(target, t3, anchor); + insert_dev(target, div3, anchor); + append_dev(div3, div0); + append_dev(div0, t4); + append_dev(div0, br0); + append_dev(div0, t5); + append_dev(div0, br1); + append_dev(div0, t6); + append_dev(div0, br2); + append_dev(div0, t7); + append_dev(div0, br3); + append_dev(div0, t8); + append_dev(div3, t9); + append_dev(div3, div1); + append_dev(div1, t10); + append_dev(div1, br4); + append_dev(div1, t11); + append_dev(div1, br5); + append_dev(div1, t12); + append_dev(div3, t13); + append_dev(div3, div2); + append_dev(div2, t14); + append_dev(div2, t15); + append_dev(div2, br6); + append_dev(div2, t16); + current = true; + }, + p: function update(ctx, [dirty]) { + const simplecollapsible0_changes = {}; - } + if (dirty & /*$$scope*/ 8192) { + simplecollapsible0_changes.$$scope = { dirty, ctx }; + } - setLength( length ) { + simplecollapsible0.$set(simplecollapsible0_changes); + const simplecollapsible1_changes = {}; - return this.normalize().multiplyScalar( length ); + if (dirty & /*$$scope*/ 8192) { + simplecollapsible1_changes.$$scope = { dirty, ctx }; + } - } + simplecollapsible1.$set(simplecollapsible1_changes); + if (!current || dirty & /*ChangedContentPlaceholder*/ 1) set_data_dev(t14, /*ChangedContentPlaceholder*/ ctx[0]); + }, + i: function intro(local) { + if (current) return; + transition_in(simplecollapsible0.$$.fragment, local); + transition_in(simplecollapsible1.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(simplecollapsible0.$$.fragment, local); + transition_out(simplecollapsible1.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(simplecollapsible0, detaching); + if (detaching) detach_dev(t0); + destroy_component(simplecollapsible1, detaching); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(hr0); + if (detaching) detach_dev(t2); + if (detaching) detach_dev(hr1); + if (detaching) detach_dev(t3); + if (detaching) detach_dev(div3); + } + }; - lerp( v, alpha ) { + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$k.name, + type: "component", + source: "", + ctx + }); - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; + return block; + } - return this; + function instance$k($$self, $$props, $$invalidate) { + let $targets; + let $objectives; + let $skills; + let $inventory; + validate_store(targets, 'targets'); + component_subscribe($$self, targets, $$value => $$invalidate(4, $targets = $$value)); + validate_store(objectives, 'objectives'); + component_subscribe($$self, objectives, $$value => $$invalidate(5, $objectives = $$value)); + validate_store(skills, 'skills'); + component_subscribe($$self, skills, $$value => $$invalidate(6, $skills = $$value)); + validate_store(inventory, 'inventory'); + component_subscribe($$self, inventory, $$value => $$invalidate(7, $inventory = $$value)); + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('MovingDotSpaceThemeManager', slots, []); + let { ChangedContentPlaceholder = "" } = $$props; + let newItem = { type: "", name: "", description: "" }; + let newSkill = { branch: "", name: "", learned: false }; + let newObjective = { branch: "", name: "", complete: false }; + // ... similarly for targets + function addItem() { + inventory.update(items => [...items, newItem]); + newItem = { type: "", name: "", description: "" }; // Reset form } - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.w = v1.w + ( v2.w - v1.w ) * alpha; - - return this; - + function addSkill() { + skills.update(skills => [...skills, newSkill]); + newSkill = { branch: "", name: "", learned: false }; // Reset form } - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - + function addObjective() { + objectives.update(objectives => [...objectives, newObjective]); + newObjective = { branch: "", name: "", complete: false }; // Reset form } - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; - - return this; + // ... similarly for targets + // Functions to save and load configurations to/from localStorage or a backend would also be defined here + // Function to download the current configuration as a JSON file + function downloadConfiguration() { + const gameConfig = { + inventory: $inventory, + skills: $skills, + objectives: $objectives, + targets: $targets + }; + const blob = new Blob([JSON.stringify(gameConfig, null, 2)], { type: 'application/json' }); + const href = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = href; + link.download = 'gameConfig.json'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); } - toArray( array = [], offset = 0 ) { + // Function to load configuration from an uploaded JSON file + function handleFileUpload(event) { + const file = event.target.files[0]; - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; + if (file) { + const reader = new FileReader(); - return array; + reader.onload = e => { + const fileContent = e.target.result; + const { inventory: loadedInventory, skills: loadedSkills, objectives: loadedObjectives, targets: loadedTargets } = JSON.parse(fileContent); + inventory.set(loadedInventory); + skills.set(loadedSkills); + objectives.set(loadedObjectives); + targets.set(loadedTargets); + alert('Configuration loaded!'); + }; + reader.readAsText(file); + } } - fromBufferAttribute( attribute, index ) { + const writable_props = ['ChangedContentPlaceholder']; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); - return this; + $$self.$$set = $$props => { + if ('ChangedContentPlaceholder' in $$props) $$invalidate(0, ChangedContentPlaceholder = $$props.ChangedContentPlaceholder); + }; - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - this.w = Math.random(); - - return this; - - } - - *[ Symbol.iterator ]() { + $$self.$capture_state = () => ({ + ChangedContentPlaceholder, + inventory, + skills, + objectives, + targets, + SimpleCollapsible, + BrainstormGameConfigsRandom, + BrainstormStateTransitionsRandom, + Testbrainstorminstantpopulate, + Testjsonmatchingfieldmerge, + CustomGameConfigHelper, + GraphwithStoryStructureIdeas, + newItem, + newSkill, + newObjective, + addItem, + addSkill, + addObjective, + downloadConfiguration, + handleFileUpload, + $targets, + $objectives, + $skills, + $inventory + }); - yield this.x; - yield this.y; - yield this.z; - yield this.w; + $$self.$inject_state = $$props => { + if ('ChangedContentPlaceholder' in $$props) $$invalidate(0, ChangedContentPlaceholder = $$props.ChangedContentPlaceholder); + if ('newItem' in $$props) newItem = $$props.newItem; + if ('newSkill' in $$props) newSkill = $$props.newSkill; + if ('newObjective' in $$props) newObjective = $$props.newObjective; + }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); } + return [ChangedContentPlaceholder]; } - /* - In options, we can specify: - * Texture parameters for an auto-generated target texture - * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers - */ - class WebGLRenderTarget extends EventDispatcher { - - constructor( width, height, options = {} ) { - - super(); - - this.isWebGLRenderTarget = true; - - this.width = width; - this.height = height; - this.depth = 1; - - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; - - this.viewport = new Vector4( 0, 0, width, height ); - - const image = { width: width, height: height, depth: 1 }; - - this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - this.texture.isRenderTargetTexture = true; - - this.texture.flipY = false; - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.internalFormat = options.internalFormat !== undefined ? options.internalFormat : null; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false; + class MovingDotSpaceThemeManager extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$k, create_fragment$k, safe_not_equal, { ChangedContentPlaceholder: 0 }); - this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "MovingDotSpaceThemeManager", + options, + id: create_fragment$k.name + }); + } - this.samples = options.samples !== undefined ? options.samples : 0; + get ChangedContentPlaceholder() { + throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); + } + set ChangedContentPlaceholder(value) { + throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); } + } - setSize( width, height, depth = 1 ) { + /* src\MovingDotSpaceGameFight.svelte generated by Svelte v3.59.2 */ - if ( this.width !== width || this.height !== height || this.depth !== depth ) { + const file$j = "src\\MovingDotSpaceGameFight.svelte"; - this.width = width; - this.height = height; - this.depth = depth; + // (115:8) {#if $fightcurrentTurn === 'human' && !gameOver} + function create_if_block$a(ctx) { + let button0; + let t1; + let button1; + let t3; + let button2; + let mounted; + let dispose; - this.texture.image.width = width; - this.texture.image.height = height; - this.texture.image.depth = depth; + const block_1 = { + c: function create() { + button0 = element$1("button"); + button0.textContent = "Attack"; + t1 = space(); + button1 = element$1("button"); + button1.textContent = "Special Attack"; + t3 = space(); + button2 = element$1("button"); + button2.textContent = "Block"; + add_location(button0, file$j, 115, 12, 3914); + add_location(button1, file$j, 116, 12, 4021); + add_location(button2, file$j, 117, 12, 4147); + }, + m: function mount(target, anchor) { + insert_dev(target, button0, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, button1, anchor); + insert_dev(target, t3, anchor); + insert_dev(target, button2, anchor); - this.dispose(); + if (!mounted) { + dispose = [ + listen_dev(button0, "click", /*click_handler*/ ctx[6], false, false, false, false), + listen_dev(button1, "click", /*click_handler_1*/ ctx[7], false, false, false, false), + listen_dev(button2, "click", /*click_handler_2*/ ctx[8], false, false, false, false) + ]; + mounted = true; + } + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(button0); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(button1); + if (detaching) detach_dev(t3); + if (detaching) detach_dev(button2); + mounted = false; + run_all(dispose); } + }; - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - } + dispatch_dev("SvelteRegisterBlock", { + block: block_1, + id: create_if_block$a.name, + type: "if", + source: "(115:8) {#if $fightcurrentTurn === 'human' && !gameOver}", + ctx + }); - clone() { + return block_1; + } - return new this.constructor().copy( this ); + function create_fragment$j(ctx) { + let div4; + let div0; + let t0; + let br0; + let t1; + let t2_value = /*$fightplayerHuman*/ ctx[2].fighthealth + ""; + let t2; + let t3; + let br1; + let t4; + let t5_value = /*$fightplayerHuman*/ ctx[2].fightstamina + ""; + let t5; + let t6; + let br2; + let t7; - } + let t8_value = (/*$fightplayerHuman*/ ctx[2].fightisBlocking + ? 'Blocking' + : '') + ""; - copy( source ) { + let t8; + let t9; + let br3; + let t10; + let t11_value = /*$fightplayerHuman*/ ctx[2].fightcooldowns.attack + ""; + let t11; + let t12; + let br4; + let t13; + let div2; + let div1; - this.width = source.width; - this.height = source.height; - this.depth = source.depth; + let t14_value = (/*gameOver*/ ctx[0] + ? "Game Over" + : /*$fightcurrentTurn*/ ctx[3] === 'human' + ? "Your turn" + : "Computer's turn") + ""; - this.viewport.copy( source.viewport ); + let t14; + let t15; + let t16; + let div3; + let t17; + let br5; + let t18; + let t19_value = /*$fightplayerComputer*/ ctx[1].fighthealth + ""; + let t19; + let t20; + let br6; + let t21; + let t22_value = /*$fightplayerComputer*/ ctx[1].fightstamina + ""; + let t22; + let t23; + let br7; + let t24; - this.texture = source.texture.clone(); - this.texture.isRenderTargetTexture = true; + let t25_value = (/*$fightplayerComputer*/ ctx[1].fightisBlocking + ? 'Blocking' + : '') + ""; - // ensure image object is not shared, see #20328 + let t25; + let t26; + let br8; + let t27; + let t28_value = /*$fightplayerComputer*/ ctx[1].fightcooldowns.attack + ""; + let t28; + let t29; + let br9; + let if_block = /*$fightcurrentTurn*/ ctx[3] === 'human' && !/*gameOver*/ ctx[0] && create_if_block$a(ctx); - const image = Object.assign( {}, source.texture.image ); - this.texture.source = new Source( image ); + const block_1 = { + c: function create() { + div4 = element$1("div"); + div0 = element$1("div"); + t0 = text("Player 1 "); + br0 = element$1("br"); + t1 = text("\r\n Health: "); + t2 = text(t2_value); + t3 = space(); + br1 = element$1("br"); + t4 = text("\r\n Stamina: "); + t5 = text(t5_value); + t6 = space(); + br2 = element$1("br"); + t7 = space(); + t8 = text(t8_value); + t9 = space(); + br3 = element$1("br"); + t10 = text("\r\n Cooldown: Attack - "); + t11 = text(t11_value); + t12 = text("s "); + br4 = element$1("br"); + t13 = space(); + div2 = element$1("div"); + div1 = element$1("div"); + t14 = text(t14_value); + t15 = space(); + if (if_block) if_block.c(); + t16 = space(); + div3 = element$1("div"); + t17 = text("Player 2 "); + br5 = element$1("br"); + t18 = text("\r\n Health: "); + t19 = text(t19_value); + t20 = space(); + br6 = element$1("br"); + t21 = text("\r\n Stamina: "); + t22 = text(t22_value); + t23 = space(); + br7 = element$1("br"); + t24 = space(); + t25 = text(t25_value); + t26 = space(); + br8 = element$1("br"); + t27 = text("\r\n Cooldown: Attack - "); + t28 = text(t28_value); + t29 = text("s "); + br9 = element$1("br"); + add_location(br0, file$j, 103, 17, 3422); + add_location(br1, file$j, 104, 48, 3476); + add_location(br2, file$j, 105, 50, 3532); + add_location(br3, file$j, 106, 62, 3600); + add_location(br4, file$j, 107, 70, 3676); + add_location(div0, file$j, 102, 4, 3398); + add_location(div1, file$j, 111, 8, 3715); + add_location(div2, file$j, 110, 4, 3700); + add_location(br5, file$j, 122, 17, 4269); + add_location(br6, file$j, 123, 51, 4326); + add_location(br7, file$j, 124, 53, 4385); + add_location(br8, file$j, 125, 65, 4456); + add_location(br9, file$j, 126, 73, 4535); + add_location(div3, file$j, 121, 4, 4245); + attr_dev(div4, "class", "statscontainer svelte-izilsr"); + add_location(div4, file$j, 101, 0, 3364); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div4, anchor); + append_dev(div4, div0); + append_dev(div0, t0); + append_dev(div0, br0); + append_dev(div0, t1); + append_dev(div0, t2); + append_dev(div0, t3); + append_dev(div0, br1); + append_dev(div0, t4); + append_dev(div0, t5); + append_dev(div0, t6); + append_dev(div0, br2); + append_dev(div0, t7); + append_dev(div0, t8); + append_dev(div0, t9); + append_dev(div0, br3); + append_dev(div0, t10); + append_dev(div0, t11); + append_dev(div0, t12); + append_dev(div0, br4); + append_dev(div4, t13); + append_dev(div4, div2); + append_dev(div2, div1); + append_dev(div1, t14); + append_dev(div2, t15); + if (if_block) if_block.m(div2, null); + append_dev(div4, t16); + append_dev(div4, div3); + append_dev(div3, t17); + append_dev(div3, br5); + append_dev(div3, t18); + append_dev(div3, t19); + append_dev(div3, t20); + append_dev(div3, br6); + append_dev(div3, t21); + append_dev(div3, t22); + append_dev(div3, t23); + append_dev(div3, br7); + append_dev(div3, t24); + append_dev(div3, t25); + append_dev(div3, t26); + append_dev(div3, br8); + append_dev(div3, t27); + append_dev(div3, t28); + append_dev(div3, t29); + append_dev(div3, br9); + }, + p: function update(ctx, [dirty]) { + if (dirty & /*$fightplayerHuman*/ 4 && t2_value !== (t2_value = /*$fightplayerHuman*/ ctx[2].fighthealth + "")) set_data_dev(t2, t2_value); + if (dirty & /*$fightplayerHuman*/ 4 && t5_value !== (t5_value = /*$fightplayerHuman*/ ctx[2].fightstamina + "")) set_data_dev(t5, t5_value); - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; + if (dirty & /*$fightplayerHuman*/ 4 && t8_value !== (t8_value = (/*$fightplayerHuman*/ ctx[2].fightisBlocking + ? 'Blocking' + : '') + "")) set_data_dev(t8, t8_value); - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); + if (dirty & /*$fightplayerHuman*/ 4 && t11_value !== (t11_value = /*$fightplayerHuman*/ ctx[2].fightcooldowns.attack + "")) set_data_dev(t11, t11_value); - this.samples = source.samples; + if (dirty & /*gameOver, $fightcurrentTurn*/ 9 && t14_value !== (t14_value = (/*gameOver*/ ctx[0] + ? "Game Over" + : /*$fightcurrentTurn*/ ctx[3] === 'human' + ? "Your turn" + : "Computer's turn") + "")) set_data_dev(t14, t14_value); - return this; + if (/*$fightcurrentTurn*/ ctx[3] === 'human' && !/*gameOver*/ ctx[0]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block$a(ctx); + if_block.c(); + if_block.m(div2, null); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } - } + if (dirty & /*$fightplayerComputer*/ 2 && t19_value !== (t19_value = /*$fightplayerComputer*/ ctx[1].fighthealth + "")) set_data_dev(t19, t19_value); + if (dirty & /*$fightplayerComputer*/ 2 && t22_value !== (t22_value = /*$fightplayerComputer*/ ctx[1].fightstamina + "")) set_data_dev(t22, t22_value); - dispose() { + if (dirty & /*$fightplayerComputer*/ 2 && t25_value !== (t25_value = (/*$fightplayerComputer*/ ctx[1].fightisBlocking + ? 'Blocking' + : '') + "")) set_data_dev(t25, t25_value); - this.dispatchEvent( { type: 'dispose' } ); + if (dirty & /*$fightplayerComputer*/ 2 && t28_value !== (t28_value = /*$fightplayerComputer*/ ctx[1].fightcooldowns.attack + "")) set_data_dev(t28, t28_value); + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div4); + if (if_block) if_block.d(); + } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block: block_1, + id: create_fragment$j.name, + type: "component", + source: "", + ctx + }); + return block_1; } - class DataArrayTexture extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - super( null ); - - this.isDataArrayTexture = true; - - this.image = { data, width, height, depth }; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + function instance$j($$self, $$props, $$invalidate) { + let $fightplayerComputer; + let $fightplayerHuman; + let $fightcurrentTurn; + validate_store(fightplayerComputer, 'fightplayerComputer'); + component_subscribe($$self, fightplayerComputer, $$value => $$invalidate(1, $fightplayerComputer = $$value)); + validate_store(fightplayerHuman, 'fightplayerHuman'); + component_subscribe($$self, fightplayerHuman, $$value => $$invalidate(2, $fightplayerHuman = $$value)); + validate_store(fightcurrentTurn, 'fightcurrentTurn'); + component_subscribe($$self, fightcurrentTurn, $$value => $$invalidate(3, $fightcurrentTurn = $$value)); + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('MovingDotSpaceGameFight', slots, []); + let gameOver = false; - this.wrapR = ClampToEdgeWrapping; + function isPlayerTurn(player) { + return $fightcurrentTurn === 'human' && player === fightplayerHuman || $fightcurrentTurn === 'computer' && player === fightplayerComputer; + } - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + function switchTurn() { + if (!gameOver) { + fightcurrentTurn.update(turn => turn === 'human' ? 'computer' : 'human'); + if ($fightcurrentTurn === 'computer') { + setTimeout(computerAction, 1000); // Simulate thinking delay for the computer's turn + } + } } - } - - class WebGLArrayRenderTarget extends WebGLRenderTarget { + function updateFightPlayer(player, changes) { + player.update(current => ({ ...current, ...changes })); + checkGameOver(); + } - constructor( width, height, depth ) { + function performAttack(attacker, defender, attackType = 'normal') { + if (!isPlayerTurn(attacker) || gameOver) return; - super( width, height ); + attacker.update(a => { + if (a.fightstamina < 20 || a.fightcooldowns.attack > 0) { + return a; // Not enough stamina or attack is on cooldown + } - this.isWebGLArrayRenderTarget = true; + defender.update(d => { + if (!d.fightisBlocking) { + d.fighthealth -= attackType === 'normal' ? 10 : 25; // Special attack does more damage + } - this.depth = depth; + return d; + }); - this.texture = new DataArrayTexture( null, width, height, depth ); + return { + ...a, + fightstamina: a.fightstamina - 20, + fightcooldowns: { + ...a.fightcooldowns, + attack: attackType === 'normal' ? 1 : 3 + }, // Cooldown in seconds + + }; + }); - this.texture.isRenderTargetTexture = true; + // Start cooldown timer + setTimeout( + () => { + attacker.update(a => ({ + ...a, + fightcooldowns: { ...a.fightcooldowns, attack: 0 } + })); + }, + attackType === 'normal' ? 1000 : 3000 + ); // Cooldown period + checkGameOver(); + switchTurn(); } - } - - class Data3DTexture extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 - - super( null ); + function block(player) { + if (!isPlayerTurn(player) || gameOver) return; + updateFightPlayer(player, { fightisBlocking: true }); - this.isData3DTexture = true; + setTimeout( + () => { + updateFightPlayer(player, { fightisBlocking: false }); + }, + 1000 + ); // Unblock after 1 second - this.image = { data, width, height, depth }; + checkGameOver(); + switchTurn(); + } - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + function computerAction() { + const action = Math.random() > 0.4 ? 'attack' : 'block'; - this.wrapR = ClampToEdgeWrapping; + if (action === 'attack') { + performAttack(fightplayerComputer, fightplayerHuman); + } else { + block(fightplayerComputer); + } + } - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + function checkGameOver() { + const human = $fightplayerHuman; + const computer = $fightplayerComputer; + if (human.fighthealth <= 0 || computer.fighthealth <= 0 || human.fightstamina <= 0 && computer.fightstamina <= 0) { + $$invalidate(0, gameOver = true); + determineWinner(); + } } - } - - class WebGL3DRenderTarget extends WebGLRenderTarget { + function determineWinner() { + const human = $fightplayerHuman; + const computer = $fightplayerComputer; - constructor( width, height, depth ) { + if (human.fighthealth > computer.fighthealth) { + alert('Game Over! You win!'); + } else if (human.fighthealth < computer.fighthealth) { + alert('Game Over! Computer wins!'); + } else { + alert('Game Over! It\'s a tie!'); + } + } - super( width, height ); + const writable_props = []; - this.isWebGL3DRenderTarget = true; + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); - this.depth = depth; + const click_handler = () => performAttack(fightplayerHuman, fightplayerComputer); + const click_handler_1 = () => performAttack(fightplayerHuman, fightplayerComputer, 'special'); + const click_handler_2 = () => block(fightplayerHuman); - this.texture = new Data3DTexture( null, width, height, depth ); + $$self.$capture_state = () => ({ + fightplayerHuman, + fightplayerComputer, + fightcurrentTurn, + gameOver, + isPlayerTurn, + switchTurn, + updateFightPlayer, + performAttack, + block, + computerAction, + checkGameOver, + determineWinner, + $fightplayerComputer, + $fightplayerHuman, + $fightcurrentTurn + }); - this.texture.isRenderTargetTexture = true; + $$self.$inject_state = $$props => { + if ('gameOver' in $$props) $$invalidate(0, gameOver = $$props.gameOver); + }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); } + return [ + gameOver, + $fightplayerComputer, + $fightplayerHuman, + $fightcurrentTurn, + performAttack, + block, + click_handler, + click_handler_1, + click_handler_2 + ]; } - class WebGLMultipleRenderTargets extends WebGLRenderTarget { - - constructor( width, height, count, options = {} ) { + class MovingDotSpaceGameFight extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$j, create_fragment$j, safe_not_equal, {}); - super( width, height, options ); + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "MovingDotSpaceGameFight", + options, + id: create_fragment$j.name + }); + } + } - this.isWebGLMultipleRenderTargets = true; + /* src\MovingDotSpaceGameFightMultiTheme.svelte generated by Svelte v3.59.2 */ - const texture = this.texture; + const { Object: Object_1$3 } = globals; - this.texture = []; + const file$i = "src\\MovingDotSpaceGameFightMultiTheme.svelte"; - for ( let i = 0; i < count; i ++ ) { + function get_each_context$e(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[20] = list[i]; + return child_ctx; + } - this.texture[ i ] = texture.clone(); - this.texture[ i ].isRenderTargetTexture = true; + // (202:4) {#each Object.keys(themes) as theme} + function create_each_block$e(ctx) { + let option; + let t_value = /*theme*/ ctx[20] + ""; + let t; + const block_1 = { + c: function create() { + option = element$1("option"); + t = text(t_value); + option.__value = /*theme*/ ctx[20]; + option.value = option.__value; + add_location(option, file$i, 202, 8, 6935); + }, + m: function mount(target, anchor) { + insert_dev(target, option, anchor); + append_dev(option, t); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(option); } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block: block_1, + id: create_each_block$e.name, + type: "each", + source: "(202:4) {#each Object.keys(themes) as theme}", + ctx + }); - setSize( width, height, depth = 1 ) { + return block_1; + } - if ( this.width !== width || this.height !== height || this.depth !== depth ) { + // (207:0) {#if $selectedTheme} + function create_if_block$9(ctx) { + let div4; + let div0; + let t0; + let br0; + let t1; + let t2_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].health + ""; + let t2; + let t3; + let t4_value = /*$themedfightplayerHuman*/ ctx[2].fighthealth + ""; + let t4; + let t5; + let br1; + let t6; + let t7_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].stamina + ""; + let t7; + let t8; + let t9_value = /*$themedfightplayerHuman*/ ctx[2].fightstamina + ""; + let t9; + let t10; + let br2; + let t11; - this.width = width; - this.height = height; - this.depth = depth; + let t12_value = (/*$themedfightplayerHuman*/ ctx[2].fightisBlocking + ? /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].blocking + : '') + ""; - for ( let i = 0, il = this.texture.length; i < il; i ++ ) { + let t12; + let t13; + let br3; + let t14; + let t15_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].attack + ""; + let t15; + let t16; + let t17_value = /*$themedfightplayerHuman*/ ctx[2].fightcooldowns.attack + ""; + let t17; + let t18; + let br4; + let t19; + let div2; + let div1; - this.texture[ i ].image.width = width; - this.texture[ i ].image.height = height; - this.texture[ i ].image.depth = depth; + let t20_value = (/*gameOver*/ ctx[0] + ? "Game Over" + : /*$themedfightcurrentTurn*/ ctx[3] === 'human' + ? "Your turn" + : "Computer's turn") + ""; - } + let t20; + let t21; + let t22; + let t23; + let div3; + let t24; + let br5; + let t25; + let t26_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].health + ""; + let t26; + let t27; + let t28_value = /*$themedfightplayerComputer*/ ctx[1].fighthealth + ""; + let t28; + let t29; + let br6; + let t30; + let t31_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].stamina + ""; + let t31; + let t32; + let t33_value = /*$themedfightplayerComputer*/ ctx[1].fightstamina + ""; + let t33; + let t34; + let br7; + let t35; - this.dispose(); + let t36_value = (/*$themedfightplayerComputer*/ ctx[1].fightisBlocking + ? /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].blocking + : '') + ""; - } + let t36; + let t37; + let br8; + let t38; + let t39_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].attack + ""; + let t39; + let t40; + let t41_value = /*$themedfightplayerComputer*/ ctx[1].fightcooldowns.attack + ""; + let t41; + let t42; + let br9; + let if_block0 = /*$themedfightcurrentTurn*/ ctx[3] === 'human' && !/*gameOver*/ ctx[0] && create_if_block_2$3(ctx); + let if_block1 = /*gameOver*/ ctx[0] && create_if_block_1$6(ctx); - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); + const block_1 = { + c: function create() { + div4 = element$1("div"); + div0 = element$1("div"); + t0 = text("Player 1 "); + br0 = element$1("br"); + t1 = space(); + t2 = text(t2_value); + t3 = text(": "); + t4 = text(t4_value); + t5 = space(); + br1 = element$1("br"); + t6 = space(); + t7 = text(t7_value); + t8 = text(": "); + t9 = text(t9_value); + t10 = space(); + br2 = element$1("br"); + t11 = space(); + t12 = text(t12_value); + t13 = space(); + br3 = element$1("br"); + t14 = text("\r\n Cooldown: "); + t15 = text(t15_value); + t16 = text(" - "); + t17 = text(t17_value); + t18 = text("s "); + br4 = element$1("br"); + t19 = space(); + div2 = element$1("div"); + div1 = element$1("div"); + t20 = text(t20_value); + t21 = space(); + if (if_block0) if_block0.c(); + t22 = space(); + if (if_block1) if_block1.c(); + t23 = space(); + div3 = element$1("div"); + t24 = text("Player 2 "); + br5 = element$1("br"); + t25 = space(); + t26 = text(t26_value); + t27 = text(": "); + t28 = text(t28_value); + t29 = space(); + br6 = element$1("br"); + t30 = space(); + t31 = text(t31_value); + t32 = text(": "); + t33 = text(t33_value); + t34 = space(); + br7 = element$1("br"); + t35 = space(); + t36 = text(t36_value); + t37 = space(); + br8 = element$1("br"); + t38 = text("\r\n Cooldown: "); + t39 = text(t39_value); + t40 = text(" - "); + t41 = text(t41_value); + t42 = text("s "); + br9 = element$1("br"); + add_location(br0, file$i, 209, 21, 7093); + add_location(br1, file$i, 210, 83, 7182); + add_location(br2, file$i, 211, 85, 7273); + add_location(br3, file$i, 212, 93, 7372); + add_location(br4, file$i, 213, 105, 7483); + add_location(div0, file$i, 208, 8, 7065); + add_location(div1, file$i, 217, 12, 7534); + add_location(div2, file$i, 216, 8, 7515); + add_location(br5, file$i, 231, 21, 8364); + add_location(br6, file$i, 232, 86, 8456); + add_location(br7, file$i, 233, 88, 8550); + add_location(br8, file$i, 234, 96, 8652); + add_location(br9, file$i, 235, 108, 8766); + add_location(div3, file$i, 230, 8, 8336); + attr_dev(div4, "class", "statscontainer svelte-izilsr"); + add_location(div4, file$i, 207, 4, 7027); + }, + m: function mount(target, anchor) { + insert_dev(target, div4, anchor); + append_dev(div4, div0); + append_dev(div0, t0); + append_dev(div0, br0); + append_dev(div0, t1); + append_dev(div0, t2); + append_dev(div0, t3); + append_dev(div0, t4); + append_dev(div0, t5); + append_dev(div0, br1); + append_dev(div0, t6); + append_dev(div0, t7); + append_dev(div0, t8); + append_dev(div0, t9); + append_dev(div0, t10); + append_dev(div0, br2); + append_dev(div0, t11); + append_dev(div0, t12); + append_dev(div0, t13); + append_dev(div0, br3); + append_dev(div0, t14); + append_dev(div0, t15); + append_dev(div0, t16); + append_dev(div0, t17); + append_dev(div0, t18); + append_dev(div0, br4); + append_dev(div4, t19); + append_dev(div4, div2); + append_dev(div2, div1); + append_dev(div1, t20); + append_dev(div2, t21); + if (if_block0) if_block0.m(div2, null); + append_dev(div2, t22); + if (if_block1) if_block1.m(div2, null); + append_dev(div4, t23); + append_dev(div4, div3); + append_dev(div3, t24); + append_dev(div3, br5); + append_dev(div3, t25); + append_dev(div3, t26); + append_dev(div3, t27); + append_dev(div3, t28); + append_dev(div3, t29); + append_dev(div3, br6); + append_dev(div3, t30); + append_dev(div3, t31); + append_dev(div3, t32); + append_dev(div3, t33); + append_dev(div3, t34); + append_dev(div3, br7); + append_dev(div3, t35); + append_dev(div3, t36); + append_dev(div3, t37); + append_dev(div3, br8); + append_dev(div3, t38); + append_dev(div3, t39); + append_dev(div3, t40); + append_dev(div3, t41); + append_dev(div3, t42); + append_dev(div3, br9); + }, + p: function update(ctx, dirty) { + if (dirty & /*$selectedTheme*/ 16 && t2_value !== (t2_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].health + "")) set_data_dev(t2, t2_value); + if (dirty & /*$themedfightplayerHuman*/ 4 && t4_value !== (t4_value = /*$themedfightplayerHuman*/ ctx[2].fighthealth + "")) set_data_dev(t4, t4_value); + if (dirty & /*$selectedTheme*/ 16 && t7_value !== (t7_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].stamina + "")) set_data_dev(t7, t7_value); + if (dirty & /*$themedfightplayerHuman*/ 4 && t9_value !== (t9_value = /*$themedfightplayerHuman*/ ctx[2].fightstamina + "")) set_data_dev(t9, t9_value); - return this; + if (dirty & /*$themedfightplayerHuman, $selectedTheme*/ 20 && t12_value !== (t12_value = (/*$themedfightplayerHuman*/ ctx[2].fightisBlocking + ? /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].blocking + : '') + "")) set_data_dev(t12, t12_value); - } + if (dirty & /*$selectedTheme*/ 16 && t15_value !== (t15_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].attack + "")) set_data_dev(t15, t15_value); + if (dirty & /*$themedfightplayerHuman*/ 4 && t17_value !== (t17_value = /*$themedfightplayerHuman*/ ctx[2].fightcooldowns.attack + "")) set_data_dev(t17, t17_value); - copy( source ) { + if (dirty & /*gameOver, $themedfightcurrentTurn*/ 9 && t20_value !== (t20_value = (/*gameOver*/ ctx[0] + ? "Game Over" + : /*$themedfightcurrentTurn*/ ctx[3] === 'human' + ? "Your turn" + : "Computer's turn") + "")) set_data_dev(t20, t20_value); - this.dispose(); + if (/*$themedfightcurrentTurn*/ ctx[3] === 'human' && !/*gameOver*/ ctx[0]) { + if (if_block0) { + if_block0.p(ctx, dirty); + } else { + if_block0 = create_if_block_2$3(ctx); + if_block0.c(); + if_block0.m(div2, t22); + } + } else if (if_block0) { + if_block0.d(1); + if_block0 = null; + } - this.width = source.width; - this.height = source.height; - this.depth = source.depth; + if (/*gameOver*/ ctx[0]) { + if (if_block1) { + if_block1.p(ctx, dirty); + } else { + if_block1 = create_if_block_1$6(ctx); + if_block1.c(); + if_block1.m(div2, null); + } + } else if (if_block1) { + if_block1.d(1); + if_block1 = null; + } - this.viewport.set( 0, 0, this.width, this.height ); - this.scissor.set( 0, 0, this.width, this.height ); + if (dirty & /*$selectedTheme*/ 16 && t26_value !== (t26_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].health + "")) set_data_dev(t26, t26_value); + if (dirty & /*$themedfightplayerComputer*/ 2 && t28_value !== (t28_value = /*$themedfightplayerComputer*/ ctx[1].fighthealth + "")) set_data_dev(t28, t28_value); + if (dirty & /*$selectedTheme*/ 16 && t31_value !== (t31_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].stamina + "")) set_data_dev(t31, t31_value); + if (dirty & /*$themedfightplayerComputer*/ 2 && t33_value !== (t33_value = /*$themedfightplayerComputer*/ ctx[1].fightstamina + "")) set_data_dev(t33, t33_value); - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; + if (dirty & /*$themedfightplayerComputer, $selectedTheme*/ 18 && t36_value !== (t36_value = (/*$themedfightplayerComputer*/ ctx[1].fightisBlocking + ? /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].blocking + : '') + "")) set_data_dev(t36, t36_value); - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); + if (dirty & /*$selectedTheme*/ 16 && t39_value !== (t39_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].attack + "")) set_data_dev(t39, t39_value); + if (dirty & /*$themedfightplayerComputer*/ 2 && t41_value !== (t41_value = /*$themedfightplayerComputer*/ ctx[1].fightcooldowns.attack + "")) set_data_dev(t41, t41_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div4); + if (if_block0) if_block0.d(); + if (if_block1) if_block1.d(); + } + }; - this.texture.length = 0; + dispatch_dev("SvelteRegisterBlock", { + block: block_1, + id: create_if_block$9.name, + type: "if", + source: "(207:0) {#if $selectedTheme}", + ctx + }); - for ( let i = 0, il = source.texture.length; i < il; i ++ ) { + return block_1; + } - this.texture[ i ] = source.texture[ i ].clone(); - this.texture[ i ].isRenderTargetTexture = true; + // (221:12) {#if $themedfightcurrentTurn === 'human' && !gameOver} + function create_if_block_2$3(ctx) { + let button0; + let t0_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].attack + ""; + let t0; + let t1; + let button1; + let t2_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].specialAttack + ""; + let t2; + let t3; + let button2; + let t4_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].blocking + ""; + let t4; + let mounted; + let dispose; - } + const block_1 = { + c: function create() { + button0 = element$1("button"); + t0 = text(t0_value); + t1 = space(); + button1 = element$1("button"); + t2 = text(t2_value); + t3 = space(); + button2 = element$1("button"); + t4 = text(t4_value); + add_location(button0, file$i, 221, 16, 7761); + add_location(button1, file$i, 222, 16, 7909); + add_location(button2, file$i, 223, 16, 8075); + }, + m: function mount(target, anchor) { + insert_dev(target, button0, anchor); + append_dev(button0, t0); + insert_dev(target, t1, anchor); + insert_dev(target, button1, anchor); + append_dev(button1, t2); + insert_dev(target, t3, anchor); + insert_dev(target, button2, anchor); + append_dev(button2, t4); - return this; + if (!mounted) { + dispose = [ + listen_dev(button0, "click", /*click_handler*/ ctx[11], false, false, false, false), + listen_dev(button1, "click", /*click_handler_1*/ ctx[12], false, false, false, false), + listen_dev(button2, "click", /*click_handler_2*/ ctx[13], false, false, false, false) + ]; - } + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty & /*$selectedTheme*/ 16 && t0_value !== (t0_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].attack + "")) set_data_dev(t0, t0_value); + if (dirty & /*$selectedTheme*/ 16 && t2_value !== (t2_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].specialAttack + "")) set_data_dev(t2, t2_value); + if (dirty & /*$selectedTheme*/ 16 && t4_value !== (t4_value = /*themes*/ ctx[5][/*$selectedTheme*/ ctx[4]].blocking + "")) set_data_dev(t4, t4_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button0); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(button1); + if (detaching) detach_dev(t3); + if (detaching) detach_dev(button2); + mounted = false; + run_all(dispose); + } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block: block_1, + id: create_if_block_2$3.name, + type: "if", + source: "(221:12) {#if $themedfightcurrentTurn === 'human' && !gameOver}", + ctx + }); - class Quaternion { + return block_1; + } - constructor( x = 0, y = 0, z = 0, w = 1 ) { + // (226:12) {#if gameOver} + function create_if_block_1$6(ctx) { + let button; + let mounted; + let dispose; - this.isQuaternion = true; + const block_1 = { + c: function create() { + button = element$1("button"); + button.textContent = "Restart Game"; + add_location(button, file$i, 226, 16, 8237); + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); - this._x = x; - this._y = y; - this._z = z; - this._w = w; + if (!mounted) { + dispose = listen_dev(button, "click", /*restartGame*/ ctx[9], false, false, false, false); + mounted = true; + } + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; - } + dispatch_dev("SvelteRegisterBlock", { + block: block_1, + id: create_if_block_1$6.name, + type: "if", + source: "(226:12) {#if gameOver}", + ctx + }); - static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + return block_1; + } - // fuzz-free, array-based Quaternion SLERP operation + function create_fragment$i(ctx) { + let select; + let t; + let if_block_anchor; + let mounted; + let dispose; + let each_value = Object.keys(/*themes*/ ctx[5]); + validate_each_argument(each_value); + let each_blocks = []; - let x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ]; + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$e(get_each_context$e(ctx, each_value, i)); + } - const x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; + let if_block = /*$selectedTheme*/ ctx[4] && create_if_block$9(ctx); - if ( t === 0 ) { + const block_1 = { + c: function create() { + select = element$1("select"); - dst[ dstOffset + 0 ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - return; + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } - } + t = space(); + if (if_block) if_block.c(); + if_block_anchor = empty(); + if (/*$selectedTheme*/ ctx[4] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[10].call(select)); + add_location(select, file$i, 200, 0, 6847); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, select, anchor); - if ( t === 1 ) { + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(select, null); + } + } - dst[ dstOffset + 0 ] = x1; - dst[ dstOffset + 1 ] = y1; - dst[ dstOffset + 2 ] = z1; - dst[ dstOffset + 3 ] = w1; - return; + select_option(select, /*$selectedTheme*/ ctx[4], true); + insert_dev(target, t, anchor); + if (if_block) if_block.m(target, anchor); + insert_dev(target, if_block_anchor, anchor); - } + if (!mounted) { + dispose = listen_dev(select, "change", /*select_change_handler*/ ctx[10]); + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*Object, themes*/ 32) { + each_value = Object.keys(/*themes*/ ctx[5]); + validate_each_argument(each_value); + let i; - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$e(ctx, each_value, i); - let s = 1 - t; - const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$e(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(select, null); + } + } - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } - const sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); + each_blocks.length = each_value.length; + } - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; + if (dirty & /*$selectedTheme, Object, themes*/ 48) { + select_option(select, /*$selectedTheme*/ ctx[4]); + } + if (/*$selectedTheme*/ ctx[4]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block$9(ctx); + if_block.c(); + if_block.m(if_block_anchor.parentNode, if_block_anchor); + } + } else if (if_block) { + if_block.d(1); + if_block = null; } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(select); + destroy_each(each_blocks, detaching); + if (detaching) detach_dev(t); + if (if_block) if_block.d(detaching); + if (detaching) detach_dev(if_block_anchor); + mounted = false; + dispose(); + } + }; - const tDir = t * dir; + dispatch_dev("SvelteRegisterBlock", { + block: block_1, + id: create_fragment$i.name, + type: "component", + source: "", + ctx + }); - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; + return block_1; + } - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { + function instance$i($$self, $$props, $$invalidate) { + let $themedfightplayerComputer; + let $themedfightplayerHuman; + let $themedfightcurrentTurn; + let $selectedTheme; + validate_store(themedfightplayerComputer, 'themedfightplayerComputer'); + component_subscribe($$self, themedfightplayerComputer, $$value => $$invalidate(1, $themedfightplayerComputer = $$value)); + validate_store(themedfightplayerHuman, 'themedfightplayerHuman'); + component_subscribe($$self, themedfightplayerHuman, $$value => $$invalidate(2, $themedfightplayerHuman = $$value)); + validate_store(themedfightcurrentTurn, 'themedfightcurrentTurn'); + component_subscribe($$self, themedfightcurrentTurn, $$value => $$invalidate(3, $themedfightcurrentTurn = $$value)); + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('MovingDotSpaceGameFightMultiTheme', slots, []); + let gameOver = false; + + const themes = { + "Running": { + health: "Energy", + stamina: "Speed", + blocking: "Resting", + attack: "Sprint", + specialAttack: "Boost" + }, + "Washing Clothes": { + health: "Cleanliness Level", + stamina: "Washing Machine Load", + blocking: "Pause Cycle", + attack: "Wash", + specialAttack: "Deep Clean" + }, + "Waiting in a Queue": { + health: "Patience", + stamina: "Position in Queue", + blocking: "Take a Break", + attack: "Move Forward", + specialAttack: "Skip Ahead" + }, + "Giving a Speech": { + health: "Confidence", + stamina: "Speech Length", + blocking: "Pause", + attack: "Deliver Point", + specialAttack: "Engaging Story" + }, + "Studying for an Exam": { + health: "Knowledge", + stamina: "Focus", + blocking: "Take a Break", + attack: "Study Topic", + specialAttack: "Intensive Study Session" + }, + "Cooking Competition": { + health: "Dish Quality", + stamina: "Ingredients", + blocking: "Take a Break", + attack: "Cook", + specialAttack: "Special Recipe" + }, + "Gardening": { + health: "Plant Health", + stamina: "Water Supply", + blocking: "Pause Work", + attack: "Water Plants", + specialAttack: "Fertilize" + }, + "Painting a Room": { + health: "Wall Coverage", + stamina: "Paint Supply", + blocking: "Take a Break", + attack: "Paint Wall", + specialAttack: "Detailed Brushwork" + }, + "Cleaning a House": { + health: "Cleanliness", + stamina: "Cleaning Supplies", + blocking: "Take a Break", + attack: "Clean Room", + specialAttack: "Deep Clean Room" + }, + "Repairing a Car": { + health: "Car Condition", + stamina: "Tools and Parts", + blocking: "Pause Repair", + attack: "Fix Part", + specialAttack: "Major Overhaul" + }, + "Camping Trip": { + health: "Camp Comfort", + stamina: "Supplies", + blocking: "Rest", + attack: "Set Up Tent", + specialAttack: "Build Campfire" + }, + "Building a Model": { + health: "Model Quality", + stamina: "Building Materials", + blocking: "Pause Work", + attack: "Add Piece", + specialAttack: "Detailed Work" + } + }; - const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + let selectedTheme = writable(Object.keys(themes)[0]); + validate_store(selectedTheme, 'selectedTheme'); + component_subscribe($$self, selectedTheme, value => $$invalidate(4, $selectedTheme = value)); - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; + function isPlayerTurn(player) { + return $themedfightcurrentTurn === 'human' && player === themedfightplayerHuman || $themedfightcurrentTurn === 'computer' && player === themedfightplayerComputer; + } - } + function switchTurn() { + if (!gameOver) { + themedfightcurrentTurn.update(turn => turn === 'human' ? 'computer' : 'human'); + if ($themedfightcurrentTurn === 'computer') { + setTimeout(computerAction, 1000); // Simulate thinking delay for the computer's turn + } } + } - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - + function updateThemedFightPlayer(player, changes) { + player.update(current => ({ ...current, ...changes })); + checkGameOver(); } - static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { + function performAttack(attacker, defender, attackType = 'normal') { + if (!isPlayerTurn(attacker) || gameOver) return; - const x0 = src0[ srcOffset0 ]; - const y0 = src0[ srcOffset0 + 1 ]; - const z0 = src0[ srcOffset0 + 2 ]; - const w0 = src0[ srcOffset0 + 3 ]; + attacker.update(a => { + if (a.fightstamina < 20 || a.fightcooldowns.attack > 0) { + return a; // Not enough stamina or attack is on cooldown + } - const x1 = src1[ srcOffset1 ]; - const y1 = src1[ srcOffset1 + 1 ]; - const z1 = src1[ srcOffset1 + 2 ]; - const w1 = src1[ srcOffset1 + 3 ]; + defender.update(d => { + if (!d.fightisBlocking) { + d.fighthealth -= attackType === 'normal' ? 10 : 25; // Special attack does more damage + } - dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; - dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; - dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; - dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; + return d; + }); - return dst; + return { + ...a, + fightstamina: a.fightstamina - 20, + fightcooldowns: { + ...a.fightcooldowns, + attack: attackType === 'normal' ? 1 : 3 + }, // Cooldown in seconds + + }; + }); + + // Start cooldown timer + setTimeout( + () => { + attacker.update(a => ({ + ...a, + fightcooldowns: { ...a.fightcooldowns, attack: 0 } + })); + }, + attackType === 'normal' ? 1000 : 3000 + ); // Cooldown period + checkGameOver(); + switchTurn(); } - get x() { + function block(player) { + if (!isPlayerTurn(player) || gameOver) return; + updateThemedFightPlayer(player, { fightisBlocking: true }); - return this._x; + setTimeout( + () => { + updateThemedFightPlayer(player, { fightisBlocking: false }); + }, + 1000 + ); // Unblock after 1 second + checkGameOver(); + switchTurn(); } - set x( value ) { - - this._x = value; - this._onChangeCallback(); + function computerAction() { + const action = Math.random() > 0.4 ? 'attack' : 'block'; + if (action === 'attack') { + performAttack(themedfightplayerComputer, themedfightplayerHuman); + } else { + block(themedfightplayerComputer); + } } - get y() { - - return this._y; + function checkGameOver() { + const human = $themedfightplayerHuman; + const computer = $themedfightplayerComputer; + if (human.fighthealth <= 0 || computer.fighthealth <= 0 || human.fightstamina <= 0 && computer.fightstamina <= 0) { + $$invalidate(0, gameOver = true); + determineWinner(); + } } - set y( value ) { - - this._y = value; - this._onChangeCallback(); + function determineWinner() { + const human = $themedfightplayerHuman; + const computer = $themedfightplayerComputer; + if (human.fighthealth > computer.fighthealth) { + alert('Game Over! You win!'); + } else if (human.fighthealth < computer.fighthealth) { + alert('Game Over! Computer wins!'); + } else { + alert('Game Over! It\'s a tie!'); + } } - get z() { + function restartGame() { + $$invalidate(0, gameOver = false); - return this._z; + themedfightplayerHuman.set({ + fighthealth: 100, + fightstamina: 100, + fightisBlocking: false, + fightcooldowns: { attack: 0 } + }); + + themedfightplayerComputer.set({ + fighthealth: 100, + fightstamina: 100, + fightisBlocking: false, + fightcooldowns: { attack: 0 } + }); + themedfightcurrentTurn.set('human'); } - set z( value ) { + const writable_props = []; - this._z = value; - this._onChangeCallback(); + Object_1$3.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + function select_change_handler() { + $selectedTheme = select_value(this); + selectedTheme.set($selectedTheme); + $$invalidate(5, themes); } - get w() { - - return this._w; - - } + const click_handler = () => performAttack(themedfightplayerHuman, themedfightplayerComputer); + const click_handler_1 = () => performAttack(themedfightplayerHuman, themedfightplayerComputer, 'special'); + const click_handler_2 = () => block(themedfightplayerHuman); - set w( value ) { + $$self.$capture_state = () => ({ + writable, + themedfightplayerHuman, + themedfightplayerComputer, + themedfightcurrentTurn, + gameOver, + themes, + selectedTheme, + isPlayerTurn, + switchTurn, + updateThemedFightPlayer, + performAttack, + block, + computerAction, + checkGameOver, + determineWinner, + restartGame, + $themedfightplayerComputer, + $themedfightplayerHuman, + $themedfightcurrentTurn, + $selectedTheme + }); - this._w = value; - this._onChangeCallback(); + $$self.$inject_state = $$props => { + if ('gameOver' in $$props) $$invalidate(0, gameOver = $$props.gameOver); + if ('selectedTheme' in $$props) $$invalidate(6, selectedTheme = $$props.selectedTheme); + }; + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); } - set( x, y, z, w ) { - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - this._onChangeCallback(); + return [ + gameOver, + $themedfightplayerComputer, + $themedfightplayerHuman, + $themedfightcurrentTurn, + $selectedTheme, + themes, + selectedTheme, + performAttack, + block, + restartGame, + select_change_handler, + click_handler, + click_handler_1, + click_handler_2 + ]; + } - return this; + class MovingDotSpaceGameFightMultiTheme extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$i, create_fragment$i, safe_not_equal, {}); + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "MovingDotSpaceGameFightMultiTheme", + options, + id: create_fragment$i.name + }); } + } - clone() { + /** + * @license + * Copyright 2010-2022 Three.js Authors + * SPDX-License-Identifier: MIT + */ + const REVISION = '145'; + const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; + const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; + const CullFaceNone = 0; + const CullFaceBack = 1; + const CullFaceFront = 2; + const CullFaceFrontBack = 3; + const BasicShadowMap = 0; + const PCFShadowMap = 1; + const PCFSoftShadowMap = 2; + const VSMShadowMap = 3; + const FrontSide = 0; + const BackSide = 1; + const DoubleSide = 2; + const NoBlending = 0; + const NormalBlending = 1; + const AdditiveBlending = 2; + const SubtractiveBlending = 3; + const MultiplyBlending = 4; + const CustomBlending = 5; + const AddEquation = 100; + const SubtractEquation = 101; + const ReverseSubtractEquation = 102; + const MinEquation = 103; + const MaxEquation = 104; + const ZeroFactor = 200; + const OneFactor = 201; + const SrcColorFactor = 202; + const OneMinusSrcColorFactor = 203; + const SrcAlphaFactor = 204; + const OneMinusSrcAlphaFactor = 205; + const DstAlphaFactor = 206; + const OneMinusDstAlphaFactor = 207; + const DstColorFactor = 208; + const OneMinusDstColorFactor = 209; + const SrcAlphaSaturateFactor = 210; + const NeverDepth = 0; + const AlwaysDepth = 1; + const LessDepth = 2; + const LessEqualDepth = 3; + const EqualDepth = 4; + const GreaterEqualDepth = 5; + const GreaterDepth = 6; + const NotEqualDepth = 7; + const MultiplyOperation = 0; + const MixOperation = 1; + const AddOperation = 2; + const NoToneMapping = 0; + const LinearToneMapping = 1; + const ReinhardToneMapping = 2; + const CineonToneMapping = 3; + const ACESFilmicToneMapping = 4; + const CustomToneMapping = 5; - return new this.constructor( this._x, this._y, this._z, this._w ); + const UVMapping = 300; + const CubeReflectionMapping = 301; + const CubeRefractionMapping = 302; + const EquirectangularReflectionMapping = 303; + const EquirectangularRefractionMapping = 304; + const CubeUVReflectionMapping = 306; + const RepeatWrapping = 1000; + const ClampToEdgeWrapping = 1001; + const MirroredRepeatWrapping = 1002; + const NearestFilter = 1003; + const NearestMipmapNearestFilter = 1004; + const NearestMipMapNearestFilter = 1004; + const NearestMipmapLinearFilter = 1005; + const NearestMipMapLinearFilter = 1005; + const LinearFilter = 1006; + const LinearMipmapNearestFilter = 1007; + const LinearMipMapNearestFilter = 1007; + const LinearMipmapLinearFilter = 1008; + const LinearMipMapLinearFilter = 1008; + const UnsignedByteType = 1009; + const ByteType = 1010; + const ShortType = 1011; + const UnsignedShortType = 1012; + const IntType = 1013; + const UnsignedIntType = 1014; + const FloatType = 1015; + const HalfFloatType = 1016; + const UnsignedShort4444Type = 1017; + const UnsignedShort5551Type = 1018; + const UnsignedInt248Type = 1020; + const AlphaFormat = 1021; + const RGBFormat = 1022; // @deprecated since r137 + const RGBAFormat = 1023; + const LuminanceFormat = 1024; + const LuminanceAlphaFormat = 1025; + const DepthFormat = 1026; + const DepthStencilFormat = 1027; + const RedFormat = 1028; + const RedIntegerFormat = 1029; + const RGFormat = 1030; + const RGIntegerFormat = 1031; + const RGBAIntegerFormat = 1033; - } + const RGB_S3TC_DXT1_Format = 33776; + const RGBA_S3TC_DXT1_Format = 33777; + const RGBA_S3TC_DXT3_Format = 33778; + const RGBA_S3TC_DXT5_Format = 33779; + const RGB_PVRTC_4BPPV1_Format = 35840; + const RGB_PVRTC_2BPPV1_Format = 35841; + const RGBA_PVRTC_4BPPV1_Format = 35842; + const RGBA_PVRTC_2BPPV1_Format = 35843; + const RGB_ETC1_Format = 36196; + const RGB_ETC2_Format = 37492; + const RGBA_ETC2_EAC_Format = 37496; + const RGBA_ASTC_4x4_Format = 37808; + const RGBA_ASTC_5x4_Format = 37809; + const RGBA_ASTC_5x5_Format = 37810; + const RGBA_ASTC_6x5_Format = 37811; + const RGBA_ASTC_6x6_Format = 37812; + const RGBA_ASTC_8x5_Format = 37813; + const RGBA_ASTC_8x6_Format = 37814; + const RGBA_ASTC_8x8_Format = 37815; + const RGBA_ASTC_10x5_Format = 37816; + const RGBA_ASTC_10x6_Format = 37817; + const RGBA_ASTC_10x8_Format = 37818; + const RGBA_ASTC_10x10_Format = 37819; + const RGBA_ASTC_12x10_Format = 37820; + const RGBA_ASTC_12x12_Format = 37821; + const RGBA_BPTC_Format = 36492; + const LoopOnce = 2200; + const LoopRepeat = 2201; + const LoopPingPong = 2202; + const InterpolateDiscrete = 2300; + const InterpolateLinear = 2301; + const InterpolateSmooth = 2302; + const ZeroCurvatureEnding = 2400; + const ZeroSlopeEnding = 2401; + const WrapAroundEnding = 2402; + const NormalAnimationBlendMode = 2500; + const AdditiveAnimationBlendMode = 2501; + const TrianglesDrawMode = 0; + const TriangleStripDrawMode = 1; + const TriangleFanDrawMode = 2; + const LinearEncoding = 3000; + const sRGBEncoding = 3001; + const BasicDepthPacking = 3200; + const RGBADepthPacking = 3201; + const TangentSpaceNormalMap = 0; + const ObjectSpaceNormalMap = 1; - copy( quaternion ) { + // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. + const NoColorSpace = ''; + const SRGBColorSpace = 'srgb'; + const LinearSRGBColorSpace = 'srgb-linear'; - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; + const ZeroStencilOp = 0; + const KeepStencilOp = 7680; + const ReplaceStencilOp = 7681; + const IncrementStencilOp = 7682; + const DecrementStencilOp = 7683; + const IncrementWrapStencilOp = 34055; + const DecrementWrapStencilOp = 34056; + const InvertStencilOp = 5386; - this._onChangeCallback(); + const NeverStencilFunc = 512; + const LessStencilFunc = 513; + const EqualStencilFunc = 514; + const LessEqualStencilFunc = 515; + const GreaterStencilFunc = 516; + const NotEqualStencilFunc = 517; + const GreaterEqualStencilFunc = 518; + const AlwaysStencilFunc = 519; - return this; + const StaticDrawUsage = 35044; + const DynamicDrawUsage = 35048; + const StreamDrawUsage = 35040; + const StaticReadUsage = 35045; + const DynamicReadUsage = 35049; + const StreamReadUsage = 35041; + const StaticCopyUsage = 35046; + const DynamicCopyUsage = 35050; + const StreamCopyUsage = 35042; - } + const GLSL1 = '100'; + const GLSL3 = '300 es'; - setFromEuler( euler, update ) { + const _SRGBAFormat = 1035; // fallback for WebGL 1 - const x = euler._x, y = euler._y, z = euler._z, order = euler._order; + /** + * https://github.com/mrdoob/eventdispatcher.js/ + */ - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m + class EventDispatcher { - const cos = Math.cos; - const sin = Math.sin; + addEventListener( type, listener ) { - const c1 = cos( x / 2 ); - const c2 = cos( y / 2 ); - const c3 = cos( z / 2 ); + if ( this._listeners === undefined ) this._listeners = {}; - const s1 = sin( x / 2 ); - const s2 = sin( y / 2 ); - const s3 = sin( z / 2 ); + const listeners = this._listeners; - switch ( order ) { + if ( listeners[ type ] === undefined ) { - case 'XYZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; + listeners[ type ] = []; - case 'YXZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; + } - case 'ZXY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; + if ( listeners[ type ].indexOf( listener ) === - 1 ) { - case 'ZYX': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; + listeners[ type ].push( listener ); - case 'YZX': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; + } - case 'XZY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; + } - default: - console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); + hasEventListener( type, listener ) { - } + if ( this._listeners === undefined ) return false; - if ( update !== false ) this._onChangeCallback(); + const listeners = this._listeners; - return this; + return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; } - setFromAxisAngle( axis, angle ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + removeEventListener( type, listener ) { - // assumes axis is normalized + if ( this._listeners === undefined ) return; - const halfAngle = angle / 2, s = Math.sin( halfAngle ); + const listeners = this._listeners; + const listenerArray = listeners[ type ]; - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); + if ( listenerArray !== undefined ) { - this._onChangeCallback(); + const index = listenerArray.indexOf( listener ); - return this; + if ( index !== - 1 ) { - } + listenerArray.splice( index, 1 ); - setFromRotationMatrix( m ) { + } - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + } - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + } - const te = m.elements, + dispatchEvent( event ) { - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], + if ( this._listeners === undefined ) return; - trace = m11 + m22 + m33; + const listeners = this._listeners; + const listenerArray = listeners[ event.type ]; - if ( trace > 0 ) { + if ( listenerArray !== undefined ) { - const s = 0.5 / Math.sqrt( trace + 1.0 ); + event.target = this; - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; + // Make a copy, in case listeners are removed while iterating. + const array = listenerArray.slice( 0 ); - } else if ( m11 > m22 && m11 > m33 ) { + for ( let i = 0, l = array.length; i < l; i ++ ) { - const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + array[ i ].call( this, event ); - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; + } - } else if ( m22 > m33 ) { + event.target = null; - const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + } - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; + } - } else { + } - const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; + let _seed = 1234567; - } - this._onChangeCallback(); + const DEG2RAD = Math.PI / 180; + const RAD2DEG = 180 / Math.PI; - return this; + // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 + function generateUUID() { - } + const d0 = Math.random() * 0xffffffff | 0; + const d1 = Math.random() * 0xffffffff | 0; + const d2 = Math.random() * 0xffffffff | 0; + const d3 = Math.random() * 0xffffffff | 0; + const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + + _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + + _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + + _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; - setFromUnitVectors( vFrom, vTo ) { + // .toLowerCase() here flattens concatenated strings to save heap memory space. + return uuid.toLowerCase(); - // assumes direction vectors vFrom and vTo are normalized + } - let r = vFrom.dot( vTo ) + 1; + function clamp( value, min, max ) { - if ( r < Number.EPSILON ) { + return Math.max( min, Math.min( max, value ) ); - // vFrom and vTo point in opposite directions + } - r = 0; + // compute euclidean modulo of m % n + // https://en.wikipedia.org/wiki/Modulo_operation + function euclideanModulo( n, m ) { - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + return ( ( n % m ) + m ) % m; - this._x = - vFrom.y; - this._y = vFrom.x; - this._z = 0; - this._w = r; + } - } else { + // Linear mapping from range to range + function mapLinear( x, a1, a2, b1, b2 ) { - this._x = 0; - this._y = - vFrom.z; - this._z = vFrom.y; - this._w = r; + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - } + } - } else { + // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ + function inverseLerp( x, y, value ) { - // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 + if ( x !== y ) { - this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; - this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; - this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; - this._w = r; + return ( value - x ) / ( y - x ); - } + } else { - return this.normalize(); + return 0; } - angleTo( q ) { + } - return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); + // https://en.wikipedia.org/wiki/Linear_interpolation + function lerp( x, y, t ) { - } + return ( 1 - t ) * x + t * y; - rotateTowards( q, step ) { + } - const angle = this.angleTo( q ); + // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ + function damp( x, y, lambda, dt ) { - if ( angle === 0 ) return this; + return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); - const t = Math.min( 1, step / angle ); + } - this.slerp( q, t ); + // https://www.desmos.com/calculator/vcsjnyz7x4 + function pingpong( x, length = 1 ) { - return this; + return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); - } + } - identity() { + // http://en.wikipedia.org/wiki/Smoothstep + function smoothstep( x, min, max ) { - return this.set( 0, 0, 0, 1 ); + if ( x <= min ) return 0; + if ( x >= max ) return 1; - } + x = ( x - min ) / ( max - min ); - invert() { + return x * x * ( 3 - 2 * x ); - // quaternion is assumed to have unit length + } - return this.conjugate(); + function smootherstep( x, min, max ) { - } + if ( x <= min ) return 0; + if ( x >= max ) return 1; - conjugate() { + x = ( x - min ) / ( max - min ); - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - this._onChangeCallback(); + } - return this; + // Random integer from interval + function randInt( low, high ) { - } + return low + Math.floor( Math.random() * ( high - low + 1 ) ); - dot( v ) { + } - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + // Random float from interval + function randFloat( low, high ) { - } + return low + Math.random() * ( high - low ); - lengthSq() { + } - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + // Random float from <-range/2, range/2> interval + function randFloatSpread( range ) { - } + return range * ( 0.5 - Math.random() ); - length() { + } - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + // Deterministic pseudo-random float in the interval [ 0, 1 ] + function seededRandom( s ) { - } + if ( s !== undefined ) _seed = s; - normalize() { + // Mulberry32 generator - let l = this.length(); + let t = _seed += 0x6D2B79F5; - if ( l === 0 ) { + t = Math.imul( t ^ t >>> 15, t | 1 ); - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; + t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); - } else { + return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; - l = 1 / l; + } - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; + function degToRad( degrees ) { - } + return degrees * DEG2RAD; - this._onChangeCallback(); + } - return this; + function radToDeg( radians ) { - } + return radians * RAD2DEG; - multiply( q ) { + } - return this.multiplyQuaternions( this, q ); + function isPowerOfTwo( value ) { - } + return ( value & ( value - 1 ) ) === 0 && value !== 0; - premultiply( q ) { + } - return this.multiplyQuaternions( q, this ); + function ceilPowerOfTwo( value ) { - } + return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); - multiplyQuaternions( a, b ) { + } - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + function floorPowerOfTwo( value ) { - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + } - this._onChangeCallback(); + function setQuaternionFromProperEuler( q, a, b, c, order ) { - return this; + // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles - } + // rotations are applied to the axes in the order specified by 'order' + // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' + // angles are in radians - slerp( qb, t ) { + const cos = Math.cos; + const sin = Math.sin; - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); + const c2 = cos( b / 2 ); + const s2 = sin( b / 2 ); - const x = this._x, y = this._y, z = this._z, w = this._w; + const c13 = cos( ( a + c ) / 2 ); + const s13 = sin( ( a + c ) / 2 ); - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + const c1_3 = cos( ( a - c ) / 2 ); + const s1_3 = sin( ( a - c ) / 2 ); - let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + const c3_1 = cos( ( c - a ) / 2 ); + const s3_1 = sin( ( c - a ) / 2 ); - if ( cosHalfTheta < 0 ) { + switch ( order ) { - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; + case 'XYX': + q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); + break; - cosHalfTheta = - cosHalfTheta; + case 'YZY': + q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); + break; - } else { + case 'ZXZ': + q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); + break; - this.copy( qb ); + case 'XZX': + q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); + break; - } + case 'YXY': + q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); + break; - if ( cosHalfTheta >= 1.0 ) { + case 'ZYZ': + q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); + break; - this._w = w; - this._x = x; - this._y = y; - this._z = z; + default: + console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); - return this; + } - } + } - const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; + function denormalize( value, array ) { - if ( sqrSinHalfTheta <= Number.EPSILON ) { + switch ( array.constructor ) { - const s = 1 - t; - this._w = s * w + t * this._w; - this._x = s * x + t * this._x; - this._y = s * y + t * this._y; - this._z = s * z + t * this._z; + case Float32Array: - this.normalize(); - this._onChangeCallback(); + return value; - return this; + case Uint16Array: - } + return value / 65535.0; - const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + case Uint8Array: - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); + return value / 255.0; - this._onChangeCallback(); + case Int16Array: - return this; + return Math.max( value / 32767.0, - 1.0 ); - } + case Int8Array: - slerpQuaternions( qa, qb, t ) { + return Math.max( value / 127.0, - 1.0 ); - return this.copy( qa ).slerp( qb, t ); + default: + + throw new Error( 'Invalid component type.' ); } - random() { + } - // Derived from http://planning.cs.uiuc.edu/node198.html - // Note, this source uses w, x, y, z ordering, - // so we swap the order below. + function normalize( value, array ) { - const u1 = Math.random(); - const sqrt1u1 = Math.sqrt( 1 - u1 ); - const sqrtu1 = Math.sqrt( u1 ); + switch ( array.constructor ) { - const u2 = 2 * Math.PI * Math.random(); + case Float32Array: - const u3 = 2 * Math.PI * Math.random(); + return value; - return this.set( - sqrt1u1 * Math.cos( u2 ), - sqrtu1 * Math.sin( u3 ), - sqrtu1 * Math.cos( u3 ), - sqrt1u1 * Math.sin( u2 ), - ); + case Uint16Array: - } + return Math.round( value * 65535.0 ); - equals( quaternion ) { + case Uint8Array: - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + return Math.round( value * 255.0 ); - } + case Int16Array: - fromArray( array, offset = 0 ) { + return Math.round( value * 32767.0 ); - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; + case Int8Array: - this._onChangeCallback(); + return Math.round( value * 127.0 ); - return this; + default: - } + throw new Error( 'Invalid component type.' ); - toArray( array = [], offset = 0 ) { + } - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; + } - return array; + var MathUtils = /*#__PURE__*/Object.freeze({ + __proto__: null, + DEG2RAD: DEG2RAD, + RAD2DEG: RAD2DEG, + generateUUID: generateUUID, + clamp: clamp, + euclideanModulo: euclideanModulo, + mapLinear: mapLinear, + inverseLerp: inverseLerp, + lerp: lerp, + damp: damp, + pingpong: pingpong, + smoothstep: smoothstep, + smootherstep: smootherstep, + randInt: randInt, + randFloat: randFloat, + randFloatSpread: randFloatSpread, + seededRandom: seededRandom, + degToRad: degToRad, + radToDeg: radToDeg, + isPowerOfTwo: isPowerOfTwo, + ceilPowerOfTwo: ceilPowerOfTwo, + floorPowerOfTwo: floorPowerOfTwo, + setQuaternionFromProperEuler: setQuaternionFromProperEuler, + normalize: normalize, + denormalize: denormalize + }); - } + class Vector2 { - fromBufferAttribute( attribute, index ) { + constructor( x = 0, y = 0 ) { - this._x = attribute.getX( index ); - this._y = attribute.getY( index ); - this._z = attribute.getZ( index ); - this._w = attribute.getW( index ); + Vector2.prototype.isVector2 = true; - return this; + this.x = x; + this.y = y; } - _onChange( callback ) { - - this._onChangeCallback = callback; + get width() { - return this; + return this.x; } - _onChangeCallback() {} - - *[ Symbol.iterator ]() { + set width( value ) { - yield this._x; - yield this._y; - yield this._z; - yield this._w; + this.x = value; } - } + get height() { - class Vector3 { + return this.y; - constructor( x = 0, y = 0, z = 0 ) { + } - Vector3.prototype.isVector3 = true; + set height( value ) { - this.x = x; - this.y = y; - this.z = z; + this.y = value; } - set( x, y, z ) { - - if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) + set( x, y ) { this.x = x; this.y = y; - this.z = z; return this; @@ -13990,7 +45561,6 @@ var app = (function () { this.x = scalar; this.y = scalar; - this.z = scalar; return this; @@ -14012,21 +45582,12 @@ var app = (function () { } - setZ( z ) { - - this.z = z; - - return this; - - } - setComponent( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; - case 2: this.z = value; break; default: throw new Error( 'index is out of range: ' + index ); } @@ -14041,7 +45602,6 @@ var app = (function () { case 0: return this.x; case 1: return this.y; - case 2: return this.z; default: throw new Error( 'index is out of range: ' + index ); } @@ -14050,7 +45610,7 @@ var app = (function () { clone() { - return new this.constructor( this.x, this.y, this.z ); + return new this.constructor( this.x, this.y ); } @@ -14058,7 +45618,6 @@ var app = (function () { this.x = v.x; this.y = v.y; - this.z = v.z; return this; @@ -14068,7 +45627,6 @@ var app = (function () { this.x += v.x; this.y += v.y; - this.z += v.z; return this; @@ -14078,7 +45636,6 @@ var app = (function () { this.x += s; this.y += s; - this.z += s; return this; @@ -14088,7 +45645,6 @@ var app = (function () { this.x = a.x + b.x; this.y = a.y + b.y; - this.z = a.z + b.z; return this; @@ -14098,7 +45654,6 @@ var app = (function () { this.x += v.x * s; this.y += v.y * s; - this.z += v.z * s; return this; @@ -14108,7 +45663,6 @@ var app = (function () { this.x -= v.x; this.y -= v.y; - this.z -= v.z; return this; @@ -14118,7 +45672,6 @@ var app = (function () { this.x -= s; this.y -= s; - this.z -= s; return this; @@ -14128,7 +45681,6 @@ var app = (function () { this.x = a.x - b.x; this.y = a.y - b.y; - this.z = a.z - b.z; return this; @@ -14138,7 +45690,6 @@ var app = (function () { this.x *= v.x; this.y *= v.y; - this.z *= v.z; return this; @@ -14148,139 +45699,42 @@ var app = (function () { this.x *= scalar; this.y *= scalar; - this.z *= scalar; return this; } - multiplyVectors( a, b ) { + divide( v ) { - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; + this.x /= v.x; + this.y /= v.y; return this; } - applyEuler( euler ) { - - return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); - - } - - applyAxisAngle( axis, angle ) { + divideScalar( scalar ) { - return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); + return this.multiplyScalar( 1 / scalar ); } applyMatrix3( m ) { - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; - this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; - - return this; - - } - - applyNormalMatrix( m ) { - - return this.applyMatrix3( m ).normalize(); - - } - - applyMatrix4( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - - this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; - this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; - this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; - - return this; - - } - - applyQuaternion( q ) { - - const x = this.x, y = this.y, z = this.z; - const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - - // calculate quat * vector - - const ix = qw * x + qy * z - qz * y; - const iy = qw * y + qz * x - qx * z; - const iz = qw * z + qx * y - qy * x; - const iw = - qx * x - qy * y - qz * z; - - // calculate result * inverse quat - - this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; - this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; - this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; - - return this; - - } - - project( camera ) { - - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); - - } - - unproject( camera ) { - - return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); - - } - - transformDirection( m ) { - - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction - - const x = this.x, y = this.y, z = this.z; + const x = this.x, y = this.y; const e = m.elements; - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; - - return this.normalize(); - - } - - divide( v ) { - - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; return this; } - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - min( v ) { this.x = Math.min( this.x, v.x ); this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); return this; @@ -14290,7 +45744,6 @@ var app = (function () { this.x = Math.max( this.x, v.x ); this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); return this; @@ -14302,7 +45755,6 @@ var app = (function () { this.x = Math.max( min.x, Math.min( max.x, this.x ) ); this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); return this; @@ -14312,7 +45764,6 @@ var app = (function () { this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); return this; @@ -14330,7 +45781,6 @@ var app = (function () { this.x = Math.floor( this.x ); this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); return this; @@ -14340,7 +45790,6 @@ var app = (function () { this.x = Math.ceil( this.x ); this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); return this; @@ -14350,7 +45799,6 @@ var app = (function () { this.x = Math.round( this.x ); this.y = Math.round( this.y ); - this.z = Math.round( this.z ); return this; @@ -14360,7 +45808,6 @@ var app = (function () { this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); return this; @@ -14370,7 +45817,6 @@ var app = (function () { this.x = - this.x; this.y = - this.y; - this.z = - this.z; return this; @@ -14378,27 +45824,31 @@ var app = (function () { dot( v ) { - return this.x * v.x + this.y * v.y + this.z * v.z; + return this.x * v.x + this.y * v.y; } - // TODO lengthSquared? + cross( v ) { + + return this.x * v.y - this.y * v.x; + + } lengthSq() { - return this.x * this.x + this.y * this.y + this.z * this.z; + return this.x * this.x + this.y * this.y; } length() { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + return Math.sqrt( this.x * this.x + this.y * this.y ); } manhattanLength() { - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + return Math.abs( this.x ) + Math.abs( this.y ); } @@ -14408,6 +45858,35 @@ var app = (function () { } + angle() { + + // computes the angle in radians with respect to the positive x-axis + + const angle = Math.atan2( - this.y, - this.x ) + Math.PI; + + return angle; + + } + + distanceTo( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + } + + distanceToSquared( v ) { + + const dx = this.x - v.x, dy = this.y - v.y; + return dx * dx + dy * dy; + + } + + manhattanDistanceTo( v ) { + + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); + + } + setLength( length ) { return this.normalize().multiplyScalar( length ); @@ -14418,7 +45897,6 @@ var app = (function () { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; return this; @@ -14428,1993 +45906,1931 @@ var app = (function () { this.x = v1.x + ( v2.x - v1.x ) * alpha; this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; return this; } - cross( v ) { + equals( v ) { - return this.crossVectors( this, v ); + return ( ( v.x === this.x ) && ( v.y === this.y ) ); } - crossVectors( a, b ) { - - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; + fromArray( array, offset = 0 ) { - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; return this; } - projectOnVector( v ) { - - const denominator = v.lengthSq(); - - if ( denominator === 0 ) return this.set( 0, 0, 0 ); + toArray( array = [], offset = 0 ) { - const scalar = v.dot( this ) / denominator; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; - return this.copy( v ).multiplyScalar( scalar ); + return array; } - projectOnPlane( planeNormal ) { + fromBufferAttribute( attribute, index ) { - _vector$c.copy( this ).projectOnVector( planeNormal ); + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); - return this.sub( _vector$c ); + return this; } - reflect( normal ) { + rotateAround( center, angle ) { - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length + const c = Math.cos( angle ), s = Math.sin( angle ); - return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + const x = this.x - center.x; + const y = this.y - center.y; - } - - angleTo( v ) { + this.x = x * c - y * s + center.x; + this.y = x * s + y * c + center.y; - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + return this; - if ( denominator === 0 ) return Math.PI / 2; + } - const theta = this.dot( v ) / denominator; + random() { - // clamp, to handle numerical problems + this.x = Math.random(); + this.y = Math.random(); - return Math.acos( clamp( theta, - 1, 1 ) ); + return this; } - distanceTo( v ) { + *[ Symbol.iterator ]() { - return Math.sqrt( this.distanceToSquared( v ) ); + yield this.x; + yield this.y; } - distanceToSquared( v ) { - - const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - - return dx * dx + dy * dy + dz * dz; + } - } + class Matrix3 { - manhattanDistanceTo( v ) { + constructor() { - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + Matrix3.prototype.isMatrix3 = true; - } + this.elements = [ - setFromSpherical( s ) { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); + ]; } - setFromSphericalCoords( radius, phi, theta ) { + set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - const sinPhiRadius = Math.sin( phi ) * radius; + const te = this.elements; - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); + te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; + te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; + te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; return this; } - setFromCylindrical( c ) { - - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + identity() { - } + this.set( - setFromCylindricalCoords( radius, theta, y ) { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); + ); return this; } - setFromMatrixPosition( m ) { + copy( m ) { - const e = m.elements; + const te = this.elements; + const me = m.elements; - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; + te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; + te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; return this; } - setFromMatrixScale( m ) { - - const sx = this.setFromMatrixColumn( m, 0 ).length(); - const sy = this.setFromMatrixColumn( m, 1 ).length(); - const sz = this.setFromMatrixColumn( m, 2 ).length(); + extractBasis( xAxis, yAxis, zAxis ) { - this.x = sx; - this.y = sy; - this.z = sz; + xAxis.setFromMatrix3Column( this, 0 ); + yAxis.setFromMatrix3Column( this, 1 ); + zAxis.setFromMatrix3Column( this, 2 ); return this; } - setFromMatrixColumn( m, index ) { - - return this.fromArray( m.elements, index * 4 ); - - } - - setFromMatrix3Column( m, index ) { + setFromMatrix4( m ) { - return this.fromArray( m.elements, index * 3 ); + const me = m.elements; - } + this.set( - setFromEuler( e ) { + me[ 0 ], me[ 4 ], me[ 8 ], + me[ 1 ], me[ 5 ], me[ 9 ], + me[ 2 ], me[ 6 ], me[ 10 ] - this.x = e._x; - this.y = e._y; - this.z = e._z; + ); return this; } - equals( v ) { + multiply( m ) { - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + return this.multiplyMatrices( this, m ); } - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; + premultiply( m ) { - return this; + return this.multiplyMatrices( m, this ); } - toArray( array = [], offset = 0 ) { + multiplyMatrices( a, b ) { - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; + const ae = a.elements; + const be = b.elements; + const te = this.elements; - return array; + const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; + const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; + const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; - } + const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; + const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; + const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; - fromBufferAttribute( attribute, index ) { + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; + te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; + te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; + te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; + te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; + + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; + te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; + te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; return this; } - random() { + multiplyScalar( s ) { - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); + const te = this.elements; + + te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; + te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; + te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; return this; } - randomDirection() { - - // Derived from https://mathworld.wolfram.com/SpherePointPicking.html + determinant() { - const u = ( Math.random() - 0.5 ) * 2; - const t = Math.random() * Math.PI * 2; - const f = Math.sqrt( 1 - u ** 2 ); + const te = this.elements; - this.x = f * Math.cos( t ); - this.y = f * Math.sin( t ); - this.z = u; + const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], + d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], + g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; - return this; + return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; } - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - - } + invert() { - } + const te = this.elements, - const _vector$c = /*@__PURE__*/ new Vector3(); - const _quaternion$4 = /*@__PURE__*/ new Quaternion(); + n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], + n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], + n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], - class Box3 { + t11 = n33 * n22 - n32 * n23, + t12 = n32 * n13 - n33 * n12, + t13 = n23 * n12 - n22 * n13, - constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { + det = n11 * t11 + n21 * t12 + n31 * t13; - this.isBox3 = true; + if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - this.min = min; - this.max = max; + const detInv = 1 / det; - } + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; + te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; - set( min, max ) { + te[ 3 ] = t12 * detInv; + te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; + te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; - this.min.copy( min ); - this.max.copy( max ); + te[ 6 ] = t13 * detInv; + te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; + te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; return this; } - setFromArray( array ) { + transpose() { - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + let tmp; + const m = this.elements; - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; + tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; + tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; - for ( let i = 0, l = array.length; i < l; i += 3 ) { + return this; - const x = array[ i ]; - const y = array[ i + 1 ]; - const z = array[ i + 2 ]; + } - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + getNormalMatrix( matrix4 ) { - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + return this.setFromMatrix4( matrix4 ).invert().transpose(); - } + } - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + transposeIntoArray( r ) { + + const m = this.elements; + + r[ 0 ] = m[ 0 ]; + r[ 1 ] = m[ 3 ]; + r[ 2 ] = m[ 6 ]; + r[ 3 ] = m[ 1 ]; + r[ 4 ] = m[ 4 ]; + r[ 5 ] = m[ 7 ]; + r[ 6 ] = m[ 2 ]; + r[ 7 ] = m[ 5 ]; + r[ 8 ] = m[ 8 ]; return this; } - setFromBufferAttribute( attribute ) { - - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + const c = Math.cos( rotation ); + const s = Math.sin( rotation ); - for ( let i = 0, l = attribute.count; i < l; i ++ ) { + this.set( + sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, + - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, + 0, 0, 1 + ); - const x = attribute.getX( i ); - const y = attribute.getY( i ); - const z = attribute.getZ( i ); + return this; - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + } - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + scale( sx, sy ) { - } + const te = this.elements; - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx; + te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy; return this; } - setFromPoints( points ) { + rotate( theta ) { - this.makeEmpty(); + const c = Math.cos( theta ); + const s = Math.sin( theta ); - for ( let i = 0, il = points.length; i < il; i ++ ) { + const te = this.elements; - this.expandByPoint( points[ i ] ); + const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ]; + const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ]; - } + te[ 0 ] = c * a11 + s * a21; + te[ 3 ] = c * a12 + s * a22; + te[ 6 ] = c * a13 + s * a23; + + te[ 1 ] = - s * a11 + c * a21; + te[ 4 ] = - s * a12 + c * a22; + te[ 7 ] = - s * a13 + c * a23; return this; } - setFromCenterAndSize( center, size ) { + translate( tx, ty ) { - const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + const te = this.elements; - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ]; + te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ]; return this; } - setFromObject( object, precise = false ) { + equals( matrix ) { - this.makeEmpty(); + const te = this.elements; + const me = matrix.elements; - return this.expandByObject( object, precise ); + for ( let i = 0; i < 9; i ++ ) { - } + if ( te[ i ] !== me[ i ] ) return false; - clone() { + } - return new this.constructor().copy( this ); + return true; } - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; + fromArray( array, offset = 0 ) { - } + for ( let i = 0; i < 9; i ++ ) { - makeEmpty() { + this.elements[ i ] = array[ i + offset ]; - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; + } return this; } - isEmpty() { + toArray( array = [], offset = 0 ) { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + const te = this.elements; - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; - } + array[ offset + 3 ] = te[ 3 ]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; - getCenter( target ) { + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + array[ offset + 8 ] = te[ 8 ]; - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + return array; } - getSize( target ) { + clone() { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); + return new this.constructor().fromArray( this.elements ); } - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; + } - } + function arrayNeedsUint32( array ) { - expandByVector( vector ) { + // assumes larger values usually on last - this.min.sub( vector ); - this.max.add( vector ); + for ( let i = array.length - 1; i >= 0; -- i ) { - return this; + if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 } - expandByScalar( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - } + return false; - expandByObject( object, precise = false ) { + } - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms + const TYPED_ARRAYS = { + Int8Array: Int8Array, + Uint8Array: Uint8Array, + Uint8ClampedArray: Uint8ClampedArray, + Int16Array: Int16Array, + Uint16Array: Uint16Array, + Int32Array: Int32Array, + Uint32Array: Uint32Array, + Float32Array: Float32Array, + Float64Array: Float64Array + }; - object.updateWorldMatrix( false, false ); + function getTypedArray( type, buffer ) { - const geometry = object.geometry; + return new TYPED_ARRAYS[ type ]( buffer ); - if ( geometry !== undefined ) { + } - if ( precise && geometry.attributes != undefined && geometry.attributes.position !== undefined ) { + function createElementNS( name ) { - const position = geometry.attributes.position; - for ( let i = 0, l = position.count; i < l; i ++ ) { + return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); - _vector$b.fromBufferAttribute( position, i ).applyMatrix4( object.matrixWorld ); - this.expandByPoint( _vector$b ); + } - } + function SRGBToLinear( c ) { - } else { + return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); - if ( geometry.boundingBox === null ) { + } - geometry.computeBoundingBox(); + function LinearToSRGB( c ) { - } + return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; - _box$3.copy( geometry.boundingBox ); - _box$3.applyMatrix4( object.matrixWorld ); + } - this.union( _box$3 ); + // JavaScript RGB-to-RGB transforms, defined as + // FN[InputColorSpace][OutputColorSpace] callback functions. + const FN = { + [ SRGBColorSpace ]: { [ LinearSRGBColorSpace ]: SRGBToLinear }, + [ LinearSRGBColorSpace ]: { [ SRGBColorSpace ]: LinearToSRGB }, + }; - } + const ColorManagement = { - } + legacyMode: true, - const children = object.children; + get workingColorSpace() { - for ( let i = 0, l = children.length; i < l; i ++ ) { + return LinearSRGBColorSpace; - this.expandByObject( children[ i ], precise ); + }, - } + set workingColorSpace( colorSpace ) { - return this; + console.warn( 'THREE.ColorManagement: .workingColorSpace is readonly.' ); - } + }, - containsPoint( point ) { + convert: function ( color, sourceColorSpace, targetColorSpace ) { - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; + if ( this.legacyMode || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { - } + return color; - containsBox( box ) { + } - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; + if ( FN[ sourceColorSpace ] && FN[ sourceColorSpace ][ targetColorSpace ] !== undefined ) { - } + const fn = FN[ sourceColorSpace ][ targetColorSpace ]; - getParameter( point, target ) { + color.r = fn( color.r ); + color.g = fn( color.g ); + color.b = fn( color.b ); - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + return color; - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ), - ( point.z - this.min.z ) / ( this.max.z - this.min.z ) - ); + } - } + throw new Error( 'Unsupported color space conversion.' ); - intersectsBox( box ) { + }, - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; + fromWorkingColorSpace: function ( color, targetColorSpace ) { - } + return this.convert( color, this.workingColorSpace, targetColorSpace ); - intersectsSphere( sphere ) { + }, - // Find the point on the AABB closest to the sphere center. - this.clampPoint( sphere.center, _vector$b ); + toWorkingColorSpace: function ( color, sourceColorSpace ) { - // If that point is inside the sphere, the AABB and sphere intersect. - return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); + return this.convert( color, sourceColorSpace, this.workingColorSpace ); - } + }, - intersectsPlane( plane ) { + }; - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. - - let min, max; + const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, + 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, + 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, + 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, + 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, + 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, + 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, + 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, + 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, + 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, + 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, + 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, + 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, + 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, + 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, + 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, + 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, + 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, + 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, + 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, + 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, + 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, + 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, + 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - if ( plane.normal.x > 0 ) { + const _rgb = { r: 0, g: 0, b: 0 }; + const _hslA = { h: 0, s: 0, l: 0 }; + const _hslB = { h: 0, s: 0, l: 0 }; - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; + function hue2rgb( p, q, t ) { - } else { + if ( t < 0 ) t += 1; + if ( t > 1 ) t -= 1; + if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; + if ( t < 1 / 2 ) return q; + if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); + return p; - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; + } - } + function toComponents( source, target ) { - if ( plane.normal.y > 0 ) { + target.r = source.r; + target.g = source.g; + target.b = source.b; - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; + return target; - } else { + } - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; + class Color { - } + constructor( r, g, b ) { - if ( plane.normal.z > 0 ) { + this.isColor = true; - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; + this.r = 1; + this.g = 1; + this.b = 1; - } else { + if ( g === undefined && b === undefined ) { - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; + // r is THREE.Color, hex or string + return this.set( r ); } - return ( min <= - plane.constant && max >= - plane.constant ); + return this.setRGB( r, g, b ); } - intersectsTriangle( triangle ) { - - if ( this.isEmpty() ) { - - return false; + set( value ) { - } + if ( value && value.isColor ) { - // compute box center and extents - this.getCenter( _center ); - _extents.subVectors( this.max, _center ); + this.copy( value ); - // translate triangle to aabb origin - _v0$2.subVectors( triangle.a, _center ); - _v1$7.subVectors( triangle.b, _center ); - _v2$3.subVectors( triangle.c, _center ); + } else if ( typeof value === 'number' ) { - // compute edge vectors for triangle - _f0.subVectors( _v1$7, _v0$2 ); - _f1.subVectors( _v2$3, _v1$7 ); - _f2.subVectors( _v0$2, _v2$3 ); + this.setHex( value ); - // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb - // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation - // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) - let axes = [ - 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, - _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, - - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 - ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) { + } else if ( typeof value === 'string' ) { - return false; + this.setStyle( value ); } - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) { + return this; - return false; + } - } + setScalar( scalar ) { - // finally testing the face normal of the triangle - // use already existing triangle edge vectors here - _triangleNormal.crossVectors( _f0, _f1 ); - axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + this.r = scalar; + this.g = scalar; + this.b = scalar; - return satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ); + return this; } - clampPoint( point, target ) { - - return target.copy( point ).clamp( this.min, this.max ); + setHex( hex, colorSpace = SRGBColorSpace ) { - } + hex = Math.floor( hex ); - distanceToPoint( point ) { + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; - const clampedPoint = _vector$b.copy( point ).clamp( this.min, this.max ); + ColorManagement.toWorkingColorSpace( this, colorSpace ); - return clampedPoint.sub( point ).length(); + return this; } - getBoundingSphere( target ) { + setRGB( r, g, b, colorSpace = LinearSRGBColorSpace ) { - this.getCenter( target.center ); + this.r = r; + this.g = g; + this.b = b; - target.radius = this.getSize( _vector$b ).length() * 0.5; + ColorManagement.toWorkingColorSpace( this, colorSpace ); - return target; + return this; } - intersect( box ) { + setHSL( h, s, l, colorSpace = LinearSRGBColorSpace ) { - this.min.max( box.min ); - this.max.min( box.max ); + // h,s,l ranges are in 0.0 - 1.0 + h = euclideanModulo( h, 1 ); + s = clamp( s, 0, 1 ); + l = clamp( l, 0, 1 ); - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if ( this.isEmpty() ) this.makeEmpty(); + if ( s === 0 ) { - return this; + this.r = this.g = this.b = l; - } + } else { - union( box ) { + const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + const q = ( 2 * l ) - p; - this.min.min( box.min ); - this.max.max( box.max ); + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); + + } + + ColorManagement.toWorkingColorSpace( this, colorSpace ); return this; } - applyMatrix4( matrix ) { + setStyle( style, colorSpace = SRGBColorSpace ) { - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; + function handleAlpha( string ) { - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + if ( string === undefined ) return; - this.setFromPoints( _points ); + if ( parseFloat( string ) < 1 ) { - return this; + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); - } + } - translate( offset ) { + } - this.min.add( offset ); - this.max.add( offset ); - return this; + let m; - } + if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) { - equals( box ) { + // rgb / hsl - return box.min.equals( this.min ) && box.max.equals( this.max ); + let color; + const name = m[ 1 ]; + const components = m[ 2 ]; - } + switch ( name ) { - } + case 'rgb': + case 'rgba': - const _points = [ - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3() - ]; + if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - const _vector$b = /*@__PURE__*/ new Vector3(); + // rgb(255,0,0) rgba(255,0,0,0.5) + this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; + this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; + this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; - const _box$3 = /*@__PURE__*/ new Box3(); + ColorManagement.toWorkingColorSpace( this, colorSpace ); - // triangle centered vertices + handleAlpha( color[ 4 ] ); - const _v0$2 = /*@__PURE__*/ new Vector3(); - const _v1$7 = /*@__PURE__*/ new Vector3(); - const _v2$3 = /*@__PURE__*/ new Vector3(); + return this; - // triangle edge vectors + } - const _f0 = /*@__PURE__*/ new Vector3(); - const _f1 = /*@__PURE__*/ new Vector3(); - const _f2 = /*@__PURE__*/ new Vector3(); + if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - const _center = /*@__PURE__*/ new Vector3(); - const _extents = /*@__PURE__*/ new Vector3(); - const _triangleNormal = /*@__PURE__*/ new Vector3(); - const _testAxis = /*@__PURE__*/ new Vector3(); + // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) + this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; + this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; + this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; - function satForAxes( axes, v0, v1, v2, extents ) { + ColorManagement.toWorkingColorSpace( this, colorSpace ); - for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { + handleAlpha( color[ 4 ] ); - _testAxis.fromArray( axes, i ); - // project the aabb onto the separating axis - const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); - // project all 3 vertices of the triangle onto the separating axis - const p0 = v0.dot( _testAxis ); - const p1 = v1.dot( _testAxis ); - const p2 = v2.dot( _testAxis ); - // actual test, basically see if either of the most extreme of the triangle points intersects r - if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { + return this; - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is separating and we can exit - return false; + } - } + break; - } + case 'hsl': + case 'hsla': - return true; + if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - } + // hsl(120,50%,50%) hsla(120,50%,50%,0.5) + const h = parseFloat( color[ 1 ] ) / 360; + const s = parseFloat( color[ 2 ] ) / 100; + const l = parseFloat( color[ 3 ] ) / 100; - const _box$2 = /*@__PURE__*/ new Box3(); - const _v1$6 = /*@__PURE__*/ new Vector3(); - const _toFarthestPoint = /*@__PURE__*/ new Vector3(); - const _toPoint = /*@__PURE__*/ new Vector3(); + handleAlpha( color[ 4 ] ); - class Sphere { + return this.setHSL( h, s, l, colorSpace ); - constructor( center = new Vector3(), radius = - 1 ) { + } - this.center = center; - this.radius = radius; + break; - } + } - set( center, radius ) { + } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { - this.center.copy( center ); - this.radius = radius; + // hex color - return this; + const hex = m[ 1 ]; + const size = hex.length; - } + if ( size === 3 ) { - setFromPoints( points, optionalCenter ) { + // #ff0 + this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; + this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; + this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; - const center = this.center; + ColorManagement.toWorkingColorSpace( this, colorSpace ); - if ( optionalCenter !== undefined ) { + return this; - center.copy( optionalCenter ); + } else if ( size === 6 ) { - } else { + // #ff0000 + this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; + this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; + this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; - _box$2.setFromPoints( points ).getCenter( center ); + ColorManagement.toWorkingColorSpace( this, colorSpace ); - } + return this; - let maxRadiusSq = 0; + } - for ( let i = 0, il = points.length; i < il; i ++ ) { + } - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + if ( style && style.length > 0 ) { - } + return this.setColorName( style, colorSpace ); - this.radius = Math.sqrt( maxRadiusSq ); + } return this; } - copy( sphere ) { + setColorName( style, colorSpace = SRGBColorSpace ) { - this.center.copy( sphere.center ); - this.radius = sphere.radius; + // color keywords + const hex = _colorKeywords[ style.toLowerCase() ]; + + if ( hex !== undefined ) { + + // red + this.setHex( hex, colorSpace ); + + } else { + + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); + + } return this; } - isEmpty() { + clone() { - return ( this.radius < 0 ); + return new this.constructor( this.r, this.g, this.b ); } - makeEmpty() { + copy( color ) { - this.center.set( 0, 0, 0 ); - this.radius = - 1; + this.r = color.r; + this.g = color.g; + this.b = color.b; return this; } - containsPoint( point ) { + copySRGBToLinear( color ) { - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + this.r = SRGBToLinear( color.r ); + this.g = SRGBToLinear( color.g ); + this.b = SRGBToLinear( color.b ); + + return this; } - distanceToPoint( point ) { + copyLinearToSRGB( color ) { - return ( point.distanceTo( this.center ) - this.radius ); + this.r = LinearToSRGB( color.r ); + this.g = LinearToSRGB( color.g ); + this.b = LinearToSRGB( color.b ); + + return this; } - intersectsSphere( sphere ) { + convertSRGBToLinear() { - const radiusSum = this.radius + sphere.radius; + this.copySRGBToLinear( this ); - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + return this; } - intersectsBox( box ) { + convertLinearToSRGB() { - return box.intersectsSphere( this ); + this.copyLinearToSRGB( this ); + + return this; } - intersectsPlane( plane ) { + getHex( colorSpace = SRGBColorSpace ) { - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; + ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); + + return clamp( _rgb.r * 255, 0, 255 ) << 16 ^ clamp( _rgb.g * 255, 0, 255 ) << 8 ^ clamp( _rgb.b * 255, 0, 255 ) << 0; } - clampPoint( point, target ) { + getHexString( colorSpace = SRGBColorSpace ) { - const deltaLengthSq = this.center.distanceToSquared( point ); + return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); - target.copy( point ); + } - if ( deltaLengthSq > ( this.radius * this.radius ) ) { + getHSL( target, colorSpace = LinearSRGBColorSpace ) { - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); + // h,s,l ranges are in 0.0 - 1.0 - } + ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); - return target; + const r = _rgb.r, g = _rgb.g, b = _rgb.b; - } + const max = Math.max( r, g, b ); + const min = Math.min( r, g, b ); - getBoundingBox( target ) { + let hue, saturation; + const lightness = ( min + max ) / 2.0; - if ( this.isEmpty() ) { + if ( min === max ) { - // Empty sphere produces empty bounding box - target.makeEmpty(); - return target; + hue = 0; + saturation = 0; - } + } else { - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); + const delta = max - min; - return target; + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - } + switch ( max ) { - applyMatrix4( matrix ) { + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + } - return this; + hue /= 6; + + } + + target.h = hue; + target.s = saturation; + target.l = lightness; + + return target; } - translate( offset ) { + getRGB( target, colorSpace = LinearSRGBColorSpace ) { - this.center.add( offset ); + ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); - return this; + target.r = _rgb.r; + target.g = _rgb.g; + target.b = _rgb.b; + + return target; } - expandByPoint( point ) { + getStyle( colorSpace = SRGBColorSpace ) { - if ( this.isEmpty() ) { + ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace ); - this.center.copy( point ); - this.radius = 0; + if ( colorSpace !== SRGBColorSpace ) { - return this; + // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). + return `color(${ colorSpace } ${ _rgb.r } ${ _rgb.g } ${ _rgb.b })`; } - // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L649-L671 - - _toPoint.subVectors( point, this.center ); - - const lengthSq = _toPoint.lengthSq(); + return `rgb(${( _rgb.r * 255 ) | 0},${( _rgb.g * 255 ) | 0},${( _rgb.b * 255 ) | 0})`; - if ( lengthSq > ( this.radius * this.radius ) ) { + } - const length = Math.sqrt( lengthSq ); - const missingRadiusHalf = ( length - this.radius ) * 0.5; + offsetHSL( h, s, l ) { - // Nudge this sphere towards the target point. Add half the missing distance to radius, - // and the other half to position. This gives a tighter enclosure, instead of if - // the whole missing distance were just added to radius. + this.getHSL( _hslA ); - this.center.add( _toPoint.multiplyScalar( missingRadiusHalf / length ) ); - this.radius += missingRadiusHalf; + _hslA.h += h; _hslA.s += s; _hslA.l += l; - } + this.setHSL( _hslA.h, _hslA.s, _hslA.l ); return this; } - union( sphere ) { - - // handle empty sphere cases - if ( sphere.isEmpty() ) { + add( color ) { - return this; + this.r += color.r; + this.g += color.g; + this.b += color.b; - } else if ( this.isEmpty() ) { + return this; - this.copy( sphere ); + } - return this; + addColors( color1, color2 ) { - } - - // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L759-L769 + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; - // To enclose another sphere into this sphere, we only need to enclose two points: - // 1) Enclose the farthest point on the other sphere into this sphere. - // 2) Enclose the opposite point of the farthest point into this sphere. + return this; - if ( this.center.equals( sphere.center ) === true ) { + } - _toFarthestPoint.set( 0, 0, 1 ).multiplyScalar( sphere.radius ); + addScalar( s ) { + this.r += s; + this.g += s; + this.b += s; - } else { + return this; - _toFarthestPoint.subVectors( sphere.center, this.center ).normalize().multiplyScalar( sphere.radius ); + } - } + sub( color ) { - this.expandByPoint( _v1$6.copy( sphere.center ).add( _toFarthestPoint ) ); - this.expandByPoint( _v1$6.copy( sphere.center ).sub( _toFarthestPoint ) ); + this.r = Math.max( 0, this.r - color.r ); + this.g = Math.max( 0, this.g - color.g ); + this.b = Math.max( 0, this.b - color.b ); return this; } - equals( sphere ) { - - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - - } + multiply( color ) { - clone() { + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; - return new this.constructor().copy( this ); + return this; } - } + multiplyScalar( s ) { - const _vector$a = /*@__PURE__*/ new Vector3(); - const _segCenter = /*@__PURE__*/ new Vector3(); - const _segDir = /*@__PURE__*/ new Vector3(); - const _diff = /*@__PURE__*/ new Vector3(); + this.r *= s; + this.g *= s; + this.b *= s; - const _edge1 = /*@__PURE__*/ new Vector3(); - const _edge2 = /*@__PURE__*/ new Vector3(); - const _normal$1 = /*@__PURE__*/ new Vector3(); + return this; - class Ray { + } - constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { + lerp( color, alpha ) { - this.origin = origin; - this.direction = direction; + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; } - set( origin, direction ) { + lerpColors( color1, color2, alpha ) { - this.origin.copy( origin ); - this.direction.copy( direction ); + this.r = color1.r + ( color2.r - color1.r ) * alpha; + this.g = color1.g + ( color2.g - color1.g ) * alpha; + this.b = color1.b + ( color2.b - color1.b ) * alpha; return this; } - copy( ray ) { + lerpHSL( color, alpha ) { - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); + this.getHSL( _hslA ); + color.getHSL( _hslB ); + + const h = lerp( _hslA.h, _hslB.h, alpha ); + const s = lerp( _hslA.s, _hslB.s, alpha ); + const l = lerp( _hslA.l, _hslB.l, alpha ); + + this.setHSL( h, s, l ); return this; } - at( t, target ) { + equals( c ) { - return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); } - lookAt( v ) { + fromArray( array, offset = 0 ) { - this.direction.copy( v ).sub( this.origin ).normalize(); + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; return this; } - recast( t ) { + toArray( array = [], offset = 0 ) { - this.origin.copy( this.at( t, _vector$a ) ); + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; - return this; + return array; } - closestPointToPoint( point, target ) { - - target.subVectors( point, this.origin ); + fromBufferAttribute( attribute, index ) { - const directionDistance = target.dot( this.direction ); + this.r = attribute.getX( index ); + this.g = attribute.getY( index ); + this.b = attribute.getZ( index ); - if ( directionDistance < 0 ) { + return this; - return target.copy( this.origin ); + } - } + toJSON() { - return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + return this.getHex(); } - distanceToPoint( point ) { + *[ Symbol.iterator ]() { - return Math.sqrt( this.distanceSqToPoint( point ) ); + yield this.r; + yield this.g; + yield this.b; } - distanceSqToPoint( point ) { + } - const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); + Color.NAMES = _colorKeywords; - // point behind the ray + let _canvas; - if ( directionDistance < 0 ) { + class ImageUtils { - return this.origin.distanceToSquared( point ); + static getDataURL( image ) { - } + if ( /^data:/i.test( image.src ) ) { - _vector$a.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + return image.src; - return _vector$a.distanceToSquared( point ); + } - } + if ( typeof HTMLCanvasElement == 'undefined' ) { - distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + return image.src; - // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h - // It returns the min distance between the ray and the segment - // defined by v0 and v1 - // It can also set two optional targets : - // - The closest point on the ray - // - The closest point on the segment + } - _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - _segDir.copy( v1 ).sub( v0 ).normalize(); - _diff.copy( this.origin ).sub( _segCenter ); + let canvas; - const segExtent = v0.distanceTo( v1 ) * 0.5; - const a01 = - this.direction.dot( _segDir ); - const b0 = _diff.dot( this.direction ); - const b1 = - _diff.dot( _segDir ); - const c = _diff.lengthSq(); - const det = Math.abs( 1 - a01 * a01 ); - let s0, s1, sqrDist, extDet; + if ( image instanceof HTMLCanvasElement ) { - if ( det > 0 ) { + canvas = image; - // The ray and segment are not parallel. + } else { - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); - if ( s0 >= 0 ) { + _canvas.width = image.width; + _canvas.height = image.height; - if ( s1 >= - extDet ) { + const context = _canvas.getContext( '2d' ); - if ( s1 <= extDet ) { + if ( image instanceof ImageData ) { - // region 0 - // Minimum at interior points of ray and segment. + context.putImageData( image, 0, 0 ); - const invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + } else { - } else { + context.drawImage( image, 0, 0, image.width, image.height ); - // region 1 + } - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + canvas = _canvas; - } + } - } else { + if ( canvas.width > 2048 || canvas.height > 2048 ) { - // region 5 + console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + return canvas.toDataURL( 'image/jpeg', 0.6 ); - } + } else { - } else { + return canvas.toDataURL( 'image/png' ); - if ( s1 <= - extDet ) { + } - // region 4 + } - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + static sRGBToLinear( image ) { - } else if ( s1 <= extDet ) { + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - // region 3 + const canvas = createElementNS( 'canvas' ); - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + canvas.width = image.width; + canvas.height = image.height; - } else { + const context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height ); - // region 2 + const imageData = context.getImageData( 0, 0, image.width, image.height ); + const data = imageData.data; - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + for ( let i = 0; i < data.length; i ++ ) { - } + data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; } - } else { + context.putImageData( imageData, 0, 0 ); - // Ray and segment are parallel. + return canvas; - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } else if ( image.data ) { - } + const data = image.data.slice( 0 ); - if ( optionalPointOnRay ) { + for ( let i = 0; i < data.length; i ++ ) { - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); + if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { - } + data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); - if ( optionalPointOnSegment ) { + } else { - optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter ); + // assuming float - } + data[ i ] = SRGBToLinear( data[ i ] ); - return sqrDist; + } - } + } - intersectSphere( sphere, target ) { + return { + data: data, + width: image.width, + height: image.height + }; - _vector$a.subVectors( sphere.center, this.origin ); - const tca = _vector$a.dot( this.direction ); - const d2 = _vector$a.dot( _vector$a ) - tca * tca; - const radius2 = sphere.radius * sphere.radius; + } else { - if ( d2 > radius2 ) return null; + console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); + return image; - const thc = Math.sqrt( radius2 - d2 ); + } - // t0 = first intersect point - entrance on front of sphere - const t0 = tca - thc; + } - // t1 = second intersect point - exit point on back of sphere - const t1 = tca + thc; + } - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; + class Source { - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, target ); + constructor( data = null ) { - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); + this.isSource = true; - } + this.uuid = generateUUID(); - intersectsSphere( sphere ) { + this.data = data; - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); + this.version = 0; } - distanceToPlane( plane ) { - - const denominator = plane.normal.dot( this.direction ); + set needsUpdate( value ) { - if ( denominator === 0 ) { + if ( value === true ) this.version ++; - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { + } - return 0; + toJSON( meta ) { - } + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - // Null is preferable to undefined since undefined means.... it is undefined + if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { - return null; + return meta.images[ this.uuid ]; } - const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - - // Return if the ray never intersects the plane + const output = { + uuid: this.uuid, + url: '' + }; - return t >= 0 ? t : null; + const data = this.data; - } + if ( data !== null ) { - intersectPlane( plane, target ) { + let url; - const t = this.distanceToPlane( plane ); + if ( Array.isArray( data ) ) { - if ( t === null ) { + // cube texture - return null; + url = []; - } + for ( let i = 0, l = data.length; i < l; i ++ ) { - return this.at( t, target ); + if ( data[ i ].isDataTexture ) { - } + url.push( serializeImage( data[ i ].image ) ); - intersectsPlane( plane ) { + } else { - // check if the ray lies on the plane first + url.push( serializeImage( data[ i ] ) ); - const distToPoint = plane.distanceToPoint( this.origin ); + } - if ( distToPoint === 0 ) { + } - return true; + } else { - } + // texture - const denominator = plane.normal.dot( this.direction ); + url = serializeImage( data ); - if ( denominator * distToPoint < 0 ) { + } - return true; + output.url = url; } - // ray origin is behind the plane (and is pointing behind it) + if ( ! isRootObject ) { - return false; + meta.images[ this.uuid ] = output; - } + } - intersectBox( box, target ) { + return output; - let tmin, tmax, tymin, tymax, tzmin, tzmax; + } - const invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; + } - const origin = this.origin; + function serializeImage( image ) { - if ( invdirx >= 0 ) { + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; + // default images - } else { + return ImageUtils.getDataURL( image ); - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; + } else { - } + if ( image.data ) { - if ( invdiry >= 0 ) { + // images of DataTexture - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; + return { + data: Array.from( image.data ), + width: image.width, + height: image.height, + type: image.data.constructor.name + }; } else { - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; + console.warn( 'THREE.Texture: Unable to serialize Texture.' ); + return {}; } - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + } - // These lines also handle the case where tmin or tmax is NaN - // (result of 0 * Infinity). x !== x returns true if x is NaN + } - if ( tymin > tmin || tmin !== tmin ) tmin = tymin; + let textureId = 0; - if ( tymax < tmax || tmax !== tmax ) tmax = tymax; + class Texture extends EventDispatcher { - if ( invdirz >= 0 ) { + constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding ) { - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; + super(); - } else { + this.isTexture = true; - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; + Object.defineProperty( this, 'id', { value: textureId ++ } ); - } + this.uuid = generateUUID(); - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + this.name = ''; - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + this.source = new Source( image ); + this.mipmaps = []; - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + this.mapping = mapping; - //return point closest to the ray (positive side) + this.wrapS = wrapS; + this.wrapT = wrapT; - if ( tmax < 0 ) return null; + this.magFilter = magFilter; + this.minFilter = minFilter; - return this.at( tmin >= 0 ? tmin : tmax, target ); + this.anisotropy = anisotropy; - } + this.format = format; + this.internalFormat = null; + this.type = type; - intersectsBox( box ) { + this.offset = new Vector2( 0, 0 ); + this.repeat = new Vector2( 1, 1 ); + this.center = new Vector2( 0, 0 ); + this.rotation = 0; - return this.intersectBox( box, _vector$a ) !== null; + this.matrixAutoUpdate = true; + this.matrix = new Matrix3(); - } + this.generateMipmaps = true; + this.premultiplyAlpha = false; + this.flipY = true; + this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - intersectTriangle( a, b, c, backfaceCulling, target ) { + // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. + // + // Also changing the encoding after already used by a Material will not automatically make the Material + // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. + this.encoding = encoding; - // Compute the offset origin, edges, and normal. + this.userData = {}; - // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h + this.version = 0; + this.onUpdate = null; - _edge1.subVectors( b, a ); - _edge2.subVectors( c, a ); - _normal$1.crossVectors( _edge1, _edge2 ); + this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not + this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - let DdN = this.direction.dot( _normal$1 ); - let sign; + } - if ( DdN > 0 ) { + get image() { - if ( backfaceCulling ) return null; - sign = 1; + return this.source.data; - } else if ( DdN < 0 ) { + } - sign = - 1; - DdN = - DdN; + set image( value ) { - } else { + this.source.data = value; - return null; + } - } + updateMatrix() { - _diff.subVectors( this.origin, a ); - const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); + this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { + } - return null; + clone() { - } + return new this.constructor().copy( this ); - const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); + } - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { - - return null; + copy( source ) { - } + this.name = source.name; - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { + this.source = source.source; + this.mipmaps = source.mipmaps.slice( 0 ); - return null; + this.mapping = source.mapping; - } + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; - // Line intersects triangle, check if ray does. - const QdN = - sign * _diff.dot( _normal$1 ); + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; - // t < 0, no intersection - if ( QdN < 0 ) { + this.anisotropy = source.anisotropy; - return null; + this.format = source.format; + this.internalFormat = source.internalFormat; + this.type = source.type; - } + this.offset.copy( source.offset ); + this.repeat.copy( source.repeat ); + this.center.copy( source.center ); + this.rotation = source.rotation; - // Ray intersects triangle. - return this.at( QdN / DdN, target ); + this.matrixAutoUpdate = source.matrixAutoUpdate; + this.matrix.copy( source.matrix ); - } + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; + this.encoding = source.encoding; - applyMatrix4( matrix4 ) { + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); + this.needsUpdate = true; return this; } - equals( ray ) { + toJSON( meta ) { - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - } + if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - clone() { + return meta.textures[ this.uuid ]; - return new this.constructor().copy( this ); + } - } + const output = { - } + metadata: { + version: 4.5, + type: 'Texture', + generator: 'Texture.toJSON' + }, - class Matrix4 { + uuid: this.uuid, + name: this.name, - constructor() { + image: this.source.toJSON( meta ).uuid, - Matrix4.prototype.isMatrix4 = true; + mapping: this.mapping, - this.elements = [ + repeat: [ this.repeat.x, this.repeat.y ], + offset: [ this.offset.x, this.offset.y ], + center: [ this.center.x, this.center.y ], + rotation: this.rotation, - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + wrap: [ this.wrapS, this.wrapT ], - ]; + format: this.format, + type: this.type, + encoding: this.encoding, - } + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy, - set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + flipY: this.flipY, - const te = this.elements; + premultiplyAlpha: this.premultiplyAlpha, + unpackAlignment: this.unpackAlignment - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; + }; - return this; + if ( JSON.stringify( this.userData ) !== '{}' ) output.userData = this.userData; - } + if ( ! isRootObject ) { - identity() { + meta.textures[ this.uuid ] = output; - this.set( + } - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + return output; - ); + } - return this; + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); } - clone() { + transformUv( uv ) { - return new Matrix4().fromArray( this.elements ); + if ( this.mapping !== UVMapping ) return uv; - } + uv.applyMatrix3( this.matrix ); - copy( m ) { + if ( uv.x < 0 || uv.x > 1 ) { - const te = this.elements; - const me = m.elements; + switch ( this.wrapS ) { - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; + case RepeatWrapping: - return this; + uv.x = uv.x - Math.floor( uv.x ); + break; - } + case ClampToEdgeWrapping: - copyPosition( m ) { + uv.x = uv.x < 0 ? 0 : 1; + break; - const te = this.elements, me = m.elements; + case MirroredRepeatWrapping: - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - return this; + uv.x = Math.ceil( uv.x ) - uv.x; - } + } else { - setFromMatrix3( m ) { + uv.x = uv.x - Math.floor( uv.x ); - const me = m.elements; + } - this.set( + break; - me[ 0 ], me[ 3 ], me[ 6 ], 0, - me[ 1 ], me[ 4 ], me[ 7 ], 0, - me[ 2 ], me[ 5 ], me[ 8 ], 0, - 0, 0, 0, 1 + } - ); + } - return this; + if ( uv.y < 0 || uv.y > 1 ) { - } + switch ( this.wrapT ) { - extractBasis( xAxis, yAxis, zAxis ) { + case RepeatWrapping: - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); + uv.y = uv.y - Math.floor( uv.y ); + break; - return this; + case ClampToEdgeWrapping: - } + uv.y = uv.y < 0 ? 0 : 1; + break; - makeBasis( xAxis, yAxis, zAxis ) { + case MirroredRepeatWrapping: - this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, - 0, 0, 0, 1 - ); + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - return this; + uv.y = Math.ceil( uv.y ) - uv.y; - } + } else { - extractRotation( m ) { + uv.y = uv.y - Math.floor( uv.y ); - // this method does not support reflection matrices + } - const te = this.elements; - const me = m.elements; + break; - const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + } - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; + } - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; + if ( this.flipY ) { - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; + uv.y = 1 - uv.y; - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + } - return this; + return uv; } - makeRotationFromEuler( euler ) { + set needsUpdate( value ) { - const te = this.elements; + if ( value === true ) { - const x = euler.x, y = euler.y, z = euler.z; - const a = Math.cos( x ), b = Math.sin( x ); - const c = Math.cos( y ), d = Math.sin( y ); - const e = Math.cos( z ), f = Math.sin( z ); + this.version ++; + this.source.needsUpdate = true; - if ( euler.order === 'XYZ' ) { + } - const ae = a * e, af = a * f, be = b * e, bf = b * f; + } - te[ 0 ] = c * e; - te[ 4 ] = - c * f; - te[ 8 ] = d; + } - te[ 1 ] = af + be * d; - te[ 5 ] = ae - bf * d; - te[ 9 ] = - b * c; + Texture.DEFAULT_IMAGE = null; + Texture.DEFAULT_MAPPING = UVMapping; - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; + class Vector4 { - } else if ( euler.order === 'YXZ' ) { + constructor( x = 0, y = 0, z = 0, w = 1 ) { - const ce = c * e, cf = c * f, de = d * e, df = d * f; + Vector4.prototype.isVector4 = true; - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; + this.x = x; + this.y = y; + this.z = z; + this.w = w; - te[ 1 ] = a * f; - te[ 5 ] = a * e; - te[ 9 ] = - b; + } - te[ 2 ] = cf * b - de; - te[ 6 ] = df + ce * b; - te[ 10 ] = a * c; + get width() { - } else if ( euler.order === 'ZXY' ) { + return this.z; - const ce = c * e, cf = c * f, de = d * e, df = d * f; + } - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; + set width( value ) { - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; + this.z = value; - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; + } - } else if ( euler.order === 'ZYX' ) { + get height() { - const ae = a * e, af = a * f, be = b * e, bf = b * f; + return this.w; - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; + } - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; + set height( value ) { - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; + this.w = value; - } else if ( euler.order === 'YZX' ) { + } - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + set( x, y, z, w ) { - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; + this.x = x; + this.y = y; + this.z = z; + this.w = w; - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; + return this; - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; + } - } else if ( euler.order === 'XZY' ) { + setScalar( scalar ) { - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + this.x = scalar; + this.y = scalar; + this.z = scalar; + this.w = scalar; - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; + return this; - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; + } - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; + setX( x ) { - } + this.x = x; - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; + return this; - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + } + + setY( y ) { + + this.y = y; return this; } - makeRotationFromQuaternion( q ) { + setZ( z ) { - return this.compose( _zero, q, _one ); + this.z = z; + + return this; } - lookAt( eye, target, up ) { + setW( w ) { - const te = this.elements; + this.w = w; - _z.subVectors( eye, target ); + return this; - if ( _z.lengthSq() === 0 ) { + } - // eye and target are in the same position + setComponent( index, value ) { - _z.z = 1; + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: throw new Error( 'index is out of range: ' + index ); } - _z.normalize(); - _x.crossVectors( up, _z ); + return this; - if ( _x.lengthSq() === 0 ) { + } - // up and z are parallel + getComponent( index ) { - if ( Math.abs( up.z ) === 1 ) { + switch ( index ) { - _z.x += 0.0001; + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: throw new Error( 'index is out of range: ' + index ); - } else { + } - _z.z += 0.0001; + } - } + clone() { - _z.normalize(); - _x.crossVectors( up, _z ); + return new this.constructor( this.x, this.y, this.z, this.w ); - } + } - _x.normalize(); - _y.crossVectors( _z, _x ); + copy( v ) { - te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; - te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; - te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; return this; } - multiply( m ) { + add( v ) { - return this.multiplyMatrices( this, m ); + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; + + return this; } - premultiply( m ) { + addScalar( s ) { - return this.multiplyMatrices( m, this ); + this.x += s; + this.y += s; + this.z += s; + this.w += s; + + return this; } - multiplyMatrices( a, b ) { + addVectors( a, b ) { - const ae = a.elements; - const be = b.elements; - const te = this.elements; + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; - const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; + return this; - const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; + } - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + addScaledVector( v, s ) { - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + return this; - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + } + + sub( v ) { + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; return this; } - multiplyScalar( s ) { - - const te = this.elements; + subScalar( s ) { - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; return this; } - determinant() { + subVectors( a, b ) { - const te = this.elements; + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; - const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; + return this; - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + } - return ( - n41 * ( - + n14 * n23 * n32 - - n13 * n24 * n32 - - n14 * n22 * n33 - + n12 * n24 * n33 - + n13 * n22 * n34 - - n12 * n23 * n34 - ) + - n42 * ( - + n11 * n23 * n34 - - n11 * n24 * n33 - + n14 * n21 * n33 - - n13 * n21 * n34 - + n13 * n24 * n31 - - n14 * n23 * n31 - ) + - n43 * ( - + n11 * n24 * n32 - - n11 * n22 * n34 - - n14 * n21 * n32 - + n12 * n21 * n34 - + n14 * n22 * n31 - - n12 * n24 * n31 - ) + - n44 * ( - - n13 * n22 * n31 - - n11 * n23 * n32 - + n11 * n22 * n33 - + n13 * n21 * n32 - - n12 * n21 * n33 - + n12 * n23 * n31 - ) + multiply( v ) { - ); + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + this.w *= v.w; + + return this; } - transpose() { + multiplyScalar( scalar ) { - const te = this.elements; - let tmp; + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; + return this; - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; + } + + applyMatrix4( m ) { + + const x = this.x, y = this.y, z = this.z, w = this.w; + const e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; + this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; return this; } - setPosition( x, y, z ) { + divideScalar( scalar ) { - const te = this.elements; + return this.multiplyScalar( 1 / scalar ); - if ( x.isVector3 ) { + } - te[ 12 ] = x.x; - te[ 13 ] = x.y; - te[ 14 ] = x.z; + setAxisAngleFromQuaternion( q ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + + // q is assumed to be normalized + + this.w = 2 * Math.acos( q.w ); + + const s = Math.sqrt( 1 - q.w * q.w ); + + if ( s < 0.0001 ) { + + this.x = 1; + this.y = 0; + this.z = 0; } else { - te[ 12 ] = x; - te[ 13 ] = y; - te[ 14 ] = z; + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; } @@ -16422,8338 +47838,8114 @@ var app = (function () { } - invert() { - - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - const te = this.elements, - - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], - n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], - n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], - n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], + setAxisAngleFromRotationMatrix( m ) { - t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, - t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, - t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, - t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + let angle, x, y, z; // variables for result + const epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - const detInv = 1 / det; + te = m.elements, - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; + if ( ( Math.abs( m12 - m21 ) < epsilon ) && + ( Math.abs( m13 - m31 ) < epsilon ) && + ( Math.abs( m23 - m32 ) < epsilon ) ) { - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && + ( Math.abs( m13 + m31 ) < epsilon2 ) && + ( Math.abs( m23 + m32 ) < epsilon2 ) && + ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - return this; + // this singularity is identity matrix so angle = 0 - } + this.set( 1, 0, 0, 0 ); - scale( v ) { + return this; // zero angle, arbitrary axis - const te = this.elements; - const x = v.x, y = v.y, z = v.z; + } - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; + // otherwise this singularity is angle = 180 - return this; + angle = Math.PI; - } + const xx = ( m11 + 1 ) / 2; + const yy = ( m22 + 1 ) / 2; + const zz = ( m33 + 1 ) / 2; + const xy = ( m12 + m21 ) / 4; + const xz = ( m13 + m31 ) / 4; + const yz = ( m23 + m32 ) / 4; - getMaxScaleOnAxis() { + if ( ( xx > yy ) && ( xx > zz ) ) { - const te = this.elements; + // m11 is the largest diagonal term - const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + if ( xx < epsilon ) { - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); + x = 0; + y = 0.707106781; + z = 0.707106781; - } + } else { - makeTranslation( x, y, z ) { + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; - this.set( + } - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 + } else if ( yy > zz ) { - ); + // m22 is the largest diagonal term - return this; + if ( yy < epsilon ) { - } + x = 0.707106781; + y = 0; + z = 0.707106781; - makeRotationX( theta ) { + } else { - const c = Math.cos( theta ), s = Math.sin( theta ); + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; - this.set( + } - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 + } else { - ); + // m33 is the largest diagonal term so base result on this - return this; + if ( zz < epsilon ) { - } + x = 0.707106781; + y = 0.707106781; + z = 0; - makeRotationY( theta ) { + } else { - const c = Math.cos( theta ), s = Math.sin( theta ); + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; - this.set( + } - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 + } - ); + this.set( x, y, z, angle ); - return this; + return this; // return 180 deg rotation - } + } - makeRotationZ( theta ) { + // as we have reached here there are no singularities so we can handle normally - const c = Math.cos( theta ), s = Math.sin( theta ); + let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - this.set( + if ( Math.abs( s ) < 0.001 ) s = 1; - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case - ); + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); return this; } - makeRotationAxis( axis, angle ) { + min( v ) { - // Based on http://www.gamedev.net/reference/articles/article1199.asp + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); + this.w = Math.min( this.w, v.w ); - const c = Math.cos( angle ); - const s = Math.sin( angle ); - const t = 1 - c; - const x = axis.x, y = axis.y, z = axis.z; - const tx = t * x, ty = t * y; + return this; - this.set( + } - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 + max( v ) { - ); + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + this.w = Math.max( this.w, v.w ); return this; } - makeScale( x, y, z ) { - - this.set( + clamp( min, max ) { - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 + // assumes min < max, componentwise - ); + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + this.w = Math.max( min.w, Math.min( max.w, this.w ) ); return this; } - makeShear( xy, xz, yx, yz, zx, zy ) { - - this.set( - - 1, yx, zx, 0, - xy, 1, zy, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 + clampScalar( minVal, maxVal ) { - ); + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); return this; } - compose( position, quaternion, scale ) { + clampLength( min, max ) { - const te = this.elements; + const length = this.length(); - const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - const x2 = x + x, y2 = y + y, z2 = z + z; - const xx = x * x2, xy = x * y2, xz = x * z2; - const yy = y * y2, yz = y * z2, zz = z * z2; - const wx = w * x2, wy = w * y2, wz = w * z2; + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - const sx = scale.x, sy = scale.y, sz = scale.z; + } - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; + floor() { - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); - te[ 8 ] = ( xz + wy ) * sz; - te[ 9 ] = ( yz - wx ) * sz; - te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; - te[ 11 ] = 0; + return this; - te[ 12 ] = position.x; - te[ 13 ] = position.y; - te[ 14 ] = position.z; - te[ 15 ] = 1; + } + + ceil() { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); return this; } - decompose( position, quaternion, scale ) { + round() { - const te = this.elements; + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); - let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + return this; - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if ( det < 0 ) sx = - sx; + } - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; + roundToZero() { - // scale the rotation part - _m1$2.copy( this ); + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; + return this; - _m1$2.elements[ 0 ] *= invSX; - _m1$2.elements[ 1 ] *= invSX; - _m1$2.elements[ 2 ] *= invSX; + } - _m1$2.elements[ 4 ] *= invSY; - _m1$2.elements[ 5 ] *= invSY; - _m1$2.elements[ 6 ] *= invSY; + negate() { - _m1$2.elements[ 8 ] *= invSZ; - _m1$2.elements[ 9 ] *= invSZ; - _m1$2.elements[ 10 ] *= invSZ; + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - quaternion.setFromRotationMatrix( _m1$2 ); + return this; - scale.x = sx; - scale.y = sy; - scale.z = sz; + } - return this; + dot( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; } - makePerspective( left, right, top, bottom, near, far ) { + lengthSq() { - const te = this.elements; - const x = 2 * near / ( right - left ); - const y = 2 * near / ( top - bottom ); + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - const a = ( right + left ) / ( right - left ); - const b = ( top + bottom ) / ( top - bottom ); - const c = - ( far + near ) / ( far - near ); - const d = - 2 * far * near / ( far - near ); + } - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; + length() { - return this; + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); } - makeOrthographic( left, right, top, bottom, near, far ) { + manhattanLength() { - const te = this.elements; - const w = 1.0 / ( right - left ); - const h = 1.0 / ( top - bottom ); - const p = 1.0 / ( far - near ); + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - const x = ( right + left ) * w; - const y = ( top + bottom ) * h; - const z = ( far + near ) * p; + } - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; + normalize() { - return this; + return this.divideScalar( this.length() || 1 ); } - equals( matrix ) { + setLength( length ) { - const te = this.elements; - const me = matrix.elements; + return this.normalize().multiplyScalar( length ); - for ( let i = 0; i < 16; i ++ ) { + } - if ( te[ i ] !== me[ i ] ) return false; + lerp( v, alpha ) { - } + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; - return true; + return this; } - fromArray( array, offset = 0 ) { + lerpVectors( v1, v2, alpha ) { - for ( let i = 0; i < 16; i ++ ) { + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; + this.w = v1.w + ( v2.w - v1.w ) * alpha; - this.elements[ i ] = array[ i + offset ]; + return this; - } + } - return this; + equals( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); } - toArray( array = [], offset = 0 ) { + fromArray( array, offset = 0 ) { - const te = this.elements; + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; + return this; - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; + } - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; + toArray( array = [], offset = 0 ) { - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; return array; } - } + fromBufferAttribute( attribute, index ) { - const _v1$5 = /*@__PURE__*/ new Vector3(); - const _m1$2 = /*@__PURE__*/ new Matrix4(); - const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); - const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); - const _x = /*@__PURE__*/ new Vector3(); - const _y = /*@__PURE__*/ new Vector3(); - const _z = /*@__PURE__*/ new Vector3(); + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + this.w = attribute.getW( index ); - const _matrix$1 = /*@__PURE__*/ new Matrix4(); - const _quaternion$3 = /*@__PURE__*/ new Quaternion(); + return this; - class Euler { + } - constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) { + random() { - this.isEuler = true; + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + this.w = Math.random(); - this._x = x; - this._y = y; - this._z = z; - this._order = order; + return this; } - get x() { + *[ Symbol.iterator ]() { - return this._x; + yield this.x; + yield this.y; + yield this.z; + yield this.w; } - set x( value ) { + } - this._x = value; - this._onChangeCallback(); + /* + In options, we can specify: + * Texture parameters for an auto-generated target texture + * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers + */ + class WebGLRenderTarget extends EventDispatcher { - } + constructor( width, height, options = {} ) { - get y() { + super(); - return this._y; + this.isWebGLRenderTarget = true; - } + this.width = width; + this.height = height; + this.depth = 1; - set y( value ) { + this.scissor = new Vector4( 0, 0, width, height ); + this.scissorTest = false; - this._y = value; - this._onChangeCallback(); + this.viewport = new Vector4( 0, 0, width, height ); - } + const image = { width: width, height: height, depth: 1 }; - get z() { + this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + this.texture.isRenderTargetTexture = true; - return this._z; + this.texture.flipY = false; + this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; + this.texture.internalFormat = options.internalFormat !== undefined ? options.internalFormat : null; + this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - } + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false; - set z( value ) { + this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; - this._z = value; - this._onChangeCallback(); + this.samples = options.samples !== undefined ? options.samples : 0; } - get order() { + setSize( width, height, depth = 1 ) { - return this._order; + if ( this.width !== width || this.height !== height || this.depth !== depth ) { - } + this.width = width; + this.height = height; + this.depth = depth; - set order( value ) { + this.texture.image.width = width; + this.texture.image.height = height; + this.texture.image.depth = depth; - this._order = value; - this._onChangeCallback(); + this.dispose(); - } + } - set( x, y, z, order = this._order ) { + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); - this._x = x; - this._y = y; - this._z = z; - this._order = order; + } - this._onChangeCallback(); + clone() { - return this; + return new this.constructor().copy( this ); } - clone() { + copy( source ) { - return new this.constructor( this._x, this._y, this._z, this._order ); + this.width = source.width; + this.height = source.height; + this.depth = source.depth; - } + this.viewport.copy( source.viewport ); - copy( euler ) { + this.texture = source.texture.clone(); + this.texture.isRenderTargetTexture = true; - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + // ensure image object is not shared, see #20328 - this._onChangeCallback(); + const image = Object.assign( {}, source.texture.image ); + this.texture.source = new Source( image ); + + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; + + if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); + + this.samples = source.samples; return this; } - setFromRotationMatrix( m, order = this._order, update = true ) { + dispose() { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + this.dispatchEvent( { type: 'dispose' } ); - const te = m.elements; - const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; - const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; - const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + } - switch ( order ) { + } - case 'XYZ': + class DataArrayTexture extends Texture { - this._y = Math.asin( clamp( m13, - 1, 1 ) ); + constructor( data = null, width = 1, height = 1, depth = 1 ) { - if ( Math.abs( m13 ) < 0.9999999 ) { + super( null ); - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); + this.isDataArrayTexture = true; - } else { + this.image = { data, width, height, depth }; - this._x = Math.atan2( m32, m22 ); - this._z = 0; + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - } + this.wrapR = ClampToEdgeWrapping; - break; + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; - case 'YXZ': + } - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + } - if ( Math.abs( m23 ) < 0.9999999 ) { + class WebGLArrayRenderTarget extends WebGLRenderTarget { - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); + constructor( width, height, depth ) { - } else { + super( width, height ); - this._y = Math.atan2( - m31, m11 ); - this._z = 0; + this.isWebGLArrayRenderTarget = true; - } + this.depth = depth; - break; + this.texture = new DataArrayTexture( null, width, height, depth ); - case 'ZXY': + this.texture.isRenderTargetTexture = true; - this._x = Math.asin( clamp( m32, - 1, 1 ) ); + } - if ( Math.abs( m32 ) < 0.9999999 ) { + } - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); + class Data3DTexture extends Texture { - } else { + constructor( data = null, width = 1, height = 1, depth = 1 ) { - this._y = 0; - this._z = Math.atan2( m21, m11 ); + // We're going to add .setXXX() methods for setting properties later. + // Users can still set in DataTexture3D directly. + // + // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // texture.anisotropy = 16; + // + // See #14839 - } + super( null ); - break; + this.isData3DTexture = true; - case 'ZYX': + this.image = { data, width, height, depth }; - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - if ( Math.abs( m31 ) < 0.9999999 ) { + this.wrapR = ClampToEdgeWrapping; - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; - } else { + } - this._x = 0; - this._z = Math.atan2( - m12, m22 ); + } - } + class WebGL3DRenderTarget extends WebGLRenderTarget { - break; + constructor( width, height, depth ) { - case 'YZX': + super( width, height ); - this._z = Math.asin( clamp( m21, - 1, 1 ) ); + this.isWebGL3DRenderTarget = true; - if ( Math.abs( m21 ) < 0.9999999 ) { + this.depth = depth; - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); + this.texture = new Data3DTexture( null, width, height, depth ); - } else { + this.texture.isRenderTargetTexture = true; - this._x = 0; - this._y = Math.atan2( m13, m33 ); + } - } + } - break; + class WebGLMultipleRenderTargets extends WebGLRenderTarget { - case 'XZY': + constructor( width, height, count, options = {} ) { - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + super( width, height, options ); - if ( Math.abs( m12 ) < 0.9999999 ) { + this.isWebGLMultipleRenderTargets = true; - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); + const texture = this.texture; - } else { + this.texture = []; - this._x = Math.atan2( - m23, m33 ); - this._y = 0; + for ( let i = 0; i < count; i ++ ) { - } + this.texture[ i ] = texture.clone(); + this.texture[ i ].isRenderTargetTexture = true; - break; + } - default: + } - console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + setSize( width, height, depth = 1 ) { - } + if ( this.width !== width || this.height !== height || this.depth !== depth ) { - this._order = order; + this.width = width; + this.height = height; + this.depth = depth; - if ( update === true ) this._onChangeCallback(); + for ( let i = 0, il = this.texture.length; i < il; i ++ ) { - return this; + this.texture[ i ].image.width = width; + this.texture[ i ].image.height = height; + this.texture[ i ].image.depth = depth; - } + } - setFromQuaternion( q, order, update ) { + this.dispose(); - _matrix$1.makeRotationFromQuaternion( q ); + } - return this.setFromRotationMatrix( _matrix$1, order, update ); + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); + + return this; } - setFromVector3( v, order = this._order ) { + copy( source ) { - return this.set( v.x, v.y, v.z, order ); + this.dispose(); - } + this.width = source.width; + this.height = source.height; + this.depth = source.depth; - reorder( newOrder ) { + this.viewport.set( 0, 0, this.width, this.height ); + this.scissor.set( 0, 0, this.width, this.height ); - // WARNING: this discards revolution information -bhouston + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; - _quaternion$3.setFromEuler( this ); + if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - return this.setFromQuaternion( _quaternion$3, newOrder ); + this.texture.length = 0; - } + for ( let i = 0, il = source.texture.length; i < il; i ++ ) { - equals( euler ) { + this.texture[ i ] = source.texture[ i ].clone(); + this.texture[ i ].isRenderTargetTexture = true; - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + } + + return this; } - fromArray( array ) { + } - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + class Quaternion { - this._onChangeCallback(); + constructor( x = 0, y = 0, z = 0, w = 1 ) { - return this; + this.isQuaternion = true; + + this._x = x; + this._y = y; + this._z = z; + this._w = w; } - toArray( array = [], offset = 0 ) { + static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; + // fuzz-free, array-based Quaternion SLERP operation - return array; + let x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ]; - } + const x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; - _onChange( callback ) { + if ( t === 0 ) { - this._onChangeCallback = callback; + dst[ dstOffset + 0 ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + return; - return this; + } - } + if ( t === 1 ) { - _onChangeCallback() {} + dst[ dstOffset + 0 ] = x1; + dst[ dstOffset + 1 ] = y1; + dst[ dstOffset + 2 ] = z1; + dst[ dstOffset + 3 ] = w1; + return; - *[ Symbol.iterator ]() { + } - yield this._x; - yield this._y; - yield this._z; - yield this._order; + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - } + let s = 1 - t; + const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; - // @deprecated since r138, 02cf0df1cb4575d5842fef9c85bb5a89fe020d53 + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { - toVector3() { + const sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); - console.error( 'THREE.Euler: .toVector3() has been removed. Use Vector3.setFromEuler() instead' ); + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; - } + } - } + const tDir = t * dir; - Euler.DefaultOrder = 'XYZ'; - Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; - class Layers { + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { - constructor() { + const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - this.mask = 1 | 0; + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; - } + } - set( channel ) { + } - this.mask = ( 1 << channel | 0 ) >>> 0; + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; } - enable( channel ) { + static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - this.mask |= 1 << channel | 0; + const x0 = src0[ srcOffset0 ]; + const y0 = src0[ srcOffset0 + 1 ]; + const z0 = src0[ srcOffset0 + 2 ]; + const w0 = src0[ srcOffset0 + 3 ]; - } + const x1 = src1[ srcOffset1 ]; + const y1 = src1[ srcOffset1 + 1 ]; + const z1 = src1[ srcOffset1 + 2 ]; + const w1 = src1[ srcOffset1 + 3 ]; - enableAll() { + dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; + dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; + dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; + dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; - this.mask = 0xffffffff | 0; + return dst; } - toggle( channel ) { + get x() { - this.mask ^= 1 << channel | 0; + return this._x; } - disable( channel ) { + set x( value ) { - this.mask &= ~ ( 1 << channel | 0 ); + this._x = value; + this._onChangeCallback(); } - disableAll() { + get y() { - this.mask = 0; + return this._y; } - test( layers ) { + set y( value ) { - return ( this.mask & layers.mask ) !== 0; + this._y = value; + this._onChangeCallback(); } - isEnabled( channel ) { + get z() { - return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + return this._z; } - } + set z( value ) { - let _object3DId = 0; + this._z = value; + this._onChangeCallback(); - const _v1$4 = /*@__PURE__*/ new Vector3(); - const _q1 = /*@__PURE__*/ new Quaternion(); - const _m1$1 = /*@__PURE__*/ new Matrix4(); - const _target = /*@__PURE__*/ new Vector3(); + } - const _position$3 = /*@__PURE__*/ new Vector3(); - const _scale$2 = /*@__PURE__*/ new Vector3(); - const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + get w() { - const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); - const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + return this._w; - const _addedEvent = { type: 'added' }; - const _removedEvent = { type: 'removed' }; + } - class Object3D extends EventDispatcher { + set w( value ) { - constructor() { + this._w = value; + this._onChangeCallback(); - super(); + } - this.isObject3D = true; + set( x, y, z, w ) { - Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + this._x = x; + this._y = y; + this._z = z; + this._w = w; - this.uuid = generateUUID(); + this._onChangeCallback(); - this.name = ''; - this.type = 'Object3D'; + return this; - this.parent = null; - this.children = []; + } - this.up = Object3D.DefaultUp.clone(); + clone() { - const position = new Vector3(); - const rotation = new Euler(); - const quaternion = new Quaternion(); - const scale = new Vector3( 1, 1, 1 ); + return new this.constructor( this._x, this._y, this._z, this._w ); - function onRotationChange() { + } - quaternion.setFromEuler( rotation, false ); + copy( quaternion ) { - } + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - function onQuaternionChange() { + this._onChangeCallback(); - rotation.setFromQuaternion( quaternion, undefined, false ); + return this; - } + } - rotation._onChange( onRotationChange ); - quaternion._onChange( onQuaternionChange ); + setFromEuler( euler, update ) { - Object.defineProperties( this, { - position: { - configurable: true, - enumerable: true, - value: position - }, - rotation: { - configurable: true, - enumerable: true, - value: rotation - }, - quaternion: { - configurable: true, - enumerable: true, - value: quaternion - }, - scale: { - configurable: true, - enumerable: true, - value: scale - }, - modelViewMatrix: { - value: new Matrix4() - }, - normalMatrix: { - value: new Matrix3() - } - } ); + const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; + const cos = Math.cos; + const sin = Math.sin; - this.matrixWorldAutoUpdate = Object3D.DefaultMatrixWorldAutoUpdate; // checked by the renderer + const c1 = cos( x / 2 ); + const c2 = cos( y / 2 ); + const c3 = cos( z / 2 ); - this.layers = new Layers(); - this.visible = true; + const s1 = sin( x / 2 ); + const s2 = sin( y / 2 ); + const s3 = sin( z / 2 ); - this.castShadow = false; - this.receiveShadow = false; + switch ( order ) { - this.frustumCulled = true; - this.renderOrder = 0; + case 'XYZ': + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + break; - this.animations = []; + case 'YXZ': + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + break; - this.userData = {}; + case 'ZXY': + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + break; - } + case 'ZYX': + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + break; - onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} + case 'YZX': + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + break; - onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} + case 'XZY': + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + break; - applyMatrix4( matrix ) { + default: + console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); - if ( this.matrixAutoUpdate ) this.updateMatrix(); + } - this.matrix.premultiply( matrix ); + if ( update !== false ) this._onChangeCallback(); - this.matrix.decompose( this.position, this.quaternion, this.scale ); + return this; } - applyQuaternion( q ) { + setFromAxisAngle( axis, angle ) { - this.quaternion.premultiply( q ); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + + // assumes axis is normalized + + const halfAngle = angle / 2, s = Math.sin( halfAngle ); + + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); + + this._onChangeCallback(); return this; } - setRotationFromAxisAngle( axis, angle ) { + setFromRotationMatrix( m ) { - // assumes axis is normalized + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - this.quaternion.setFromAxisAngle( axis, angle ); + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - } + const te = m.elements, - setRotationFromEuler( euler ) { + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - this.quaternion.setFromEuler( euler, true ); + trace = m11 + m22 + m33; - } + if ( trace > 0 ) { - setRotationFromMatrix( m ) { + const s = 0.5 / Math.sqrt( trace + 1.0 ); - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; - this.quaternion.setFromRotationMatrix( m ); + } else if ( m11 > m22 && m11 > m33 ) { - } + const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - setRotationFromQuaternion( q ) { + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; - // assumes q is normalized + } else if ( m22 > m33 ) { - this.quaternion.copy( q ); + const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - } + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; - rotateOnAxis( axis, angle ) { + } else { - // rotate object on axis in object space - // axis is assumed to be normalized + const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - _q1.setFromAxisAngle( axis, angle ); + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; - this.quaternion.multiply( _q1 ); + } + + this._onChangeCallback(); return this; } - rotateOnWorldAxis( axis, angle ) { + setFromUnitVectors( vFrom, vTo ) { - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent + // assumes direction vectors vFrom and vTo are normalized - _q1.setFromAxisAngle( axis, angle ); + let r = vFrom.dot( vTo ) + 1; - this.quaternion.premultiply( _q1 ); + if ( r < Number.EPSILON ) { - return this; + // vFrom and vTo point in opposite directions - } + r = 0; - rotateX( angle ) { + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - return this.rotateOnAxis( _xAxis, angle ); + this._x = - vFrom.y; + this._y = vFrom.x; + this._z = 0; + this._w = r; - } + } else { - rotateY( angle ) { + this._x = 0; + this._y = - vFrom.z; + this._z = vFrom.y; + this._w = r; - return this.rotateOnAxis( _yAxis, angle ); + } + + } else { + + // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 + + this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; + this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; + this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; + this._w = r; + + } + + return this.normalize(); } - rotateZ( angle ) { + angleTo( q ) { - return this.rotateOnAxis( _zAxis, angle ); + return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); } - translateOnAxis( axis, distance ) { + rotateTowards( q, step ) { - // translate object by distance along axis in object space - // axis is assumed to be normalized + const angle = this.angleTo( q ); - _v1$4.copy( axis ).applyQuaternion( this.quaternion ); + if ( angle === 0 ) return this; - this.position.add( _v1$4.multiplyScalar( distance ) ); + const t = Math.min( 1, step / angle ); + + this.slerp( q, t ); return this; } - translateX( distance ) { + identity() { - return this.translateOnAxis( _xAxis, distance ); + return this.set( 0, 0, 0, 1 ); } - translateY( distance ) { + invert() { - return this.translateOnAxis( _yAxis, distance ); + // quaternion is assumed to have unit length + + return this.conjugate(); } - translateZ( distance ) { + conjugate() { - return this.translateOnAxis( _zAxis, distance ); + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; + + this._onChangeCallback(); + + return this; } - localToWorld( vector ) { + dot( v ) { - return vector.applyMatrix4( this.matrixWorld ); + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; } - worldToLocal( vector ) { + lengthSq() { - return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; } - lookAt( x, y, z ) { + length() { - // This method does not support objects having non-uniformly-scaled parent(s) + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - if ( x.isVector3 ) { + } - _target.copy( x ); + normalize() { - } else { + let l = this.length(); - _target.set( x, y, z ); + if ( l === 0 ) { - } + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; - const parent = this.parent; + } else { - this.updateWorldMatrix( true, false ); + l = 1 / l; - _position$3.setFromMatrixPosition( this.matrixWorld ); + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; - if ( this.isCamera || this.isLight ) { + } - _m1$1.lookAt( _position$3, _target, this.up ); + this._onChangeCallback(); - } else { + return this; - _m1$1.lookAt( _target, _position$3, this.up ); + } - } + multiply( q ) { - this.quaternion.setFromRotationMatrix( _m1$1 ); + return this.multiplyQuaternions( this, q ); - if ( parent ) { + } - _m1$1.extractRotation( parent.matrixWorld ); - _q1.setFromRotationMatrix( _m1$1 ); - this.quaternion.premultiply( _q1.invert() ); + premultiply( q ) { - } + return this.multiplyQuaternions( q, this ); } - add( object ) { - - if ( arguments.length > 1 ) { + multiplyQuaternions( a, b ) { - for ( let i = 0; i < arguments.length; i ++ ) { + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - this.add( arguments[ i ] ); + const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - } + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - return this; + this._onChangeCallback(); - } + return this; - if ( object === this ) { + } - console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); - return this; + slerp( qb, t ) { - } + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); - if ( object && object.isObject3D ) { + const x = this._x, y = this._y, z = this._z, w = this._w; - if ( object.parent !== null ) { + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - object.parent.remove( object ); + let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - } + if ( cosHalfTheta < 0 ) { - object.parent = this; - this.children.push( object ); + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - object.dispatchEvent( _addedEvent ); + cosHalfTheta = - cosHalfTheta; } else { - console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); + this.copy( qb ); } - return this; + if ( cosHalfTheta >= 1.0 ) { - } + this._w = w; + this._x = x; + this._y = y; + this._z = z; - remove( object ) { + return this; - if ( arguments.length > 1 ) { + } - for ( let i = 0; i < arguments.length; i ++ ) { + const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - this.remove( arguments[ i ] ); + if ( sqrSinHalfTheta <= Number.EPSILON ) { - } + const s = 1 - t; + this._w = s * w + t * this._w; + this._x = s * x + t * this._x; + this._y = s * y + t * this._y; + this._z = s * z + t * this._z; + + this.normalize(); + this._onChangeCallback(); return this; } - const index = this.children.indexOf( object ); - - if ( index !== - 1 ) { - - object.parent = null; - this.children.splice( index, 1 ); + const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); + const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - object.dispatchEvent( _removedEvent ); + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); - } + this._onChangeCallback(); return this; } - removeFromParent() { - - const parent = this.parent; - - if ( parent !== null ) { - - parent.remove( this ); - - } + slerpQuaternions( qa, qb, t ) { - return this; + return this.copy( qa ).slerp( qb, t ); } - clear() { + random() { - for ( let i = 0; i < this.children.length; i ++ ) { + // Derived from http://planning.cs.uiuc.edu/node198.html + // Note, this source uses w, x, y, z ordering, + // so we swap the order below. - const object = this.children[ i ]; + const u1 = Math.random(); + const sqrt1u1 = Math.sqrt( 1 - u1 ); + const sqrtu1 = Math.sqrt( u1 ); - object.parent = null; + const u2 = 2 * Math.PI * Math.random(); - object.dispatchEvent( _removedEvent ); + const u3 = 2 * Math.PI * Math.random(); - } + return this.set( + sqrt1u1 * Math.cos( u2 ), + sqrtu1 * Math.sin( u3 ), + sqrtu1 * Math.cos( u3 ), + sqrt1u1 * Math.sin( u2 ), + ); - this.children.length = 0; + } - return this; + equals( quaternion ) { + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); } - attach( object ) { - - // adds object as a child of this, while maintaining the object's world transform + fromArray( array, offset = 0 ) { - // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; - this.updateWorldMatrix( true, false ); + this._onChangeCallback(); - _m1$1.copy( this.matrixWorld ).invert(); + return this; - if ( object.parent !== null ) { + } - object.parent.updateWorldMatrix( true, false ); + toArray( array = [], offset = 0 ) { - _m1$1.multiply( object.parent.matrixWorld ); + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; - } + return array; - object.applyMatrix4( _m1$1 ); + } - this.add( object ); + fromBufferAttribute( attribute, index ) { - object.updateWorldMatrix( false, true ); + this._x = attribute.getX( index ); + this._y = attribute.getY( index ); + this._z = attribute.getZ( index ); + this._w = attribute.getW( index ); return this; } - getObjectById( id ) { + _onChange( callback ) { - return this.getObjectByProperty( 'id', id ); + this._onChangeCallback = callback; + + return this; } - getObjectByName( name ) { + _onChangeCallback() {} - return this.getObjectByProperty( 'name', name ); + *[ Symbol.iterator ]() { + + yield this._x; + yield this._y; + yield this._z; + yield this._w; } - getObjectByProperty( name, value ) { + } - if ( this[ name ] === value ) return this; + class Vector3 { - for ( let i = 0, l = this.children.length; i < l; i ++ ) { + constructor( x = 0, y = 0, z = 0 ) { - const child = this.children[ i ]; - const object = child.getObjectByProperty( name, value ); + Vector3.prototype.isVector3 = true; - if ( object !== undefined ) { + this.x = x; + this.y = y; + this.z = z; - return object; + } - } + set( x, y, z ) { - } + if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) - return undefined; + this.x = x; + this.y = y; + this.z = z; + + return this; } - getWorldPosition( target ) { + setScalar( scalar ) { - this.updateWorldMatrix( true, false ); + this.x = scalar; + this.y = scalar; + this.z = scalar; - return target.setFromMatrixPosition( this.matrixWorld ); + return this; } - getWorldQuaternion( target ) { - - this.updateWorldMatrix( true, false ); + setX( x ) { - this.matrixWorld.decompose( _position$3, target, _scale$2 ); + this.x = x; - return target; + return this; } - getWorldScale( target ) { - - this.updateWorldMatrix( true, false ); + setY( y ) { - this.matrixWorld.decompose( _position$3, _quaternion$2, target ); + this.y = y; - return target; + return this; } - getWorldDirection( target ) { - - this.updateWorldMatrix( true, false ); + setZ( z ) { - const e = this.matrixWorld.elements; + this.z = z; - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + return this; } - raycast( /* raycaster, intersects */ ) {} - - traverse( callback ) { - - callback( this ); - - const children = this.children; + setComponent( index, value ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + switch ( index ) { - children[ i ].traverse( callback ); + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( 'index is out of range: ' + index ); } - } - - traverseVisible( callback ) { - - if ( this.visible === false ) return; + return this; - callback( this ); + } - const children = this.children; + getComponent( index ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + switch ( index ) { - children[ i ].traverseVisible( callback ); + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( 'index is out of range: ' + index ); } } - traverseAncestors( callback ) { + clone() { - const parent = this.parent; + return new this.constructor( this.x, this.y, this.z ); - if ( parent !== null ) { + } - callback( parent ); + copy( v ) { - parent.traverseAncestors( callback ); + this.x = v.x; + this.y = v.y; + this.z = v.z; - } + return this; } - updateMatrix() { + add( v ) { - this.matrix.compose( this.position, this.quaternion, this.scale ); + this.x += v.x; + this.y += v.y; + this.z += v.z; - this.matrixWorldNeedsUpdate = true; + return this; } - updateMatrixWorld( force ) { + addScalar( s ) { - if ( this.matrixAutoUpdate ) this.updateMatrix(); + this.x += s; + this.y += s; + this.z += s; - if ( this.matrixWorldNeedsUpdate || force ) { + return this; - if ( this.parent === null ) { + } - this.matrixWorld.copy( this.matrix ); + addVectors( a, b ) { - } else { + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + return this; - } + } - this.matrixWorldNeedsUpdate = false; + addScaledVector( v, s ) { - force = true; + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; - } + return this; - // update children + } - const children = this.children; + sub( v ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; - const child = children[ i ]; + return this; - if ( child.matrixWorldAutoUpdate === true || force === true ) { + } - child.updateMatrixWorld( force ); + subScalar( s ) { - } + this.x -= s; + this.y -= s; + this.z -= s; - } + return this; } - updateWorldMatrix( updateParents, updateChildren ) { + subVectors( a, b ) { - const parent = this.parent; + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; - if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { + return this; - parent.updateWorldMatrix( true, false ); + } - } + multiply( v ) { - if ( this.matrixAutoUpdate ) this.updateMatrix(); + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; - if ( this.parent === null ) { + return this; - this.matrixWorld.copy( this.matrix ); + } - } else { + multiplyScalar( scalar ) { - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; - } + return this; - // update children + } - if ( updateChildren === true ) { + multiplyVectors( a, b ) { - const children = this.children; + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; - for ( let i = 0, l = children.length; i < l; i ++ ) { + return this; - const child = children[ i ]; + } - if ( child.matrixWorldAutoUpdate === true ) { + applyEuler( euler ) { - child.updateWorldMatrix( false, true ); + return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); - } + } - } + applyAxisAngle( axis, angle ) { - } + return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); } - toJSON( meta ) { - - // meta is a string when called from JSON.stringify - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + applyMatrix3( m ) { - const output = {}; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; + this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {}, - skeletons: {}, - animations: {}, - nodes: {} - }; + return this; - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' - }; + } - } + applyNormalMatrix( m ) { - // standard Object3D serialization + return this.applyMatrix3( m ).normalize(); - const object = {}; + } - object.uuid = this.uuid; - object.type = this.type; + applyMatrix4( m ) { - if ( this.name !== '' ) object.name = this.name; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - if ( this.frustumCulled === false ) object.frustumCulled = false; - if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; - if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); + const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; + this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; + this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; + this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; - // object specific properties + return this; - if ( this.isInstancedMesh ) { + } - object.type = 'InstancedMesh'; - object.count = this.count; - object.instanceMatrix = this.instanceMatrix.toJSON(); - if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); + applyQuaternion( q ) { - } + const x = this.x, y = this.y, z = this.z; + const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - // + // calculate quat * vector - function serialize( library, element ) { + const ix = qw * x + qy * z - qz * y; + const iy = qw * y + qz * x - qx * z; + const iz = qw * z + qx * y - qy * x; + const iw = - qx * x - qy * y - qz * z; - if ( library[ element.uuid ] === undefined ) { + // calculate result * inverse quat - library[ element.uuid ] = element.toJSON( meta ); + this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; + this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; + this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; - } + return this; - return element.uuid; + } - } + project( camera ) { - if ( this.isScene ) { + return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); - if ( this.background ) { + } - if ( this.background.isColor ) { + unproject( camera ) { - object.background = this.background.toJSON(); + return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); - } else if ( this.background.isTexture ) { + } - object.background = this.background.toJSON( meta ).uuid; + transformDirection( m ) { - } + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction - } + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; - object.environment = this.environment.toJSON( meta ).uuid; + return this.normalize(); - } + } - } else if ( this.isMesh || this.isLine || this.isPoints ) { + divide( v ) { - object.geometry = serialize( meta.geometries, this.geometry ); + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; - const parameters = this.geometry.parameters; + return this; - if ( parameters !== undefined && parameters.shapes !== undefined ) { + } - const shapes = parameters.shapes; + divideScalar( scalar ) { - if ( Array.isArray( shapes ) ) { + return this.multiplyScalar( 1 / scalar ); - for ( let i = 0, l = shapes.length; i < l; i ++ ) { + } - const shape = shapes[ i ]; + min( v ) { - serialize( meta.shapes, shape ); + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); - } + return this; - } else { + } - serialize( meta.shapes, shapes ); + max( v ) { - } + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); - } + return this; - } + } - if ( this.isSkinnedMesh ) { + clamp( min, max ) { - object.bindMode = this.bindMode; - object.bindMatrix = this.bindMatrix.toArray(); + // assumes min < max, componentwise - if ( this.skeleton !== undefined ) { + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - serialize( meta.skeletons, this.skeleton ); + return this; - object.skeleton = this.skeleton.uuid; + } - } + clampScalar( minVal, maxVal ) { - } + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - if ( this.material !== undefined ) { + return this; - if ( Array.isArray( this.material ) ) { + } - const uuids = []; + clampLength( min, max ) { - for ( let i = 0, l = this.material.length; i < l; i ++ ) { + const length = this.length(); - uuids.push( serialize( meta.materials, this.material[ i ] ) ); + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - } + } - object.material = uuids; + floor() { - } else { + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); - object.material = serialize( meta.materials, this.material ); + return this; - } + } - } + ceil() { - // + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); - if ( this.children.length > 0 ) { + return this; - object.children = []; + } - for ( let i = 0; i < this.children.length; i ++ ) { + round() { - object.children.push( this.children[ i ].toJSON( meta ).object ); + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); - } + return this; - } + } - // + roundToZero() { - if ( this.animations.length > 0 ) { + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - object.animations = []; + return this; - for ( let i = 0; i < this.animations.length; i ++ ) { + } - const animation = this.animations[ i ]; + negate() { - object.animations.push( serialize( meta.animations, animation ) ); + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; - } + return this; - } + } - if ( isRootObject ) { + dot( v ) { - const geometries = extractFromCache( meta.geometries ); - const materials = extractFromCache( meta.materials ); - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const shapes = extractFromCache( meta.shapes ); - const skeletons = extractFromCache( meta.skeletons ); - const animations = extractFromCache( meta.animations ); - const nodes = extractFromCache( meta.nodes ); + return this.x * v.x + this.y * v.y + this.z * v.z; - if ( geometries.length > 0 ) output.geometries = geometries; - if ( materials.length > 0 ) output.materials = materials; - if ( textures.length > 0 ) output.textures = textures; - if ( images.length > 0 ) output.images = images; - if ( shapes.length > 0 ) output.shapes = shapes; - if ( skeletons.length > 0 ) output.skeletons = skeletons; - if ( animations.length > 0 ) output.animations = animations; - if ( nodes.length > 0 ) output.nodes = nodes; + } - } + // TODO lengthSquared? - output.object = object; + lengthSq() { - return output; + return this.x * this.x + this.y * this.y + this.z * this.z; - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { + } - const values = []; - for ( const key in cache ) { + length() { - const data = cache[ key ]; - delete data.metadata; - values.push( data ); + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - } + } - return values; + manhattanLength() { - } + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); } - clone( recursive ) { + normalize() { - return new this.constructor().copy( this, recursive ); + return this.divideScalar( this.length() || 1 ); } - copy( source, recursive = true ) { + setLength( length ) { - this.name = source.name; + return this.normalize().multiplyScalar( length ); - this.up.copy( source.up ); + } - this.position.copy( source.position ); - this.rotation.order = source.rotation.order; - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); + lerp( v, alpha ) { - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + return this; - this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; + } - this.layers.mask = source.layers.mask; - this.visible = source.visible; + lerpVectors( v1, v2, alpha ) { - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; + return this; - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + } - if ( recursive === true ) { + cross( v ) { - for ( let i = 0; i < source.children.length; i ++ ) { + return this.crossVectors( this, v ); - const child = source.children[ i ]; - this.add( child.clone() ); + } - } + crossVectors( a, b ) { - } + const ax = a.x, ay = a.y, az = a.z; + const bx = b.x, by = b.y, bz = b.z; + + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; return this; } - } - - Object3D.DefaultUp = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - Object3D.DefaultMatrixAutoUpdate = true; - Object3D.DefaultMatrixWorldAutoUpdate = true; - - const _v0$1 = /*@__PURE__*/ new Vector3(); - const _v1$3 = /*@__PURE__*/ new Vector3(); - const _v2$2 = /*@__PURE__*/ new Vector3(); - const _v3$1 = /*@__PURE__*/ new Vector3(); + projectOnVector( v ) { - const _vab = /*@__PURE__*/ new Vector3(); - const _vac = /*@__PURE__*/ new Vector3(); - const _vbc = /*@__PURE__*/ new Vector3(); - const _vap = /*@__PURE__*/ new Vector3(); - const _vbp = /*@__PURE__*/ new Vector3(); - const _vcp = /*@__PURE__*/ new Vector3(); + const denominator = v.lengthSq(); - class Triangle { + if ( denominator === 0 ) return this.set( 0, 0, 0 ); - constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { + const scalar = v.dot( this ) / denominator; - this.a = a; - this.b = b; - this.c = c; + return this.copy( v ).multiplyScalar( scalar ); } - static getNormal( a, b, c, target ) { + projectOnPlane( planeNormal ) { - target.subVectors( c, b ); - _v0$1.subVectors( a, b ); - target.cross( _v0$1 ); + _vector$c.copy( this ).projectOnVector( planeNormal ); - const targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { + return this.sub( _vector$c ); - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); + } - } + reflect( normal ) { - return target.set( 0, 0, 0 ); + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length + + return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); } - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - static getBarycoord( point, a, b, c, target ) { + angleTo( v ) { - _v0$1.subVectors( c, a ); - _v1$3.subVectors( b, a ); - _v2$2.subVectors( point, a ); + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - const dot00 = _v0$1.dot( _v0$1 ); - const dot01 = _v0$1.dot( _v1$3 ); - const dot02 = _v0$1.dot( _v2$2 ); - const dot11 = _v1$3.dot( _v1$3 ); - const dot12 = _v1$3.dot( _v2$2 ); + if ( denominator === 0 ) return Math.PI / 2; - const denom = ( dot00 * dot11 - dot01 * dot01 ); + const theta = this.dot( v ) / denominator; - // collinear or singular triangle - if ( denom === 0 ) { + // clamp, to handle numerical problems - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return target.set( - 2, - 1, - 1 ); + return Math.acos( clamp( theta, - 1, 1 ) ); - } + } - const invDenom = 1 / denom; - const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + distanceTo( v ) { - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); + return Math.sqrt( this.distanceToSquared( v ) ); } - static containsPoint( point, a, b, c ) { + distanceToSquared( v ) { - this.getBarycoord( point, a, b, c, _v3$1 ); + const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); + return dx * dx + dy * dy + dz * dz; } - static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { + manhattanDistanceTo( v ) { - this.getBarycoord( point, p1, p2, p3, _v3$1 ); + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); - target.set( 0, 0 ); - target.addScaledVector( uv1, _v3$1.x ); - target.addScaledVector( uv2, _v3$1.y ); - target.addScaledVector( uv3, _v3$1.z ); + } - return target; + setFromSpherical( s ) { + + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); } - static isFrontFacing( a, b, c, direction ) { + setFromSphericalCoords( radius, phi, theta ) { - _v0$1.subVectors( c, b ); - _v1$3.subVectors( a, b ); + const sinPhiRadius = Math.sin( phi ) * radius; - // strictly front facing - return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); + + return this; } - set( a, b, c ) { + setFromCylindrical( c ) { - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); + return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + + } + + setFromCylindricalCoords( radius, theta, y ) { + + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); return this; } - setFromPointsAndIndices( points, i0, i1, i2 ) { + setFromMatrixPosition( m ) { - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); + const e = m.elements; + + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; return this; } - setFromAttributeAndIndices( attribute, i0, i1, i2 ) { + setFromMatrixScale( m ) { - this.a.fromBufferAttribute( attribute, i0 ); - this.b.fromBufferAttribute( attribute, i1 ); - this.c.fromBufferAttribute( attribute, i2 ); + const sx = this.setFromMatrixColumn( m, 0 ).length(); + const sy = this.setFromMatrixColumn( m, 1 ).length(); + const sz = this.setFromMatrixColumn( m, 2 ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; return this; } - clone() { + setFromMatrixColumn( m, index ) { - return new this.constructor().copy( this ); + return this.fromArray( m.elements, index * 4 ); } - copy( triangle ) { - - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); + setFromMatrix3Column( m, index ) { - return this; + return this.fromArray( m.elements, index * 3 ); } - getArea() { + setFromEuler( e ) { - _v0$1.subVectors( this.c, this.b ); - _v1$3.subVectors( this.a, this.b ); + this.x = e._x; + this.y = e._y; + this.z = e._z; - return _v0$1.cross( _v1$3 ).length() * 0.5; + return this; } - getMidpoint( target ) { + equals( v ) { - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); } - getNormal( target ) { + fromArray( array, offset = 0 ) { - return Triangle.getNormal( this.a, this.b, this.c, target ); + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + + return this; } - getPlane( target ) { + toArray( array = [], offset = 0 ) { - return target.setFromCoplanarPoints( this.a, this.b, this.c ); + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + + return array; } - getBarycoord( point, target ) { + fromBufferAttribute( attribute, index ) { - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + + return this; } - getUV( point, uv1, uv2, uv3, target ) { + random() { - return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + + return this; } - containsPoint( point ) { + randomDirection() { - return Triangle.containsPoint( point, this.a, this.b, this.c ); + // Derived from https://mathworld.wolfram.com/SpherePointPicking.html + + const u = ( Math.random() - 0.5 ) * 2; + const t = Math.random() * Math.PI * 2; + const f = Math.sqrt( 1 - u ** 2 ); + + this.x = f * Math.cos( t ); + this.y = f * Math.sin( t ); + this.z = u; + + return this; } - isFrontFacing( direction ) { + *[ Symbol.iterator ]() { - return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); + yield this.x; + yield this.y; + yield this.z; } - intersectsBox( box ) { + } - return box.intersectsTriangle( this ); + const _vector$c = /*@__PURE__*/ new Vector3(); + const _quaternion$4 = /*@__PURE__*/ new Quaternion(); + + class Box3 { + + constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { + + this.isBox3 = true; + + this.min = min; + this.max = max; } - closestPointToPoint( p, target ) { + set( min, max ) { - const a = this.a, b = this.b, c = this.c; - let v, w; + this.min.copy( min ); + this.max.copy( max ); - // algorithm thanks to Real-Time Collision Detection by Christer Ericson, - // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., - // under the accompanying license; see chapter 5.1.5 for detailed explanation. - // basically, we're distinguishing which of the voronoi regions of the triangle - // the point lies in with the minimum amount of redundant computation. + return this; - _vab.subVectors( b, a ); - _vac.subVectors( c, a ); - _vap.subVectors( p, a ); - const d1 = _vab.dot( _vap ); - const d2 = _vac.dot( _vap ); - if ( d1 <= 0 && d2 <= 0 ) { + } - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); + setFromArray( array ) { - } + let minX = + Infinity; + let minY = + Infinity; + let minZ = + Infinity; - _vbp.subVectors( p, b ); - const d3 = _vab.dot( _vbp ); - const d4 = _vac.dot( _vbp ); - if ( d3 >= 0 && d4 <= d3 ) { + let maxX = - Infinity; + let maxY = - Infinity; + let maxZ = - Infinity; - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); + for ( let i = 0, l = array.length; i < l; i += 3 ) { - } + const x = array[ i ]; + const y = array[ i + 1 ]; + const z = array[ i + 2 ]; - const vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( z < minZ ) minZ = z; - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( _vab, v ); + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; + if ( z > maxZ ) maxZ = z; } - _vcp.subVectors( p, c ); - const d5 = _vab.dot( _vcp ); - const d6 = _vac.dot( _vcp ); - if ( d6 >= 0 && d5 <= d6 ) { + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); + return this; - } + } - const vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { + setFromBufferAttribute( attribute ) { - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( _vac, w ); + let minX = + Infinity; + let minY = + Infinity; + let minZ = + Infinity; - } + let maxX = - Infinity; + let maxY = - Infinity; + let maxZ = - Infinity; - const va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { + for ( let i = 0, l = attribute.count; i < l; i ++ ) { - _vbc.subVectors( c, b ); - w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); - // edge region of BC; barycentric coords (0, 1-w, w) - return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC + const x = attribute.getX( i ); + const y = attribute.getY( i ); + const z = attribute.getZ( i ); + + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( z < minZ ) minZ = z; + + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; + if ( z > maxZ ) maxZ = z; } - // face region - const denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); - return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); + return this; } - equals( triangle ) { + setFromPoints( points ) { - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + this.makeEmpty(); - } + for ( let i = 0, il = points.length; i < il; i ++ ) { - } + this.expandByPoint( points[ i ] ); - let materialId = 0; + } - class Material extends EventDispatcher { + return this; - constructor() { + } - super(); + setFromCenterAndSize( center, size ) { - this.isMaterial = true; + const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); - Object.defineProperty( this, 'id', { value: materialId ++ } ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - this.uuid = generateUUID(); + return this; - this.name = ''; - this.type = 'Material'; + } - this.blending = NormalBlending; - this.side = FrontSide; - this.vertexColors = false; + setFromObject( object, precise = false ) { - this.opacity = 1; - this.transparent = false; + this.makeEmpty(); - this.blendSrc = SrcAlphaFactor; - this.blendDst = OneMinusSrcAlphaFactor; - this.blendEquation = AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; + return this.expandByObject( object, precise ); - this.depthFunc = LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; + } - this.stencilWriteMask = 0xff; - this.stencilFunc = AlwaysStencilFunc; - this.stencilRef = 0; - this.stencilFuncMask = 0xff; - this.stencilFail = KeepStencilOp; - this.stencilZFail = KeepStencilOp; - this.stencilZPass = KeepStencilOp; - this.stencilWrite = false; + clone() { - this.clippingPlanes = null; - this.clipIntersection = false; - this.clipShadows = false; + return new this.constructor().copy( this ); - this.shadowSide = null; + } - this.colorWrite = true; + copy( box ) { - this.precision = null; // override the renderer's default precision for this material + this.min.copy( box.min ); + this.max.copy( box.max ); - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; + return this; - this.dithering = false; + } - this.alphaToCoverage = false; - this.premultipliedAlpha = false; + makeEmpty() { - this.visible = true; + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; - this.toneMapped = true; + return this; - this.userData = {}; + } - this.version = 0; + isEmpty() { - this._alphaTest = 0; + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); } - get alphaTest() { + getCenter( target ) { - return this._alphaTest; + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); } - set alphaTest( value ) { + getSize( target ) { - if ( this._alphaTest > 0 !== value > 0 ) { + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); - this.version ++; + } - } + expandByPoint( point ) { - this._alphaTest = value; + this.min.min( point ); + this.max.max( point ); + + return this; } - onBuild( /* shaderobject, renderer */ ) {} + expandByVector( vector ) { - onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} + this.min.sub( vector ); + this.max.add( vector ); - onBeforeCompile( /* shaderobject, renderer */ ) {} + return this; - customProgramCacheKey() { + } - return this.onBeforeCompile.toString(); + expandByScalar( scalar ) { - } + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - setValues( values ) { + return this; - if ( values === undefined ) return; + } - for ( const key in values ) { + expandByObject( object, precise = false ) { - const newValue = values[ key ]; + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms - if ( newValue === undefined ) { + object.updateWorldMatrix( false, false ); - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); - continue; + const geometry = object.geometry; - } + if ( geometry !== undefined ) { - const currentValue = this[ key ]; + if ( precise && geometry.attributes != undefined && geometry.attributes.position !== undefined ) { - if ( currentValue === undefined ) { + const position = geometry.attributes.position; + for ( let i = 0, l = position.count; i < l; i ++ ) { - console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' ); - continue; + _vector$b.fromBufferAttribute( position, i ).applyMatrix4( object.matrixWorld ); + this.expandByPoint( _vector$b ); - } + } - if ( currentValue && currentValue.isColor ) { + } else { - currentValue.set( newValue ); + if ( geometry.boundingBox === null ) { - } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { + geometry.computeBoundingBox(); - currentValue.copy( newValue ); + } - } else { + _box$3.copy( geometry.boundingBox ); + _box$3.applyMatrix4( object.matrixWorld ); - this[ key ] = newValue; + this.union( _box$3 ); } } - } + const children = object.children; - toJSON( meta ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + this.expandByObject( children[ i ], precise ); - if ( isRootObject ) { + } - meta = { - textures: {}, - images: {} - }; + return this; - } + } - const data = { - metadata: { - version: 4.5, - type: 'Material', - generator: 'Material.toJSON' - } - }; + containsPoint( point ) { - // standard Material serialization - data.uuid = this.uuid; - data.type = this.type; + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ? false : true; - if ( this.name !== '' ) data.name = this.name; + } - if ( this.color && this.color.isColor ) data.color = this.color.getHex(); + containsBox( box ) { - if ( this.roughness !== undefined ) data.roughness = this.roughness; - if ( this.metalness !== undefined ) data.metalness = this.metalness; + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y && + this.min.z <= box.min.z && box.max.z <= this.max.z; - if ( this.sheen !== undefined ) data.sheen = this.sheen; - if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); - if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; - if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); - if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; + } - if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); - if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; - if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); - if ( this.shininess !== undefined ) data.shininess = this.shininess; - if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; - if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; + getParameter( point, target ) { - if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; + return target.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ), + ( point.z - this.min.z ) / ( this.max.z - this.min.z ) + ); - } + } - if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { + intersectsBox( box ) { - data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; + // using 6 splitting planes to rule out intersections. + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ? false : true; - } + } - if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { + intersectsSphere( sphere ) { - data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; - data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, _vector$b ); - } + // If that point is inside the sphere, the AABB and sphere intersect. + return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); - if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; - if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; - if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; + } - if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { + intersectsPlane( plane ) { - data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; + // We compute the minimum and maximum dot product values. If those values + // are on the same side (back or front) of the plane, then there is no intersection. - } + let min, max; - if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { + if ( plane.normal.x > 0 ) { - data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; - } + } else { - if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; - if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; - if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; - if ( this.lightMap && this.lightMap.isTexture ) { + } - data.lightMap = this.lightMap.toJSON( meta ).uuid; - data.lightMapIntensity = this.lightMapIntensity; + if ( plane.normal.y > 0 ) { - } + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; - if ( this.aoMap && this.aoMap.isTexture ) { + } else { - data.aoMap = this.aoMap.toJSON( meta ).uuid; - data.aoMapIntensity = this.aoMapIntensity; + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; } - if ( this.bumpMap && this.bumpMap.isTexture ) { + if ( plane.normal.z > 0 ) { - data.bumpMap = this.bumpMap.toJSON( meta ).uuid; - data.bumpScale = this.bumpScale; + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; + + } else { + + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; } - if ( this.normalMap && this.normalMap.isTexture ) { + return ( min <= - plane.constant && max >= - plane.constant ); - data.normalMap = this.normalMap.toJSON( meta ).uuid; - data.normalMapType = this.normalMapType; - data.normalScale = this.normalScale.toArray(); + } - } + intersectsTriangle( triangle ) { - if ( this.displacementMap && this.displacementMap.isTexture ) { + if ( this.isEmpty() ) { - data.displacementMap = this.displacementMap.toJSON( meta ).uuid; - data.displacementScale = this.displacementScale; - data.displacementBias = this.displacementBias; + return false; } - if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; - if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; + // compute box center and extents + this.getCenter( _center ); + _extents.subVectors( this.max, _center ); - if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; - if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; - if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; - if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; + // translate triangle to aabb origin + _v0$2.subVectors( triangle.a, _center ); + _v1$7.subVectors( triangle.b, _center ); + _v2$3.subVectors( triangle.c, _center ); - if ( this.envMap && this.envMap.isTexture ) { + // compute edge vectors for triangle + _f0.subVectors( _v1$7, _v0$2 ); + _f1.subVectors( _v2$3, _v1$7 ); + _f2.subVectors( _v0$2, _v2$3 ); - data.envMap = this.envMap.toJSON( meta ).uuid; + // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb + // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation + // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) + let axes = [ + 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, + _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, + - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 + ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) { - if ( this.combine !== undefined ) data.combine = this.combine; + return false; } - if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; - if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; - if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; - - if ( this.gradientMap && this.gradientMap.isTexture ) { + // test 3 face normals from the aabb + axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) { - data.gradientMap = this.gradientMap.toJSON( meta ).uuid; + return false; } - if ( this.transmission !== undefined ) data.transmission = this.transmission; - if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; - if ( this.thickness !== undefined ) data.thickness = this.thickness; - if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; - if ( this.attenuationDistance !== undefined ) data.attenuationDistance = this.attenuationDistance; - if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); + // finally testing the face normal of the triangle + // use already existing triangle edge vectors here + _triangleNormal.crossVectors( _f0, _f1 ); + axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; - if ( this.size !== undefined ) data.size = this.size; - if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; - if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; + return satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ); - if ( this.blending !== NormalBlending ) data.blending = this.blending; - if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors ) data.vertexColors = true; + } - if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = this.transparent; + clampPoint( point, target ) { - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; - data.colorWrite = this.colorWrite; + return target.copy( point ).clamp( this.min, this.max ); - data.stencilWrite = this.stencilWrite; - data.stencilWriteMask = this.stencilWriteMask; - data.stencilFunc = this.stencilFunc; - data.stencilRef = this.stencilRef; - data.stencilFuncMask = this.stencilFuncMask; - data.stencilFail = this.stencilFail; - data.stencilZFail = this.stencilZFail; - data.stencilZPass = this.stencilZPass; + } - // rotation (SpriteMaterial) - if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; + distanceToPoint( point ) { - if ( this.polygonOffset === true ) data.polygonOffset = true; - if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; - if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; + const clampedPoint = _vector$b.copy( point ).clamp( this.min, this.max ); - if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; - if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; - if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; - if ( this.scale !== undefined ) data.scale = this.scale; + return clampedPoint.sub( point ).length(); - if ( this.dithering === true ) data.dithering = true; + } - if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; + getBoundingSphere( target ) { - if ( this.wireframe === true ) data.wireframe = this.wireframe; - if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; - if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; - if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; + this.getCenter( target.center ); - if ( this.flatShading === true ) data.flatShading = this.flatShading; + target.radius = this.getSize( _vector$b ).length() * 0.5; - if ( this.visible === false ) data.visible = false; + return target; - if ( this.toneMapped === false ) data.toneMapped = false; + } - if ( this.fog === false ) data.fog = false; + intersect( box ) { - if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; + this.min.max( box.min ); + this.max.min( box.max ); - // TODO: Copied from Object3D.toJSON + // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. + if ( this.isEmpty() ) this.makeEmpty(); - function extractFromCache( cache ) { + return this; - const values = []; + } - for ( const key in cache ) { + union( box ) { - const data = cache[ key ]; - delete data.metadata; - values.push( data ); + this.min.min( box.min ); + this.max.max( box.max ); - } + return this; - return values; + } - } + applyMatrix4( matrix ) { - if ( isRootObject ) { + // transform of empty box is an empty box. + if ( this.isEmpty() ) return this; - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; + this.setFromPoints( _points ); - } + return this; - return data; + } + + translate( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; } - clone() { + equals( box ) { - return new this.constructor().copy( this ); + return box.min.equals( this.min ) && box.max.equals( this.max ); } - copy( source ) { + } - this.name = source.name; + const _points = [ + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3(), + /*@__PURE__*/ new Vector3() + ]; - this.blending = source.blending; - this.side = source.side; - this.vertexColors = source.vertexColors; + const _vector$b = /*@__PURE__*/ new Vector3(); - this.opacity = source.opacity; - this.transparent = source.transparent; + const _box$3 = /*@__PURE__*/ new Box3(); - this.blendSrc = source.blendSrc; - this.blendDst = source.blendDst; - this.blendEquation = source.blendEquation; - this.blendSrcAlpha = source.blendSrcAlpha; - this.blendDstAlpha = source.blendDstAlpha; - this.blendEquationAlpha = source.blendEquationAlpha; + // triangle centered vertices - this.depthFunc = source.depthFunc; - this.depthTest = source.depthTest; - this.depthWrite = source.depthWrite; + const _v0$2 = /*@__PURE__*/ new Vector3(); + const _v1$7 = /*@__PURE__*/ new Vector3(); + const _v2$3 = /*@__PURE__*/ new Vector3(); - this.stencilWriteMask = source.stencilWriteMask; - this.stencilFunc = source.stencilFunc; - this.stencilRef = source.stencilRef; - this.stencilFuncMask = source.stencilFuncMask; - this.stencilFail = source.stencilFail; - this.stencilZFail = source.stencilZFail; - this.stencilZPass = source.stencilZPass; - this.stencilWrite = source.stencilWrite; + // triangle edge vectors - const srcPlanes = source.clippingPlanes; - let dstPlanes = null; + const _f0 = /*@__PURE__*/ new Vector3(); + const _f1 = /*@__PURE__*/ new Vector3(); + const _f2 = /*@__PURE__*/ new Vector3(); - if ( srcPlanes !== null ) { + const _center = /*@__PURE__*/ new Vector3(); + const _extents = /*@__PURE__*/ new Vector3(); + const _triangleNormal = /*@__PURE__*/ new Vector3(); + const _testAxis = /*@__PURE__*/ new Vector3(); - const n = srcPlanes.length; - dstPlanes = new Array( n ); + function satForAxes( axes, v0, v1, v2, extents ) { - for ( let i = 0; i !== n; ++ i ) { + for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { - dstPlanes[ i ] = srcPlanes[ i ].clone(); + _testAxis.fromArray( axes, i ); + // project the aabb onto the separating axis + const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); + // project all 3 vertices of the triangle onto the separating axis + const p0 = v0.dot( _testAxis ); + const p1 = v1.dot( _testAxis ); + const p2 = v2.dot( _testAxis ); + // actual test, basically see if either of the most extreme of the triangle points intersects r + if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { - } + // points of the projected triangle are outside the projected half-length of the aabb + // the axis is separating and we can exit + return false; } - this.clippingPlanes = dstPlanes; - this.clipIntersection = source.clipIntersection; - this.clipShadows = source.clipShadows; + } - this.shadowSide = source.shadowSide; + return true; - this.colorWrite = source.colorWrite; + } - this.precision = source.precision; + const _box$2 = /*@__PURE__*/ new Box3(); + const _v1$6 = /*@__PURE__*/ new Vector3(); + const _toFarthestPoint = /*@__PURE__*/ new Vector3(); + const _toPoint = /*@__PURE__*/ new Vector3(); - this.polygonOffset = source.polygonOffset; - this.polygonOffsetFactor = source.polygonOffsetFactor; - this.polygonOffsetUnits = source.polygonOffsetUnits; + class Sphere { - this.dithering = source.dithering; + constructor( center = new Vector3(), radius = - 1 ) { - this.alphaTest = source.alphaTest; - this.alphaToCoverage = source.alphaToCoverage; - this.premultipliedAlpha = source.premultipliedAlpha; + this.center = center; + this.radius = radius; - this.visible = source.visible; + } - this.toneMapped = source.toneMapped; + set( center, radius ) { - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + this.center.copy( center ); + this.radius = radius; return this; } - dispose() { + setFromPoints( points, optionalCenter ) { - this.dispatchEvent( { type: 'dispose' } ); + const center = this.center; - } + if ( optionalCenter !== undefined ) { - set needsUpdate( value ) { + center.copy( optionalCenter ); - if ( value === true ) this.version ++; + } else { - } + _box$2.setFromPoints( points ).getCenter( center ); - } + } - class MeshBasicMaterial extends Material { + let maxRadiusSq = 0; - constructor( parameters ) { + for ( let i = 0, il = points.length; i < il; i ++ ) { - super(); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - this.isMeshBasicMaterial = true; + } - this.type = 'MeshBasicMaterial'; + this.radius = Math.sqrt( maxRadiusSq ); - this.color = new Color( 0xffffff ); // emissive + return this; - this.map = null; + } - this.lightMap = null; - this.lightMapIntensity = 1.0; + copy( sphere ) { - this.aoMap = null; - this.aoMapIntensity = 1.0; + this.center.copy( sphere.center ); + this.radius = sphere.radius; - this.specularMap = null; + return this; - this.alphaMap = null; + } - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + isEmpty() { - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + return ( this.radius < 0 ); - this.fog = true; + } - this.setValues( parameters ); + makeEmpty() { + + this.center.set( 0, 0, 0 ); + this.radius = - 1; + + return this; } - copy( source ) { + containsPoint( point ) { - super.copy( source ); + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - this.color.copy( source.color ); + } - this.map = source.map; + distanceToPoint( point ) { - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + return ( point.distanceTo( this.center ) - this.radius ); - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + } - this.specularMap = source.specularMap; + intersectsSphere( sphere ) { - this.alphaMap = source.alphaMap; + const radiusSum = this.radius + sphere.radius; - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + } - this.fog = source.fog; + intersectsBox( box ) { - return this; + return box.intersectsSphere( this ); } - } + intersectsPlane( plane ) { - const _vector$9 = /*@__PURE__*/ new Vector3(); - const _vector2$1 = /*@__PURE__*/ new Vector2(); + return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; - class BufferAttribute { + } - constructor( array, itemSize, normalized ) { + clampPoint( point, target ) { - if ( Array.isArray( array ) ) { + const deltaLengthSq = this.center.distanceToSquared( point ); - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + target.copy( point ); - } + if ( deltaLengthSq > ( this.radius * this.radius ) ) { - this.isBufferAttribute = true; + target.sub( this.center ).normalize(); + target.multiplyScalar( this.radius ).add( this.center ); - this.name = ''; + } - this.array = array; - this.itemSize = itemSize; - this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; + return target; - this.usage = StaticDrawUsage; - this.updateRange = { offset: 0, count: - 1 }; + } - this.version = 0; + getBoundingBox( target ) { - } + if ( this.isEmpty() ) { - onUploadCallback() {} + // Empty sphere produces empty bounding box + target.makeEmpty(); + return target; - set needsUpdate( value ) { + } - if ( value === true ) this.version ++; + target.set( this.center, this.center ); + target.expandByScalar( this.radius ); + + return target; } - setUsage( value ) { + applyMatrix4( matrix ) { - this.usage = value; + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); return this; } - copy( source ) { - - this.name = source.name; - this.array = new source.array.constructor( source.array ); - this.itemSize = source.itemSize; - this.count = source.count; - this.normalized = source.normalized; + translate( offset ) { - this.usage = source.usage; + this.center.add( offset ); return this; } - copyAt( index1, attribute, index2 ) { + expandByPoint( point ) { - index1 *= this.itemSize; - index2 *= attribute.itemSize; + if ( this.isEmpty() ) { - for ( let i = 0, l = this.itemSize; i < l; i ++ ) { + this.center.copy( point ); + this.radius = 0; - this.array[ index1 + i ] = attribute.array[ index2 + i ]; + return this; } - return this; - - } + // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L649-L671 - copyArray( array ) { + _toPoint.subVectors( point, this.center ); - this.array.set( array ); + const lengthSq = _toPoint.lengthSq(); - return this; + if ( lengthSq > ( this.radius * this.radius ) ) { - } + const length = Math.sqrt( lengthSq ); + const missingRadiusHalf = ( length - this.radius ) * 0.5; - applyMatrix3( m ) { + // Nudge this sphere towards the target point. Add half the missing distance to radius, + // and the other half to position. This gives a tighter enclosure, instead of if + // the whole missing distance were just added to radius. - if ( this.itemSize === 2 ) { + this.center.add( _toPoint.multiplyScalar( missingRadiusHalf / length ) ); + this.radius += missingRadiusHalf; - for ( let i = 0, l = this.count; i < l; i ++ ) { + } - _vector2$1.fromBufferAttribute( this, i ); - _vector2$1.applyMatrix3( m ); + return this; - this.setXY( i, _vector2$1.x, _vector2$1.y ); + } - } + union( sphere ) { - } else if ( this.itemSize === 3 ) { + // handle empty sphere cases + if ( sphere.isEmpty() ) { - for ( let i = 0, l = this.count; i < l; i ++ ) { + return this; - _vector$9.fromBufferAttribute( this, i ); - _vector$9.applyMatrix3( m ); + } else if ( this.isEmpty() ) { - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + this.copy( sphere ); - } + return this; } - return this; + // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L759-L769 - } + // To enclose another sphere into this sphere, we only need to enclose two points: + // 1) Enclose the farthest point on the other sphere into this sphere. + // 2) Enclose the opposite point of the farthest point into this sphere. - applyMatrix4( m ) { + if ( this.center.equals( sphere.center ) === true ) { - for ( let i = 0, l = this.count; i < l; i ++ ) { + _toFarthestPoint.set( 0, 0, 1 ).multiplyScalar( sphere.radius ); - _vector$9.fromBufferAttribute( this, i ); - _vector$9.applyMatrix4( m ); + } else { - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + _toFarthestPoint.subVectors( sphere.center, this.center ).normalize().multiplyScalar( sphere.radius ); } + this.expandByPoint( _v1$6.copy( sphere.center ).add( _toFarthestPoint ) ); + this.expandByPoint( _v1$6.copy( sphere.center ).sub( _toFarthestPoint ) ); + return this; } - applyNormalMatrix( m ) { + equals( sphere ) { - for ( let i = 0, l = this.count; i < l; i ++ ) { + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - _vector$9.fromBufferAttribute( this, i ); + } - _vector$9.applyNormalMatrix( m ); + clone() { - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + return new this.constructor().copy( this ); - } + } - return this; + } - } + const _vector$a = /*@__PURE__*/ new Vector3(); + const _segCenter = /*@__PURE__*/ new Vector3(); + const _segDir = /*@__PURE__*/ new Vector3(); + const _diff = /*@__PURE__*/ new Vector3(); - transformDirection( m ) { + const _edge1 = /*@__PURE__*/ new Vector3(); + const _edge2 = /*@__PURE__*/ new Vector3(); + const _normal$1 = /*@__PURE__*/ new Vector3(); - for ( let i = 0, l = this.count; i < l; i ++ ) { + class Ray { - _vector$9.fromBufferAttribute( this, i ); + constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { - _vector$9.transformDirection( m ); + this.origin = origin; + this.direction = direction; - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); + } - } + set( origin, direction ) { + + this.origin.copy( origin ); + this.direction.copy( direction ); return this; } - set( value, offset = 0 ) { + copy( ray ) { - // Matching BufferAttribute constructor, do not normalize the array. - this.array.set( value, offset ); + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); return this; } - getX( index ) { - - let x = this.array[ index * this.itemSize ]; - - if ( this.normalized ) x = denormalize( x, this.array ); + at( t, target ) { - return x; + return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); } - setX( index, x ) { - - if ( this.normalized ) x = normalize( x, this.array ); + lookAt( v ) { - this.array[ index * this.itemSize ] = x; + this.direction.copy( v ).sub( this.origin ).normalize(); return this; } - getY( index ) { - - let y = this.array[ index * this.itemSize + 1 ]; + recast( t ) { - if ( this.normalized ) y = denormalize( y, this.array ); + this.origin.copy( this.at( t, _vector$a ) ); - return y; + return this; } - setY( index, y ) { + closestPointToPoint( point, target ) { - if ( this.normalized ) y = normalize( y, this.array ); + target.subVectors( point, this.origin ); - this.array[ index * this.itemSize + 1 ] = y; + const directionDistance = target.dot( this.direction ); - return this; + if ( directionDistance < 0 ) { - } + return target.copy( this.origin ); - getZ( index ) { + } - let z = this.array[ index * this.itemSize + 2 ]; + return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - if ( this.normalized ) z = denormalize( z, this.array ); + } - return z; + distanceToPoint( point ) { - } + return Math.sqrt( this.distanceSqToPoint( point ) ); - setZ( index, z ) { + } - if ( this.normalized ) z = normalize( z, this.array ); + distanceSqToPoint( point ) { - this.array[ index * this.itemSize + 2 ] = z; + const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); - return this; + // point behind the ray - } + if ( directionDistance < 0 ) { - getW( index ) { + return this.origin.distanceToSquared( point ); - let w = this.array[ index * this.itemSize + 3 ]; + } - if ( this.normalized ) w = denormalize( w, this.array ); + _vector$a.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - return w; + return _vector$a.distanceToSquared( point ); } - setW( index, w ) { - - if ( this.normalized ) w = normalize( w, this.array ); + distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - this.array[ index * this.itemSize + 3 ] = w; + // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h + // It returns the min distance between the ray and the segment + // defined by v0 and v1 + // It can also set two optional targets : + // - The closest point on the ray + // - The closest point on the segment - return this; + _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + _segDir.copy( v1 ).sub( v0 ).normalize(); + _diff.copy( this.origin ).sub( _segCenter ); - } + const segExtent = v0.distanceTo( v1 ) * 0.5; + const a01 = - this.direction.dot( _segDir ); + const b0 = _diff.dot( this.direction ); + const b1 = - _diff.dot( _segDir ); + const c = _diff.lengthSq(); + const det = Math.abs( 1 - a01 * a01 ); + let s0, s1, sqrDist, extDet; - setXY( index, x, y ) { + if ( det > 0 ) { - index *= this.itemSize; + // The ray and segment are not parallel. - if ( this.normalized ) { + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - x = normalize( x, this.array ); - y = normalize( y, this.array ); + if ( s0 >= 0 ) { - } + if ( s1 >= - extDet ) { - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; + if ( s1 <= extDet ) { - return this; + // region 0 + // Minimum at interior points of ray and segment. - } + const invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - setXYZ( index, x, y, z ) { + } else { - index *= this.itemSize; + // region 1 - if ( this.normalized ) { + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); + } - } + } else { - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; + // region 5 - return this; + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } + } - setXYZW( index, x, y, z, w ) { + } else { - index *= this.itemSize; + if ( s1 <= - extDet ) { - if ( this.normalized ) { + // region 4 - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } + } else if ( s1 <= extDet ) { - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; + // region 3 - return this; + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - } + } else { - onUpload( callback ) { + // region 2 - this.onUploadCallback = callback; + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - return this; + } - } + } - clone() { + } else { - return new this.constructor( this.array, this.itemSize ).copy( this ); + // Ray and segment are parallel. - } + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - toJSON() { + } - const data = { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: Array.from( this.array ), - normalized: this.normalized - }; + if ( optionalPointOnRay ) { - if ( this.name !== '' ) data.name = this.name; - if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; - if ( this.updateRange.offset !== 0 || this.updateRange.count !== - 1 ) data.updateRange = this.updateRange; + optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); - return data; + } - } + if ( optionalPointOnSegment ) { - // @deprecated + optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter ); - copyColorsArray() { + } - console.error( 'THREE.BufferAttribute: copyColorsArray() was removed in r144.' ); + return sqrDist; } - copyVector2sArray() { + intersectSphere( sphere, target ) { - console.error( 'THREE.BufferAttribute: copyVector2sArray() was removed in r144.' ); + _vector$a.subVectors( sphere.center, this.origin ); + const tca = _vector$a.dot( this.direction ); + const d2 = _vector$a.dot( _vector$a ) - tca * tca; + const radius2 = sphere.radius * sphere.radius; - } + if ( d2 > radius2 ) return null; - copyVector3sArray() { + const thc = Math.sqrt( radius2 - d2 ); - console.error( 'THREE.BufferAttribute: copyVector3sArray() was removed in r144.' ); + // t0 = first intersect point - entrance on front of sphere + const t0 = tca - thc; - } + // t1 = second intersect point - exit point on back of sphere + const t1 = tca + thc; - copyVector4sArray() { + // test to see if both t0 and t1 are behind the ray - if so, return null + if ( t0 < 0 && t1 < 0 ) return null; - console.error( 'THREE.BufferAttribute: copyVector4sArray() was removed in r144.' ); + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, target ); + + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, target ); } - } + intersectsSphere( sphere ) { - // + return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); - class Int8BufferAttribute extends BufferAttribute { + } - constructor( array, itemSize, normalized ) { + distanceToPlane( plane ) { - super( new Int8Array( array ), itemSize, normalized ); + const denominator = plane.normal.dot( this.direction ); - } + if ( denominator === 0 ) { - } + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { - class Uint8BufferAttribute extends BufferAttribute { + return 0; - constructor( array, itemSize, normalized ) { + } - super( new Uint8Array( array ), itemSize, normalized ); + // Null is preferable to undefined since undefined means.... it is undefined - } + return null; - } + } - class Uint8ClampedBufferAttribute extends BufferAttribute { + const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - constructor( array, itemSize, normalized ) { + // Return if the ray never intersects the plane - super( new Uint8ClampedArray( array ), itemSize, normalized ); + return t >= 0 ? t : null; } - } + intersectPlane( plane, target ) { - class Int16BufferAttribute extends BufferAttribute { + const t = this.distanceToPlane( plane ); - constructor( array, itemSize, normalized ) { + if ( t === null ) { - super( new Int16Array( array ), itemSize, normalized ); + return null; - } + } - } + return this.at( t, target ); - class Uint16BufferAttribute extends BufferAttribute { + } - constructor( array, itemSize, normalized ) { + intersectsPlane( plane ) { - super( new Uint16Array( array ), itemSize, normalized ); + // check if the ray lies on the plane first - } + const distToPoint = plane.distanceToPoint( this.origin ); - } + if ( distToPoint === 0 ) { - class Int32BufferAttribute extends BufferAttribute { + return true; - constructor( array, itemSize, normalized ) { + } - super( new Int32Array( array ), itemSize, normalized ); + const denominator = plane.normal.dot( this.direction ); - } + if ( denominator * distToPoint < 0 ) { - } + return true; - class Uint32BufferAttribute extends BufferAttribute { + } - constructor( array, itemSize, normalized ) { + // ray origin is behind the plane (and is pointing behind it) - super( new Uint32Array( array ), itemSize, normalized ); + return false; } - } + intersectBox( box, target ) { - class Float16BufferAttribute extends BufferAttribute { + let tmin, tmax, tymin, tymax, tzmin, tzmax; - constructor( array, itemSize, normalized ) { + const invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - super( new Uint16Array( array ), itemSize, normalized ); + const origin = this.origin; - this.isFloat16BufferAttribute = true; + if ( invdirx >= 0 ) { - } + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - } + } else { + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; - class Float32BufferAttribute extends BufferAttribute { + } - constructor( array, itemSize, normalized ) { + if ( invdiry >= 0 ) { - super( new Float32Array( array ), itemSize, normalized ); + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - } + } else { - } + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; - class Float64BufferAttribute extends BufferAttribute { + } - constructor( array, itemSize, normalized ) { + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - super( new Float64Array( array ), itemSize, normalized ); + // These lines also handle the case where tmin or tmax is NaN + // (result of 0 * Infinity). x !== x returns true if x is NaN - } + if ( tymin > tmin || tmin !== tmin ) tmin = tymin; - } + if ( tymax < tmax || tmax !== tmax ) tmax = tymax; - let _id$1 = 0; + if ( invdirz >= 0 ) { - const _m1 = /*@__PURE__*/ new Matrix4(); - const _obj = /*@__PURE__*/ new Object3D(); - const _offset = /*@__PURE__*/ new Vector3(); - const _box$1 = /*@__PURE__*/ new Box3(); - const _boxMorphTargets = /*@__PURE__*/ new Box3(); - const _vector$8 = /*@__PURE__*/ new Vector3(); + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - class BufferGeometry extends EventDispatcher { + } else { - constructor() { + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; - super(); + } - this.isBufferGeometry = true; + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - Object.defineProperty( this, 'id', { value: _id$1 ++ } ); + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - this.uuid = generateUUID(); + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - this.name = ''; - this.type = 'BufferGeometry'; + //return point closest to the ray (positive side) - this.index = null; - this.attributes = {}; + if ( tmax < 0 ) return null; - this.morphAttributes = {}; - this.morphTargetsRelative = false; - - this.groups = []; - - this.boundingBox = null; - this.boundingSphere = null; - - this.drawRange = { start: 0, count: Infinity }; - - this.userData = {}; + return this.at( tmin >= 0 ? tmin : tmax, target ); } - getIndex() { + intersectsBox( box ) { - return this.index; + return this.intersectBox( box, _vector$a ) !== null; } - setIndex( index ) { - - if ( Array.isArray( index ) ) { + intersectTriangle( a, b, c, backfaceCulling, target ) { - this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); + // Compute the offset origin, edges, and normal. - } else { + // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - this.index = index; + _edge1.subVectors( b, a ); + _edge2.subVectors( c, a ); + _normal$1.crossVectors( _edge1, _edge2 ); - } + // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, + // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by + // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) + // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) + // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) + let DdN = this.direction.dot( _normal$1 ); + let sign; - return this; + if ( DdN > 0 ) { - } + if ( backfaceCulling ) return null; + sign = 1; - getAttribute( name ) { + } else if ( DdN < 0 ) { - return this.attributes[ name ]; + sign = - 1; + DdN = - DdN; - } + } else { - setAttribute( name, attribute ) { + return null; - this.attributes[ name ] = attribute; + } - return this; + _diff.subVectors( this.origin, a ); + const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - } + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { - deleteAttribute( name ) { + return null; - delete this.attributes[ name ]; + } - return this; + const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - } + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { - hasAttribute( name ) { + return null; - return this.attributes[ name ] !== undefined; + } - } + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - addGroup( start, count, materialIndex = 0 ) { + return null; - this.groups.push( { + } - start: start, - count: count, - materialIndex: materialIndex + // Line intersects triangle, check if ray does. + const QdN = - sign * _diff.dot( _normal$1 ); - } ); + // t < 0, no intersection + if ( QdN < 0 ) { - } + return null; - clearGroups() { + } - this.groups = []; + // Ray intersects triangle. + return this.at( QdN / DdN, target ); } - setDrawRange( start, count ) { + applyMatrix4( matrix4 ) { - this.drawRange.start = start; - this.drawRange.count = count; + this.origin.applyMatrix4( matrix4 ); + this.direction.transformDirection( matrix4 ); + + return this; } - applyMatrix4( matrix ) { + equals( ray ) { - const position = this.attributes.position; + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - if ( position !== undefined ) { + } - position.applyMatrix4( matrix ); + clone() { - position.needsUpdate = true; + return new this.constructor().copy( this ); - } + } - const normal = this.attributes.normal; + } - if ( normal !== undefined ) { + class Matrix4 { - const normalMatrix = new Matrix3().getNormalMatrix( matrix ); + constructor() { - normal.applyNormalMatrix( normalMatrix ); + Matrix4.prototype.isMatrix4 = true; - normal.needsUpdate = true; + this.elements = [ - } + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - const tangent = this.attributes.tangent; + ]; - if ( tangent !== undefined ) { + } - tangent.transformDirection( matrix ); + set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - tangent.needsUpdate = true; + const te = this.elements; - } + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - if ( this.boundingBox !== null ) { + return this; - this.computeBoundingBox(); + } - } + identity() { - if ( this.boundingSphere !== null ) { + this.set( - this.computeBoundingSphere(); + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - } + ); return this; } - applyQuaternion( q ) { - - _m1.makeRotationFromQuaternion( q ); - - this.applyMatrix4( _m1 ); + clone() { - return this; + return new Matrix4().fromArray( this.elements ); } - rotateX( angle ) { - - // rotate geometry around world x-axis + copy( m ) { - _m1.makeRotationX( angle ); + const te = this.elements; + const me = m.elements; - this.applyMatrix4( _m1 ); + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; + te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; + te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; + te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; return this; } - rotateY( angle ) { - - // rotate geometry around world y-axis + copyPosition( m ) { - _m1.makeRotationY( angle ); + const te = this.elements, me = m.elements; - this.applyMatrix4( _m1 ); + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; return this; } - rotateZ( angle ) { + setFromMatrix3( m ) { - // rotate geometry around world z-axis + const me = m.elements; - _m1.makeRotationZ( angle ); + this.set( - this.applyMatrix4( _m1 ); + me[ 0 ], me[ 3 ], me[ 6 ], 0, + me[ 1 ], me[ 4 ], me[ 7 ], 0, + me[ 2 ], me[ 5 ], me[ 8 ], 0, + 0, 0, 0, 1 + + ); return this; } - translate( x, y, z ) { - - // translate geometry - - _m1.makeTranslation( x, y, z ); + extractBasis( xAxis, yAxis, zAxis ) { - this.applyMatrix4( _m1 ); + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); + zAxis.setFromMatrixColumn( this, 2 ); return this; } - scale( x, y, z ) { - - // scale geometry - - _m1.makeScale( x, y, z ); + makeBasis( xAxis, yAxis, zAxis ) { - this.applyMatrix4( _m1 ); + this.set( + xAxis.x, yAxis.x, zAxis.x, 0, + xAxis.y, yAxis.y, zAxis.y, 0, + xAxis.z, yAxis.z, zAxis.z, 0, + 0, 0, 0, 1 + ); return this; } - lookAt( vector ) { - - _obj.lookAt( vector ); - - _obj.updateMatrix(); + extractRotation( m ) { - this.applyMatrix4( _obj.matrix ); + // this method does not support reflection matrices - return this; + const te = this.elements; + const me = m.elements; - } + const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); + const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); + const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); - center() { + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; + te[ 3 ] = 0; - this.computeBoundingBox(); + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; + te[ 7 ] = 0; - this.boundingBox.getCenter( _offset ).negate(); + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; + te[ 11 ] = 0; - this.translate( _offset.x, _offset.y, _offset.z ); + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; return this; } - setFromPoints( points ) { - - const position = []; + makeRotationFromEuler( euler ) { - for ( let i = 0, l = points.length; i < l; i ++ ) { + const te = this.elements; - const point = points[ i ]; - position.push( point.x, point.y, point.z || 0 ); + const x = euler.x, y = euler.y, z = euler.z; + const a = Math.cos( x ), b = Math.sin( x ); + const c = Math.cos( y ), d = Math.sin( y ); + const e = Math.cos( z ), f = Math.sin( z ); - } + if ( euler.order === 'XYZ' ) { - this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); + const ae = a * e, af = a * f, be = b * e, bf = b * f; - return this; + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - } + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; - computeBoundingBox() { + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; - if ( this.boundingBox === null ) { + } else if ( euler.order === 'YXZ' ) { - this.boundingBox = new Box3(); + const ce = c * e, cf = c * f, de = d * e, df = d * f; - } + te[ 0 ] = ce + df * b; + te[ 4 ] = de * b - cf; + te[ 8 ] = a * d; - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; + te[ 1 ] = a * f; + te[ 5 ] = a * e; + te[ 9 ] = - b; - if ( position && position.isGLBufferAttribute ) { + te[ 2 ] = cf * b - de; + te[ 6 ] = df + ce * b; + te[ 10 ] = a * c; - console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this ); + } else if ( euler.order === 'ZXY' ) { - this.boundingBox.set( - new Vector3( - Infinity, - Infinity, - Infinity ), - new Vector3( + Infinity, + Infinity, + Infinity ) - ); + const ce = c * e, cf = c * f, de = d * e, df = d * f; - return; + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; - } + te[ 1 ] = cf + de * b; + te[ 5 ] = a * e; + te[ 9 ] = df - ce * b; - if ( position !== undefined ) { + te[ 2 ] = - a * d; + te[ 6 ] = b; + te[ 10 ] = a * c; - this.boundingBox.setFromBufferAttribute( position ); + } else if ( euler.order === 'ZYX' ) { - // process morph attributes if present + const ae = a * e, af = a * f, be = b * e, bf = b * f; - if ( morphAttributesPosition ) { + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; - const morphAttribute = morphAttributesPosition[ i ]; - _box$1.setFromBufferAttribute( morphAttribute ); + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; - if ( this.morphTargetsRelative ) { + } else if ( euler.order === 'YZX' ) { - _vector$8.addVectors( this.boundingBox.min, _box$1.min ); - this.boundingBox.expandByPoint( _vector$8 ); + const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - _vector$8.addVectors( this.boundingBox.max, _box$1.max ); - this.boundingBox.expandByPoint( _vector$8 ); + te[ 0 ] = c * e; + te[ 4 ] = bd - ac * f; + te[ 8 ] = bc * f + ad; - } else { + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - this.boundingBox.expandByPoint( _box$1.min ); - this.boundingBox.expandByPoint( _box$1.max ); + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; - } + } else if ( euler.order === 'XZY' ) { - } + const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - } + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - } else { + te[ 1 ] = ac * f + bd; + te[ 5 ] = a * e; + te[ 9 ] = ad * f - bc; - this.boundingBox.makeEmpty(); + te[ 2 ] = bc * f - ad; + te[ 6 ] = b * e; + te[ 10 ] = bd * f + ac; } - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { + // bottom row + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); + // last column + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - } + return this; } - computeBoundingSphere() { + makeRotationFromQuaternion( q ) { - if ( this.boundingSphere === null ) { + return this.compose( _zero, q, _one ); - this.boundingSphere = new Sphere(); + } - } + lookAt( eye, target, up ) { - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; + const te = this.elements; - if ( position && position.isGLBufferAttribute ) { + _z.subVectors( eye, target ); - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this ); + if ( _z.lengthSq() === 0 ) { - this.boundingSphere.set( new Vector3(), Infinity ); + // eye and target are in the same position - return; + _z.z = 1; } - if ( position ) { + _z.normalize(); + _x.crossVectors( up, _z ); - // first, find the center of the bounding sphere + if ( _x.lengthSq() === 0 ) { - const center = this.boundingSphere.center; + // up and z are parallel - _box$1.setFromBufferAttribute( position ); + if ( Math.abs( up.z ) === 1 ) { - // process morph attributes if present + _z.x += 0.0001; - if ( morphAttributesPosition ) { + } else { - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { + _z.z += 0.0001; - const morphAttribute = morphAttributesPosition[ i ]; - _boxMorphTargets.setFromBufferAttribute( morphAttribute ); + } - if ( this.morphTargetsRelative ) { + _z.normalize(); + _x.crossVectors( up, _z ); - _vector$8.addVectors( _box$1.min, _boxMorphTargets.min ); - _box$1.expandByPoint( _vector$8 ); + } - _vector$8.addVectors( _box$1.max, _boxMorphTargets.max ); - _box$1.expandByPoint( _vector$8 ); + _x.normalize(); + _y.crossVectors( _z, _x ); - } else { + te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; + te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; + te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; - _box$1.expandByPoint( _boxMorphTargets.min ); - _box$1.expandByPoint( _boxMorphTargets.max ); + return this; - } + } - } + multiply( m ) { - } + return this.multiplyMatrices( this, m ); - _box$1.getCenter( center ); + } - // second, try to find a boundingSphere with a radius smaller than the - // boundingSphere of the boundingBox: sqrt(3) smaller in the best case + premultiply( m ) { - let maxRadiusSq = 0; + return this.multiplyMatrices( m, this ); - for ( let i = 0, il = position.count; i < il; i ++ ) { + } - _vector$8.fromBufferAttribute( position, i ); + multiplyMatrices( a, b ) { - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); + const ae = a.elements; + const be = b.elements; + const te = this.elements; - } + const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; + const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; + const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; + const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - // process morph attributes if present + const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; + const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; + const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; + const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - if ( morphAttributesPosition ) { + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - const morphAttribute = morphAttributesPosition[ i ]; - const morphTargetsRelative = this.morphTargetsRelative; + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { + te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - _vector$8.fromBufferAttribute( morphAttribute, j ); + return this; - if ( morphTargetsRelative ) { + } - _offset.fromBufferAttribute( position, j ); - _vector$8.add( _offset ); + multiplyScalar( s ) { - } + const te = this.elements; - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); + te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; + te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; + te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; + te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - } + return this; - } + } - } + determinant() { - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + const te = this.elements; - if ( isNaN( this.boundingSphere.radius ) ) { + const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; + const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; + const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; + const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - } + return ( + n41 * ( + + n14 * n23 * n32 + - n13 * n24 * n32 + - n14 * n22 * n33 + + n12 * n24 * n33 + + n13 * n22 * n34 + - n12 * n23 * n34 + ) + + n42 * ( + + n11 * n23 * n34 + - n11 * n24 * n33 + + n14 * n21 * n33 + - n13 * n21 * n34 + + n13 * n24 * n31 + - n14 * n23 * n31 + ) + + n43 * ( + + n11 * n24 * n32 + - n11 * n22 * n34 + - n14 * n21 * n32 + + n12 * n21 * n34 + + n14 * n22 * n31 + - n12 * n24 * n31 + ) + + n44 * ( + - n13 * n22 * n31 + - n11 * n23 * n32 + + n11 * n22 * n33 + + n13 * n21 * n32 + - n12 * n21 * n33 + + n12 * n23 * n31 + ) - } + ); } - computeTangents() { - - const index = this.index; - const attributes = this.attributes; - - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) - - if ( index === null || - attributes.position === undefined || - attributes.normal === undefined || - attributes.uv === undefined ) { + transpose() { - console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); - return; + const te = this.elements; + let tmp; - } + tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; + tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; + tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - const indices = index.array; - const positions = attributes.position.array; - const normals = attributes.normal.array; - const uvs = attributes.uv.array; + tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; + tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; + tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; - const nVertices = positions.length / 3; + return this; - if ( this.hasAttribute( 'tangent' ) === false ) { + } - this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); + setPosition( x, y, z ) { - } + const te = this.elements; - const tangents = this.getAttribute( 'tangent' ).array; + if ( x.isVector3 ) { - const tan1 = [], tan2 = []; + te[ 12 ] = x.x; + te[ 13 ] = x.y; + te[ 14 ] = x.z; - for ( let i = 0; i < nVertices; i ++ ) { + } else { - tan1[ i ] = new Vector3(); - tan2[ i ] = new Vector3(); + te[ 12 ] = x; + te[ 13 ] = y; + te[ 14 ] = z; } - const vA = new Vector3(), - vB = new Vector3(), - vC = new Vector3(), - - uvA = new Vector2(), - uvB = new Vector2(), - uvC = new Vector2(), + return this; - sdir = new Vector3(), - tdir = new Vector3(); + } - function handleTriangle( a, b, c ) { + invert() { - vA.fromArray( positions, a * 3 ); - vB.fromArray( positions, b * 3 ); - vC.fromArray( positions, c * 3 ); + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + const te = this.elements, - uvA.fromArray( uvs, a * 2 ); - uvB.fromArray( uvs, b * 2 ); - uvC.fromArray( uvs, c * 2 ); + n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], + n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], + n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], + n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], - vB.sub( vA ); - vC.sub( vA ); + t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, + t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, + t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, + t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; - uvB.sub( uvA ); - uvC.sub( uvA ); + const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); + if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - // silently ignore degenerate uv triangles having coincident or colinear vertices + const detInv = 1 / det; - if ( ! isFinite( r ) ) return; + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; + te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; + te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); - tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); + te[ 4 ] = t12 * detInv; + te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; + te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; + te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); + te[ 8 ] = t13 * detInv; + te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; + te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; + te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); + te[ 12 ] = t14 * detInv; + te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; + te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; + te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; - } + return this; - let groups = this.groups; + } - if ( groups.length === 0 ) { + scale( v ) { - groups = [ { - start: 0, - count: indices.length - } ]; + const te = this.elements; + const x = v.x, y = v.y, z = v.z; - } + te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; + te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; + te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; + te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; - for ( let i = 0, il = groups.length; i < il; ++ i ) { + return this; - const group = groups[ i ]; + } - const start = group.start; - const count = group.count; + getMaxScaleOnAxis() { - for ( let j = start, jl = start + count; j < jl; j += 3 ) { + const te = this.elements; - handleTriangle( - indices[ j + 0 ], - indices[ j + 1 ], - indices[ j + 2 ] - ); + const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; + const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; + const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; - } + return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); - } + } - const tmp = new Vector3(), tmp2 = new Vector3(); - const n = new Vector3(), n2 = new Vector3(); + makeTranslation( x, y, z ) { - function handleVertex( v ) { + this.set( - n.fromArray( normals, v * 3 ); - n2.copy( n ); + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 - const t = tan1[ v ]; + ); - // Gram-Schmidt orthogonalize + return this; - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + } - // Calculate handedness + makeRotationX( theta ) { - tmp2.crossVectors( n2, t ); - const test = tmp2.dot( tan2[ v ] ); - const w = ( test < 0.0 ) ? - 1.0 : 1.0; + const c = Math.cos( theta ), s = Math.sin( theta ); - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; + this.set( - } + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, + 0, 0, 0, 1 - for ( let i = 0, il = groups.length; i < il; ++ i ) { + ); - const group = groups[ i ]; + return this; - const start = group.start; - const count = group.count; + } - for ( let j = start, jl = start + count; j < jl; j += 3 ) { + makeRotationY( theta ) { - handleVertex( indices[ j + 0 ] ); - handleVertex( indices[ j + 1 ] ); - handleVertex( indices[ j + 2 ] ); + const c = Math.cos( theta ), s = Math.sin( theta ); - } + this.set( - } + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 - } + ); - computeVertexNormals() { + return this; - const index = this.index; - const positionAttribute = this.getAttribute( 'position' ); + } - if ( positionAttribute !== undefined ) { + makeRotationZ( theta ) { - let normalAttribute = this.getAttribute( 'normal' ); + const c = Math.cos( theta ), s = Math.sin( theta ); - if ( normalAttribute === undefined ) { + this.set( - normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); - this.setAttribute( 'normal', normalAttribute ); + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - } else { + ); - // reset existing normals to zero + return this; - for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { + } - normalAttribute.setXYZ( i, 0, 0, 0 ); + makeRotationAxis( axis, angle ) { - } + // Based on http://www.gamedev.net/reference/articles/article1199.asp - } + const c = Math.cos( angle ); + const s = Math.sin( angle ); + const t = 1 - c; + const x = axis.x, y = axis.y, z = axis.z; + const tx = t * x, ty = t * y; - const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); - const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); - const cb = new Vector3(), ab = new Vector3(); + this.set( - // indexed elements + tx * x + c, tx * y - s * z, tx * z + s * y, 0, + tx * y + s * z, ty * y + c, ty * z - s * x, 0, + tx * z - s * y, ty * z + s * x, t * z * z + c, 0, + 0, 0, 0, 1 - if ( index ) { + ); - for ( let i = 0, il = index.count; i < il; i += 3 ) { + return this; - const vA = index.getX( i + 0 ); - const vB = index.getX( i + 1 ); - const vC = index.getX( i + 2 ); + } - pA.fromBufferAttribute( positionAttribute, vA ); - pB.fromBufferAttribute( positionAttribute, vB ); - pC.fromBufferAttribute( positionAttribute, vC ); + makeScale( x, y, z ) { - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + this.set( - nA.fromBufferAttribute( normalAttribute, vA ); - nB.fromBufferAttribute( normalAttribute, vB ); - nC.fromBufferAttribute( normalAttribute, vC ); + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 - nA.add( cb ); - nB.add( cb ); - nC.add( cb ); + ); - normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); - normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); - normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); + return this; - } + } - } else { + makeShear( xy, xz, yx, yz, zx, zy ) { - // non-indexed elements (unconnected triangle soup) + this.set( - for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { + 1, yx, zx, 0, + xy, 1, zy, 0, + xz, yz, 1, 0, + 0, 0, 0, 1 - pA.fromBufferAttribute( positionAttribute, i + 0 ); - pB.fromBufferAttribute( positionAttribute, i + 1 ); - pC.fromBufferAttribute( positionAttribute, i + 2 ); + ); - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + return this; - normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); + } - } + compose( position, quaternion, scale ) { - } + const te = this.elements; - this.normalizeNormals(); + const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; + const x2 = x + x, y2 = y + y, z2 = z + z; + const xx = x * x2, xy = x * y2, xz = x * z2; + const yy = y * y2, yz = y * z2, zz = z * z2; + const wx = w * x2, wy = w * y2, wz = w * z2; - normalAttribute.needsUpdate = true; + const sx = scale.x, sy = scale.y, sz = scale.z; - } + te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; + te[ 1 ] = ( xy + wz ) * sx; + te[ 2 ] = ( xz - wy ) * sx; + te[ 3 ] = 0; - } + te[ 4 ] = ( xy - wz ) * sy; + te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; + te[ 6 ] = ( yz + wx ) * sy; + te[ 7 ] = 0; - // @deprecated since r144 + te[ 8 ] = ( xz + wy ) * sz; + te[ 9 ] = ( yz - wx ) * sz; + te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; + te[ 11 ] = 0; - merge() { + te[ 12 ] = position.x; + te[ 13 ] = position.y; + te[ 14 ] = position.z; + te[ 15 ] = 1; - console.error( 'THREE.BufferGeometry.merge() has been removed. Use THREE.BufferGeometryUtils.mergeBufferGeometries() instead.' ); return this; } - normalizeNormals() { + decompose( position, quaternion, scale ) { - const normals = this.attributes.normal; + const te = this.elements; - for ( let i = 0, il = normals.count; i < il; i ++ ) { + let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - _vector$8.fromBufferAttribute( normals, i ); + // if determine is negative, we need to invert one scale + const det = this.determinant(); + if ( det < 0 ) sx = - sx; - _vector$8.normalize(); + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; - normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); + // scale the rotation part + _m1$2.copy( this ); - } + const invSX = 1 / sx; + const invSY = 1 / sy; + const invSZ = 1 / sz; - } + _m1$2.elements[ 0 ] *= invSX; + _m1$2.elements[ 1 ] *= invSX; + _m1$2.elements[ 2 ] *= invSX; - toNonIndexed() { + _m1$2.elements[ 4 ] *= invSY; + _m1$2.elements[ 5 ] *= invSY; + _m1$2.elements[ 6 ] *= invSY; - function convertBufferAttribute( attribute, indices ) { + _m1$2.elements[ 8 ] *= invSZ; + _m1$2.elements[ 9 ] *= invSZ; + _m1$2.elements[ 10 ] *= invSZ; - const array = attribute.array; - const itemSize = attribute.itemSize; - const normalized = attribute.normalized; + quaternion.setFromRotationMatrix( _m1$2 ); - const array2 = new array.constructor( indices.length * itemSize ); + scale.x = sx; + scale.y = sy; + scale.z = sz; - let index = 0, index2 = 0; + return this; - for ( let i = 0, l = indices.length; i < l; i ++ ) { + } - if ( attribute.isInterleavedBufferAttribute ) { + makePerspective( left, right, top, bottom, near, far ) { - index = indices[ i ] * attribute.data.stride + attribute.offset; + const te = this.elements; + const x = 2 * near / ( right - left ); + const y = 2 * near / ( top - bottom ); - } else { + const a = ( right + left ) / ( right - left ); + const b = ( top + bottom ) / ( top - bottom ); + const c = - ( far + near ) / ( far - near ); + const d = - 2 * far * near / ( far - near ); - index = indices[ i ] * itemSize; + te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; + te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - } + return this; - for ( let j = 0; j < itemSize; j ++ ) { + } - array2[ index2 ++ ] = array[ index ++ ]; + makeOrthographic( left, right, top, bottom, near, far ) { - } + const te = this.elements; + const w = 1.0 / ( right - left ); + const h = 1.0 / ( top - bottom ); + const p = 1.0 / ( far - near ); - } + const x = ( right + left ) * w; + const y = ( top + bottom ) * h; + const z = ( far + near ) * p; - return new BufferAttribute( array2, itemSize, normalized ); + te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; + te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; - } + return this; - // + } - if ( this.index === null ) { + equals( matrix ) { - console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); - return this; + const te = this.elements; + const me = matrix.elements; - } + for ( let i = 0; i < 16; i ++ ) { - const geometry2 = new BufferGeometry(); + if ( te[ i ] !== me[ i ] ) return false; - const indices = this.index.array; - const attributes = this.attributes; + } - // attributes + return true; - for ( const name in attributes ) { + } - const attribute = attributes[ name ]; + fromArray( array, offset = 0 ) { - const newAttribute = convertBufferAttribute( attribute, indices ); + for ( let i = 0; i < 16; i ++ ) { - geometry2.setAttribute( name, newAttribute ); + this.elements[ i ] = array[ i + offset ]; } - // morph attributes - - const morphAttributes = this.morphAttributes; - - for ( const name in morphAttributes ) { + return this; - const morphArray = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes + } - for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { + toArray( array = [], offset = 0 ) { - const attribute = morphAttribute[ i ]; + const te = this.elements; - const newAttribute = convertBufferAttribute( attribute, indices ); + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - morphArray.push( newAttribute ); + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; - } + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; - geometry2.morphAttributes[ name ] = morphArray; + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; - } + return array; - geometry2.morphTargetsRelative = this.morphTargetsRelative; + } - // groups + } - const groups = this.groups; + const _v1$5 = /*@__PURE__*/ new Vector3(); + const _m1$2 = /*@__PURE__*/ new Matrix4(); + const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); + const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); + const _x = /*@__PURE__*/ new Vector3(); + const _y = /*@__PURE__*/ new Vector3(); + const _z = /*@__PURE__*/ new Vector3(); - for ( let i = 0, l = groups.length; i < l; i ++ ) { + const _matrix$1 = /*@__PURE__*/ new Matrix4(); + const _quaternion$3 = /*@__PURE__*/ new Quaternion(); - const group = groups[ i ]; - geometry2.addGroup( group.start, group.count, group.materialIndex ); + class Euler { - } + constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) { - return geometry2; + this.isEuler = true; - } + this._x = x; + this._y = y; + this._z = z; + this._order = order; - toJSON() { + } - const data = { - metadata: { - version: 4.5, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' - } - }; + get x() { - // standard BufferGeometry serialization + return this._x; - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; - if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; + } - if ( this.parameters !== undefined ) { + set x( value ) { - const parameters = this.parameters; + this._x = value; + this._onChangeCallback(); - for ( const key in parameters ) { + } - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + get y() { - } + return this._y; - return data; + } - } + set y( value ) { - // for simplicity the code assumes attributes are not shared across geometries, see #15811 + this._y = value; + this._onChangeCallback(); - data.data = { attributes: {} }; + } - const index = this.index; + get z() { - if ( index !== null ) { + return this._z; - data.data.index = { - type: index.array.constructor.name, - array: Array.prototype.slice.call( index.array ) - }; + } - } + set z( value ) { - const attributes = this.attributes; + this._z = value; + this._onChangeCallback(); - for ( const key in attributes ) { + } - const attribute = attributes[ key ]; + get order() { - data.data.attributes[ key ] = attribute.toJSON( data.data ); + return this._order; - } + } - const morphAttributes = {}; - let hasMorphAttributes = false; + set order( value ) { - for ( const key in this.morphAttributes ) { + this._order = value; + this._onChangeCallback(); - const attributeArray = this.morphAttributes[ key ]; + } - const array = []; + set( x, y, z, order = this._order ) { - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { + this._x = x; + this._y = y; + this._z = z; + this._order = order; - const attribute = attributeArray[ i ]; + this._onChangeCallback(); - array.push( attribute.toJSON( data.data ) ); + return this; - } + } - if ( array.length > 0 ) { + clone() { - morphAttributes[ key ] = array; + return new this.constructor( this._x, this._y, this._z, this._order ); - hasMorphAttributes = true; + } - } + copy( euler ) { - } + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; - if ( hasMorphAttributes ) { + this._onChangeCallback(); - data.data.morphAttributes = morphAttributes; - data.data.morphTargetsRelative = this.morphTargetsRelative; + return this; - } + } - const groups = this.groups; + setFromRotationMatrix( m, order = this._order, update = true ) { - if ( groups.length > 0 ) { + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - data.data.groups = JSON.parse( JSON.stringify( groups ) ); + const te = m.elements; + const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; + const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; + const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - } + switch ( order ) { - const boundingSphere = this.boundingSphere; + case 'XYZ': - if ( boundingSphere !== null ) { + this._y = Math.asin( clamp( m13, - 1, 1 ) ); - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - }; + if ( Math.abs( m13 ) < 0.9999999 ) { - } + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); - return data; + } else { - } + this._x = Math.atan2( m32, m22 ); + this._z = 0; - clone() { + } - return new this.constructor().copy( this ); + break; - } + case 'YXZ': - copy( source ) { + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - // reset + if ( Math.abs( m23 ) < 0.9999999 ) { - this.index = null; - this.attributes = {}; - this.morphAttributes = {}; - this.groups = []; - this.boundingBox = null; - this.boundingSphere = null; + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); - // used for storing cloned, shared data + } else { - const data = {}; + this._y = Math.atan2( - m31, m11 ); + this._z = 0; - // name + } - this.name = source.name; + break; - // index + case 'ZXY': - const index = source.index; + this._x = Math.asin( clamp( m32, - 1, 1 ) ); - if ( index !== null ) { + if ( Math.abs( m32 ) < 0.9999999 ) { - this.setIndex( index.clone( data ) ); + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); - } + } else { - // attributes + this._y = 0; + this._z = Math.atan2( m21, m11 ); - const attributes = source.attributes; + } - for ( const name in attributes ) { + break; - const attribute = attributes[ name ]; - this.setAttribute( name, attribute.clone( data ) ); + case 'ZYX': - } + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - // morph attributes + if ( Math.abs( m31 ) < 0.9999999 ) { - const morphAttributes = source.morphAttributes; + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); - for ( const name in morphAttributes ) { + } else { - const array = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes + this._x = 0; + this._z = Math.atan2( - m12, m22 ); - for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { + } - array.push( morphAttribute[ i ].clone( data ) ); + break; - } + case 'YZX': - this.morphAttributes[ name ] = array; + this._z = Math.asin( clamp( m21, - 1, 1 ) ); - } + if ( Math.abs( m21 ) < 0.9999999 ) { - this.morphTargetsRelative = source.morphTargetsRelative; + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); - // groups + } else { - const groups = source.groups; + this._x = 0; + this._y = Math.atan2( m13, m33 ); - for ( let i = 0, l = groups.length; i < l; i ++ ) { + } - const group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); + break; - } + case 'XZY': - // bounding box + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - const boundingBox = source.boundingBox; + if ( Math.abs( m12 ) < 0.9999999 ) { - if ( boundingBox !== null ) { + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); - this.boundingBox = boundingBox.clone(); + } else { - } + this._x = Math.atan2( - m23, m33 ); + this._y = 0; - // bounding sphere + } - const boundingSphere = source.boundingSphere; + break; - if ( boundingSphere !== null ) { + default: - this.boundingSphere = boundingSphere.clone(); + console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); } - // draw range + this._order = order; - this.drawRange.start = source.drawRange.start; - this.drawRange.count = source.drawRange.count; + if ( update === true ) this._onChangeCallback(); - // user data + return this; - this.userData = source.userData; + } - // geometry generator parameters + setFromQuaternion( q, order, update ) { - if ( source.parameters !== undefined ) this.parameters = Object.assign( {}, source.parameters ); + _matrix$1.makeRotationFromQuaternion( q ); - return this; + return this.setFromRotationMatrix( _matrix$1, order, update ); } - dispose() { + setFromVector3( v, order = this._order ) { - this.dispatchEvent( { type: 'dispose' } ); + return this.set( v.x, v.y, v.z, order ); } - } - - const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); - const _ray$2 = /*@__PURE__*/ new Ray(); - const _sphere$3 = /*@__PURE__*/ new Sphere(); - - const _vA$1 = /*@__PURE__*/ new Vector3(); - const _vB$1 = /*@__PURE__*/ new Vector3(); - const _vC$1 = /*@__PURE__*/ new Vector3(); + reorder( newOrder ) { - const _tempA = /*@__PURE__*/ new Vector3(); - const _tempB = /*@__PURE__*/ new Vector3(); - const _tempC = /*@__PURE__*/ new Vector3(); + // WARNING: this discards revolution information -bhouston - const _morphA = /*@__PURE__*/ new Vector3(); - const _morphB = /*@__PURE__*/ new Vector3(); - const _morphC = /*@__PURE__*/ new Vector3(); + _quaternion$3.setFromEuler( this ); - const _uvA$1 = /*@__PURE__*/ new Vector2(); - const _uvB$1 = /*@__PURE__*/ new Vector2(); - const _uvC$1 = /*@__PURE__*/ new Vector2(); + return this.setFromQuaternion( _quaternion$3, newOrder ); - const _intersectionPoint = /*@__PURE__*/ new Vector3(); - const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); + } - class Mesh extends Object3D { + equals( euler ) { - constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - super(); + } - this.isMesh = true; + fromArray( array ) { - this.type = 'Mesh'; + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - this.geometry = geometry; - this.material = material; + this._onChangeCallback(); - this.updateMorphTargets(); + return this; } - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.morphTargetInfluences !== undefined ) { - - this.morphTargetInfluences = source.morphTargetInfluences.slice(); + toArray( array = [], offset = 0 ) { - } + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; - if ( source.morphTargetDictionary !== undefined ) { + return array; - this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); + } - } + _onChange( callback ) { - this.material = source.material; - this.geometry = source.geometry; + this._onChangeCallback = callback; return this; } - updateMorphTargets() { + _onChangeCallback() {} - const geometry = this.geometry; + *[ Symbol.iterator ]() { - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); + yield this._x; + yield this._y; + yield this._z; + yield this._order; - if ( keys.length > 0 ) { + } - const morphAttribute = morphAttributes[ keys[ 0 ] ]; + // @deprecated since r138, 02cf0df1cb4575d5842fef9c85bb5a89fe020d53 - if ( morphAttribute !== undefined ) { + toVector3() { - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + console.error( 'THREE.Euler: .toVector3() has been removed. Use Vector3.setFromEuler() instead' ); - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + } - const name = morphAttribute[ m ].name || String( m ); + } - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + Euler.DefaultOrder = 'XYZ'; + Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - } + class Layers { - } + constructor() { - } + this.mask = 1 | 0; } - raycast( raycaster, intersects ) { + set( channel ) { - const geometry = this.geometry; - const material = this.material; - const matrixWorld = this.matrixWorld; + this.mask = ( 1 << channel | 0 ) >>> 0; - if ( material === undefined ) return; + } - // Checking boundingSphere distance to ray + enable( channel ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + this.mask |= 1 << channel | 0; - _sphere$3.copy( geometry.boundingSphere ); - _sphere$3.applyMatrix4( matrixWorld ); + } - if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; + enableAll() { - // + this.mask = 0xffffffff | 0; - _inverseMatrix$2.copy( matrixWorld ).invert(); - _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); + } - // Check boundingBox before continuing + toggle( channel ) { - if ( geometry.boundingBox !== null ) { + this.mask ^= 1 << channel | 0; - if ( _ray$2.intersectsBox( geometry.boundingBox ) === false ) return; + } - } + disable( channel ) { - let intersection; + this.mask &= ~ ( 1 << channel | 0 ); - const index = geometry.index; - const position = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; - const uv = geometry.attributes.uv; - const uv2 = geometry.attributes.uv2; - const groups = geometry.groups; - const drawRange = geometry.drawRange; + } - if ( index !== null ) { + disableAll() { - // indexed buffer geometry + this.mask = 0; - if ( Array.isArray( material ) ) { + } - for ( let i = 0, il = groups.length; i < il; i ++ ) { + test( layers ) { - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; + return ( this.mask & layers.mask ) !== 0; - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); + } - for ( let j = start, jl = end; j < jl; j += 3 ) { + isEnabled( channel ) { - const a = index.getX( j ); - const b = index.getX( j + 1 ); - const c = index.getX( j + 2 ); + return ( this.mask & ( 1 << channel | 0 ) ) !== 0; - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + } - if ( intersection ) { + } - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); + let _object3DId = 0; - } + const _v1$4 = /*@__PURE__*/ new Vector3(); + const _q1 = /*@__PURE__*/ new Quaternion(); + const _m1$1 = /*@__PURE__*/ new Matrix4(); + const _target = /*@__PURE__*/ new Vector3(); - } + const _position$3 = /*@__PURE__*/ new Vector3(); + const _scale$2 = /*@__PURE__*/ new Vector3(); + const _quaternion$2 = /*@__PURE__*/ new Quaternion(); - } + const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); + const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); - } else { + const _addedEvent = { type: 'added' }; + const _removedEvent = { type: 'removed' }; - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); + class Object3D extends EventDispatcher { - for ( let i = start, il = end; i < il; i += 3 ) { + constructor() { - const a = index.getX( i ); - const b = index.getX( i + 1 ); - const c = index.getX( i + 2 ); + super(); - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + this.isObject3D = true; - if ( intersection ) { + Object.defineProperty( this, 'id', { value: _object3DId ++ } ); - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics - intersects.push( intersection ); + this.uuid = generateUUID(); - } + this.name = ''; + this.type = 'Object3D'; - } + this.parent = null; + this.children = []; - } + this.up = Object3D.DefaultUp.clone(); - } else if ( position !== undefined ) { + const position = new Vector3(); + const rotation = new Euler(); + const quaternion = new Quaternion(); + const scale = new Vector3( 1, 1, 1 ); - // non-indexed buffer geometry + function onRotationChange() { - if ( Array.isArray( material ) ) { + quaternion.setFromEuler( rotation, false ); - for ( let i = 0, il = groups.length; i < il; i ++ ) { + } - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); + function onQuaternionChange() { - for ( let j = start, jl = end; j < jl; j += 3 ) { + rotation.setFromQuaternion( quaternion, undefined, false ); - const a = j; - const b = j + 1; - const c = j + 2; + } - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + rotation._onChange( onRotationChange ); + quaternion._onChange( onQuaternionChange ); - if ( intersection ) { + Object.defineProperties( this, { + position: { + configurable: true, + enumerable: true, + value: position + }, + rotation: { + configurable: true, + enumerable: true, + value: rotation + }, + quaternion: { + configurable: true, + enumerable: true, + value: quaternion + }, + scale: { + configurable: true, + enumerable: true, + value: scale + }, + modelViewMatrix: { + value: new Matrix4() + }, + normalMatrix: { + value: new Matrix3() + } + } ); - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); + this.matrix = new Matrix4(); + this.matrixWorld = new Matrix4(); - } + this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; + this.matrixWorldNeedsUpdate = false; - } + this.matrixWorldAutoUpdate = Object3D.DefaultMatrixWorldAutoUpdate; // checked by the renderer - } + this.layers = new Layers(); + this.visible = true; - } else { + this.castShadow = false; + this.receiveShadow = false; - const start = Math.max( 0, drawRange.start ); - const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); + this.frustumCulled = true; + this.renderOrder = 0; - for ( let i = start, il = end; i < il; i += 3 ) { + this.animations = []; - const a = i; - const b = i + 1; - const c = i + 2; + this.userData = {}; - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + } - if ( intersection ) { + onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics - intersects.push( intersection ); + onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} - } + applyMatrix4( matrix ) { - } + if ( this.matrixAutoUpdate ) this.updateMatrix(); - } + this.matrix.premultiply( matrix ); - } + this.matrix.decompose( this.position, this.quaternion, this.scale ); } - } + applyQuaternion( q ) { - function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { + this.quaternion.premultiply( q ); - let intersect; + return this; - if ( material.side === BackSide ) { + } - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); + setRotationFromAxisAngle( axis, angle ) { - } else { + // assumes axis is normalized - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); + this.quaternion.setFromAxisAngle( axis, angle ); } - if ( intersect === null ) return null; + setRotationFromEuler( euler ) { - _intersectionPointWorld.copy( point ); - _intersectionPointWorld.applyMatrix4( object.matrixWorld ); + this.quaternion.setFromEuler( euler, true ); - const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); + } - if ( distance < raycaster.near || distance > raycaster.far ) return null; + setRotationFromMatrix( m ) { - return { - distance: distance, - point: _intersectionPointWorld.clone(), - object: object - }; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - } + this.quaternion.setFromRotationMatrix( m ); - function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { + } - _vA$1.fromBufferAttribute( position, a ); - _vB$1.fromBufferAttribute( position, b ); - _vC$1.fromBufferAttribute( position, c ); + setRotationFromQuaternion( q ) { - const morphInfluences = object.morphTargetInfluences; + // assumes q is normalized - if ( morphPosition && morphInfluences ) { + this.quaternion.copy( q ); - _morphA.set( 0, 0, 0 ); - _morphB.set( 0, 0, 0 ); - _morphC.set( 0, 0, 0 ); + } - for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { + rotateOnAxis( axis, angle ) { - const influence = morphInfluences[ i ]; - const morphAttribute = morphPosition[ i ]; + // rotate object on axis in object space + // axis is assumed to be normalized - if ( influence === 0 ) continue; + _q1.setFromAxisAngle( axis, angle ); - _tempA.fromBufferAttribute( morphAttribute, a ); - _tempB.fromBufferAttribute( morphAttribute, b ); - _tempC.fromBufferAttribute( morphAttribute, c ); + this.quaternion.multiply( _q1 ); - if ( morphTargetsRelative ) { + return this; - _morphA.addScaledVector( _tempA, influence ); - _morphB.addScaledVector( _tempB, influence ); - _morphC.addScaledVector( _tempC, influence ); + } - } else { + rotateOnWorldAxis( axis, angle ) { - _morphA.addScaledVector( _tempA.sub( _vA$1 ), influence ); - _morphB.addScaledVector( _tempB.sub( _vB$1 ), influence ); - _morphC.addScaledVector( _tempC.sub( _vC$1 ), influence ); + // rotate object on axis in world space + // axis is assumed to be normalized + // method assumes no rotated parent - } + _q1.setFromAxisAngle( axis, angle ); - } + this.quaternion.premultiply( _q1 ); - _vA$1.add( _morphA ); - _vB$1.add( _morphB ); - _vC$1.add( _morphC ); + return this; } - if ( object.isSkinnedMesh ) { + rotateX( angle ) { - object.boneTransform( a, _vA$1 ); - object.boneTransform( b, _vB$1 ); - object.boneTransform( c, _vC$1 ); + return this.rotateOnAxis( _xAxis, angle ); } - const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); + rotateY( angle ) { - if ( intersection ) { + return this.rotateOnAxis( _yAxis, angle ); - if ( uv ) { + } - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); + rotateZ( angle ) { - intersection.uv = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + return this.rotateOnAxis( _zAxis, angle ); - } + } - if ( uv2 ) { + translateOnAxis( axis, distance ) { - _uvA$1.fromBufferAttribute( uv2, a ); - _uvB$1.fromBufferAttribute( uv2, b ); - _uvC$1.fromBufferAttribute( uv2, c ); + // translate object by distance along axis in object space + // axis is assumed to be normalized - intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + _v1$4.copy( axis ).applyQuaternion( this.quaternion ); - } + this.position.add( _v1$4.multiplyScalar( distance ) ); - const face = { - a: a, - b: b, - c: c, - normal: new Vector3(), - materialIndex: 0 - }; + return this; - Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); + } - intersection.face = face; + translateX( distance ) { + + return this.translateOnAxis( _xAxis, distance ); } - return intersection; + translateY( distance ) { - } + return this.translateOnAxis( _yAxis, distance ); - class BoxGeometry extends BufferGeometry { + } - constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { + translateZ( distance ) { - super(); + return this.translateOnAxis( _zAxis, distance ); - this.type = 'BoxGeometry'; + } - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; + localToWorld( vector ) { - const scope = this; + return vector.applyMatrix4( this.matrixWorld ); - // segments + } - widthSegments = Math.floor( widthSegments ); - heightSegments = Math.floor( heightSegments ); - depthSegments = Math.floor( depthSegments ); + worldToLocal( vector ) { - // buffers + return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + } - // helper variables + lookAt( x, y, z ) { - let numberOfVertices = 0; - let groupStart = 0; + // This method does not support objects having non-uniformly-scaled parent(s) - // build each side of the box geometry + if ( x.isVector3 ) { - buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px - buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx - buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py - buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny - buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz - buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz + _target.copy( x ); - // build geometry + } else { - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + _target.set( x, y, z ); - function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { + } - const segmentWidth = width / gridX; - const segmentHeight = height / gridY; + const parent = this.parent; - const widthHalf = width / 2; - const heightHalf = height / 2; - const depthHalf = depth / 2; + this.updateWorldMatrix( true, false ); - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; + _position$3.setFromMatrixPosition( this.matrixWorld ); - let vertexCounter = 0; - let groupCount = 0; + if ( this.isCamera || this.isLight ) { - const vector = new Vector3(); + _m1$1.lookAt( _position$3, _target, this.up ); - // generate vertices, normals and uvs + } else { - for ( let iy = 0; iy < gridY1; iy ++ ) { + _m1$1.lookAt( _target, _position$3, this.up ); - const y = iy * segmentHeight - heightHalf; + } - for ( let ix = 0; ix < gridX1; ix ++ ) { + this.quaternion.setFromRotationMatrix( _m1$1 ); - const x = ix * segmentWidth - widthHalf; + if ( parent ) { - // set values to correct vector component + _m1$1.extractRotation( parent.matrixWorld ); + _q1.setFromRotationMatrix( _m1$1 ); + this.quaternion.premultiply( _q1.invert() ); - vector[ u ] = x * udir; - vector[ v ] = y * vdir; - vector[ w ] = depthHalf; + } - // now apply vector to vertex buffer + } - vertices.push( vector.x, vector.y, vector.z ); + add( object ) { - // set values to correct vector component + if ( arguments.length > 1 ) { - vector[ u ] = 0; - vector[ v ] = 0; - vector[ w ] = depth > 0 ? 1 : - 1; + for ( let i = 0; i < arguments.length; i ++ ) { - // now apply vector to normal buffer + this.add( arguments[ i ] ); - normals.push( vector.x, vector.y, vector.z ); + } - // uvs + return this; - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); + } - // counters + if ( object === this ) { - vertexCounter += 1; + console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); + return this; - } + } + + if ( object && object.isObject3D ) { + + if ( object.parent !== null ) { + + object.parent.remove( object ); } - // indices + object.parent = this; + this.children.push( object ); - // 1. you need three indices to draw a single face - // 2. a single segment consists of two faces - // 3. so we need to generate six (2*3) indices per segment + object.dispatchEvent( _addedEvent ); - for ( let iy = 0; iy < gridY; iy ++ ) { + } else { - for ( let ix = 0; ix < gridX; ix ++ ) { + console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); - const a = numberOfVertices + ix + gridX1 * iy; - const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); - const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; + } - // faces + return this; - indices.push( a, b, d ); - indices.push( b, c, d ); + } - // increase counter + remove( object ) { - groupCount += 6; + if ( arguments.length > 1 ) { - } + for ( let i = 0; i < arguments.length; i ++ ) { + + this.remove( arguments[ i ] ); } - // add a group to the geometry. this will ensure multi material support + return this; - scope.addGroup( groupStart, groupCount, materialIndex ); + } - // calculate new start value for groups + const index = this.children.indexOf( object ); - groupStart += groupCount; + if ( index !== - 1 ) { - // update total number of vertices + object.parent = null; + this.children.splice( index, 1 ); - numberOfVertices += vertexCounter; + object.dispatchEvent( _removedEvent ); } - } - - static fromJSON( data ) { - - return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); + return this; } - } + removeFromParent() { - /** - * Uniform Utilities - */ + const parent = this.parent; - function cloneUniforms( src ) { + if ( parent !== null ) { - const dst = {}; + parent.remove( this ); - for ( const u in src ) { + } - dst[ u ] = {}; + return this; - for ( const p in src[ u ] ) { + } - const property = src[ u ][ p ]; + clear() { - if ( property && ( property.isColor || - property.isMatrix3 || property.isMatrix4 || - property.isVector2 || property.isVector3 || property.isVector4 || - property.isTexture || property.isQuaternion ) ) { + for ( let i = 0; i < this.children.length; i ++ ) { - dst[ u ][ p ] = property.clone(); + const object = this.children[ i ]; - } else if ( Array.isArray( property ) ) { + object.parent = null; - dst[ u ][ p ] = property.slice(); + object.dispatchEvent( _removedEvent ); - } else { + } - dst[ u ][ p ] = property; + this.children.length = 0; - } + return this; - } } - return dst; + attach( object ) { - } + // adds object as a child of this, while maintaining the object's world transform - function mergeUniforms( uniforms ) { + // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) - const merged = {}; + this.updateWorldMatrix( true, false ); - for ( let u = 0; u < uniforms.length; u ++ ) { + _m1$1.copy( this.matrixWorld ).invert(); - const tmp = cloneUniforms( uniforms[ u ] ); + if ( object.parent !== null ) { - for ( const p in tmp ) { + object.parent.updateWorldMatrix( true, false ); - merged[ p ] = tmp[ p ]; + _m1$1.multiply( object.parent.matrixWorld ); } - } + object.applyMatrix4( _m1$1 ); - return merged; + this.add( object ); - } + object.updateWorldMatrix( false, true ); - function cloneUniformsGroups( src ) { + return this; - const dst = []; + } - for ( let u = 0; u < src.length; u ++ ) { + getObjectById( id ) { - dst.push( src[ u ].clone() ); + return this.getObjectByProperty( 'id', id ); } - return dst; - - } - - // Legacy + getObjectByName( name ) { - const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; + return this.getObjectByProperty( 'name', name ); - var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; + } - var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; + getObjectByProperty( name, value ) { - class ShaderMaterial extends Material { + if ( this[ name ] === value ) return this; - constructor( parameters ) { + for ( let i = 0, l = this.children.length; i < l; i ++ ) { - super(); + const child = this.children[ i ]; + const object = child.getObjectByProperty( name, value ); - this.isShaderMaterial = true; + if ( object !== undefined ) { - this.type = 'ShaderMaterial'; + return object; - this.defines = {}; - this.uniforms = {}; - this.uniformsGroups = []; + } - this.vertexShader = default_vertex; - this.fragmentShader = default_fragment; + } - this.linewidth = 1; + return undefined; - this.wireframe = false; - this.wireframeLinewidth = 1; + } - this.fog = false; // set to use scene fog - this.lights = false; // set to use scene lights - this.clipping = false; // set to use user-defined clipping planes + getWorldPosition( target ) { - this.extensions = { - derivatives: false, // set to use derivatives - fragDepth: false, // set to use fragment depth values - drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false // set to use shader texture LOD - }; + this.updateWorldMatrix( true, false ); - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - 'color': [ 1, 1, 1 ], - 'uv': [ 0, 0 ], - 'uv2': [ 0, 0 ] - }; + return target.setFromMatrixPosition( this.matrixWorld ); - this.index0AttributeName = undefined; - this.uniformsNeedUpdate = false; + } - this.glslVersion = null; + getWorldQuaternion( target ) { - if ( parameters !== undefined ) { + this.updateWorldMatrix( true, false ); - this.setValues( parameters ); + this.matrixWorld.decompose( _position$3, target, _scale$2 ); - } + return target; } - copy( source ) { + getWorldScale( target ) { - super.copy( source ); - - this.fragmentShader = source.fragmentShader; - this.vertexShader = source.vertexShader; + this.updateWorldMatrix( true, false ); - this.uniforms = cloneUniforms( source.uniforms ); - this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); + this.matrixWorld.decompose( _position$3, _quaternion$2, target ); - this.defines = Object.assign( {}, source.defines ); + return target; - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; + } - this.fog = source.fog; - this.lights = source.lights; - this.clipping = source.clipping; + getWorldDirection( target ) { - this.extensions = Object.assign( {}, source.extensions ); + this.updateWorldMatrix( true, false ); - this.glslVersion = source.glslVersion; + const e = this.matrixWorld.elements; - return this; + return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); } - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.glslVersion = this.glslVersion; - data.uniforms = {}; + raycast( /* raycaster, intersects */ ) {} - for ( const name in this.uniforms ) { + traverse( callback ) { - const uniform = this.uniforms[ name ]; - const value = uniform.value; + callback( this ); - if ( value && value.isTexture ) { + const children = this.children; - data.uniforms[ name ] = { - type: 't', - value: value.toJSON( meta ).uuid - }; + for ( let i = 0, l = children.length; i < l; i ++ ) { - } else if ( value && value.isColor ) { + children[ i ].traverse( callback ); - data.uniforms[ name ] = { - type: 'c', - value: value.getHex() - }; + } - } else if ( value && value.isVector2 ) { + } - data.uniforms[ name ] = { - type: 'v2', - value: value.toArray() - }; + traverseVisible( callback ) { - } else if ( value && value.isVector3 ) { + if ( this.visible === false ) return; - data.uniforms[ name ] = { - type: 'v3', - value: value.toArray() - }; + callback( this ); - } else if ( value && value.isVector4 ) { + const children = this.children; - data.uniforms[ name ] = { - type: 'v4', - value: value.toArray() - }; + for ( let i = 0, l = children.length; i < l; i ++ ) { - } else if ( value && value.isMatrix3 ) { + children[ i ].traverseVisible( callback ); - data.uniforms[ name ] = { - type: 'm3', - value: value.toArray() - }; + } - } else if ( value && value.isMatrix4 ) { + } - data.uniforms[ name ] = { - type: 'm4', - value: value.toArray() - }; + traverseAncestors( callback ) { - } else { + const parent = this.parent; - data.uniforms[ name ] = { - value: value - }; + if ( parent !== null ) { - // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far + callback( parent ); - } + parent.traverseAncestors( callback ); } - if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; - - data.vertexShader = this.vertexShader; - data.fragmentShader = this.fragmentShader; - - const extensions = {}; - - for ( const key in this.extensions ) { - - if ( this.extensions[ key ] === true ) extensions[ key ] = true; + } - } + updateMatrix() { - if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; + this.matrix.compose( this.position, this.quaternion, this.scale ); - return data; + this.matrixWorldNeedsUpdate = true; } - } + updateMatrixWorld( force ) { - class Camera extends Object3D { + if ( this.matrixAutoUpdate ) this.updateMatrix(); - constructor() { + if ( this.matrixWorldNeedsUpdate || force ) { - super(); + if ( this.parent === null ) { - this.isCamera = true; + this.matrixWorld.copy( this.matrix ); - this.type = 'Camera'; + } else { - this.matrixWorldInverse = new Matrix4(); + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - this.projectionMatrix = new Matrix4(); - this.projectionMatrixInverse = new Matrix4(); + } - } + this.matrixWorldNeedsUpdate = false; - copy( source, recursive ) { + force = true; - super.copy( source, recursive ); + } - this.matrixWorldInverse.copy( source.matrixWorldInverse ); + // update children - this.projectionMatrix.copy( source.projectionMatrix ); - this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); + const children = this.children; - return this; + for ( let i = 0, l = children.length; i < l; i ++ ) { - } + const child = children[ i ]; - getWorldDirection( target ) { + if ( child.matrixWorldAutoUpdate === true || force === true ) { - this.updateWorldMatrix( true, false ); + child.updateMatrixWorld( force ); - const e = this.matrixWorld.elements; + } - return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); + } } - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); + updateWorldMatrix( updateParents, updateChildren ) { - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + const parent = this.parent; - } + if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { - updateWorldMatrix( updateParents, updateChildren ) { + parent.updateWorldMatrix( true, false ); - super.updateWorldMatrix( updateParents, updateChildren ); + } - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + if ( this.matrixAutoUpdate ) this.updateMatrix(); - } + if ( this.parent === null ) { - clone() { + this.matrixWorld.copy( this.matrix ); - return new this.constructor().copy( this ); + } else { - } + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - } + } - class PerspectiveCamera extends Camera { + // update children - constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { + if ( updateChildren === true ) { - super(); + const children = this.children; - this.isPerspectiveCamera = true; + for ( let i = 0, l = children.length; i < l; i ++ ) { - this.type = 'PerspectiveCamera'; + const child = children[ i ]; - this.fov = fov; - this.zoom = 1; + if ( child.matrixWorldAutoUpdate === true ) { - this.near = near; - this.far = far; - this.focus = 10; + child.updateWorldMatrix( false, true ); - this.aspect = aspect; - this.view = null; + } - this.filmGauge = 35; // width of the film (default in millimeters) - this.filmOffset = 0; // horizontal film offset (same unit as gauge) + } - this.updateProjectionMatrix(); + } } - copy( source, recursive ) { + toJSON( meta ) { - super.copy( source, recursive ); + // meta is a string when called from JSON.stringify + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - this.fov = source.fov; - this.zoom = source.zoom; + const output = {}; - this.near = source.near; - this.far = source.far; - this.focus = source.focus; + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { - this.aspect = source.aspect; - this.view = source.view === null ? null : Object.assign( {}, source.view ); + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {}, + shapes: {}, + skeletons: {}, + animations: {}, + nodes: {} + }; - this.filmGauge = source.filmGauge; - this.filmOffset = source.filmOffset; + output.metadata = { + version: 4.5, + type: 'Object', + generator: 'Object3D.toJSON' + }; - return this; + } - } + // standard Object3D serialization - /** - * Sets the FOV by focal length in respect to the current .filmGauge. - * - * The default film gauge is 35, so that the focal length can be specified for - * a 35mm (full frame) camera. - * - * Values for focal length and film gauge must have the same unit. - */ - setFocalLength( focalLength ) { + const object = {}; - /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ - const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; + object.uuid = this.uuid; + object.type = this.type; - this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); - this.updateProjectionMatrix(); + if ( this.name !== '' ) object.name = this.name; + if ( this.castShadow === true ) object.castShadow = true; + if ( this.receiveShadow === true ) object.receiveShadow = true; + if ( this.visible === false ) object.visible = false; + if ( this.frustumCulled === false ) object.frustumCulled = false; + if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; + if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; - } + object.layers = this.layers.mask; + object.matrix = this.matrix.toArray(); - /** - * Calculates the focal length from the current .fov and .filmGauge. - */ - getFocalLength() { + if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); + // object specific properties - return 0.5 * this.getFilmHeight() / vExtentSlope; + if ( this.isInstancedMesh ) { - } + object.type = 'InstancedMesh'; + object.count = this.count; + object.instanceMatrix = this.instanceMatrix.toJSON(); + if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); - getEffectiveFOV() { + } - return RAD2DEG * 2 * Math.atan( - Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); + // - } + function serialize( library, element ) { - getFilmWidth() { + if ( library[ element.uuid ] === undefined ) { - // film not completely covered in portrait format (aspect < 1) - return this.filmGauge * Math.min( this.aspect, 1 ); + library[ element.uuid ] = element.toJSON( meta ); - } + } - getFilmHeight() { + return element.uuid; - // film not completely covered in landscape format (aspect > 1) - return this.filmGauge / Math.max( this.aspect, 1 ); + } - } + if ( this.isScene ) { - /** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * const w = 1920; - * const h = 1080; - * const fullWidth = w * 3; - * const fullHeight = h * 2; - * - * --A-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { + if ( this.background ) { - this.aspect = fullWidth / fullHeight; + if ( this.background.isColor ) { - if ( this.view === null ) { + object.background = this.background.toJSON(); - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; + } else if ( this.background.isTexture ) { - } + object.background = this.background.toJSON( meta ).uuid; - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; + } - this.updateProjectionMatrix(); + } - } + if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { - clearViewOffset() { + object.environment = this.environment.toJSON( meta ).uuid; - if ( this.view !== null ) { + } - this.view.enabled = false; + } else if ( this.isMesh || this.isLine || this.isPoints ) { - } + object.geometry = serialize( meta.geometries, this.geometry ); - this.updateProjectionMatrix(); + const parameters = this.geometry.parameters; - } + if ( parameters !== undefined && parameters.shapes !== undefined ) { - updateProjectionMatrix() { + const shapes = parameters.shapes; - const near = this.near; - let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; - let height = 2 * top; - let width = this.aspect * height; - let left = - 0.5 * width; - const view = this.view; + if ( Array.isArray( shapes ) ) { - if ( this.view !== null && this.view.enabled ) { + for ( let i = 0, l = shapes.length; i < l; i ++ ) { - const fullWidth = view.fullWidth, - fullHeight = view.fullHeight; + const shape = shapes[ i ]; - left += view.offsetX * width / fullWidth; - top -= view.offsetY * height / fullHeight; - width *= view.width / fullWidth; - height *= view.height / fullHeight; + serialize( meta.shapes, shape ); - } + } - const skew = this.filmOffset; - if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); + } else { - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); + serialize( meta.shapes, shapes ); - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); + } - } + } - toJSON( meta ) { + } - const data = super.toJSON( meta ); + if ( this.isSkinnedMesh ) { - data.object.fov = this.fov; - data.object.zoom = this.zoom; + object.bindMode = this.bindMode; + object.bindMatrix = this.bindMatrix.toArray(); - data.object.near = this.near; - data.object.far = this.far; - data.object.focus = this.focus; + if ( this.skeleton !== undefined ) { - data.object.aspect = this.aspect; + serialize( meta.skeletons, this.skeleton ); - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + object.skeleton = this.skeleton.uuid; - data.object.filmGauge = this.filmGauge; - data.object.filmOffset = this.filmOffset; + } - return data; + } - } + if ( this.material !== undefined ) { - } + if ( Array.isArray( this.material ) ) { - const fov = 90, aspect = 1; + const uuids = []; - class CubeCamera extends Object3D { + for ( let i = 0, l = this.material.length; i < l; i ++ ) { - constructor( near, far, renderTarget ) { + uuids.push( serialize( meta.materials, this.material[ i ] ) ); - super(); + } - this.type = 'CubeCamera'; + object.material = uuids; - this.renderTarget = renderTarget; + } else { - const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); - cameraPX.layers = this.layers; - cameraPX.up.set( 0, - 1, 0 ); - cameraPX.lookAt( new Vector3( 1, 0, 0 ) ); - this.add( cameraPX ); + object.material = serialize( meta.materials, this.material ); - const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); - cameraNX.layers = this.layers; - cameraNX.up.set( 0, - 1, 0 ); - cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); - this.add( cameraNX ); + } - const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); - cameraPY.layers = this.layers; - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); + } - const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); - cameraNY.layers = this.layers; - cameraNY.up.set( 0, 0, - 1 ); - cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); - this.add( cameraNY ); + // - const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.layers = this.layers; - cameraPZ.up.set( 0, - 1, 0 ); - cameraPZ.lookAt( new Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); + if ( this.children.length > 0 ) { - const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.layers = this.layers; - cameraNZ.up.set( 0, - 1, 0 ); - cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); - this.add( cameraNZ ); + object.children = []; - } + for ( let i = 0; i < this.children.length; i ++ ) { - update( renderer, scene ) { + object.children.push( this.children[ i ].toJSON( meta ).object ); - if ( this.parent === null ) this.updateMatrixWorld(); + } - const renderTarget = this.renderTarget; + } - const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; + // - const currentRenderTarget = renderer.getRenderTarget(); + if ( this.animations.length > 0 ) { - const currentToneMapping = renderer.toneMapping; - const currentXrEnabled = renderer.xr.enabled; + object.animations = []; - renderer.toneMapping = NoToneMapping; - renderer.xr.enabled = false; + for ( let i = 0; i < this.animations.length; i ++ ) { - const generateMipmaps = renderTarget.texture.generateMipmaps; + const animation = this.animations[ i ]; - renderTarget.texture.generateMipmaps = false; + object.animations.push( serialize( meta.animations, animation ) ); - renderer.setRenderTarget( renderTarget, 0 ); - renderer.render( scene, cameraPX ); + } - renderer.setRenderTarget( renderTarget, 1 ); - renderer.render( scene, cameraNX ); + } - renderer.setRenderTarget( renderTarget, 2 ); - renderer.render( scene, cameraPY ); + if ( isRootObject ) { - renderer.setRenderTarget( renderTarget, 3 ); - renderer.render( scene, cameraNY ); - - renderer.setRenderTarget( renderTarget, 4 ); - renderer.render( scene, cameraPZ ); - - renderTarget.texture.generateMipmaps = generateMipmaps; - - renderer.setRenderTarget( renderTarget, 5 ); - renderer.render( scene, cameraNZ ); - - renderer.setRenderTarget( currentRenderTarget ); + const geometries = extractFromCache( meta.geometries ); + const materials = extractFromCache( meta.materials ); + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const shapes = extractFromCache( meta.shapes ); + const skeletons = extractFromCache( meta.skeletons ); + const animations = extractFromCache( meta.animations ); + const nodes = extractFromCache( meta.nodes ); - renderer.toneMapping = currentToneMapping; - renderer.xr.enabled = currentXrEnabled; + if ( geometries.length > 0 ) output.geometries = geometries; + if ( materials.length > 0 ) output.materials = materials; + if ( textures.length > 0 ) output.textures = textures; + if ( images.length > 0 ) output.images = images; + if ( shapes.length > 0 ) output.shapes = shapes; + if ( skeletons.length > 0 ) output.skeletons = skeletons; + if ( animations.length > 0 ) output.animations = animations; + if ( nodes.length > 0 ) output.nodes = nodes; - renderTarget.texture.needsPMREMUpdate = true; + } - } + output.object = object; - } + return output; - class CubeTexture extends Texture { + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { - constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + const values = []; + for ( const key in cache ) { - images = images !== undefined ? images : []; - mapping = mapping !== undefined ? mapping : CubeReflectionMapping; + const data = cache[ key ]; + delete data.metadata; + values.push( data ); - super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + } - this.isCubeTexture = true; + return values; - this.flipY = false; + } } - get images() { + clone( recursive ) { - return this.image; + return new this.constructor().copy( this, recursive ); } - set images( value ) { + copy( source, recursive = true ) { - this.image = value; + this.name = source.name; - } + this.up.copy( source.up ); - } + this.position.copy( source.position ); + this.rotation.order = source.rotation.order; + this.quaternion.copy( source.quaternion ); + this.scale.copy( source.scale ); - class WebGLCubeRenderTarget extends WebGLRenderTarget { + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); - constructor( size, options = {} ) { + this.matrixAutoUpdate = source.matrixAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - super( size, size, options ); + this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; - this.isWebGLCubeRenderTarget = true; + this.layers.mask = source.layers.mask; + this.visible = source.visible; - const image = { width: size, height: size, depth: 1 }; - const images = [ image, image, image, image, image, image ]; + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; - this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; - // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) - // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, - // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped - // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture - // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). + if ( recursive === true ) { - this.texture.isRenderTargetTexture = true; + for ( let i = 0; i < source.children.length; i ++ ) { - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; + const child = source.children[ i ]; + this.add( child.clone() ); - } + } - fromEquirectangularTexture( renderer, texture ) { + } - this.texture.type = texture.type; - this.texture.encoding = texture.encoding; + return this; - this.texture.generateMipmaps = texture.generateMipmaps; - this.texture.minFilter = texture.minFilter; - this.texture.magFilter = texture.magFilter; + } - const shader = { + } - uniforms: { - tEquirect: { value: null }, - }, + Object3D.DefaultUp = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + Object3D.DefaultMatrixAutoUpdate = true; + Object3D.DefaultMatrixWorldAutoUpdate = true; - vertexShader: /* glsl */` + const _v0$1 = /*@__PURE__*/ new Vector3(); + const _v1$3 = /*@__PURE__*/ new Vector3(); + const _v2$2 = /*@__PURE__*/ new Vector3(); + const _v3$1 = /*@__PURE__*/ new Vector3(); - varying vec3 vWorldDirection; + const _vab = /*@__PURE__*/ new Vector3(); + const _vac = /*@__PURE__*/ new Vector3(); + const _vbc = /*@__PURE__*/ new Vector3(); + const _vap = /*@__PURE__*/ new Vector3(); + const _vbp = /*@__PURE__*/ new Vector3(); + const _vcp = /*@__PURE__*/ new Vector3(); - vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + class Triangle { - return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); + constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { - } + this.a = a; + this.b = b; + this.c = c; - void main() { + } - vWorldDirection = transformDirection( position, modelMatrix ); + static getNormal( a, b, c, target ) { - #include - #include + target.subVectors( c, b ); + _v0$1.subVectors( a, b ); + target.cross( _v0$1 ); - } - `, + const targetLengthSq = target.lengthSq(); + if ( targetLengthSq > 0 ) { - fragmentShader: /* glsl */` + return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); - uniform sampler2D tEquirect; + } - varying vec3 vWorldDirection; + return target.set( 0, 0, 0 ); - #include + } - void main() { + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + static getBarycoord( point, a, b, c, target ) { - vec3 direction = normalize( vWorldDirection ); + _v0$1.subVectors( c, a ); + _v1$3.subVectors( b, a ); + _v2$2.subVectors( point, a ); - vec2 sampleUV = equirectUv( direction ); + const dot00 = _v0$1.dot( _v0$1 ); + const dot01 = _v0$1.dot( _v1$3 ); + const dot02 = _v0$1.dot( _v2$2 ); + const dot11 = _v1$3.dot( _v1$3 ); + const dot12 = _v1$3.dot( _v2$2 ); - gl_FragColor = texture2D( tEquirect, sampleUV ); + const denom = ( dot00 * dot11 - dot01 * dot01 ); - } - ` - }; + // collinear or singular triangle + if ( denom === 0 ) { - const geometry = new BoxGeometry( 5, 5, 5 ); + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return target.set( - 2, - 1, - 1 ); - const material = new ShaderMaterial( { + } - name: 'CubemapFromEquirect', + const invDenom = 1 / denom; + const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - uniforms: cloneUniforms( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader, - side: BackSide, - blending: NoBlending + // barycentric coordinates must always sum to 1 + return target.set( 1 - u - v, v, u ); - } ); + } - material.uniforms.tEquirect.value = texture; + static containsPoint( point, a, b, c ) { - const mesh = new Mesh( geometry, material ); + this.getBarycoord( point, a, b, c, _v3$1 ); - const currentMinFilter = texture.minFilter; + return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); - // Avoid blurred poles - if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; + } - const camera = new CubeCamera( 1, 10, this ); - camera.update( renderer, mesh ); + static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { - texture.minFilter = currentMinFilter; + this.getBarycoord( point, p1, p2, p3, _v3$1 ); - mesh.geometry.dispose(); - mesh.material.dispose(); + target.set( 0, 0 ); + target.addScaledVector( uv1, _v3$1.x ); + target.addScaledVector( uv2, _v3$1.y ); + target.addScaledVector( uv3, _v3$1.z ); - return this; + return target; } - clear( renderer, color, depth, stencil ) { + static isFrontFacing( a, b, c, direction ) { - const currentRenderTarget = renderer.getRenderTarget(); + _v0$1.subVectors( c, b ); + _v1$3.subVectors( a, b ); - for ( let i = 0; i < 6; i ++ ) { + // strictly front facing + return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; - renderer.setRenderTarget( this, i ); + } - renderer.clear( color, depth, stencil ); + set( a, b, c ) { - } + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - renderer.setRenderTarget( currentRenderTarget ); + return this; } - } + setFromPointsAndIndices( points, i0, i1, i2 ) { - const _vector1 = /*@__PURE__*/ new Vector3(); - const _vector2 = /*@__PURE__*/ new Vector3(); - const _normalMatrix = /*@__PURE__*/ new Matrix3(); + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); - class Plane { + return this; - constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { + } - this.isPlane = true; + setFromAttributeAndIndices( attribute, i0, i1, i2 ) { - // normal is assumed to be normalized + this.a.fromBufferAttribute( attribute, i0 ); + this.b.fromBufferAttribute( attribute, i1 ); + this.c.fromBufferAttribute( attribute, i2 ); - this.normal = normal; - this.constant = constant; + return this; } - set( normal, constant ) { - - this.normal.copy( normal ); - this.constant = constant; + clone() { - return this; + return new this.constructor().copy( this ); } - setComponents( x, y, z, w ) { + copy( triangle ) { - this.normal.set( x, y, z ); - this.constant = w; + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); return this; } - setFromNormalAndCoplanarPoint( normal, point ) { + getArea() { - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); + _v0$1.subVectors( this.c, this.b ); + _v1$3.subVectors( this.a, this.b ); - return this; + return _v0$1.cross( _v1$3 ).length() * 0.5; } - setFromCoplanarPoints( a, b, c ) { + getMidpoint( target ) { - const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); + return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + } - this.setFromNormalAndCoplanarPoint( normal, a ); + getNormal( target ) { - return this; + return Triangle.getNormal( this.a, this.b, this.c, target ); } - copy( plane ) { - - this.normal.copy( plane.normal ); - this.constant = plane.constant; + getPlane( target ) { - return this; + return target.setFromCoplanarPoints( this.a, this.b, this.c ); } - normalize() { - - // Note: will lead to a divide by zero if the plane is invalid. - - const inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; + getBarycoord( point, target ) { - return this; + return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); } - negate() { - - this.constant *= - 1; - this.normal.negate(); + getUV( point, uv1, uv2, uv3, target ) { - return this; + return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); } - distanceToPoint( point ) { + containsPoint( point ) { - return this.normal.dot( point ) + this.constant; + return Triangle.containsPoint( point, this.a, this.b, this.c ); } - distanceToSphere( sphere ) { + isFrontFacing( direction ) { - return this.distanceToPoint( sphere.center ) - sphere.radius; + return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); } - projectPoint( point, target ) { + intersectsBox( box ) { - return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); + return box.intersectsTriangle( this ); } - intersectLine( line, target ) { + closestPointToPoint( p, target ) { - const direction = line.delta( _vector1 ); + const a = this.a, b = this.b, c = this.c; + let v, w; - const denominator = this.normal.dot( direction ); + // algorithm thanks to Real-Time Collision Detection by Christer Ericson, + // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., + // under the accompanying license; see chapter 5.1.5 for detailed explanation. + // basically, we're distinguishing which of the voronoi regions of the triangle + // the point lies in with the minimum amount of redundant computation. - if ( denominator === 0 ) { + _vab.subVectors( b, a ); + _vac.subVectors( c, a ); + _vap.subVectors( p, a ); + const d1 = _vab.dot( _vap ); + const d2 = _vac.dot( _vap ); + if ( d1 <= 0 && d2 <= 0 ) { - // line is coplanar, return origin - if ( this.distanceToPoint( line.start ) === 0 ) { + // vertex region of A; barycentric coords (1, 0, 0) + return target.copy( a ); - return target.copy( line.start ); + } - } + _vbp.subVectors( p, b ); + const d3 = _vab.dot( _vbp ); + const d4 = _vac.dot( _vbp ); + if ( d3 >= 0 && d4 <= d3 ) { - // Unsure if this is the correct method to handle this case. - return null; + // vertex region of B; barycentric coords (0, 1, 0) + return target.copy( b ); } - const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - - if ( t < 0 || t > 1 ) { + const vc = d1 * d4 - d3 * d2; + if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - return null; + v = d1 / ( d1 - d3 ); + // edge region of AB; barycentric coords (1-v, v, 0) + return target.copy( a ).addScaledVector( _vab, v ); } - return target.copy( direction ).multiplyScalar( t ).add( line.start ); - - } + _vcp.subVectors( p, c ); + const d5 = _vab.dot( _vcp ); + const d6 = _vac.dot( _vcp ); + if ( d6 >= 0 && d5 <= d6 ) { - intersectsLine( line ) { + // vertex region of C; barycentric coords (0, 0, 1) + return target.copy( c ); - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + } - const startSign = this.distanceToPoint( line.start ); - const endSign = this.distanceToPoint( line.end ); + const vb = d5 * d2 - d1 * d6; + if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + w = d2 / ( d2 - d6 ); + // edge region of AC; barycentric coords (1-w, 0, w) + return target.copy( a ).addScaledVector( _vac, w ); - } + } - intersectsBox( box ) { + const va = d3 * d6 - d5 * d4; + if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - return box.intersectsPlane( this ); + _vbc.subVectors( c, b ); + w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); + // edge region of BC; barycentric coords (0, 1-w, w) + return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC - } + } - intersectsSphere( sphere ) { + // face region + const denom = 1 / ( va + vb + vc ); + // u = va * denom + v = vb * denom; + w = vc * denom; - return sphere.intersectsPlane( this ); + return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); } - coplanarPoint( target ) { + equals( triangle ) { - return target.copy( this.normal ).multiplyScalar( - this.constant ); + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); } - applyMatrix4( matrix, optionalNormalMatrix ) { - - const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); + } - const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); + let materialId = 0; - const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); + class Material extends EventDispatcher { - this.constant = - referencePoint.dot( normal ); + constructor() { - return this; + super(); - } + this.isMaterial = true; - translate( offset ) { + Object.defineProperty( this, 'id', { value: materialId ++ } ); - this.constant -= offset.dot( this.normal ); + this.uuid = generateUUID(); - return this; + this.name = ''; + this.type = 'Material'; - } + this.blending = NormalBlending; + this.side = FrontSide; + this.vertexColors = false; - equals( plane ) { + this.opacity = 1; + this.transparent = false; - return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); + this.blendSrc = SrcAlphaFactor; + this.blendDst = OneMinusSrcAlphaFactor; + this.blendEquation = AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; - } + this.depthFunc = LessEqualDepth; + this.depthTest = true; + this.depthWrite = true; - clone() { + this.stencilWriteMask = 0xff; + this.stencilFunc = AlwaysStencilFunc; + this.stencilRef = 0; + this.stencilFuncMask = 0xff; + this.stencilFail = KeepStencilOp; + this.stencilZFail = KeepStencilOp; + this.stencilZPass = KeepStencilOp; + this.stencilWrite = false; - return new this.constructor().copy( this ); + this.clippingPlanes = null; + this.clipIntersection = false; + this.clipShadows = false; - } + this.shadowSide = null; - } + this.colorWrite = true; - const _sphere$2 = /*@__PURE__*/ new Sphere(); - const _vector$7 = /*@__PURE__*/ new Vector3(); + this.precision = null; // override the renderer's default precision for this material - class Frustum { + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; - constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { + this.dithering = false; - this.planes = [ p0, p1, p2, p3, p4, p5 ]; + this.alphaToCoverage = false; + this.premultipliedAlpha = false; - } + this.visible = true; - set( p0, p1, p2, p3, p4, p5 ) { + this.toneMapped = true; - const planes = this.planes; + this.userData = {}; - planes[ 0 ].copy( p0 ); - planes[ 1 ].copy( p1 ); - planes[ 2 ].copy( p2 ); - planes[ 3 ].copy( p3 ); - planes[ 4 ].copy( p4 ); - planes[ 5 ].copy( p5 ); + this.version = 0; - return this; + this._alphaTest = 0; } - copy( frustum ) { + get alphaTest() { - const planes = this.planes; + return this._alphaTest; - for ( let i = 0; i < 6; i ++ ) { + } - planes[ i ].copy( frustum.planes[ i ] ); + set alphaTest( value ) { - } + if ( this._alphaTest > 0 !== value > 0 ) { - return this; + this.version ++; - } - - setFromProjectionMatrix( m ) { - - const planes = this.planes; - const me = m.elements; - const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; - const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; - const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; - const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - - planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); - planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); - planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); - planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); - planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + } - return this; + this._alphaTest = value; } - intersectsObject( object ) { - - const geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$2.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - - return this.intersectsSphere( _sphere$2 ); + onBuild( /* shaderobject, renderer */ ) {} - } + onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} - intersectsSprite( sprite ) { + onBeforeCompile( /* shaderobject, renderer */ ) {} - _sphere$2.center.set( 0, 0, 0 ); - _sphere$2.radius = 0.7071067811865476; - _sphere$2.applyMatrix4( sprite.matrixWorld ); + customProgramCacheKey() { - return this.intersectsSphere( _sphere$2 ); + return this.onBeforeCompile.toString(); } - intersectsSphere( sphere ) { + setValues( values ) { - const planes = this.planes; - const center = sphere.center; - const negRadius = - sphere.radius; + if ( values === undefined ) return; - for ( let i = 0; i < 6; i ++ ) { + for ( const key in values ) { - const distance = planes[ i ].distanceToPoint( center ); + const newValue = values[ key ]; - if ( distance < negRadius ) { + if ( newValue === undefined ) { - return false; + console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); + continue; } - } - - return true; + const currentValue = this[ key ]; - } + if ( currentValue === undefined ) { - intersectsBox( box ) { + console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' ); + continue; - const planes = this.planes; + } - for ( let i = 0; i < 6; i ++ ) { + if ( currentValue && currentValue.isColor ) { - const plane = planes[ i ]; + currentValue.set( newValue ); - // corner at max distance + } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { - _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x; - _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y; - _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z; + currentValue.copy( newValue ); - if ( plane.distanceToPoint( _vector$7 ) < 0 ) { + } else { - return false; + this[ key ] = newValue; } } - return true; - } - containsPoint( point ) { + toJSON( meta ) { - const planes = this.planes; + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - for ( let i = 0; i < 6; i ++ ) { + if ( isRootObject ) { - if ( planes[ i ].distanceToPoint( point ) < 0 ) { + meta = { + textures: {}, + images: {} + }; - return false; + } + const data = { + metadata: { + version: 4.5, + type: 'Material', + generator: 'Material.toJSON' } + }; - } + // standard Material serialization + data.uuid = this.uuid; + data.type = this.type; - return true; + if ( this.name !== '' ) data.name = this.name; - } + if ( this.color && this.color.isColor ) data.color = this.color.getHex(); - clone() { + if ( this.roughness !== undefined ) data.roughness = this.roughness; + if ( this.metalness !== undefined ) data.metalness = this.metalness; - return new this.constructor().copy( this ); + if ( this.sheen !== undefined ) data.sheen = this.sheen; + if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); + if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; + if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); + if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; - } + if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); + if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; + if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); + if ( this.shininess !== undefined ) data.shininess = this.shininess; + if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; + if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; - } + if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { - function WebGLAnimation() { + data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; - let context = null; - let isAnimating = false; - let animationLoop = null; - let requestId = null; + } - function onAnimationFrame( time, frame ) { + if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { - animationLoop( time, frame ); + data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; - requestId = context.requestAnimationFrame( onAnimationFrame ); + } - } + if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { - return { + data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; + data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); - start: function () { + } - if ( isAnimating === true ) return; - if ( animationLoop === null ) return; + if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; + if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; + if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; - requestId = context.requestAnimationFrame( onAnimationFrame ); + if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { - isAnimating = true; + data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; - }, + } - stop: function () { + if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { - context.cancelAnimationFrame( requestId ); + data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; - isAnimating = false; + } - }, + if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; + if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; + if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; - setAnimationLoop: function ( callback ) { + if ( this.lightMap && this.lightMap.isTexture ) { - animationLoop = callback; + data.lightMap = this.lightMap.toJSON( meta ).uuid; + data.lightMapIntensity = this.lightMapIntensity; - }, + } - setContext: function ( value ) { + if ( this.aoMap && this.aoMap.isTexture ) { - context = value; + data.aoMap = this.aoMap.toJSON( meta ).uuid; + data.aoMapIntensity = this.aoMapIntensity; } - }; - - } - - function WebGLAttributes( gl, capabilities ) { + if ( this.bumpMap && this.bumpMap.isTexture ) { - const isWebGL2 = capabilities.isWebGL2; + data.bumpMap = this.bumpMap.toJSON( meta ).uuid; + data.bumpScale = this.bumpScale; - const buffers = new WeakMap(); + } - function createBuffer( attribute, bufferType ) { + if ( this.normalMap && this.normalMap.isTexture ) { - const array = attribute.array; - const usage = attribute.usage; + data.normalMap = this.normalMap.toJSON( meta ).uuid; + data.normalMapType = this.normalMapType; + data.normalScale = this.normalScale.toArray(); - const buffer = gl.createBuffer(); + } - gl.bindBuffer( bufferType, buffer ); - gl.bufferData( bufferType, array, usage ); + if ( this.displacementMap && this.displacementMap.isTexture ) { - attribute.onUploadCallback(); + data.displacementMap = this.displacementMap.toJSON( meta ).uuid; + data.displacementScale = this.displacementScale; + data.displacementBias = this.displacementBias; - let type; + } - if ( array instanceof Float32Array ) { + if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; + if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; - type = 5126; + if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; + if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; + if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; + if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; - } else if ( array instanceof Uint16Array ) { + if ( this.envMap && this.envMap.isTexture ) { - if ( attribute.isFloat16BufferAttribute ) { + data.envMap = this.envMap.toJSON( meta ).uuid; - if ( isWebGL2 ) { + if ( this.combine !== undefined ) data.combine = this.combine; - type = 5131; + } - } else { + if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; + if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; + if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; - throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' ); + if ( this.gradientMap && this.gradientMap.isTexture ) { - } + data.gradientMap = this.gradientMap.toJSON( meta ).uuid; - } else { + } - type = 5123; + if ( this.transmission !== undefined ) data.transmission = this.transmission; + if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; + if ( this.thickness !== undefined ) data.thickness = this.thickness; + if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; + if ( this.attenuationDistance !== undefined ) data.attenuationDistance = this.attenuationDistance; + if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); - } + if ( this.size !== undefined ) data.size = this.size; + if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; + if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; - } else if ( array instanceof Int16Array ) { + if ( this.blending !== NormalBlending ) data.blending = this.blending; + if ( this.side !== FrontSide ) data.side = this.side; + if ( this.vertexColors ) data.vertexColors = true; - type = 5122; + if ( this.opacity < 1 ) data.opacity = this.opacity; + if ( this.transparent === true ) data.transparent = this.transparent; - } else if ( array instanceof Uint32Array ) { + data.depthFunc = this.depthFunc; + data.depthTest = this.depthTest; + data.depthWrite = this.depthWrite; + data.colorWrite = this.colorWrite; - type = 5125; + data.stencilWrite = this.stencilWrite; + data.stencilWriteMask = this.stencilWriteMask; + data.stencilFunc = this.stencilFunc; + data.stencilRef = this.stencilRef; + data.stencilFuncMask = this.stencilFuncMask; + data.stencilFail = this.stencilFail; + data.stencilZFail = this.stencilZFail; + data.stencilZPass = this.stencilZPass; - } else if ( array instanceof Int32Array ) { + // rotation (SpriteMaterial) + if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; - type = 5124; + if ( this.polygonOffset === true ) data.polygonOffset = true; + if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; + if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; - } else if ( array instanceof Int8Array ) { + if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; + if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; + if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; + if ( this.scale !== undefined ) data.scale = this.scale; - type = 5120; + if ( this.dithering === true ) data.dithering = true; - } else if ( array instanceof Uint8Array ) { + if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; + if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage; + if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; - type = 5121; + if ( this.wireframe === true ) data.wireframe = this.wireframe; + if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; + if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; + if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - } else if ( array instanceof Uint8ClampedArray ) { + if ( this.flatShading === true ) data.flatShading = this.flatShading; - type = 5121; + if ( this.visible === false ) data.visible = false; - } else { + if ( this.toneMapped === false ) data.toneMapped = false; - throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array ); + if ( this.fog === false ) data.fog = false; - } + if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; - return { - buffer: buffer, - type: type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version - }; + // TODO: Copied from Object3D.toJSON - } + function extractFromCache( cache ) { - function updateBuffer( buffer, attribute, bufferType ) { + const values = []; - const array = attribute.array; - const updateRange = attribute.updateRange; + for ( const key in cache ) { - gl.bindBuffer( bufferType, buffer ); + const data = cache[ key ]; + delete data.metadata; + values.push( data ); - if ( updateRange.count === - 1 ) { + } - // Not using update ranges + return values; - gl.bufferSubData( bufferType, 0, array ); + } - } else { + if ( isRootObject ) { - if ( isWebGL2 ) { + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array, updateRange.offset, updateRange.count ); + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; - } else { + } - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); + return data; - } + } - updateRange.count = - 1; // reset range + clone() { - } + return new this.constructor().copy( this ); } - // - - function get( attribute ) { + copy( source ) { - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + this.name = source.name; - return buffers.get( attribute ); + this.blending = source.blending; + this.side = source.side; + this.vertexColors = source.vertexColors; - } + this.opacity = source.opacity; + this.transparent = source.transparent; - function remove( attribute ) { + this.blendSrc = source.blendSrc; + this.blendDst = source.blendDst; + this.blendEquation = source.blendEquation; + this.blendSrcAlpha = source.blendSrcAlpha; + this.blendDstAlpha = source.blendDstAlpha; + this.blendEquationAlpha = source.blendEquationAlpha; - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + this.depthFunc = source.depthFunc; + this.depthTest = source.depthTest; + this.depthWrite = source.depthWrite; - const data = buffers.get( attribute ); + this.stencilWriteMask = source.stencilWriteMask; + this.stencilFunc = source.stencilFunc; + this.stencilRef = source.stencilRef; + this.stencilFuncMask = source.stencilFuncMask; + this.stencilFail = source.stencilFail; + this.stencilZFail = source.stencilZFail; + this.stencilZPass = source.stencilZPass; + this.stencilWrite = source.stencilWrite; - if ( data ) { + const srcPlanes = source.clippingPlanes; + let dstPlanes = null; - gl.deleteBuffer( data.buffer ); + if ( srcPlanes !== null ) { - buffers.delete( attribute ); + const n = srcPlanes.length; + dstPlanes = new Array( n ); - } + for ( let i = 0; i !== n; ++ i ) { - } + dstPlanes[ i ] = srcPlanes[ i ].clone(); - function update( attribute, bufferType ) { + } - if ( attribute.isGLBufferAttribute ) { + } - const cached = buffers.get( attribute ); + this.clippingPlanes = dstPlanes; + this.clipIntersection = source.clipIntersection; + this.clipShadows = source.clipShadows; - if ( ! cached || cached.version < attribute.version ) { + this.shadowSide = source.shadowSide; - buffers.set( attribute, { - buffer: attribute.buffer, - type: attribute.type, - bytesPerElement: attribute.elementSize, - version: attribute.version - } ); + this.colorWrite = source.colorWrite; - } + this.precision = source.precision; - return; + this.polygonOffset = source.polygonOffset; + this.polygonOffsetFactor = source.polygonOffsetFactor; + this.polygonOffsetUnits = source.polygonOffsetUnits; - } + this.dithering = source.dithering; - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + this.alphaTest = source.alphaTest; + this.alphaToCoverage = source.alphaToCoverage; + this.premultipliedAlpha = source.premultipliedAlpha; - const data = buffers.get( attribute ); + this.visible = source.visible; - if ( data === undefined ) { + this.toneMapped = source.toneMapped; - buffers.set( attribute, createBuffer( attribute, bufferType ) ); + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - } else if ( data.version < attribute.version ) { + return this; - updateBuffer( data.buffer, attribute, bufferType ); + } - data.version = attribute.version; + dispose() { - } + this.dispatchEvent( { type: 'dispose' } ); } - return { + set needsUpdate( value ) { - get: get, - remove: remove, - update: update + if ( value === true ) this.version ++; - }; + } } - class PlaneGeometry extends BufferGeometry { + class MeshBasicMaterial extends Material { - constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { + constructor( parameters ) { super(); - this.type = 'PlaneGeometry'; + this.isMeshBasicMaterial = true; - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; + this.type = 'MeshBasicMaterial'; - const width_half = width / 2; - const height_half = height / 2; + this.color = new Color( 0xffffff ); // emissive - const gridX = Math.floor( widthSegments ); - const gridY = Math.floor( heightSegments ); + this.map = null; - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; + this.lightMap = null; + this.lightMapIntensity = 1.0; - const segment_width = width / gridX; - const segment_height = height / gridY; + this.aoMap = null; + this.aoMapIntensity = 1.0; - // + this.specularMap = null; - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + this.alphaMap = null; - for ( let iy = 0; iy < gridY1; iy ++ ) { + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - const y = iy * segment_height - height_half; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - for ( let ix = 0; ix < gridX1; ix ++ ) { + this.fog = true; - const x = ix * segment_width - width_half; + this.setValues( parameters ); - vertices.push( x, - y, 0 ); + } - normals.push( 0, 0, 1 ); + copy( source ) { - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); + super.copy( source ); - } + this.color.copy( source.color ); - } + this.map = source.map; - for ( let iy = 0; iy < gridY; iy ++ ) { + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - for ( let ix = 0; ix < gridX; ix ++ ) { + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - const a = ix + gridX1 * iy; - const b = ix + gridX1 * ( iy + 1 ); - const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = ( ix + 1 ) + gridX1 * iy; + this.specularMap = source.specularMap; - indices.push( a, b, d ); - indices.push( b, c, d ); + this.alphaMap = source.alphaMap; - } - - } - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; - } + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - static fromJSON( data ) { + this.fog = source.fog; - return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); + return this; } } - var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; + const _vector$9 = /*@__PURE__*/ new Vector3(); + const _vector2$1 = /*@__PURE__*/ new Vector2(); - var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; + class BufferAttribute { - var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif"; + constructor( array, itemSize, normalized ) { - var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; + if ( Array.isArray( array ) ) { - var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; + } - var begin_vertex = "vec3 transformed = vec3( position );"; + this.isBufferAttribute = true; - var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; + this.name = ''; - var bsdfs = "vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( V * D );\n}\n#ifdef USE_IRIDESCENCE\n\tvec3 BRDF_GGX_Iridescence( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float iridescence, const in vec3 iridescenceFresnel, const in float roughness ) {\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = mix( F_Schlick( f0, f90, dotVH ), iridescenceFresnel, iridescence );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif"; + this.array = array; + this.itemSize = itemSize; + this.count = array !== undefined ? array.length / itemSize : 0; + this.normalized = normalized === true; - var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\t return vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat R21 = R12;\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; + this.usage = StaticDrawUsage; + this.updateRange = { offset: 0, count: - 1 }; - var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos.xyz );\n\t\tvec3 vSigmaY = dFdy( surf_pos.xyz );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; + this.version = 0; - var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif"; + } - var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; + onUploadCallback() {} - var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; + set needsUpdate( value ) { - var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; + if ( value === true ) this.version ++; - var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; + } - var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; + setUsage( value ) { - var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif"; + this.usage = value; - var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; + return this; - var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}"; + } - var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_v0 0.339\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_v1 0.276\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_v4 0.046\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_v5 0.016\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_v6 0.0038\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; + copy( source ) { - var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; + this.name = source.name; + this.array = new source.array.constructor( source.array ); + this.itemSize = source.itemSize; + this.count = source.count; + this.normalized = source.normalized; - var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; + this.usage = source.usage; - var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif"; + return this; - var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; + } - var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; + copyAt( index1, attribute, index2 ) { - var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; + index1 *= this.itemSize; + index2 *= attribute.itemSize; - var encodings_pars_fragment = "vec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}"; + for ( let i = 0, l = this.itemSize; i < l; i ++ ) { - var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif"; + } - var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif"; + return this; - var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif"; + } - var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif"; + copyArray( array ) { - var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; + this.array.set( array ); - var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; + return this; - var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"; + } - var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif"; + applyMatrix3( m ) { - var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; + if ( this.itemSize === 2 ) { - var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; + for ( let i = 0, l = this.count; i < l; i ++ ) { - var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; + _vector2$1.fromBufferAttribute( this, i ); + _vector2$1.applyMatrix3( m ); - var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; + this.setXY( i, _vector2$1.x, _vector2$1.y ); - var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert\n#define Material_LightProbeLOD( material )\t(0)"; + } - var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; + } else if ( this.itemSize === 3 ) { - var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif"; + for ( let i = 0, l = this.count; i < l; i ++ ) { - var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; + _vector$9.fromBufferAttribute( this, i ); + _vector$9.applyMatrix3( m ); - var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)"; + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; + } - var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)"; + } - var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARCOLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vUv ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vUv ).a;\n\t#endif\n#endif"; + return this; - var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec3 sheenSpecular = vec3( 0.0 );\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX_Iridescence( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness );\n\t#else\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometry.normal, geometry.viewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; + } - var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometry.viewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry.normal );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; + applyMatrix4( m ) { - var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry.normal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; + for ( let i = 0, l = this.count; i < l; i ++ ) { - var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif"; + _vector$9.fromBufferAttribute( this, i ); - var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; + _vector$9.applyMatrix4( m ); - var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif"; + } - var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; + return this; - var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; + } - var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; + applyNormalMatrix( m ) { - var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; + for ( let i = 0, l = this.count; i < l; i ++ ) { - var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; + _vector$9.fromBufferAttribute( this, i ); - var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; + _vector$9.applyNormalMatrix( m ); - var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - var morphcolor_vertex = "#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif"; + } - var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif"; + return this; - var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif"; + } - var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; + transformDirection( m ) { - var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;"; + for ( let i = 0, l = this.count; i < l; i ++ ) { - var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; + _vector$9.fromBufferAttribute( this, i ); - var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; + _vector$9.transformDirection( m ); - var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; + this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; + } - var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif"; + return this; - var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif"; + } - var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif"; + set( value, offset = 0 ) { - var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif"; + // Matching BufferAttribute constructor, do not normalize the array. + this.array.set( value, offset ); - var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; + return this; - var output_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; + } - var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}"; + getX( index ) { - var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; + let x = this.array[ index * this.itemSize ]; - var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; + if ( this.normalized ) x = denormalize( x, this.array ); - var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; + return x; - var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; + } - var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; + setX( index, x ) { - var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; + if ( this.normalized ) x = normalize( x, this.array ); - var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; + this.array[ index * this.itemSize ] = x; - var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; + return this; - var shadowmap_vertex = "#if defined( USE_SHADOWMAP ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_COORDS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif"; + } - var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; + getY( index ) { - var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; + let y = this.array[ index * this.itemSize + 1 ]; - var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tuniform int boneTextureSize;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tfloat j = i * 4.0;\n\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\ty = dy * ( y + 0.5 );\n\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\treturn bone;\n\t}\n#endif"; + if ( this.normalized ) y = denormalize( y, this.array ); - var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; + return y; - var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; + } - var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; + setY( index, y ) { - var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; + if ( this.normalized ) y = normalize( y, this.array ); - var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; + this.array[ index * this.itemSize + 1 ] = y; - var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; + return this; - var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmission.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n#endif"; + } - var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef texture2DLodEXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif"; + getZ( index ) { - var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif"; + let z = this.array[ index * this.itemSize + 2 ]; - var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif"; + if ( this.normalized ) z = denormalize( z, this.array ); - var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; + return z; - var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; + } - var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif"; + setZ( index, z ) { - var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif"; + if ( this.normalized ) z = normalize( z, this.array ); - var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; + this.array[ index * this.itemSize + 2 ] = z; - const vertex$g = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; + return this; - const fragment$g = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tgl_FragColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tgl_FragColor = vec4( mix( pow( gl_FragColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), gl_FragColor.rgb * 0.0773993808, vec3( lessThanEqual( gl_FragColor.rgb, vec3( 0.04045 ) ) ) ), gl_FragColor.w );\n\t#endif\n\t#include \n\t#include \n}"; + } - const vertex$f = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; + getW( index ) { - const fragment$f = "#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; + let w = this.array[ index * this.itemSize + 3 ]; - const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; + if ( this.normalized ) w = denormalize( w, this.array ); - const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; + return w; - const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; + } - const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; + setW( index, w ) { - const vertex$c = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; + if ( this.normalized ) w = normalize( w, this.array ); - const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; + this.array[ index * this.itemSize + 3 ] = w; - const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + return this; - const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + } - const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + setXY( index, x, y ) { - const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + index *= this.itemSize; - const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + if ( this.normalized ) { - const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + x = normalize( x, this.array ); + y = normalize( y, this.array ); - const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; + } - const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; - const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; + return this; - const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; + } - const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + setXYZ( index, x, y, z ) { - const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + index *= this.itemSize; - const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; + if ( this.normalized ) { - const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARCOLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + x = normalize( x, this.array ); + y = normalize( y, this.array ); + z = normalize( z, this.array ); - const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; + } - const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; - const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + return this; - const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + } - const vertex$2 = "#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + setXYZW( index, x, y, z, w ) { - const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; + index *= this.itemSize; - const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; + if ( this.normalized ) { - const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + x = normalize( x, this.array ); + y = normalize( y, this.array ); + z = normalize( z, this.array ); + w = normalize( w, this.array ); - const ShaderChunk = { - alphamap_fragment: alphamap_fragment, - alphamap_pars_fragment: alphamap_pars_fragment, - alphatest_fragment: alphatest_fragment, - alphatest_pars_fragment: alphatest_pars_fragment, - aomap_fragment: aomap_fragment, - aomap_pars_fragment: aomap_pars_fragment, - begin_vertex: begin_vertex, - beginnormal_vertex: beginnormal_vertex, - bsdfs: bsdfs, - iridescence_fragment: iridescence_fragment, - bumpmap_pars_fragment: bumpmap_pars_fragment, - clipping_planes_fragment: clipping_planes_fragment, - clipping_planes_pars_fragment: clipping_planes_pars_fragment, - clipping_planes_pars_vertex: clipping_planes_pars_vertex, - clipping_planes_vertex: clipping_planes_vertex, - color_fragment: color_fragment, - color_pars_fragment: color_pars_fragment, - color_pars_vertex: color_pars_vertex, - color_vertex: color_vertex, - common: common, - cube_uv_reflection_fragment: cube_uv_reflection_fragment, - defaultnormal_vertex: defaultnormal_vertex, - displacementmap_pars_vertex: displacementmap_pars_vertex, - displacementmap_vertex: displacementmap_vertex, - emissivemap_fragment: emissivemap_fragment, - emissivemap_pars_fragment: emissivemap_pars_fragment, - encodings_fragment: encodings_fragment, - encodings_pars_fragment: encodings_pars_fragment, - envmap_fragment: envmap_fragment, - envmap_common_pars_fragment: envmap_common_pars_fragment, - envmap_pars_fragment: envmap_pars_fragment, - envmap_pars_vertex: envmap_pars_vertex, - envmap_physical_pars_fragment: envmap_physical_pars_fragment, - envmap_vertex: envmap_vertex, - fog_vertex: fog_vertex, - fog_pars_vertex: fog_pars_vertex, - fog_fragment: fog_fragment, - fog_pars_fragment: fog_pars_fragment, - gradientmap_pars_fragment: gradientmap_pars_fragment, - lightmap_fragment: lightmap_fragment, - lightmap_pars_fragment: lightmap_pars_fragment, - lights_lambert_fragment: lights_lambert_fragment, - lights_lambert_pars_fragment: lights_lambert_pars_fragment, - lights_pars_begin: lights_pars_begin, - lights_toon_fragment: lights_toon_fragment, - lights_toon_pars_fragment: lights_toon_pars_fragment, - lights_phong_fragment: lights_phong_fragment, - lights_phong_pars_fragment: lights_phong_pars_fragment, - lights_physical_fragment: lights_physical_fragment, - lights_physical_pars_fragment: lights_physical_pars_fragment, - lights_fragment_begin: lights_fragment_begin, - lights_fragment_maps: lights_fragment_maps, - lights_fragment_end: lights_fragment_end, - logdepthbuf_fragment: logdepthbuf_fragment, - logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, - logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, - logdepthbuf_vertex: logdepthbuf_vertex, - map_fragment: map_fragment, - map_pars_fragment: map_pars_fragment, - map_particle_fragment: map_particle_fragment, - map_particle_pars_fragment: map_particle_pars_fragment, - metalnessmap_fragment: metalnessmap_fragment, - metalnessmap_pars_fragment: metalnessmap_pars_fragment, - morphcolor_vertex: morphcolor_vertex, - morphnormal_vertex: morphnormal_vertex, - morphtarget_pars_vertex: morphtarget_pars_vertex, - morphtarget_vertex: morphtarget_vertex, - normal_fragment_begin: normal_fragment_begin, - normal_fragment_maps: normal_fragment_maps, - normal_pars_fragment: normal_pars_fragment, - normal_pars_vertex: normal_pars_vertex, - normal_vertex: normal_vertex, - normalmap_pars_fragment: normalmap_pars_fragment, - clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, - clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, - clearcoat_pars_fragment: clearcoat_pars_fragment, - iridescence_pars_fragment: iridescence_pars_fragment, - output_fragment: output_fragment, - packing: packing, - premultiplied_alpha_fragment: premultiplied_alpha_fragment, - project_vertex: project_vertex, - dithering_fragment: dithering_fragment, - dithering_pars_fragment: dithering_pars_fragment, - roughnessmap_fragment: roughnessmap_fragment, - roughnessmap_pars_fragment: roughnessmap_pars_fragment, - shadowmap_pars_fragment: shadowmap_pars_fragment, - shadowmap_pars_vertex: shadowmap_pars_vertex, - shadowmap_vertex: shadowmap_vertex, - shadowmask_pars_fragment: shadowmask_pars_fragment, - skinbase_vertex: skinbase_vertex, - skinning_pars_vertex: skinning_pars_vertex, - skinning_vertex: skinning_vertex, - skinnormal_vertex: skinnormal_vertex, - specularmap_fragment: specularmap_fragment, - specularmap_pars_fragment: specularmap_pars_fragment, - tonemapping_fragment: tonemapping_fragment, - tonemapping_pars_fragment: tonemapping_pars_fragment, - transmission_fragment: transmission_fragment, - transmission_pars_fragment: transmission_pars_fragment, - uv_pars_fragment: uv_pars_fragment, - uv_pars_vertex: uv_pars_vertex, - uv_vertex: uv_vertex, - uv2_pars_fragment: uv2_pars_fragment, - uv2_pars_vertex: uv2_pars_vertex, - uv2_vertex: uv2_vertex, - worldpos_vertex: worldpos_vertex, + } - background_vert: vertex$g, - background_frag: fragment$g, - cube_vert: vertex$f, - cube_frag: fragment$f, - depth_vert: vertex$e, - depth_frag: fragment$e, - distanceRGBA_vert: vertex$d, - distanceRGBA_frag: fragment$d, - equirect_vert: vertex$c, - equirect_frag: fragment$c, - linedashed_vert: vertex$b, - linedashed_frag: fragment$b, - meshbasic_vert: vertex$a, - meshbasic_frag: fragment$a, - meshlambert_vert: vertex$9, - meshlambert_frag: fragment$9, - meshmatcap_vert: vertex$8, - meshmatcap_frag: fragment$8, - meshnormal_vert: vertex$7, - meshnormal_frag: fragment$7, - meshphong_vert: vertex$6, - meshphong_frag: fragment$6, - meshphysical_vert: vertex$5, - meshphysical_frag: fragment$5, - meshtoon_vert: vertex$4, - meshtoon_frag: fragment$4, - points_vert: vertex$3, - points_frag: fragment$3, - shadow_vert: vertex$2, - shadow_frag: fragment$2, - sprite_vert: vertex$1, - sprite_frag: fragment$1 - }; + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; - /** - * Uniforms library for shared webgl shaders - */ + return this; - const UniformsLib = { + } - common: { + onUpload( callback ) { - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, + this.onUploadCallback = callback; - map: { value: null }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() }, - uv2Transform: { value: /*@__PURE__*/ new Matrix3() }, + return this; - alphaMap: { value: null }, - alphaTest: { value: 0 } + } - }, + clone() { - specularmap: { + return new this.constructor( this.array, this.itemSize ).copy( this ); - specularMap: { value: null }, + } - }, + toJSON() { - envmap: { + const data = { + itemSize: this.itemSize, + type: this.array.constructor.name, + array: Array.from( this.array ), + normalized: this.normalized + }; - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - reflectivity: { value: 1.0 }, // basic, lambert, phong - ior: { value: 1.5 }, // physical - refractionRatio: { value: 0.98 } // basic, lambert, phong + if ( this.name !== '' ) data.name = this.name; + if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; + if ( this.updateRange.offset !== 0 || this.updateRange.count !== - 1 ) data.updateRange = this.updateRange; - }, + return data; - aomap: { + } - aoMap: { value: null }, - aoMapIntensity: { value: 1 } + // @deprecated - }, + copyColorsArray() { - lightmap: { - - lightMap: { value: null }, - lightMapIntensity: { value: 1 } - - }, + console.error( 'THREE.BufferAttribute: copyColorsArray() was removed in r144.' ); - emissivemap: { + } - emissiveMap: { value: null } + copyVector2sArray() { - }, + console.error( 'THREE.BufferAttribute: copyVector2sArray() was removed in r144.' ); - bumpmap: { + } - bumpMap: { value: null }, - bumpScale: { value: 1 } + copyVector3sArray() { - }, + console.error( 'THREE.BufferAttribute: copyVector3sArray() was removed in r144.' ); - normalmap: { + } - normalMap: { value: null }, - normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } + copyVector4sArray() { - }, + console.error( 'THREE.BufferAttribute: copyVector4sArray() was removed in r144.' ); - displacementmap: { + } - displacementMap: { value: null }, - displacementScale: { value: 1 }, - displacementBias: { value: 0 } + } - }, + // - roughnessmap: { + class Int8BufferAttribute extends BufferAttribute { - roughnessMap: { value: null } + constructor( array, itemSize, normalized ) { - }, + super( new Int8Array( array ), itemSize, normalized ); - metalnessmap: { + } - metalnessMap: { value: null } + } - }, + class Uint8BufferAttribute extends BufferAttribute { - gradientmap: { + constructor( array, itemSize, normalized ) { - gradientMap: { value: null } + super( new Uint8Array( array ), itemSize, normalized ); - }, + } - fog: { + } - fogDensity: { value: 0.00025 }, - fogNear: { value: 1 }, - fogFar: { value: 2000 }, - fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) } + class Uint8ClampedBufferAttribute extends BufferAttribute { - }, + constructor( array, itemSize, normalized ) { - lights: { + super( new Uint8ClampedArray( array ), itemSize, normalized ); - ambientLightColor: { value: [] }, + } - lightProbe: { value: [] }, + } - directionalLights: { value: [], properties: { - direction: {}, - color: {} - } }, + class Int16BufferAttribute extends BufferAttribute { - directionalLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, + constructor( array, itemSize, normalized ) { - directionalShadowMap: { value: [] }, - directionalShadowMatrix: { value: [] }, + super( new Int16Array( array ), itemSize, normalized ); - spotLights: { value: [], properties: { - color: {}, - position: {}, - direction: {}, - distance: {}, - coneCos: {}, - penumbraCos: {}, - decay: {} - } }, + } - spotLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, + } - spotLightMap: { value: [] }, - spotShadowMap: { value: [] }, - spotLightMatrix: { value: [] }, + class Uint16BufferAttribute extends BufferAttribute { - pointLights: { value: [], properties: { - color: {}, - position: {}, - decay: {}, - distance: {} - } }, + constructor( array, itemSize, normalized ) { - pointLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {}, - shadowCameraNear: {}, - shadowCameraFar: {} - } }, + super( new Uint16Array( array ), itemSize, normalized ); - pointShadowMap: { value: [] }, - pointShadowMatrix: { value: [] }, + } - hemisphereLights: { value: [], properties: { - direction: {}, - skyColor: {}, - groundColor: {} - } }, + } - // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src - rectAreaLights: { value: [], properties: { - color: {}, - position: {}, - width: {}, - height: {} - } }, + class Int32BufferAttribute extends BufferAttribute { - ltc_1: { value: null }, - ltc_2: { value: null } + constructor( array, itemSize, normalized ) { - }, + super( new Int32Array( array ), itemSize, normalized ); - points: { + } - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - map: { value: null }, - alphaMap: { value: null }, - alphaTest: { value: 0 }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() } + } - }, + class Uint32BufferAttribute extends BufferAttribute { - sprite: { + constructor( array, itemSize, normalized ) { - diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, - rotation: { value: 0.0 }, - map: { value: null }, - alphaMap: { value: null }, - alphaTest: { value: 0 }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() } + super( new Uint32Array( array ), itemSize, normalized ); } - }; + } - const ShaderLib = { + class Float16BufferAttribute extends BufferAttribute { - basic: { + constructor( array, itemSize, normalized ) { - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.fog - ] ), + super( new Uint16Array( array ), itemSize, normalized ); - vertexShader: ShaderChunk.meshbasic_vert, - fragmentShader: ShaderChunk.meshbasic_frag + this.isFloat16BufferAttribute = true; - }, + } - lambert: { + } - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } - } - ] ), - vertexShader: ShaderChunk.meshlambert_vert, - fragmentShader: ShaderChunk.meshlambert_frag + class Float32BufferAttribute extends BufferAttribute { - }, + constructor( array, itemSize, normalized ) { - phong: { + super( new Float32Array( array ), itemSize, normalized ); - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specular: { value: /*@__PURE__*/ new Color( 0x111111 ) }, - shininess: { value: 30 } - } - ] ), + } - vertexShader: ShaderChunk.meshphong_vert, - fragmentShader: ShaderChunk.meshphong_frag + } - }, + class Float64BufferAttribute extends BufferAttribute { - standard: { + constructor( array, itemSize, normalized ) { - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.roughnessmap, - UniformsLib.metalnessmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - roughness: { value: 1.0 }, - metalness: { value: 0.0 }, - envMapIntensity: { value: 1 } // temporary - } - ] ), + super( new Float64Array( array ), itemSize, normalized ); - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag + } - }, + } - toon: { + let _id$1 = 0; - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.gradientmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } - } - ] ), + const _m1 = /*@__PURE__*/ new Matrix4(); + const _obj = /*@__PURE__*/ new Object3D(); + const _offset = /*@__PURE__*/ new Vector3(); + const _box$1 = /*@__PURE__*/ new Box3(); + const _boxMorphTargets = /*@__PURE__*/ new Box3(); + const _vector$8 = /*@__PURE__*/ new Vector3(); - vertexShader: ShaderChunk.meshtoon_vert, - fragmentShader: ShaderChunk.meshtoon_frag + class BufferGeometry extends EventDispatcher { - }, + constructor() { - matcap: { + super(); - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - { - matcap: { value: null } - } - ] ), + this.isBufferGeometry = true; - vertexShader: ShaderChunk.meshmatcap_vert, - fragmentShader: ShaderChunk.meshmatcap_frag + Object.defineProperty( this, 'id', { value: _id$1 ++ } ); - }, + this.uuid = generateUUID(); - points: { + this.name = ''; + this.type = 'BufferGeometry'; - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.points, - UniformsLib.fog - ] ), + this.index = null; + this.attributes = {}; - vertexShader: ShaderChunk.points_vert, - fragmentShader: ShaderChunk.points_frag + this.morphAttributes = {}; + this.morphTargetsRelative = false; - }, + this.groups = []; - dashed: { + this.boundingBox = null; + this.boundingSphere = null; - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.fog, - { - scale: { value: 1 }, - dashSize: { value: 1 }, - totalSize: { value: 2 } - } - ] ), + this.drawRange = { start: 0, count: Infinity }; - vertexShader: ShaderChunk.linedashed_vert, - fragmentShader: ShaderChunk.linedashed_frag + this.userData = {}; - }, + } - depth: { + getIndex() { - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap - ] ), + return this.index; - vertexShader: ShaderChunk.depth_vert, - fragmentShader: ShaderChunk.depth_frag + } - }, + setIndex( index ) { - normal: { + if ( Array.isArray( index ) ) { - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - { - opacity: { value: 1.0 } - } - ] ), + this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); - vertexShader: ShaderChunk.meshnormal_vert, - fragmentShader: ShaderChunk.meshnormal_frag + } else { - }, + this.index = index; - sprite: { + } - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.sprite, - UniformsLib.fog - ] ), + return this; - vertexShader: ShaderChunk.sprite_vert, - fragmentShader: ShaderChunk.sprite_frag + } - }, + getAttribute( name ) { - background: { + return this.attributes[ name ]; - uniforms: { - uvTransform: { value: /*@__PURE__*/ new Matrix3() }, - t2D: { value: null }, - }, + } - vertexShader: ShaderChunk.background_vert, - fragmentShader: ShaderChunk.background_frag + setAttribute( name, attribute ) { - }, + this.attributes[ name ] = attribute; - cube: { + return this; - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.envmap, - { - opacity: { value: 1.0 } - } - ] ), + } - vertexShader: ShaderChunk.cube_vert, - fragmentShader: ShaderChunk.cube_frag + deleteAttribute( name ) { - }, + delete this.attributes[ name ]; - equirect: { + return this; - uniforms: { - tEquirect: { value: null }, - }, + } - vertexShader: ShaderChunk.equirect_vert, - fragmentShader: ShaderChunk.equirect_frag + hasAttribute( name ) { - }, + return this.attributes[ name ] !== undefined; - distanceRGBA: { + } - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap, - { - referencePosition: { value: /*@__PURE__*/ new Vector3() }, - nearDistance: { value: 1 }, - farDistance: { value: 1000 } - } - ] ), + addGroup( start, count, materialIndex = 0 ) { - vertexShader: ShaderChunk.distanceRGBA_vert, - fragmentShader: ShaderChunk.distanceRGBA_frag + this.groups.push( { - }, + start: start, + count: count, + materialIndex: materialIndex - shadow: { + } ); - uniforms: /*@__PURE__*/ mergeUniforms( [ - UniformsLib.lights, - UniformsLib.fog, - { - color: { value: /*@__PURE__*/ new Color( 0x00000 ) }, - opacity: { value: 1.0 } - }, - ] ), + } - vertexShader: ShaderChunk.shadow_vert, - fragmentShader: ShaderChunk.shadow_frag + clearGroups() { + + this.groups = []; } - }; + setDrawRange( start, count ) { - ShaderLib.physical = { + this.drawRange.start = start; + this.drawRange.count = count; - uniforms: /*@__PURE__*/ mergeUniforms( [ - ShaderLib.standard.uniforms, - { - clearcoat: { value: 0 }, - clearcoatMap: { value: null }, - clearcoatRoughness: { value: 0 }, - clearcoatRoughnessMap: { value: null }, - clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, - clearcoatNormalMap: { value: null }, - iridescence: { value: 0 }, - iridescenceMap: { value: null }, - iridescenceIOR: { value: 1.3 }, - iridescenceThicknessMinimum: { value: 100 }, - iridescenceThicknessMaximum: { value: 400 }, - iridescenceThicknessMap: { value: null }, - sheen: { value: 0 }, - sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - sheenColorMap: { value: null }, - sheenRoughness: { value: 1 }, - sheenRoughnessMap: { value: null }, - transmission: { value: 0 }, - transmissionMap: { value: null }, - transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, - transmissionSamplerMap: { value: null }, - thickness: { value: 0 }, - thicknessMap: { value: null }, - attenuationDistance: { value: 0 }, - attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specularIntensity: { value: 1 }, - specularIntensityMap: { value: null }, - specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, - specularColorMap: { value: null }, - } - ] ), + } - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag + applyMatrix4( matrix ) { - }; + const position = this.attributes.position; - function WebGLBackground( renderer, cubemaps, state, objects, alpha, premultipliedAlpha ) { + if ( position !== undefined ) { - const clearColor = new Color( 0x000000 ); - let clearAlpha = alpha === true ? 0 : 1; + position.applyMatrix4( matrix ); - let planeMesh; - let boxMesh; + position.needsUpdate = true; - let currentBackground = null; - let currentBackgroundVersion = 0; - let currentTonemapping = null; + } - function render( renderList, scene ) { + const normal = this.attributes.normal; - let forceClear = false; - let background = scene.isScene === true ? scene.background : null; + if ( normal !== undefined ) { - if ( background && background.isTexture ) { + const normalMatrix = new Matrix3().getNormalMatrix( matrix ); - background = cubemaps.get( background ); + normal.applyNormalMatrix( normalMatrix ); + + normal.needsUpdate = true; } - // Ignore background in AR - // TODO: Reconsider this. + const tangent = this.attributes.tangent; - const xr = renderer.xr; - const session = xr.getSession && xr.getSession(); + if ( tangent !== undefined ) { - if ( session && session.environmentBlendMode === 'additive' ) { + tangent.transformDirection( matrix ); - background = null; + tangent.needsUpdate = true; } - if ( background === null ) { - - setClear( clearColor, clearAlpha ); - - } else if ( background && background.isColor ) { + if ( this.boundingBox !== null ) { - setClear( background, 1 ); - forceClear = true; + this.computeBoundingBox(); } - if ( renderer.autoClear || forceClear ) { + if ( this.boundingSphere !== null ) { - renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); + this.computeBoundingSphere(); } - if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) { + return this; - if ( boxMesh === undefined ) { + } - boxMesh = new Mesh( - new BoxGeometry( 1, 1, 1 ), - new ShaderMaterial( { - name: 'BackgroundCubeMaterial', - uniforms: cloneUniforms( ShaderLib.cube.uniforms ), - vertexShader: ShaderLib.cube.vertexShader, - fragmentShader: ShaderLib.cube.fragmentShader, - side: BackSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); + applyQuaternion( q ) { - boxMesh.geometry.deleteAttribute( 'normal' ); - boxMesh.geometry.deleteAttribute( 'uv' ); + _m1.makeRotationFromQuaternion( q ); - boxMesh.onBeforeRender = function ( renderer, scene, camera ) { + this.applyMatrix4( _m1 ); - this.matrixWorld.copyPosition( camera.matrixWorld ); + return this; - }; + } - // add "envMap" material property so the renderer can evaluate it like for built-in materials - Object.defineProperty( boxMesh.material, 'envMap', { + rotateX( angle ) { - get: function () { + // rotate geometry around world x-axis - return this.uniforms.envMap.value; + _m1.makeRotationX( angle ); - } + this.applyMatrix4( _m1 ); - } ); + return this; - objects.update( boxMesh ); + } - } + rotateY( angle ) { - boxMesh.material.uniforms.envMap.value = background; - boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1; + // rotate geometry around world y-axis - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { + _m1.makeRotationY( angle ); - boxMesh.material.needsUpdate = true; + this.applyMatrix4( _m1 ); - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; + return this; - } + } - boxMesh.layers.enableAll(); + rotateZ( angle ) { - // push to the pre-sorted opaque render list - renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); + // rotate geometry around world z-axis - } else if ( background && background.isTexture ) { + _m1.makeRotationZ( angle ); - if ( planeMesh === undefined ) { + this.applyMatrix4( _m1 ); - planeMesh = new Mesh( - new PlaneGeometry( 2, 2 ), - new ShaderMaterial( { - name: 'BackgroundMaterial', - uniforms: cloneUniforms( ShaderLib.background.uniforms ), - vertexShader: ShaderLib.background.vertexShader, - fragmentShader: ShaderLib.background.fragmentShader, - side: FrontSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); + return this; - planeMesh.geometry.deleteAttribute( 'normal' ); + } - // add "map" material property so the renderer can evaluate it like for built-in materials - Object.defineProperty( planeMesh.material, 'map', { + translate( x, y, z ) { - get: function () { + // translate geometry - return this.uniforms.t2D.value; + _m1.makeTranslation( x, y, z ); - } + this.applyMatrix4( _m1 ); - } ); + return this; - objects.update( planeMesh ); + } - } + scale( x, y, z ) { - planeMesh.material.uniforms.t2D.value = background; + // scale geometry - if ( background.matrixAutoUpdate === true ) { + _m1.makeScale( x, y, z ); - background.updateMatrix(); + this.applyMatrix4( _m1 ); - } + return this; - planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); + } - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { + lookAt( vector ) { - planeMesh.material.needsUpdate = true; + _obj.lookAt( vector ); - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; + _obj.updateMatrix(); - } + this.applyMatrix4( _obj.matrix ); - planeMesh.layers.enableAll(); + return this; - // push to the pre-sorted opaque render list - renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); + } - } + center() { - } + this.computeBoundingBox(); - function setClear( color, alpha ) { + this.boundingBox.getCenter( _offset ).negate(); - state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); + this.translate( _offset.x, _offset.y, _offset.z ); + + return this; } - return { + setFromPoints( points ) { - getClearColor: function () { + const position = []; - return clearColor; + for ( let i = 0, l = points.length; i < l; i ++ ) { - }, - setClearColor: function ( color, alpha = 1 ) { + const point = points[ i ]; + position.push( point.x, point.y, point.z || 0 ); - clearColor.set( color ); - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); + } - }, - getClearAlpha: function () { + this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); - return clearAlpha; + return this; - }, - setClearAlpha: function ( alpha ) { + } - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); + computeBoundingBox() { - }, - render: render + if ( this.boundingBox === null ) { - }; + this.boundingBox = new Box3(); - } + } - function WebGLBindingStates( gl, extensions, attributes, capabilities ) { + const position = this.attributes.position; + const morphAttributesPosition = this.morphAttributes.position; - const maxVertexAttributes = gl.getParameter( 34921 ); + if ( position && position.isGLBufferAttribute ) { - const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); - const vaoAvailable = capabilities.isWebGL2 || extension !== null; + console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this ); - const bindingStates = {}; + this.boundingBox.set( + new Vector3( - Infinity, - Infinity, - Infinity ), + new Vector3( + Infinity, + Infinity, + Infinity ) + ); - const defaultState = createBindingState( null ); - let currentState = defaultState; - let forceUpdate = false; + return; - function setup( object, material, program, geometry, index ) { + } - let updateBuffers = false; + if ( position !== undefined ) { - if ( vaoAvailable ) { + this.boundingBox.setFromBufferAttribute( position ); - const state = getBindingState( geometry, program, material ); + // process morph attributes if present - if ( currentState !== state ) { + if ( morphAttributesPosition ) { - currentState = state; - bindVertexArrayObject( currentState.object ); + for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - } + const morphAttribute = morphAttributesPosition[ i ]; + _box$1.setFromBufferAttribute( morphAttribute ); - updateBuffers = needsUpdate( object, geometry, program, index ); + if ( this.morphTargetsRelative ) { - if ( updateBuffers ) saveCache( object, geometry, program, index ); + _vector$8.addVectors( this.boundingBox.min, _box$1.min ); + this.boundingBox.expandByPoint( _vector$8 ); - } else { + _vector$8.addVectors( this.boundingBox.max, _box$1.max ); + this.boundingBox.expandByPoint( _vector$8 ); - const wireframe = ( material.wireframe === true ); + } else { - if ( currentState.geometry !== geometry.id || - currentState.program !== program.id || - currentState.wireframe !== wireframe ) { + this.boundingBox.expandByPoint( _box$1.min ); + this.boundingBox.expandByPoint( _box$1.max ); - currentState.geometry = geometry.id; - currentState.program = program.id; - currentState.wireframe = wireframe; + } - updateBuffers = true; + } } - } - - if ( index !== null ) { + } else { - attributes.update( index, 34963 ); + this.boundingBox.makeEmpty(); } - if ( updateBuffers || forceUpdate ) { - - forceUpdate = false; - - setupVertexAttributes( object, material, program, geometry ); - - if ( index !== null ) { - - gl.bindBuffer( 34963, attributes.get( index ).buffer ); + if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - } + console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); } } - function createVertexArrayObject() { - - if ( capabilities.isWebGL2 ) return gl.createVertexArray(); - - return extension.createVertexArrayOES(); - - } - - function bindVertexArrayObject( vao ) { + computeBoundingSphere() { - if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao ); + if ( this.boundingSphere === null ) { - return extension.bindVertexArrayOES( vao ); + this.boundingSphere = new Sphere(); - } + } - function deleteVertexArrayObject( vao ) { + const position = this.attributes.position; + const morphAttributesPosition = this.morphAttributes.position; - if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao ); + if ( position && position.isGLBufferAttribute ) { - return extension.deleteVertexArrayOES( vao ); + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this ); - } + this.boundingSphere.set( new Vector3(), Infinity ); - function getBindingState( geometry, program, material ) { + return; - const wireframe = ( material.wireframe === true ); + } - let programMap = bindingStates[ geometry.id ]; + if ( position ) { - if ( programMap === undefined ) { + // first, find the center of the bounding sphere - programMap = {}; - bindingStates[ geometry.id ] = programMap; + const center = this.boundingSphere.center; - } + _box$1.setFromBufferAttribute( position ); - let stateMap = programMap[ program.id ]; + // process morph attributes if present - if ( stateMap === undefined ) { + if ( morphAttributesPosition ) { - stateMap = {}; - programMap[ program.id ] = stateMap; + for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - } + const morphAttribute = morphAttributesPosition[ i ]; + _boxMorphTargets.setFromBufferAttribute( morphAttribute ); - let state = stateMap[ wireframe ]; + if ( this.morphTargetsRelative ) { - if ( state === undefined ) { + _vector$8.addVectors( _box$1.min, _boxMorphTargets.min ); + _box$1.expandByPoint( _vector$8 ); - state = createBindingState( createVertexArrayObject() ); - stateMap[ wireframe ] = state; + _vector$8.addVectors( _box$1.max, _boxMorphTargets.max ); + _box$1.expandByPoint( _vector$8 ); - } + } else { - return state; + _box$1.expandByPoint( _boxMorphTargets.min ); + _box$1.expandByPoint( _boxMorphTargets.max ); - } + } - function createBindingState( vao ) { + } - const newAttributes = []; - const enabledAttributes = []; - const attributeDivisors = []; + } - for ( let i = 0; i < maxVertexAttributes; i ++ ) { + _box$1.getCenter( center ); - newAttributes[ i ] = 0; - enabledAttributes[ i ] = 0; - attributeDivisors[ i ] = 0; + // second, try to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - } + let maxRadiusSq = 0; - return { + for ( let i = 0, il = position.count; i < il; i ++ ) { - // for backward compatibility on non-VAO support browser - geometry: null, - program: null, - wireframe: false, + _vector$8.fromBufferAttribute( position, i ); - newAttributes: newAttributes, - enabledAttributes: enabledAttributes, - attributeDivisors: attributeDivisors, - object: vao, - attributes: {}, - index: null + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - }; + } - } + // process morph attributes if present - function needsUpdate( object, geometry, program, index ) { + if ( morphAttributesPosition ) { - const cachedAttributes = currentState.attributes; - const geometryAttributes = geometry.attributes; + for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - let attributesNum = 0; + const morphAttribute = morphAttributesPosition[ i ]; + const morphTargetsRelative = this.morphTargetsRelative; - const programAttributes = program.getAttributes(); + for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { - for ( const name in programAttributes ) { + _vector$8.fromBufferAttribute( morphAttribute, j ); - const programAttribute = programAttributes[ name ]; + if ( morphTargetsRelative ) { - if ( programAttribute.location >= 0 ) { + _offset.fromBufferAttribute( position, j ); + _vector$8.add( _offset ); - const cachedAttribute = cachedAttributes[ name ]; - let geometryAttribute = geometryAttributes[ name ]; + } - if ( geometryAttribute === undefined ) { + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; + } } - if ( cachedAttribute === undefined ) return true; + } - if ( cachedAttribute.attribute !== geometryAttribute ) return true; + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true; + if ( isNaN( this.boundingSphere.radius ) ) { - attributesNum ++; + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); } } - if ( currentState.attributesNum !== attributesNum ) return true; + } - if ( currentState.index !== index ) return true; + computeTangents() { - return false; + const index = this.index; + const attributes = this.attributes; - } + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) - function saveCache( object, geometry, program, index ) { + if ( index === null || + attributes.position === undefined || + attributes.normal === undefined || + attributes.uv === undefined ) { - const cache = {}; - const attributes = geometry.attributes; - let attributesNum = 0; + console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); + return; - const programAttributes = program.getAttributes(); + } - for ( const name in programAttributes ) { + const indices = index.array; + const positions = attributes.position.array; + const normals = attributes.normal.array; + const uvs = attributes.uv.array; - const programAttribute = programAttributes[ name ]; + const nVertices = positions.length / 3; - if ( programAttribute.location >= 0 ) { + if ( this.hasAttribute( 'tangent' ) === false ) { - let attribute = attributes[ name ]; + this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); - if ( attribute === undefined ) { + } - if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor; + const tangents = this.getAttribute( 'tangent' ).array; - } + const tan1 = [], tan2 = []; - const data = {}; - data.attribute = attribute; + for ( let i = 0; i < nVertices; i ++ ) { - if ( attribute && attribute.data ) { + tan1[ i ] = new Vector3(); + tan2[ i ] = new Vector3(); - data.data = attribute.data; + } - } + const vA = new Vector3(), + vB = new Vector3(), + vC = new Vector3(), - cache[ name ] = data; + uvA = new Vector2(), + uvB = new Vector2(), + uvC = new Vector2(), - attributesNum ++; + sdir = new Vector3(), + tdir = new Vector3(); - } + function handleTriangle( a, b, c ) { - } + vA.fromArray( positions, a * 3 ); + vB.fromArray( positions, b * 3 ); + vC.fromArray( positions, c * 3 ); - currentState.attributes = cache; - currentState.attributesNum = attributesNum; + uvA.fromArray( uvs, a * 2 ); + uvB.fromArray( uvs, b * 2 ); + uvC.fromArray( uvs, c * 2 ); - currentState.index = index; + vB.sub( vA ); + vC.sub( vA ); - } + uvB.sub( uvA ); + uvC.sub( uvA ); - function initAttributes() { + const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); - const newAttributes = currentState.newAttributes; + // silently ignore degenerate uv triangles having coincident or colinear vertices - for ( let i = 0, il = newAttributes.length; i < il; i ++ ) { + if ( ! isFinite( r ) ) return; - newAttributes[ i ] = 0; + sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); + tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); - } + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); - } + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); - function enableAttribute( attribute ) { + } - enableAttributeAndDivisor( attribute, 0 ); + let groups = this.groups; - } + if ( groups.length === 0 ) { - function enableAttributeAndDivisor( attribute, meshPerAttribute ) { + groups = [ { + start: 0, + count: indices.length + } ]; - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; - const attributeDivisors = currentState.attributeDivisors; + } - newAttributes[ attribute ] = 1; + for ( let i = 0, il = groups.length; i < il; ++ i ) { - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; + const group = groups[ i ]; - } + const start = group.start; + const count = group.count; - if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { + for ( let j = start, jl = start + count; j < jl; j += 3 ) { - const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); + handleTriangle( + indices[ j + 0 ], + indices[ j + 1 ], + indices[ j + 2 ] + ); - extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); - attributeDivisors[ attribute ] = meshPerAttribute; + } } - } + const tmp = new Vector3(), tmp2 = new Vector3(); + const n = new Vector3(), n2 = new Vector3(); - function disableUnusedAttributes() { + function handleVertex( v ) { - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; + n.fromArray( normals, v * 3 ); + n2.copy( n ); - for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) { + const t = tan1[ v ]; - if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { + // Gram-Schmidt orthogonalize - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - } + // Calculate handedness + + tmp2.crossVectors( n2, t ); + const test = tmp2.dot( tan2[ v ] ); + const w = ( test < 0.0 ) ? - 1.0 : 1.0; + + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; } - } + for ( let i = 0, il = groups.length; i < il; ++ i ) { - function vertexAttribPointer( index, size, type, normalized, stride, offset ) { + const group = groups[ i ]; - if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) { + const start = group.start; + const count = group.count; - gl.vertexAttribIPointer( index, size, type, stride, offset ); + for ( let j = start, jl = start + count; j < jl; j += 3 ) { - } else { + handleVertex( indices[ j + 0 ] ); + handleVertex( indices[ j + 1 ] ); + handleVertex( indices[ j + 2 ] ); - gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); + } } } - function setupVertexAttributes( object, material, program, geometry ) { + computeVertexNormals() { - if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) { + const index = this.index; + const positionAttribute = this.getAttribute( 'position' ); - if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return; + if ( positionAttribute !== undefined ) { - } + let normalAttribute = this.getAttribute( 'normal' ); - initAttributes(); + if ( normalAttribute === undefined ) { - const geometryAttributes = geometry.attributes; + normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); + this.setAttribute( 'normal', normalAttribute ); - const programAttributes = program.getAttributes(); + } else { - const materialDefaultAttributeValues = material.defaultAttributeValues; + // reset existing normals to zero - for ( const name in programAttributes ) { + for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { - const programAttribute = programAttributes[ name ]; + normalAttribute.setXYZ( i, 0, 0, 0 ); - if ( programAttribute.location >= 0 ) { + } - let geometryAttribute = geometryAttributes[ name ]; + } - if ( geometryAttribute === undefined ) { + const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); + const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); + const cb = new Vector3(), ab = new Vector3(); - if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; + // indexed elements - } + if ( index ) { - if ( geometryAttribute !== undefined ) { + for ( let i = 0, il = index.count; i < il; i += 3 ) { - const normalized = geometryAttribute.normalized; - const size = geometryAttribute.itemSize; + const vA = index.getX( i + 0 ); + const vB = index.getX( i + 1 ); + const vC = index.getX( i + 2 ); - const attribute = attributes.get( geometryAttribute ); + pA.fromBufferAttribute( positionAttribute, vA ); + pB.fromBufferAttribute( positionAttribute, vB ); + pC.fromBufferAttribute( positionAttribute, vC ); - // TODO Attribute may not be available on context restore + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - if ( attribute === undefined ) continue; + nA.fromBufferAttribute( normalAttribute, vA ); + nB.fromBufferAttribute( normalAttribute, vB ); + nC.fromBufferAttribute( normalAttribute, vC ); - const buffer = attribute.buffer; - const type = attribute.type; - const bytesPerElement = attribute.bytesPerElement; + nA.add( cb ); + nB.add( cb ); + nC.add( cb ); - if ( geometryAttribute.isInterleavedBufferAttribute ) { + normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); + normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); + normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); - const data = geometryAttribute.data; - const stride = data.stride; - const offset = geometryAttribute.offset; + } - if ( data.isInstancedInterleavedBuffer ) { + } else { - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { + // non-indexed elements (unconnected triangle soup) - enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute ); + for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { - } + pA.fromBufferAttribute( positionAttribute, i + 0 ); + pB.fromBufferAttribute( positionAttribute, i + 1 ); + pC.fromBufferAttribute( positionAttribute, i + 2 ); - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - geometry._maxInstanceCount = data.meshPerAttribute * data.count; + normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); + normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); + normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); - } + } - } else { + } - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { + this.normalizeNormals(); - enableAttribute( programAttribute.location + i ); + normalAttribute.needsUpdate = true; - } + } - } + } - gl.bindBuffer( 34962, buffer ); + // @deprecated since r144 - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { + merge() { - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - stride * bytesPerElement, - ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement - ); + console.error( 'THREE.BufferGeometry.merge() has been removed. Use THREE.BufferGeometryUtils.mergeBufferGeometries() instead.' ); + return this; - } + } - } else { + normalizeNormals() { - if ( geometryAttribute.isInstancedBufferAttribute ) { + const normals = this.attributes.normal; - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { + for ( let i = 0, il = normals.count; i < il; i ++ ) { - enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute ); + _vector$8.fromBufferAttribute( normals, i ); - } + _vector$8.normalize(); - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { + normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); - geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; + } - } + } - } else { + toNonIndexed() { - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { + function convertBufferAttribute( attribute, indices ) { - enableAttribute( programAttribute.location + i ); + const array = attribute.array; + const itemSize = attribute.itemSize; + const normalized = attribute.normalized; - } + const array2 = new array.constructor( indices.length * itemSize ); - } + let index = 0, index2 = 0; - gl.bindBuffer( 34962, buffer ); + for ( let i = 0, l = indices.length; i < l; i ++ ) { - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { + if ( attribute.isInterleavedBufferAttribute ) { - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - size * bytesPerElement, - ( size / programAttribute.locationSize ) * i * bytesPerElement - ); + index = indices[ i ] * attribute.data.stride + attribute.offset; - } + } else { - } + index = indices[ i ] * itemSize; - } else if ( materialDefaultAttributeValues !== undefined ) { + } - const value = materialDefaultAttributeValues[ name ]; + for ( let j = 0; j < itemSize; j ++ ) { - if ( value !== undefined ) { + array2[ index2 ++ ] = array[ index ++ ]; - switch ( value.length ) { + } - case 2: - gl.vertexAttrib2fv( programAttribute.location, value ); - break; + } - case 3: - gl.vertexAttrib3fv( programAttribute.location, value ); - break; + return new BufferAttribute( array2, itemSize, normalized ); - case 4: - gl.vertexAttrib4fv( programAttribute.location, value ); - break; + } - default: - gl.vertexAttrib1fv( programAttribute.location, value ); + // - } + if ( this.index === null ) { - } + console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); + return this; - } + } - } + const geometry2 = new BufferGeometry(); - } + const indices = this.index.array; + const attributes = this.attributes; - disableUnusedAttributes(); + // attributes - } + for ( const name in attributes ) { - function dispose() { + const attribute = attributes[ name ]; - reset(); + const newAttribute = convertBufferAttribute( attribute, indices ); - for ( const geometryId in bindingStates ) { + geometry2.setAttribute( name, newAttribute ); - const programMap = bindingStates[ geometryId ]; + } - for ( const programId in programMap ) { + // morph attributes - const stateMap = programMap[ programId ]; + const morphAttributes = this.morphAttributes; - for ( const wireframe in stateMap ) { + for ( const name in morphAttributes ) { - deleteVertexArrayObject( stateMap[ wireframe ].object ); + const morphArray = []; + const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - delete stateMap[ wireframe ]; + for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { - } + const attribute = morphAttribute[ i ]; - delete programMap[ programId ]; + const newAttribute = convertBufferAttribute( attribute, indices ); + + morphArray.push( newAttribute ); } - delete bindingStates[ geometryId ]; + geometry2.morphAttributes[ name ] = morphArray; } - } + geometry2.morphTargetsRelative = this.morphTargetsRelative; - function releaseStatesOfGeometry( geometry ) { + // groups - if ( bindingStates[ geometry.id ] === undefined ) return; + const groups = this.groups; - const programMap = bindingStates[ geometry.id ]; + for ( let i = 0, l = groups.length; i < l; i ++ ) { - for ( const programId in programMap ) { + const group = groups[ i ]; + geometry2.addGroup( group.start, group.count, group.materialIndex ); - const stateMap = programMap[ programId ]; + } - for ( const wireframe in stateMap ) { + return geometry2; - deleteVertexArrayObject( stateMap[ wireframe ].object ); + } - delete stateMap[ wireframe ]; + toJSON() { + const data = { + metadata: { + version: 4.5, + type: 'BufferGeometry', + generator: 'BufferGeometry.toJSON' } + }; - delete programMap[ programId ]; + // standard BufferGeometry serialization - } + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; + if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; - delete bindingStates[ geometry.id ]; + if ( this.parameters !== undefined ) { - } + const parameters = this.parameters; - function releaseStatesOfProgram( program ) { + for ( const key in parameters ) { - for ( const geometryId in bindingStates ) { + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - const programMap = bindingStates[ geometryId ]; + } - if ( programMap[ program.id ] === undefined ) continue; + return data; - const stateMap = programMap[ program.id ]; + } - for ( const wireframe in stateMap ) { + // for simplicity the code assumes attributes are not shared across geometries, see #15811 - deleteVertexArrayObject( stateMap[ wireframe ].object ); + data.data = { attributes: {} }; - delete stateMap[ wireframe ]; + const index = this.index; - } + if ( index !== null ) { - delete programMap[ program.id ]; + data.data.index = { + type: index.array.constructor.name, + array: Array.prototype.slice.call( index.array ) + }; } - } - - function reset() { + const attributes = this.attributes; - resetDefaultState(); - forceUpdate = true; + for ( const key in attributes ) { - if ( currentState === defaultState ) return; + const attribute = attributes[ key ]; - currentState = defaultState; - bindVertexArrayObject( currentState.object ); + data.data.attributes[ key ] = attribute.toJSON( data.data ); - } + } - // for backward-compatibility + const morphAttributes = {}; + let hasMorphAttributes = false; - function resetDefaultState() { + for ( const key in this.morphAttributes ) { - defaultState.geometry = null; - defaultState.program = null; - defaultState.wireframe = false; + const attributeArray = this.morphAttributes[ key ]; - } + const array = []; - return { + for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - setup: setup, - reset: reset, - resetDefaultState: resetDefaultState, - dispose: dispose, - releaseStatesOfGeometry: releaseStatesOfGeometry, - releaseStatesOfProgram: releaseStatesOfProgram, + const attribute = attributeArray[ i ]; - initAttributes: initAttributes, - enableAttribute: enableAttribute, - disableUnusedAttributes: disableUnusedAttributes + array.push( attribute.toJSON( data.data ) ); - }; + } - } + if ( array.length > 0 ) { - function WebGLBufferRenderer( gl, extensions, info, capabilities ) { + morphAttributes[ key ] = array; - const isWebGL2 = capabilities.isWebGL2; + hasMorphAttributes = true; - let mode; + } - function setMode( value ) { + } - mode = value; + if ( hasMorphAttributes ) { - } + data.data.morphAttributes = morphAttributes; + data.data.morphTargetsRelative = this.morphTargetsRelative; - function render( start, count ) { + } - gl.drawArrays( mode, start, count ); + const groups = this.groups; - info.update( count, mode, 1 ); + if ( groups.length > 0 ) { - } + data.data.groups = JSON.parse( JSON.stringify( groups ) ); - function renderInstances( start, count, primcount ) { + } - if ( primcount === 0 ) return; + const boundingSphere = this.boundingSphere; - let extension, methodName; + if ( boundingSphere !== null ) { - if ( isWebGL2 ) { + data.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + }; - extension = gl; - methodName = 'drawArraysInstanced'; + } - } else { + return data; - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawArraysInstancedANGLE'; + } - if ( extension === null ) { + clone() { - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + return new this.constructor().copy( this ); - } + } - } + copy( source ) { - extension[ methodName ]( mode, start, count, primcount ); + // reset - info.update( count, mode, primcount ); + this.index = null; + this.attributes = {}; + this.morphAttributes = {}; + this.groups = []; + this.boundingBox = null; + this.boundingSphere = null; - } + // used for storing cloned, shared data - // + const data = {}; - this.setMode = setMode; - this.render = render; - this.renderInstances = renderInstances; + // name - } + this.name = source.name; - function WebGLCapabilities( gl, extensions, parameters ) { + // index - let maxAnisotropy; + const index = source.index; - function getMaxAnisotropy() { + if ( index !== null ) { - if ( maxAnisotropy !== undefined ) return maxAnisotropy; + this.setIndex( index.clone( data ) ); - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { + } - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + // attributes - maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); + const attributes = source.attributes; - } else { + for ( const name in attributes ) { - maxAnisotropy = 0; + const attribute = attributes[ name ]; + this.setAttribute( name, attribute.clone( data ) ); } - return maxAnisotropy; + // morph attributes - } + const morphAttributes = source.morphAttributes; - function getMaxPrecision( precision ) { + for ( const name in morphAttributes ) { - if ( precision === 'highp' ) { + const array = []; + const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { + for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { - return 'highp'; + array.push( morphAttribute[ i ].clone( data ) ); } - precision = 'mediump'; + this.morphAttributes[ name ] = array; } - if ( precision === 'mediump' ) { + this.morphTargetsRelative = source.morphTargetsRelative; - if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { + // groups - return 'mediump'; + const groups = source.groups; - } + for ( let i = 0, l = groups.length; i < l; i ++ ) { + + const group = groups[ i ]; + this.addGroup( group.start, group.count, group.materialIndex ); } - return 'lowp'; + // bounding box - } + const boundingBox = source.boundingBox; - const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) || - ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext ); + if ( boundingBox !== null ) { - let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; - const maxPrecision = getMaxPrecision( precision ); - - if ( maxPrecision !== precision ) { - - console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); - precision = maxPrecision; + this.boundingBox = boundingBox.clone(); - } + } - const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ); + // bounding sphere - const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; + const boundingSphere = source.boundingSphere; - const maxTextures = gl.getParameter( 34930 ); - const maxVertexTextures = gl.getParameter( 35660 ); - const maxTextureSize = gl.getParameter( 3379 ); - const maxCubemapSize = gl.getParameter( 34076 ); + if ( boundingSphere !== null ) { - const maxAttributes = gl.getParameter( 34921 ); - const maxVertexUniforms = gl.getParameter( 36347 ); - const maxVaryings = gl.getParameter( 36348 ); - const maxFragmentUniforms = gl.getParameter( 36349 ); + this.boundingSphere = boundingSphere.clone(); - const vertexTextures = maxVertexTextures > 0; - const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); - const floatVertexTextures = vertexTextures && floatFragmentTextures; + } - const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0; + // draw range - return { + this.drawRange.start = source.drawRange.start; + this.drawRange.count = source.drawRange.count; - isWebGL2: isWebGL2, + // user data - drawBuffers: drawBuffers, + this.userData = source.userData; - getMaxAnisotropy: getMaxAnisotropy, - getMaxPrecision: getMaxPrecision, + // geometry generator parameters - precision: precision, - logarithmicDepthBuffer: logarithmicDepthBuffer, + if ( source.parameters !== undefined ) this.parameters = Object.assign( {}, source.parameters ); - maxTextures: maxTextures, - maxVertexTextures: maxVertexTextures, - maxTextureSize: maxTextureSize, - maxCubemapSize: maxCubemapSize, + return this; - maxAttributes: maxAttributes, - maxVertexUniforms: maxVertexUniforms, - maxVaryings: maxVaryings, - maxFragmentUniforms: maxFragmentUniforms, + } - vertexTextures: vertexTextures, - floatFragmentTextures: floatFragmentTextures, - floatVertexTextures: floatVertexTextures, + dispose() { - maxSamples: maxSamples + this.dispatchEvent( { type: 'dispose' } ); - }; + } } - function WebGLClipping( properties ) { + const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); + const _ray$2 = /*@__PURE__*/ new Ray(); + const _sphere$3 = /*@__PURE__*/ new Sphere(); - const scope = this; + const _vA$1 = /*@__PURE__*/ new Vector3(); + const _vB$1 = /*@__PURE__*/ new Vector3(); + const _vC$1 = /*@__PURE__*/ new Vector3(); - let globalState = null, - numGlobalPlanes = 0, - localClippingEnabled = false, - renderingShadows = false; + const _tempA = /*@__PURE__*/ new Vector3(); + const _tempB = /*@__PURE__*/ new Vector3(); + const _tempC = /*@__PURE__*/ new Vector3(); - const plane = new Plane(), - viewNormalMatrix = new Matrix3(), + const _morphA = /*@__PURE__*/ new Vector3(); + const _morphB = /*@__PURE__*/ new Vector3(); + const _morphC = /*@__PURE__*/ new Vector3(); - uniform = { value: null, needsUpdate: false }; + const _uvA$1 = /*@__PURE__*/ new Vector2(); + const _uvB$1 = /*@__PURE__*/ new Vector2(); + const _uvC$1 = /*@__PURE__*/ new Vector2(); - this.uniform = uniform; - this.numPlanes = 0; - this.numIntersection = 0; + const _intersectionPoint = /*@__PURE__*/ new Vector3(); + const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); - this.init = function ( planes, enableLocalClipping, camera ) { + class Mesh extends Object3D { - const enabled = - planes.length !== 0 || - enableLocalClipping || - // enable state of previous frame - the clipping code has to - // run another frame in order to reset the state: - numGlobalPlanes !== 0 || - localClippingEnabled; + constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { - localClippingEnabled = enableLocalClipping; + super(); - globalState = projectPlanes( planes, camera, 0 ); - numGlobalPlanes = planes.length; + this.isMesh = true; - return enabled; + this.type = 'Mesh'; - }; + this.geometry = geometry; + this.material = material; - this.beginShadows = function () { + this.updateMorphTargets(); - renderingShadows = true; - projectPlanes( null ); + } - }; + copy( source, recursive ) { - this.endShadows = function () { + super.copy( source, recursive ); - renderingShadows = false; - resetGlobalState(); + if ( source.morphTargetInfluences !== undefined ) { - }; + this.morphTargetInfluences = source.morphTargetInfluences.slice(); - this.setState = function ( material, camera, useCache ) { + } - const planes = material.clippingPlanes, - clipIntersection = material.clipIntersection, - clipShadows = material.clipShadows; + if ( source.morphTargetDictionary !== undefined ) { - const materialProperties = properties.get( material ); + this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); - if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { + } - // there's no local clipping + this.material = source.material; + this.geometry = source.geometry; - if ( renderingShadows ) { + return this; - // there's no global clipping + } - projectPlanes( null ); + updateMorphTargets() { - } else { + const geometry = this.geometry; - resetGlobalState(); + const morphAttributes = geometry.morphAttributes; + const keys = Object.keys( morphAttributes ); - } + if ( keys.length > 0 ) { - } else { + const morphAttribute = morphAttributes[ keys[ 0 ] ]; - const nGlobal = renderingShadows ? 0 : numGlobalPlanes, - lGlobal = nGlobal * 4; + if ( morphAttribute !== undefined ) { - let dstArray = materialProperties.clippingState || null; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - uniform.value = dstArray; // ensure unique state + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - dstArray = projectPlanes( planes, camera, lGlobal, useCache ); + const name = morphAttribute[ m ].name || String( m ); - for ( let i = 0; i !== lGlobal; ++ i ) { + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; - dstArray[ i ] = globalState[ i ]; + } } - materialProperties.clippingState = dstArray; - this.numIntersection = clipIntersection ? this.numPlanes : 0; - this.numPlanes += nGlobal; - } + } - }; + raycast( raycaster, intersects ) { - function resetGlobalState() { + const geometry = this.geometry; + const material = this.material; + const matrixWorld = this.matrixWorld; - if ( uniform.value !== globalState ) { + if ( material === undefined ) return; - uniform.value = globalState; - uniform.needsUpdate = numGlobalPlanes > 0; + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere$3.copy( geometry.boundingSphere ); + _sphere$3.applyMatrix4( matrixWorld ); + + if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; + + // + + _inverseMatrix$2.copy( matrixWorld ).invert(); + _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); + + // Check boundingBox before continuing + + if ( geometry.boundingBox !== null ) { + + if ( _ray$2.intersectsBox( geometry.boundingBox ) === false ) return; } - scope.numPlanes = numGlobalPlanes; - scope.numIntersection = 0; + let intersection; - } + const index = geometry.index; + const position = geometry.attributes.position; + const morphPosition = geometry.morphAttributes.position; + const morphTargetsRelative = geometry.morphTargetsRelative; + const uv = geometry.attributes.uv; + const uv2 = geometry.attributes.uv2; + const groups = geometry.groups; + const drawRange = geometry.drawRange; - function projectPlanes( planes, camera, dstOffset, skipTransform ) { + if ( index !== null ) { - const nPlanes = planes !== null ? planes.length : 0; - let dstArray = null; + // indexed buffer geometry - if ( nPlanes !== 0 ) { + if ( Array.isArray( material ) ) { - dstArray = uniform.value; + for ( let i = 0, il = groups.length; i < il; i ++ ) { - if ( skipTransform !== true || dstArray === null ) { + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; - const flatSize = dstOffset + nPlanes * 4, - viewMatrix = camera.matrixWorldInverse; + const start = Math.max( group.start, drawRange.start ); + const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); - viewNormalMatrix.getNormalMatrix( viewMatrix ); + for ( let j = start, jl = end; j < jl; j += 3 ) { - if ( dstArray === null || dstArray.length < flatSize ) { + const a = index.getX( j ); + const b = index.getX( j + 1 ); + const c = index.getX( j + 2 ); - dstArray = new Float32Array( flatSize ); + intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - } + if ( intersection ) { - for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { + intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics + intersection.face.materialIndex = group.materialIndex; + intersects.push( intersection ); - plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); + } - plane.normal.toArray( dstArray, i4 ); - dstArray[ i4 + 3 ] = plane.constant; + } } - } - - uniform.value = dstArray; - uniform.needsUpdate = true; + } else { - } + const start = Math.max( 0, drawRange.start ); + const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - scope.numPlanes = nPlanes; - scope.numIntersection = 0; + for ( let i = start, il = end; i < il; i += 3 ) { - return dstArray; + const a = index.getX( i ); + const b = index.getX( i + 1 ); + const c = index.getX( i + 2 ); - } + intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - } + if ( intersection ) { - function WebGLCubeMaps( renderer ) { + intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics + intersects.push( intersection ); - let cubemaps = new WeakMap(); + } - function mapTextureMapping( texture, mapping ) { + } - if ( mapping === EquirectangularReflectionMapping ) { + } - texture.mapping = CubeReflectionMapping; + } else if ( position !== undefined ) { - } else if ( mapping === EquirectangularRefractionMapping ) { + // non-indexed buffer geometry - texture.mapping = CubeRefractionMapping; + if ( Array.isArray( material ) ) { - } + for ( let i = 0, il = groups.length; i < il; i ++ ) { - return texture; + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; - } + const start = Math.max( group.start, drawRange.start ); + const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); - function get( texture ) { + for ( let j = start, jl = end; j < jl; j += 3 ) { - if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) { + const a = j; + const b = j + 1; + const c = j + 2; - const mapping = texture.mapping; + intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { + if ( intersection ) { - if ( cubemaps.has( texture ) ) { + intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics + intersection.face.materialIndex = group.materialIndex; + intersects.push( intersection ); - const cubemap = cubemaps.get( texture ).texture; - return mapTextureMapping( cubemap, texture.mapping ); + } - } else { + } - const image = texture.image; + } - if ( image && image.height > 0 ) { + } else { - const renderTarget = new WebGLCubeRenderTarget( image.height / 2 ); - renderTarget.fromEquirectangularTexture( renderer, texture ); - cubemaps.set( texture, renderTarget ); + const start = Math.max( 0, drawRange.start ); + const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); - texture.addEventListener( 'dispose', onTextureDispose ); + for ( let i = start, il = end; i < il; i += 3 ) { - return mapTextureMapping( renderTarget.texture, texture.mapping ); + const a = i; + const b = i + 1; + const c = i + 2; - } else { + intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - // image not yet ready. try the conversion next frame + if ( intersection ) { - return null; + intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics + intersects.push( intersection ); } @@ -24763,5398 +55955,5341 @@ var app = (function () { } - return texture; - } - function onTextureDispose( event ) { + } - const texture = event.target; + function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { - texture.removeEventListener( 'dispose', onTextureDispose ); + let intersect; - const cubemap = cubemaps.get( texture ); + if ( material.side === BackSide ) { - if ( cubemap !== undefined ) { + intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - cubemaps.delete( texture ); - cubemap.dispose(); + } else { - } + intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); } - function dispose() { + if ( intersect === null ) return null; - cubemaps = new WeakMap(); + _intersectionPointWorld.copy( point ); + _intersectionPointWorld.applyMatrix4( object.matrixWorld ); - } + const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); + + if ( distance < raycaster.near || distance > raycaster.far ) return null; return { - get: get, - dispose: dispose + distance: distance, + point: _intersectionPointWorld.clone(), + object: object }; } - class OrthographicCamera extends Camera { - - constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { - - super(); - - this.isOrthographicCamera = true; - - this.type = 'OrthographicCamera'; - - this.zoom = 1; - this.view = null; + function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; + _vA$1.fromBufferAttribute( position, a ); + _vB$1.fromBufferAttribute( position, b ); + _vC$1.fromBufferAttribute( position, c ); - this.near = near; - this.far = far; + const morphInfluences = object.morphTargetInfluences; - this.updateProjectionMatrix(); + if ( morphPosition && morphInfluences ) { - } + _morphA.set( 0, 0, 0 ); + _morphB.set( 0, 0, 0 ); + _morphC.set( 0, 0, 0 ); - copy( source, recursive ) { + for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { - super.copy( source, recursive ); + const influence = morphInfluences[ i ]; + const morphAttribute = morphPosition[ i ]; - this.left = source.left; - this.right = source.right; - this.top = source.top; - this.bottom = source.bottom; - this.near = source.near; - this.far = source.far; + if ( influence === 0 ) continue; - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); + _tempA.fromBufferAttribute( morphAttribute, a ); + _tempB.fromBufferAttribute( morphAttribute, b ); + _tempC.fromBufferAttribute( morphAttribute, c ); - return this; + if ( morphTargetsRelative ) { - } + _morphA.addScaledVector( _tempA, influence ); + _morphB.addScaledVector( _tempB, influence ); + _morphC.addScaledVector( _tempC, influence ); - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { + } else { - if ( this.view === null ) { + _morphA.addScaledVector( _tempA.sub( _vA$1 ), influence ); + _morphB.addScaledVector( _tempB.sub( _vB$1 ), influence ); + _morphC.addScaledVector( _tempC.sub( _vC$1 ), influence ); - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; + } } - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); + _vA$1.add( _morphA ); + _vB$1.add( _morphB ); + _vC$1.add( _morphC ); } - clearViewOffset() { + if ( object.isSkinnedMesh ) { - if ( this.view !== null ) { + object.boneTransform( a, _vA$1 ); + object.boneTransform( b, _vB$1 ); + object.boneTransform( c, _vC$1 ); - this.view.enabled = false; + } - } + const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); - this.updateProjectionMatrix(); + if ( intersection ) { - } + if ( uv ) { - updateProjectionMatrix() { + _uvA$1.fromBufferAttribute( uv, a ); + _uvB$1.fromBufferAttribute( uv, b ); + _uvC$1.fromBufferAttribute( uv, c ); - const dx = ( this.right - this.left ) / ( 2 * this.zoom ); - const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); - const cx = ( this.right + this.left ) / 2; - const cy = ( this.top + this.bottom ) / 2; + intersection.uv = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); - let left = cx - dx; - let right = cx + dx; - let top = cy + dy; - let bottom = cy - dy; + } - if ( this.view !== null && this.view.enabled ) { + if ( uv2 ) { - const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; - const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; + _uvA$1.fromBufferAttribute( uv2, a ); + _uvB$1.fromBufferAttribute( uv2, b ); + _uvC$1.fromBufferAttribute( uv2, c ); - left += scaleW * this.view.offsetX; - right = left + scaleW * this.view.width; - top -= scaleH * this.view.offsetY; - bottom = top - scaleH * this.view.height; + intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); } - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); + const face = { + a: a, + b: b, + c: c, + normal: new Vector3(), + materialIndex: 0 + }; - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); + Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); - } + intersection.face = face; - toJSON( meta ) { + } - const data = super.toJSON( meta ); + return intersection; - data.object.zoom = this.zoom; - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; + } - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + class BoxGeometry extends BufferGeometry { - return data; + constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { - } + super(); - } + this.type = 'BoxGeometry'; - const LOD_MIN = 4; + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; - // The standard deviations (radians) associated with the extra mips. These are - // chosen to approximate a Trowbridge-Reitz distribution function times the - // geometric shadowing function. These sigma values squared must match the - // variance #defines in cube_uv_reflection_fragment.glsl.js. - const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; + const scope = this; - // The maximum length of the blur for loop. Smaller sigmas will use fewer - // samples and exit early, but not recompile the shader. - const MAX_SAMPLES = 20; + // segments - const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); - const _clearColor = /*@__PURE__*/ new Color(); - let _oldTarget = null; + widthSegments = Math.floor( widthSegments ); + heightSegments = Math.floor( heightSegments ); + depthSegments = Math.floor( depthSegments ); - // Golden Ratio - const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; - const INV_PHI = 1 / PHI; + // buffers - // Vertices of a dodecahedron (except the opposites, which represent the - // same axis), used as axis directions evenly spread on a sphere. - const _axisDirections = [ - /*@__PURE__*/ new Vector3( 1, 1, 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, 1 ), - /*@__PURE__*/ new Vector3( 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), - /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), - /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), - /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ]; + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - /** - * This class generates a Prefiltered, Mipmapped Radiance Environment Map - * (PMREM) from a cubeMap environment texture. This allows different levels of - * blur to be quickly accessed based on material roughness. It is packed into a - * special CubeUV format that allows us to perform custom interpolation so that - * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap - * chain, it only goes down to the LOD_MIN level (above), and then creates extra - * even more filtered 'mips' at the same LOD_MIN resolution, associated with - * higher roughness levels. In this way we maintain resolution to smoothly - * interpolate diffuse lighting while limiting sampling computation. - * - * Paper: Fast, Accurate Image-Based Lighting - * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view - */ + // helper variables - class PMREMGenerator { + let numberOfVertices = 0; + let groupStart = 0; - constructor( renderer ) { + // build each side of the box geometry - this._renderer = renderer; - this._pingPongRenderTarget = null; + buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px + buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx + buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py + buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny + buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz + buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz - this._lodMax = 0; - this._cubeSize = 0; - this._lodPlanes = []; - this._sizeLods = []; - this._sigmas = []; + // build geometry - this._blurMaterial = null; - this._cubemapMaterial = null; - this._equirectMaterial = null; + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - this._compileMaterial( this._blurMaterial ); + function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { - } + const segmentWidth = width / gridX; + const segmentHeight = height / gridY; - /** - * Generates a PMREM from a supplied Scene, which can be faster than using an - * image if networking bandwidth is low. Optional sigma specifies a blur radius - * in radians to be applied to the scene before PMREM generation. Optional near - * and far planes ensure the scene is rendered in its entirety (the cubeCamera - * is placed at the origin). - */ - fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { + const widthHalf = width / 2; + const heightHalf = height / 2; + const depthHalf = depth / 2; - _oldTarget = this._renderer.getRenderTarget(); + const gridX1 = gridX + 1; + const gridY1 = gridY + 1; - this._setSize( 256 ); + let vertexCounter = 0; + let groupCount = 0; - const cubeUVRenderTarget = this._allocateTargets(); - cubeUVRenderTarget.depthBuffer = true; + const vector = new Vector3(); - this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); + // generate vertices, normals and uvs - if ( sigma > 0 ) { + for ( let iy = 0; iy < gridY1; iy ++ ) { - this._blur( cubeUVRenderTarget, 0, 0, sigma ); + const y = iy * segmentHeight - heightHalf; - } + for ( let ix = 0; ix < gridX1; ix ++ ) { - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); + const x = ix * segmentWidth - widthHalf; - return cubeUVRenderTarget; + // set values to correct vector component - } + vector[ u ] = x * udir; + vector[ v ] = y * vdir; + vector[ w ] = depthHalf; - /** - * Generates a PMREM from an equirectangular texture, which can be either LDR - * or HDR. The ideal input image size is 1k (1024 x 512), - * as this matches best with the 256 x 256 cubemap output. - */ - fromEquirectangular( equirectangular, renderTarget = null ) { + // now apply vector to vertex buffer - return this._fromTexture( equirectangular, renderTarget ); + vertices.push( vector.x, vector.y, vector.z ); - } + // set values to correct vector component - /** - * Generates a PMREM from an cubemap texture, which can be either LDR - * or HDR. The ideal input cube size is 256 x 256, - * as this matches best with the 256 x 256 cubemap output. - */ - fromCubemap( cubemap, renderTarget = null ) { + vector[ u ] = 0; + vector[ v ] = 0; + vector[ w ] = depth > 0 ? 1 : - 1; - return this._fromTexture( cubemap, renderTarget ); + // now apply vector to normal buffer - } + normals.push( vector.x, vector.y, vector.z ); - /** - * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileCubemapShader() { + // uvs - if ( this._cubemapMaterial === null ) { + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); - this._cubemapMaterial = _getCubemapMaterial(); - this._compileMaterial( this._cubemapMaterial ); + // counters - } + vertexCounter += 1; - } + } - /** - * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileEquirectangularShader() { + } - if ( this._equirectMaterial === null ) { + // indices - this._equirectMaterial = _getEquirectMaterial(); - this._compileMaterial( this._equirectMaterial ); + // 1. you need three indices to draw a single face + // 2. a single segment consists of two faces + // 3. so we need to generate six (2*3) indices per segment - } + for ( let iy = 0; iy < gridY; iy ++ ) { - } + for ( let ix = 0; ix < gridX; ix ++ ) { - /** - * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, - * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on - * one of them will cause any others to also become unusable. - */ - dispose() { + const a = numberOfVertices + ix + gridX1 * iy; + const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); + const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); + const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; - this._dispose(); + // faces - if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); - if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); + indices.push( a, b, d ); + indices.push( b, c, d ); - } + // increase counter - // private interface + groupCount += 6; - _setSize( cubeSize ) { + } - this._lodMax = Math.floor( Math.log2( cubeSize ) ); - this._cubeSize = Math.pow( 2, this._lodMax ); + } - } + // add a group to the geometry. this will ensure multi material support - _dispose() { + scope.addGroup( groupStart, groupCount, materialIndex ); - if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); + // calculate new start value for groups - if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); + groupStart += groupCount; - for ( let i = 0; i < this._lodPlanes.length; i ++ ) { + // update total number of vertices - this._lodPlanes[ i ].dispose(); + numberOfVertices += vertexCounter; } } - _cleanup( outputTarget ) { + static fromJSON( data ) { - this._renderer.setRenderTarget( _oldTarget ); - outputTarget.scissorTest = false; - _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); + return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); } - _fromTexture( texture, renderTarget ) { + } - if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { + /** + * Uniform Utilities + */ - this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); + function cloneUniforms( src ) { - } else { // Equirectangular + const dst = {}; - this._setSize( texture.image.width / 4 ); + for ( const u in src ) { - } + dst[ u ] = {}; - _oldTarget = this._renderer.getRenderTarget(); + for ( const p in src[ u ] ) { - const cubeUVRenderTarget = renderTarget || this._allocateTargets(); - this._textureToCubeUV( texture, cubeUVRenderTarget ); - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); + const property = src[ u ][ p ]; - return cubeUVRenderTarget; + if ( property && ( property.isColor || + property.isMatrix3 || property.isMatrix4 || + property.isVector2 || property.isVector3 || property.isVector4 || + property.isTexture || property.isQuaternion ) ) { - } + dst[ u ][ p ] = property.clone(); - _allocateTargets() { + } else if ( Array.isArray( property ) ) { - const width = 3 * Math.max( this._cubeSize, 16 * 7 ); - const height = 4 * this._cubeSize; + dst[ u ][ p ] = property.slice(); - const params = { - magFilter: LinearFilter, - minFilter: LinearFilter, - generateMipmaps: false, - type: HalfFloatType, - format: RGBAFormat, - encoding: LinearEncoding, - depthBuffer: false - }; + } else { - const cubeUVRenderTarget = _createRenderTarget( width, height, params ); + dst[ u ][ p ] = property; - if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width ) { + } - if ( this._pingPongRenderTarget !== null ) { + } - this._dispose(); + } - } + return dst; - this._pingPongRenderTarget = _createRenderTarget( width, height, params ); + } - const { _lodMax } = this; - ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); + function mergeUniforms( uniforms ) { - this._blurMaterial = _getBlurShader( _lodMax, width, height ); + const merged = {}; - } + for ( let u = 0; u < uniforms.length; u ++ ) { - return cubeUVRenderTarget; + const tmp = cloneUniforms( uniforms[ u ] ); - } + for ( const p in tmp ) { - _compileMaterial( material ) { + merged[ p ] = tmp[ p ]; - const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); - this._renderer.compile( tmpMesh, _flatCamera ); + } } - _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { - - const fov = 90; - const aspect = 1; - const cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); - const upSign = [ 1, - 1, 1, 1, 1, 1 ]; - const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; - const renderer = this._renderer; + return merged; - const originalAutoClear = renderer.autoClear; - const toneMapping = renderer.toneMapping; - renderer.getClearColor( _clearColor ); + } - renderer.toneMapping = NoToneMapping; - renderer.autoClear = false; + function cloneUniformsGroups( src ) { - const backgroundMaterial = new MeshBasicMaterial( { - name: 'PMREM.Background', - side: BackSide, - depthWrite: false, - depthTest: false, - } ); + const dst = []; - const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); + for ( let u = 0; u < src.length; u ++ ) { - let useSolidColor = false; - const background = scene.background; + dst.push( src[ u ].clone() ); - if ( background ) { + } - if ( background.isColor ) { + return dst; - backgroundMaterial.color.copy( background ); - scene.background = null; - useSolidColor = true; + } - } + // Legacy - } else { + const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; - backgroundMaterial.color.copy( _clearColor ); - useSolidColor = true; + var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; - } + var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; - for ( let i = 0; i < 6; i ++ ) { + class ShaderMaterial extends Material { - const col = i % 3; + constructor( parameters ) { - if ( col === 0 ) { + super(); - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); + this.isShaderMaterial = true; - } else if ( col === 1 ) { + this.type = 'ShaderMaterial'; - cubeCamera.up.set( 0, 0, upSign[ i ] ); - cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); + this.defines = {}; + this.uniforms = {}; + this.uniformsGroups = []; - } else { + this.vertexShader = default_vertex; + this.fragmentShader = default_fragment; - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); + this.linewidth = 1; - } + this.wireframe = false; + this.wireframeLinewidth = 1; - const size = this._cubeSize; + this.fog = false; // set to use scene fog + this.lights = false; // set to use scene lights + this.clipping = false; // set to use user-defined clipping planes - _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); + this.extensions = { + derivatives: false, // set to use derivatives + fragDepth: false, // set to use fragment depth values + drawBuffers: false, // set to use draw buffers + shaderTextureLOD: false // set to use shader texture LOD + }; - renderer.setRenderTarget( cubeUVRenderTarget ); + // When rendered geometry doesn't include these attributes but the material does, + // use these default values in WebGL. This avoids errors when buffer data is missing. + this.defaultAttributeValues = { + 'color': [ 1, 1, 1 ], + 'uv': [ 0, 0 ], + 'uv2': [ 0, 0 ] + }; - if ( useSolidColor ) { + this.index0AttributeName = undefined; + this.uniformsNeedUpdate = false; - renderer.render( backgroundBox, cubeCamera ); + this.glslVersion = null; - } + if ( parameters !== undefined ) { - renderer.render( scene, cubeCamera ); + this.setValues( parameters ); } - backgroundBox.geometry.dispose(); - backgroundBox.material.dispose(); + } - renderer.toneMapping = toneMapping; - renderer.autoClear = originalAutoClear; - scene.background = background; + copy( source ) { - } + super.copy( source ); - _textureToCubeUV( texture, cubeUVRenderTarget ) { + this.fragmentShader = source.fragmentShader; + this.vertexShader = source.vertexShader; - const renderer = this._renderer; + this.uniforms = cloneUniforms( source.uniforms ); + this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); - const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); + this.defines = Object.assign( {}, source.defines ); - if ( isCubeTexture ) { + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - if ( this._cubemapMaterial === null ) { + this.fog = source.fog; + this.lights = source.lights; + this.clipping = source.clipping; - this._cubemapMaterial = _getCubemapMaterial(); + this.extensions = Object.assign( {}, source.extensions ); - } + this.glslVersion = source.glslVersion; - this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1; + return this; - } else { + } - if ( this._equirectMaterial === null ) { + toJSON( meta ) { - this._equirectMaterial = _getEquirectMaterial(); + const data = super.toJSON( meta ); - } + data.glslVersion = this.glslVersion; + data.uniforms = {}; - } + for ( const name in this.uniforms ) { - const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; - const mesh = new Mesh( this._lodPlanes[ 0 ], material ); + const uniform = this.uniforms[ name ]; + const value = uniform.value; - const uniforms = material.uniforms; + if ( value && value.isTexture ) { - uniforms[ 'envMap' ].value = texture; + data.uniforms[ name ] = { + type: 't', + value: value.toJSON( meta ).uuid + }; - const size = this._cubeSize; + } else if ( value && value.isColor ) { - _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); + data.uniforms[ name ] = { + type: 'c', + value: value.getHex() + }; - renderer.setRenderTarget( cubeUVRenderTarget ); - renderer.render( mesh, _flatCamera ); + } else if ( value && value.isVector2 ) { - } + data.uniforms[ name ] = { + type: 'v2', + value: value.toArray() + }; - _applyPMREM( cubeUVRenderTarget ) { + } else if ( value && value.isVector3 ) { - const renderer = this._renderer; - const autoClear = renderer.autoClear; - renderer.autoClear = false; + data.uniforms[ name ] = { + type: 'v3', + value: value.toArray() + }; - for ( let i = 1; i < this._lodPlanes.length; i ++ ) { + } else if ( value && value.isVector4 ) { - const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); + data.uniforms[ name ] = { + type: 'v4', + value: value.toArray() + }; - const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ]; + } else if ( value && value.isMatrix3 ) { - this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); + data.uniforms[ name ] = { + type: 'm3', + value: value.toArray() + }; - } + } else if ( value && value.isMatrix4 ) { - renderer.autoClear = autoClear; + data.uniforms[ name ] = { + type: 'm4', + value: value.toArray() + }; - } + } else { - /** - * This is a two-pass Gaussian blur for a cubemap. Normally this is done - * vertically and horizontally, but this breaks down on a cube. Here we apply - * the blur latitudinally (around the poles), and then longitudinally (towards - * the poles) to approximate the orthogonally-separable blur. It is least - * accurate at the poles, but still does a decent job. - */ - _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { + data.uniforms[ name ] = { + value: value + }; - const pingPongRenderTarget = this._pingPongRenderTarget; + // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far - this._halfBlur( - cubeUVRenderTarget, - pingPongRenderTarget, - lodIn, - lodOut, - sigma, - 'latitudinal', - poleAxis ); + } - this._halfBlur( - pingPongRenderTarget, - cubeUVRenderTarget, - lodOut, - lodOut, - sigma, - 'longitudinal', - poleAxis ); + } - } + if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; - _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { + data.vertexShader = this.vertexShader; + data.fragmentShader = this.fragmentShader; - const renderer = this._renderer; - const blurMaterial = this._blurMaterial; + const extensions = {}; - if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { + for ( const key in this.extensions ) { - console.error( - 'blur direction must be either latitudinal or longitudinal!' ); + if ( this.extensions[ key ] === true ) extensions[ key ] = true; } - // Number of standard deviations at which to cut off the discrete approximation. - const STANDARD_DEVIATIONS = 3; + if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; - const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial ); - const blurUniforms = blurMaterial.uniforms; + return data; - const pixels = this._sizeLods[ lodIn ] - 1; - const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); - const sigmaPixels = sigmaRadians / radiansPerPixel; - const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; + } - if ( samples > MAX_SAMPLES ) { + } - console.warn( `sigmaRadians, ${ - sigmaRadians}, is too large and will clip, as it requested ${ - samples} samples when the maximum is set to ${MAX_SAMPLES}` ); + class Camera extends Object3D { - } + constructor() { - const weights = []; - let sum = 0; + super(); - for ( let i = 0; i < MAX_SAMPLES; ++ i ) { + this.isCamera = true; - const x = i / sigmaPixels; - const weight = Math.exp( - x * x / 2 ); - weights.push( weight ); + this.type = 'Camera'; - if ( i === 0 ) { + this.matrixWorldInverse = new Matrix4(); - sum += weight; + this.projectionMatrix = new Matrix4(); + this.projectionMatrixInverse = new Matrix4(); - } else if ( i < samples ) { + } - sum += 2 * weight; + copy( source, recursive ) { - } + super.copy( source, recursive ); - } + this.matrixWorldInverse.copy( source.matrixWorldInverse ); - for ( let i = 0; i < weights.length; i ++ ) { + this.projectionMatrix.copy( source.projectionMatrix ); + this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); - weights[ i ] = weights[ i ] / sum; + return this; - } + } - blurUniforms[ 'envMap' ].value = targetIn.texture; - blurUniforms[ 'samples' ].value = samples; - blurUniforms[ 'weights' ].value = weights; - blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; + getWorldDirection( target ) { - if ( poleAxis ) { + this.updateWorldMatrix( true, false ); - blurUniforms[ 'poleAxis' ].value = poleAxis; + const e = this.matrixWorld.elements; - } + return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); - const { _lodMax } = this; - blurUniforms[ 'dTheta' ].value = radiansPerPixel; - blurUniforms[ 'mipInt' ].value = _lodMax - lodIn; + } - const outputSize = this._sizeLods[ lodOut ]; - const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); - const y = 4 * ( this._cubeSize - outputSize ); + updateMatrixWorld( force ) { - _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); - renderer.setRenderTarget( targetOut ); - renderer.render( blurMesh, _flatCamera ); + super.updateMatrixWorld( force ); + + this.matrixWorldInverse.copy( this.matrixWorld ).invert(); } - } + updateWorldMatrix( updateParents, updateChildren ) { + super.updateWorldMatrix( updateParents, updateChildren ); + this.matrixWorldInverse.copy( this.matrixWorld ).invert(); - function _createPlanes( lodMax ) { + } - const lodPlanes = []; - const sizeLods = []; - const sigmas = []; + clone() { - let lod = lodMax; + return new this.constructor().copy( this ); - const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; + } - for ( let i = 0; i < totalLods; i ++ ) { + } - const sizeLod = Math.pow( 2, lod ); - sizeLods.push( sizeLod ); - let sigma = 1.0 / sizeLod; + class PerspectiveCamera extends Camera { - if ( i > lodMax - LOD_MIN ) { + constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { - sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; + super(); - } else if ( i === 0 ) { + this.isPerspectiveCamera = true; - sigma = 0; + this.type = 'PerspectiveCamera'; - } + this.fov = fov; + this.zoom = 1; - sigmas.push( sigma ); + this.near = near; + this.far = far; + this.focus = 10; - const texelSize = 1.0 / ( sizeLod - 2 ); - const min = - texelSize; - const max = 1 + texelSize; - const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; + this.aspect = aspect; + this.view = null; - const cubeFaces = 6; - const vertices = 6; - const positionSize = 3; - const uvSize = 2; - const faceIndexSize = 1; + this.filmGauge = 35; // width of the film (default in millimeters) + this.filmOffset = 0; // horizontal film offset (same unit as gauge) - const position = new Float32Array( positionSize * vertices * cubeFaces ); - const uv = new Float32Array( uvSize * vertices * cubeFaces ); - const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); + this.updateProjectionMatrix(); - for ( let face = 0; face < cubeFaces; face ++ ) { + } - const x = ( face % 3 ) * 2 / 3 - 1; - const y = face > 2 ? 0 : - 1; - const coordinates = [ - x, y, 0, - x + 2 / 3, y, 0, - x + 2 / 3, y + 1, 0, - x, y, 0, - x + 2 / 3, y + 1, 0, - x, y + 1, 0 - ]; - position.set( coordinates, positionSize * vertices * face ); - uv.set( uv1, uvSize * vertices * face ); - const fill = [ face, face, face, face, face, face ]; - faceIndex.set( fill, faceIndexSize * vertices * face ); + copy( source, recursive ) { - } + super.copy( source, recursive ); - const planes = new BufferGeometry(); - planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); - planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); - planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); - lodPlanes.push( planes ); + this.fov = source.fov; + this.zoom = source.zoom; - if ( lod > LOD_MIN ) { + this.near = source.near; + this.far = source.far; + this.focus = source.focus; - lod --; + this.aspect = source.aspect; + this.view = source.view === null ? null : Object.assign( {}, source.view ); - } + this.filmGauge = source.filmGauge; + this.filmOffset = source.filmOffset; + + return this; } - return { lodPlanes, sizeLods, sigmas }; + /** + * Sets the FOV by focal length in respect to the current .filmGauge. + * + * The default film gauge is 35, so that the focal length can be specified for + * a 35mm (full frame) camera. + * + * Values for focal length and film gauge must have the same unit. + */ + setFocalLength( focalLength ) { - } + /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ + const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; - function _createRenderTarget( width, height, params ) { + this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); + this.updateProjectionMatrix(); - const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params ); - cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; - cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; - cubeUVRenderTarget.scissorTest = true; - return cubeUVRenderTarget; + } - } + /** + * Calculates the focal length from the current .fov and .filmGauge. + */ + getFocalLength() { - function _setViewport( target, x, y, width, height ) { + const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); - target.viewport.set( x, y, width, height ); - target.scissor.set( x, y, width, height ); + return 0.5 * this.getFilmHeight() / vExtentSlope; - } + } - function _getBlurShader( lodMax, width, height ) { + getEffectiveFOV() { - const weights = new Float32Array( MAX_SAMPLES ); - const poleAxis = new Vector3( 0, 1, 0 ); - const shaderMaterial = new ShaderMaterial( { + return RAD2DEG * 2 * Math.atan( + Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); - name: 'SphericalGaussianBlur', + } - defines: { - 'n': MAX_SAMPLES, - 'CUBEUV_TEXEL_WIDTH': 1.0 / width, - 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, - 'CUBEUV_MAX_MIP': `${lodMax}.0`, - }, + getFilmWidth() { - uniforms: { - 'envMap': { value: null }, - 'samples': { value: 1 }, - 'weights': { value: weights }, - 'latitudinal': { value: false }, - 'dTheta': { value: 0 }, - 'mipInt': { value: 0 }, - 'poleAxis': { value: poleAxis } - }, + // film not completely covered in portrait format (aspect < 1) + return this.filmGauge * Math.min( this.aspect, 1 ); - vertexShader: _getCommonVertexShader(), + } - fragmentShader: /* glsl */` + getFilmHeight() { - precision mediump float; - precision mediump int; + // film not completely covered in landscape format (aspect > 1) + return this.filmGauge / Math.max( this.aspect, 1 ); - varying vec3 vOutputDirection; + } - uniform sampler2D envMap; - uniform int samples; - uniform float weights[ n ]; - uniform bool latitudinal; - uniform float dTheta; - uniform float mipInt; - uniform vec3 poleAxis; + /** + * Sets an offset in a larger frustum. This is useful for multi-window or + * multi-monitor/multi-machine setups. + * + * For example, if you have 3x2 monitors and each monitor is 1920x1080 and + * the monitors are in grid like this + * + * +---+---+---+ + * | A | B | C | + * +---+---+---+ + * | D | E | F | + * +---+---+---+ + * + * then for each monitor you would call it like this + * + * const w = 1920; + * const h = 1080; + * const fullWidth = w * 3; + * const fullHeight = h * 2; + * + * --A-- + * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); + * --B-- + * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); + * --C-- + * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); + * --D-- + * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); + * --E-- + * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); + * --F-- + * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); + * + * Note there is no reason monitors have to be the same size or in a grid. + */ + setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - #define ENVMAP_TYPE_CUBE_UV - #include + this.aspect = fullWidth / fullHeight; - vec3 getSample( float theta, vec3 axis ) { + if ( this.view === null ) { - float cosTheta = cos( theta ); - // Rodrigues' axis-angle rotation - vec3 sampleDirection = vOutputDirection * cosTheta - + cross( axis, vOutputDirection ) * sin( theta ) - + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; - return bilinearCubeUV( envMap, sampleDirection, mipInt ); + } - } + this.view.enabled = true; + this.view.fullWidth = fullWidth; + this.view.fullHeight = fullHeight; + this.view.offsetX = x; + this.view.offsetY = y; + this.view.width = width; + this.view.height = height; - void main() { + this.updateProjectionMatrix(); - vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); + } - if ( all( equal( axis, vec3( 0.0 ) ) ) ) { + clearViewOffset() { - axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); + if ( this.view !== null ) { - } + this.view.enabled = false; - axis = normalize( axis ); + } - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); + this.updateProjectionMatrix(); - for ( int i = 1; i < n; i++ ) { + } - if ( i >= samples ) { + updateProjectionMatrix() { - break; + const near = this.near; + let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; + let height = 2 * top; + let width = this.aspect * height; + let left = - 0.5 * width; + const view = this.view; - } + if ( this.view !== null && this.view.enabled ) { - float theta = dTheta * float( i ); - gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); - gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); + const fullWidth = view.fullWidth, + fullHeight = view.fullHeight; - } + left += view.offsetX * width / fullWidth; + top -= view.offsetY * height / fullHeight; + width *= view.width / fullWidth; + height *= view.height / fullHeight; - } - `, + } - blending: NoBlending, - depthTest: false, - depthWrite: false + const skew = this.filmOffset; + if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - } ); + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); - return shaderMaterial; + this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); - } + } - function _getEquirectMaterial() { + toJSON( meta ) { - return new ShaderMaterial( { + const data = super.toJSON( meta ); - name: 'EquirectangularToCubeUV', + data.object.fov = this.fov; + data.object.zoom = this.zoom; - uniforms: { - 'envMap': { value: null } - }, + data.object.near = this.near; + data.object.far = this.far; + data.object.focus = this.focus; - vertexShader: _getCommonVertexShader(), + data.object.aspect = this.aspect; - fragmentShader: /* glsl */` + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - precision mediump float; - precision mediump int; + data.object.filmGauge = this.filmGauge; + data.object.filmOffset = this.filmOffset; - varying vec3 vOutputDirection; + return data; - uniform sampler2D envMap; + } - #include + } - void main() { + const fov = 90, aspect = 1; - vec3 outputDirection = normalize( vOutputDirection ); - vec2 uv = equirectUv( outputDirection ); + class CubeCamera extends Object3D { - gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); + constructor( near, far, renderTarget ) { - } - `, + super(); - blending: NoBlending, - depthTest: false, - depthWrite: false + this.type = 'CubeCamera'; - } ); + this.renderTarget = renderTarget; - } + const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); + cameraPX.layers = this.layers; + cameraPX.up.set( 0, - 1, 0 ); + cameraPX.lookAt( new Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); - function _getCubemapMaterial() { + const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); + cameraNX.layers = this.layers; + cameraNX.up.set( 0, - 1, 0 ); + cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); + this.add( cameraNX ); - return new ShaderMaterial( { + const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); + cameraPY.layers = this.layers; + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); - name: 'CubemapToCubeUV', + const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); + cameraNY.layers = this.layers; + cameraNY.up.set( 0, 0, - 1 ); + cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); + this.add( cameraNY ); - uniforms: { - 'envMap': { value: null }, - 'flipEnvMap': { value: - 1 } - }, + const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.layers = this.layers; + cameraPZ.up.set( 0, - 1, 0 ); + cameraPZ.lookAt( new Vector3( 0, 0, 1 ) ); + this.add( cameraPZ ); - vertexShader: _getCommonVertexShader(), + const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.layers = this.layers; + cameraNZ.up.set( 0, - 1, 0 ); + cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); + this.add( cameraNZ ); - fragmentShader: /* glsl */` + } - precision mediump float; - precision mediump int; + update( renderer, scene ) { - uniform float flipEnvMap; + if ( this.parent === null ) this.updateMatrixWorld(); - varying vec3 vOutputDirection; + const renderTarget = this.renderTarget; - uniform samplerCube envMap; + const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; - void main() { + const currentRenderTarget = renderer.getRenderTarget(); - gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); + const currentToneMapping = renderer.toneMapping; + const currentXrEnabled = renderer.xr.enabled; - } - `, + renderer.toneMapping = NoToneMapping; + renderer.xr.enabled = false; - blending: NoBlending, - depthTest: false, - depthWrite: false + const generateMipmaps = renderTarget.texture.generateMipmaps; - } ); + renderTarget.texture.generateMipmaps = false; - } + renderer.setRenderTarget( renderTarget, 0 ); + renderer.render( scene, cameraPX ); - function _getCommonVertexShader() { + renderer.setRenderTarget( renderTarget, 1 ); + renderer.render( scene, cameraNX ); - return /* glsl */` + renderer.setRenderTarget( renderTarget, 2 ); + renderer.render( scene, cameraPY ); - precision mediump float; - precision mediump int; + renderer.setRenderTarget( renderTarget, 3 ); + renderer.render( scene, cameraNY ); - attribute float faceIndex; + renderer.setRenderTarget( renderTarget, 4 ); + renderer.render( scene, cameraPZ ); - varying vec3 vOutputDirection; - - // RH coordinate system; PMREM face-indexing convention - vec3 getDirection( vec2 uv, float face ) { - - uv = 2.0 * uv - 1.0; + renderTarget.texture.generateMipmaps = generateMipmaps; - vec3 direction = vec3( uv, 1.0 ); + renderer.setRenderTarget( renderTarget, 5 ); + renderer.render( scene, cameraNZ ); - if ( face == 0.0 ) { + renderer.setRenderTarget( currentRenderTarget ); - direction = direction.zyx; // ( 1, v, u ) pos x + renderer.toneMapping = currentToneMapping; + renderer.xr.enabled = currentXrEnabled; - } else if ( face == 1.0 ) { + renderTarget.texture.needsPMREMUpdate = true; - direction = direction.xzy; - direction.xz *= -1.0; // ( -u, 1, -v ) pos y + } - } else if ( face == 2.0 ) { + } - direction.x *= -1.0; // ( -u, v, 1 ) pos z + class CubeTexture extends Texture { - } else if ( face == 3.0 ) { + constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - direction = direction.zyx; - direction.xz *= -1.0; // ( -1, v, -u ) neg x + images = images !== undefined ? images : []; + mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - } else if ( face == 4.0 ) { + super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - direction = direction.xzy; - direction.xy *= -1.0; // ( -u, -1, v ) neg y + this.isCubeTexture = true; - } else if ( face == 5.0 ) { + this.flipY = false; - direction.z *= -1.0; // ( u, v, -1 ) neg z + } - } + get images() { - return direction; + return this.image; - } + } - void main() { + set images( value ) { - vOutputDirection = getDirection( uv, faceIndex ); - gl_Position = vec4( position, 1.0 ); + this.image = value; - } - `; + } } - function WebGLCubeUVMaps( renderer ) { - - let cubeUVmaps = new WeakMap(); - - let pmremGenerator = null; - - function get( texture ) { + class WebGLCubeRenderTarget extends WebGLRenderTarget { - if ( texture && texture.isTexture ) { + constructor( size, options = {} ) { - const mapping = texture.mapping; + super( size, size, options ); - const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ); - const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); + this.isWebGLCubeRenderTarget = true; - // equirect/cube map to cubeUV conversion + const image = { width: size, height: size, depth: 1 }; + const images = [ image, image, image, image, image, image ]; - if ( isEquirectMap || isCubeMap ) { + this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) { + // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) + // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, + // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. - texture.needsPMREMUpdate = false; + // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped + // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture + // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). - let renderTarget = cubeUVmaps.get( texture ); + this.texture.isRenderTargetTexture = true; - if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); + this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; + this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget ); - cubeUVmaps.set( texture, renderTarget ); + } - return renderTarget.texture; + fromEquirectangularTexture( renderer, texture ) { - } else { + this.texture.type = texture.type; + this.texture.encoding = texture.encoding; - if ( cubeUVmaps.has( texture ) ) { + this.texture.generateMipmaps = texture.generateMipmaps; + this.texture.minFilter = texture.minFilter; + this.texture.magFilter = texture.magFilter; - return cubeUVmaps.get( texture ).texture; + const shader = { - } else { + uniforms: { + tEquirect: { value: null }, + }, - const image = texture.image; + vertexShader: /* glsl */` - if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) { + varying vec3 vWorldDirection; - if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { - const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture ); - cubeUVmaps.set( texture, renderTarget ); + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); - texture.addEventListener( 'dispose', onTextureDispose ); + } - return renderTarget.texture; + void main() { - } else { + vWorldDirection = transformDirection( position, modelMatrix ); - // image not yet ready. try the conversion next frame + #include + #include - return null; + } + `, - } + fragmentShader: /* glsl */` - } + uniform sampler2D tEquirect; - } + varying vec3 vWorldDirection; - } + #include - } + void main() { - return texture; + vec3 direction = normalize( vWorldDirection ); - } + vec2 sampleUV = equirectUv( direction ); - function isCubeTextureComplete( image ) { + gl_FragColor = texture2D( tEquirect, sampleUV ); - let count = 0; - const length = 6; + } + ` + }; - for ( let i = 0; i < length; i ++ ) { + const geometry = new BoxGeometry( 5, 5, 5 ); - if ( image[ i ] !== undefined ) count ++; + const material = new ShaderMaterial( { - } + name: 'CubemapFromEquirect', - return count === length; + uniforms: cloneUniforms( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + side: BackSide, + blending: NoBlending + } ); - } + material.uniforms.tEquirect.value = texture; - function onTextureDispose( event ) { + const mesh = new Mesh( geometry, material ); - const texture = event.target; + const currentMinFilter = texture.minFilter; - texture.removeEventListener( 'dispose', onTextureDispose ); + // Avoid blurred poles + if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; - const cubemapUV = cubeUVmaps.get( texture ); + const camera = new CubeCamera( 1, 10, this ); + camera.update( renderer, mesh ); - if ( cubemapUV !== undefined ) { + texture.minFilter = currentMinFilter; - cubeUVmaps.delete( texture ); - cubemapUV.dispose(); + mesh.geometry.dispose(); + mesh.material.dispose(); - } + return this; } - function dispose() { + clear( renderer, color, depth, stencil ) { - cubeUVmaps = new WeakMap(); + const currentRenderTarget = renderer.getRenderTarget(); - if ( pmremGenerator !== null ) { + for ( let i = 0; i < 6; i ++ ) { - pmremGenerator.dispose(); - pmremGenerator = null; + renderer.setRenderTarget( this, i ); + + renderer.clear( color, depth, stencil ); } - } + renderer.setRenderTarget( currentRenderTarget ); - return { - get: get, - dispose: dispose - }; + } } - function WebGLExtensions( gl ) { + const _vector1 = /*@__PURE__*/ new Vector3(); + const _vector2 = /*@__PURE__*/ new Vector3(); + const _normalMatrix = /*@__PURE__*/ new Matrix3(); - const extensions = {}; + class Plane { - function getExtension( name ) { + constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { - if ( extensions[ name ] !== undefined ) { + this.isPlane = true; - return extensions[ name ]; + // normal is assumed to be normalized - } + this.normal = normal; + this.constant = constant; - let extension; + } - switch ( name ) { + set( normal, constant ) { - case 'WEBGL_depth_texture': - extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); - break; + this.normal.copy( normal ); + this.constant = constant; - case 'EXT_texture_filter_anisotropic': - extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); - break; + return this; - case 'WEBGL_compressed_texture_s3tc': - extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); - break; + } - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); - break; + setComponents( x, y, z, w ) { - default: - extension = gl.getExtension( name ); + this.normal.set( x, y, z ); + this.constant = w; - } + return this; - extensions[ name ] = extension; + } - return extension; + setFromNormalAndCoplanarPoint( normal, point ) { + + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); + + return this; } - return { + setFromCoplanarPoints( a, b, c ) { - has: function ( name ) { + const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); - return getExtension( name ) !== null; + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - }, + this.setFromNormalAndCoplanarPoint( normal, a ); - init: function ( capabilities ) { + return this; - if ( capabilities.isWebGL2 ) { + } - getExtension( 'EXT_color_buffer_float' ); + copy( plane ) { - } else { + this.normal.copy( plane.normal ); + this.constant = plane.constant; - getExtension( 'WEBGL_depth_texture' ); - getExtension( 'OES_texture_float' ); - getExtension( 'OES_texture_half_float' ); - getExtension( 'OES_texture_half_float_linear' ); - getExtension( 'OES_standard_derivatives' ); - getExtension( 'OES_element_index_uint' ); - getExtension( 'OES_vertex_array_object' ); - getExtension( 'ANGLE_instanced_arrays' ); + return this; - } + } - getExtension( 'OES_texture_float_linear' ); - getExtension( 'EXT_color_buffer_half_float' ); - getExtension( 'WEBGL_multisampled_render_to_texture' ); + normalize() { - }, + // Note: will lead to a divide by zero if the plane is invalid. - get: function ( name ) { + const inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; - const extension = getExtension( name ); + return this; - if ( extension === null ) { + } - console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); + negate() { - } + this.constant *= - 1; + this.normal.negate(); - return extension; + return this; - } + } - }; + distanceToPoint( point ) { - } + return this.normal.dot( point ) + this.constant; - function WebGLGeometries( gl, attributes, info, bindingStates ) { + } - const geometries = {}; - const wireframeAttributes = new WeakMap(); + distanceToSphere( sphere ) { - function onGeometryDispose( event ) { + return this.distanceToPoint( sphere.center ) - sphere.radius; - const geometry = event.target; + } - if ( geometry.index !== null ) { + projectPoint( point, target ) { - attributes.remove( geometry.index ); + return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); - } + } - for ( const name in geometry.attributes ) { + intersectLine( line, target ) { - attributes.remove( geometry.attributes[ name ] ); + const direction = line.delta( _vector1 ); - } + const denominator = this.normal.dot( direction ); - geometry.removeEventListener( 'dispose', onGeometryDispose ); + if ( denominator === 0 ) { - delete geometries[ geometry.id ]; + // line is coplanar, return origin + if ( this.distanceToPoint( line.start ) === 0 ) { - const attribute = wireframeAttributes.get( geometry ); + return target.copy( line.start ); - if ( attribute ) { + } - attributes.remove( attribute ); - wireframeAttributes.delete( geometry ); + // Unsure if this is the correct method to handle this case. + return null; } - bindingStates.releaseStatesOfGeometry( geometry ); + const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - if ( geometry.isInstancedBufferGeometry === true ) { + if ( t < 0 || t > 1 ) { - delete geometry._maxInstanceCount; + return null; } - // - - info.memory.geometries --; + return target.copy( direction ).multiplyScalar( t ).add( line.start ); } - function get( object, geometry ) { + intersectsLine( line ) { - if ( geometries[ geometry.id ] === true ) return geometry; + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - geometry.addEventListener( 'dispose', onGeometryDispose ); + const startSign = this.distanceToPoint( line.start ); + const endSign = this.distanceToPoint( line.end ); - geometries[ geometry.id ] = true; + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - info.memory.geometries ++; + } - return geometry; + intersectsBox( box ) { + + return box.intersectsPlane( this ); } - function update( geometry ) { + intersectsSphere( sphere ) { - const geometryAttributes = geometry.attributes; + return sphere.intersectsPlane( this ); - // Updating index buffer in VAO now. See WebGLBindingStates. + } - for ( const name in geometryAttributes ) { + coplanarPoint( target ) { - attributes.update( geometryAttributes[ name ], 34962 ); + return target.copy( this.normal ).multiplyScalar( - this.constant ); - } + } - // morph targets + applyMatrix4( matrix, optionalNormalMatrix ) { - const morphAttributes = geometry.morphAttributes; + const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); - for ( const name in morphAttributes ) { + const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); - const array = morphAttributes[ name ]; + const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); - for ( let i = 0, l = array.length; i < l; i ++ ) { + this.constant = - referencePoint.dot( normal ); - attributes.update( array[ i ], 34962 ); + return this; - } + } - } + translate( offset ) { + + this.constant -= offset.dot( this.normal ); + + return this; } - function updateWireframeAttribute( geometry ) { + equals( plane ) { - const indices = []; + return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); - const geometryIndex = geometry.index; - const geometryPosition = geometry.attributes.position; - let version = 0; + } - if ( geometryIndex !== null ) { + clone() { - const array = geometryIndex.array; - version = geometryIndex.version; + return new this.constructor().copy( this ); - for ( let i = 0, l = array.length; i < l; i += 3 ) { + } - const a = array[ i + 0 ]; - const b = array[ i + 1 ]; - const c = array[ i + 2 ]; + } - indices.push( a, b, b, c, c, a ); + const _sphere$2 = /*@__PURE__*/ new Sphere(); + const _vector$7 = /*@__PURE__*/ new Vector3(); - } + class Frustum { - } else { + constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { - const array = geometryPosition.array; - version = geometryPosition.version; + this.planes = [ p0, p1, p2, p3, p4, p5 ]; - for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { + } - const a = i + 0; - const b = i + 1; - const c = i + 2; + set( p0, p1, p2, p3, p4, p5 ) { - indices.push( a, b, b, c, c, a ); + const planes = this.planes; - } + planes[ 0 ].copy( p0 ); + planes[ 1 ].copy( p1 ); + planes[ 2 ].copy( p2 ); + planes[ 3 ].copy( p3 ); + planes[ 4 ].copy( p4 ); + planes[ 5 ].copy( p5 ); - } + return this; - const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - attribute.version = version; + } - // Updating index buffer in VAO now. See WebGLBindingStates + copy( frustum ) { - // + const planes = this.planes; - const previousAttribute = wireframeAttributes.get( geometry ); + for ( let i = 0; i < 6; i ++ ) { - if ( previousAttribute ) attributes.remove( previousAttribute ); + planes[ i ].copy( frustum.planes[ i ] ); - // + } - wireframeAttributes.set( geometry, attribute ); + return this; } - function getWireframeAttribute( geometry ) { + setFromProjectionMatrix( m ) { - const currentAttribute = wireframeAttributes.get( geometry ); + const planes = this.planes; + const me = m.elements; + const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; + const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; + const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; + const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - if ( currentAttribute ) { + planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); + planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); + planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); + planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); + planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); - const geometryIndex = geometry.index; + return this; - if ( geometryIndex !== null ) { + } - // if the attribute is obsolete, create a new one + intersectsObject( object ) { - if ( currentAttribute.version < geometryIndex.version ) { + const geometry = object.geometry; - updateWireframeAttribute( geometry ); + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - } + _sphere$2.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - } + return this.intersectsSphere( _sphere$2 ); - } else { + } - updateWireframeAttribute( geometry ); + intersectsSprite( sprite ) { - } + _sphere$2.center.set( 0, 0, 0 ); + _sphere$2.radius = 0.7071067811865476; + _sphere$2.applyMatrix4( sprite.matrixWorld ); - return wireframeAttributes.get( geometry ); + return this.intersectsSphere( _sphere$2 ); } - return { + intersectsSphere( sphere ) { - get: get, - update: update, + const planes = this.planes; + const center = sphere.center; + const negRadius = - sphere.radius; - getWireframeAttribute: getWireframeAttribute + for ( let i = 0; i < 6; i ++ ) { - }; + const distance = planes[ i ].distanceToPoint( center ); - } + if ( distance < negRadius ) { - function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { + return false; - const isWebGL2 = capabilities.isWebGL2; + } - let mode; - - function setMode( value ) { + } - mode = value; + return true; } - let type, bytesPerElement; + intersectsBox( box ) { - function setIndex( value ) { + const planes = this.planes; - type = value.type; - bytesPerElement = value.bytesPerElement; + for ( let i = 0; i < 6; i ++ ) { - } + const plane = planes[ i ]; - function render( start, count ) { + // corner at max distance - gl.drawElements( mode, count, type, start * bytesPerElement ); + _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x; + _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y; + _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z; - info.update( count, mode, 1 ); + if ( plane.distanceToPoint( _vector$7 ) < 0 ) { - } + return false; - function renderInstances( start, count, primcount ) { + } - if ( primcount === 0 ) return; + } - let extension, methodName; + return true; - if ( isWebGL2 ) { + } - extension = gl; - methodName = 'drawElementsInstanced'; + containsPoint( point ) { - } else { + const planes = this.planes; - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawElementsInstancedANGLE'; + for ( let i = 0; i < 6; i ++ ) { - if ( extension === null ) { + if ( planes[ i ].distanceToPoint( point ) < 0 ) { - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + return false; } } - extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); - - info.update( count, mode, primcount ); + return true; } - // + clone() { - this.setMode = setMode; - this.setIndex = setIndex; - this.render = render; - this.renderInstances = renderInstances; + return new this.constructor().copy( this ); - } + } - function WebGLInfo( gl ) { + } - const memory = { - geometries: 0, - textures: 0 - }; + function WebGLAnimation() { - const render = { - frame: 0, - calls: 0, - triangles: 0, - points: 0, - lines: 0 - }; + let context = null; + let isAnimating = false; + let animationLoop = null; + let requestId = null; - function update( count, mode, instanceCount ) { + function onAnimationFrame( time, frame ) { - render.calls ++; + animationLoop( time, frame ); - switch ( mode ) { + requestId = context.requestAnimationFrame( onAnimationFrame ); - case 4: - render.triangles += instanceCount * ( count / 3 ); - break; + } - case 1: - render.lines += instanceCount * ( count / 2 ); - break; + return { - case 3: - render.lines += instanceCount * ( count - 1 ); - break; + start: function () { - case 2: - render.lines += instanceCount * count; - break; + if ( isAnimating === true ) return; + if ( animationLoop === null ) return; - case 0: - render.points += instanceCount * count; - break; + requestId = context.requestAnimationFrame( onAnimationFrame ); - default: - console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); - break; + isAnimating = true; - } + }, - } + stop: function () { - function reset() { + context.cancelAnimationFrame( requestId ); - render.frame ++; - render.calls = 0; - render.triangles = 0; - render.points = 0; - render.lines = 0; + isAnimating = false; - } + }, - return { - memory: memory, - render: render, - programs: null, - autoReset: true, - reset: reset, - update: update - }; + setAnimationLoop: function ( callback ) { - } + animationLoop = callback; - function numericalSort( a, b ) { + }, - return a[ 0 ] - b[ 0 ]; + setContext: function ( value ) { - } + context = value; - function absNumericalSort( a, b ) { + } - return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); + }; } - function WebGLMorphtargets( gl, capabilities, textures ) { - - const influencesList = {}; - const morphInfluences = new Float32Array( 8 ); - const morphTextures = new WeakMap(); - const morph = new Vector4(); - - const workInfluences = []; - - for ( let i = 0; i < 8; i ++ ) { - - workInfluences[ i ] = [ i, 0 ]; + function WebGLAttributes( gl, capabilities ) { - } + const isWebGL2 = capabilities.isWebGL2; - function update( object, geometry, material, program ) { + const buffers = new WeakMap(); - const objectInfluences = object.morphTargetInfluences; + function createBuffer( attribute, bufferType ) { - if ( capabilities.isWebGL2 === true ) { + const array = attribute.array; + const usage = attribute.usage; - // instead of using attributes, the WebGL 2 code path encodes morph targets - // into an array of data textures. Each layer represents a single morph target. + const buffer = gl.createBuffer(); - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + gl.bindBuffer( bufferType, buffer ); + gl.bufferData( bufferType, array, usage ); - let entry = morphTextures.get( geometry ); + attribute.onUploadCallback(); - if ( entry === undefined || entry.count !== morphTargetsCount ) { + let type; - if ( entry !== undefined ) entry.texture.dispose(); + if ( array instanceof Float32Array ) { - const hasMorphPosition = geometry.morphAttributes.position !== undefined; - const hasMorphNormals = geometry.morphAttributes.normal !== undefined; - const hasMorphColors = geometry.morphAttributes.color !== undefined; + type = 5126; - const morphTargets = geometry.morphAttributes.position || []; - const morphNormals = geometry.morphAttributes.normal || []; - const morphColors = geometry.morphAttributes.color || []; + } else if ( array instanceof Uint16Array ) { - let vertexDataCount = 0; + if ( attribute.isFloat16BufferAttribute ) { - if ( hasMorphPosition === true ) vertexDataCount = 1; - if ( hasMorphNormals === true ) vertexDataCount = 2; - if ( hasMorphColors === true ) vertexDataCount = 3; + if ( isWebGL2 ) { - let width = geometry.attributes.position.count * vertexDataCount; - let height = 1; + type = 5131; - if ( width > capabilities.maxTextureSize ) { + } else { - height = Math.ceil( width / capabilities.maxTextureSize ); - width = capabilities.maxTextureSize; + throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' ); } - const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); + } else { - const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); - texture.type = FloatType; - texture.needsUpdate = true; + type = 5123; - // fill buffer + } - const vertexDataStride = vertexDataCount * 4; + } else if ( array instanceof Int16Array ) { - for ( let i = 0; i < morphTargetsCount; i ++ ) { + type = 5122; - const morphTarget = morphTargets[ i ]; - const morphNormal = morphNormals[ i ]; - const morphColor = morphColors[ i ]; + } else if ( array instanceof Uint32Array ) { - const offset = width * height * 4 * i; + type = 5125; - for ( let j = 0; j < morphTarget.count; j ++ ) { + } else if ( array instanceof Int32Array ) { - const stride = j * vertexDataStride; + type = 5124; - if ( hasMorphPosition === true ) { + } else if ( array instanceof Int8Array ) { - morph.fromBufferAttribute( morphTarget, j ); + type = 5120; - buffer[ offset + stride + 0 ] = morph.x; - buffer[ offset + stride + 1 ] = morph.y; - buffer[ offset + stride + 2 ] = morph.z; - buffer[ offset + stride + 3 ] = 0; + } else if ( array instanceof Uint8Array ) { - } + type = 5121; - if ( hasMorphNormals === true ) { + } else if ( array instanceof Uint8ClampedArray ) { - morph.fromBufferAttribute( morphNormal, j ); + type = 5121; - buffer[ offset + stride + 4 ] = morph.x; - buffer[ offset + stride + 5 ] = morph.y; - buffer[ offset + stride + 6 ] = morph.z; - buffer[ offset + stride + 7 ] = 0; + } else { - } + throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array ); - if ( hasMorphColors === true ) { + } - morph.fromBufferAttribute( morphColor, j ); + return { + buffer: buffer, + type: type, + bytesPerElement: array.BYTES_PER_ELEMENT, + version: attribute.version + }; - buffer[ offset + stride + 8 ] = morph.x; - buffer[ offset + stride + 9 ] = morph.y; - buffer[ offset + stride + 10 ] = morph.z; - buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1; + } - } + function updateBuffer( buffer, attribute, bufferType ) { - } + const array = attribute.array; + const updateRange = attribute.updateRange; - } + gl.bindBuffer( bufferType, buffer ); - entry = { - count: morphTargetsCount, - texture: texture, - size: new Vector2( width, height ) - }; + if ( updateRange.count === - 1 ) { - morphTextures.set( geometry, entry ); + // Not using update ranges - function disposeTexture() { + gl.bufferSubData( bufferType, 0, array ); - texture.dispose(); + } else { - morphTextures.delete( geometry ); + if ( isWebGL2 ) { - geometry.removeEventListener( 'dispose', disposeTexture ); + gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, + array, updateRange.offset, updateRange.count ); - } + } else { - geometry.addEventListener( 'dispose', disposeTexture ); + gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, + array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); } - // + updateRange.count = - 1; // reset range - let morphInfluencesSum = 0; + } - for ( let i = 0; i < objectInfluences.length; i ++ ) { + } - morphInfluencesSum += objectInfluences[ i ]; + // - } + function get( attribute ) { - const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); - program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences ); + return buffers.get( attribute ); - program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures ); - program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size ); + } + function remove( attribute ) { - } else { + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - // When object doesn't have morph target influences defined, we treat it as a 0-length array - // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences + const data = buffers.get( attribute ); - const length = objectInfluences === undefined ? 0 : objectInfluences.length; + if ( data ) { - let influences = influencesList[ geometry.id ]; + gl.deleteBuffer( data.buffer ); - if ( influences === undefined || influences.length !== length ) { + buffers.delete( attribute ); - // initialise list + } - influences = []; + } - for ( let i = 0; i < length; i ++ ) { + function update( attribute, bufferType ) { - influences[ i ] = [ i, 0 ]; + if ( attribute.isGLBufferAttribute ) { - } + const cached = buffers.get( attribute ); - influencesList[ geometry.id ] = influences; + if ( ! cached || cached.version < attribute.version ) { + + buffers.set( attribute, { + buffer: attribute.buffer, + type: attribute.type, + bytesPerElement: attribute.elementSize, + version: attribute.version + } ); } - // Collect influences + return; - for ( let i = 0; i < length; i ++ ) { + } - const influence = influences[ i ]; + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - influence[ 0 ] = i; - influence[ 1 ] = objectInfluences[ i ]; + const data = buffers.get( attribute ); - } + if ( data === undefined ) { - influences.sort( absNumericalSort ); + buffers.set( attribute, createBuffer( attribute, bufferType ) ); - for ( let i = 0; i < 8; i ++ ) { + } else if ( data.version < attribute.version ) { - if ( i < length && influences[ i ][ 1 ] ) { + updateBuffer( data.buffer, attribute, bufferType ); - workInfluences[ i ][ 0 ] = influences[ i ][ 0 ]; - workInfluences[ i ][ 1 ] = influences[ i ][ 1 ]; + data.version = attribute.version; - } else { + } - workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER; - workInfluences[ i ][ 1 ] = 0; + } - } + return { - } + get: get, + remove: remove, + update: update - workInfluences.sort( numericalSort ); + }; - const morphTargets = geometry.morphAttributes.position; - const morphNormals = geometry.morphAttributes.normal; + } - let morphInfluencesSum = 0; + class PlaneGeometry extends BufferGeometry { - for ( let i = 0; i < 8; i ++ ) { + constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { - const influence = workInfluences[ i ]; - const index = influence[ 0 ]; - const value = influence[ 1 ]; + super(); - if ( index !== Number.MAX_SAFE_INTEGER && value ) { + this.type = 'PlaneGeometry'; - if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) { + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] ); + const width_half = width / 2; + const height_half = height / 2; - } + const gridX = Math.floor( widthSegments ); + const gridY = Math.floor( heightSegments ); - if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) { + const gridX1 = gridX + 1; + const gridY1 = gridY + 1; - geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] ); + const segment_width = width / gridX; + const segment_height = height / gridY; - } + // - morphInfluences[ i ] = value; - morphInfluencesSum += value; + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - } else { + for ( let iy = 0; iy < gridY1; iy ++ ) { - if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) { + const y = iy * segment_height - height_half; - geometry.deleteAttribute( 'morphTarget' + i ); + for ( let ix = 0; ix < gridX1; ix ++ ) { - } + const x = ix * segment_width - width_half; - if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) { + vertices.push( x, - y, 0 ); - geometry.deleteAttribute( 'morphNormal' + i ); + normals.push( 0, 0, 1 ); - } + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); - morphInfluences[ i ] = 0; + } - } + } - } + for ( let iy = 0; iy < gridY; iy ++ ) { - // GLSL shader uses formula baseinfluence * base + sum(target * influence) - // This allows us to switch between absolute morphs and relative morphs without changing shader code - // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence) - const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; + for ( let ix = 0; ix < gridX; ix ++ ) { - program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); - program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); + const a = ix + gridX1 * iy; + const b = ix + gridX1 * ( iy + 1 ); + const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + const d = ( ix + 1 ) + gridX1 * iy; + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } } + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + } - return { + static fromJSON( data ) { - update: update + return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); - }; + } } - function WebGLObjects( gl, geometries, attributes, info ) { + var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; - let updateMap = new WeakMap(); + var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - function update( object ) { + var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif"; - const frame = info.render.frame; + var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; - const geometry = object.geometry; - const buffergeometry = geometries.get( object, geometry ); + var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; - // Update once per frame + var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - if ( updateMap.get( buffergeometry ) !== frame ) { + var begin_vertex = "vec3 transformed = vec3( position );"; - geometries.update( buffergeometry ); + var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - updateMap.set( buffergeometry, frame ); + var bsdfs = "vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( V * D );\n}\n#ifdef USE_IRIDESCENCE\n\tvec3 BRDF_GGX_Iridescence( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float iridescence, const in vec3 iridescenceFresnel, const in float roughness ) {\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = mix( F_Schlick( f0, f90, dotVH ), iridescenceFresnel, iridescence );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif"; - } + var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\t return vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat R21 = R12;\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; - if ( object.isInstancedMesh ) { + var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos.xyz );\n\t\tvec3 vSigmaY = dFdy( surf_pos.xyz );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; - if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) { + var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif"; - object.addEventListener( 'dispose', onInstancedMeshDispose ); + var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; - } + var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; - attributes.update( object.instanceMatrix, 34962 ); + var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; - if ( object.instanceColor !== null ) { + var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; - attributes.update( object.instanceColor, 34962 ); + var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; - } + var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif"; - } + var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; - return buffergeometry; + var common$1 = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}"; - } + var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_v0 0.339\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_v1 0.276\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_v4 0.046\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_v5 0.016\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_v6 0.0038\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; - function dispose() { + var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; - updateMap = new WeakMap(); + var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; - } + var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif"; - function onInstancedMeshDispose( event ) { + var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; - const instancedMesh = event.target; + var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose ); + var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - attributes.remove( instancedMesh.instanceMatrix ); + var encodings_pars_fragment = "vec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}"; - if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor ); + var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; - } + var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif"; - return { + var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif"; - update: update, - dispose: dispose + var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif"; - }; + var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif"; - } + var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; - /** - * Uniforms of a program. - * Those form a tree structure with a special top-level container for the root, - * which you get by calling 'new WebGLUniforms( gl, program )'. - * - * - * Properties of inner nodes including the top-level container: - * - * .seq - array of nested uniforms - * .map - nested uniforms by name - * - * - * Methods of all nodes except the top-level container: - * - * .setValue( gl, value, [textures] ) - * - * uploads a uniform value(s) - * the 'textures' parameter is needed for sampler uniforms - * - * - * Static methods of the top-level container (textures factorizations): - * - * .upload( gl, seq, values, textures ) - * - * sets uniforms in 'seq' to 'values[id].value' - * - * .seqWithValue( seq, values ) : filteredSeq - * - * filters 'seq' entries with corresponding entry in values - * - * - * Methods of the top-level container (textures factorizations): - * - * .setValue( gl, name, value, textures ) - * - * sets uniform with name 'name' to 'value' - * - * .setOptional( gl, obj, prop ) - * - * like .set for an optional property of the object - * - */ + var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; - const emptyTexture = /*@__PURE__*/ new Texture(); - const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); - const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); - const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); + var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"; - // --- Utilities --- + var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif"; - // Array Caches (provide typed arrays for temporary by size) + var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; - const arrayCacheF32 = []; - const arrayCacheI32 = []; + var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; - // Float32Array caches used for uploading Matrix uniforms + var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; - const mat4array = new Float32Array( 16 ); - const mat3array = new Float32Array( 9 ); - const mat2array = new Float32Array( 4 ); + var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; - // Flattening for arrays of vectors and matrices + var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert\n#define Material_LightProbeLOD( material )\t(0)"; - function flatten( array, nBlocks, blockSize ) { + var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; - const firstElem = array[ 0 ]; + var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif"; - if ( firstElem <= 0 || firstElem > 0 ) return array; - // unoptimized: ! isNaN( firstElem ) - // see http://jacksondunstan.com/articles/983 + var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - const n = nBlocks * blockSize; - let r = arrayCacheF32[ n ]; + var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)"; - if ( r === undefined ) { + var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - r = new Float32Array( n ); - arrayCacheF32[ n ] = r; + var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)"; - } + var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARCOLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vUv ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vUv ).a;\n\t#endif\n#endif"; - if ( nBlocks !== 0 ) { + var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec3 sheenSpecular = vec3( 0.0 );\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX_Iridescence( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness );\n\t#else\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometry.normal, geometry.viewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; - firstElem.toArray( r, 0 ); + var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometry.viewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry.normal );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; - for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) { + var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry.normal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; - offset += blockSize; - array[ i ].toArray( r, offset ); + var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif"; - } + var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; - } + var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; - return r; + var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif"; - } + var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; - function arraysEqual( a, b ) { + var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; - if ( a.length !== b.length ) return false; + var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - for ( let i = 0, l = a.length; i < l; i ++ ) { + var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; - if ( a[ i ] !== b[ i ] ) return false; + var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - } + var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; - return true; + var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; - } + var morphcolor_vertex = "#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif"; - function copyArray( a, b ) { + var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif"; - for ( let i = 0, l = b.length; i < l; i ++ ) { + var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif"; - a[ i ] = b[ i ]; + var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; - } + var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;"; - } + var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; - // Texture unit allocation + var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - function allocTexUnits( textures, n ) { + var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - let r = arrayCacheI32[ n ]; + var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; - if ( r === undefined ) { + var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif"; - r = new Int32Array( n ); - arrayCacheI32[ n ] = r; + var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif"; - } + var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif"; - for ( let i = 0; i !== n; ++ i ) { + var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif"; - r[ i ] = textures.allocateTextureUnit(); + var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; - } + var output_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; - return r; + var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}"; - } + var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - // --- Setters --- + var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; - // Note: Defining these methods externally, because they come in a bunch - // and this way their names minify. + var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; - // Single scalar + var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; - function setValueV1f( gl, v ) { + var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; - const cache = this.cache; + var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - if ( cache[ 0 ] === v ) return; + var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; - gl.uniform1f( this.addr, v ); + var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; - cache[ 0 ] = v; + var shadowmap_vertex = "#if defined( USE_SHADOWMAP ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_COORDS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif"; - } + var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; - // Single float vector (from flat array or THREE.VectorN) + var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - function setValueV2f( gl, v ) { + var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tuniform int boneTextureSize;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tfloat j = i * 4.0;\n\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\ty = dy * ( y + 0.5 );\n\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\treturn bone;\n\t}\n#endif"; - const cache = this.cache; + var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; - if ( v.x !== undefined ) { + var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { + var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; - gl.uniform2f( this.addr, v.x, v.y ); + var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; + var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; - } + var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - } else { + var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmission.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n#endif"; - if ( arraysEqual( cache, v ) ) return; + var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef texture2DLodEXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif"; - gl.uniform2fv( this.addr, v ); + var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif"; - copyArray( cache, v ); + var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif"; - } + var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; - } + var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; - function setValueV3f( gl, v ) { + var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif"; - const cache = this.cache; + var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif"; - if ( v.x !== undefined ) { + var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { + const vertex$g = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; - gl.uniform3f( this.addr, v.x, v.y, v.z ); + const fragment$g = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tgl_FragColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tgl_FragColor = vec4( mix( pow( gl_FragColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), gl_FragColor.rgb * 0.0773993808, vec3( lessThanEqual( gl_FragColor.rgb, vec3( 0.04045 ) ) ) ), gl_FragColor.w );\n\t#endif\n\t#include \n\t#include \n}"; - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; + const vertex$f = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - } + const fragment$f = "#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; - } else if ( v.r !== undefined ) { + const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; - if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { + const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; - gl.uniform3f( this.addr, v.r, v.g, v.b ); + const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; - cache[ 0 ] = v.r; - cache[ 1 ] = v.g; - cache[ 2 ] = v.b; + const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; - } + const vertex$c = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; - } else { + const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; - if ( arraysEqual( cache, v ) ) return; + const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - gl.uniform3fv( this.addr, v ); + const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - copyArray( cache, v ); + const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - } + const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - } + const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - function setValueV4f( gl, v ) { + const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const cache = this.cache; + const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; - if ( v.x !== undefined ) { + const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { + const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; - gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); + const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; + const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - } + const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - } else { + const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; - if ( arraysEqual( cache, v ) ) return; + const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARCOLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - gl.uniform4fv( this.addr, v ); + const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; - copyArray( cache, v ); + const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - } + const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - } + const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - // Single matrix (from flat array or THREE.MatrixN) + const vertex$2 = "#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - function setValueM2( gl, v ) { + const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; - const cache = this.cache; - const elements = v.elements; + const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; - if ( elements === undefined ) { + const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - if ( arraysEqual( cache, v ) ) return; + const ShaderChunk = { + alphamap_fragment: alphamap_fragment, + alphamap_pars_fragment: alphamap_pars_fragment, + alphatest_fragment: alphatest_fragment, + alphatest_pars_fragment: alphatest_pars_fragment, + aomap_fragment: aomap_fragment, + aomap_pars_fragment: aomap_pars_fragment, + begin_vertex: begin_vertex, + beginnormal_vertex: beginnormal_vertex, + bsdfs: bsdfs, + iridescence_fragment: iridescence_fragment, + bumpmap_pars_fragment: bumpmap_pars_fragment, + clipping_planes_fragment: clipping_planes_fragment, + clipping_planes_pars_fragment: clipping_planes_pars_fragment, + clipping_planes_pars_vertex: clipping_planes_pars_vertex, + clipping_planes_vertex: clipping_planes_vertex, + color_fragment: color_fragment, + color_pars_fragment: color_pars_fragment, + color_pars_vertex: color_pars_vertex, + color_vertex: color_vertex, + common: common$1, + cube_uv_reflection_fragment: cube_uv_reflection_fragment, + defaultnormal_vertex: defaultnormal_vertex, + displacementmap_pars_vertex: displacementmap_pars_vertex, + displacementmap_vertex: displacementmap_vertex, + emissivemap_fragment: emissivemap_fragment, + emissivemap_pars_fragment: emissivemap_pars_fragment, + encodings_fragment: encodings_fragment, + encodings_pars_fragment: encodings_pars_fragment, + envmap_fragment: envmap_fragment, + envmap_common_pars_fragment: envmap_common_pars_fragment, + envmap_pars_fragment: envmap_pars_fragment, + envmap_pars_vertex: envmap_pars_vertex, + envmap_physical_pars_fragment: envmap_physical_pars_fragment, + envmap_vertex: envmap_vertex, + fog_vertex: fog_vertex, + fog_pars_vertex: fog_pars_vertex, + fog_fragment: fog_fragment, + fog_pars_fragment: fog_pars_fragment, + gradientmap_pars_fragment: gradientmap_pars_fragment, + lightmap_fragment: lightmap_fragment, + lightmap_pars_fragment: lightmap_pars_fragment, + lights_lambert_fragment: lights_lambert_fragment, + lights_lambert_pars_fragment: lights_lambert_pars_fragment, + lights_pars_begin: lights_pars_begin, + lights_toon_fragment: lights_toon_fragment, + lights_toon_pars_fragment: lights_toon_pars_fragment, + lights_phong_fragment: lights_phong_fragment, + lights_phong_pars_fragment: lights_phong_pars_fragment, + lights_physical_fragment: lights_physical_fragment, + lights_physical_pars_fragment: lights_physical_pars_fragment, + lights_fragment_begin: lights_fragment_begin, + lights_fragment_maps: lights_fragment_maps, + lights_fragment_end: lights_fragment_end, + logdepthbuf_fragment: logdepthbuf_fragment, + logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, + logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, + logdepthbuf_vertex: logdepthbuf_vertex, + map_fragment: map_fragment, + map_pars_fragment: map_pars_fragment, + map_particle_fragment: map_particle_fragment, + map_particle_pars_fragment: map_particle_pars_fragment, + metalnessmap_fragment: metalnessmap_fragment, + metalnessmap_pars_fragment: metalnessmap_pars_fragment, + morphcolor_vertex: morphcolor_vertex, + morphnormal_vertex: morphnormal_vertex, + morphtarget_pars_vertex: morphtarget_pars_vertex, + morphtarget_vertex: morphtarget_vertex, + normal_fragment_begin: normal_fragment_begin, + normal_fragment_maps: normal_fragment_maps, + normal_pars_fragment: normal_pars_fragment, + normal_pars_vertex: normal_pars_vertex, + normal_vertex: normal_vertex, + normalmap_pars_fragment: normalmap_pars_fragment, + clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, + clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, + clearcoat_pars_fragment: clearcoat_pars_fragment, + iridescence_pars_fragment: iridescence_pars_fragment, + output_fragment: output_fragment, + packing: packing, + premultiplied_alpha_fragment: premultiplied_alpha_fragment, + project_vertex: project_vertex, + dithering_fragment: dithering_fragment, + dithering_pars_fragment: dithering_pars_fragment, + roughnessmap_fragment: roughnessmap_fragment, + roughnessmap_pars_fragment: roughnessmap_pars_fragment, + shadowmap_pars_fragment: shadowmap_pars_fragment, + shadowmap_pars_vertex: shadowmap_pars_vertex, + shadowmap_vertex: shadowmap_vertex, + shadowmask_pars_fragment: shadowmask_pars_fragment, + skinbase_vertex: skinbase_vertex, + skinning_pars_vertex: skinning_pars_vertex, + skinning_vertex: skinning_vertex, + skinnormal_vertex: skinnormal_vertex, + specularmap_fragment: specularmap_fragment, + specularmap_pars_fragment: specularmap_pars_fragment, + tonemapping_fragment: tonemapping_fragment, + tonemapping_pars_fragment: tonemapping_pars_fragment, + transmission_fragment: transmission_fragment, + transmission_pars_fragment: transmission_pars_fragment, + uv_pars_fragment: uv_pars_fragment, + uv_pars_vertex: uv_pars_vertex, + uv_vertex: uv_vertex, + uv2_pars_fragment: uv2_pars_fragment, + uv2_pars_vertex: uv2_pars_vertex, + uv2_vertex: uv2_vertex, + worldpos_vertex: worldpos_vertex, - gl.uniformMatrix2fv( this.addr, false, v ); + background_vert: vertex$g, + background_frag: fragment$g, + cube_vert: vertex$f, + cube_frag: fragment$f, + depth_vert: vertex$e, + depth_frag: fragment$e, + distanceRGBA_vert: vertex$d, + distanceRGBA_frag: fragment$d, + equirect_vert: vertex$c, + equirect_frag: fragment$c, + linedashed_vert: vertex$b, + linedashed_frag: fragment$b, + meshbasic_vert: vertex$a, + meshbasic_frag: fragment$a, + meshlambert_vert: vertex$9, + meshlambert_frag: fragment$9, + meshmatcap_vert: vertex$8, + meshmatcap_frag: fragment$8, + meshnormal_vert: vertex$7, + meshnormal_frag: fragment$7, + meshphong_vert: vertex$6, + meshphong_frag: fragment$6, + meshphysical_vert: vertex$5, + meshphysical_frag: fragment$5, + meshtoon_vert: vertex$4, + meshtoon_frag: fragment$4, + points_vert: vertex$3, + points_frag: fragment$3, + shadow_vert: vertex$2, + shadow_frag: fragment$2, + sprite_vert: vertex$1, + sprite_frag: fragment$1 + }; - copyArray( cache, v ); + /** + * Uniforms library for shared webgl shaders + */ - } else { + const UniformsLib = { - if ( arraysEqual( cache, elements ) ) return; + common: { - mat2array.set( elements ); + diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, + opacity: { value: 1.0 }, - gl.uniformMatrix2fv( this.addr, false, mat2array ); + map: { value: null }, + uvTransform: { value: /*@__PURE__*/ new Matrix3() }, + uv2Transform: { value: /*@__PURE__*/ new Matrix3() }, - copyArray( cache, elements ); + alphaMap: { value: null }, + alphaTest: { value: 0 } - } + }, - } + specularmap: { - function setValueM3( gl, v ) { + specularMap: { value: null }, - const cache = this.cache; - const elements = v.elements; + }, - if ( elements === undefined ) { + envmap: { - if ( arraysEqual( cache, v ) ) return; + envMap: { value: null }, + flipEnvMap: { value: - 1 }, + reflectivity: { value: 1.0 }, // basic, lambert, phong + ior: { value: 1.5 }, // physical + refractionRatio: { value: 0.98 } // basic, lambert, phong - gl.uniformMatrix3fv( this.addr, false, v ); + }, - copyArray( cache, v ); + aomap: { - } else { + aoMap: { value: null }, + aoMapIntensity: { value: 1 } - if ( arraysEqual( cache, elements ) ) return; + }, - mat3array.set( elements ); + lightmap: { - gl.uniformMatrix3fv( this.addr, false, mat3array ); + lightMap: { value: null }, + lightMapIntensity: { value: 1 } - copyArray( cache, elements ); + }, - } + emissivemap: { - } + emissiveMap: { value: null } - function setValueM4( gl, v ) { + }, - const cache = this.cache; - const elements = v.elements; + bumpmap: { - if ( elements === undefined ) { + bumpMap: { value: null }, + bumpScale: { value: 1 } - if ( arraysEqual( cache, v ) ) return; + }, - gl.uniformMatrix4fv( this.addr, false, v ); + normalmap: { - copyArray( cache, v ); + normalMap: { value: null }, + normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } - } else { + }, - if ( arraysEqual( cache, elements ) ) return; + displacementmap: { - mat4array.set( elements ); + displacementMap: { value: null }, + displacementScale: { value: 1 }, + displacementBias: { value: 0 } - gl.uniformMatrix4fv( this.addr, false, mat4array ); + }, - copyArray( cache, elements ); + roughnessmap: { - } + roughnessMap: { value: null } - } + }, - // Single integer / boolean + metalnessmap: { - function setValueV1i( gl, v ) { + metalnessMap: { value: null } - const cache = this.cache; + }, - if ( cache[ 0 ] === v ) return; + gradientmap: { - gl.uniform1i( this.addr, v ); + gradientMap: { value: null } - cache[ 0 ] = v; + }, - } + fog: { - // Single integer / boolean vector (from flat array) + fogDensity: { value: 0.00025 }, + fogNear: { value: 1 }, + fogFar: { value: 2000 }, + fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) } - function setValueV2i( gl, v ) { + }, - const cache = this.cache; + lights: { - if ( arraysEqual( cache, v ) ) return; + ambientLightColor: { value: [] }, - gl.uniform2iv( this.addr, v ); + lightProbe: { value: [] }, - copyArray( cache, v ); + directionalLights: { value: [], properties: { + direction: {}, + color: {} + } }, - } + directionalLightShadows: { value: [], properties: { + shadowBias: {}, + shadowNormalBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, - function setValueV3i( gl, v ) { + directionalShadowMap: { value: [] }, + directionalShadowMatrix: { value: [] }, - const cache = this.cache; + spotLights: { value: [], properties: { + color: {}, + position: {}, + direction: {}, + distance: {}, + coneCos: {}, + penumbraCos: {}, + decay: {} + } }, - if ( arraysEqual( cache, v ) ) return; + spotLightShadows: { value: [], properties: { + shadowBias: {}, + shadowNormalBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, - gl.uniform3iv( this.addr, v ); + spotLightMap: { value: [] }, + spotShadowMap: { value: [] }, + spotLightMatrix: { value: [] }, - copyArray( cache, v ); + pointLights: { value: [], properties: { + color: {}, + position: {}, + decay: {}, + distance: {} + } }, - } + pointLightShadows: { value: [], properties: { + shadowBias: {}, + shadowNormalBias: {}, + shadowRadius: {}, + shadowMapSize: {}, + shadowCameraNear: {}, + shadowCameraFar: {} + } }, - function setValueV4i( gl, v ) { + pointShadowMap: { value: [] }, + pointShadowMatrix: { value: [] }, - const cache = this.cache; + hemisphereLights: { value: [], properties: { + direction: {}, + skyColor: {}, + groundColor: {} + } }, - if ( arraysEqual( cache, v ) ) return; + // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src + rectAreaLights: { value: [], properties: { + color: {}, + position: {}, + width: {}, + height: {} + } }, - gl.uniform4iv( this.addr, v ); + ltc_1: { value: null }, + ltc_2: { value: null } - copyArray( cache, v ); + }, - } + points: { - // Single unsigned integer + diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, + opacity: { value: 1.0 }, + size: { value: 1.0 }, + scale: { value: 1.0 }, + map: { value: null }, + alphaMap: { value: null }, + alphaTest: { value: 0 }, + uvTransform: { value: /*@__PURE__*/ new Matrix3() } - function setValueV1ui( gl, v ) { + }, - const cache = this.cache; + sprite: { - if ( cache[ 0 ] === v ) return; + diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, + opacity: { value: 1.0 }, + center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, + rotation: { value: 0.0 }, + map: { value: null }, + alphaMap: { value: null }, + alphaTest: { value: 0 }, + uvTransform: { value: /*@__PURE__*/ new Matrix3() } - gl.uniform1ui( this.addr, v ); + } - cache[ 0 ] = v; + }; - } + const ShaderLib = { - // Single unsigned integer vector (from flat array) + basic: { - function setValueV2ui( gl, v ) { + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.specularmap, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.fog + ] ), - const cache = this.cache; + vertexShader: ShaderChunk.meshbasic_vert, + fragmentShader: ShaderChunk.meshbasic_frag - if ( arraysEqual( cache, v ) ) return; + }, - gl.uniform2uiv( this.addr, v ); + lambert: { - copyArray( cache, v ); + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.specularmap, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } + } + ] ), - } + vertexShader: ShaderChunk.meshlambert_vert, + fragmentShader: ShaderChunk.meshlambert_frag - function setValueV3ui( gl, v ) { + }, - const cache = this.cache; + phong: { - if ( arraysEqual( cache, v ) ) return; + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.specularmap, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, + specular: { value: /*@__PURE__*/ new Color( 0x111111 ) }, + shininess: { value: 30 } + } + ] ), - gl.uniform3uiv( this.addr, v ); + vertexShader: ShaderChunk.meshphong_vert, + fragmentShader: ShaderChunk.meshphong_frag - copyArray( cache, v ); + }, - } + standard: { - function setValueV4ui( gl, v ) { + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.roughnessmap, + UniformsLib.metalnessmap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, + roughness: { value: 1.0 }, + metalness: { value: 0.0 }, + envMapIntensity: { value: 1 } // temporary + } + ] ), - const cache = this.cache; + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag - if ( arraysEqual( cache, v ) ) return; + }, - gl.uniform4uiv( this.addr, v ); + toon: { - copyArray( cache, v ); + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.gradientmap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } + } + ] ), - } + vertexShader: ShaderChunk.meshtoon_vert, + fragmentShader: ShaderChunk.meshtoon_frag + }, - // Single texture (2D / Cube) + matcap: { - function setValueT1( gl, v, textures ) { + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.fog, + { + matcap: { value: null } + } + ] ), - const cache = this.cache; - const unit = textures.allocateTextureUnit(); + vertexShader: ShaderChunk.meshmatcap_vert, + fragmentShader: ShaderChunk.meshmatcap_frag - if ( cache[ 0 ] !== unit ) { + }, - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; + points: { - } + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.points, + UniformsLib.fog + ] ), - textures.setTexture2D( v || emptyTexture, unit ); + vertexShader: ShaderChunk.points_vert, + fragmentShader: ShaderChunk.points_frag - } + }, - function setValueT3D1( gl, v, textures ) { + dashed: { - const cache = this.cache; - const unit = textures.allocateTextureUnit(); + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.fog, + { + scale: { value: 1 }, + dashSize: { value: 1 }, + totalSize: { value: 2 } + } + ] ), - if ( cache[ 0 ] !== unit ) { + vertexShader: ShaderChunk.linedashed_vert, + fragmentShader: ShaderChunk.linedashed_frag - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; + }, - } + depth: { - textures.setTexture3D( v || empty3dTexture, unit ); + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.displacementmap + ] ), - } + vertexShader: ShaderChunk.depth_vert, + fragmentShader: ShaderChunk.depth_frag - function setValueT6( gl, v, textures ) { + }, - const cache = this.cache; - const unit = textures.allocateTextureUnit(); + normal: { - if ( cache[ 0 ] !== unit ) { + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + { + opacity: { value: 1.0 } + } + ] ), - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; + vertexShader: ShaderChunk.meshnormal_vert, + fragmentShader: ShaderChunk.meshnormal_frag - } + }, - textures.setTextureCube( v || emptyCubeTexture, unit ); + sprite: { - } + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.sprite, + UniformsLib.fog + ] ), - function setValueT2DArray1( gl, v, textures ) { + vertexShader: ShaderChunk.sprite_vert, + fragmentShader: ShaderChunk.sprite_frag - const cache = this.cache; - const unit = textures.allocateTextureUnit(); + }, - if ( cache[ 0 ] !== unit ) { + background: { - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; + uniforms: { + uvTransform: { value: /*@__PURE__*/ new Matrix3() }, + t2D: { value: null }, + }, - } + vertexShader: ShaderChunk.background_vert, + fragmentShader: ShaderChunk.background_frag - textures.setTexture2DArray( v || emptyArrayTexture, unit ); + }, - } + cube: { - // Helper to pick the right setter for the singular case + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.envmap, + { + opacity: { value: 1.0 } + } + ] ), - function getSingularSetter( type ) { + vertexShader: ShaderChunk.cube_vert, + fragmentShader: ShaderChunk.cube_frag - switch ( type ) { + }, - case 0x1406: return setValueV1f; // FLOAT - case 0x8b50: return setValueV2f; // _VEC2 - case 0x8b51: return setValueV3f; // _VEC3 - case 0x8b52: return setValueV4f; // _VEC4 + equirect: { - case 0x8b5a: return setValueM2; // _MAT2 - case 0x8b5b: return setValueM3; // _MAT3 - case 0x8b5c: return setValueM4; // _MAT4 + uniforms: { + tEquirect: { value: null }, + }, - case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 + vertexShader: ShaderChunk.equirect_vert, + fragmentShader: ShaderChunk.equirect_frag - case 0x1405: return setValueV1ui; // UINT - case 0x8dc6: return setValueV2ui; // _VEC2 - case 0x8dc7: return setValueV3ui; // _VEC3 - case 0x8dc8: return setValueV4ui; // _VEC4 + }, - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1; + distanceRGBA: { - case 0x8b5f: // SAMPLER_3D - case 0x8dcb: // INT_SAMPLER_3D - case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D - return setValueT3D1; + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.common, + UniformsLib.displacementmap, + { + referencePosition: { value: /*@__PURE__*/ new Vector3() }, + nearDistance: { value: 1 }, + farDistance: { value: 1000 } + } + ] ), - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6; + vertexShader: ShaderChunk.distanceRGBA_vert, + fragmentShader: ShaderChunk.distanceRGBA_frag - case 0x8dc1: // SAMPLER_2D_ARRAY - case 0x8dcf: // INT_SAMPLER_2D_ARRAY - case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY - case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW - return setValueT2DArray1; + }, - } + shadow: { - } + uniforms: /*@__PURE__*/ mergeUniforms( [ + UniformsLib.lights, + UniformsLib.fog, + { + color: { value: /*@__PURE__*/ new Color( 0x00000 ) }, + opacity: { value: 1.0 } + }, + ] ), + vertexShader: ShaderChunk.shadow_vert, + fragmentShader: ShaderChunk.shadow_frag - // Array of scalars + } - function setValueV1fArray( gl, v ) { + }; - gl.uniform1fv( this.addr, v ); + ShaderLib.physical = { - } + uniforms: /*@__PURE__*/ mergeUniforms( [ + ShaderLib.standard.uniforms, + { + clearcoat: { value: 0 }, + clearcoatMap: { value: null }, + clearcoatRoughness: { value: 0 }, + clearcoatRoughnessMap: { value: null }, + clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, + clearcoatNormalMap: { value: null }, + iridescence: { value: 0 }, + iridescenceMap: { value: null }, + iridescenceIOR: { value: 1.3 }, + iridescenceThicknessMinimum: { value: 100 }, + iridescenceThicknessMaximum: { value: 400 }, + iridescenceThicknessMap: { value: null }, + sheen: { value: 0 }, + sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, + sheenColorMap: { value: null }, + sheenRoughness: { value: 1 }, + sheenRoughnessMap: { value: null }, + transmission: { value: 0 }, + transmissionMap: { value: null }, + transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, + transmissionSamplerMap: { value: null }, + thickness: { value: 0 }, + thicknessMap: { value: null }, + attenuationDistance: { value: 0 }, + attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, + specularIntensity: { value: 1 }, + specularIntensityMap: { value: null }, + specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, + specularColorMap: { value: null }, + } + ] ), - // Array of vectors (from flat array or array of THREE.VectorN) + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag - function setValueV2fArray( gl, v ) { + }; - const data = flatten( v, this.size, 2 ); + function WebGLBackground( renderer, cubemaps, state, objects, alpha, premultipliedAlpha ) { - gl.uniform2fv( this.addr, data ); + const clearColor = new Color( 0x000000 ); + let clearAlpha = alpha === true ? 0 : 1; - } + let planeMesh; + let boxMesh; - function setValueV3fArray( gl, v ) { + let currentBackground = null; + let currentBackgroundVersion = 0; + let currentTonemapping = null; - const data = flatten( v, this.size, 3 ); + function render( renderList, scene ) { - gl.uniform3fv( this.addr, data ); + let forceClear = false; + let background = scene.isScene === true ? scene.background : null; - } + if ( background && background.isTexture ) { - function setValueV4fArray( gl, v ) { + background = cubemaps.get( background ); - const data = flatten( v, this.size, 4 ); + } - gl.uniform4fv( this.addr, data ); + // Ignore background in AR + // TODO: Reconsider this. - } + const xr = renderer.xr; + const session = xr.getSession && xr.getSession(); - // Array of matrices (from flat array or array of THREE.MatrixN) - - function setValueM2Array( gl, v ) { + if ( session && session.environmentBlendMode === 'additive' ) { - const data = flatten( v, this.size, 4 ); + background = null; - gl.uniformMatrix2fv( this.addr, false, data ); + } - } + if ( background === null ) { - function setValueM3Array( gl, v ) { + setClear( clearColor, clearAlpha ); - const data = flatten( v, this.size, 9 ); + } else if ( background && background.isColor ) { - gl.uniformMatrix3fv( this.addr, false, data ); + setClear( background, 1 ); + forceClear = true; - } + } - function setValueM4Array( gl, v ) { + if ( renderer.autoClear || forceClear ) { - const data = flatten( v, this.size, 16 ); + renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); - gl.uniformMatrix4fv( this.addr, false, data ); + } - } + if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) { - // Array of integer / boolean + if ( boxMesh === undefined ) { - function setValueV1iArray( gl, v ) { + boxMesh = new Mesh( + new BoxGeometry( 1, 1, 1 ), + new ShaderMaterial( { + name: 'BackgroundCubeMaterial', + uniforms: cloneUniforms( ShaderLib.cube.uniforms ), + vertexShader: ShaderLib.cube.vertexShader, + fragmentShader: ShaderLib.cube.fragmentShader, + side: BackSide, + depthTest: false, + depthWrite: false, + fog: false + } ) + ); - gl.uniform1iv( this.addr, v ); + boxMesh.geometry.deleteAttribute( 'normal' ); + boxMesh.geometry.deleteAttribute( 'uv' ); - } + boxMesh.onBeforeRender = function ( renderer, scene, camera ) { - // Array of integer / boolean vectors (from flat array) + this.matrixWorld.copyPosition( camera.matrixWorld ); - function setValueV2iArray( gl, v ) { + }; - gl.uniform2iv( this.addr, v ); + // add "envMap" material property so the renderer can evaluate it like for built-in materials + Object.defineProperty( boxMesh.material, 'envMap', { - } + get: function () { - function setValueV3iArray( gl, v ) { + return this.uniforms.envMap.value; - gl.uniform3iv( this.addr, v ); + } - } + } ); - function setValueV4iArray( gl, v ) { + objects.update( boxMesh ); - gl.uniform4iv( this.addr, v ); + } - } + boxMesh.material.uniforms.envMap.value = background; + boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1; - // Array of unsigned integer + if ( currentBackground !== background || + currentBackgroundVersion !== background.version || + currentTonemapping !== renderer.toneMapping ) { - function setValueV1uiArray( gl, v ) { + boxMesh.material.needsUpdate = true; - gl.uniform1uiv( this.addr, v ); + currentBackground = background; + currentBackgroundVersion = background.version; + currentTonemapping = renderer.toneMapping; - } + } - // Array of unsigned integer vectors (from flat array) + boxMesh.layers.enableAll(); - function setValueV2uiArray( gl, v ) { + // push to the pre-sorted opaque render list + renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); - gl.uniform2uiv( this.addr, v ); + } else if ( background && background.isTexture ) { - } + if ( planeMesh === undefined ) { - function setValueV3uiArray( gl, v ) { + planeMesh = new Mesh( + new PlaneGeometry( 2, 2 ), + new ShaderMaterial( { + name: 'BackgroundMaterial', + uniforms: cloneUniforms( ShaderLib.background.uniforms ), + vertexShader: ShaderLib.background.vertexShader, + fragmentShader: ShaderLib.background.fragmentShader, + side: FrontSide, + depthTest: false, + depthWrite: false, + fog: false + } ) + ); - gl.uniform3uiv( this.addr, v ); + planeMesh.geometry.deleteAttribute( 'normal' ); - } + // add "map" material property so the renderer can evaluate it like for built-in materials + Object.defineProperty( planeMesh.material, 'map', { - function setValueV4uiArray( gl, v ) { + get: function () { - gl.uniform4uiv( this.addr, v ); + return this.uniforms.t2D.value; - } + } + } ); - // Array of textures (2D / 3D / Cube / 2DArray) + objects.update( planeMesh ); - function setValueT1Array( gl, v, textures ) { + } - const cache = this.cache; + planeMesh.material.uniforms.t2D.value = background; - const n = v.length; + if ( background.matrixAutoUpdate === true ) { - const units = allocTexUnits( textures, n ); + background.updateMatrix(); - if ( ! arraysEqual( cache, units ) ) { + } - gl.uniform1iv( this.addr, units ); + planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); - copyArray( cache, units ); + if ( currentBackground !== background || + currentBackgroundVersion !== background.version || + currentTonemapping !== renderer.toneMapping ) { - } + planeMesh.material.needsUpdate = true; - for ( let i = 0; i !== n; ++ i ) { + currentBackground = background; + currentBackgroundVersion = background.version; + currentTonemapping = renderer.toneMapping; - textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); + } - } + planeMesh.layers.enableAll(); - } + // push to the pre-sorted opaque render list + renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); - function setValueT3DArray( gl, v, textures ) { + } - const cache = this.cache; + } - const n = v.length; + function setClear( color, alpha ) { - const units = allocTexUnits( textures, n ); + state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); - if ( ! arraysEqual( cache, units ) ) { + } - gl.uniform1iv( this.addr, units ); + return { - copyArray( cache, units ); + getClearColor: function () { - } + return clearColor; - for ( let i = 0; i !== n; ++ i ) { + }, + setClearColor: function ( color, alpha = 1 ) { - textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] ); + clearColor.set( color ); + clearAlpha = alpha; + setClear( clearColor, clearAlpha ); - } + }, + getClearAlpha: function () { - } + return clearAlpha; - function setValueT6Array( gl, v, textures ) { + }, + setClearAlpha: function ( alpha ) { - const cache = this.cache; + clearAlpha = alpha; + setClear( clearColor, clearAlpha ); - const n = v.length; + }, + render: render - const units = allocTexUnits( textures, n ); + }; - if ( ! arraysEqual( cache, units ) ) { + } - gl.uniform1iv( this.addr, units ); + function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - copyArray( cache, units ); + const maxVertexAttributes = gl.getParameter( 34921 ); - } + const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); + const vaoAvailable = capabilities.isWebGL2 || extension !== null; - for ( let i = 0; i !== n; ++ i ) { + const bindingStates = {}; - textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); + const defaultState = createBindingState( null ); + let currentState = defaultState; + let forceUpdate = false; - } + function setup( object, material, program, geometry, index ) { - } + let updateBuffers = false; - function setValueT2DArrayArray( gl, v, textures ) { + if ( vaoAvailable ) { - const cache = this.cache; + const state = getBindingState( geometry, program, material ); - const n = v.length; + if ( currentState !== state ) { - const units = allocTexUnits( textures, n ); + currentState = state; + bindVertexArrayObject( currentState.object ); - if ( ! arraysEqual( cache, units ) ) { + } - gl.uniform1iv( this.addr, units ); + updateBuffers = needsUpdate( object, geometry, program, index ); - copyArray( cache, units ); + if ( updateBuffers ) saveCache( object, geometry, program, index ); - } + } else { - for ( let i = 0; i !== n; ++ i ) { + const wireframe = ( material.wireframe === true ); - textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] ); + if ( currentState.geometry !== geometry.id || + currentState.program !== program.id || + currentState.wireframe !== wireframe ) { - } + currentState.geometry = geometry.id; + currentState.program = program.id; + currentState.wireframe = wireframe; - } + updateBuffers = true; + } - // Helper to pick the right setter for a pure (bottom-level) array + } - function getPureArraySetter( type ) { + if ( index !== null ) { - switch ( type ) { + attributes.update( index, 34963 ); - case 0x1406: return setValueV1fArray; // FLOAT - case 0x8b50: return setValueV2fArray; // _VEC2 - case 0x8b51: return setValueV3fArray; // _VEC3 - case 0x8b52: return setValueV4fArray; // _VEC4 + } - case 0x8b5a: return setValueM2Array; // _MAT2 - case 0x8b5b: return setValueM3Array; // _MAT3 - case 0x8b5c: return setValueM4Array; // _MAT4 + if ( updateBuffers || forceUpdate ) { - case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 + forceUpdate = false; - case 0x1405: return setValueV1uiArray; // UINT - case 0x8dc6: return setValueV2uiArray; // _VEC2 - case 0x8dc7: return setValueV3uiArray; // _VEC3 - case 0x8dc8: return setValueV4uiArray; // _VEC4 + setupVertexAttributes( object, material, program, geometry ); - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1Array; + if ( index !== null ) { - case 0x8b5f: // SAMPLER_3D - case 0x8dcb: // INT_SAMPLER_3D - case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D - return setValueT3DArray; + gl.bindBuffer( 34963, attributes.get( index ).buffer ); - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6Array; + } - case 0x8dc1: // SAMPLER_2D_ARRAY - case 0x8dcf: // INT_SAMPLER_2D_ARRAY - case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY - case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW - return setValueT2DArrayArray; + } } - } - - // --- Uniform Classes --- + function createVertexArrayObject() { - class SingleUniform { + if ( capabilities.isWebGL2 ) return gl.createVertexArray(); - constructor( id, activeInfo, addr ) { + return extension.createVertexArrayOES(); - this.id = id; - this.addr = addr; - this.cache = []; - this.setValue = getSingularSetter( activeInfo.type ); + } - // this.path = activeInfo.name; // DEBUG + function bindVertexArrayObject( vao ) { - } + if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao ); - } + return extension.bindVertexArrayOES( vao ); - class PureArrayUniform { + } - constructor( id, activeInfo, addr ) { + function deleteVertexArrayObject( vao ) { - this.id = id; - this.addr = addr; - this.cache = []; - this.size = activeInfo.size; - this.setValue = getPureArraySetter( activeInfo.type ); + if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao ); - // this.path = activeInfo.name; // DEBUG + return extension.deleteVertexArrayOES( vao ); } - } - - class StructuredUniform { + function getBindingState( geometry, program, material ) { - constructor( id ) { + const wireframe = ( material.wireframe === true ); - this.id = id; + let programMap = bindingStates[ geometry.id ]; - this.seq = []; - this.map = {}; + if ( programMap === undefined ) { - } + programMap = {}; + bindingStates[ geometry.id ] = programMap; - setValue( gl, value, textures ) { + } - const seq = this.seq; + let stateMap = programMap[ program.id ]; - for ( let i = 0, n = seq.length; i !== n; ++ i ) { + if ( stateMap === undefined ) { - const u = seq[ i ]; - u.setValue( gl, value[ u.id ], textures ); + stateMap = {}; + programMap[ program.id ] = stateMap; } - } + let state = stateMap[ wireframe ]; - } + if ( state === undefined ) { - // --- Top-level --- + state = createBindingState( createVertexArrayObject() ); + stateMap[ wireframe ] = state; - // Parser - builds up the property tree from the path strings + } - const RePathPart = /(\w+)(\])?(\[|\.)?/g; + return state; - // extracts - // - the identifier (member name or array index) - // - followed by an optional right bracket (found when array index) - // - followed by an optional left bracket or dot (type of subscript) - // - // Note: These portions can be read in a non-overlapping fashion and - // allow straightforward parsing of the hierarchy that WebGL encodes - // in the uniform names. + } - function addUniform( container, uniformObject ) { + function createBindingState( vao ) { - container.seq.push( uniformObject ); - container.map[ uniformObject.id ] = uniformObject; + const newAttributes = []; + const enabledAttributes = []; + const attributeDivisors = []; - } + for ( let i = 0; i < maxVertexAttributes; i ++ ) { - function parseUniform( activeInfo, addr, container ) { + newAttributes[ i ] = 0; + enabledAttributes[ i ] = 0; + attributeDivisors[ i ] = 0; - const path = activeInfo.name, - pathLength = path.length; + } - // reset RegExp object, because of the early exit of a previous run - RePathPart.lastIndex = 0; + return { - while ( true ) { + // for backward compatibility on non-VAO support browser + geometry: null, + program: null, + wireframe: false, - const match = RePathPart.exec( path ), - matchEnd = RePathPart.lastIndex; + newAttributes: newAttributes, + enabledAttributes: enabledAttributes, + attributeDivisors: attributeDivisors, + object: vao, + attributes: {}, + index: null - let id = match[ 1 ]; - const idIsIndex = match[ 2 ] === ']', - subscript = match[ 3 ]; + }; - if ( idIsIndex ) id = id | 0; // convert to integer + } - if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { + function needsUpdate( object, geometry, program, index ) { - // bare name or "pure" bottom-level array "[0]" suffix + const cachedAttributes = currentState.attributes; + const geometryAttributes = geometry.attributes; - addUniform( container, subscript === undefined ? - new SingleUniform( id, activeInfo, addr ) : - new PureArrayUniform( id, activeInfo, addr ) ); + let attributesNum = 0; - break; + const programAttributes = program.getAttributes(); - } else { + for ( const name in programAttributes ) { - // step into inner node / create it in case it doesn't exist + const programAttribute = programAttributes[ name ]; - const map = container.map; - let next = map[ id ]; + if ( programAttribute.location >= 0 ) { - if ( next === undefined ) { + const cachedAttribute = cachedAttributes[ name ]; + let geometryAttribute = geometryAttributes[ name ]; - next = new StructuredUniform( id ); - addUniform( container, next ); + if ( geometryAttribute === undefined ) { - } + if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; + if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; - container = next; + } - } + if ( cachedAttribute === undefined ) return true; - } + if ( cachedAttribute.attribute !== geometryAttribute ) return true; - } + if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true; - // Root Container + attributesNum ++; - class WebGLUniforms { + } - constructor( gl, program ) { + } - this.seq = []; - this.map = {}; + if ( currentState.attributesNum !== attributesNum ) return true; - const n = gl.getProgramParameter( program, 35718 ); + if ( currentState.index !== index ) return true; - for ( let i = 0; i < n; ++ i ) { + return false; - const info = gl.getActiveUniform( program, i ), - addr = gl.getUniformLocation( program, info.name ); + } - parseUniform( info, addr, this ); + function saveCache( object, geometry, program, index ) { - } + const cache = {}; + const attributes = geometry.attributes; + let attributesNum = 0; - } + const programAttributes = program.getAttributes(); - setValue( gl, name, value, textures ) { + for ( const name in programAttributes ) { - const u = this.map[ name ]; + const programAttribute = programAttributes[ name ]; - if ( u !== undefined ) u.setValue( gl, value, textures ); + if ( programAttribute.location >= 0 ) { - } + let attribute = attributes[ name ]; - setOptional( gl, object, name ) { + if ( attribute === undefined ) { - const v = object[ name ]; + if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix; + if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor; - if ( v !== undefined ) this.setValue( gl, name, v ); + } - } + const data = {}; + data.attribute = attribute; - static upload( gl, seq, values, textures ) { + if ( attribute && attribute.data ) { - for ( let i = 0, n = seq.length; i !== n; ++ i ) { + data.data = attribute.data; - const u = seq[ i ], - v = values[ u.id ]; + } - if ( v.needsUpdate !== false ) { + cache[ name ] = data; - // note: always updating when .needsUpdate is undefined - u.setValue( gl, v.value, textures ); + attributesNum ++; } } + currentState.attributes = cache; + currentState.attributesNum = attributesNum; + + currentState.index = index; + } - static seqWithValue( seq, values ) { + function initAttributes() { - const r = []; + const newAttributes = currentState.newAttributes; - for ( let i = 0, n = seq.length; i !== n; ++ i ) { + for ( let i = 0, il = newAttributes.length; i < il; i ++ ) { - const u = seq[ i ]; - if ( u.id in values ) r.push( u ); + newAttributes[ i ] = 0; } - return r; - } - } + function enableAttribute( attribute ) { - function WebGLShader( gl, type, string ) { + enableAttributeAndDivisor( attribute, 0 ); - const shader = gl.createShader( type ); + } - gl.shaderSource( shader, string ); - gl.compileShader( shader ); + function enableAttributeAndDivisor( attribute, meshPerAttribute ) { - return shader; + const newAttributes = currentState.newAttributes; + const enabledAttributes = currentState.enabledAttributes; + const attributeDivisors = currentState.attributeDivisors; - } + newAttributes[ attribute ] = 1; - let programIdCount = 0; + if ( enabledAttributes[ attribute ] === 0 ) { - function handleSource( string, errorLine ) { + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; - const lines = string.split( '\n' ); - const lines2 = []; + } - const from = Math.max( errorLine - 6, 0 ); - const to = Math.min( errorLine + 6, lines.length ); + if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { - for ( let i = from; i < to; i ++ ) { + const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); - const line = i + 1; - lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` ); + extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); + attributeDivisors[ attribute ] = meshPerAttribute; - } + } - return lines2.join( '\n' ); + } - } + function disableUnusedAttributes() { - function getEncodingComponents( encoding ) { + const newAttributes = currentState.newAttributes; + const enabledAttributes = currentState.enabledAttributes; - switch ( encoding ) { + for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) { - case LinearEncoding: - return [ 'Linear', '( value )' ]; - case sRGBEncoding: - return [ 'sRGB', '( value )' ]; - default: - console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding ); - return [ 'Linear', '( value )' ]; + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - } + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; - } + } - function getShaderErrors( gl, shader, type ) { + } - const status = gl.getShaderParameter( shader, 35713 ); - const errors = gl.getShaderInfoLog( shader ).trim(); + } - if ( status && errors === '' ) return ''; + function vertexAttribPointer( index, size, type, normalized, stride, offset ) { - const errorMatches = /ERROR: 0:(\d+)/.exec( errors ); - if ( errorMatches ) { + if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) { - // --enable-privileged-webgl-extension - // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); + gl.vertexAttribIPointer( index, size, type, stride, offset ); - const errorLine = parseInt( errorMatches[ 1 ] ); - return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine ); + } else { - } else { + gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); - return errors; + } } - } + function setupVertexAttributes( object, material, program, geometry ) { - function getTexelEncodingFunction( functionName, encoding ) { + if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) { - const components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; + if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return; - } + } - function getToneMappingFunction( functionName, toneMapping ) { + initAttributes(); - let toneMappingName; + const geometryAttributes = geometry.attributes; - switch ( toneMapping ) { + const programAttributes = program.getAttributes(); - case LinearToneMapping: - toneMappingName = 'Linear'; - break; + const materialDefaultAttributeValues = material.defaultAttributeValues; - case ReinhardToneMapping: - toneMappingName = 'Reinhard'; - break; + for ( const name in programAttributes ) { - case CineonToneMapping: - toneMappingName = 'OptimizedCineon'; - break; + const programAttribute = programAttributes[ name ]; - case ACESFilmicToneMapping: - toneMappingName = 'ACESFilmic'; - break; + if ( programAttribute.location >= 0 ) { - case CustomToneMapping: - toneMappingName = 'Custom'; - break; + let geometryAttribute = geometryAttributes[ name ]; - default: - console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); - toneMappingName = 'Linear'; + if ( geometryAttribute === undefined ) { - } + if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; + if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; - return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; + } - } + if ( geometryAttribute !== undefined ) { - function generateExtensions( parameters ) { + const normalized = geometryAttribute.normalized; + const size = geometryAttribute.itemSize; - const chunks = [ - ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', - ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', - ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', - ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' - ]; + const attribute = attributes.get( geometryAttribute ); - return chunks.filter( filterEmptyLine ).join( '\n' ); + // TODO Attribute may not be available on context restore - } + if ( attribute === undefined ) continue; - function generateDefines( defines ) { + const buffer = attribute.buffer; + const type = attribute.type; + const bytesPerElement = attribute.bytesPerElement; - const chunks = []; + if ( geometryAttribute.isInterleavedBufferAttribute ) { - for ( const name in defines ) { + const data = geometryAttribute.data; + const stride = data.stride; + const offset = geometryAttribute.offset; - const value = defines[ name ]; + if ( data.isInstancedInterleavedBuffer ) { - if ( value === false ) continue; + for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - chunks.push( '#define ' + name + ' ' + value ); + enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute ); - } + } - return chunks.join( '\n' ); + if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - } + geometry._maxInstanceCount = data.meshPerAttribute * data.count; - function fetchAttributeLocations( gl, program ) { + } - const attributes = {}; + } else { - const n = gl.getProgramParameter( program, 35721 ); + for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - for ( let i = 0; i < n; i ++ ) { + enableAttribute( programAttribute.location + i ); - const info = gl.getActiveAttrib( program, i ); - const name = info.name; + } - let locationSize = 1; - if ( info.type === 35674 ) locationSize = 2; - if ( info.type === 35675 ) locationSize = 3; - if ( info.type === 35676 ) locationSize = 4; + } - // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); + gl.bindBuffer( 34962, buffer ); - attributes[ name ] = { - type: info.type, - location: gl.getAttribLocation( program, name ), - locationSize: locationSize - }; + for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - } + vertexAttribPointer( + programAttribute.location + i, + size / programAttribute.locationSize, + type, + normalized, + stride * bytesPerElement, + ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement + ); - return attributes; + } - } + } else { - function filterEmptyLine( string ) { + if ( geometryAttribute.isInstancedBufferAttribute ) { - return string !== ''; + for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - } + enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute ); - function replaceLightNums( string, parameters ) { + } - const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; + if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - return string - .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) - .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) - .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps ) - .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords ) - .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) - .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) - .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) - .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) - .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps ) - .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) - .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows ); + geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - } + } - function replaceClippingPlaneNums( string, parameters ) { + } else { - return string - .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) - .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); + for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - } + enableAttribute( programAttribute.location + i ); - // Resolve Includes + } - const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; + } - function resolveIncludes( string ) { + gl.bindBuffer( 34962, buffer ); - return string.replace( includePattern, includeReplacer ); + for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - } + vertexAttribPointer( + programAttribute.location + i, + size / programAttribute.locationSize, + type, + normalized, + size * bytesPerElement, + ( size / programAttribute.locationSize ) * i * bytesPerElement + ); - function includeReplacer( match, include ) { + } - const string = ShaderChunk[ include ]; + } - if ( string === undefined ) { + } else if ( materialDefaultAttributeValues !== undefined ) { - throw new Error( 'Can not resolve #include <' + include + '>' ); + const value = materialDefaultAttributeValues[ name ]; - } + if ( value !== undefined ) { - return resolveIncludes( string ); + switch ( value.length ) { - } + case 2: + gl.vertexAttrib2fv( programAttribute.location, value ); + break; - // Unroll Loops + case 3: + gl.vertexAttrib3fv( programAttribute.location, value ); + break; - const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; + case 4: + gl.vertexAttrib4fv( programAttribute.location, value ); + break; - function unrollLoops( string ) { + default: + gl.vertexAttrib1fv( programAttribute.location, value ); - return string.replace( unrollLoopPattern, loopReplacer ); + } - } + } - function loopReplacer( match, start, end, snippet ) { + } - let string = ''; + } - for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) { + } - string += snippet - .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) - .replace( /UNROLLED_LOOP_INDEX/g, i ); + disableUnusedAttributes(); } - return string; + function dispose() { - } + reset(); - // + for ( const geometryId in bindingStates ) { - function generatePrecision( parameters ) { + const programMap = bindingStates[ geometryId ]; - let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;'; + for ( const programId in programMap ) { - if ( parameters.precision === 'highp' ) { + const stateMap = programMap[ programId ]; - precisionstring += '\n#define HIGH_PRECISION'; + for ( const wireframe in stateMap ) { - } else if ( parameters.precision === 'mediump' ) { + deleteVertexArrayObject( stateMap[ wireframe ].object ); - precisionstring += '\n#define MEDIUM_PRECISION'; + delete stateMap[ wireframe ]; - } else if ( parameters.precision === 'lowp' ) { + } - precisionstring += '\n#define LOW_PRECISION'; + delete programMap[ programId ]; + + } + + delete bindingStates[ geometryId ]; + + } } - return precisionstring; + function releaseStatesOfGeometry( geometry ) { - } + if ( bindingStates[ geometry.id ] === undefined ) return; - function generateShadowMapTypeDefine( parameters ) { + const programMap = bindingStates[ geometry.id ]; - let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; + for ( const programId in programMap ) { - if ( parameters.shadowMapType === PCFShadowMap ) { + const stateMap = programMap[ programId ]; - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; + for ( const wireframe in stateMap ) { - } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { + deleteVertexArrayObject( stateMap[ wireframe ].object ); - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; + delete stateMap[ wireframe ]; - } else if ( parameters.shadowMapType === VSMShadowMap ) { + } - shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; + delete programMap[ programId ]; + + } + + delete bindingStates[ geometry.id ]; } - return shadowMapTypeDefine; + function releaseStatesOfProgram( program ) { - } + for ( const geometryId in bindingStates ) { - function generateEnvMapTypeDefine( parameters ) { + const programMap = bindingStates[ geometryId ]; - let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + if ( programMap[ program.id ] === undefined ) continue; - if ( parameters.envMap ) { + const stateMap = programMap[ program.id ]; - switch ( parameters.envMapMode ) { + for ( const wireframe in stateMap ) { - case CubeReflectionMapping: - case CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; + deleteVertexArrayObject( stateMap[ wireframe ].object ); - case CubeUVReflectionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; - break; + delete stateMap[ wireframe ]; + + } + + delete programMap[ program.id ]; } } - return envMapTypeDefine; - - } + function reset() { - function generateEnvMapModeDefine( parameters ) { + resetDefaultState(); + forceUpdate = true; - let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; + if ( currentState === defaultState ) return; - if ( parameters.envMap ) { + currentState = defaultState; + bindVertexArrayObject( currentState.object ); - switch ( parameters.envMapMode ) { + } - case CubeRefractionMapping: + // for backward-compatibility - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; + function resetDefaultState() { - } + defaultState.geometry = null; + defaultState.program = null; + defaultState.wireframe = false; } - return envMapModeDefine; + return { + + setup: setup, + reset: reset, + resetDefaultState: resetDefaultState, + dispose: dispose, + releaseStatesOfGeometry: releaseStatesOfGeometry, + releaseStatesOfProgram: releaseStatesOfProgram, + + initAttributes: initAttributes, + enableAttribute: enableAttribute, + disableUnusedAttributes: disableUnusedAttributes + + }; } - function generateEnvMapBlendingDefine( parameters ) { + function WebGLBufferRenderer( gl, extensions, info, capabilities ) { - let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; + const isWebGL2 = capabilities.isWebGL2; - if ( parameters.envMap ) { + let mode; - switch ( parameters.combine ) { + function setMode( value ) { - case MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; + mode = value; - case MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; + } - case AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; + function render( start, count ) { - } + gl.drawArrays( mode, start, count ); + + info.update( count, mode, 1 ); } - return envMapBlendingDefine; + function renderInstances( start, count, primcount ) { - } + if ( primcount === 0 ) return; - function generateCubeUVSize( parameters ) { + let extension, methodName; - const imageHeight = parameters.envMapCubeUVHeight; + if ( isWebGL2 ) { - if ( imageHeight === null ) return null; + extension = gl; + methodName = 'drawArraysInstanced'; - const maxMip = Math.log2( imageHeight ) - 2; + } else { - const texelHeight = 1.0 / imageHeight; + extension = extensions.get( 'ANGLE_instanced_arrays' ); + methodName = 'drawArraysInstancedANGLE'; - const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); + if ( extension === null ) { - return { texelWidth, texelHeight, maxMip }; + console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - } + } - function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { + } - // TODO Send this event to Three.js DevTools - // console.log( 'WebGLProgram', cacheKey ); + extension[ methodName ]( mode, start, count, primcount ); - const gl = renderer.getContext(); + info.update( count, mode, primcount ); - const defines = parameters.defines; + } - let vertexShader = parameters.vertexShader; - let fragmentShader = parameters.fragmentShader; + // - const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); - const envMapTypeDefine = generateEnvMapTypeDefine( parameters ); - const envMapModeDefine = generateEnvMapModeDefine( parameters ); - const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); - const envMapCubeUVSize = generateCubeUVSize( parameters ); + this.setMode = setMode; + this.render = render; + this.renderInstances = renderInstances; - const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); + } - const customDefines = generateDefines( defines ); + function WebGLCapabilities( gl, extensions, parameters ) { - const program = gl.createProgram(); + let maxAnisotropy; - let prefixVertex, prefixFragment; - let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; + function getMaxAnisotropy() { - if ( parameters.isRawShaderMaterial ) { + if ( maxAnisotropy !== undefined ) return maxAnisotropy; - prefixVertex = [ + if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - customDefines + const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - ].filter( filterEmptyLine ).join( '\n' ); + maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - if ( prefixVertex.length > 0 ) { + } else { - prefixVertex += '\n'; + maxAnisotropy = 0; } - prefixFragment = [ + return maxAnisotropy; - customExtensions, - customDefines + } - ].filter( filterEmptyLine ).join( '\n' ); + function getMaxPrecision( precision ) { - if ( prefixFragment.length > 0 ) { + if ( precision === 'highp' ) { - prefixFragment += '\n'; + if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && + gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { - } + return 'highp'; - } else { + } - prefixVertex = [ + precision = 'mediump'; - generatePrecision( parameters ), + } - '#define SHADER_NAME ' + parameters.shaderName, + if ( precision === 'mediump' ) { - customDefines, + if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && + gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { - parameters.instancing ? '#define USE_INSTANCING' : '', - parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', + return 'mediump'; - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', + } - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + } - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + return 'lowp'; - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', + } - parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', - parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', + const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) || + ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext ); - parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', + let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; + const maxPrecision = getMaxPrecision( precision ); - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + if ( maxPrecision !== precision ) { - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); + precision = maxPrecision; - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', + } - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ); - parameters.vertexTangents ? '#define USE_TANGENT' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - parameters.flatShading ? '#define FLAT_SHADED' : '', + const maxTextures = gl.getParameter( 34930 ); + const maxVertexTextures = gl.getParameter( 35660 ); + const maxTextureSize = gl.getParameter( 3379 ); + const maxCubemapSize = gl.getParameter( 34076 ); - parameters.skinning ? '#define USE_SKINNING' : '', + const maxAttributes = gl.getParameter( 34921 ); + const maxVertexUniforms = gl.getParameter( 36347 ); + const maxVaryings = gl.getParameter( 36348 ); + const maxFragmentUniforms = gl.getParameter( 36349 ); - parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', - parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', - ( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', - ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', + const vertexTextures = maxVertexTextures > 0; + const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); + const floatVertexTextures = vertexTextures && floatFragmentTextures; - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0; - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', + return { - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + isWebGL2: isWebGL2, - 'uniform mat4 modelMatrix;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform mat4 viewMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', + drawBuffers: drawBuffers, - '#ifdef USE_INSTANCING', + getMaxAnisotropy: getMaxAnisotropy, + getMaxPrecision: getMaxPrecision, - ' attribute mat4 instanceMatrix;', + precision: precision, + logarithmicDepthBuffer: logarithmicDepthBuffer, - '#endif', + maxTextures: maxTextures, + maxVertexTextures: maxVertexTextures, + maxTextureSize: maxTextureSize, + maxCubemapSize: maxCubemapSize, - '#ifdef USE_INSTANCING_COLOR', + maxAttributes: maxAttributes, + maxVertexUniforms: maxVertexUniforms, + maxVaryings: maxVaryings, + maxFragmentUniforms: maxFragmentUniforms, - ' attribute vec3 instanceColor;', + vertexTextures: vertexTextures, + floatFragmentTextures: floatFragmentTextures, + floatVertexTextures: floatVertexTextures, - '#endif', + maxSamples: maxSamples - 'attribute vec3 position;', - 'attribute vec3 normal;', - 'attribute vec2 uv;', + }; - '#ifdef USE_TANGENT', + } - ' attribute vec4 tangent;', + function WebGLClipping( properties ) { - '#endif', + const scope = this; - '#if defined( USE_COLOR_ALPHA )', + let globalState = null, + numGlobalPlanes = 0, + localClippingEnabled = false, + renderingShadows = false; - ' attribute vec4 color;', + const plane = new Plane(), + viewNormalMatrix = new Matrix3(), - '#elif defined( USE_COLOR )', + uniform = { value: null, needsUpdate: false }; - ' attribute vec3 color;', + this.uniform = uniform; + this.numPlanes = 0; + this.numIntersection = 0; - '#endif', + this.init = function ( planes, enableLocalClipping, camera ) { - '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )', + const enabled = + planes.length !== 0 || + enableLocalClipping || + // enable state of previous frame - the clipping code has to + // run another frame in order to reset the state: + numGlobalPlanes !== 0 || + localClippingEnabled; - ' attribute vec3 morphTarget0;', - ' attribute vec3 morphTarget1;', - ' attribute vec3 morphTarget2;', - ' attribute vec3 morphTarget3;', + localClippingEnabled = enableLocalClipping; - ' #ifdef USE_MORPHNORMALS', + globalState = projectPlanes( planes, camera, 0 ); + numGlobalPlanes = planes.length; - ' attribute vec3 morphNormal0;', - ' attribute vec3 morphNormal1;', - ' attribute vec3 morphNormal2;', - ' attribute vec3 morphNormal3;', + return enabled; - ' #else', + }; - ' attribute vec3 morphTarget4;', - ' attribute vec3 morphTarget5;', - ' attribute vec3 morphTarget6;', - ' attribute vec3 morphTarget7;', + this.beginShadows = function () { - ' #endif', + renderingShadows = true; + projectPlanes( null ); - '#endif', + }; - '#ifdef USE_SKINNING', + this.endShadows = function () { - ' attribute vec4 skinIndex;', - ' attribute vec4 skinWeight;', + renderingShadows = false; + resetGlobalState(); - '#endif', + }; - '\n' + this.setState = function ( material, camera, useCache ) { - ].filter( filterEmptyLine ).join( '\n' ); + const planes = material.clippingPlanes, + clipIntersection = material.clipIntersection, + clipShadows = material.clipShadows; - prefixFragment = [ + const materialProperties = properties.get( material ); - customExtensions, + if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { - generatePrecision( parameters ), + // there's no local clipping - '#define SHADER_NAME ' + parameters.shaderName, + if ( renderingShadows ) { - customDefines, + // there's no global clipping - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + projectPlanes( null ); - parameters.map ? '#define USE_MAP' : '', - parameters.matcap ? '#define USE_MATCAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapTypeDefine : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.envMap ? '#define ' + envMapBlendingDefine : '', - envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', - envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', - envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + } else { - parameters.clearcoat ? '#define USE_CLEARCOAT' : '', - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', + resetGlobalState(); - parameters.iridescence ? '#define USE_IRIDESCENCE' : '', - parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', - parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', + } - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', + } else { - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.alphaTest ? '#define USE_ALPHATEST' : '', + const nGlobal = renderingShadows ? 0 : numGlobalPlanes, + lGlobal = nGlobal * 4; - parameters.sheen ? '#define USE_SHEEN' : '', - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + let dstArray = materialProperties.clippingState || null; - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', + uniform.value = dstArray; // ensure unique state - parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', + dstArray = projectPlanes( planes, camera, lGlobal, useCache ); - parameters.vertexTangents ? '#define USE_TANGENT' : '', - parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + for ( let i = 0; i !== lGlobal; ++ i ) { - parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', + dstArray[ i ] = globalState[ i ]; - parameters.flatShading ? '#define FLAT_SHADED' : '', + } - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', + materialProperties.clippingState = dstArray; + this.numIntersection = clipIntersection ? this.numPlanes : 0; + this.numPlanes += nGlobal; - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + } - parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', + }; - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + function resetGlobalState() { - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', + if ( uniform.value !== globalState ) { - ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', - ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below - ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', + uniform.value = globalState; + uniform.needsUpdate = numGlobalPlanes > 0; - parameters.dithering ? '#define DITHERING' : '', - parameters.opaque ? '#define OPAQUE' : '', + } - ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below - getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ), + scope.numPlanes = numGlobalPlanes; + scope.numIntersection = 0; - parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', + } - '\n' + function projectPlanes( planes, camera, dstOffset, skipTransform ) { - ].filter( filterEmptyLine ).join( '\n' ); + const nPlanes = planes !== null ? planes.length : 0; + let dstArray = null; - } + if ( nPlanes !== 0 ) { - vertexShader = resolveIncludes( vertexShader ); - vertexShader = replaceLightNums( vertexShader, parameters ); - vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); + dstArray = uniform.value; - fragmentShader = resolveIncludes( fragmentShader ); - fragmentShader = replaceLightNums( fragmentShader, parameters ); - fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); + if ( skipTransform !== true || dstArray === null ) { - vertexShader = unrollLoops( vertexShader ); - fragmentShader = unrollLoops( fragmentShader ); + const flatSize = dstOffset + nPlanes * 4, + viewMatrix = camera.matrixWorldInverse; - if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) { + viewNormalMatrix.getNormalMatrix( viewMatrix ); - // GLSL 3.0 conversion for built-in materials and ShaderMaterial + if ( dstArray === null || dstArray.length < flatSize ) { - versionString = '#version 300 es\n'; + dstArray = new Float32Array( flatSize ); - prefixVertex = [ - 'precision mediump sampler2DArray;', - '#define attribute in', - '#define varying out', - '#define texture2D texture' - ].join( '\n' ) + '\n' + prefixVertex; + } - prefixFragment = [ - '#define varying in', - ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', - ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', - '#define gl_FragDepthEXT gl_FragDepth', - '#define texture2D texture', - '#define textureCube texture', - '#define texture2DProj textureProj', - '#define texture2DLodEXT textureLod', - '#define texture2DProjLodEXT textureProjLod', - '#define textureCubeLodEXT textureLod', - '#define texture2DGradEXT textureGrad', - '#define texture2DProjGradEXT textureProjGrad', - '#define textureCubeGradEXT textureGrad' - ].join( '\n' ) + '\n' + prefixFragment; + for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { - } + plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); - const vertexGlsl = versionString + prefixVertex + vertexShader; - const fragmentGlsl = versionString + prefixFragment + fragmentShader; + plane.normal.toArray( dstArray, i4 ); + dstArray[ i4 + 3 ] = plane.constant; - // console.log( '*VERTEX*', vertexGlsl ); - // console.log( '*FRAGMENT*', fragmentGlsl ); + } - const glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); - const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); + } - gl.attachShader( program, glVertexShader ); - gl.attachShader( program, glFragmentShader ); + uniform.value = dstArray; + uniform.needsUpdate = true; - // Force a particular attribute to index 0. + } - if ( parameters.index0AttributeName !== undefined ) { + scope.numPlanes = nPlanes; + scope.numIntersection = 0; - gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); + return dstArray; - } else if ( parameters.morphTargets === true ) { + } - // programs with morphTargets displace position out of attribute 0 - gl.bindAttribLocation( program, 0, 'position' ); + } - } + function WebGLCubeMaps( renderer ) { - gl.linkProgram( program ); + let cubemaps = new WeakMap(); - // check for link errors - if ( renderer.debug.checkShaderErrors ) { + function mapTextureMapping( texture, mapping ) { - const programLog = gl.getProgramInfoLog( program ).trim(); - const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); + if ( mapping === EquirectangularReflectionMapping ) { - let runnable = true; - let haveDiagnostics = true; + texture.mapping = CubeReflectionMapping; - if ( gl.getProgramParameter( program, 35714 ) === false ) { + } else if ( mapping === EquirectangularRefractionMapping ) { - runnable = false; + texture.mapping = CubeRefractionMapping; - const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); - const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); + } - console.error( - 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + - 'VALIDATE_STATUS ' + gl.getProgramParameter( program, 35715 ) + '\n\n' + - 'Program Info Log: ' + programLog + '\n' + - vertexErrors + '\n' + - fragmentErrors - ); + return texture; - } else if ( programLog !== '' ) { + } - console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); + function get( texture ) { - } else if ( vertexLog === '' || fragmentLog === '' ) { + if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) { - haveDiagnostics = false; + const mapping = texture.mapping; - } + if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { - if ( haveDiagnostics ) { + if ( cubemaps.has( texture ) ) { - this.diagnostics = { + const cubemap = cubemaps.get( texture ).texture; + return mapTextureMapping( cubemap, texture.mapping ); - runnable: runnable, + } else { - programLog: programLog, + const image = texture.image; - vertexShader: { + if ( image && image.height > 0 ) { - log: vertexLog, - prefix: prefixVertex + const renderTarget = new WebGLCubeRenderTarget( image.height / 2 ); + renderTarget.fromEquirectangularTexture( renderer, texture ); + cubemaps.set( texture, renderTarget ); - }, + texture.addEventListener( 'dispose', onTextureDispose ); - fragmentShader: { + return mapTextureMapping( renderTarget.texture, texture.mapping ); - log: fragmentLog, - prefix: prefixFragment + } else { + + // image not yet ready. try the conversion next frame + + return null; + + } } - }; + } } + return texture; + } - // Clean up + function onTextureDispose( event ) { - // Crashes in iOS9 and iOS10. #18402 - // gl.detachShader( program, glVertexShader ); - // gl.detachShader( program, glFragmentShader ); + const texture = event.target; - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); + texture.removeEventListener( 'dispose', onTextureDispose ); - // set up caching for uniform locations + const cubemap = cubemaps.get( texture ); - let cachedUniforms; + if ( cubemap !== undefined ) { - this.getUniforms = function () { + cubemaps.delete( texture ); + cubemap.dispose(); - if ( cachedUniforms === undefined ) { + } - cachedUniforms = new WebGLUniforms( gl, program ); + } - } + function dispose() { - return cachedUniforms; + cubemaps = new WeakMap(); - }; + } - // set up caching for attribute locations + return { + get: get, + dispose: dispose + }; - let cachedAttributes; + } - this.getAttributes = function () { + class OrthographicCamera extends Camera { - if ( cachedAttributes === undefined ) { + constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { - cachedAttributes = fetchAttributeLocations( gl, program ); + super(); - } + this.isOrthographicCamera = true; - return cachedAttributes; + this.type = 'OrthographicCamera'; - }; + this.zoom = 1; + this.view = null; - // free resource + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; - this.destroy = function () { + this.near = near; + this.far = far; - bindingStates.releaseStatesOfProgram( this ); + this.updateProjectionMatrix(); - gl.deleteProgram( program ); - this.program = undefined; + } - }; + copy( source, recursive ) { - // + super.copy( source, recursive ); - this.name = parameters.shaderName; - this.id = programIdCount ++; - this.cacheKey = cacheKey; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; + this.left = source.left; + this.right = source.right; + this.top = source.top; + this.bottom = source.bottom; + this.near = source.near; + this.far = source.far; - return this; + this.zoom = source.zoom; + this.view = source.view === null ? null : Object.assign( {}, source.view ); - } + return this; - let _id = 0; + } - class WebGLShaderCache { + setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - constructor() { + if ( this.view === null ) { - this.shaderCache = new Map(); - this.materialCache = new Map(); - - } - - update( material ) { - - const vertexShader = material.vertexShader; - const fragmentShader = material.fragmentShader; + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; - const vertexShaderStage = this._getShaderStage( vertexShader ); - const fragmentShaderStage = this._getShaderStage( fragmentShader ); + } - const materialShaders = this._getShaderCacheForMaterial( material ); + this.view.enabled = true; + this.view.fullWidth = fullWidth; + this.view.fullHeight = fullHeight; + this.view.offsetX = x; + this.view.offsetY = y; + this.view.width = width; + this.view.height = height; - if ( materialShaders.has( vertexShaderStage ) === false ) { + this.updateProjectionMatrix(); - materialShaders.add( vertexShaderStage ); - vertexShaderStage.usedTimes ++; + } - } + clearViewOffset() { - if ( materialShaders.has( fragmentShaderStage ) === false ) { + if ( this.view !== null ) { - materialShaders.add( fragmentShaderStage ); - fragmentShaderStage.usedTimes ++; + this.view.enabled = false; } - return this; + this.updateProjectionMatrix(); } - remove( material ) { + updateProjectionMatrix() { - const materialShaders = this.materialCache.get( material ); + const dx = ( this.right - this.left ) / ( 2 * this.zoom ); + const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); + const cx = ( this.right + this.left ) / 2; + const cy = ( this.top + this.bottom ) / 2; - for ( const shaderStage of materialShaders ) { + let left = cx - dx; + let right = cx + dx; + let top = cy + dy; + let bottom = cy - dy; - shaderStage.usedTimes --; + if ( this.view !== null && this.view.enabled ) { - if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code ); + const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; + const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; + + left += scaleW * this.view.offsetX; + right = left + scaleW * this.view.width; + top -= scaleH * this.view.offsetY; + bottom = top - scaleH * this.view.height; } - this.materialCache.delete( material ); + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); - return this; + this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); } - getVertexShaderID( material ) { + toJSON( meta ) { - return this._getShaderStage( material.vertexShader ).id; + const data = super.toJSON( meta ); - } + data.object.zoom = this.zoom; + data.object.left = this.left; + data.object.right = this.right; + data.object.top = this.top; + data.object.bottom = this.bottom; + data.object.near = this.near; + data.object.far = this.far; - getFragmentShaderID( material ) { + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - return this._getShaderStage( material.fragmentShader ).id; + return data; } - dispose() { - - this.shaderCache.clear(); - this.materialCache.clear(); - - } + } - _getShaderCacheForMaterial( material ) { + const LOD_MIN = 4; - const cache = this.materialCache; - let set = cache.get( material ); + // The standard deviations (radians) associated with the extra mips. These are + // chosen to approximate a Trowbridge-Reitz distribution function times the + // geometric shadowing function. These sigma values squared must match the + // variance #defines in cube_uv_reflection_fragment.glsl.js. + const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; - if ( set === undefined ) { + // The maximum length of the blur for loop. Smaller sigmas will use fewer + // samples and exit early, but not recompile the shader. + const MAX_SAMPLES = 20; - set = new Set(); - cache.set( material, set ); + const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); + const _clearColor = /*@__PURE__*/ new Color(); + let _oldTarget = null; - } + // Golden Ratio + const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; + const INV_PHI = 1 / PHI; - return set; + // Vertices of a dodecahedron (except the opposites, which represent the + // same axis), used as axis directions evenly spread on a sphere. + const _axisDirections = [ + /*@__PURE__*/ new Vector3( 1, 1, 1 ), + /*@__PURE__*/ new Vector3( - 1, 1, 1 ), + /*@__PURE__*/ new Vector3( 1, 1, - 1 ), + /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), + /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), + /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), + /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), + /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), + /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), + /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ]; - } + /** + * This class generates a Prefiltered, Mipmapped Radiance Environment Map + * (PMREM) from a cubeMap environment texture. This allows different levels of + * blur to be quickly accessed based on material roughness. It is packed into a + * special CubeUV format that allows us to perform custom interpolation so that + * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap + * chain, it only goes down to the LOD_MIN level (above), and then creates extra + * even more filtered 'mips' at the same LOD_MIN resolution, associated with + * higher roughness levels. In this way we maintain resolution to smoothly + * interpolate diffuse lighting while limiting sampling computation. + * + * Paper: Fast, Accurate Image-Based Lighting + * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view + */ - _getShaderStage( code ) { + class PMREMGenerator { - const cache = this.shaderCache; - let stage = cache.get( code ); + constructor( renderer ) { - if ( stage === undefined ) { + this._renderer = renderer; + this._pingPongRenderTarget = null; - stage = new WebGLShaderStage( code ); - cache.set( code, stage ); + this._lodMax = 0; + this._cubeSize = 0; + this._lodPlanes = []; + this._sizeLods = []; + this._sigmas = []; - } + this._blurMaterial = null; + this._cubemapMaterial = null; + this._equirectMaterial = null; - return stage; + this._compileMaterial( this._blurMaterial ); } - } - - class WebGLShaderStage { + /** + * Generates a PMREM from a supplied Scene, which can be faster than using an + * image if networking bandwidth is low. Optional sigma specifies a blur radius + * in radians to be applied to the scene before PMREM generation. Optional near + * and far planes ensure the scene is rendered in its entirety (the cubeCamera + * is placed at the origin). + */ + fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { - constructor( code ) { + _oldTarget = this._renderer.getRenderTarget(); - this.id = _id ++; + this._setSize( 256 ); - this.code = code; - this.usedTimes = 0; + const cubeUVRenderTarget = this._allocateTargets(); + cubeUVRenderTarget.depthBuffer = true; - } + this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); - } + if ( sigma > 0 ) { - function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) { + this._blur( cubeUVRenderTarget, 0, 0, sigma ); - const _programLayers = new Layers(); - const _customShaders = new WebGLShaderCache(); - const programs = []; + } - const isWebGL2 = capabilities.isWebGL2; - const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; - const vertexTextures = capabilities.vertexTextures; - let precision = capabilities.precision; + this._applyPMREM( cubeUVRenderTarget ); + this._cleanup( cubeUVRenderTarget ); - const shaderIDs = { - MeshDepthMaterial: 'depth', - MeshDistanceMaterial: 'distanceRGBA', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - MeshToonMaterial: 'toon', - MeshStandardMaterial: 'physical', - MeshPhysicalMaterial: 'physical', - MeshMatcapMaterial: 'matcap', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointsMaterial: 'points', - ShadowMaterial: 'shadow', - SpriteMaterial: 'sprite' - }; + return cubeUVRenderTarget; - function getParameters( material, lights, shadows, scene, object ) { + } - const fog = scene.fog; - const geometry = object.geometry; - const environment = material.isMeshStandardMaterial ? scene.environment : null; + /** + * Generates a PMREM from an equirectangular texture, which can be either LDR + * or HDR. The ideal input image size is 1k (1024 x 512), + * as this matches best with the 256 x 256 cubemap output. + */ + fromEquirectangular( equirectangular, renderTarget = null ) { - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null; + return this._fromTexture( equirectangular, renderTarget ); - const shaderID = shaderIDs[ material.type ]; + } - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * or HDR. The ideal input cube size is 256 x 256, + * as this matches best with the 256 x 256 cubemap output. + */ + fromCubemap( cubemap, renderTarget = null ) { - if ( material.precision !== null ) { + return this._fromTexture( cubemap, renderTarget ); - precision = capabilities.getMaxPrecision( material.precision ); + } - if ( precision !== material.precision ) { + /** + * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during + * your texture's network fetch for increased concurrency. + */ + compileCubemapShader() { - console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); + if ( this._cubemapMaterial === null ) { - } + this._cubemapMaterial = _getCubemapMaterial(); + this._compileMaterial( this._cubemapMaterial ); } - // + } - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + /** + * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during + * your texture's network fetch for increased concurrency. + */ + compileEquirectangularShader() { - let morphTextureStride = 0; + if ( this._equirectMaterial === null ) { - if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1; - if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2; - if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3; + this._equirectMaterial = _getEquirectMaterial(); + this._compileMaterial( this._equirectMaterial ); - // + } - let vertexShader, fragmentShader; - let customVertexShaderID, customFragmentShaderID; + } - if ( shaderID ) { + /** + * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, + * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on + * one of them will cause any others to also become unusable. + */ + dispose() { - const shader = ShaderLib[ shaderID ]; + this._dispose(); - vertexShader = shader.vertexShader; - fragmentShader = shader.fragmentShader; + if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); + if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); - } else { + } - vertexShader = material.vertexShader; - fragmentShader = material.fragmentShader; + // private interface - _customShaders.update( material ); + _setSize( cubeSize ) { - customVertexShaderID = _customShaders.getVertexShaderID( material ); - customFragmentShaderID = _customShaders.getFragmentShaderID( material ); + this._lodMax = Math.floor( Math.log2( cubeSize ) ); + this._cubeSize = Math.pow( 2, this._lodMax ); - } + } - const currentRenderTarget = renderer.getRenderTarget(); + _dispose() { - const useAlphaTest = material.alphaTest > 0; - const useClearcoat = material.clearcoat > 0; - const useIridescence = material.iridescence > 0; + if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); - const parameters = { + if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); - isWebGL2: isWebGL2, + for ( let i = 0; i < this._lodPlanes.length; i ++ ) { - shaderID: shaderID, - shaderName: material.type, + this._lodPlanes[ i ].dispose(); - vertexShader: vertexShader, - fragmentShader: fragmentShader, - defines: material.defines, + } - customVertexShaderID: customVertexShaderID, - customFragmentShaderID: customFragmentShaderID, + } - isRawShaderMaterial: material.isRawShaderMaterial === true, - glslVersion: material.glslVersion, + _cleanup( outputTarget ) { - precision: precision, + this._renderer.setRenderTarget( _oldTarget ); + outputTarget.scissorTest = false; + _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); - instancing: object.isInstancedMesh === true, - instancingColor: object.isInstancedMesh === true && object.instanceColor !== null, + } - supportsVertexTextures: vertexTextures, - outputEncoding: ( currentRenderTarget === null ) ? renderer.outputEncoding : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.encoding : LinearEncoding ), - map: !! material.map, - matcap: !! material.matcap, - envMap: !! envMap, - envMapMode: envMap && envMap.mapping, - envMapCubeUVHeight: envMapCubeUVHeight, - lightMap: !! material.lightMap, - aoMap: !! material.aoMap, - emissiveMap: !! material.emissiveMap, - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, - tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap, + _fromTexture( texture, renderTarget ) { - decodeVideoTexture: !! material.map && ( material.map.isVideoTexture === true ) && ( material.map.encoding === sRGBEncoding ), + if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { - clearcoat: useClearcoat, - clearcoatMap: useClearcoat && !! material.clearcoatMap, - clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap, - clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap, + this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); - iridescence: useIridescence, - iridescenceMap: useIridescence && !! material.iridescenceMap, - iridescenceThicknessMap: useIridescence && !! material.iridescenceThicknessMap, + } else { // Equirectangular - displacementMap: !! material.displacementMap, - roughnessMap: !! material.roughnessMap, - metalnessMap: !! material.metalnessMap, - specularMap: !! material.specularMap, - specularIntensityMap: !! material.specularIntensityMap, - specularColorMap: !! material.specularColorMap, + this._setSize( texture.image.width / 4 ); - opaque: material.transparent === false && material.blending === NormalBlending, + } - alphaMap: !! material.alphaMap, - alphaTest: useAlphaTest, + _oldTarget = this._renderer.getRenderTarget(); - gradientMap: !! material.gradientMap, + const cubeUVRenderTarget = renderTarget || this._allocateTargets(); + this._textureToCubeUV( texture, cubeUVRenderTarget ); + this._applyPMREM( cubeUVRenderTarget ); + this._cleanup( cubeUVRenderTarget ); - sheen: material.sheen > 0, - sheenColorMap: !! material.sheenColorMap, - sheenRoughnessMap: !! material.sheenRoughnessMap, + return cubeUVRenderTarget; - transmission: material.transmission > 0, - transmissionMap: !! material.transmissionMap, - thicknessMap: !! material.thicknessMap, + } - combine: material.combine, + _allocateTargets() { - vertexTangents: ( !! material.normalMap && !! geometry.attributes.tangent ), - vertexColors: material.vertexColors, - vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, - vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || !! material.sheenRoughnessMap, - uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap, + const width = 3 * Math.max( this._cubeSize, 16 * 7 ); + const height = 4 * this._cubeSize; - fog: !! fog, - useFog: material.fog === true, - fogExp2: ( fog && fog.isFogExp2 ), + const params = { + magFilter: LinearFilter, + minFilter: LinearFilter, + generateMipmaps: false, + type: HalfFloatType, + format: RGBAFormat, + encoding: LinearEncoding, + depthBuffer: false + }; - flatShading: !! material.flatShading, + const cubeUVRenderTarget = _createRenderTarget( width, height, params ); - sizeAttenuation: material.sizeAttenuation, - logarithmicDepthBuffer: logarithmicDepthBuffer, + if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width ) { - skinning: object.isSkinnedMesh === true, + if ( this._pingPongRenderTarget !== null ) { - morphTargets: geometry.morphAttributes.position !== undefined, - morphNormals: geometry.morphAttributes.normal !== undefined, - morphColors: geometry.morphAttributes.color !== undefined, - morphTargetsCount: morphTargetsCount, - morphTextureStride: morphTextureStride, + this._dispose(); - numDirLights: lights.directional.length, - numPointLights: lights.point.length, - numSpotLights: lights.spot.length, - numSpotLightMaps: lights.spotLightMap.length, - numRectAreaLights: lights.rectArea.length, - numHemiLights: lights.hemi.length, + } - numDirLightShadows: lights.directionalShadowMap.length, - numPointLightShadows: lights.pointShadowMap.length, - numSpotLightShadows: lights.spotShadowMap.length, - numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, + this._pingPongRenderTarget = _createRenderTarget( width, height, params ); - numClippingPlanes: clipping.numPlanes, - numClipIntersection: clipping.numIntersection, + const { _lodMax } = this; + ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); - dithering: material.dithering, + this._blurMaterial = _getBlurShader( _lodMax, width, height ); - shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, - shadowMapType: renderer.shadowMap.type, + } - toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping, - physicallyCorrectLights: renderer.physicallyCorrectLights, + return cubeUVRenderTarget; - premultipliedAlpha: material.premultipliedAlpha, + } - doubleSided: material.side === DoubleSide, - flipSided: material.side === BackSide, + _compileMaterial( material ) { - useDepthPacking: !! material.depthPacking, - depthPacking: material.depthPacking || 0, + const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); + this._renderer.compile( tmpMesh, _flatCamera ); - index0AttributeName: material.index0AttributeName, + } - extensionDerivatives: material.extensions && material.extensions.derivatives, - extensionFragDepth: material.extensions && material.extensions.fragDepth, - extensionDrawBuffers: material.extensions && material.extensions.drawBuffers, - extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD, + _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { - rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ), - rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ), - rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ), + const fov = 90; + const aspect = 1; + const cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); + const upSign = [ 1, - 1, 1, 1, 1, 1 ]; + const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; + const renderer = this._renderer; - customProgramCacheKey: material.customProgramCacheKey() + const originalAutoClear = renderer.autoClear; + const toneMapping = renderer.toneMapping; + renderer.getClearColor( _clearColor ); - }; + renderer.toneMapping = NoToneMapping; + renderer.autoClear = false; - return parameters; + const backgroundMaterial = new MeshBasicMaterial( { + name: 'PMREM.Background', + side: BackSide, + depthWrite: false, + depthTest: false, + } ); - } + const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); - function getProgramCacheKey( parameters ) { + let useSolidColor = false; + const background = scene.background; - const array = []; + if ( background ) { - if ( parameters.shaderID ) { + if ( background.isColor ) { - array.push( parameters.shaderID ); + backgroundMaterial.color.copy( background ); + scene.background = null; + useSolidColor = true; + + } } else { - array.push( parameters.customVertexShaderID ); - array.push( parameters.customFragmentShaderID ); + backgroundMaterial.color.copy( _clearColor ); + useSolidColor = true; } - if ( parameters.defines !== undefined ) { + for ( let i = 0; i < 6; i ++ ) { - for ( const name in parameters.defines ) { + const col = i % 3; - array.push( name ); - array.push( parameters.defines[ name ] ); + if ( col === 0 ) { - } + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); - } + } else if ( col === 1 ) { - if ( parameters.isRawShaderMaterial === false ) { - - getProgramCacheKeyParameters( array, parameters ); - getProgramCacheKeyBooleans( array, parameters ); - array.push( renderer.outputEncoding ); + cubeCamera.up.set( 0, 0, upSign[ i ] ); + cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); - } + } else { - array.push( parameters.customProgramCacheKey ); + cubeCamera.up.set( 0, upSign[ i ], 0 ); + cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); - return array.join(); + } - } + const size = this._cubeSize; - function getProgramCacheKeyParameters( array, parameters ) { + _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); - array.push( parameters.precision ); - array.push( parameters.outputEncoding ); - array.push( parameters.envMapMode ); - array.push( parameters.envMapCubeUVHeight ); - array.push( parameters.combine ); - array.push( parameters.vertexUvs ); - array.push( parameters.fogExp2 ); - array.push( parameters.sizeAttenuation ); - array.push( parameters.morphTargetsCount ); - array.push( parameters.morphAttributeCount ); - array.push( parameters.numDirLights ); - array.push( parameters.numPointLights ); - array.push( parameters.numSpotLights ); - array.push( parameters.numSpotLightMaps ); - array.push( parameters.numHemiLights ); - array.push( parameters.numRectAreaLights ); - array.push( parameters.numDirLightShadows ); - array.push( parameters.numPointLightShadows ); - array.push( parameters.numSpotLightShadows ); - array.push( parameters.numSpotLightShadowsWithMaps ); - array.push( parameters.shadowMapType ); - array.push( parameters.toneMapping ); - array.push( parameters.numClippingPlanes ); - array.push( parameters.numClipIntersection ); - array.push( parameters.depthPacking ); + renderer.setRenderTarget( cubeUVRenderTarget ); - } + if ( useSolidColor ) { - function getProgramCacheKeyBooleans( array, parameters ) { + renderer.render( backgroundBox, cubeCamera ); - _programLayers.disableAll(); + } - if ( parameters.isWebGL2 ) - _programLayers.enable( 0 ); - if ( parameters.supportsVertexTextures ) - _programLayers.enable( 1 ); - if ( parameters.instancing ) - _programLayers.enable( 2 ); - if ( parameters.instancingColor ) - _programLayers.enable( 3 ); - if ( parameters.map ) - _programLayers.enable( 4 ); - if ( parameters.matcap ) - _programLayers.enable( 5 ); - if ( parameters.envMap ) - _programLayers.enable( 6 ); - if ( parameters.lightMap ) - _programLayers.enable( 7 ); - if ( parameters.aoMap ) - _programLayers.enable( 8 ); - if ( parameters.emissiveMap ) - _programLayers.enable( 9 ); - if ( parameters.bumpMap ) - _programLayers.enable( 10 ); - if ( parameters.normalMap ) - _programLayers.enable( 11 ); - if ( parameters.objectSpaceNormalMap ) - _programLayers.enable( 12 ); - if ( parameters.tangentSpaceNormalMap ) - _programLayers.enable( 13 ); - if ( parameters.clearcoat ) - _programLayers.enable( 14 ); - if ( parameters.clearcoatMap ) - _programLayers.enable( 15 ); - if ( parameters.clearcoatRoughnessMap ) - _programLayers.enable( 16 ); - if ( parameters.clearcoatNormalMap ) - _programLayers.enable( 17 ); - if ( parameters.iridescence ) - _programLayers.enable( 18 ); - if ( parameters.iridescenceMap ) - _programLayers.enable( 19 ); - if ( parameters.iridescenceThicknessMap ) - _programLayers.enable( 20 ); - if ( parameters.displacementMap ) - _programLayers.enable( 21 ); - if ( parameters.specularMap ) - _programLayers.enable( 22 ); - if ( parameters.roughnessMap ) - _programLayers.enable( 23 ); - if ( parameters.metalnessMap ) - _programLayers.enable( 24 ); - if ( parameters.gradientMap ) - _programLayers.enable( 25 ); - if ( parameters.alphaMap ) - _programLayers.enable( 26 ); - if ( parameters.alphaTest ) - _programLayers.enable( 27 ); - if ( parameters.vertexColors ) - _programLayers.enable( 28 ); - if ( parameters.vertexAlphas ) - _programLayers.enable( 29 ); - if ( parameters.vertexUvs ) - _programLayers.enable( 30 ); - if ( parameters.vertexTangents ) - _programLayers.enable( 31 ); - if ( parameters.uvsVertexOnly ) - _programLayers.enable( 32 ); + renderer.render( scene, cubeCamera ); - array.push( _programLayers.mask ); - _programLayers.disableAll(); + } - if ( parameters.fog ) - _programLayers.enable( 0 ); - if ( parameters.useFog ) - _programLayers.enable( 1 ); - if ( parameters.flatShading ) - _programLayers.enable( 2 ); - if ( parameters.logarithmicDepthBuffer ) - _programLayers.enable( 3 ); - if ( parameters.skinning ) - _programLayers.enable( 4 ); - if ( parameters.morphTargets ) - _programLayers.enable( 5 ); - if ( parameters.morphNormals ) - _programLayers.enable( 6 ); - if ( parameters.morphColors ) - _programLayers.enable( 7 ); - if ( parameters.premultipliedAlpha ) - _programLayers.enable( 8 ); - if ( parameters.shadowMapEnabled ) - _programLayers.enable( 9 ); - if ( parameters.physicallyCorrectLights ) - _programLayers.enable( 10 ); - if ( parameters.doubleSided ) - _programLayers.enable( 11 ); - if ( parameters.flipSided ) - _programLayers.enable( 12 ); - if ( parameters.useDepthPacking ) - _programLayers.enable( 13 ); - if ( parameters.dithering ) - _programLayers.enable( 14 ); - if ( parameters.specularIntensityMap ) - _programLayers.enable( 15 ); - if ( parameters.specularColorMap ) - _programLayers.enable( 16 ); - if ( parameters.transmission ) - _programLayers.enable( 17 ); - if ( parameters.transmissionMap ) - _programLayers.enable( 18 ); - if ( parameters.thicknessMap ) - _programLayers.enable( 19 ); - if ( parameters.sheen ) - _programLayers.enable( 20 ); - if ( parameters.sheenColorMap ) - _programLayers.enable( 21 ); - if ( parameters.sheenRoughnessMap ) - _programLayers.enable( 22 ); - if ( parameters.decodeVideoTexture ) - _programLayers.enable( 23 ); - if ( parameters.opaque ) - _programLayers.enable( 24 ); + backgroundBox.geometry.dispose(); + backgroundBox.material.dispose(); - array.push( _programLayers.mask ); + renderer.toneMapping = toneMapping; + renderer.autoClear = originalAutoClear; + scene.background = background; } - function getUniforms( material ) { - - const shaderID = shaderIDs[ material.type ]; - let uniforms; - - if ( shaderID ) { - - const shader = ShaderLib[ shaderID ]; - uniforms = UniformsUtils.clone( shader.uniforms ); - - } else { - - uniforms = material.uniforms; + _textureToCubeUV( texture, cubeUVRenderTarget ) { - } + const renderer = this._renderer; - return uniforms; + const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); - } + if ( isCubeTexture ) { - function acquireProgram( parameters, cacheKey ) { + if ( this._cubemapMaterial === null ) { - let program; + this._cubemapMaterial = _getCubemapMaterial(); - // Check if code has been already compiled - for ( let p = 0, pl = programs.length; p < pl; p ++ ) { + } - const preexistingProgram = programs[ p ]; + this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1; - if ( preexistingProgram.cacheKey === cacheKey ) { + } else { - program = preexistingProgram; - ++ program.usedTimes; + if ( this._equirectMaterial === null ) { - break; + this._equirectMaterial = _getEquirectMaterial(); } } - if ( program === undefined ) { - - program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); - programs.push( program ); + const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; + const mesh = new Mesh( this._lodPlanes[ 0 ], material ); - } + const uniforms = material.uniforms; - return program; + uniforms[ 'envMap' ].value = texture; - } + const size = this._cubeSize; - function releaseProgram( program ) { + _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); - if ( -- program.usedTimes === 0 ) { + renderer.setRenderTarget( cubeUVRenderTarget ); + renderer.render( mesh, _flatCamera ); - // Remove from unordered set - const i = programs.indexOf( program ); - programs[ i ] = programs[ programs.length - 1 ]; - programs.pop(); + } - // Free WebGL resources - program.destroy(); + _applyPMREM( cubeUVRenderTarget ) { - } + const renderer = this._renderer; + const autoClear = renderer.autoClear; + renderer.autoClear = false; - } + for ( let i = 1; i < this._lodPlanes.length; i ++ ) { - function releaseShaderCache( material ) { + const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); - _customShaders.remove( material ); + const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ]; - } + this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); - function dispose() { + } - _customShaders.dispose(); + renderer.autoClear = autoClear; } - return { - getParameters: getParameters, - getProgramCacheKey: getProgramCacheKey, - getUniforms: getUniforms, - acquireProgram: acquireProgram, - releaseProgram: releaseProgram, - releaseShaderCache: releaseShaderCache, - // Exposed for resource monitoring & error feedback via renderer.info: - programs: programs, - dispose: dispose - }; + /** + * This is a two-pass Gaussian blur for a cubemap. Normally this is done + * vertically and horizontally, but this breaks down on a cube. Here we apply + * the blur latitudinally (around the poles), and then longitudinally (towards + * the poles) to approximate the orthogonally-separable blur. It is least + * accurate at the poles, but still does a decent job. + */ + _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { - } + const pingPongRenderTarget = this._pingPongRenderTarget; - function WebGLProperties() { + this._halfBlur( + cubeUVRenderTarget, + pingPongRenderTarget, + lodIn, + lodOut, + sigma, + 'latitudinal', + poleAxis ); - let properties = new WeakMap(); + this._halfBlur( + pingPongRenderTarget, + cubeUVRenderTarget, + lodOut, + lodOut, + sigma, + 'longitudinal', + poleAxis ); - function get( object ) { + } - let map = properties.get( object ); + _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { - if ( map === undefined ) { + const renderer = this._renderer; + const blurMaterial = this._blurMaterial; - map = {}; - properties.set( object, map ); + if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { + + console.error( + 'blur direction must be either latitudinal or longitudinal!' ); } - return map; + // Number of standard deviations at which to cut off the discrete approximation. + const STANDARD_DEVIATIONS = 3; - } + const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial ); + const blurUniforms = blurMaterial.uniforms; - function remove( object ) { + const pixels = this._sizeLods[ lodIn ] - 1; + const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); + const sigmaPixels = sigmaRadians / radiansPerPixel; + const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; - properties.delete( object ); + if ( samples > MAX_SAMPLES ) { - } + console.warn( `sigmaRadians, ${ + sigmaRadians}, is too large and will clip, as it requested ${ + samples} samples when the maximum is set to ${MAX_SAMPLES}` ); - function update( object, key, value ) { + } - properties.get( object )[ key ] = value; + const weights = []; + let sum = 0; - } + for ( let i = 0; i < MAX_SAMPLES; ++ i ) { - function dispose() { + const x = i / sigmaPixels; + const weight = Math.exp( - x * x / 2 ); + weights.push( weight ); - properties = new WeakMap(); + if ( i === 0 ) { - } + sum += weight; - return { - get: get, - remove: remove, - update: update, - dispose: dispose - }; + } else if ( i < samples ) { - } + sum += 2 * weight; - function painterSortStable( a, b ) { + } - if ( a.groupOrder !== b.groupOrder ) { + } - return a.groupOrder - b.groupOrder; + for ( let i = 0; i < weights.length; i ++ ) { - } else if ( a.renderOrder !== b.renderOrder ) { + weights[ i ] = weights[ i ] / sum; - return a.renderOrder - b.renderOrder; + } - } else if ( a.material.id !== b.material.id ) { + blurUniforms[ 'envMap' ].value = targetIn.texture; + blurUniforms[ 'samples' ].value = samples; + blurUniforms[ 'weights' ].value = weights; + blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; - return a.material.id - b.material.id; + if ( poleAxis ) { - } else if ( a.z !== b.z ) { + blurUniforms[ 'poleAxis' ].value = poleAxis; - return a.z - b.z; + } - } else { + const { _lodMax } = this; + blurUniforms[ 'dTheta' ].value = radiansPerPixel; + blurUniforms[ 'mipInt' ].value = _lodMax - lodIn; - return a.id - b.id; + const outputSize = this._sizeLods[ lodOut ]; + const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); + const y = 4 * ( this._cubeSize - outputSize ); + + _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); + renderer.setRenderTarget( targetOut ); + renderer.render( blurMesh, _flatCamera ); } } - function reversePainterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - return a.renderOrder - b.renderOrder; - } else if ( a.z !== b.z ) { + function _createPlanes( lodMax ) { - return b.z - a.z; + const lodPlanes = []; + const sizeLods = []; + const sigmas = []; - } else { + let lod = lodMax; - return a.id - b.id; + const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; - } + for ( let i = 0; i < totalLods; i ++ ) { - } + const sizeLod = Math.pow( 2, lod ); + sizeLods.push( sizeLod ); + let sigma = 1.0 / sizeLod; + if ( i > lodMax - LOD_MIN ) { - function WebGLRenderList() { + sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; - const renderItems = []; - let renderItemsIndex = 0; + } else if ( i === 0 ) { - const opaque = []; - const transmissive = []; - const transparent = []; + sigma = 0; - function init() { + } - renderItemsIndex = 0; + sigmas.push( sigma ); - opaque.length = 0; - transmissive.length = 0; - transparent.length = 0; + const texelSize = 1.0 / ( sizeLod - 2 ); + const min = - texelSize; + const max = 1 + texelSize; + const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; - } + const cubeFaces = 6; + const vertices = 6; + const positionSize = 3; + const uvSize = 2; + const faceIndexSize = 1; - function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { + const position = new Float32Array( positionSize * vertices * cubeFaces ); + const uv = new Float32Array( uvSize * vertices * cubeFaces ); + const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); - let renderItem = renderItems[ renderItemsIndex ]; + for ( let face = 0; face < cubeFaces; face ++ ) { - if ( renderItem === undefined ) { + const x = ( face % 3 ) * 2 / 3 - 1; + const y = face > 2 ? 0 : - 1; + const coordinates = [ + x, y, 0, + x + 2 / 3, y, 0, + x + 2 / 3, y + 1, 0, + x, y, 0, + x + 2 / 3, y + 1, 0, + x, y + 1, 0 + ]; + position.set( coordinates, positionSize * vertices * face ); + uv.set( uv1, uvSize * vertices * face ); + const fill = [ face, face, face, face, face, face ]; + faceIndex.set( fill, faceIndexSize * vertices * face ); - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - groupOrder: groupOrder, - renderOrder: object.renderOrder, - z: z, - group: group - }; + } - renderItems[ renderItemsIndex ] = renderItem; + const planes = new BufferGeometry(); + planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); + planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); + planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); + lodPlanes.push( planes ); - } else { + if ( lod > LOD_MIN ) { - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.groupOrder = groupOrder; - renderItem.renderOrder = object.renderOrder; - renderItem.z = z; - renderItem.group = group; + lod --; } - renderItemsIndex ++; - - return renderItem; - } - function push( object, geometry, material, groupOrder, z, group ) { + return { lodPlanes, sizeLods, sigmas }; - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); + } - if ( material.transmission > 0.0 ) { + function _createRenderTarget( width, height, params ) { - transmissive.push( renderItem ); + const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params ); + cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; + cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; + cubeUVRenderTarget.scissorTest = true; + return cubeUVRenderTarget; - } else if ( material.transparent === true ) { + } - transparent.push( renderItem ); + function _setViewport( target, x, y, width, height ) { - } else { + target.viewport.set( x, y, width, height ); + target.scissor.set( x, y, width, height ); - opaque.push( renderItem ); + } - } + function _getBlurShader( lodMax, width, height ) { - } + const weights = new Float32Array( MAX_SAMPLES ); + const poleAxis = new Vector3( 0, 1, 0 ); + const shaderMaterial = new ShaderMaterial( { - function unshift( object, geometry, material, groupOrder, z, group ) { + name: 'SphericalGaussianBlur', - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); + defines: { + 'n': MAX_SAMPLES, + 'CUBEUV_TEXEL_WIDTH': 1.0 / width, + 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, + 'CUBEUV_MAX_MIP': `${lodMax}.0`, + }, - if ( material.transmission > 0.0 ) { + uniforms: { + 'envMap': { value: null }, + 'samples': { value: 1 }, + 'weights': { value: weights }, + 'latitudinal': { value: false }, + 'dTheta': { value: 0 }, + 'mipInt': { value: 0 }, + 'poleAxis': { value: poleAxis } + }, - transmissive.unshift( renderItem ); + vertexShader: _getCommonVertexShader(), - } else if ( material.transparent === true ) { + fragmentShader: /* glsl */` - transparent.unshift( renderItem ); + precision mediump float; + precision mediump int; - } else { + varying vec3 vOutputDirection; - opaque.unshift( renderItem ); + uniform sampler2D envMap; + uniform int samples; + uniform float weights[ n ]; + uniform bool latitudinal; + uniform float dTheta; + uniform float mipInt; + uniform vec3 poleAxis; - } + #define ENVMAP_TYPE_CUBE_UV + #include - } + vec3 getSample( float theta, vec3 axis ) { - function sort( customOpaqueSort, customTransparentSort ) { + float cosTheta = cos( theta ); + // Rodrigues' axis-angle rotation + vec3 sampleDirection = vOutputDirection * cosTheta + + cross( axis, vOutputDirection ) * sin( theta ) + + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); - if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable ); - if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable ); - if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable ); + return bilinearCubeUV( envMap, sampleDirection, mipInt ); - } + } - function finish() { + void main() { - // Clear references from inactive renderItems in the list + vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); - for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { + if ( all( equal( axis, vec3( 0.0 ) ) ) ) { - const renderItem = renderItems[ i ]; + axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); - if ( renderItem.id === null ) break; + } - renderItem.id = null; - renderItem.object = null; - renderItem.geometry = null; - renderItem.material = null; - renderItem.group = null; + axis = normalize( axis ); - } + gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); - } + for ( int i = 1; i < n; i++ ) { - return { + if ( i >= samples ) { - opaque: opaque, - transmissive: transmissive, - transparent: transparent, + break; - init: init, - push: push, - unshift: unshift, - finish: finish, + } - sort: sort - }; + float theta = dTheta * float( i ); + gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); + gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); - } + } - function WebGLRenderLists() { + } + `, - let lists = new WeakMap(); + blending: NoBlending, + depthTest: false, + depthWrite: false - function get( scene, renderCallDepth ) { + } ); - const listArray = lists.get( scene ); - let list; + return shaderMaterial; - if ( listArray === undefined ) { + } - list = new WebGLRenderList(); - lists.set( scene, [ list ] ); + function _getEquirectMaterial() { - } else { + return new ShaderMaterial( { - if ( renderCallDepth >= listArray.length ) { + name: 'EquirectangularToCubeUV', - list = new WebGLRenderList(); - listArray.push( list ); + uniforms: { + 'envMap': { value: null } + }, - } else { + vertexShader: _getCommonVertexShader(), - list = listArray[ renderCallDepth ]; + fragmentShader: /* glsl */` - } + precision mediump float; + precision mediump int; - } + varying vec3 vOutputDirection; - return list; + uniform sampler2D envMap; - } + #include - function dispose() { + void main() { - lists = new WeakMap(); + vec3 outputDirection = normalize( vOutputDirection ); + vec2 uv = equirectUv( outputDirection ); - } + gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); - return { - get: get, - dispose: dispose - }; + } + `, - } + blending: NoBlending, + depthTest: false, + depthWrite: false - function UniformsCache() { + } ); - const lights = {}; + } - return { + function _getCubemapMaterial() { - get: function ( light ) { + return new ShaderMaterial( { - if ( lights[ light.id ] !== undefined ) { + name: 'CubemapToCubeUV', - return lights[ light.id ]; + uniforms: { + 'envMap': { value: null }, + 'flipEnvMap': { value: - 1 } + }, - } + vertexShader: _getCommonVertexShader(), - let uniforms; + fragmentShader: /* glsl */` - switch ( light.type ) { + precision mediump float; + precision mediump int; - case 'DirectionalLight': - uniforms = { - direction: new Vector3(), - color: new Color() - }; - break; + uniform float flipEnvMap; - case 'SpotLight': - uniforms = { - position: new Vector3(), - direction: new Vector3(), - color: new Color(), - distance: 0, - coneCos: 0, - penumbraCos: 0, - decay: 0 - }; - break; + varying vec3 vOutputDirection; - case 'PointLight': - uniforms = { - position: new Vector3(), - color: new Color(), - distance: 0, - decay: 0 - }; - break; + uniform samplerCube envMap; - case 'HemisphereLight': - uniforms = { - direction: new Vector3(), - skyColor: new Color(), - groundColor: new Color() - }; - break; + void main() { - case 'RectAreaLight': - uniforms = { - color: new Color(), - position: new Vector3(), - halfWidth: new Vector3(), - halfHeight: new Vector3() - }; - break; + gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); - } + } + `, - lights[ light.id ] = uniforms; + blending: NoBlending, + depthTest: false, + depthWrite: false - return uniforms; + } ); - } + } - }; + function _getCommonVertexShader() { - } + return /* glsl */` - function ShadowUniformsCache() { + precision mediump float; + precision mediump int; - const lights = {}; + attribute float faceIndex; - return { + varying vec3 vOutputDirection; - get: function ( light ) { + // RH coordinate system; PMREM face-indexing convention + vec3 getDirection( vec2 uv, float face ) { - if ( lights[ light.id ] !== undefined ) { + uv = 2.0 * uv - 1.0; - return lights[ light.id ]; + vec3 direction = vec3( uv, 1.0 ); - } + if ( face == 0.0 ) { - let uniforms; + direction = direction.zyx; // ( 1, v, u ) pos x - switch ( light.type ) { + } else if ( face == 1.0 ) { - case 'DirectionalLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; + direction = direction.xzy; + direction.xz *= -1.0; // ( -u, 1, -v ) pos y - case 'SpotLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; + } else if ( face == 2.0 ) { - case 'PointLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2(), - shadowCameraNear: 1, - shadowCameraFar: 1000 - }; - break; + direction.x *= -1.0; // ( -u, v, 1 ) pos z - // TODO (abelnation): set RectAreaLight shadow uniforms + } else if ( face == 3.0 ) { - } + direction = direction.zyx; + direction.xz *= -1.0; // ( -1, v, -u ) neg x - lights[ light.id ] = uniforms; + } else if ( face == 4.0 ) { - return uniforms; + direction = direction.xzy; + direction.xy *= -1.0; // ( -u, -1, v ) neg y - } + } else if ( face == 5.0 ) { - }; + direction.z *= -1.0; // ( u, v, -1 ) neg z - } + } + return direction; + } - let nextVersion = 0; + void main() { - function shadowCastingAndTexturingLightsFirst( lightA, lightB ) { + vOutputDirection = getDirection( uv, faceIndex ); + gl_Position = vec4( position, 1.0 ); - return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 ); + } + `; } - function WebGLLights( extensions, capabilities ) { + function WebGLCubeUVMaps( renderer ) { - const cache = new UniformsCache(); + let cubeUVmaps = new WeakMap(); - const shadowCache = ShadowUniformsCache(); + let pmremGenerator = null; - const state = { + function get( texture ) { - version: 0, + if ( texture && texture.isTexture ) { - hash: { - directionalLength: - 1, - pointLength: - 1, - spotLength: - 1, - rectAreaLength: - 1, - hemiLength: - 1, + const mapping = texture.mapping; - numDirectionalShadows: - 1, - numPointShadows: - 1, - numSpotShadows: - 1, - numSpotMaps: - 1 - }, + const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ); + const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); - ambient: [ 0, 0, 0 ], - probe: [], - directional: [], - directionalShadow: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotLightMap: [], - spotShadow: [], - spotShadowMap: [], - spotLightMatrix: [], - rectArea: [], - rectAreaLTC1: null, - rectAreaLTC2: null, - point: [], - pointShadow: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [], - numSpotLightShadowsWithMaps: 0 + // equirect/cube map to cubeUV conversion - }; + if ( isEquirectMap || isCubeMap ) { - for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() ); + if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) { - const vector3 = new Vector3(); - const matrix4 = new Matrix4(); - const matrix42 = new Matrix4(); + texture.needsPMREMUpdate = false; - function setup( lights, physicallyCorrectLights ) { + let renderTarget = cubeUVmaps.get( texture ); - let r = 0, g = 0, b = 0; + if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); - for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 ); + renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget ); + cubeUVmaps.set( texture, renderTarget ); - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; + return renderTarget.texture; - let numDirectionalShadows = 0; - let numPointShadows = 0; - let numSpotShadows = 0; - let numSpotMaps = 0; - let numSpotShadowsWithMaps = 0; + } else { - // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] - lights.sort( shadowCastingAndTexturingLightsFirst ); + if ( cubeUVmaps.has( texture ) ) { - // artist-friendly light intensity scaling factor - const scaleFactor = ( physicallyCorrectLights !== true ) ? Math.PI : 1; + return cubeUVmaps.get( texture ).texture; - for ( let i = 0, l = lights.length; i < l; i ++ ) { + } else { - const light = lights[ i ]; + const image = texture.image; - const color = light.color; - const intensity = light.intensity; - const distance = light.distance; + if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) { - const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; + if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); - if ( light.isAmbientLight ) { + const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture ); + cubeUVmaps.set( texture, renderTarget ); - r += color.r * intensity * scaleFactor; - g += color.g * intensity * scaleFactor; - b += color.b * intensity * scaleFactor; + texture.addEventListener( 'dispose', onTextureDispose ); - } else if ( light.isLightProbe ) { + return renderTarget.texture; - for ( let j = 0; j < 9; j ++ ) { + } else { - state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); + // image not yet ready. try the conversion next frame - } + return null; - } else if ( light.isDirectionalLight ) { + } - const uniforms = cache.get( light ); + } - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); + } - if ( light.castShadow ) { + } - const shadow = light.shadow; + } - const shadowUniforms = shadowCache.get( light ); + return texture; - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; + } - state.directionalShadow[ directionalLength ] = shadowUniforms; - state.directionalShadowMap[ directionalLength ] = shadowMap; - state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; + function isCubeTextureComplete( image ) { - numDirectionalShadows ++; + let count = 0; + const length = 6; - } + for ( let i = 0; i < length; i ++ ) { - state.directional[ directionalLength ] = uniforms; + if ( image[ i ] !== undefined ) count ++; - directionalLength ++; + } - } else if ( light.isSpotLight ) { + return count === length; - const uniforms = cache.get( light ); - uniforms.position.setFromMatrixPosition( light.matrixWorld ); + } - uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor ); - uniforms.distance = distance; + function onTextureDispose( event ) { - uniforms.coneCos = Math.cos( light.angle ); - uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); - uniforms.decay = light.decay; + const texture = event.target; - state.spot[ spotLength ] = uniforms; + texture.removeEventListener( 'dispose', onTextureDispose ); - const shadow = light.shadow; + const cubemapUV = cubeUVmaps.get( texture ); - if ( light.map ) { + if ( cubemapUV !== undefined ) { - state.spotLightMap[ numSpotMaps ] = light.map; - numSpotMaps ++; + cubeUVmaps.delete( texture ); + cubemapUV.dispose(); - // make sure the lightMatrix is up to date - // TODO : do it if required only - shadow.updateMatrices( light ); + } - if ( light.castShadow ) numSpotShadowsWithMaps ++; + } - } + function dispose() { - state.spotLightMatrix[ spotLength ] = shadow.matrix; + cubeUVmaps = new WeakMap(); - if ( light.castShadow ) { + if ( pmremGenerator !== null ) { - const shadowUniforms = shadowCache.get( light ); + pmremGenerator.dispose(); + pmremGenerator = null; - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; + } - state.spotShadow[ spotLength ] = shadowUniforms; - state.spotShadowMap[ spotLength ] = shadowMap; + } - numSpotShadows ++; + return { + get: get, + dispose: dispose + }; - } + } - spotLength ++; + function WebGLExtensions( gl ) { - } else if ( light.isRectAreaLight ) { + const extensions = {}; - const uniforms = cache.get( light ); + function getExtension( name ) { - // (a) intensity is the total visible light emitted - //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) ); + if ( extensions[ name ] !== undefined ) { - // (b) intensity is the brightness of the light - uniforms.color.copy( color ).multiplyScalar( intensity ); + return extensions[ name ]; - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); + } - state.rectArea[ rectAreaLength ] = uniforms; + let extension; - rectAreaLength ++; + switch ( name ) { - } else if ( light.isPointLight ) { + case 'WEBGL_depth_texture': + extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); + break; - const uniforms = cache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - uniforms.distance = light.distance; - uniforms.decay = light.decay; + case 'EXT_texture_filter_anisotropic': + extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); + break; - if ( light.castShadow ) { + case 'WEBGL_compressed_texture_s3tc': + extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); + break; - const shadow = light.shadow; + case 'WEBGL_compressed_texture_pvrtc': + extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); + break; - const shadowUniforms = shadowCache.get( light ); + default: + extension = gl.getExtension( name ); - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - shadowUniforms.shadowCameraNear = shadow.camera.near; - shadowUniforms.shadowCameraFar = shadow.camera.far; + } - state.pointShadow[ pointLength ] = shadowUniforms; - state.pointShadowMap[ pointLength ] = shadowMap; - state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; + extensions[ name ] = extension; - numPointShadows ++; + return extension; - } + } - state.point[ pointLength ] = uniforms; + return { - pointLength ++; + has: function ( name ) { - } else if ( light.isHemisphereLight ) { + return getExtension( name ) !== null; - const uniforms = cache.get( light ); + }, - uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor ); - uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor ); + init: function ( capabilities ) { - state.hemi[ hemiLength ] = uniforms; + if ( capabilities.isWebGL2 ) { - hemiLength ++; + getExtension( 'EXT_color_buffer_float' ); - } + } else { - } + getExtension( 'WEBGL_depth_texture' ); + getExtension( 'OES_texture_float' ); + getExtension( 'OES_texture_half_float' ); + getExtension( 'OES_texture_half_float_linear' ); + getExtension( 'OES_standard_derivatives' ); + getExtension( 'OES_element_index_uint' ); + getExtension( 'OES_vertex_array_object' ); + getExtension( 'ANGLE_instanced_arrays' ); - if ( rectAreaLength > 0 ) { + } - if ( capabilities.isWebGL2 ) { + getExtension( 'OES_texture_float_linear' ); + getExtension( 'EXT_color_buffer_half_float' ); + getExtension( 'WEBGL_multisampled_render_to_texture' ); - // WebGL 2 + }, - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; + get: function ( name ) { - } else { + const extension = getExtension( name ); - // WebGL 1 + if ( extension === null ) { - if ( extensions.has( 'OES_texture_float_linear' ) === true ) { + console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; + } - } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) { + return extension; - state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; - state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; + } - } else { + }; - console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' ); + } - } + function WebGLGeometries( gl, attributes, info, bindingStates ) { - } + const geometries = {}; + const wireframeAttributes = new WeakMap(); - } + function onGeometryDispose( event ) { - state.ambient[ 0 ] = r; - state.ambient[ 1 ] = g; - state.ambient[ 2 ] = b; + const geometry = event.target; - const hash = state.hash; + if ( geometry.index !== null ) { - if ( hash.directionalLength !== directionalLength || - hash.pointLength !== pointLength || - hash.spotLength !== spotLength || - hash.rectAreaLength !== rectAreaLength || - hash.hemiLength !== hemiLength || - hash.numDirectionalShadows !== numDirectionalShadows || - hash.numPointShadows !== numPointShadows || - hash.numSpotShadows !== numSpotShadows || - hash.numSpotMaps !== numSpotMaps ) { + attributes.remove( geometry.index ); - state.directional.length = directionalLength; - state.spot.length = spotLength; - state.rectArea.length = rectAreaLength; - state.point.length = pointLength; - state.hemi.length = hemiLength; + } - state.directionalShadow.length = numDirectionalShadows; - state.directionalShadowMap.length = numDirectionalShadows; - state.pointShadow.length = numPointShadows; - state.pointShadowMap.length = numPointShadows; - state.spotShadow.length = numSpotShadows; - state.spotShadowMap.length = numSpotShadows; - state.directionalShadowMatrix.length = numDirectionalShadows; - state.pointShadowMatrix.length = numPointShadows; - state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; - state.spotLightMap.length = numSpotMaps; - state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; + for ( const name in geometry.attributes ) { - hash.directionalLength = directionalLength; - hash.pointLength = pointLength; - hash.spotLength = spotLength; - hash.rectAreaLength = rectAreaLength; - hash.hemiLength = hemiLength; + attributes.remove( geometry.attributes[ name ] ); - hash.numDirectionalShadows = numDirectionalShadows; - hash.numPointShadows = numPointShadows; - hash.numSpotShadows = numSpotShadows; - hash.numSpotMaps = numSpotMaps; + } - state.version = nextVersion ++; + geometry.removeEventListener( 'dispose', onGeometryDispose ); - } + delete geometries[ geometry.id ]; - } + const attribute = wireframeAttributes.get( geometry ); - function setupView( lights, camera ) { + if ( attribute ) { - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; + attributes.remove( attribute ); + wireframeAttributes.delete( geometry ); - const viewMatrix = camera.matrixWorldInverse; + } - for ( let i = 0, l = lights.length; i < l; i ++ ) { + bindingStates.releaseStatesOfGeometry( geometry ); - const light = lights[ i ]; + if ( geometry.isInstancedBufferGeometry === true ) { - if ( light.isDirectionalLight ) { + delete geometry._maxInstanceCount; - const uniforms = state.directional[ directionalLength ]; + } - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); + // - directionalLength ++; + info.memory.geometries --; - } else if ( light.isSpotLight ) { + } - const uniforms = state.spot[ spotLength ]; + function get( object, geometry ) { - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + if ( geometries[ geometry.id ] === true ) return geometry; - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); + geometry.addEventListener( 'dispose', onGeometryDispose ); - spotLength ++; + geometries[ geometry.id ] = true; - } else if ( light.isRectAreaLight ) { + info.memory.geometries ++; - const uniforms = state.rectArea[ rectAreaLength ]; + return geometry; - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + } - // extract local rotation of light to derive width/height half vectors - matrix42.identity(); - matrix4.copy( light.matrixWorld ); - matrix4.premultiply( viewMatrix ); - matrix42.extractRotation( matrix4 ); + function update( geometry ) { - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); + const geometryAttributes = geometry.attributes; - uniforms.halfWidth.applyMatrix4( matrix42 ); - uniforms.halfHeight.applyMatrix4( matrix42 ); + // Updating index buffer in VAO now. See WebGLBindingStates. - rectAreaLength ++; + for ( const name in geometryAttributes ) { - } else if ( light.isPointLight ) { + attributes.update( geometryAttributes[ name ], 34962 ); - const uniforms = state.point[ pointLength ]; + } - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + // morph targets - pointLength ++; + const morphAttributes = geometry.morphAttributes; - } else if ( light.isHemisphereLight ) { + for ( const name in morphAttributes ) { - const uniforms = state.hemi[ hemiLength ]; + const array = morphAttributes[ name ]; - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - uniforms.direction.transformDirection( viewMatrix ); + for ( let i = 0, l = array.length; i < l; i ++ ) { - hemiLength ++; + attributes.update( array[ i ], 34962 ); } @@ -30162,9622 +61297,10020 @@ var app = (function () { } - return { - setup: setup, - setupView: setupView, - state: state - }; - - } + function updateWireframeAttribute( geometry ) { - function WebGLRenderState( extensions, capabilities ) { + const indices = []; - const lights = new WebGLLights( extensions, capabilities ); + const geometryIndex = geometry.index; + const geometryPosition = geometry.attributes.position; + let version = 0; - const lightsArray = []; - const shadowsArray = []; + if ( geometryIndex !== null ) { - function init() { + const array = geometryIndex.array; + version = geometryIndex.version; - lightsArray.length = 0; - shadowsArray.length = 0; + for ( let i = 0, l = array.length; i < l; i += 3 ) { - } + const a = array[ i + 0 ]; + const b = array[ i + 1 ]; + const c = array[ i + 2 ]; - function pushLight( light ) { + indices.push( a, b, b, c, c, a ); - lightsArray.push( light ); + } - } + } else { - function pushShadow( shadowLight ) { + const array = geometryPosition.array; + version = geometryPosition.version; - shadowsArray.push( shadowLight ); + for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - } + const a = i + 0; + const b = i + 1; + const c = i + 2; - function setupLights( physicallyCorrectLights ) { + indices.push( a, b, b, c, c, a ); - lights.setup( lightsArray, physicallyCorrectLights ); + } - } + } - function setupLightsView( camera ) { + const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + attribute.version = version; - lights.setupView( lightsArray, camera ); + // Updating index buffer in VAO now. See WebGLBindingStates - } + // - const state = { - lightsArray: lightsArray, - shadowsArray: shadowsArray, + const previousAttribute = wireframeAttributes.get( geometry ); - lights: lights - }; + if ( previousAttribute ) attributes.remove( previousAttribute ); - return { - init: init, - state: state, - setupLights: setupLights, - setupLightsView: setupLightsView, + // - pushLight: pushLight, - pushShadow: pushShadow - }; + wireframeAttributes.set( geometry, attribute ); - } + } - function WebGLRenderStates( extensions, capabilities ) { + function getWireframeAttribute( geometry ) { - let renderStates = new WeakMap(); + const currentAttribute = wireframeAttributes.get( geometry ); - function get( scene, renderCallDepth = 0 ) { + if ( currentAttribute ) { - const renderStateArray = renderStates.get( scene ); - let renderState; + const geometryIndex = geometry.index; - if ( renderStateArray === undefined ) { + if ( geometryIndex !== null ) { - renderState = new WebGLRenderState( extensions, capabilities ); - renderStates.set( scene, [ renderState ] ); + // if the attribute is obsolete, create a new one - } else { + if ( currentAttribute.version < geometryIndex.version ) { - if ( renderCallDepth >= renderStateArray.length ) { + updateWireframeAttribute( geometry ); - renderState = new WebGLRenderState( extensions, capabilities ); - renderStateArray.push( renderState ); + } - } else { + } - renderState = renderStateArray[ renderCallDepth ]; + } else { - } + updateWireframeAttribute( geometry ); } - return renderState; + return wireframeAttributes.get( geometry ); } - function dispose() { + return { - renderStates = new WeakMap(); + get: get, + update: update, - } + getWireframeAttribute: getWireframeAttribute - return { - get: get, - dispose: dispose }; } - class MeshDepthMaterial extends Material { + function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { - constructor( parameters ) { + const isWebGL2 = capabilities.isWebGL2; - super(); + let mode; - this.isMeshDepthMaterial = true; + function setMode( value ) { - this.type = 'MeshDepthMaterial'; + mode = value; - this.depthPacking = BasicDepthPacking; + } - this.map = null; + let type, bytesPerElement; - this.alphaMap = null; + function setIndex( value ) { - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + type = value.type; + bytesPerElement = value.bytesPerElement; - this.wireframe = false; - this.wireframeLinewidth = 1; + } - this.setValues( parameters ); + function render( start, count ) { + + gl.drawElements( mode, count, type, start * bytesPerElement ); + + info.update( count, mode, 1 ); } - copy( source ) { + function renderInstances( start, count, primcount ) { - super.copy( source ); + if ( primcount === 0 ) return; - this.depthPacking = source.depthPacking; + let extension, methodName; - this.map = source.map; + if ( isWebGL2 ) { - this.alphaMap = source.alphaMap; + extension = gl; + methodName = 'drawElementsInstanced'; - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + } else { - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; + extension = extensions.get( 'ANGLE_instanced_arrays' ); + methodName = 'drawElementsInstancedANGLE'; - return this; + if ( extension === null ) { + + console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; + + } + + } + + extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); + + info.update( count, mode, primcount ); } - } + // - class MeshDistanceMaterial extends Material { + this.setMode = setMode; + this.setIndex = setIndex; + this.render = render; + this.renderInstances = renderInstances; - constructor( parameters ) { + } - super(); + function WebGLInfo( gl ) { - this.isMeshDistanceMaterial = true; + const memory = { + geometries: 0, + textures: 0 + }; - this.type = 'MeshDistanceMaterial'; + const render = { + frame: 0, + calls: 0, + triangles: 0, + points: 0, + lines: 0 + }; - this.referencePosition = new Vector3(); - this.nearDistance = 1; - this.farDistance = 1000; + function update( count, mode, instanceCount ) { - this.map = null; + render.calls ++; - this.alphaMap = null; + switch ( mode ) { - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + case 4: + render.triangles += instanceCount * ( count / 3 ); + break; - this.setValues( parameters ); + case 1: + render.lines += instanceCount * ( count / 2 ); + break; - } + case 3: + render.lines += instanceCount * ( count - 1 ); + break; - copy( source ) { + case 2: + render.lines += instanceCount * count; + break; - super.copy( source ); + case 0: + render.points += instanceCount * count; + break; - this.referencePosition.copy( source.referencePosition ); - this.nearDistance = source.nearDistance; - this.farDistance = source.farDistance; + default: + console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); + break; - this.map = source.map; + } - this.alphaMap = source.alphaMap; + } - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + function reset() { - return this; + render.frame ++; + render.calls = 0; + render.triangles = 0; + render.points = 0; + render.lines = 0; } + return { + memory: memory, + render: render, + programs: null, + autoReset: true, + reset: reset, + update: update + }; + } - const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; + function numericalSort( a, b ) { - const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; + return a[ 0 ] - b[ 0 ]; - function WebGLShadowMap( _renderer, _objects, _capabilities ) { + } - let _frustum = new Frustum(); + function absNumericalSort( a, b ) { - const _shadowMapSize = new Vector2(), - _viewportSize = new Vector2(), + return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); - _viewport = new Vector4(), + } - _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ), - _distanceMaterial = new MeshDistanceMaterial(), + function WebGLMorphtargets( gl, capabilities, textures ) { - _materialCache = {}, + const influencesList = {}; + const morphInfluences = new Float32Array( 8 ); + const morphTextures = new WeakMap(); + const morph = new Vector4(); - _maxTextureSize = _capabilities.maxTextureSize; + const workInfluences = []; - const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; + for ( let i = 0; i < 8; i ++ ) { - const shadowMaterialVertical = new ShaderMaterial( { - defines: { - VSM_SAMPLES: 8 - }, - uniforms: { - shadow_pass: { value: null }, - resolution: { value: new Vector2() }, - radius: { value: 4.0 } - }, + workInfluences[ i ] = [ i, 0 ]; - vertexShader: vertex, - fragmentShader: fragment + } - } ); + function update( object, geometry, material, program ) { - const shadowMaterialHorizontal = shadowMaterialVertical.clone(); - shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; + const objectInfluences = object.morphTargetInfluences; - const fullScreenTri = new BufferGeometry(); - fullScreenTri.setAttribute( - 'position', - new BufferAttribute( - new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ), - 3 - ) - ); + if ( capabilities.isWebGL2 === true ) { - const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); + // instead of using attributes, the WebGL 2 code path encodes morph targets + // into an array of data textures. Each layer represents a single morph target. - const scope = this; + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - this.enabled = false; + let entry = morphTextures.get( geometry ); - this.autoUpdate = true; - this.needsUpdate = false; + if ( entry === undefined || entry.count !== morphTargetsCount ) { - this.type = PCFShadowMap; + if ( entry !== undefined ) entry.texture.dispose(); - this.render = function ( lights, scene, camera ) { + const hasMorphPosition = geometry.morphAttributes.position !== undefined; + const hasMorphNormals = geometry.morphAttributes.normal !== undefined; + const hasMorphColors = geometry.morphAttributes.color !== undefined; - if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; + const morphTargets = geometry.morphAttributes.position || []; + const morphNormals = geometry.morphAttributes.normal || []; + const morphColors = geometry.morphAttributes.color || []; - if ( lights.length === 0 ) return; + let vertexDataCount = 0; - const currentRenderTarget = _renderer.getRenderTarget(); - const activeCubeFace = _renderer.getActiveCubeFace(); - const activeMipmapLevel = _renderer.getActiveMipmapLevel(); + if ( hasMorphPosition === true ) vertexDataCount = 1; + if ( hasMorphNormals === true ) vertexDataCount = 2; + if ( hasMorphColors === true ) vertexDataCount = 3; - const _state = _renderer.state; + let width = geometry.attributes.position.count * vertexDataCount; + let height = 1; - // Set GL state for depth map. - _state.setBlending( NoBlending ); - _state.buffers.color.setClear( 1, 1, 1, 1 ); - _state.buffers.depth.setTest( true ); - _state.setScissorTest( false ); + if ( width > capabilities.maxTextureSize ) { - // render depth map + height = Math.ceil( width / capabilities.maxTextureSize ); + width = capabilities.maxTextureSize; - for ( let i = 0, il = lights.length; i < il; i ++ ) { + } - const light = lights[ i ]; - const shadow = light.shadow; + const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); - if ( shadow === undefined ) { + const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); + texture.type = FloatType; + texture.needsUpdate = true; - console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); - continue; + // fill buffer - } + const vertexDataStride = vertexDataCount * 4; - if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue; + for ( let i = 0; i < morphTargetsCount; i ++ ) { - _shadowMapSize.copy( shadow.mapSize ); + const morphTarget = morphTargets[ i ]; + const morphNormal = morphNormals[ i ]; + const morphColor = morphColors[ i ]; - const shadowFrameExtents = shadow.getFrameExtents(); + const offset = width * height * 4 * i; - _shadowMapSize.multiply( shadowFrameExtents ); + for ( let j = 0; j < morphTarget.count; j ++ ) { - _viewportSize.copy( shadow.mapSize ); + const stride = j * vertexDataStride; - if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) { + if ( hasMorphPosition === true ) { - if ( _shadowMapSize.x > _maxTextureSize ) { + morph.fromBufferAttribute( morphTarget, j ); - _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x ); - _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; - shadow.mapSize.x = _viewportSize.x; + buffer[ offset + stride + 0 ] = morph.x; + buffer[ offset + stride + 1 ] = morph.y; + buffer[ offset + stride + 2 ] = morph.z; + buffer[ offset + stride + 3 ] = 0; - } + } - if ( _shadowMapSize.y > _maxTextureSize ) { + if ( hasMorphNormals === true ) { - _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y ); - _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; - shadow.mapSize.y = _viewportSize.y; + morph.fromBufferAttribute( morphNormal, j ); - } + buffer[ offset + stride + 4 ] = morph.x; + buffer[ offset + stride + 5 ] = morph.y; + buffer[ offset + stride + 6 ] = morph.z; + buffer[ offset + stride + 7 ] = 0; - } + } - if ( shadow.map === null ) { + if ( hasMorphColors === true ) { - const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; + morph.fromBufferAttribute( morphColor, j ); - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + '.shadowMap'; + buffer[ offset + stride + 8 ] = morph.x; + buffer[ offset + stride + 9 ] = morph.y; + buffer[ offset + stride + 10 ] = morph.z; + buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1; - shadow.camera.updateProjectionMatrix(); + } - } + } - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); + } - const viewportCount = shadow.getViewportCount(); + entry = { + count: morphTargetsCount, + texture: texture, + size: new Vector2( width, height ) + }; - for ( let vp = 0; vp < viewportCount; vp ++ ) { + morphTextures.set( geometry, entry ); - const viewport = shadow.getViewport( vp ); + function disposeTexture() { - _viewport.set( - _viewportSize.x * viewport.x, - _viewportSize.y * viewport.y, - _viewportSize.x * viewport.z, - _viewportSize.y * viewport.w - ); + texture.dispose(); - _state.viewport( _viewport ); + morphTextures.delete( geometry ); - shadow.updateMatrices( light, vp ); + geometry.removeEventListener( 'dispose', disposeTexture ); - _frustum = shadow.getFrustum(); + } - renderObject( scene, camera, shadow.camera, light, this.type ); + geometry.addEventListener( 'dispose', disposeTexture ); } - // do blur pass for VSM + // - if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) { + let morphInfluencesSum = 0; - VSMPass( shadow, camera ); + for ( let i = 0; i < objectInfluences.length; i ++ ) { + + morphInfluencesSum += objectInfluences[ i ]; } - shadow.needsUpdate = false; + const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - } + program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); + program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences ); - scope.needsUpdate = false; + program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures ); + program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size ); - _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); - }; + } else { - function VSMPass( shadow, camera ) { + // When object doesn't have morph target influences defined, we treat it as a 0-length array + // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences - const geometry = _objects.update( fullScreenMesh ); + const length = objectInfluences === undefined ? 0 : objectInfluences.length; - if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) { + let influences = influencesList[ geometry.id ]; - shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; - shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; + if ( influences === undefined || influences.length !== length ) { - shadowMaterialVertical.needsUpdate = true; - shadowMaterialHorizontal.needsUpdate = true; + // initialise list - } + influences = []; - if ( shadow.mapPass === null ) { + for ( let i = 0; i < length; i ++ ) { - shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y ); + influences[ i ] = [ i, 0 ]; - } + } - // vertical pass + influencesList[ geometry.id ] = influences; - shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; - shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; - shadowMaterialVertical.uniforms.radius.value = shadow.radius; - _renderer.setRenderTarget( shadow.mapPass ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); + } - // horizontal pass + // Collect influences - shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; - shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; - shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null ); + for ( let i = 0; i < length; i ++ ) { - } + const influence = influences[ i ]; - function getDepthMaterial( object, material, light, shadowCameraNear, shadowCameraFar, type ) { + influence[ 0 ] = i; + influence[ 1 ] = objectInfluences[ i ]; - let result = null; + } - const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial; + influences.sort( absNumericalSort ); - if ( customMaterial !== undefined ) { + for ( let i = 0; i < 8; i ++ ) { - result = customMaterial; + if ( i < length && influences[ i ][ 1 ] ) { - } else { + workInfluences[ i ][ 0 ] = influences[ i ][ 0 ]; + workInfluences[ i ][ 1 ] = influences[ i ][ 1 ]; - result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; + } else { - } + workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER; + workInfluences[ i ][ 1 ] = 0; - if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || - ( material.displacementMap && material.displacementScale !== 0 ) || - ( material.alphaMap && material.alphaTest > 0 ) ) { + } - // in this case we need a unique material instance reflecting the - // appropriate state + } - const keyA = result.uuid, keyB = material.uuid; + workInfluences.sort( numericalSort ); - let materialsForVariant = _materialCache[ keyA ]; + const morphTargets = geometry.morphAttributes.position; + const morphNormals = geometry.morphAttributes.normal; - if ( materialsForVariant === undefined ) { + let morphInfluencesSum = 0; - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; + for ( let i = 0; i < 8; i ++ ) { - } + const influence = workInfluences[ i ]; + const index = influence[ 0 ]; + const value = influence[ 1 ]; - let cachedMaterial = materialsForVariant[ keyB ]; + if ( index !== Number.MAX_SAFE_INTEGER && value ) { - if ( cachedMaterial === undefined ) { + if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) { - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; + geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] ); - } + } - result = cachedMaterial; + if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) { - } + geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] ); - result.visible = material.visible; - result.wireframe = material.wireframe; + } - if ( type === VSMShadowMap ) { + morphInfluences[ i ] = value; + morphInfluencesSum += value; - result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; + } else { - } else { + if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) { - result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; + geometry.deleteAttribute( 'morphTarget' + i ); - } + } - result.alphaMap = material.alphaMap; - result.alphaTest = material.alphaTest; + if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) { - result.clipShadows = material.clipShadows; - result.clippingPlanes = material.clippingPlanes; - result.clipIntersection = material.clipIntersection; + geometry.deleteAttribute( 'morphNormal' + i ); - result.displacementMap = material.displacementMap; - result.displacementScale = material.displacementScale; - result.displacementBias = material.displacementBias; + } - result.wireframeLinewidth = material.wireframeLinewidth; - result.linewidth = material.linewidth; + morphInfluences[ i ] = 0; - if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { + } - result.referencePosition.setFromMatrixPosition( light.matrixWorld ); - result.nearDistance = shadowCameraNear; - result.farDistance = shadowCameraFar; + } - } + // GLSL shader uses formula baseinfluence * base + sum(target * influence) + // This allows us to switch between absolute morphs and relative morphs without changing shader code + // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence) + const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - return result; + program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); + program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); + + } } - function renderObject( object, camera, shadowCamera, light, type ) { + return { - if ( object.visible === false ) return; + update: update - const visible = object.layers.test( camera.layers ); + }; - if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { + } - if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { + function WebGLObjects( gl, geometries, attributes, info ) { - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + let updateMap = new WeakMap(); - const geometry = _objects.update( object ); - const material = object.material; + function update( object ) { - if ( Array.isArray( material ) ) { + const frame = info.render.frame; - const groups = geometry.groups; + const geometry = object.geometry; + const buffergeometry = geometries.get( object, geometry ); - for ( let k = 0, kl = groups.length; k < kl; k ++ ) { + // Update once per frame - const group = groups[ k ]; - const groupMaterial = material[ group.materialIndex ]; + if ( updateMap.get( buffergeometry ) !== frame ) { - if ( groupMaterial && groupMaterial.visible ) { + geometries.update( buffergeometry ); - const depthMaterial = getDepthMaterial( object, groupMaterial, light, shadowCamera.near, shadowCamera.far, type ); + updateMap.set( buffergeometry, frame ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + } - } + if ( object.isInstancedMesh ) { - } + if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) { - } else if ( material.visible ) { + object.addEventListener( 'dispose', onInstancedMeshDispose ); - const depthMaterial = getDepthMaterial( object, material, light, shadowCamera.near, shadowCamera.far, type ); + } - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + attributes.update( object.instanceMatrix, 34962 ); - } + if ( object.instanceColor !== null ) { + + attributes.update( object.instanceColor, 34962 ); } } - const children = object.children; + return buffergeometry; - for ( let i = 0, l = children.length; i < l; i ++ ) { + } - renderObject( children[ i ], camera, shadowCamera, light, type ); + function dispose() { - } + updateMap = new WeakMap(); } - } + function onInstancedMeshDispose( event ) { - function WebGLState( gl, extensions, capabilities ) { + const instancedMesh = event.target; - const isWebGL2 = capabilities.isWebGL2; + instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose ); - function ColorBuffer() { + attributes.remove( instancedMesh.instanceMatrix ); - let locked = false; + if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor ); - const color = new Vector4(); - let currentColorMask = null; - const currentColorClear = new Vector4( 0, 0, 0, 0 ); + } - return { + return { - setMask: function ( colorMask ) { + update: update, + dispose: dispose - if ( currentColorMask !== colorMask && ! locked ) { + }; - gl.colorMask( colorMask, colorMask, colorMask, colorMask ); - currentColorMask = colorMask; + } - } + /** + * Uniforms of a program. + * Those form a tree structure with a special top-level container for the root, + * which you get by calling 'new WebGLUniforms( gl, program )'. + * + * + * Properties of inner nodes including the top-level container: + * + * .seq - array of nested uniforms + * .map - nested uniforms by name + * + * + * Methods of all nodes except the top-level container: + * + * .setValue( gl, value, [textures] ) + * + * uploads a uniform value(s) + * the 'textures' parameter is needed for sampler uniforms + * + * + * Static methods of the top-level container (textures factorizations): + * + * .upload( gl, seq, values, textures ) + * + * sets uniforms in 'seq' to 'values[id].value' + * + * .seqWithValue( seq, values ) : filteredSeq + * + * filters 'seq' entries with corresponding entry in values + * + * + * Methods of the top-level container (textures factorizations): + * + * .setValue( gl, name, value, textures ) + * + * sets uniform with name 'name' to 'value' + * + * .setOptional( gl, obj, prop ) + * + * like .set for an optional property of the object + * + */ - }, + const emptyTexture = /*@__PURE__*/ new Texture(); + const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); + const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); + const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); - setLocked: function ( lock ) { + // --- Utilities --- - locked = lock; + // Array Caches (provide typed arrays for temporary by size) - }, + const arrayCacheF32 = []; + const arrayCacheI32 = []; - setClear: function ( r, g, b, a, premultipliedAlpha ) { + // Float32Array caches used for uploading Matrix uniforms - if ( premultipliedAlpha === true ) { + const mat4array = new Float32Array( 16 ); + const mat3array = new Float32Array( 9 ); + const mat2array = new Float32Array( 4 ); - r *= a; g *= a; b *= a; + // Flattening for arrays of vectors and matrices - } + function flatten( array, nBlocks, blockSize ) { - color.set( r, g, b, a ); + const firstElem = array[ 0 ]; - if ( currentColorClear.equals( color ) === false ) { + if ( firstElem <= 0 || firstElem > 0 ) return array; + // unoptimized: ! isNaN( firstElem ) + // see http://jacksondunstan.com/articles/983 - gl.clearColor( r, g, b, a ); - currentColorClear.copy( color ); + const n = nBlocks * blockSize; + let r = arrayCacheF32[ n ]; - } + if ( r === undefined ) { - }, + r = new Float32Array( n ); + arrayCacheF32[ n ] = r; - reset: function () { + } - locked = false; + if ( nBlocks !== 0 ) { - currentColorMask = null; - currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state + firstElem.toArray( r, 0 ); - } + for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) { - }; + offset += blockSize; + array[ i ].toArray( r, offset ); + + } } - function DepthBuffer() { + return r; - let locked = false; + } - let currentDepthMask = null; - let currentDepthFunc = null; - let currentDepthClear = null; + function arraysEqual( a, b ) { - return { + if ( a.length !== b.length ) return false; - setTest: function ( depthTest ) { + for ( let i = 0, l = a.length; i < l; i ++ ) { - if ( depthTest ) { + if ( a[ i ] !== b[ i ] ) return false; - enable( 2929 ); + } - } else { + return true; - disable( 2929 ); + } - } + function copyArray( a, b ) { - }, + for ( let i = 0, l = b.length; i < l; i ++ ) { - setMask: function ( depthMask ) { - - if ( currentDepthMask !== depthMask && ! locked ) { - - gl.depthMask( depthMask ); - currentDepthMask = depthMask; - - } - - }, - - setFunc: function ( depthFunc ) { - - if ( currentDepthFunc !== depthFunc ) { - - switch ( depthFunc ) { - - case NeverDepth: + a[ i ] = b[ i ]; - gl.depthFunc( 512 ); - break; + } - case AlwaysDepth: + } - gl.depthFunc( 519 ); - break; + // Texture unit allocation - case LessDepth: + function allocTexUnits( textures, n ) { - gl.depthFunc( 513 ); - break; + let r = arrayCacheI32[ n ]; - case LessEqualDepth: + if ( r === undefined ) { - gl.depthFunc( 515 ); - break; + r = new Int32Array( n ); + arrayCacheI32[ n ] = r; - case EqualDepth: + } - gl.depthFunc( 514 ); - break; + for ( let i = 0; i !== n; ++ i ) { - case GreaterEqualDepth: + r[ i ] = textures.allocateTextureUnit(); - gl.depthFunc( 518 ); - break; + } - case GreaterDepth: + return r; - gl.depthFunc( 516 ); - break; + } - case NotEqualDepth: + // --- Setters --- - gl.depthFunc( 517 ); - break; + // Note: Defining these methods externally, because they come in a bunch + // and this way their names minify. - default: + // Single scalar - gl.depthFunc( 515 ); + function setValueV1f( gl, v ) { - } + const cache = this.cache; - currentDepthFunc = depthFunc; + if ( cache[ 0 ] === v ) return; - } + gl.uniform1f( this.addr, v ); - }, + cache[ 0 ] = v; - setLocked: function ( lock ) { + } - locked = lock; + // Single float vector (from flat array or THREE.VectorN) - }, + function setValueV2f( gl, v ) { - setClear: function ( depth ) { + const cache = this.cache; - if ( currentDepthClear !== depth ) { + if ( v.x !== undefined ) { - gl.clearDepth( depth ); - currentDepthClear = depth; + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - } + gl.uniform2f( this.addr, v.x, v.y ); - }, + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; - reset: function () { + } - locked = false; + } else { - currentDepthMask = null; - currentDepthFunc = null; - currentDepthClear = null; + if ( arraysEqual( cache, v ) ) return; - } + gl.uniform2fv( this.addr, v ); - }; + copyArray( cache, v ); } - function StencilBuffer() { + } - let locked = false; + function setValueV3f( gl, v ) { - let currentStencilMask = null; - let currentStencilFunc = null; - let currentStencilRef = null; - let currentStencilFuncMask = null; - let currentStencilFail = null; - let currentStencilZFail = null; - let currentStencilZPass = null; - let currentStencilClear = null; + const cache = this.cache; - return { + if ( v.x !== undefined ) { - setTest: function ( stencilTest ) { + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - if ( ! locked ) { + gl.uniform3f( this.addr, v.x, v.y, v.z ); - if ( stencilTest ) { + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; + cache[ 2 ] = v.z; - enable( 2960 ); + } - } else { + } else if ( v.r !== undefined ) { - disable( 2960 ); + if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { - } + gl.uniform3f( this.addr, v.r, v.g, v.b ); - } + cache[ 0 ] = v.r; + cache[ 1 ] = v.g; + cache[ 2 ] = v.b; - }, + } - setMask: function ( stencilMask ) { + } else { - if ( currentStencilMask !== stencilMask && ! locked ) { + if ( arraysEqual( cache, v ) ) return; - gl.stencilMask( stencilMask ); - currentStencilMask = stencilMask; + gl.uniform3fv( this.addr, v ); - } + copyArray( cache, v ); - }, + } - setFunc: function ( stencilFunc, stencilRef, stencilMask ) { + } - if ( currentStencilFunc !== stencilFunc || - currentStencilRef !== stencilRef || - currentStencilFuncMask !== stencilMask ) { + function setValueV4f( gl, v ) { - gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); + const cache = this.cache; - currentStencilFunc = stencilFunc; - currentStencilRef = stencilRef; - currentStencilFuncMask = stencilMask; + if ( v.x !== undefined ) { - } + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - }, + gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); - setOp: function ( stencilFail, stencilZFail, stencilZPass ) { + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; + cache[ 2 ] = v.z; + cache[ 3 ] = v.w; - if ( currentStencilFail !== stencilFail || - currentStencilZFail !== stencilZFail || - currentStencilZPass !== stencilZPass ) { + } - gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); + } else { - currentStencilFail = stencilFail; - currentStencilZFail = stencilZFail; - currentStencilZPass = stencilZPass; + if ( arraysEqual( cache, v ) ) return; - } + gl.uniform4fv( this.addr, v ); - }, + copyArray( cache, v ); - setLocked: function ( lock ) { + } - locked = lock; + } - }, + // Single matrix (from flat array or THREE.MatrixN) - setClear: function ( stencil ) { + function setValueM2( gl, v ) { - if ( currentStencilClear !== stencil ) { + const cache = this.cache; + const elements = v.elements; - gl.clearStencil( stencil ); - currentStencilClear = stencil; + if ( elements === undefined ) { - } + if ( arraysEqual( cache, v ) ) return; - }, + gl.uniformMatrix2fv( this.addr, false, v ); - reset: function () { + copyArray( cache, v ); - locked = false; + } else { - currentStencilMask = null; - currentStencilFunc = null; - currentStencilRef = null; - currentStencilFuncMask = null; - currentStencilFail = null; - currentStencilZFail = null; - currentStencilZPass = null; - currentStencilClear = null; + if ( arraysEqual( cache, elements ) ) return; - } + mat2array.set( elements ); - }; + gl.uniformMatrix2fv( this.addr, false, mat2array ); + + copyArray( cache, elements ); } - // + } - const colorBuffer = new ColorBuffer(); - const depthBuffer = new DepthBuffer(); - const stencilBuffer = new StencilBuffer(); + function setValueM3( gl, v ) { - const uboBindings = new WeakMap(); - const uboProgamMap = new WeakMap(); + const cache = this.cache; + const elements = v.elements; - let enabledCapabilities = {}; + if ( elements === undefined ) { - let currentBoundFramebuffers = {}; - let currentDrawbuffers = new WeakMap(); - let defaultDrawbuffers = []; + if ( arraysEqual( cache, v ) ) return; - let currentProgram = null; + gl.uniformMatrix3fv( this.addr, false, v ); - let currentBlendingEnabled = false; - let currentBlending = null; - let currentBlendEquation = null; - let currentBlendSrc = null; - let currentBlendDst = null; - let currentBlendEquationAlpha = null; - let currentBlendSrcAlpha = null; - let currentBlendDstAlpha = null; - let currentPremultipledAlpha = false; + copyArray( cache, v ); - let currentFlipSided = null; - let currentCullFace = null; + } else { - let currentLineWidth = null; + if ( arraysEqual( cache, elements ) ) return; - let currentPolygonOffsetFactor = null; - let currentPolygonOffsetUnits = null; + mat3array.set( elements ); - const maxTextures = gl.getParameter( 35661 ); + gl.uniformMatrix3fv( this.addr, false, mat3array ); - let lineWidthAvailable = false; - let version = 0; - const glVersion = gl.getParameter( 7938 ); + copyArray( cache, elements ); - if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { + } - version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 1.0 ); + } - } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { + function setValueM4( gl, v ) { - version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 2.0 ); + const cache = this.cache; + const elements = v.elements; - } + if ( elements === undefined ) { - let currentTextureSlot = null; - let currentBoundTextures = {}; + if ( arraysEqual( cache, v ) ) return; - const scissorParam = gl.getParameter( 3088 ); - const viewportParam = gl.getParameter( 2978 ); + gl.uniformMatrix4fv( this.addr, false, v ); - const currentScissor = new Vector4().fromArray( scissorParam ); - const currentViewport = new Vector4().fromArray( viewportParam ); + copyArray( cache, v ); - function createTexture( type, target, count ) { + } else { - const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. - const texture = gl.createTexture(); + if ( arraysEqual( cache, elements ) ) return; - gl.bindTexture( type, texture ); - gl.texParameteri( type, 10241, 9728 ); - gl.texParameteri( type, 10240, 9728 ); + mat4array.set( elements ); - for ( let i = 0; i < count; i ++ ) { + gl.uniformMatrix4fv( this.addr, false, mat4array ); - gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); + copyArray( cache, elements ); - } + } - return texture; + } - } + // Single integer / boolean - const emptyTextures = {}; - emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); - emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); + function setValueV1i( gl, v ) { - // init + const cache = this.cache; - colorBuffer.setClear( 0, 0, 0, 1 ); - depthBuffer.setClear( 1 ); - stencilBuffer.setClear( 0 ); + if ( cache[ 0 ] === v ) return; - enable( 2929 ); - depthBuffer.setFunc( LessEqualDepth ); + gl.uniform1i( this.addr, v ); - setFlipSided( false ); - setCullFace( CullFaceBack ); - enable( 2884 ); + cache[ 0 ] = v; - setBlending( NoBlending ); + } - // + // Single integer / boolean vector (from flat array) - function enable( id ) { + function setValueV2i( gl, v ) { - if ( enabledCapabilities[ id ] !== true ) { + const cache = this.cache; - gl.enable( id ); - enabledCapabilities[ id ] = true; + if ( arraysEqual( cache, v ) ) return; - } + gl.uniform2iv( this.addr, v ); - } + copyArray( cache, v ); - function disable( id ) { + } - if ( enabledCapabilities[ id ] !== false ) { + function setValueV3i( gl, v ) { - gl.disable( id ); - enabledCapabilities[ id ] = false; + const cache = this.cache; - } + if ( arraysEqual( cache, v ) ) return; - } + gl.uniform3iv( this.addr, v ); - function bindFramebuffer( target, framebuffer ) { + copyArray( cache, v ); - if ( currentBoundFramebuffers[ target ] !== framebuffer ) { + } - gl.bindFramebuffer( target, framebuffer ); + function setValueV4i( gl, v ) { - currentBoundFramebuffers[ target ] = framebuffer; + const cache = this.cache; - if ( isWebGL2 ) { + if ( arraysEqual( cache, v ) ) return; - // 36009 is equivalent to 36160 + gl.uniform4iv( this.addr, v ); - if ( target === 36009 ) { + copyArray( cache, v ); - currentBoundFramebuffers[ 36160 ] = framebuffer; + } - } + // Single unsigned integer - if ( target === 36160 ) { + function setValueV1ui( gl, v ) { - currentBoundFramebuffers[ 36009 ] = framebuffer; + const cache = this.cache; - } + if ( cache[ 0 ] === v ) return; - } + gl.uniform1ui( this.addr, v ); - return true; + cache[ 0 ] = v; - } + } - return false; + // Single unsigned integer vector (from flat array) - } + function setValueV2ui( gl, v ) { - function drawBuffers( renderTarget, framebuffer ) { + const cache = this.cache; - let drawBuffers = defaultDrawbuffers; + if ( arraysEqual( cache, v ) ) return; - let needsUpdate = false; + gl.uniform2uiv( this.addr, v ); - if ( renderTarget ) { + copyArray( cache, v ); - drawBuffers = currentDrawbuffers.get( framebuffer ); + } - if ( drawBuffers === undefined ) { + function setValueV3ui( gl, v ) { - drawBuffers = []; - currentDrawbuffers.set( framebuffer, drawBuffers ); + const cache = this.cache; - } + if ( arraysEqual( cache, v ) ) return; - if ( renderTarget.isWebGLMultipleRenderTargets ) { + gl.uniform3uiv( this.addr, v ); - const textures = renderTarget.texture; + copyArray( cache, v ); - if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== 36064 ) { + } - for ( let i = 0, il = textures.length; i < il; i ++ ) { + function setValueV4ui( gl, v ) { - drawBuffers[ i ] = 36064 + i; + const cache = this.cache; - } + if ( arraysEqual( cache, v ) ) return; - drawBuffers.length = textures.length; + gl.uniform4uiv( this.addr, v ); - needsUpdate = true; + copyArray( cache, v ); - } + } - } else { - if ( drawBuffers[ 0 ] !== 36064 ) { + // Single texture (2D / Cube) - drawBuffers[ 0 ] = 36064; + function setValueT1( gl, v, textures ) { - needsUpdate = true; + const cache = this.cache; + const unit = textures.allocateTextureUnit(); - } + if ( cache[ 0 ] !== unit ) { - } + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - } else { + } - if ( drawBuffers[ 0 ] !== 1029 ) { + textures.setTexture2D( v || emptyTexture, unit ); - drawBuffers[ 0 ] = 1029; + } - needsUpdate = true; + function setValueT3D1( gl, v, textures ) { - } + const cache = this.cache; + const unit = textures.allocateTextureUnit(); - } + if ( cache[ 0 ] !== unit ) { - if ( needsUpdate ) { + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - if ( capabilities.isWebGL2 ) { + } - gl.drawBuffers( drawBuffers ); + textures.setTexture3D( v || empty3dTexture, unit ); - } else { + } - extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers ); + function setValueT6( gl, v, textures ) { - } + const cache = this.cache; + const unit = textures.allocateTextureUnit(); - } + if ( cache[ 0 ] !== unit ) { + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; } - function useProgram( program ) { - - if ( currentProgram !== program ) { + textures.setTextureCube( v || emptyCubeTexture, unit ); - gl.useProgram( program ); + } - currentProgram = program; + function setValueT2DArray1( gl, v, textures ) { - return true; + const cache = this.cache; + const unit = textures.allocateTextureUnit(); - } + if ( cache[ 0 ] !== unit ) { - return false; + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; } - const equationToGL = { - [ AddEquation ]: 32774, - [ SubtractEquation ]: 32778, - [ ReverseSubtractEquation ]: 32779 - }; + textures.setTexture2DArray( v || emptyArrayTexture, unit ); - if ( isWebGL2 ) { + } - equationToGL[ MinEquation ] = 32775; - equationToGL[ MaxEquation ] = 32776; + // Helper to pick the right setter for the singular case - } else { + function getSingularSetter( type ) { - const extension = extensions.get( 'EXT_blend_minmax' ); + switch ( type ) { - if ( extension !== null ) { + case 0x1406: return setValueV1f; // FLOAT + case 0x8b50: return setValueV2f; // _VEC2 + case 0x8b51: return setValueV3f; // _VEC3 + case 0x8b52: return setValueV4f; // _VEC4 - equationToGL[ MinEquation ] = extension.MIN_EXT; - equationToGL[ MaxEquation ] = extension.MAX_EXT; + case 0x8b5a: return setValueM2; // _MAT2 + case 0x8b5b: return setValueM3; // _MAT3 + case 0x8b5c: return setValueM4; // _MAT4 - } + case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL + case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 + case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 + case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 - } + case 0x1405: return setValueV1ui; // UINT + case 0x8dc6: return setValueV2ui; // _VEC2 + case 0x8dc7: return setValueV3ui; // _VEC3 + case 0x8dc8: return setValueV4ui; // _VEC4 - const factorToGL = { - [ ZeroFactor ]: 0, - [ OneFactor ]: 1, - [ SrcColorFactor ]: 768, - [ SrcAlphaFactor ]: 770, - [ SrcAlphaSaturateFactor ]: 776, - [ DstColorFactor ]: 774, - [ DstAlphaFactor ]: 772, - [ OneMinusSrcColorFactor ]: 769, - [ OneMinusSrcAlphaFactor ]: 771, - [ OneMinusDstColorFactor ]: 775, - [ OneMinusDstAlphaFactor ]: 773 - }; - - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + case 0x8b5e: // SAMPLER_2D + case 0x8d66: // SAMPLER_EXTERNAL_OES + case 0x8dca: // INT_SAMPLER_2D + case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D + case 0x8b62: // SAMPLER_2D_SHADOW + return setValueT1; - if ( blending === NoBlending ) { + case 0x8b5f: // SAMPLER_3D + case 0x8dcb: // INT_SAMPLER_3D + case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D + return setValueT3D1; - if ( currentBlendingEnabled === true ) { + case 0x8b60: // SAMPLER_CUBE + case 0x8dcc: // INT_SAMPLER_CUBE + case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE + case 0x8dc5: // SAMPLER_CUBE_SHADOW + return setValueT6; - disable( 3042 ); - currentBlendingEnabled = false; + case 0x8dc1: // SAMPLER_2D_ARRAY + case 0x8dcf: // INT_SAMPLER_2D_ARRAY + case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY + case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW + return setValueT2DArray1; - } + } - return; + } - } - if ( currentBlendingEnabled === false ) { + // Array of scalars - enable( 3042 ); - currentBlendingEnabled = true; + function setValueV1fArray( gl, v ) { - } + gl.uniform1fv( this.addr, v ); - if ( blending !== CustomBlending ) { + } - if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { + // Array of vectors (from flat array or array of THREE.VectorN) - if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { + function setValueV2fArray( gl, v ) { - gl.blendEquation( 32774 ); + const data = flatten( v, this.size, 2 ); - currentBlendEquation = AddEquation; - currentBlendEquationAlpha = AddEquation; + gl.uniform2fv( this.addr, data ); - } + } - if ( premultipliedAlpha ) { + function setValueV3fArray( gl, v ) { - switch ( blending ) { + const data = flatten( v, this.size, 3 ); - case NormalBlending: - gl.blendFuncSeparate( 1, 771, 1, 771 ); - break; + gl.uniform3fv( this.addr, data ); - case AdditiveBlending: - gl.blendFunc( 1, 1 ); - break; + } - case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); - break; + function setValueV4fArray( gl, v ) { - case MultiplyBlending: - gl.blendFuncSeparate( 0, 768, 0, 770 ); - break; + const data = flatten( v, this.size, 4 ); - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; + gl.uniform4fv( this.addr, data ); - } + } - } else { + // Array of matrices (from flat array or array of THREE.MatrixN) - switch ( blending ) { + function setValueM2Array( gl, v ) { - case NormalBlending: - gl.blendFuncSeparate( 770, 771, 1, 771 ); - break; + const data = flatten( v, this.size, 4 ); - case AdditiveBlending: - gl.blendFunc( 770, 1 ); - break; + gl.uniformMatrix2fv( this.addr, false, data ); - case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); - break; + } - case MultiplyBlending: - gl.blendFunc( 0, 768 ); - break; + function setValueM3Array( gl, v ) { - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; + const data = flatten( v, this.size, 9 ); - } + gl.uniformMatrix3fv( this.addr, false, data ); - } + } - currentBlendSrc = null; - currentBlendDst = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; + function setValueM4Array( gl, v ) { - currentBlending = blending; - currentPremultipledAlpha = premultipliedAlpha; + const data = flatten( v, this.size, 16 ); - } + gl.uniformMatrix4fv( this.addr, false, data ); - return; + } - } + // Array of integer / boolean - // custom blending + function setValueV1iArray( gl, v ) { - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; + gl.uniform1iv( this.addr, v ); - if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { + } - gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); + // Array of integer / boolean vectors (from flat array) - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; + function setValueV2iArray( gl, v ) { - } + gl.uniform2iv( this.addr, v ); - if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { + } - gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); + function setValueV3iArray( gl, v ) { - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; + gl.uniform3iv( this.addr, v ); - } + } - currentBlending = blending; - currentPremultipledAlpha = null; + function setValueV4iArray( gl, v ) { - } + gl.uniform4iv( this.addr, v ); - function setMaterial( material, frontFaceCW ) { + } - material.side === DoubleSide - ? disable( 2884 ) - : enable( 2884 ); + // Array of unsigned integer - let flipSided = ( material.side === BackSide ); - if ( frontFaceCW ) flipSided = ! flipSided; + function setValueV1uiArray( gl, v ) { - setFlipSided( flipSided ); + gl.uniform1uiv( this.addr, v ); - ( material.blending === NormalBlending && material.transparent === false ) - ? setBlending( NoBlending ) - : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); + } - depthBuffer.setFunc( material.depthFunc ); - depthBuffer.setTest( material.depthTest ); - depthBuffer.setMask( material.depthWrite ); - colorBuffer.setMask( material.colorWrite ); + // Array of unsigned integer vectors (from flat array) - const stencilWrite = material.stencilWrite; - stencilBuffer.setTest( stencilWrite ); - if ( stencilWrite ) { + function setValueV2uiArray( gl, v ) { - stencilBuffer.setMask( material.stencilWriteMask ); - stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); - stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); + gl.uniform2uiv( this.addr, v ); - } + } - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + function setValueV3uiArray( gl, v ) { - material.alphaToCoverage === true - ? enable( 32926 ) - : disable( 32926 ); + gl.uniform3uiv( this.addr, v ); - } + } - // + function setValueV4uiArray( gl, v ) { - function setFlipSided( flipSided ) { + gl.uniform4uiv( this.addr, v ); - if ( currentFlipSided !== flipSided ) { + } - if ( flipSided ) { - gl.frontFace( 2304 ); + // Array of textures (2D / 3D / Cube / 2DArray) - } else { + function setValueT1Array( gl, v, textures ) { - gl.frontFace( 2305 ); + const cache = this.cache; - } + const n = v.length; - currentFlipSided = flipSided; + const units = allocTexUnits( textures, n ); - } + if ( ! arraysEqual( cache, units ) ) { - } + gl.uniform1iv( this.addr, units ); - function setCullFace( cullFace ) { + copyArray( cache, units ); - if ( cullFace !== CullFaceNone ) { + } - enable( 2884 ); + for ( let i = 0; i !== n; ++ i ) { - if ( cullFace !== currentCullFace ) { + textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); - if ( cullFace === CullFaceBack ) { + } - gl.cullFace( 1029 ); + } - } else if ( cullFace === CullFaceFront ) { + function setValueT3DArray( gl, v, textures ) { - gl.cullFace( 1028 ); + const cache = this.cache; - } else { + const n = v.length; - gl.cullFace( 1032 ); + const units = allocTexUnits( textures, n ); - } + if ( ! arraysEqual( cache, units ) ) { - } + gl.uniform1iv( this.addr, units ); - } else { + copyArray( cache, units ); - disable( 2884 ); + } - } + for ( let i = 0; i !== n; ++ i ) { - currentCullFace = cullFace; + textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] ); } - function setLineWidth( width ) { + } - if ( width !== currentLineWidth ) { + function setValueT6Array( gl, v, textures ) { - if ( lineWidthAvailable ) gl.lineWidth( width ); + const cache = this.cache; - currentLineWidth = width; + const n = v.length; - } + const units = allocTexUnits( textures, n ); - } + if ( ! arraysEqual( cache, units ) ) { - function setPolygonOffset( polygonOffset, factor, units ) { + gl.uniform1iv( this.addr, units ); - if ( polygonOffset ) { + copyArray( cache, units ); - enable( 32823 ); + } - if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { + for ( let i = 0; i !== n; ++ i ) { - gl.polygonOffset( factor, units ); + textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; + } - } + } - } else { + function setValueT2DArrayArray( gl, v, textures ) { - disable( 32823 ); + const cache = this.cache; - } + const n = v.length; - } + const units = allocTexUnits( textures, n ); - function setScissorTest( scissorTest ) { + if ( ! arraysEqual( cache, units ) ) { - if ( scissorTest ) { + gl.uniform1iv( this.addr, units ); - enable( 3089 ); + copyArray( cache, units ); - } else { + } - disable( 3089 ); + for ( let i = 0; i !== n; ++ i ) { - } + textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] ); } - // texture + } - function activeTexture( webglSlot ) { - if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; + // Helper to pick the right setter for a pure (bottom-level) array - if ( currentTextureSlot !== webglSlot ) { + function getPureArraySetter( type ) { - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; + switch ( type ) { - } + case 0x1406: return setValueV1fArray; // FLOAT + case 0x8b50: return setValueV2fArray; // _VEC2 + case 0x8b51: return setValueV3fArray; // _VEC3 + case 0x8b52: return setValueV4fArray; // _VEC4 - } + case 0x8b5a: return setValueM2Array; // _MAT2 + case 0x8b5b: return setValueM3Array; // _MAT3 + case 0x8b5c: return setValueM4Array; // _MAT4 - function bindTexture( webglType, webglTexture, webglSlot ) { + case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL + case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 + case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 + case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 - if ( webglSlot === undefined ) { + case 0x1405: return setValueV1uiArray; // UINT + case 0x8dc6: return setValueV2uiArray; // _VEC2 + case 0x8dc7: return setValueV3uiArray; // _VEC3 + case 0x8dc8: return setValueV4uiArray; // _VEC4 - if ( currentTextureSlot === null ) { + case 0x8b5e: // SAMPLER_2D + case 0x8d66: // SAMPLER_EXTERNAL_OES + case 0x8dca: // INT_SAMPLER_2D + case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D + case 0x8b62: // SAMPLER_2D_SHADOW + return setValueT1Array; - webglSlot = 33984 + maxTextures - 1; + case 0x8b5f: // SAMPLER_3D + case 0x8dcb: // INT_SAMPLER_3D + case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D + return setValueT3DArray; - } else { + case 0x8b60: // SAMPLER_CUBE + case 0x8dcc: // INT_SAMPLER_CUBE + case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE + case 0x8dc5: // SAMPLER_CUBE_SHADOW + return setValueT6Array; - webglSlot = currentTextureSlot; + case 0x8dc1: // SAMPLER_2D_ARRAY + case 0x8dcf: // INT_SAMPLER_2D_ARRAY + case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY + case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW + return setValueT2DArrayArray; - } + } - } + } - let boundTexture = currentBoundTextures[ webglSlot ]; + // --- Uniform Classes --- - if ( boundTexture === undefined ) { + class SingleUniform { - boundTexture = { type: undefined, texture: undefined }; - currentBoundTextures[ webglSlot ] = boundTexture; + constructor( id, activeInfo, addr ) { - } + this.id = id; + this.addr = addr; + this.cache = []; + this.setValue = getSingularSetter( activeInfo.type ); - if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { + // this.path = activeInfo.name; // DEBUG - if ( currentTextureSlot !== webglSlot ) { + } - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; + } - } + class PureArrayUniform { - gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); + constructor( id, activeInfo, addr ) { - boundTexture.type = webglType; - boundTexture.texture = webglTexture; + this.id = id; + this.addr = addr; + this.cache = []; + this.size = activeInfo.size; + this.setValue = getPureArraySetter( activeInfo.type ); - } + // this.path = activeInfo.name; // DEBUG } - function unbindTexture() { - - const boundTexture = currentBoundTextures[ currentTextureSlot ]; + } - if ( boundTexture !== undefined && boundTexture.type !== undefined ) { + class StructuredUniform { - gl.bindTexture( boundTexture.type, null ); + constructor( id ) { - boundTexture.type = undefined; - boundTexture.texture = undefined; + this.id = id; - } + this.seq = []; + this.map = {}; } - function compressedTexImage2D() { - - try { + setValue( gl, value, textures ) { - gl.compressedTexImage2D.apply( gl, arguments ); + const seq = this.seq; - } catch ( error ) { + for ( let i = 0, n = seq.length; i !== n; ++ i ) { - console.error( 'THREE.WebGLState:', error ); + const u = seq[ i ]; + u.setValue( gl, value[ u.id ], textures ); } } - function texSubImage2D() { + } - try { + // --- Top-level --- - gl.texSubImage2D.apply( gl, arguments ); + // Parser - builds up the property tree from the path strings - } catch ( error ) { + const RePathPart = /(\w+)(\])?(\[|\.)?/g; - console.error( 'THREE.WebGLState:', error ); + // extracts + // - the identifier (member name or array index) + // - followed by an optional right bracket (found when array index) + // - followed by an optional left bracket or dot (type of subscript) + // + // Note: These portions can be read in a non-overlapping fashion and + // allow straightforward parsing of the hierarchy that WebGL encodes + // in the uniform names. - } + function addUniform( container, uniformObject ) { - } + container.seq.push( uniformObject ); + container.map[ uniformObject.id ] = uniformObject; - function texSubImage3D() { + } - try { + function parseUniform( activeInfo, addr, container ) { - gl.texSubImage3D.apply( gl, arguments ); + const path = activeInfo.name, + pathLength = path.length; - } catch ( error ) { + // reset RegExp object, because of the early exit of a previous run + RePathPart.lastIndex = 0; - console.error( 'THREE.WebGLState:', error ); + while ( true ) { - } + const match = RePathPart.exec( path ), + matchEnd = RePathPart.lastIndex; - } + let id = match[ 1 ]; + const idIsIndex = match[ 2 ] === ']', + subscript = match[ 3 ]; - function compressedTexSubImage2D() { + if ( idIsIndex ) id = id | 0; // convert to integer - try { + if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { - gl.compressedTexSubImage2D.apply( gl, arguments ); + // bare name or "pure" bottom-level array "[0]" suffix - } catch ( error ) { + addUniform( container, subscript === undefined ? + new SingleUniform( id, activeInfo, addr ) : + new PureArrayUniform( id, activeInfo, addr ) ); - console.error( 'THREE.WebGLState:', error ); + break; - } + } else { - } + // step into inner node / create it in case it doesn't exist - function texStorage2D() { + const map = container.map; + let next = map[ id ]; - try { + if ( next === undefined ) { - gl.texStorage2D.apply( gl, arguments ); + next = new StructuredUniform( id ); + addUniform( container, next ); - } catch ( error ) { + } - console.error( 'THREE.WebGLState:', error ); + container = next; } } - function texStorage3D() { - - try { - - gl.texStorage3D.apply( gl, arguments ); - - } catch ( error ) { + } - console.error( 'THREE.WebGLState:', error ); + // Root Container - } + class WebGLUniforms { - } + constructor( gl, program ) { - function texImage2D() { + this.seq = []; + this.map = {}; - try { + const n = gl.getProgramParameter( program, 35718 ); - gl.texImage2D.apply( gl, arguments ); + for ( let i = 0; i < n; ++ i ) { - } catch ( error ) { + const info = gl.getActiveUniform( program, i ), + addr = gl.getUniformLocation( program, info.name ); - console.error( 'THREE.WebGLState:', error ); + parseUniform( info, addr, this ); } } - function texImage3D() { + setValue( gl, name, value, textures ) { - try { + const u = this.map[ name ]; - gl.texImage3D.apply( gl, arguments ); + if ( u !== undefined ) u.setValue( gl, value, textures ); - } catch ( error ) { + } - console.error( 'THREE.WebGLState:', error ); + setOptional( gl, object, name ) { - } + const v = object[ name ]; + + if ( v !== undefined ) this.setValue( gl, name, v ); } - // + static upload( gl, seq, values, textures ) { - function scissor( scissor ) { + for ( let i = 0, n = seq.length; i !== n; ++ i ) { - if ( currentScissor.equals( scissor ) === false ) { + const u = seq[ i ], + v = values[ u.id ]; - gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); - currentScissor.copy( scissor ); + if ( v.needsUpdate !== false ) { + + // note: always updating when .needsUpdate is undefined + u.setValue( gl, v.value, textures ); + + } } } - function viewport( viewport ) { + static seqWithValue( seq, values ) { - if ( currentViewport.equals( viewport ) === false ) { + const r = []; - gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); - currentViewport.copy( viewport ); + for ( let i = 0, n = seq.length; i !== n; ++ i ) { + + const u = seq[ i ]; + if ( u.id in values ) r.push( u ); } + return r; + } - function updateUBOMapping( uniformsGroup, program ) { + } - let mapping = uboProgamMap.get( program ); + function WebGLShader( gl, type, string ) { - if ( mapping === undefined ) { + const shader = gl.createShader( type ); - mapping = new WeakMap(); + gl.shaderSource( shader, string ); + gl.compileShader( shader ); - uboProgamMap.set( program, mapping ); + return shader; - } + } - let blockIndex = mapping.get( uniformsGroup ); + let programIdCount = 0; - if ( blockIndex === undefined ) { + function handleSource( string, errorLine ) { - blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name ); + const lines = string.split( '\n' ); + const lines2 = []; - mapping.set( uniformsGroup, blockIndex ); + const from = Math.max( errorLine - 6, 0 ); + const to = Math.min( errorLine + 6, lines.length ); - } + for ( let i = from; i < to; i ++ ) { + + const line = i + 1; + lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` ); } - function uniformBlockBinding( uniformsGroup, program ) { + return lines2.join( '\n' ); - const mapping = uboProgamMap.get( program ); - const blockIndex = mapping.get( uniformsGroup ); + } - if ( uboBindings.get( uniformsGroup ) !== blockIndex ) { + function getEncodingComponents( encoding ) { - // bind shader specific block index to global block point + switch ( encoding ) { - gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); + case LinearEncoding: + return [ 'Linear', '( value )' ]; + case sRGBEncoding: + return [ 'sRGB', '( value )' ]; + default: + console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding ); + return [ 'Linear', '( value )' ]; - uboBindings.set( uniformsGroup, blockIndex ); + } - } + } - } + function getShaderErrors( gl, shader, type ) { - // + const status = gl.getShaderParameter( shader, 35713 ); + const errors = gl.getShaderInfoLog( shader ).trim(); - function reset() { + if ( status && errors === '' ) return ''; - // reset state + const errorMatches = /ERROR: 0:(\d+)/.exec( errors ); + if ( errorMatches ) { - gl.disable( 3042 ); - gl.disable( 2884 ); - gl.disable( 2929 ); - gl.disable( 32823 ); - gl.disable( 3089 ); - gl.disable( 2960 ); - gl.disable( 32926 ); + // --enable-privileged-webgl-extension + // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - gl.blendEquation( 32774 ); - gl.blendFunc( 1, 0 ); - gl.blendFuncSeparate( 1, 0, 1, 0 ); + const errorLine = parseInt( errorMatches[ 1 ] ); + return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine ); - gl.colorMask( true, true, true, true ); - gl.clearColor( 0, 0, 0, 0 ); + } else { - gl.depthMask( true ); - gl.depthFunc( 513 ); - gl.clearDepth( 1 ); + return errors; - gl.stencilMask( 0xffffffff ); - gl.stencilFunc( 519, 0, 0xffffffff ); - gl.stencilOp( 7680, 7680, 7680 ); - gl.clearStencil( 0 ); + } - gl.cullFace( 1029 ); - gl.frontFace( 2305 ); + } - gl.polygonOffset( 0, 0 ); + function getTexelEncodingFunction( functionName, encoding ) { - gl.activeTexture( 33984 ); + const components = getEncodingComponents( encoding ); + return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; - gl.bindFramebuffer( 36160, null ); + } - if ( isWebGL2 === true ) { + function getToneMappingFunction( functionName, toneMapping ) { - gl.bindFramebuffer( 36009, null ); - gl.bindFramebuffer( 36008, null ); + let toneMappingName; - } + switch ( toneMapping ) { - gl.useProgram( null ); + case LinearToneMapping: + toneMappingName = 'Linear'; + break; - gl.lineWidth( 1 ); + case ReinhardToneMapping: + toneMappingName = 'Reinhard'; + break; - gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height ); - gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height ); + case CineonToneMapping: + toneMappingName = 'OptimizedCineon'; + break; - // reset internals + case ACESFilmicToneMapping: + toneMappingName = 'ACESFilmic'; + break; - enabledCapabilities = {}; + case CustomToneMapping: + toneMappingName = 'Custom'; + break; - currentTextureSlot = null; - currentBoundTextures = {}; + default: + console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); + toneMappingName = 'Linear'; - currentBoundFramebuffers = {}; - currentDrawbuffers = new WeakMap(); - defaultDrawbuffers = []; + } - currentProgram = null; + return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; - currentBlendingEnabled = false; - currentBlending = null; - currentBlendEquation = null; - currentBlendSrc = null; - currentBlendDst = null; - currentBlendEquationAlpha = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - currentPremultipledAlpha = false; + } - currentFlipSided = null; - currentCullFace = null; + function generateExtensions( parameters ) { - currentLineWidth = null; + const chunks = [ + ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', + ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', + ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' + ]; - currentPolygonOffsetFactor = null; - currentPolygonOffsetUnits = null; + return chunks.filter( filterEmptyLine ).join( '\n' ); - currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height ); - currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height ); + } - colorBuffer.reset(); - depthBuffer.reset(); - stencilBuffer.reset(); + function generateDefines( defines ) { - } + const chunks = []; - return { + for ( const name in defines ) { - buffers: { - color: colorBuffer, - depth: depthBuffer, - stencil: stencilBuffer - }, + const value = defines[ name ]; - enable: enable, - disable: disable, + if ( value === false ) continue; - bindFramebuffer: bindFramebuffer, - drawBuffers: drawBuffers, + chunks.push( '#define ' + name + ' ' + value ); - useProgram: useProgram, + } - setBlending: setBlending, - setMaterial: setMaterial, + return chunks.join( '\n' ); - setFlipSided: setFlipSided, - setCullFace: setCullFace, + } - setLineWidth: setLineWidth, - setPolygonOffset: setPolygonOffset, + function fetchAttributeLocations( gl, program ) { - setScissorTest: setScissorTest, + const attributes = {}; - activeTexture: activeTexture, - bindTexture: bindTexture, - unbindTexture: unbindTexture, - compressedTexImage2D: compressedTexImage2D, - texImage2D: texImage2D, - texImage3D: texImage3D, + const n = gl.getProgramParameter( program, 35721 ); - updateUBOMapping: updateUBOMapping, - uniformBlockBinding: uniformBlockBinding, + for ( let i = 0; i < n; i ++ ) { - texStorage2D: texStorage2D, - texStorage3D: texStorage3D, - texSubImage2D: texSubImage2D, - texSubImage3D: texSubImage3D, - compressedTexSubImage2D: compressedTexSubImage2D, + const info = gl.getActiveAttrib( program, i ); + const name = info.name; - scissor: scissor, - viewport: viewport, + let locationSize = 1; + if ( info.type === 35674 ) locationSize = 2; + if ( info.type === 35675 ) locationSize = 3; + if ( info.type === 35676 ) locationSize = 4; - reset: reset + // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); - }; + attributes[ name ] = { + type: info.type, + location: gl.getAttribLocation( program, name ), + locationSize: locationSize + }; - } + } - function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { + return attributes; - const isWebGL2 = capabilities.isWebGL2; - const maxTextures = capabilities.maxTextures; - const maxCubemapSize = capabilities.maxCubemapSize; - const maxTextureSize = capabilities.maxTextureSize; - const maxSamples = capabilities.maxSamples; - const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; - const supportsInvalidateFramebuffer = /OculusBrowser/g.test( navigator.userAgent ); + } - const _videoTextures = new WeakMap(); - let _canvas; + function filterEmptyLine( string ) { - const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source + return string !== ''; - // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, - // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! - // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). + } - let useOffscreenCanvas = false; + function replaceLightNums( string, parameters ) { - try { + const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; - useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' - // eslint-disable-next-line compat/compat - && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; + return string + .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) + .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) + .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps ) + .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords ) + .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) + .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) + .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) + .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) + .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps ) + .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) + .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows ); - } catch ( err ) { + } - // Ignore any errors + function replaceClippingPlaneNums( string, parameters ) { - } + return string + .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) + .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); - function createCanvas( width, height ) { + } - // Use OffscreenCanvas when available. Specially needed in web workers + // Resolve Includes - return useOffscreenCanvas ? - // eslint-disable-next-line compat/compat - new OffscreenCanvas( width, height ) : createElementNS( 'canvas' ); + const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; - } + function resolveIncludes( string ) { - function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) { + return string.replace( includePattern, includeReplacer ); - let scale = 1; + } - // handle case if texture exceeds max size + function includeReplacer( match, include ) { - if ( image.width > maxSize || image.height > maxSize ) { + const string = ShaderChunk[ include ]; - scale = maxSize / Math.max( image.width, image.height ); + if ( string === undefined ) { - } + throw new Error( 'Can not resolve #include <' + include + '>' ); - // only perform resize if necessary + } - if ( scale < 1 || needsPowerOfTwo === true ) { + return resolveIncludes( string ); - // only perform resize for certain image types + } - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + // Unroll Loops - const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor; + const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; - const width = floor( scale * image.width ); - const height = floor( scale * image.height ); + function unrollLoops( string ) { - if ( _canvas === undefined ) _canvas = createCanvas( width, height ); + return string.replace( unrollLoopPattern, loopReplacer ); - // cube textures can't reuse the same canvas + } - const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; + function loopReplacer( match, start, end, snippet ) { - canvas.width = width; - canvas.height = height; + let string = ''; - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, width, height ); + for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) { - console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' ); + string += snippet + .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) + .replace( /UNROLLED_LOOP_INDEX/g, i ); - return canvas; + } - } else { + return string; - if ( 'data' in image ) { + } - console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); + // - } + function generatePrecision( parameters ) { - return image; + let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;'; - } + if ( parameters.precision === 'highp' ) { - } + precisionstring += '\n#define HIGH_PRECISION'; - return image; + } else if ( parameters.precision === 'mediump' ) { - } + precisionstring += '\n#define MEDIUM_PRECISION'; - function isPowerOfTwo$1( image ) { + } else if ( parameters.precision === 'lowp' ) { - return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ); + precisionstring += '\n#define LOW_PRECISION'; } - function textureNeedsPowerOfTwo( texture ) { + return precisionstring; - if ( isWebGL2 ) return false; + } - return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || - ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); + function generateShadowMapTypeDefine( parameters ) { - } + let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - function textureNeedsGenerateMipmaps( texture, supportsMips ) { + if ( parameters.shadowMapType === PCFShadowMap ) { - return texture.generateMipmaps && supportsMips && - texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - } + } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { - function generateMipmap( target ) { + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - _gl.generateMipmap( target ); + } else if ( parameters.shadowMapType === VSMShadowMap ) { - } + shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; - function getInternalFormat( internalFormatName, glFormat, glType, encoding, forceLinearEncoding = false ) { + } - if ( isWebGL2 === false ) return glFormat; + return shadowMapTypeDefine; - if ( internalFormatName !== null ) { + } - if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ]; + function generateEnvMapTypeDefine( parameters ) { - console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); + let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - } + if ( parameters.envMap ) { - let internalFormat = glFormat; + switch ( parameters.envMapMode ) { - if ( glFormat === 6403 ) { + case CubeReflectionMapping: + case CubeRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + break; - if ( glType === 5126 ) internalFormat = 33326; - if ( glType === 5131 ) internalFormat = 33325; - if ( glType === 5121 ) internalFormat = 33321; + case CubeUVReflectionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; + break; } - if ( glFormat === 33319 ) { + } - if ( glType === 5126 ) internalFormat = 33328; - if ( glType === 5131 ) internalFormat = 33327; - if ( glType === 5121 ) internalFormat = 33323; + return envMapTypeDefine; - } + } - if ( glFormat === 6408 ) { + function generateEnvMapModeDefine( parameters ) { - if ( glType === 5126 ) internalFormat = 34836; - if ( glType === 5131 ) internalFormat = 34842; - if ( glType === 5121 ) internalFormat = ( encoding === sRGBEncoding && forceLinearEncoding === false ) ? 35907 : 32856; - if ( glType === 32819 ) internalFormat = 32854; - if ( glType === 32820 ) internalFormat = 32855; + let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - } + if ( parameters.envMap ) { - if ( internalFormat === 33325 || internalFormat === 33326 || - internalFormat === 33327 || internalFormat === 33328 || - internalFormat === 34842 || internalFormat === 34836 ) { + switch ( parameters.envMapMode ) { - extensions.get( 'EXT_color_buffer_float' ); + case CubeRefractionMapping: - } + envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; + break; - return internalFormat; + } } - function getMipLevels( texture, image, supportsMips ) { - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) { - - return Math.log2( Math.max( image.width, image.height ) ) + 1; + return envMapModeDefine; - } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) { + } - // user-defined mipmaps + function generateEnvMapBlendingDefine( parameters ) { - return texture.mipmaps.length; + let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; - } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) { + if ( parameters.envMap ) { - return image.mipmaps.length; + switch ( parameters.combine ) { - } else { + case MultiplyOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + break; - // texture without mipmaps (only base level) + case MixOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; + break; - return 1; + case AddOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; + break; } } - // Fallback filters for non-power-of-2 textures + return envMapBlendingDefine; - function filterFallback( f ) { + } - if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { + function generateCubeUVSize( parameters ) { - return 9728; + const imageHeight = parameters.envMapCubeUVHeight; - } + if ( imageHeight === null ) return null; - return 9729; + const maxMip = Math.log2( imageHeight ) - 2; - } + const texelHeight = 1.0 / imageHeight; - // + const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); - function onTextureDispose( event ) { + return { texelWidth, texelHeight, maxMip }; - const texture = event.target; + } - texture.removeEventListener( 'dispose', onTextureDispose ); + function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { - deallocateTexture( texture ); + // TODO Send this event to Three.js DevTools + // console.log( 'WebGLProgram', cacheKey ); - if ( texture.isVideoTexture ) { + const gl = renderer.getContext(); - _videoTextures.delete( texture ); + const defines = parameters.defines; - } + let vertexShader = parameters.vertexShader; + let fragmentShader = parameters.fragmentShader; - } + const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); + const envMapTypeDefine = generateEnvMapTypeDefine( parameters ); + const envMapModeDefine = generateEnvMapModeDefine( parameters ); + const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); + const envMapCubeUVSize = generateCubeUVSize( parameters ); - function onRenderTargetDispose( event ) { + const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); - const renderTarget = event.target; + const customDefines = generateDefines( defines ); - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + const program = gl.createProgram(); - deallocateRenderTarget( renderTarget ); + let prefixVertex, prefixFragment; + let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; - } + if ( parameters.isRawShaderMaterial ) { - // + prefixVertex = [ - function deallocateTexture( texture ) { + customDefines - const textureProperties = properties.get( texture ); + ].filter( filterEmptyLine ).join( '\n' ); - if ( textureProperties.__webglInit === undefined ) return; + if ( prefixVertex.length > 0 ) { - // check if it's necessary to remove the WebGLTexture object + prefixVertex += '\n'; - const source = texture.source; - const webglTextures = _sources.get( source ); + } - if ( webglTextures ) { + prefixFragment = [ - const webglTexture = webglTextures[ textureProperties.__cacheKey ]; - webglTexture.usedTimes --; + customExtensions, + customDefines - // the WebGLTexture object is not used anymore, remove it + ].filter( filterEmptyLine ).join( '\n' ); - if ( webglTexture.usedTimes === 0 ) { + if ( prefixFragment.length > 0 ) { - deleteTexture( texture ); + prefixFragment += '\n'; - } + } - // remove the weak map entry if no WebGLTexture uses the source anymore + } else { - if ( Object.keys( webglTextures ).length === 0 ) { + prefixVertex = [ - _sources.delete( source ); + generatePrecision( parameters ), - } + '#define SHADER_NAME ' + parameters.shaderName, - } + customDefines, - properties.remove( texture ); + parameters.instancing ? '#define USE_INSTANCING' : '', + parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', - } + parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - function deleteTexture( texture ) { + ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', + ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', - const textureProperties = properties.get( texture ); - _gl.deleteTexture( textureProperties.__webglTexture ); + parameters.map ? '#define USE_MAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.aoMap ? '#define USE_AOMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', + ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', - const source = texture.source; - const webglTextures = _sources.get( source ); - delete webglTextures[ textureProperties.__cacheKey ]; + parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', + parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', + parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - info.memory.textures --; + parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', + parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - } + parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', - function deallocateRenderTarget( renderTarget ) { + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', - const texture = renderTarget.texture; + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', + parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); + parameters.transmission ? '#define USE_TRANSMISSION' : '', + parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', + parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - if ( textureProperties.__webglTexture !== undefined ) { + parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', - _gl.deleteTexture( textureProperties.__webglTexture ); + parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', + parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', + parameters.vertexUvs ? '#define USE_UV' : '', + parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', - info.memory.textures --; + parameters.flatShading ? '#define FLAT_SHADED' : '', - } + parameters.skinning ? '#define USE_SKINNING' : '', - if ( renderTarget.depthTexture ) { + parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', + parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', + ( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '', + ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '', + ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', + ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - renderTarget.depthTexture.dispose(); + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - } + parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - if ( renderTarget.isWebGLCubeRenderTarget ) { + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - for ( let i = 0; i < 6; i ++ ) { + 'uniform mat4 modelMatrix;', + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform mat4 viewMatrix;', + 'uniform mat3 normalMatrix;', + 'uniform vec3 cameraPosition;', + 'uniform bool isOrthographic;', - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); + '#ifdef USE_INSTANCING', - } + ' attribute mat4 instanceMatrix;', - } else { + '#endif', - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); - if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); + '#ifdef USE_INSTANCING_COLOR', - if ( renderTargetProperties.__webglColorRenderbuffer ) { + ' attribute vec3 instanceColor;', - for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) { + '#endif', - if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] ); + 'attribute vec3 position;', + 'attribute vec3 normal;', + 'attribute vec2 uv;', - } + '#ifdef USE_TANGENT', - } + ' attribute vec4 tangent;', - if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer ); + '#endif', - } + '#if defined( USE_COLOR_ALPHA )', - if ( renderTarget.isWebGLMultipleRenderTargets ) { + ' attribute vec4 color;', - for ( let i = 0, il = texture.length; i < il; i ++ ) { + '#elif defined( USE_COLOR )', - const attachmentProperties = properties.get( texture[ i ] ); + ' attribute vec3 color;', - if ( attachmentProperties.__webglTexture ) { + '#endif', - _gl.deleteTexture( attachmentProperties.__webglTexture ); + '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )', - info.memory.textures --; + ' attribute vec3 morphTarget0;', + ' attribute vec3 morphTarget1;', + ' attribute vec3 morphTarget2;', + ' attribute vec3 morphTarget3;', - } + ' #ifdef USE_MORPHNORMALS', - properties.remove( texture[ i ] ); + ' attribute vec3 morphNormal0;', + ' attribute vec3 morphNormal1;', + ' attribute vec3 morphNormal2;', + ' attribute vec3 morphNormal3;', - } + ' #else', - } + ' attribute vec3 morphTarget4;', + ' attribute vec3 morphTarget5;', + ' attribute vec3 morphTarget6;', + ' attribute vec3 morphTarget7;', - properties.remove( texture ); - properties.remove( renderTarget ); + ' #endif', - } + '#endif', - // + '#ifdef USE_SKINNING', - let textureUnits = 0; + ' attribute vec4 skinIndex;', + ' attribute vec4 skinWeight;', - function resetTextureUnits() { + '#endif', - textureUnits = 0; + '\n' - } + ].filter( filterEmptyLine ).join( '\n' ); - function allocateTextureUnit() { + prefixFragment = [ - const textureUnit = textureUnits; + customExtensions, - if ( textureUnit >= maxTextures ) { + generatePrecision( parameters ), - console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures ); + '#define SHADER_NAME ' + parameters.shaderName, - } + customDefines, - textureUnits += 1; + ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', + ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', - return textureUnit; + parameters.map ? '#define USE_MAP' : '', + parameters.matcap ? '#define USE_MATCAP' : '', + parameters.envMap ? '#define USE_ENVMAP' : '', + parameters.envMap ? '#define ' + envMapTypeDefine : '', + parameters.envMap ? '#define ' + envMapModeDefine : '', + parameters.envMap ? '#define ' + envMapBlendingDefine : '', + envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', + envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', + envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', + parameters.lightMap ? '#define USE_LIGHTMAP' : '', + parameters.aoMap ? '#define USE_AOMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + parameters.bumpMap ? '#define USE_BUMPMAP' : '', + parameters.normalMap ? '#define USE_NORMALMAP' : '', + ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', + ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', - } + parameters.clearcoat ? '#define USE_CLEARCOAT' : '', + parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', + parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', + parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - function getTextureCacheKey( texture ) { + parameters.iridescence ? '#define USE_IRIDESCENCE' : '', + parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', + parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - const array = []; + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', + parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - array.push( texture.wrapS ); - array.push( texture.wrapT ); - array.push( texture.magFilter ); - array.push( texture.minFilter ); - array.push( texture.anisotropy ); - array.push( texture.internalFormat ); - array.push( texture.format ); - array.push( texture.type ); - array.push( texture.generateMipmaps ); - array.push( texture.premultiplyAlpha ); - array.push( texture.flipY ); - array.push( texture.unpackAlignment ); - array.push( texture.encoding ); + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.alphaTest ? '#define USE_ALPHATEST' : '', - return array.join(); + parameters.sheen ? '#define USE_SHEEN' : '', + parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', - } + parameters.transmission ? '#define USE_TRANSMISSION' : '', + parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', + parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - // + parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', - function setTexture2D( texture, slot ) { + parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', + parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', + parameters.vertexUvs ? '#define USE_UV' : '', + parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', - const textureProperties = properties.get( texture ); + parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', - if ( texture.isVideoTexture ) updateVideoTexture( texture ); + parameters.flatShading ? '#define FLAT_SHADED' : '', - if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) { + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - const image = texture.image; + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - if ( image === null ) { + parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' ); + parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', - } else if ( image.complete === false ) { + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); + 'uniform mat4 viewMatrix;', + 'uniform vec3 cameraPosition;', + 'uniform bool isOrthographic;', - } else { + ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', + ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below + ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', - uploadTexture( textureProperties, texture, slot ); - return; + parameters.dithering ? '#define DITHERING' : '', + parameters.opaque ? '#define OPAQUE' : '', - } + ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below + getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ), - } + parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', - state.bindTexture( 3553, textureProperties.__webglTexture, 33984 + slot ); + '\n' + + ].filter( filterEmptyLine ).join( '\n' ); } - function setTexture2DArray( texture, slot ) { + vertexShader = resolveIncludes( vertexShader ); + vertexShader = replaceLightNums( vertexShader, parameters ); + vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); - const textureProperties = properties.get( texture ); + fragmentShader = resolveIncludes( fragmentShader ); + fragmentShader = replaceLightNums( fragmentShader, parameters ); + fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + vertexShader = unrollLoops( vertexShader ); + fragmentShader = unrollLoops( fragmentShader ); - uploadTexture( textureProperties, texture, slot ); - return; + if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) { - } + // GLSL 3.0 conversion for built-in materials and ShaderMaterial - state.bindTexture( 35866, textureProperties.__webglTexture, 33984 + slot ); + versionString = '#version 300 es\n'; - } + prefixVertex = [ + 'precision mediump sampler2DArray;', + '#define attribute in', + '#define varying out', + '#define texture2D texture' + ].join( '\n' ) + '\n' + prefixVertex; - function setTexture3D( texture, slot ) { + prefixFragment = [ + '#define varying in', + ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', + ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', + '#define gl_FragDepthEXT gl_FragDepth', + '#define texture2D texture', + '#define textureCube texture', + '#define texture2DProj textureProj', + '#define texture2DLodEXT textureLod', + '#define texture2DProjLodEXT textureProjLod', + '#define textureCubeLodEXT textureLod', + '#define texture2DGradEXT textureGrad', + '#define texture2DProjGradEXT textureProjGrad', + '#define textureCubeGradEXT textureGrad' + ].join( '\n' ) + '\n' + prefixFragment; - const textureProperties = properties.get( texture ); + } - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + const vertexGlsl = versionString + prefixVertex + vertexShader; + const fragmentGlsl = versionString + prefixFragment + fragmentShader; - uploadTexture( textureProperties, texture, slot ); - return; + // console.log( '*VERTEX*', vertexGlsl ); + // console.log( '*FRAGMENT*', fragmentGlsl ); - } + const glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); + const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); - state.bindTexture( 32879, textureProperties.__webglTexture, 33984 + slot ); + gl.attachShader( program, glVertexShader ); + gl.attachShader( program, glFragmentShader ); - } + // Force a particular attribute to index 0. - function setTextureCube( texture, slot ) { + if ( parameters.index0AttributeName !== undefined ) { - const textureProperties = properties.get( texture ); + gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + } else if ( parameters.morphTargets === true ) { - uploadCubeTexture( textureProperties, texture, slot ); - return; + // programs with morphTargets displace position out of attribute 0 + gl.bindAttribLocation( program, 0, 'position' ); - } + } - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + gl.linkProgram( program ); - } + // check for link errors + if ( renderer.debug.checkShaderErrors ) { - const wrappingToGL = { - [ RepeatWrapping ]: 10497, - [ ClampToEdgeWrapping ]: 33071, - [ MirroredRepeatWrapping ]: 33648 - }; + const programLog = gl.getProgramInfoLog( program ).trim(); + const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); + const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - const filterToGL = { - [ NearestFilter ]: 9728, - [ NearestMipmapNearestFilter ]: 9984, - [ NearestMipmapLinearFilter ]: 9986, + let runnable = true; + let haveDiagnostics = true; - [ LinearFilter ]: 9729, - [ LinearMipmapNearestFilter ]: 9985, - [ LinearMipmapLinearFilter ]: 9987 - }; + if ( gl.getProgramParameter( program, 35714 ) === false ) { - function setTextureParameters( textureType, texture, supportsMips ) { + runnable = false; - if ( supportsMips ) { + const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); + const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] ); - _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] ); + console.error( + 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + + 'VALIDATE_STATUS ' + gl.getProgramParameter( program, 35715 ) + '\n\n' + + 'Program Info Log: ' + programLog + '\n' + + vertexErrors + '\n' + + fragmentErrors + ); - if ( textureType === 32879 || textureType === 35866 ) { + } else if ( programLog !== '' ) { - _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] ); + console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); - } + } else if ( vertexLog === '' || fragmentLog === '' ) { - _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] ); - _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] ); + haveDiagnostics = false; - } else { + } - _gl.texParameteri( textureType, 10242, 33071 ); - _gl.texParameteri( textureType, 10243, 33071 ); + if ( haveDiagnostics ) { - if ( textureType === 32879 || textureType === 35866 ) { + this.diagnostics = { - _gl.texParameteri( textureType, 32882, 33071 ); + runnable: runnable, - } + programLog: programLog, - if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { + vertexShader: { - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); + log: vertexLog, + prefix: prefixVertex - } + }, - _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); + fragmentShader: { - if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { + log: fragmentLog, + prefix: prefixFragment - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); + } - } + }; } - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { + } - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + // Clean up - if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 - if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only + // Crashes in iOS9 and iOS10. #18402 + // gl.detachShader( program, glVertexShader ); + // gl.detachShader( program, glFragmentShader ); - if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { + gl.deleteShader( glVertexShader ); + gl.deleteShader( glFragmentShader ); - _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); - properties.get( texture ).__currentAnisotropy = texture.anisotropy; + // set up caching for uniform locations - } + let cachedUniforms; - } + this.getUniforms = function () { - } + if ( cachedUniforms === undefined ) { - function initTexture( textureProperties, texture ) { + cachedUniforms = new WebGLUniforms( gl, program ); - let forceUpload = false; + } - if ( textureProperties.__webglInit === undefined ) { + return cachedUniforms; - textureProperties.__webglInit = true; + }; - texture.addEventListener( 'dispose', onTextureDispose ); + // set up caching for attribute locations - } + let cachedAttributes; - // create Source <-> WebGLTextures mapping if necessary - - const source = texture.source; - let webglTextures = _sources.get( source ); + this.getAttributes = function () { - if ( webglTextures === undefined ) { + if ( cachedAttributes === undefined ) { - webglTextures = {}; - _sources.set( source, webglTextures ); + cachedAttributes = fetchAttributeLocations( gl, program ); } - // check if there is already a WebGLTexture object for the given texture parameters + return cachedAttributes; - const textureCacheKey = getTextureCacheKey( texture ); + }; - if ( textureCacheKey !== textureProperties.__cacheKey ) { + // free resource - // if not, create a new instance of WebGLTexture + this.destroy = function () { - if ( webglTextures[ textureCacheKey ] === undefined ) { + bindingStates.releaseStatesOfProgram( this ); - // create new entry + gl.deleteProgram( program ); + this.program = undefined; - webglTextures[ textureCacheKey ] = { - texture: _gl.createTexture(), - usedTimes: 0 - }; + }; - info.memory.textures ++; + // - // when a new instance of WebGLTexture was created, a texture upload is required - // even if the image contents are identical + this.name = parameters.shaderName; + this.id = programIdCount ++; + this.cacheKey = cacheKey; + this.usedTimes = 1; + this.program = program; + this.vertexShader = glVertexShader; + this.fragmentShader = glFragmentShader; - forceUpload = true; + return this; - } + } - webglTextures[ textureCacheKey ].usedTimes ++; + let _id = 0; - // every time the texture cache key changes, it's necessary to check if an instance of - // WebGLTexture can be deleted in order to avoid a memory leak. + class WebGLShaderCache { - const webglTexture = webglTextures[ textureProperties.__cacheKey ]; + constructor() { - if ( webglTexture !== undefined ) { + this.shaderCache = new Map(); + this.materialCache = new Map(); - webglTextures[ textureProperties.__cacheKey ].usedTimes --; + } - if ( webglTexture.usedTimes === 0 ) { + update( material ) { - deleteTexture( texture ); + const vertexShader = material.vertexShader; + const fragmentShader = material.fragmentShader; - } + const vertexShaderStage = this._getShaderStage( vertexShader ); + const fragmentShaderStage = this._getShaderStage( fragmentShader ); - } + const materialShaders = this._getShaderCacheForMaterial( material ); - // store references to cache key and WebGLTexture object + if ( materialShaders.has( vertexShaderStage ) === false ) { - textureProperties.__cacheKey = textureCacheKey; - textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture; + materialShaders.add( vertexShaderStage ); + vertexShaderStage.usedTimes ++; } - return forceUpload; - - } - - function uploadTexture( textureProperties, texture, slot ) { + if ( materialShaders.has( fragmentShaderStage ) === false ) { - let textureType = 3553; + materialShaders.add( fragmentShaderStage ); + fragmentShaderStage.usedTimes ++; - if ( texture.isDataArrayTexture ) textureType = 35866; - if ( texture.isData3DTexture ) textureType = 32879; + } - const forceUpload = initTexture( textureProperties, texture ); - const source = texture.source; + return this; - state.bindTexture( textureType, textureProperties.__webglTexture, 33984 + slot ); + } - const sourceProperties = properties.get( source ); + remove( material ) { - if ( source.version !== sourceProperties.__version || forceUpload === true ) { + const materialShaders = this.materialCache.get( material ); - state.activeTexture( 33984 + slot ); + for ( const shaderStage of materialShaders ) { - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + shaderStage.usedTimes --; - const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; - let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize ); - image = verifyColorSpace( texture, image ); + if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code ); - const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ); + } - let glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, texture.isVideoTexture ); + this.materialCache.delete( material ); - setTextureParameters( textureType, texture, supportsMips ); + return this; - let mipmap; - const mipmaps = texture.mipmaps; + } - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); - const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); - const levels = getMipLevels( texture, image, supportsMips ); + getVertexShaderID( material ) { - if ( texture.isDepthTexture ) { + return this._getShaderStage( material.vertexShader ).id; - // populate depth texture with dummy data + } - glInternalFormat = 6402; + getFragmentShaderID( material ) { - if ( isWebGL2 ) { + return this._getShaderStage( material.fragmentShader ).id; - if ( texture.type === FloatType ) { + } - glInternalFormat = 36012; + dispose() { - } else if ( texture.type === UnsignedIntType ) { + this.shaderCache.clear(); + this.materialCache.clear(); - glInternalFormat = 33190; + } - } else if ( texture.type === UnsignedInt248Type ) { + _getShaderCacheForMaterial( material ) { - glInternalFormat = 35056; + const cache = this.materialCache; + let set = cache.get( material ); - } else { + if ( set === undefined ) { - glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D + set = new Set(); + cache.set( material, set ); - } + } - } else { + return set; - if ( texture.type === FloatType ) { + } - console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' ); + _getShaderStage( code ) { - } + const cache = this.shaderCache; + let stage = cache.get( code ); - } + if ( stage === undefined ) { - // validation checks for WebGL 1 + stage = new WebGLShaderStage( code ); + cache.set( code, stage ); - if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { + } - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { + return stage; - console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); + } - texture.type = UnsignedIntType; - glType = utils.convert( texture.type ); + } - } + class WebGLShaderStage { - } + constructor( code ) { - if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) { + this.id = _id ++; - // Depth stencil textures need the DEPTH_STENCIL internal format - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - glInternalFormat = 34041; + this.code = code; + this.usedTimes = 0; - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedInt248Type ) { + } - console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); + } - texture.type = UnsignedInt248Type; - glType = utils.convert( texture.type ); + function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) { - } + const _programLayers = new Layers(); + const _customShaders = new WebGLShaderCache(); + const programs = []; - } + const isWebGL2 = capabilities.isWebGL2; + const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; + const vertexTextures = capabilities.vertexTextures; + let precision = capabilities.precision; - // + const shaderIDs = { + MeshDepthMaterial: 'depth', + MeshDistanceMaterial: 'distanceRGBA', + MeshNormalMaterial: 'normal', + MeshBasicMaterial: 'basic', + MeshLambertMaterial: 'lambert', + MeshPhongMaterial: 'phong', + MeshToonMaterial: 'toon', + MeshStandardMaterial: 'physical', + MeshPhysicalMaterial: 'physical', + MeshMatcapMaterial: 'matcap', + LineBasicMaterial: 'basic', + LineDashedMaterial: 'dashed', + PointsMaterial: 'points', + ShadowMaterial: 'shadow', + SpriteMaterial: 'sprite' + }; - if ( allocateMemory ) { + function getParameters( material, lights, shadows, scene, object ) { - if ( useTexStorage ) { + const fog = scene.fog; + const geometry = object.geometry; + const environment = material.isMeshStandardMaterial ? scene.environment : null; - state.texStorage2D( 3553, 1, glInternalFormat, image.width, image.height ); + const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); + const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null; - } else { + const shaderID = shaderIDs[ material.type ]; - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) - } + if ( material.precision !== null ) { - } + precision = capabilities.getMaxPrecision( material.precision ); - } else if ( texture.isDataTexture ) { + if ( precision !== material.precision ) { - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels + console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); - if ( mipmaps.length > 0 && supportsMips ) { + } - if ( useTexStorage && allocateMemory ) { + } - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + // - } + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { + let morphTextureStride = 0; - mipmap = mipmaps[ i ]; + if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1; + if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2; + if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3; - if ( useTexStorage ) { + // - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + let vertexShader, fragmentShader; + let customVertexShaderID, customFragmentShaderID; - } else { + if ( shaderID ) { - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + const shader = ShaderLib[ shaderID ]; - } + vertexShader = shader.vertexShader; + fragmentShader = shader.fragmentShader; - } + } else { - texture.generateMipmaps = false; + vertexShader = material.vertexShader; + fragmentShader = material.fragmentShader; - } else { + _customShaders.update( material ); - if ( useTexStorage ) { + customVertexShaderID = _customShaders.getVertexShaderID( material ); + customFragmentShaderID = _customShaders.getFragmentShaderID( material ); - if ( allocateMemory ) { + } - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + const currentRenderTarget = renderer.getRenderTarget(); - } + const useAlphaTest = material.alphaTest > 0; + const useClearcoat = material.clearcoat > 0; + const useIridescence = material.iridescence > 0; - state.texSubImage2D( 3553, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); + const parameters = { - } else { + isWebGL2: isWebGL2, - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); + shaderID: shaderID, + shaderName: material.type, - } + vertexShader: vertexShader, + fragmentShader: fragmentShader, + defines: material.defines, - } + customVertexShaderID: customVertexShaderID, + customFragmentShaderID: customFragmentShaderID, - } else if ( texture.isCompressedTexture ) { + isRawShaderMaterial: material.isRawShaderMaterial === true, + glslVersion: material.glslVersion, - if ( useTexStorage && allocateMemory ) { + precision: precision, - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + instancing: object.isInstancedMesh === true, + instancingColor: object.isInstancedMesh === true && object.instanceColor !== null, - } + supportsVertexTextures: vertexTextures, + outputEncoding: ( currentRenderTarget === null ) ? renderer.outputEncoding : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.encoding : LinearEncoding ), + map: !! material.map, + matcap: !! material.matcap, + envMap: !! envMap, + envMapMode: envMap && envMap.mapping, + envMapCubeUVHeight: envMapCubeUVHeight, + lightMap: !! material.lightMap, + aoMap: !! material.aoMap, + emissiveMap: !! material.emissiveMap, + bumpMap: !! material.bumpMap, + normalMap: !! material.normalMap, + objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, + tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap, - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { + decodeVideoTexture: !! material.map && ( material.map.isVideoTexture === true ) && ( material.map.encoding === sRGBEncoding ), - mipmap = mipmaps[ i ]; + clearcoat: useClearcoat, + clearcoatMap: useClearcoat && !! material.clearcoatMap, + clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap, + clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap, - if ( texture.format !== RGBAFormat ) { + iridescence: useIridescence, + iridescenceMap: useIridescence && !! material.iridescenceMap, + iridescenceThicknessMap: useIridescence && !! material.iridescenceThicknessMap, - if ( glFormat !== null ) { + displacementMap: !! material.displacementMap, + roughnessMap: !! material.roughnessMap, + metalnessMap: !! material.metalnessMap, + specularMap: !! material.specularMap, + specularIntensityMap: !! material.specularIntensityMap, + specularColorMap: !! material.specularColorMap, - if ( useTexStorage ) { + opaque: material.transparent === false && material.blending === NormalBlending, - state.compressedTexSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + alphaMap: !! material.alphaMap, + alphaTest: useAlphaTest, - } else { + gradientMap: !! material.gradientMap, - state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + sheen: material.sheen > 0, + sheenColorMap: !! material.sheenColorMap, + sheenRoughnessMap: !! material.sheenRoughnessMap, - } + transmission: material.transmission > 0, + transmissionMap: !! material.transmissionMap, + thicknessMap: !! material.thicknessMap, - } else { + combine: material.combine, - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); + vertexTangents: ( !! material.normalMap && !! geometry.attributes.tangent ), + vertexColors: material.vertexColors, + vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, + vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || !! material.sheenRoughnessMap, + uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap, - } + fog: !! fog, + useFog: material.fog === true, + fogExp2: ( fog && fog.isFogExp2 ), - } else { + flatShading: !! material.flatShading, - if ( useTexStorage ) { + sizeAttenuation: material.sizeAttenuation, + logarithmicDepthBuffer: logarithmicDepthBuffer, - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + skinning: object.isSkinnedMesh === true, - } else { + morphTargets: geometry.morphAttributes.position !== undefined, + morphNormals: geometry.morphAttributes.normal !== undefined, + morphColors: geometry.morphAttributes.color !== undefined, + morphTargetsCount: morphTargetsCount, + morphTextureStride: morphTextureStride, - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + numDirLights: lights.directional.length, + numPointLights: lights.point.length, + numSpotLights: lights.spot.length, + numSpotLightMaps: lights.spotLightMap.length, + numRectAreaLights: lights.rectArea.length, + numHemiLights: lights.hemi.length, - } + numDirLightShadows: lights.directionalShadowMap.length, + numPointLightShadows: lights.pointShadowMap.length, + numSpotLightShadows: lights.spotShadowMap.length, + numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, - } + numClippingPlanes: clipping.numPlanes, + numClipIntersection: clipping.numIntersection, - } + dithering: material.dithering, - } else if ( texture.isDataArrayTexture ) { + shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, + shadowMapType: renderer.shadowMap.type, - if ( useTexStorage ) { + toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping, + physicallyCorrectLights: renderer.physicallyCorrectLights, - if ( allocateMemory ) { + premultipliedAlpha: material.premultipliedAlpha, - state.texStorage3D( 35866, levels, glInternalFormat, image.width, image.height, image.depth ); + doubleSided: material.side === DoubleSide, + flipSided: material.side === BackSide, - } + useDepthPacking: !! material.depthPacking, + depthPacking: material.depthPacking || 0, - state.texSubImage3D( 35866, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + index0AttributeName: material.index0AttributeName, - } else { + extensionDerivatives: material.extensions && material.extensions.derivatives, + extensionFragDepth: material.extensions && material.extensions.fragDepth, + extensionDrawBuffers: material.extensions && material.extensions.drawBuffers, + extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD, - state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ), + rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ), + rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ), - } + customProgramCacheKey: material.customProgramCacheKey() - } else if ( texture.isData3DTexture ) { + }; - if ( useTexStorage ) { + return parameters; - if ( allocateMemory ) { + } - state.texStorage3D( 32879, levels, glInternalFormat, image.width, image.height, image.depth ); + function getProgramCacheKey( parameters ) { - } + const array = []; - state.texSubImage3D( 32879, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + if ( parameters.shaderID ) { - } else { + array.push( parameters.shaderID ); - state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + } else { - } + array.push( parameters.customVertexShaderID ); + array.push( parameters.customFragmentShaderID ); - } else if ( texture.isFramebufferTexture ) { + } - if ( allocateMemory ) { + if ( parameters.defines !== undefined ) { - if ( useTexStorage ) { + for ( const name in parameters.defines ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + array.push( name ); + array.push( parameters.defines[ name ] ); - } else { + } - let width = image.width, height = image.height; + } - for ( let i = 0; i < levels; i ++ ) { + if ( parameters.isRawShaderMaterial === false ) { - state.texImage2D( 3553, i, glInternalFormat, width, height, 0, glFormat, glType, null ); + getProgramCacheKeyParameters( array, parameters ); + getProgramCacheKeyBooleans( array, parameters ); + array.push( renderer.outputEncoding ); - width >>= 1; - height >>= 1; + } - } + array.push( parameters.customProgramCacheKey ); - } + return array.join(); - } + } - } else { + function getProgramCacheKeyParameters( array, parameters ) { - // regular Texture (image, video, canvas) + array.push( parameters.precision ); + array.push( parameters.outputEncoding ); + array.push( parameters.envMapMode ); + array.push( parameters.envMapCubeUVHeight ); + array.push( parameters.combine ); + array.push( parameters.vertexUvs ); + array.push( parameters.fogExp2 ); + array.push( parameters.sizeAttenuation ); + array.push( parameters.morphTargetsCount ); + array.push( parameters.morphAttributeCount ); + array.push( parameters.numDirLights ); + array.push( parameters.numPointLights ); + array.push( parameters.numSpotLights ); + array.push( parameters.numSpotLightMaps ); + array.push( parameters.numHemiLights ); + array.push( parameters.numRectAreaLights ); + array.push( parameters.numDirLightShadows ); + array.push( parameters.numPointLightShadows ); + array.push( parameters.numSpotLightShadows ); + array.push( parameters.numSpotLightShadowsWithMaps ); + array.push( parameters.shadowMapType ); + array.push( parameters.toneMapping ); + array.push( parameters.numClippingPlanes ); + array.push( parameters.numClipIntersection ); + array.push( parameters.depthPacking ); - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels + } - if ( mipmaps.length > 0 && supportsMips ) { + function getProgramCacheKeyBooleans( array, parameters ) { - if ( useTexStorage && allocateMemory ) { + _programLayers.disableAll(); - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + if ( parameters.isWebGL2 ) + _programLayers.enable( 0 ); + if ( parameters.supportsVertexTextures ) + _programLayers.enable( 1 ); + if ( parameters.instancing ) + _programLayers.enable( 2 ); + if ( parameters.instancingColor ) + _programLayers.enable( 3 ); + if ( parameters.map ) + _programLayers.enable( 4 ); + if ( parameters.matcap ) + _programLayers.enable( 5 ); + if ( parameters.envMap ) + _programLayers.enable( 6 ); + if ( parameters.lightMap ) + _programLayers.enable( 7 ); + if ( parameters.aoMap ) + _programLayers.enable( 8 ); + if ( parameters.emissiveMap ) + _programLayers.enable( 9 ); + if ( parameters.bumpMap ) + _programLayers.enable( 10 ); + if ( parameters.normalMap ) + _programLayers.enable( 11 ); + if ( parameters.objectSpaceNormalMap ) + _programLayers.enable( 12 ); + if ( parameters.tangentSpaceNormalMap ) + _programLayers.enable( 13 ); + if ( parameters.clearcoat ) + _programLayers.enable( 14 ); + if ( parameters.clearcoatMap ) + _programLayers.enable( 15 ); + if ( parameters.clearcoatRoughnessMap ) + _programLayers.enable( 16 ); + if ( parameters.clearcoatNormalMap ) + _programLayers.enable( 17 ); + if ( parameters.iridescence ) + _programLayers.enable( 18 ); + if ( parameters.iridescenceMap ) + _programLayers.enable( 19 ); + if ( parameters.iridescenceThicknessMap ) + _programLayers.enable( 20 ); + if ( parameters.displacementMap ) + _programLayers.enable( 21 ); + if ( parameters.specularMap ) + _programLayers.enable( 22 ); + if ( parameters.roughnessMap ) + _programLayers.enable( 23 ); + if ( parameters.metalnessMap ) + _programLayers.enable( 24 ); + if ( parameters.gradientMap ) + _programLayers.enable( 25 ); + if ( parameters.alphaMap ) + _programLayers.enable( 26 ); + if ( parameters.alphaTest ) + _programLayers.enable( 27 ); + if ( parameters.vertexColors ) + _programLayers.enable( 28 ); + if ( parameters.vertexAlphas ) + _programLayers.enable( 29 ); + if ( parameters.vertexUvs ) + _programLayers.enable( 30 ); + if ( parameters.vertexTangents ) + _programLayers.enable( 31 ); + if ( parameters.uvsVertexOnly ) + _programLayers.enable( 32 ); - } + array.push( _programLayers.mask ); + _programLayers.disableAll(); - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { + if ( parameters.fog ) + _programLayers.enable( 0 ); + if ( parameters.useFog ) + _programLayers.enable( 1 ); + if ( parameters.flatShading ) + _programLayers.enable( 2 ); + if ( parameters.logarithmicDepthBuffer ) + _programLayers.enable( 3 ); + if ( parameters.skinning ) + _programLayers.enable( 4 ); + if ( parameters.morphTargets ) + _programLayers.enable( 5 ); + if ( parameters.morphNormals ) + _programLayers.enable( 6 ); + if ( parameters.morphColors ) + _programLayers.enable( 7 ); + if ( parameters.premultipliedAlpha ) + _programLayers.enable( 8 ); + if ( parameters.shadowMapEnabled ) + _programLayers.enable( 9 ); + if ( parameters.physicallyCorrectLights ) + _programLayers.enable( 10 ); + if ( parameters.doubleSided ) + _programLayers.enable( 11 ); + if ( parameters.flipSided ) + _programLayers.enable( 12 ); + if ( parameters.useDepthPacking ) + _programLayers.enable( 13 ); + if ( parameters.dithering ) + _programLayers.enable( 14 ); + if ( parameters.specularIntensityMap ) + _programLayers.enable( 15 ); + if ( parameters.specularColorMap ) + _programLayers.enable( 16 ); + if ( parameters.transmission ) + _programLayers.enable( 17 ); + if ( parameters.transmissionMap ) + _programLayers.enable( 18 ); + if ( parameters.thicknessMap ) + _programLayers.enable( 19 ); + if ( parameters.sheen ) + _programLayers.enable( 20 ); + if ( parameters.sheenColorMap ) + _programLayers.enable( 21 ); + if ( parameters.sheenRoughnessMap ) + _programLayers.enable( 22 ); + if ( parameters.decodeVideoTexture ) + _programLayers.enable( 23 ); + if ( parameters.opaque ) + _programLayers.enable( 24 ); - mipmap = mipmaps[ i ]; + array.push( _programLayers.mask ); - if ( useTexStorage ) { + } - state.texSubImage2D( 3553, i, 0, 0, glFormat, glType, mipmap ); + function getUniforms( material ) { - } else { + const shaderID = shaderIDs[ material.type ]; + let uniforms; - state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); + if ( shaderID ) { - } + const shader = ShaderLib[ shaderID ]; + uniforms = UniformsUtils.clone( shader.uniforms ); - } + } else { - texture.generateMipmaps = false; + uniforms = material.uniforms; - } else { + } - if ( useTexStorage ) { + return uniforms; - if ( allocateMemory ) { + } - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + function acquireProgram( parameters, cacheKey ) { - } + let program; - state.texSubImage2D( 3553, 0, 0, 0, glFormat, glType, image ); + // Check if code has been already compiled + for ( let p = 0, pl = programs.length; p < pl; p ++ ) { - } else { + const preexistingProgram = programs[ p ]; - state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); + if ( preexistingProgram.cacheKey === cacheKey ) { - } + program = preexistingProgram; + ++ program.usedTimes; - } + break; } - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( textureType ); - - } + } - sourceProperties.__version = source.version; + if ( program === undefined ) { - if ( texture.onUpdate ) texture.onUpdate( texture ); + program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); + programs.push( program ); } - textureProperties.__version = texture.version; + return program; } - function uploadCubeTexture( textureProperties, texture, slot ) { + function releaseProgram( program ) { - if ( texture.image.length !== 6 ) return; + if ( -- program.usedTimes === 0 ) { - const forceUpload = initTexture( textureProperties, texture ); - const source = texture.source; + // Remove from unordered set + const i = programs.indexOf( program ); + programs[ i ] = programs[ programs.length - 1 ]; + programs.pop(); - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + // Free WebGL resources + program.destroy(); - const sourceProperties = properties.get( source ); + } - if ( source.version !== sourceProperties.__version || forceUpload === true ) { + } - state.activeTexture( 33984 + slot ); + function releaseShaderCache( material ) { - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + _customShaders.remove( material ); - const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); - const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); + } - const cubeImage = []; + function dispose() { - for ( let i = 0; i < 6; i ++ ) { + _customShaders.dispose(); - if ( ! isCompressed && ! isDataTexture ) { + } - cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize ); + return { + getParameters: getParameters, + getProgramCacheKey: getProgramCacheKey, + getUniforms: getUniforms, + acquireProgram: acquireProgram, + releaseProgram: releaseProgram, + releaseShaderCache: releaseShaderCache, + // Exposed for resource monitoring & error feedback via renderer.info: + programs: programs, + dispose: dispose + }; - } else { + } - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; + function WebGLProperties() { - } + let properties = new WeakMap(); - cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] ); + function get( object ) { - } + let map = properties.get( object ); - const image = cubeImage[ 0 ], - supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ), - glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + if ( map === undefined ) { - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); - const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); - let levels = getMipLevels( texture, image, supportsMips ); + map = {}; + properties.set( object, map ); - setTextureParameters( 34067, texture, supportsMips ); + } - let mipmaps; + return map; - if ( isCompressed ) { + } - if ( useTexStorage && allocateMemory ) { + function remove( object ) { - state.texStorage2D( 34067, levels, glInternalFormat, image.width, image.height ); + properties.delete( object ); - } + } - for ( let i = 0; i < 6; i ++ ) { + function update( object, key, value ) { - mipmaps = cubeImage[ i ].mipmaps; + properties.get( object )[ key ] = value; - for ( let j = 0; j < mipmaps.length; j ++ ) { + } - const mipmap = mipmaps[ j ]; + function dispose() { - if ( texture.format !== RGBAFormat ) { + properties = new WeakMap(); - if ( glFormat !== null ) { + } - if ( useTexStorage ) { + return { + get: get, + remove: remove, + update: update, + dispose: dispose + }; - state.compressedTexSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + } - } else { + function painterSortStable( a, b ) { - state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + if ( a.groupOrder !== b.groupOrder ) { - } + return a.groupOrder - b.groupOrder; - } else { + } else if ( a.renderOrder !== b.renderOrder ) { - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); + return a.renderOrder - b.renderOrder; - } + } else if ( a.material.id !== b.material.id ) { - } else { + return a.material.id - b.material.id; - if ( useTexStorage ) { + } else if ( a.z !== b.z ) { - state.texSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + return a.z - b.z; - } else { + } else { - state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + return a.id - b.id; - } + } - } + } - } + function reversePainterSortStable( a, b ) { - } + if ( a.groupOrder !== b.groupOrder ) { - } else { + return a.groupOrder - b.groupOrder; - mipmaps = texture.mipmaps; + } else if ( a.renderOrder !== b.renderOrder ) { - if ( useTexStorage && allocateMemory ) { + return a.renderOrder - b.renderOrder; - // TODO: Uniformly handle mipmap definitions - // Normal textures and compressed cube textures define base level + mips with their mipmap array - // Uncompressed cube textures use their mipmap array only for mips (no base level) + } else if ( a.z !== b.z ) { - if ( mipmaps.length > 0 ) levels ++; + return b.z - a.z; - state.texStorage2D( 34067, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); + } else { - } + return a.id - b.id; - for ( let i = 0; i < 6; i ++ ) { + } - if ( isDataTexture ) { + } - if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); + function WebGLRenderList() { - } else { + const renderItems = []; + let renderItemsIndex = 0; - state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + const opaque = []; + const transmissive = []; + const transparent = []; - } + function init() { - for ( let j = 0; j < mipmaps.length; j ++ ) { + renderItemsIndex = 0; - const mipmap = mipmaps[ j ]; - const mipmapImage = mipmap.image[ i ].image; + opaque.length = 0; + transmissive.length = 0; + transparent.length = 0; - if ( useTexStorage ) { + } - state.texSubImage2D( 34069 + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); + function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { - } else { + let renderItem = renderItems[ renderItemsIndex ]; - state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); + if ( renderItem === undefined ) { - } + renderItem = { + id: object.id, + object: object, + geometry: geometry, + material: material, + groupOrder: groupOrder, + renderOrder: object.renderOrder, + z: z, + group: group + }; - } + renderItems[ renderItemsIndex ] = renderItem; - } else { + } else { - if ( useTexStorage ) { + renderItem.id = object.id; + renderItem.object = object; + renderItem.geometry = geometry; + renderItem.material = material; + renderItem.groupOrder = groupOrder; + renderItem.renderOrder = object.renderOrder; + renderItem.z = z; + renderItem.group = group; - state.texSubImage2D( 34069 + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); + } - } else { + renderItemsIndex ++; - state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); + return renderItem; - } + } - for ( let j = 0; j < mipmaps.length; j ++ ) { + function push( object, geometry, material, groupOrder, z, group ) { - const mipmap = mipmaps[ j ]; + const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - if ( useTexStorage ) { + if ( material.transmission > 0.0 ) { - state.texSubImage2D( 34069 + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); + transmissive.push( renderItem ); - } else { + } else if ( material.transparent === true ) { - state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); + transparent.push( renderItem ); - } + } else { - } + opaque.push( renderItem ); - } + } - } + } - } + function unshift( object, geometry, material, groupOrder, z, group ) { - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { + const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - // We assume images for cube map have the same size. - generateMipmap( 34067 ); + if ( material.transmission > 0.0 ) { - } + transmissive.unshift( renderItem ); - sourceProperties.__version = source.version; + } else if ( material.transparent === true ) { - if ( texture.onUpdate ) texture.onUpdate( texture ); + transparent.unshift( renderItem ); - } + } else { - textureProperties.__version = texture.version; + opaque.unshift( renderItem ); + + } } - // Render targets + function sort( customOpaqueSort, customTransparentSort ) { - // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) { + if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable ); + if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable ); + if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable ); - const glFormat = utils.convert( texture.format, texture.encoding ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); - const renderTargetProperties = properties.get( renderTarget ); + } - if ( ! renderTargetProperties.__hasExternalTextures ) { + function finish() { - if ( textureTarget === 32879 || textureTarget === 35866 ) { + // Clear references from inactive renderItems in the list - state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null ); + for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { - } else { + const renderItem = renderItems[ i ]; - state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + if ( renderItem.id === null ) break; - } + renderItem.id = null; + renderItem.object = null; + renderItem.geometry = null; + renderItem.material = null; + renderItem.group = null; } - state.bindFramebuffer( 36160, framebuffer ); + } - if ( useMultisampledRTT( renderTarget ) ) { + return { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); + opaque: opaque, + transmissive: transmissive, + transparent: transparent, - } else { + init: init, + push: push, + unshift: unshift, + finish: finish, - _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 ); + sort: sort + }; - } + } - state.bindFramebuffer( 36160, null ); + function WebGLRenderLists() { - } + let lists = new WeakMap(); + function get( scene, renderCallDepth ) { - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer - function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { + const listArray = lists.get( scene ); + let list; - _gl.bindRenderbuffer( 36161, renderbuffer ); + if ( listArray === undefined ) { - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + list = new WebGLRenderList(); + lists.set( scene, [ list ] ); - let glInternalFormat = 33189; + } else { - if ( isMultisample || useMultisampledRTT( renderTarget ) ) { + if ( renderCallDepth >= listArray.length ) { - const depthTexture = renderTarget.depthTexture; + list = new WebGLRenderList(); + listArray.push( list ); - if ( depthTexture && depthTexture.isDepthTexture ) { + } else { - if ( depthTexture.type === FloatType ) { + list = listArray[ renderCallDepth ]; - glInternalFormat = 36012; + } - } else if ( depthTexture.type === UnsignedIntType ) { + } - glInternalFormat = 33190; + return list; - } + } - } + function dispose() { - const samples = getRenderTargetSamples( renderTarget ); + lists = new WeakMap(); - if ( useMultisampledRTT( renderTarget ) ) { + } - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + return { + get: get, + dispose: dispose + }; - } else { + } - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + function UniformsCache() { - } + const lights = {}; - } else { + return { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + get: function ( light ) { - } + if ( lights[ light.id ] !== undefined ) { - _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); + return lights[ light.id ]; - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + } - const samples = getRenderTargetSamples( renderTarget ); + let uniforms; - if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { + switch ( light.type ) { - _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + case 'DirectionalLight': + uniforms = { + direction: new Vector3(), + color: new Color() + }; + break; - } else if ( useMultisampledRTT( renderTarget ) ) { + case 'SpotLight': + uniforms = { + position: new Vector3(), + direction: new Vector3(), + color: new Color(), + distance: 0, + coneCos: 0, + penumbraCos: 0, + decay: 0 + }; + break; - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + case 'PointLight': + uniforms = { + position: new Vector3(), + color: new Color(), + distance: 0, + decay: 0 + }; + break; - } else { + case 'HemisphereLight': + uniforms = { + direction: new Vector3(), + skyColor: new Color(), + groundColor: new Color() + }; + break; - _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); + case 'RectAreaLight': + uniforms = { + color: new Color(), + position: new Vector3(), + halfWidth: new Vector3(), + halfHeight: new Vector3() + }; + break; } + lights[ light.id ] = uniforms; - _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); - - } else { - - const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - - for ( let i = 0; i < textures.length; i ++ ) { + return uniforms; - const texture = textures[ i ]; + } - const glFormat = utils.convert( texture.format, texture.encoding ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); - const samples = getRenderTargetSamples( renderTarget ); + }; - if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { + } - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + function ShadowUniformsCache() { - } else if ( useMultisampledRTT( renderTarget ) ) { + const lights = {}; - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + return { - } else { + get: function ( light ) { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + if ( lights[ light.id ] !== undefined ) { - } + return lights[ light.id ]; } - } - - _gl.bindRenderbuffer( 36161, null ); - - } + let uniforms; - // Setup resources for a Depth Texture for a FBO (needs an extension) - function setupDepthTexture( framebuffer, renderTarget ) { + switch ( light.type ) { - const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); - if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); + case 'DirectionalLight': + uniforms = { + shadowBias: 0, + shadowNormalBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; - state.bindFramebuffer( 36160, framebuffer ); + case 'SpotLight': + uniforms = { + shadowBias: 0, + shadowNormalBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; - if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { + case 'PointLight': + uniforms = { + shadowBias: 0, + shadowNormalBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2(), + shadowCameraNear: 1, + shadowCameraFar: 1000 + }; + break; - throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); + // TODO (abelnation): set RectAreaLight shadow uniforms - } + } - // upload an empty depth texture with framebuffer size - if ( ! properties.get( renderTarget.depthTexture ).__webglTexture || - renderTarget.depthTexture.image.width !== renderTarget.width || - renderTarget.depthTexture.image.height !== renderTarget.height ) { + lights[ light.id ] = uniforms; - renderTarget.depthTexture.image.width = renderTarget.width; - renderTarget.depthTexture.image.height = renderTarget.height; - renderTarget.depthTexture.needsUpdate = true; + return uniforms; } - setTexture2D( renderTarget.depthTexture, 0 ); + }; - const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; - const samples = getRenderTargetSamples( renderTarget ); + } - if ( renderTarget.depthTexture.format === DepthFormat ) { - if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 36096, 3553, webglDepthTexture, 0, samples ); + let nextVersion = 0; - } else { + function shadowCastingAndTexturingLightsFirst( lightA, lightB ) { - _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); + return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 ); - } + } - } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { + function WebGLLights( extensions, capabilities ) { - if ( useMultisampledRTT( renderTarget ) ) { + const cache = new UniformsCache(); - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 33306, 3553, webglDepthTexture, 0, samples ); + const shadowCache = ShadowUniformsCache(); - } else { + const state = { - _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); + version: 0, - } + hash: { + directionalLength: - 1, + pointLength: - 1, + spotLength: - 1, + rectAreaLength: - 1, + hemiLength: - 1, - } else { + numDirectionalShadows: - 1, + numPointShadows: - 1, + numSpotShadows: - 1, + numSpotMaps: - 1 + }, - throw new Error( 'Unknown depthTexture format' ); + ambient: [ 0, 0, 0 ], + probe: [], + directional: [], + directionalShadow: [], + directionalShadowMap: [], + directionalShadowMatrix: [], + spot: [], + spotLightMap: [], + spotShadow: [], + spotShadowMap: [], + spotLightMatrix: [], + rectArea: [], + rectAreaLTC1: null, + rectAreaLTC2: null, + point: [], + pointShadow: [], + pointShadowMap: [], + pointShadowMatrix: [], + hemi: [], + numSpotLightShadowsWithMaps: 0 - } + }; - } + for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() ); - // Setup GL resources for a non-texture depth buffer - function setupDepthRenderbuffer( renderTarget ) { + const vector3 = new Vector3(); + const matrix4 = new Matrix4(); + const matrix42 = new Matrix4(); - const renderTargetProperties = properties.get( renderTarget ); - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); + function setup( lights, physicallyCorrectLights ) { - if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) { + let r = 0, g = 0, b = 0; - if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); + for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 ); - setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); + let directionalLength = 0; + let pointLength = 0; + let spotLength = 0; + let rectAreaLength = 0; + let hemiLength = 0; - } else { + let numDirectionalShadows = 0; + let numPointShadows = 0; + let numSpotShadows = 0; + let numSpotMaps = 0; + let numSpotShadowsWithMaps = 0; - if ( isCube ) { + // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] + lights.sort( shadowCastingAndTexturingLightsFirst ); - renderTargetProperties.__webglDepthbuffer = []; + // artist-friendly light intensity scaling factor + const scaleFactor = ( physicallyCorrectLights !== true ) ? Math.PI : 1; - for ( let i = 0; i < 6; i ++ ) { + for ( let i = 0, l = lights.length; i < l; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); - renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); + const light = lights[ i ]; - } + const color = light.color; + const intensity = light.intensity; + const distance = light.distance; - } else { + const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); + if ( light.isAmbientLight ) { - } + r += color.r * intensity * scaleFactor; + g += color.g * intensity * scaleFactor; + b += color.b * intensity * scaleFactor; - } + } else if ( light.isLightProbe ) { - state.bindFramebuffer( 36160, null ); + for ( let j = 0; j < 9; j ++ ) { - } + state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); - // rebind framebuffer with external textures - function rebindTextures( renderTarget, colorTexture, depthTexture ) { + } - const renderTargetProperties = properties.get( renderTarget ); + } else if ( light.isDirectionalLight ) { - if ( colorTexture !== undefined ) { + const uniforms = cache.get( light ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, 36064, 3553 ); + uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - } + if ( light.castShadow ) { - if ( depthTexture !== undefined ) { + const shadow = light.shadow; - setupDepthRenderbuffer( renderTarget ); + const shadowUniforms = shadowCache.get( light ); - } + shadowUniforms.shadowBias = shadow.bias; + shadowUniforms.shadowNormalBias = shadow.normalBias; + shadowUniforms.shadowRadius = shadow.radius; + shadowUniforms.shadowMapSize = shadow.mapSize; - } + state.directionalShadow[ directionalLength ] = shadowUniforms; + state.directionalShadowMap[ directionalLength ] = shadowMap; + state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - // Set up GL resources for the render target - function setupRenderTarget( renderTarget ) { + numDirectionalShadows ++; - const texture = renderTarget.texture; + } - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); + state.directional[ directionalLength ] = uniforms; - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + directionalLength ++; - if ( renderTarget.isWebGLMultipleRenderTargets !== true ) { + } else if ( light.isSpotLight ) { - if ( textureProperties.__webglTexture === undefined ) { + const uniforms = cache.get( light ); - textureProperties.__webglTexture = _gl.createTexture(); + uniforms.position.setFromMatrixPosition( light.matrixWorld ); - } + uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor ); + uniforms.distance = distance; - textureProperties.__version = texture.version; - info.memory.textures ++; + uniforms.coneCos = Math.cos( light.angle ); + uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); + uniforms.decay = light.decay; - } + state.spot[ spotLength ] = uniforms; - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; + const shadow = light.shadow; - // Setup framebuffer + if ( light.map ) { - if ( isCube ) { + state.spotLightMap[ numSpotMaps ] = light.map; + numSpotMaps ++; - renderTargetProperties.__webglFramebuffer = []; + // make sure the lightMatrix is up to date + // TODO : do it if required only + shadow.updateMatrices( light ); - for ( let i = 0; i < 6; i ++ ) { + if ( light.castShadow ) numSpotShadowsWithMaps ++; - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + } - } + state.spotLightMatrix[ spotLength ] = shadow.matrix; - } else { + if ( light.castShadow ) { - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + const shadowUniforms = shadowCache.get( light ); - if ( isMultipleRenderTargets ) { + shadowUniforms.shadowBias = shadow.bias; + shadowUniforms.shadowNormalBias = shadow.normalBias; + shadowUniforms.shadowRadius = shadow.radius; + shadowUniforms.shadowMapSize = shadow.mapSize; - if ( capabilities.drawBuffers ) { + state.spotShadow[ spotLength ] = shadowUniforms; + state.spotShadowMap[ spotLength ] = shadowMap; - const textures = renderTarget.texture; + numSpotShadows ++; - for ( let i = 0, il = textures.length; i < il; i ++ ) { + } - const attachmentProperties = properties.get( textures[ i ] ); + spotLength ++; - if ( attachmentProperties.__webglTexture === undefined ) { + } else if ( light.isRectAreaLight ) { - attachmentProperties.__webglTexture = _gl.createTexture(); + const uniforms = cache.get( light ); - info.memory.textures ++; + // (a) intensity is the total visible light emitted + //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) ); - } + // (b) intensity is the brightness of the light + uniforms.color.copy( color ).multiplyScalar( intensity ); - } + uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); + uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - } else { + state.rectArea[ rectAreaLength ] = uniforms; - console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' ); + rectAreaLength ++; - } + } else if ( light.isPointLight ) { - } + const uniforms = cache.get( light ); - if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { + uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); + uniforms.distance = light.distance; + uniforms.decay = light.decay; - const textures = isMultipleRenderTargets ? texture : [ texture ]; + if ( light.castShadow ) { - renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); - renderTargetProperties.__webglColorRenderbuffer = []; + const shadow = light.shadow; - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); + const shadowUniforms = shadowCache.get( light ); - for ( let i = 0; i < textures.length; i ++ ) { + shadowUniforms.shadowBias = shadow.bias; + shadowUniforms.shadowNormalBias = shadow.normalBias; + shadowUniforms.shadowRadius = shadow.radius; + shadowUniforms.shadowMapSize = shadow.mapSize; + shadowUniforms.shadowCameraNear = shadow.camera.near; + shadowUniforms.shadowCameraFar = shadow.camera.far; - const texture = textures[ i ]; - renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); + state.pointShadow[ pointLength ] = shadowUniforms; + state.pointShadowMap[ pointLength ] = shadowMap; + state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + numPointShadows ++; - const glFormat = utils.convert( texture.format, texture.encoding ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, renderTarget.isXRRenderTarget === true ); - const samples = getRenderTargetSamples( renderTarget ); - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + } - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + state.point[ pointLength ] = uniforms; - } + pointLength ++; - _gl.bindRenderbuffer( 36161, null ); + } else if ( light.isHemisphereLight ) { - if ( renderTarget.depthBuffer ) { + const uniforms = cache.get( light ); - renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); + uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor ); + uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor ); - } + state.hemi[ hemiLength ] = uniforms; - state.bindFramebuffer( 36160, null ); + hemiLength ++; } } - // Setup color buffer - - if ( isCube ) { - - state.bindTexture( 34067, textureProperties.__webglTexture ); - setTextureParameters( 34067, texture, supportsMips ); - - for ( let i = 0; i < 6; i ++ ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, 36064, 34069 + i ); - - } + if ( rectAreaLength > 0 ) { - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { + if ( capabilities.isWebGL2 ) { - generateMipmap( 34067 ); + // WebGL 2 - } + state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; + state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - state.unbindTexture(); + } else { - } else if ( isMultipleRenderTargets ) { + // WebGL 1 - const textures = renderTarget.texture; + if ( extensions.has( 'OES_texture_float_linear' ) === true ) { - for ( let i = 0, il = textures.length; i < il; i ++ ) { + state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; + state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - const attachment = textures[ i ]; - const attachmentProperties = properties.get( attachment ); + } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) { - state.bindTexture( 3553, attachmentProperties.__webglTexture ); - setTextureParameters( 3553, attachment, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, 36064 + i, 3553 ); + state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; + state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; - if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { + } else { - generateMipmap( 3553 ); + console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' ); } } - state.unbindTexture(); + } - } else { + state.ambient[ 0 ] = r; + state.ambient[ 1 ] = g; + state.ambient[ 2 ] = b; - let glTextureType = 3553; + const hash = state.hash; - if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { + if ( hash.directionalLength !== directionalLength || + hash.pointLength !== pointLength || + hash.spotLength !== spotLength || + hash.rectAreaLength !== rectAreaLength || + hash.hemiLength !== hemiLength || + hash.numDirectionalShadows !== numDirectionalShadows || + hash.numPointShadows !== numPointShadows || + hash.numSpotShadows !== numSpotShadows || + hash.numSpotMaps !== numSpotMaps ) { - if ( isWebGL2 ) { + state.directional.length = directionalLength; + state.spot.length = spotLength; + state.rectArea.length = rectAreaLength; + state.point.length = pointLength; + state.hemi.length = hemiLength; - glTextureType = renderTarget.isWebGL3DRenderTarget ? 32879 : 35866; + state.directionalShadow.length = numDirectionalShadows; + state.directionalShadowMap.length = numDirectionalShadows; + state.pointShadow.length = numPointShadows; + state.pointShadowMap.length = numPointShadows; + state.spotShadow.length = numSpotShadows; + state.spotShadowMap.length = numSpotShadows; + state.directionalShadowMatrix.length = numDirectionalShadows; + state.pointShadowMatrix.length = numPointShadows; + state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; + state.spotLightMap.length = numSpotMaps; + state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; - } else { + hash.directionalLength = directionalLength; + hash.pointLength = pointLength; + hash.spotLength = spotLength; + hash.rectAreaLength = rectAreaLength; + hash.hemiLength = hemiLength; - console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' ); + hash.numDirectionalShadows = numDirectionalShadows; + hash.numPointShadows = numPointShadows; + hash.numSpotShadows = numSpotShadows; + hash.numSpotMaps = numSpotMaps; - } + state.version = nextVersion ++; - } + } - state.bindTexture( glTextureType, textureProperties.__webglTexture ); - setTextureParameters( glTextureType, texture, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, 36064, glTextureType ); + } - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { + function setupView( lights, camera ) { - generateMipmap( glTextureType ); + let directionalLength = 0; + let pointLength = 0; + let spotLength = 0; + let rectAreaLength = 0; + let hemiLength = 0; - } + const viewMatrix = camera.matrixWorldInverse; - state.unbindTexture(); + for ( let i = 0, l = lights.length; i < l; i ++ ) { - } + const light = lights[ i ]; - // Setup depth and stencil buffers + if ( light.isDirectionalLight ) { - if ( renderTarget.depthBuffer ) { + const uniforms = state.directional[ directionalLength ]; - setupDepthRenderbuffer( renderTarget ); + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + vector3.setFromMatrixPosition( light.target.matrixWorld ); + uniforms.direction.sub( vector3 ); + uniforms.direction.transformDirection( viewMatrix ); - } + directionalLength ++; - } + } else if ( light.isSpotLight ) { - function updateRenderTargetMipmap( renderTarget ) { + const uniforms = state.spot[ spotLength ]; - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); - const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + vector3.setFromMatrixPosition( light.target.matrixWorld ); + uniforms.direction.sub( vector3 ); + uniforms.direction.transformDirection( viewMatrix ); - for ( let i = 0, il = textures.length; i < il; i ++ ) { + spotLength ++; - const texture = textures[ i ]; + } else if ( light.isRectAreaLight ) { - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { + const uniforms = state.rectArea[ rectAreaLength ]; - const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553; - const webglTexture = properties.get( texture ).__webglTexture; + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); - state.bindTexture( target, webglTexture ); - generateMipmap( target ); - state.unbindTexture(); + // extract local rotation of light to derive width/height half vectors + matrix42.identity(); + matrix4.copy( light.matrixWorld ); + matrix4.premultiply( viewMatrix ); + matrix42.extractRotation( matrix4 ); - } + uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); + uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - } + uniforms.halfWidth.applyMatrix4( matrix42 ); + uniforms.halfHeight.applyMatrix4( matrix42 ); - } + rectAreaLength ++; - function updateMultisampleRenderTarget( renderTarget ) { + } else if ( light.isPointLight ) { - if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { + const uniforms = state.point[ pointLength ]; - const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; - const width = renderTarget.width; - const height = renderTarget.height; - let mask = 16384; - const invalidationArray = []; - const depthStyle = renderTarget.stencilBuffer ? 33306 : 36096; - const renderTargetProperties = properties.get( renderTarget ); - const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); - // If MRT we need to remove FBO attachments - if ( isMultipleRenderTargets ) { + pointLength ++; - for ( let i = 0; i < textures.length; i ++ ) { + } else if ( light.isHemisphereLight ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, null ); + const uniforms = state.hemi[ hemiLength ]; - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, null, 0 ); + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + uniforms.direction.transformDirection( viewMatrix ); - } + hemiLength ++; } - state.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer ); - state.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer ); + } - for ( let i = 0; i < textures.length; i ++ ) { + } - invalidationArray.push( 36064 + i ); + return { + setup: setup, + setupView: setupView, + state: state + }; - if ( renderTarget.depthBuffer ) { + } - invalidationArray.push( depthStyle ); + function WebGLRenderState( extensions, capabilities ) { - } + const lights = new WebGLLights( extensions, capabilities ); - const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false; + const lightsArray = []; + const shadowsArray = []; - if ( ignoreDepthValues === false ) { + function init() { - if ( renderTarget.depthBuffer ) mask |= 256; - if ( renderTarget.stencilBuffer ) mask |= 1024; + lightsArray.length = 0; + shadowsArray.length = 0; - } + } - if ( isMultipleRenderTargets ) { + function pushLight( light ) { - _gl.framebufferRenderbuffer( 36008, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + lightsArray.push( light ); - } + } - if ( ignoreDepthValues === true ) { + function pushShadow( shadowLight ) { - _gl.invalidateFramebuffer( 36008, [ depthStyle ] ); - _gl.invalidateFramebuffer( 36009, [ depthStyle ] ); + shadowsArray.push( shadowLight ); - } + } - if ( isMultipleRenderTargets ) { + function setupLights( physicallyCorrectLights ) { - const webglTexture = properties.get( textures[ i ] ).__webglTexture; - _gl.framebufferTexture2D( 36009, 36064, 3553, webglTexture, 0 ); + lights.setup( lightsArray, physicallyCorrectLights ); - } + } - _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 ); + function setupLightsView( camera ) { - if ( supportsInvalidateFramebuffer ) { + lights.setupView( lightsArray, camera ); - _gl.invalidateFramebuffer( 36008, invalidationArray ); + } - } + const state = { + lightsArray: lightsArray, + shadowsArray: shadowsArray, + lights: lights + }; - } + return { + init: init, + state: state, + setupLights: setupLights, + setupLightsView: setupLightsView, - state.bindFramebuffer( 36008, null ); - state.bindFramebuffer( 36009, null ); + pushLight: pushLight, + pushShadow: pushShadow + }; - // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments - if ( isMultipleRenderTargets ) { + } - for ( let i = 0; i < textures.length; i ++ ) { + function WebGLRenderStates( extensions, capabilities ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + let renderStates = new WeakMap(); - const webglTexture = properties.get( textures[ i ] ).__webglTexture; + function get( scene, renderCallDepth = 0 ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, webglTexture, 0 ); + const renderStateArray = renderStates.get( scene ); + let renderState; - } + if ( renderStateArray === undefined ) { - } + renderState = new WebGLRenderState( extensions, capabilities ); + renderStates.set( scene, [ renderState ] ); - state.bindFramebuffer( 36009, renderTargetProperties.__webglMultisampledFramebuffer ); + } else { - } + if ( renderCallDepth >= renderStateArray.length ) { - } + renderState = new WebGLRenderState( extensions, capabilities ); + renderStateArray.push( renderState ); - function getRenderTargetSamples( renderTarget ) { + } else { - return Math.min( maxSamples, renderTarget.samples ); + renderState = renderStateArray[ renderCallDepth ]; - } + } - function useMultisampledRTT( renderTarget ) { + } - const renderTargetProperties = properties.get( renderTarget ); + return renderState; - return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false; + } + + function dispose() { + + renderStates = new WeakMap(); } - function updateVideoTexture( texture ) { + return { + get: get, + dispose: dispose + }; - const frame = info.render.frame; + } - // Check the last frame we updated the VideoTexture + class MeshDepthMaterial extends Material { - if ( _videoTextures.get( texture ) !== frame ) { + constructor( parameters ) { - _videoTextures.set( texture, frame ); - texture.update(); + super(); - } + this.isMeshDepthMaterial = true; - } + this.type = 'MeshDepthMaterial'; - function verifyColorSpace( texture, image ) { + this.depthPacking = BasicDepthPacking; - const encoding = texture.encoding; - const format = texture.format; - const type = texture.type; + this.map = null; - if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; + this.alphaMap = null; - if ( encoding !== LinearEncoding ) { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - // sRGB + this.wireframe = false; + this.wireframeLinewidth = 1; - if ( encoding === sRGBEncoding ) { + this.setValues( parameters ); - if ( isWebGL2 === false ) { + } - // in WebGL 1, try to use EXT_sRGB extension and unsized formats + copy( source ) { - if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) { + super.copy( source ); - texture.format = _SRGBAFormat; + this.depthPacking = source.depthPacking; - // it's not possible to generate mips in WebGL 1 with this extension + this.map = source.map; - texture.minFilter = LinearFilter; - texture.generateMipmaps = false; + this.alphaMap = source.alphaMap; - } else { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - // slow fallback (CPU decode) + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - image = ImageUtils.sRGBToLinear( image ); + return this; - } + } - } else { + } - // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format + class MeshDistanceMaterial extends Material { - if ( format !== RGBAFormat || type !== UnsignedByteType ) { + constructor( parameters ) { - console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' ); + super(); - } + this.isMeshDistanceMaterial = true; - } + this.type = 'MeshDistanceMaterial'; - } else { + this.referencePosition = new Vector3(); + this.nearDistance = 1; + this.farDistance = 1000; - console.error( 'THREE.WebGLTextures: Unsupported texture encoding:', encoding ); + this.map = null; - } + this.alphaMap = null; - } + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - return image; + this.setValues( parameters ); } - // - - this.allocateTextureUnit = allocateTextureUnit; - this.resetTextureUnits = resetTextureUnits; + copy( source ) { - this.setTexture2D = setTexture2D; - this.setTexture2DArray = setTexture2DArray; - this.setTexture3D = setTexture3D; - this.setTextureCube = setTextureCube; - this.rebindTextures = rebindTextures; - this.setupRenderTarget = setupRenderTarget; - this.updateRenderTargetMipmap = updateRenderTargetMipmap; - this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; - this.setupDepthRenderbuffer = setupDepthRenderbuffer; - this.setupFrameBufferTexture = setupFrameBufferTexture; - this.useMultisampledRTT = useMultisampledRTT; + super.copy( source ); - } + this.referencePosition.copy( source.referencePosition ); + this.nearDistance = source.nearDistance; + this.farDistance = source.farDistance; - function WebGLUtils( gl, extensions, capabilities ) { + this.map = source.map; - const isWebGL2 = capabilities.isWebGL2; + this.alphaMap = source.alphaMap; - function convert( p, encoding = null ) { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - let extension; + return this; - if ( p === UnsignedByteType ) return 5121; - if ( p === UnsignedShort4444Type ) return 32819; - if ( p === UnsignedShort5551Type ) return 32820; + } - if ( p === ByteType ) return 5120; - if ( p === ShortType ) return 5122; - if ( p === UnsignedShortType ) return 5123; - if ( p === IntType ) return 5124; - if ( p === UnsignedIntType ) return 5125; - if ( p === FloatType ) return 5126; + } - if ( p === HalfFloatType ) { + const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; - if ( isWebGL2 ) return 5131; + const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; - extension = extensions.get( 'OES_texture_half_float' ); + function WebGLShadowMap( _renderer, _objects, _capabilities ) { - if ( extension !== null ) { + let _frustum = new Frustum(); - return extension.HALF_FLOAT_OES; + const _shadowMapSize = new Vector2(), + _viewportSize = new Vector2(), - } else { + _viewport = new Vector4(), - return null; + _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ), + _distanceMaterial = new MeshDistanceMaterial(), - } + _materialCache = {}, - } + _maxTextureSize = _capabilities.maxTextureSize; - if ( p === AlphaFormat ) return 6406; - if ( p === RGBAFormat ) return 6408; - if ( p === LuminanceFormat ) return 6409; - if ( p === LuminanceAlphaFormat ) return 6410; - if ( p === DepthFormat ) return 6402; - if ( p === DepthStencilFormat ) return 34041; - if ( p === RedFormat ) return 6403; + const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; - // @deprecated since r137 + const shadowMaterialVertical = new ShaderMaterial( { + defines: { + VSM_SAMPLES: 8 + }, + uniforms: { + shadow_pass: { value: null }, + resolution: { value: new Vector2() }, + radius: { value: 4.0 } + }, - if ( p === RGBFormat ) { + vertexShader: vertex, + fragmentShader: fragment - console.warn( 'THREE.WebGLRenderer: THREE.RGBFormat has been removed. Use THREE.RGBAFormat instead. https://github.com/mrdoob/three.js/pull/23228' ); - return 6408; + } ); - } + const shadowMaterialHorizontal = shadowMaterialVertical.clone(); + shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; - // WebGL 1 sRGB fallback + const fullScreenTri = new BufferGeometry(); + fullScreenTri.setAttribute( + 'position', + new BufferAttribute( + new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ), + 3 + ) + ); - if ( p === _SRGBAFormat ) { + const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); - extension = extensions.get( 'EXT_sRGB' ); + const scope = this; - if ( extension !== null ) { + this.enabled = false; - return extension.SRGB_ALPHA_EXT; + this.autoUpdate = true; + this.needsUpdate = false; - } else { + this.type = PCFShadowMap; - return null; + this.render = function ( lights, scene, camera ) { - } + if ( scope.enabled === false ) return; + if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - } + if ( lights.length === 0 ) return; - // WebGL2 formats. + const currentRenderTarget = _renderer.getRenderTarget(); + const activeCubeFace = _renderer.getActiveCubeFace(); + const activeMipmapLevel = _renderer.getActiveMipmapLevel(); - if ( p === RedIntegerFormat ) return 36244; - if ( p === RGFormat ) return 33319; - if ( p === RGIntegerFormat ) return 33320; - if ( p === RGBAIntegerFormat ) return 36249; + const _state = _renderer.state; - // S3TC + // Set GL state for depth map. + _state.setBlending( NoBlending ); + _state.buffers.color.setClear( 1, 1, 1, 1 ); + _state.buffers.depth.setTest( true ); + _state.setScissorTest( false ); - if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { + // render depth map - if ( encoding === sRGBEncoding ) { + for ( let i = 0, il = lights.length; i < il; i ++ ) { - extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); + const light = lights[ i ]; + const shadow = light.shadow; - if ( extension !== null ) { + if ( shadow === undefined ) { - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); + continue; - } else { + } - return null; + if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue; - } + _shadowMapSize.copy( shadow.mapSize ); - } else { + const shadowFrameExtents = shadow.getFrameExtents(); - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); + _shadowMapSize.multiply( shadowFrameExtents ); - if ( extension !== null ) { + _viewportSize.copy( shadow.mapSize ); - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; + if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) { - } else { + if ( _shadowMapSize.x > _maxTextureSize ) { - return null; + _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x ); + _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; + shadow.mapSize.x = _viewportSize.x; } - } - - } + if ( _shadowMapSize.y > _maxTextureSize ) { - // PVRTC + _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y ); + _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; + shadow.mapSize.y = _viewportSize.y; - if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { + } - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + } - if ( extension !== null ) { + if ( shadow.map === null ) { - if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; - } else { + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); + shadow.map.texture.name = light.name + '.shadowMap'; - return null; + shadow.camera.updateProjectionMatrix(); } - } + _renderer.setRenderTarget( shadow.map ); + _renderer.clear(); - // ETC1 + const viewportCount = shadow.getViewportCount(); - if ( p === RGB_ETC1_Format ) { + for ( let vp = 0; vp < viewportCount; vp ++ ) { - extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); + const viewport = shadow.getViewport( vp ); - if ( extension !== null ) { + _viewport.set( + _viewportSize.x * viewport.x, + _viewportSize.y * viewport.y, + _viewportSize.x * viewport.z, + _viewportSize.y * viewport.w + ); - return extension.COMPRESSED_RGB_ETC1_WEBGL; + _state.viewport( _viewport ); - } else { + shadow.updateMatrices( light, vp ); - return null; + _frustum = shadow.getFrustum(); + + renderObject( scene, camera, shadow.camera, light, this.type ); } - } + // do blur pass for VSM - // ETC2 - - if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc' ); - - if ( extension !== null ) { - - if ( p === RGB_ETC2_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; - if ( p === RGBA_ETC2_EAC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; - - } else { + if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) { - return null; + VSMPass( shadow, camera ); } + shadow.needsUpdate = false; + } - // ASTC + scope.needsUpdate = false; - if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || - p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || - p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || - p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || - p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) { + _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); - extension = extensions.get( 'WEBGL_compressed_texture_astc' ); + }; - if ( extension !== null ) { + function VSMPass( shadow, camera ) { - if ( p === RGBA_ASTC_4x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; - if ( p === RGBA_ASTC_5x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; - if ( p === RGBA_ASTC_5x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; - if ( p === RGBA_ASTC_6x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; - if ( p === RGBA_ASTC_6x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; - if ( p === RGBA_ASTC_8x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; - if ( p === RGBA_ASTC_8x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; - if ( p === RGBA_ASTC_8x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; - if ( p === RGBA_ASTC_10x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; - if ( p === RGBA_ASTC_10x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; - if ( p === RGBA_ASTC_10x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; - if ( p === RGBA_ASTC_10x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; - if ( p === RGBA_ASTC_12x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; - if ( p === RGBA_ASTC_12x12_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; + const geometry = _objects.update( fullScreenMesh ); - } else { + if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) { - return null; + shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; + shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; - } + shadowMaterialVertical.needsUpdate = true; + shadowMaterialHorizontal.needsUpdate = true; } - // BPTC - - if ( p === RGBA_BPTC_Format ) { - - extension = extensions.get( 'EXT_texture_compression_bptc' ); - - if ( extension !== null ) { - - if ( p === RGBA_BPTC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; - - } else { - - return null; + if ( shadow.mapPass === null ) { - } + shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y ); } - // + // vertical pass - if ( p === UnsignedInt248Type ) { + shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; + shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; + shadowMaterialVertical.uniforms.radius.value = shadow.radius; + _renderer.setRenderTarget( shadow.mapPass ); + _renderer.clear(); + _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); - if ( isWebGL2 ) return 34042; + // horizontal pass - extension = extensions.get( 'WEBGL_depth_texture' ); + shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; + shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; + shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; + _renderer.setRenderTarget( shadow.map ); + _renderer.clear(); + _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null ); - if ( extension !== null ) { + } - return extension.UNSIGNED_INT_24_8_WEBGL; + function getDepthMaterial( object, material, light, shadowCameraNear, shadowCameraFar, type ) { - } else { + let result = null; - return null; + const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial; - } + if ( customMaterial !== undefined ) { - } + result = customMaterial; - // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) + } else { - return ( gl[ p ] !== undefined ) ? gl[ p ] : null; + result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; - } + } - return { convert: convert }; + if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || + ( material.displacementMap && material.displacementScale !== 0 ) || + ( material.alphaMap && material.alphaTest > 0 ) ) { - } + // in this case we need a unique material instance reflecting the + // appropriate state - class ArrayCamera extends PerspectiveCamera { + const keyA = result.uuid, keyB = material.uuid; - constructor( array = [] ) { + let materialsForVariant = _materialCache[ keyA ]; - super(); + if ( materialsForVariant === undefined ) { - this.isArrayCamera = true; + materialsForVariant = {}; + _materialCache[ keyA ] = materialsForVariant; - this.cameras = array; + } - } + let cachedMaterial = materialsForVariant[ keyB ]; - } + if ( cachedMaterial === undefined ) { - class Group extends Object3D { + cachedMaterial = result.clone(); + materialsForVariant[ keyB ] = cachedMaterial; - constructor() { + } - super(); + result = cachedMaterial; - this.isGroup = true; + } - this.type = 'Group'; + result.visible = material.visible; + result.wireframe = material.wireframe; - } + if ( type === VSMShadowMap ) { - } + result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; - const _moveEvent = { type: 'move' }; + } else { - class WebXRController { + result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; - constructor() { + } - this._targetRay = null; - this._grip = null; - this._hand = null; + result.alphaMap = material.alphaMap; + result.alphaTest = material.alphaTest; - } + result.clipShadows = material.clipShadows; + result.clippingPlanes = material.clippingPlanes; + result.clipIntersection = material.clipIntersection; - getHandSpace() { + result.displacementMap = material.displacementMap; + result.displacementScale = material.displacementScale; + result.displacementBias = material.displacementBias; - if ( this._hand === null ) { + result.wireframeLinewidth = material.wireframeLinewidth; + result.linewidth = material.linewidth; - this._hand = new Group(); - this._hand.matrixAutoUpdate = false; - this._hand.visible = false; + if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { - this._hand.joints = {}; - this._hand.inputState = { pinching: false }; + result.referencePosition.setFromMatrixPosition( light.matrixWorld ); + result.nearDistance = shadowCameraNear; + result.farDistance = shadowCameraFar; } - return this._hand; + return result; } - getTargetRaySpace() { + function renderObject( object, camera, shadowCamera, light, type ) { - if ( this._targetRay === null ) { + if ( object.visible === false ) return; - this._targetRay = new Group(); - this._targetRay.matrixAutoUpdate = false; - this._targetRay.visible = false; - this._targetRay.hasLinearVelocity = false; - this._targetRay.linearVelocity = new Vector3(); - this._targetRay.hasAngularVelocity = false; - this._targetRay.angularVelocity = new Vector3(); + const visible = object.layers.test( camera.layers ); - } + if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - return this._targetRay; + if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { - } + object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - getGripSpace() { + const geometry = _objects.update( object ); + const material = object.material; - if ( this._grip === null ) { + if ( Array.isArray( material ) ) { - this._grip = new Group(); - this._grip.matrixAutoUpdate = false; - this._grip.visible = false; - this._grip.hasLinearVelocity = false; - this._grip.linearVelocity = new Vector3(); - this._grip.hasAngularVelocity = false; - this._grip.angularVelocity = new Vector3(); + const groups = geometry.groups; - } + for ( let k = 0, kl = groups.length; k < kl; k ++ ) { - return this._grip; + const group = groups[ k ]; + const groupMaterial = material[ group.materialIndex ]; - } + if ( groupMaterial && groupMaterial.visible ) { - dispatchEvent( event ) { + const depthMaterial = getDepthMaterial( object, groupMaterial, light, shadowCamera.near, shadowCamera.far, type ); - if ( this._targetRay !== null ) { + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); - this._targetRay.dispatchEvent( event ); + } - } + } - if ( this._grip !== null ) { + } else if ( material.visible ) { - this._grip.dispatchEvent( event ); + const depthMaterial = getDepthMaterial( object, material, light, shadowCamera.near, shadowCamera.far, type ); - } + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); - if ( this._hand !== null ) { + } - this._hand.dispatchEvent( event ); + } } - return this; - - } - - disconnect( inputSource ) { - - this.dispatchEvent( { type: 'disconnected', data: inputSource } ); + const children = object.children; - if ( this._targetRay !== null ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - this._targetRay.visible = false; + renderObject( children[ i ], camera, shadowCamera, light, type ); } - if ( this._grip !== null ) { - - this._grip.visible = false; + } - } + } - if ( this._hand !== null ) { + function WebGLState( gl, extensions, capabilities ) { - this._hand.visible = false; + const isWebGL2 = capabilities.isWebGL2; - } + function ColorBuffer() { - return this; + let locked = false; - } + const color = new Vector4(); + let currentColorMask = null; + const currentColorClear = new Vector4( 0, 0, 0, 0 ); - update( inputSource, frame, referenceSpace ) { + return { - let inputPose = null; - let gripPose = null; - let handPose = null; + setMask: function ( colorMask ) { - const targetRay = this._targetRay; - const grip = this._grip; - const hand = this._hand; + if ( currentColorMask !== colorMask && ! locked ) { - if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) { + gl.colorMask( colorMask, colorMask, colorMask, colorMask ); + currentColorMask = colorMask; - if ( hand && inputSource.hand ) { + } - handPose = true; + }, - for ( const inputjoint of inputSource.hand.values() ) { + setLocked: function ( lock ) { - // Update the joints groups with the XRJoint poses - const jointPose = frame.getJointPose( inputjoint, referenceSpace ); + locked = lock; - if ( hand.joints[ inputjoint.jointName ] === undefined ) { + }, - // The transform of this joint will be updated with the joint pose on each frame - const joint = new Group(); - joint.matrixAutoUpdate = false; - joint.visible = false; - hand.joints[ inputjoint.jointName ] = joint; - // ?? - hand.add( joint ); + setClear: function ( r, g, b, a, premultipliedAlpha ) { - } + if ( premultipliedAlpha === true ) { - const joint = hand.joints[ inputjoint.jointName ]; + r *= a; g *= a; b *= a; - if ( jointPose !== null ) { + } - joint.matrix.fromArray( jointPose.transform.matrix ); - joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); - joint.jointRadius = jointPose.radius; + color.set( r, g, b, a ); - } + if ( currentColorClear.equals( color ) === false ) { - joint.visible = jointPose !== null; + gl.clearColor( r, g, b, a ); + currentColorClear.copy( color ); } - // Custom events + }, - // Check pinchz - const indexTip = hand.joints[ 'index-finger-tip' ]; - const thumbTip = hand.joints[ 'thumb-tip' ]; - const distance = indexTip.position.distanceTo( thumbTip.position ); + reset: function () { - const distanceToPinch = 0.02; - const threshold = 0.005; + locked = false; - if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { + currentColorMask = null; + currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state - hand.inputState.pinching = false; - this.dispatchEvent( { - type: 'pinchend', - handedness: inputSource.handedness, - target: this - } ); + } - } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { + }; - hand.inputState.pinching = true; - this.dispatchEvent( { - type: 'pinchstart', - handedness: inputSource.handedness, - target: this - } ); + } - } + function DepthBuffer() { - } else { + let locked = false; - if ( grip !== null && inputSource.gripSpace ) { + let currentDepthMask = null; + let currentDepthFunc = null; + let currentDepthClear = null; - gripPose = frame.getPose( inputSource.gripSpace, referenceSpace ); + return { - if ( gripPose !== null ) { + setTest: function ( depthTest ) { - grip.matrix.fromArray( gripPose.transform.matrix ); - grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); + if ( depthTest ) { - if ( gripPose.linearVelocity ) { + enable( 2929 ); - grip.hasLinearVelocity = true; - grip.linearVelocity.copy( gripPose.linearVelocity ); + } else { - } else { + disable( 2929 ); - grip.hasLinearVelocity = false; + } - } + }, - if ( gripPose.angularVelocity ) { + setMask: function ( depthMask ) { - grip.hasAngularVelocity = true; - grip.angularVelocity.copy( gripPose.angularVelocity ); + if ( currentDepthMask !== depthMask && ! locked ) { - } else { + gl.depthMask( depthMask ); + currentDepthMask = depthMask; - grip.hasAngularVelocity = false; + } - } + }, - } + setFunc: function ( depthFunc ) { - } + if ( currentDepthFunc !== depthFunc ) { - } + switch ( depthFunc ) { - if ( targetRay !== null ) { + case NeverDepth: - inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); + gl.depthFunc( 512 ); + break; - // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it - if ( inputPose === null && gripPose !== null ) { + case AlwaysDepth: - inputPose = gripPose; + gl.depthFunc( 519 ); + break; - } + case LessDepth: - if ( inputPose !== null ) { + gl.depthFunc( 513 ); + break; - targetRay.matrix.fromArray( inputPose.transform.matrix ); - targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); + case LessEqualDepth: - if ( inputPose.linearVelocity ) { + gl.depthFunc( 515 ); + break; - targetRay.hasLinearVelocity = true; - targetRay.linearVelocity.copy( inputPose.linearVelocity ); + case EqualDepth: - } else { + gl.depthFunc( 514 ); + break; - targetRay.hasLinearVelocity = false; + case GreaterEqualDepth: - } + gl.depthFunc( 518 ); + break; - if ( inputPose.angularVelocity ) { + case GreaterDepth: - targetRay.hasAngularVelocity = true; - targetRay.angularVelocity.copy( inputPose.angularVelocity ); + gl.depthFunc( 516 ); + break; - } else { + case NotEqualDepth: - targetRay.hasAngularVelocity = false; + gl.depthFunc( 517 ); + break; + + default: + + gl.depthFunc( 515 ); } - this.dispatchEvent( _moveEvent ); + currentDepthFunc = depthFunc; } - } + }, + setLocked: function ( lock ) { - } + locked = lock; - if ( targetRay !== null ) { + }, - targetRay.visible = ( inputPose !== null ); + setClear: function ( depth ) { - } + if ( currentDepthClear !== depth ) { - if ( grip !== null ) { + gl.clearDepth( depth ); + currentDepthClear = depth; - grip.visible = ( gripPose !== null ); + } - } + }, - if ( hand !== null ) { + reset: function () { - hand.visible = ( handPose !== null ); + locked = false; - } + currentDepthMask = null; + currentDepthFunc = null; + currentDepthClear = null; - return this; + } + + }; } - } + function StencilBuffer() { - class DepthTexture extends Texture { + let locked = false; - constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { + let currentStencilMask = null; + let currentStencilFunc = null; + let currentStencilRef = null; + let currentStencilFuncMask = null; + let currentStencilFail = null; + let currentStencilZFail = null; + let currentStencilZPass = null; + let currentStencilClear = null; - format = format !== undefined ? format : DepthFormat; + return { - if ( format !== DepthFormat && format !== DepthStencilFormat ) { + setTest: function ( stencilTest ) { - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); + if ( ! locked ) { - } + if ( stencilTest ) { - if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + enable( 2960 ); - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + } else { - this.isDepthTexture = true; + disable( 2960 ); - this.image = { width: width, height: height }; + } - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + } - this.flipY = false; - this.generateMipmaps = false; + }, - } + setMask: function ( stencilMask ) { + if ( currentStencilMask !== stencilMask && ! locked ) { - } + gl.stencilMask( stencilMask ); + currentStencilMask = stencilMask; - class WebXRManager extends EventDispatcher { + } - constructor( renderer, gl ) { + }, - super(); + setFunc: function ( stencilFunc, stencilRef, stencilMask ) { - const scope = this; + if ( currentStencilFunc !== stencilFunc || + currentStencilRef !== stencilRef || + currentStencilFuncMask !== stencilMask ) { - let session = null; - let framebufferScaleFactor = 1.0; + gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); - let referenceSpace = null; - let referenceSpaceType = 'local-floor'; - let customReferenceSpace = null; + currentStencilFunc = stencilFunc; + currentStencilRef = stencilRef; + currentStencilFuncMask = stencilMask; - let pose = null; - let glBinding = null; - let glProjLayer = null; - let glBaseLayer = null; - let xrFrame = null; - const attributes = gl.getContextAttributes(); - let initialRenderTarget = null; - let newRenderTarget = null; + } - const controllers = []; - const controllerInputSources = []; + }, - // + setOp: function ( stencilFail, stencilZFail, stencilZPass ) { - const cameraL = new PerspectiveCamera(); - cameraL.layers.enable( 1 ); - cameraL.viewport = new Vector4(); + if ( currentStencilFail !== stencilFail || + currentStencilZFail !== stencilZFail || + currentStencilZPass !== stencilZPass ) { - const cameraR = new PerspectiveCamera(); - cameraR.layers.enable( 2 ); - cameraR.viewport = new Vector4(); + gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); - const cameras = [ cameraL, cameraR ]; + currentStencilFail = stencilFail; + currentStencilZFail = stencilZFail; + currentStencilZPass = stencilZPass; - const cameraVR = new ArrayCamera(); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); + } - let _currentDepthNear = null; - let _currentDepthFar = null; + }, - // + setLocked: function ( lock ) { - this.cameraAutoUpdate = true; - this.enabled = false; + locked = lock; - this.isPresenting = false; + }, - this.getController = function ( index ) { + setClear: function ( stencil ) { - let controller = controllers[ index ]; + if ( currentStencilClear !== stencil ) { - if ( controller === undefined ) { + gl.clearStencil( stencil ); + currentStencilClear = stencil; - controller = new WebXRController(); - controllers[ index ] = controller; + } - } + }, - return controller.getTargetRaySpace(); + reset: function () { - }; + locked = false; - this.getControllerGrip = function ( index ) { + currentStencilMask = null; + currentStencilFunc = null; + currentStencilRef = null; + currentStencilFuncMask = null; + currentStencilFail = null; + currentStencilZFail = null; + currentStencilZPass = null; + currentStencilClear = null; - let controller = controllers[ index ]; + } - if ( controller === undefined ) { + }; - controller = new WebXRController(); - controllers[ index ] = controller; + } - } + // - return controller.getGripSpace(); + const colorBuffer = new ColorBuffer(); + const depthBuffer = new DepthBuffer(); + const stencilBuffer = new StencilBuffer(); - }; + const uboBindings = new WeakMap(); + const uboProgamMap = new WeakMap(); - this.getHand = function ( index ) { + let enabledCapabilities = {}; - let controller = controllers[ index ]; + let currentBoundFramebuffers = {}; + let currentDrawbuffers = new WeakMap(); + let defaultDrawbuffers = []; - if ( controller === undefined ) { + let currentProgram = null; - controller = new WebXRController(); - controllers[ index ] = controller; + let currentBlendingEnabled = false; + let currentBlending = null; + let currentBlendEquation = null; + let currentBlendSrc = null; + let currentBlendDst = null; + let currentBlendEquationAlpha = null; + let currentBlendSrcAlpha = null; + let currentBlendDstAlpha = null; + let currentPremultipledAlpha = false; - } + let currentFlipSided = null; + let currentCullFace = null; - return controller.getHandSpace(); + let currentLineWidth = null; - }; + let currentPolygonOffsetFactor = null; + let currentPolygonOffsetUnits = null; - // + const maxTextures = gl.getParameter( 35661 ); - function onSessionEvent( event ) { + let lineWidthAvailable = false; + let version = 0; + const glVersion = gl.getParameter( 7938 ); - const controllerIndex = controllerInputSources.indexOf( event.inputSource ); + if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { - if ( controllerIndex === - 1 ) { + version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] ); + lineWidthAvailable = ( version >= 1.0 ); - return; + } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { - } + version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] ); + lineWidthAvailable = ( version >= 2.0 ); - const controller = controllers[ controllerIndex ]; + } - if ( controller !== undefined ) { + let currentTextureSlot = null; + let currentBoundTextures = {}; - controller.dispatchEvent( { type: event.type, data: event.inputSource } ); + const scissorParam = gl.getParameter( 3088 ); + const viewportParam = gl.getParameter( 2978 ); - } + const currentScissor = new Vector4().fromArray( scissorParam ); + const currentViewport = new Vector4().fromArray( viewportParam ); - } + function createTexture( type, target, count ) { - function onSessionEnd() { + const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. + const texture = gl.createTexture(); - session.removeEventListener( 'select', onSessionEvent ); - session.removeEventListener( 'selectstart', onSessionEvent ); - session.removeEventListener( 'selectend', onSessionEvent ); - session.removeEventListener( 'squeeze', onSessionEvent ); - session.removeEventListener( 'squeezestart', onSessionEvent ); - session.removeEventListener( 'squeezeend', onSessionEvent ); - session.removeEventListener( 'end', onSessionEnd ); - session.removeEventListener( 'inputsourceschange', onInputSourcesChange ); + gl.bindTexture( type, texture ); + gl.texParameteri( type, 10241, 9728 ); + gl.texParameteri( type, 10240, 9728 ); - for ( let i = 0; i < controllers.length; i ++ ) { + for ( let i = 0; i < count; i ++ ) { - const inputSource = controllerInputSources[ i ]; + gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); - if ( inputSource === null ) continue; + } - controllerInputSources[ i ] = null; + return texture; - controllers[ i ].disconnect( inputSource ); + } - } + const emptyTextures = {}; + emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); + emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); - _currentDepthNear = null; - _currentDepthFar = null; + // init - // restore framebuffer/rendering state + colorBuffer.setClear( 0, 0, 0, 1 ); + depthBuffer.setClear( 1 ); + stencilBuffer.setClear( 0 ); - renderer.setRenderTarget( initialRenderTarget ); + enable( 2929 ); + depthBuffer.setFunc( LessEqualDepth ); - glBaseLayer = null; - glProjLayer = null; - glBinding = null; - session = null; - newRenderTarget = null; + setFlipSided( false ); + setCullFace( CullFaceBack ); + enable( 2884 ); - // + setBlending( NoBlending ); - animation.stop(); + // - scope.isPresenting = false; + function enable( id ) { - scope.dispatchEvent( { type: 'sessionend' } ); + if ( enabledCapabilities[ id ] !== true ) { + + gl.enable( id ); + enabledCapabilities[ id ] = true; } - this.setFramebufferScaleFactor = function ( value ) { + } - framebufferScaleFactor = value; + function disable( id ) { - if ( scope.isPresenting === true ) { + if ( enabledCapabilities[ id ] !== false ) { - console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); + gl.disable( id ); + enabledCapabilities[ id ] = false; - } + } - }; + } - this.setReferenceSpaceType = function ( value ) { + function bindFramebuffer( target, framebuffer ) { - referenceSpaceType = value; + if ( currentBoundFramebuffers[ target ] !== framebuffer ) { - if ( scope.isPresenting === true ) { + gl.bindFramebuffer( target, framebuffer ); - console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); + currentBoundFramebuffers[ target ] = framebuffer; - } + if ( isWebGL2 ) { - }; + // 36009 is equivalent to 36160 - this.getReferenceSpace = function () { + if ( target === 36009 ) { - return customReferenceSpace || referenceSpace; + currentBoundFramebuffers[ 36160 ] = framebuffer; - }; + } - this.setReferenceSpace = function ( space ) { + if ( target === 36160 ) { - customReferenceSpace = space; + currentBoundFramebuffers[ 36009 ] = framebuffer; - }; + } - this.getBaseLayer = function () { + } - return glProjLayer !== null ? glProjLayer : glBaseLayer; + return true; - }; + } - this.getBinding = function () { + return false; - return glBinding; + } - }; + function drawBuffers( renderTarget, framebuffer ) { - this.getFrame = function () { + let drawBuffers = defaultDrawbuffers; - return xrFrame; + let needsUpdate = false; - }; + if ( renderTarget ) { - this.getSession = function () { + drawBuffers = currentDrawbuffers.get( framebuffer ); - return session; + if ( drawBuffers === undefined ) { - }; + drawBuffers = []; + currentDrawbuffers.set( framebuffer, drawBuffers ); - this.setSession = async function ( value ) { + } - session = value; + if ( renderTarget.isWebGLMultipleRenderTargets ) { - if ( session !== null ) { + const textures = renderTarget.texture; - initialRenderTarget = renderer.getRenderTarget(); + if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== 36064 ) { - session.addEventListener( 'select', onSessionEvent ); - session.addEventListener( 'selectstart', onSessionEvent ); - session.addEventListener( 'selectend', onSessionEvent ); - session.addEventListener( 'squeeze', onSessionEvent ); - session.addEventListener( 'squeezestart', onSessionEvent ); - session.addEventListener( 'squeezeend', onSessionEvent ); - session.addEventListener( 'end', onSessionEnd ); - session.addEventListener( 'inputsourceschange', onInputSourcesChange ); + for ( let i = 0, il = textures.length; i < il; i ++ ) { - if ( attributes.xrCompatible !== true ) { + drawBuffers[ i ] = 36064 + i; - await gl.makeXRCompatible(); + } + + drawBuffers.length = textures.length; + + needsUpdate = true; } - if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { + } else { - const layerInit = { - antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, - alpha: attributes.alpha, - depth: attributes.depth, - stencil: attributes.stencil, - framebufferScaleFactor: framebufferScaleFactor - }; + if ( drawBuffers[ 0 ] !== 36064 ) { - glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); + drawBuffers[ 0 ] = 36064; - session.updateRenderState( { baseLayer: glBaseLayer } ); + needsUpdate = true; - newRenderTarget = new WebGLRenderTarget( - glBaseLayer.framebufferWidth, - glBaseLayer.framebufferHeight, - { - format: RGBAFormat, - type: UnsignedByteType, - encoding: renderer.outputEncoding, - stencilBuffer: attributes.stencil - } - ); + } - } else { + } - let depthFormat = null; - let depthType = null; - let glDepthFormat = null; + } else { - if ( attributes.depth ) { + if ( drawBuffers[ 0 ] !== 1029 ) { - glDepthFormat = attributes.stencil ? 35056 : 33190; - depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; - depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; + drawBuffers[ 0 ] = 1029; - } + needsUpdate = true; - const projectionlayerInit = { - colorFormat: 32856, - depthFormat: glDepthFormat, - scaleFactor: framebufferScaleFactor - }; + } - glBinding = new XRWebGLBinding( session, gl ); + } - glProjLayer = glBinding.createProjectionLayer( projectionlayerInit ); + if ( needsUpdate ) { - session.updateRenderState( { layers: [ glProjLayer ] } ); + if ( capabilities.isWebGL2 ) { - newRenderTarget = new WebGLRenderTarget( - glProjLayer.textureWidth, - glProjLayer.textureHeight, - { - format: RGBAFormat, - type: UnsignedByteType, - depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), - stencilBuffer: attributes.stencil, - encoding: renderer.outputEncoding, - samples: attributes.antialias ? 4 : 0 - } ); + gl.drawBuffers( drawBuffers ); - const renderTargetProperties = renderer.properties.get( newRenderTarget ); - renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues; + } else { - } + extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers ); - newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 + } - // Set foveation to maximum. - this.setFoveation( 1.0 ); + } - customReferenceSpace = null; - referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); - animation.setContext( session ); - animation.start(); + } - scope.isPresenting = true; + function useProgram( program ) { - scope.dispatchEvent( { type: 'sessionstart' } ); + if ( currentProgram !== program ) { - } + gl.useProgram( program ); - }; + currentProgram = program; - function onInputSourcesChange( event ) { + return true; - // Notify disconnected + } - for ( let i = 0; i < event.removed.length; i ++ ) { + return false; - const inputSource = event.removed[ i ]; - const index = controllerInputSources.indexOf( inputSource ); + } - if ( index >= 0 ) { + const equationToGL = { + [ AddEquation ]: 32774, + [ SubtractEquation ]: 32778, + [ ReverseSubtractEquation ]: 32779 + }; - controllerInputSources[ index ] = null; - controllers[ index ].dispatchEvent( { type: 'disconnected', data: inputSource } ); + if ( isWebGL2 ) { - } + equationToGL[ MinEquation ] = 32775; + equationToGL[ MaxEquation ] = 32776; - } + } else { - // Notify connected + const extension = extensions.get( 'EXT_blend_minmax' ); - for ( let i = 0; i < event.added.length; i ++ ) { + if ( extension !== null ) { - const inputSource = event.added[ i ]; + equationToGL[ MinEquation ] = extension.MIN_EXT; + equationToGL[ MaxEquation ] = extension.MAX_EXT; - let controllerIndex = controllerInputSources.indexOf( inputSource ); + } - if ( controllerIndex === - 1 ) { + } - // Assign input source a controller that currently has no input source + const factorToGL = { + [ ZeroFactor ]: 0, + [ OneFactor ]: 1, + [ SrcColorFactor ]: 768, + [ SrcAlphaFactor ]: 770, + [ SrcAlphaSaturateFactor ]: 776, + [ DstColorFactor ]: 774, + [ DstAlphaFactor ]: 772, + [ OneMinusSrcColorFactor ]: 769, + [ OneMinusSrcAlphaFactor ]: 771, + [ OneMinusDstColorFactor ]: 775, + [ OneMinusDstAlphaFactor ]: 773 + }; - for ( let i = 0; i < controllers.length; i ++ ) { + function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { - if ( i >= controllerInputSources.length ) { + if ( blending === NoBlending ) { - controllerInputSources.push( inputSource ); - controllerIndex = i; - break; + if ( currentBlendingEnabled === true ) { - } else if ( controllerInputSources[ i ] === null ) { + disable( 3042 ); + currentBlendingEnabled = false; - controllerInputSources[ i ] = inputSource; - controllerIndex = i; - break; + } - } + return; - } + } - // If all controllers do currently receive input we ignore new ones + if ( currentBlendingEnabled === false ) { - if ( controllerIndex === - 1 ) break; + enable( 3042 ); + currentBlendingEnabled = true; - } + } - const controller = controllers[ controllerIndex ]; + if ( blending !== CustomBlending ) { - if ( controller ) { + if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { - controller.dispatchEvent( { type: 'connected', data: inputSource } ); + if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { + + gl.blendEquation( 32774 ); + + currentBlendEquation = AddEquation; + currentBlendEquationAlpha = AddEquation; } - } + if ( premultipliedAlpha ) { - } + switch ( blending ) { - // + case NormalBlending: + gl.blendFuncSeparate( 1, 771, 1, 771 ); + break; - const cameraLPos = new Vector3(); - const cameraRPos = new Vector3(); + case AdditiveBlending: + gl.blendFunc( 1, 1 ); + break; - /** - * Assumes 2 cameras that are parallel and share an X-axis, and that - * the cameras' projection and world matrices have already been set. - * And that near and far planes are identical for both cameras. - * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 - */ - function setProjectionFromUnion( camera, cameraL, cameraR ) { + case SubtractiveBlending: + gl.blendFuncSeparate( 0, 769, 0, 1 ); + break; - cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); - cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); + case MultiplyBlending: + gl.blendFuncSeparate( 0, 768, 0, 770 ); + break; - const ipd = cameraLPos.distanceTo( cameraRPos ); + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; - const projL = cameraL.projectionMatrix.elements; - const projR = cameraR.projectionMatrix.elements; + } - // VR systems will have identical far and near planes, and - // most likely identical top and bottom frustum extents. - // Use the left camera for these values. - const near = projL[ 14 ] / ( projL[ 10 ] - 1 ); - const far = projL[ 14 ] / ( projL[ 10 ] + 1 ); - const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; - const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; + } else { - const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; - const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; - const left = near * leftFov; - const right = near * rightFov; + switch ( blending ) { - // Calculate the new camera's position offset from the - // left camera. xOffset should be roughly half `ipd`. - const zOffset = ipd / ( - leftFov + rightFov ); - const xOffset = zOffset * - leftFov; - - // TODO: Better way to apply this offset? - cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale ); - camera.translateX( xOffset ); - camera.translateZ( zOffset ); - camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale ); - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); + case NormalBlending: + gl.blendFuncSeparate( 770, 771, 1, 771 ); + break; - // Find the union of the frustum values of the cameras and scale - // the values so that the near plane's position does not change in world space, - // although must now be relative to the new union camera. - const near2 = near + zOffset; - const far2 = far + zOffset; - const left2 = left - xOffset; - const right2 = right + ( ipd - xOffset ); - const top2 = topFov * far / far2 * near2; - const bottom2 = bottomFov * far / far2 * near2; + case AdditiveBlending: + gl.blendFunc( 770, 1 ); + break; - camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); + case SubtractiveBlending: + gl.blendFuncSeparate( 0, 769, 0, 1 ); + break; - } + case MultiplyBlending: + gl.blendFunc( 0, 768 ); + break; - function updateCamera( camera, parent ) { + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; - if ( parent === null ) { + } - camera.matrixWorld.copy( camera.matrix ); + } - } else { + currentBlendSrc = null; + currentBlendDst = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; - camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); + currentBlending = blending; + currentPremultipledAlpha = premultipliedAlpha; } - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); + return; } - this.updateCamera = function ( camera ) { + // custom blending - if ( session === null ) return; + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; - cameraVR.near = cameraR.near = cameraL.near = camera.near; - cameraVR.far = cameraR.far = cameraL.far = camera.far; + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) { + gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); - // Note that the new renderState won't apply until the next frame. See #18320 + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; - session.updateRenderState( { - depthNear: cameraVR.near, - depthFar: cameraVR.far - } ); + } - _currentDepthNear = cameraVR.near; - _currentDepthFar = cameraVR.far; + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - } + gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); - const parent = camera.parent; - const cameras = cameraVR.cameras; + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; - updateCamera( cameraVR, parent ); + } - for ( let i = 0; i < cameras.length; i ++ ) { + currentBlending = blending; + currentPremultipledAlpha = null; - updateCamera( cameras[ i ], parent ); + } - } + function setMaterial( material, frontFaceCW ) { - cameraVR.matrixWorld.decompose( cameraVR.position, cameraVR.quaternion, cameraVR.scale ); + material.side === DoubleSide + ? disable( 2884 ) + : enable( 2884 ); - // update user camera and its children + let flipSided = ( material.side === BackSide ); + if ( frontFaceCW ) flipSided = ! flipSided; - camera.matrix.copy( cameraVR.matrix ); - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); + setFlipSided( flipSided ); - const children = camera.children; + ( material.blending === NormalBlending && material.transparent === false ) + ? setBlending( NoBlending ) + : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); - for ( let i = 0, l = children.length; i < l; i ++ ) { + depthBuffer.setFunc( material.depthFunc ); + depthBuffer.setTest( material.depthTest ); + depthBuffer.setMask( material.depthWrite ); + colorBuffer.setMask( material.colorWrite ); - children[ i ].updateMatrixWorld( true ); + const stencilWrite = material.stencilWrite; + stencilBuffer.setTest( stencilWrite ); + if ( stencilWrite ) { - } + stencilBuffer.setMask( material.stencilWriteMask ); + stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); + stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); - // update projection matrix for proper view frustum culling + } - if ( cameras.length === 2 ) { + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - setProjectionFromUnion( cameraVR, cameraL, cameraR ); + material.alphaToCoverage === true + ? enable( 32926 ) + : disable( 32926 ); - } else { + } - // assume single camera setup (AR) + // - cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); + function setFlipSided( flipSided ) { - } + if ( currentFlipSided !== flipSided ) { - }; + if ( flipSided ) { - this.getCamera = function () { + gl.frontFace( 2304 ); - return cameraVR; + } else { - }; + gl.frontFace( 2305 ); - this.getFoveation = function () { + } - if ( glProjLayer !== null ) { + currentFlipSided = flipSided; - return glProjLayer.fixedFoveation; + } - } + } - if ( glBaseLayer !== null ) { + function setCullFace( cullFace ) { - return glBaseLayer.fixedFoveation; + if ( cullFace !== CullFaceNone ) { - } + enable( 2884 ); - return undefined; + if ( cullFace !== currentCullFace ) { - }; + if ( cullFace === CullFaceBack ) { - this.setFoveation = function ( foveation ) { + gl.cullFace( 1029 ); - // 0 = no foveation = full resolution - // 1 = maximum foveation = the edges render at lower resolution + } else if ( cullFace === CullFaceFront ) { - if ( glProjLayer !== null ) { + gl.cullFace( 1028 ); - glProjLayer.fixedFoveation = foveation; + } else { + + gl.cullFace( 1032 ); + + } } - if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { + } else { - glBaseLayer.fixedFoveation = foveation; + disable( 2884 ); - } + } - }; + currentCullFace = cullFace; - // Animation Loop + } - let onAnimationFrameCallback = null; + function setLineWidth( width ) { - function onAnimationFrame( time, frame ) { + if ( width !== currentLineWidth ) { - pose = frame.getViewerPose( customReferenceSpace || referenceSpace ); - xrFrame = frame; + if ( lineWidthAvailable ) gl.lineWidth( width ); - if ( pose !== null ) { + currentLineWidth = width; - const views = pose.views; + } - if ( glBaseLayer !== null ) { + } - renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer ); - renderer.setRenderTarget( newRenderTarget ); + function setPolygonOffset( polygonOffset, factor, units ) { - } + if ( polygonOffset ) { - let cameraVRNeedsUpdate = false; + enable( 32823 ); - // check if it's necessary to rebuild cameraVR's camera list + if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { - if ( views.length !== cameraVR.cameras.length ) { + gl.polygonOffset( factor, units ); - cameraVR.cameras.length = 0; - cameraVRNeedsUpdate = true; + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; - } + } - for ( let i = 0; i < views.length; i ++ ) { + } else { - const view = views[ i ]; + disable( 32823 ); - let viewport = null; + } - if ( glBaseLayer !== null ) { + } - viewport = glBaseLayer.getViewport( view ); + function setScissorTest( scissorTest ) { - } else { + if ( scissorTest ) { - const glSubImage = glBinding.getViewSubImage( glProjLayer, view ); - viewport = glSubImage.viewport; + enable( 3089 ); - // For side-by-side projection, we only produce a single texture for both eyes. - if ( i === 0 ) { + } else { - renderer.setRenderTargetTextures( - newRenderTarget, - glSubImage.colorTexture, - glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture ); + disable( 3089 ); - renderer.setRenderTarget( newRenderTarget ); + } - } + } - } + // texture - let camera = cameras[ i ]; + function activeTexture( webglSlot ) { - if ( camera === undefined ) { + if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; - camera = new PerspectiveCamera(); - camera.layers.enable( i ); - camera.viewport = new Vector4(); - cameras[ i ] = camera; + if ( currentTextureSlot !== webglSlot ) { - } + gl.activeTexture( webglSlot ); + currentTextureSlot = webglSlot; - camera.matrix.fromArray( view.transform.matrix ); - camera.projectionMatrix.fromArray( view.projectionMatrix ); - camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); + } - if ( i === 0 ) { + } - cameraVR.matrix.copy( camera.matrix ); + function bindTexture( webglType, webglTexture, webglSlot ) { - } + if ( webglSlot === undefined ) { - if ( cameraVRNeedsUpdate === true ) { + if ( currentTextureSlot === null ) { - cameraVR.cameras.push( camera ); + webglSlot = 33984 + maxTextures - 1; - } + } else { - } + webglSlot = currentTextureSlot; } - // + } - for ( let i = 0; i < controllers.length; i ++ ) { + let boundTexture = currentBoundTextures[ webglSlot ]; - const inputSource = controllerInputSources[ i ]; - const controller = controllers[ i ]; + if ( boundTexture === undefined ) { - if ( inputSource !== null && controller !== undefined ) { + boundTexture = { type: undefined, texture: undefined }; + currentBoundTextures[ webglSlot ] = boundTexture; - controller.update( inputSource, frame, customReferenceSpace || referenceSpace ); + } - } + if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { - } + if ( currentTextureSlot !== webglSlot ) { - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame ); + gl.activeTexture( webglSlot ); + currentTextureSlot = webglSlot; - xrFrame = null; + } - } + gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); - const animation = new WebGLAnimation(); + boundTexture.type = webglType; + boundTexture.texture = webglTexture; - animation.setAnimationLoop( onAnimationFrame ); + } - this.setAnimationLoop = function ( callback ) { + } - onAnimationFrameCallback = callback; + function unbindTexture() { - }; + const boundTexture = currentBoundTextures[ currentTextureSlot ]; - this.dispose = function () {}; + if ( boundTexture !== undefined && boundTexture.type !== undefined ) { - } + gl.bindTexture( boundTexture.type, null ); - } + boundTexture.type = undefined; + boundTexture.texture = undefined; - function WebGLMaterials( renderer, properties ) { + } - function refreshFogUniforms( uniforms, fog ) { + } - uniforms.fogColor.value.copy( fog.color ); + function compressedTexImage2D() { - if ( fog.isFog ) { + try { - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; + gl.compressedTexImage2D.apply( gl, arguments ); - } else if ( fog.isFogExp2 ) { + } catch ( error ) { - uniforms.fogDensity.value = fog.density; + console.error( 'THREE.WebGLState:', error ); } } - function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) { - - if ( material.isMeshBasicMaterial ) { - - refreshUniformsCommon( uniforms, material ); + function texSubImage2D() { - } else if ( material.isMeshLambertMaterial ) { + try { - refreshUniformsCommon( uniforms, material ); + gl.texSubImage2D.apply( gl, arguments ); - } else if ( material.isMeshToonMaterial ) { + } catch ( error ) { - refreshUniformsCommon( uniforms, material ); - refreshUniformsToon( uniforms, material ); + console.error( 'THREE.WebGLState:', error ); - } else if ( material.isMeshPhongMaterial ) { + } - refreshUniformsCommon( uniforms, material ); - refreshUniformsPhong( uniforms, material ); + } - } else if ( material.isMeshStandardMaterial ) { + function texSubImage3D() { - refreshUniformsCommon( uniforms, material ); - refreshUniformsStandard( uniforms, material ); + try { - if ( material.isMeshPhysicalMaterial ) { + gl.texSubImage3D.apply( gl, arguments ); - refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ); + } catch ( error ) { - } + console.error( 'THREE.WebGLState:', error ); - } else if ( material.isMeshMatcapMaterial ) { + } - refreshUniformsCommon( uniforms, material ); - refreshUniformsMatcap( uniforms, material ); + } - } else if ( material.isMeshDepthMaterial ) { + function compressedTexSubImage2D() { - refreshUniformsCommon( uniforms, material ); + try { - } else if ( material.isMeshDistanceMaterial ) { + gl.compressedTexSubImage2D.apply( gl, arguments ); - refreshUniformsCommon( uniforms, material ); - refreshUniformsDistance( uniforms, material ); + } catch ( error ) { - } else if ( material.isMeshNormalMaterial ) { + console.error( 'THREE.WebGLState:', error ); - refreshUniformsCommon( uniforms, material ); + } - } else if ( material.isLineBasicMaterial ) { + } - refreshUniformsLine( uniforms, material ); + function texStorage2D() { - if ( material.isLineDashedMaterial ) { + try { - refreshUniformsDash( uniforms, material ); + gl.texStorage2D.apply( gl, arguments ); - } + } catch ( error ) { - } else if ( material.isPointsMaterial ) { + console.error( 'THREE.WebGLState:', error ); - refreshUniformsPoints( uniforms, material, pixelRatio, height ); + } - } else if ( material.isSpriteMaterial ) { + } - refreshUniformsSprites( uniforms, material ); + function texStorage3D() { - } else if ( material.isShadowMaterial ) { + try { - uniforms.color.value.copy( material.color ); - uniforms.opacity.value = material.opacity; + gl.texStorage3D.apply( gl, arguments ); - } else if ( material.isShaderMaterial ) { + } catch ( error ) { - material.uniformsNeedUpdate = false; // #15581 + console.error( 'THREE.WebGLState:', error ); } } - function refreshUniformsCommon( uniforms, material ) { + function texImage2D() { - uniforms.opacity.value = material.opacity; + try { - if ( material.color ) { + gl.texImage2D.apply( gl, arguments ); - uniforms.diffuse.value.copy( material.color ); + } catch ( error ) { + + console.error( 'THREE.WebGLState:', error ); } - if ( material.emissive ) { + } - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); + function texImage3D() { - } + try { - if ( material.map ) { + gl.texImage3D.apply( gl, arguments ); - uniforms.map.value = material.map; + } catch ( error ) { + + console.error( 'THREE.WebGLState:', error ); } - if ( material.alphaMap ) { + } - uniforms.alphaMap.value = material.alphaMap; + // - } + function scissor( scissor ) { - if ( material.bumpMap ) { + if ( currentScissor.equals( scissor ) === false ) { - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); + currentScissor.copy( scissor ); } - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; + } - } + function viewport( viewport ) { - if ( material.emissiveMap ) { + if ( currentViewport.equals( viewport ) === false ) { - uniforms.emissiveMap.value = material.emissiveMap; + gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); + currentViewport.copy( viewport ); } - if ( material.normalMap ) { + } - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + function updateUBOMapping( uniformsGroup, program ) { - } + let mapping = uboProgamMap.get( program ); - if ( material.specularMap ) { + if ( mapping === undefined ) { - uniforms.specularMap.value = material.specularMap; + mapping = new WeakMap(); - } + uboProgamMap.set( program, mapping ); - if ( material.alphaTest > 0 ) { + } - uniforms.alphaTest.value = material.alphaTest; + let blockIndex = mapping.get( uniformsGroup ); - } + if ( blockIndex === undefined ) { - const envMap = properties.get( material ).envMap; + blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name ); - if ( envMap ) { + mapping.set( uniformsGroup, blockIndex ); - uniforms.envMap.value = envMap; + } - uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; + } - uniforms.reflectivity.value = material.reflectivity; - uniforms.ior.value = material.ior; - uniforms.refractionRatio.value = material.refractionRatio; + function uniformBlockBinding( uniformsGroup, program ) { - } + const mapping = uboProgamMap.get( program ); + const blockIndex = mapping.get( uniformsGroup ); - if ( material.lightMap ) { + if ( uboBindings.get( uniformsGroup ) !== blockIndex ) { - uniforms.lightMap.value = material.lightMap; + // bind shader specific block index to global block point - // artist-friendly light intensity scaling factor - const scaleFactor = ( renderer.physicallyCorrectLights !== true ) ? Math.PI : 1; + gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); - uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; + uboBindings.set( uniformsGroup, blockIndex ); } - if ( material.aoMap ) { + } - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; + // - } + function reset() { - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. displacementMap map - // 4. normal map - // 5. bump map - // 6. roughnessMap map - // 7. metalnessMap map - // 8. alphaMap map - // 9. emissiveMap map - // 10. clearcoat map - // 11. clearcoat normal map - // 12. clearcoat roughnessMap map - // 13. iridescence map - // 14. iridescence thickness map - // 15. specular intensity map - // 16. specular tint map - // 17. transmission map - // 18. thickness map - - let uvScaleMap; + // reset state - if ( material.map ) { + gl.disable( 3042 ); + gl.disable( 2884 ); + gl.disable( 2929 ); + gl.disable( 32823 ); + gl.disable( 3089 ); + gl.disable( 2960 ); + gl.disable( 32926 ); - uvScaleMap = material.map; + gl.blendEquation( 32774 ); + gl.blendFunc( 1, 0 ); + gl.blendFuncSeparate( 1, 0, 1, 0 ); - } else if ( material.specularMap ) { + gl.colorMask( true, true, true, true ); + gl.clearColor( 0, 0, 0, 0 ); - uvScaleMap = material.specularMap; + gl.depthMask( true ); + gl.depthFunc( 513 ); + gl.clearDepth( 1 ); - } else if ( material.displacementMap ) { + gl.stencilMask( 0xffffffff ); + gl.stencilFunc( 519, 0, 0xffffffff ); + gl.stencilOp( 7680, 7680, 7680 ); + gl.clearStencil( 0 ); - uvScaleMap = material.displacementMap; + gl.cullFace( 1029 ); + gl.frontFace( 2305 ); - } else if ( material.normalMap ) { + gl.polygonOffset( 0, 0 ); - uvScaleMap = material.normalMap; + gl.activeTexture( 33984 ); - } else if ( material.bumpMap ) { + gl.bindFramebuffer( 36160, null ); - uvScaleMap = material.bumpMap; + if ( isWebGL2 === true ) { - } else if ( material.roughnessMap ) { + gl.bindFramebuffer( 36009, null ); + gl.bindFramebuffer( 36008, null ); - uvScaleMap = material.roughnessMap; + } - } else if ( material.metalnessMap ) { + gl.useProgram( null ); - uvScaleMap = material.metalnessMap; + gl.lineWidth( 1 ); - } else if ( material.alphaMap ) { + gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height ); + gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height ); - uvScaleMap = material.alphaMap; + // reset internals - } else if ( material.emissiveMap ) { + enabledCapabilities = {}; - uvScaleMap = material.emissiveMap; + currentTextureSlot = null; + currentBoundTextures = {}; - } else if ( material.clearcoatMap ) { + currentBoundFramebuffers = {}; + currentDrawbuffers = new WeakMap(); + defaultDrawbuffers = []; - uvScaleMap = material.clearcoatMap; + currentProgram = null; - } else if ( material.clearcoatNormalMap ) { + currentBlendingEnabled = false; + currentBlending = null; + currentBlendEquation = null; + currentBlendSrc = null; + currentBlendDst = null; + currentBlendEquationAlpha = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; + currentPremultipledAlpha = false; - uvScaleMap = material.clearcoatNormalMap; + currentFlipSided = null; + currentCullFace = null; - } else if ( material.clearcoatRoughnessMap ) { + currentLineWidth = null; - uvScaleMap = material.clearcoatRoughnessMap; + currentPolygonOffsetFactor = null; + currentPolygonOffsetUnits = null; - } else if ( material.iridescenceMap ) { + currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height ); + currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height ); - uvScaleMap = material.iridescenceMap; + colorBuffer.reset(); + depthBuffer.reset(); + stencilBuffer.reset(); - } else if ( material.iridescenceThicknessMap ) { + } - uvScaleMap = material.iridescenceThicknessMap; + return { - } else if ( material.specularIntensityMap ) { + buffers: { + color: colorBuffer, + depth: depthBuffer, + stencil: stencilBuffer + }, - uvScaleMap = material.specularIntensityMap; + enable: enable, + disable: disable, - } else if ( material.specularColorMap ) { + bindFramebuffer: bindFramebuffer, + drawBuffers: drawBuffers, - uvScaleMap = material.specularColorMap; + useProgram: useProgram, - } else if ( material.transmissionMap ) { + setBlending: setBlending, + setMaterial: setMaterial, - uvScaleMap = material.transmissionMap; + setFlipSided: setFlipSided, + setCullFace: setCullFace, - } else if ( material.thicknessMap ) { + setLineWidth: setLineWidth, + setPolygonOffset: setPolygonOffset, - uvScaleMap = material.thicknessMap; + setScissorTest: setScissorTest, - } else if ( material.sheenColorMap ) { + activeTexture: activeTexture, + bindTexture: bindTexture, + unbindTexture: unbindTexture, + compressedTexImage2D: compressedTexImage2D, + texImage2D: texImage2D, + texImage3D: texImage3D, - uvScaleMap = material.sheenColorMap; + updateUBOMapping: updateUBOMapping, + uniformBlockBinding: uniformBlockBinding, - } else if ( material.sheenRoughnessMap ) { + texStorage2D: texStorage2D, + texStorage3D: texStorage3D, + texSubImage2D: texSubImage2D, + texSubImage3D: texSubImage3D, + compressedTexSubImage2D: compressedTexSubImage2D, - uvScaleMap = material.sheenRoughnessMap; + scissor: scissor, + viewport: viewport, - } + reset: reset - if ( uvScaleMap !== undefined ) { + }; - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { + } - uvScaleMap = uvScaleMap.texture; + function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { - } + const isWebGL2 = capabilities.isWebGL2; + const maxTextures = capabilities.maxTextures; + const maxCubemapSize = capabilities.maxCubemapSize; + const maxTextureSize = capabilities.maxTextureSize; + const maxSamples = capabilities.maxSamples; + const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; + const supportsInvalidateFramebuffer = /OculusBrowser/g.test( navigator.userAgent ); - if ( uvScaleMap.matrixAutoUpdate === true ) { + const _videoTextures = new WeakMap(); + let _canvas; - uvScaleMap.updateMatrix(); + const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source - } + // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, + // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! + // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); + let useOffscreenCanvas = false; - } + try { - // uv repeat and offset setting priorities for uv2 - // 1. ao map - // 2. light map + useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' + // eslint-disable-next-line compat/compat + && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; - let uv2ScaleMap; + } catch ( err ) { - if ( material.aoMap ) { + // Ignore any errors - uv2ScaleMap = material.aoMap; + } - } else if ( material.lightMap ) { + function createCanvas( width, height ) { - uv2ScaleMap = material.lightMap; + // Use OffscreenCanvas when available. Specially needed in web workers - } + return useOffscreenCanvas ? + // eslint-disable-next-line compat/compat + new OffscreenCanvas( width, height ) : createElementNS( 'canvas' ); - if ( uv2ScaleMap !== undefined ) { + } - // backwards compatibility - if ( uv2ScaleMap.isWebGLRenderTarget ) { + function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) { - uv2ScaleMap = uv2ScaleMap.texture; + let scale = 1; - } + // handle case if texture exceeds max size - if ( uv2ScaleMap.matrixAutoUpdate === true ) { + if ( image.width > maxSize || image.height > maxSize ) { - uv2ScaleMap.updateMatrix(); + scale = maxSize / Math.max( image.width, image.height ); - } + } - uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix ); + // only perform resize if necessary - } + if ( scale < 1 || needsPowerOfTwo === true ) { - } + // only perform resize for certain image types - function refreshUniformsLine( uniforms, material ) { + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; + const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor; - } + const width = floor( scale * image.width ); + const height = floor( scale * image.height ); - function refreshUniformsDash( uniforms, material ) { + if ( _canvas === undefined ) _canvas = createCanvas( width, height ); - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; + // cube textures can't reuse the same canvas - } + const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; - function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { + canvas.width = width; + canvas.height = height; - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size * pixelRatio; - uniforms.scale.value = height * 0.5; + const context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, width, height ); - if ( material.map ) { + console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' ); - uniforms.map.value = material.map; + return canvas; - } + } else { - if ( material.alphaMap ) { + if ( 'data' in image ) { - uniforms.alphaMap.value = material.alphaMap; + console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); - } + } - if ( material.alphaTest > 0 ) { + return image; - uniforms.alphaTest.value = material.alphaTest; + } } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map + return image; - let uvScaleMap; + } - if ( material.map ) { + function isPowerOfTwo$1( image ) { - uvScaleMap = material.map; + return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ); - } else if ( material.alphaMap ) { + } - uvScaleMap = material.alphaMap; + function textureNeedsPowerOfTwo( texture ) { - } + if ( isWebGL2 ) return false; - if ( uvScaleMap !== undefined ) { + return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || + ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); - if ( uvScaleMap.matrixAutoUpdate === true ) { + } - uvScaleMap.updateMatrix(); + function textureNeedsGenerateMipmaps( texture, supportsMips ) { - } + return texture.generateMipmaps && supportsMips && + texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); + } - } + function generateMipmap( target ) { + + _gl.generateMipmap( target ); } - function refreshUniformsSprites( uniforms, material ) { + function getInternalFormat( internalFormatName, glFormat, glType, encoding, forceLinearEncoding = false ) { - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.rotation.value = material.rotation; + if ( isWebGL2 === false ) return glFormat; - if ( material.map ) { + if ( internalFormatName !== null ) { - uniforms.map.value = material.map; + if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ]; + + console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); } - if ( material.alphaMap ) { + let internalFormat = glFormat; - uniforms.alphaMap.value = material.alphaMap; + if ( glFormat === 6403 ) { + + if ( glType === 5126 ) internalFormat = 33326; + if ( glType === 5131 ) internalFormat = 33325; + if ( glType === 5121 ) internalFormat = 33321; } - if ( material.alphaTest > 0 ) { + if ( glFormat === 33319 ) { - uniforms.alphaTest.value = material.alphaTest; + if ( glType === 5126 ) internalFormat = 33328; + if ( glType === 5131 ) internalFormat = 33327; + if ( glType === 5121 ) internalFormat = 33323; } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; + if ( glFormat === 6408 ) { - if ( material.map ) { + if ( glType === 5126 ) internalFormat = 34836; + if ( glType === 5131 ) internalFormat = 34842; + if ( glType === 5121 ) internalFormat = ( encoding === sRGBEncoding && forceLinearEncoding === false ) ? 35907 : 32856; + if ( glType === 32819 ) internalFormat = 32854; + if ( glType === 32820 ) internalFormat = 32855; - uvScaleMap = material.map; + } - } else if ( material.alphaMap ) { + if ( internalFormat === 33325 || internalFormat === 33326 || + internalFormat === 33327 || internalFormat === 33328 || + internalFormat === 34842 || internalFormat === 34836 ) { - uvScaleMap = material.alphaMap; + extensions.get( 'EXT_color_buffer_float' ); } - if ( uvScaleMap !== undefined ) { + return internalFormat; - if ( uvScaleMap.matrixAutoUpdate === true ) { + } - uvScaleMap.updateMatrix(); + function getMipLevels( texture, image, supportsMips ) { - } + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) { - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); + return Math.log2( Math.max( image.width, image.height ) ) + 1; - } + } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) { - } + // user-defined mipmaps - function refreshUniformsPhong( uniforms, material ) { + return texture.mipmaps.length; - uniforms.specular.value.copy( material.specular ); - uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) + } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) { - } + return image.mipmaps.length; - function refreshUniformsToon( uniforms, material ) { + } else { - if ( material.gradientMap ) { + // texture without mipmaps (only base level) - uniforms.gradientMap.value = material.gradientMap; + return 1; } } - function refreshUniformsStandard( uniforms, material ) { + // Fallback filters for non-power-of-2 textures - uniforms.roughness.value = material.roughness; - uniforms.metalness.value = material.metalness; + function filterFallback( f ) { - if ( material.roughnessMap ) { + if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - uniforms.roughnessMap.value = material.roughnessMap; + return 9728; } - if ( material.metalnessMap ) { + return 9729; - uniforms.metalnessMap.value = material.metalnessMap; + } - } + // - const envMap = properties.get( material ).envMap; + function onTextureDispose( event ) { - if ( envMap ) { + const texture = event.target; - //uniforms.envMap.value = material.envMap; // part of uniforms common - uniforms.envMapIntensity.value = material.envMapIntensity; + texture.removeEventListener( 'dispose', onTextureDispose ); + + deallocateTexture( texture ); + + if ( texture.isVideoTexture ) { + + _videoTextures.delete( texture ); } } - function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) { + function onRenderTargetDispose( event ) { - uniforms.ior.value = material.ior; // also part of uniforms common + const renderTarget = event.target; - if ( material.sheen > 0 ) { + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen ); + deallocateRenderTarget( renderTarget ); - uniforms.sheenRoughness.value = material.sheenRoughness; + } - if ( material.sheenColorMap ) { + // - uniforms.sheenColorMap.value = material.sheenColorMap; + function deallocateTexture( texture ) { - } + const textureProperties = properties.get( texture ); - if ( material.sheenRoughnessMap ) { + if ( textureProperties.__webglInit === undefined ) return; - uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; + // check if it's necessary to remove the WebGLTexture object - } + const source = texture.source; + const webglTextures = _sources.get( source ); - } + if ( webglTextures ) { - if ( material.clearcoat > 0 ) { + const webglTexture = webglTextures[ textureProperties.__cacheKey ]; + webglTexture.usedTimes --; - uniforms.clearcoat.value = material.clearcoat; - uniforms.clearcoatRoughness.value = material.clearcoatRoughness; + // the WebGLTexture object is not used anymore, remove it - if ( material.clearcoatMap ) { + if ( webglTexture.usedTimes === 0 ) { - uniforms.clearcoatMap.value = material.clearcoatMap; + deleteTexture( texture ); } - if ( material.clearcoatRoughnessMap ) { + // remove the weak map entry if no WebGLTexture uses the source anymore - uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; + if ( Object.keys( webglTextures ).length === 0 ) { - } + _sources.delete( source ); - if ( material.clearcoatNormalMap ) { + } - uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); - uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; + } - if ( material.side === BackSide ) { + properties.remove( texture ); - uniforms.clearcoatNormalScale.value.negate(); + } - } + function deleteTexture( texture ) { - } + const textureProperties = properties.get( texture ); + _gl.deleteTexture( textureProperties.__webglTexture ); - } + const source = texture.source; + const webglTextures = _sources.get( source ); + delete webglTextures[ textureProperties.__cacheKey ]; - if ( material.iridescence > 0 ) { + info.memory.textures --; - uniforms.iridescence.value = material.iridescence; - uniforms.iridescenceIOR.value = material.iridescenceIOR; - uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ]; - uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ]; + } - if ( material.iridescenceMap ) { + function deallocateRenderTarget( renderTarget ) { - uniforms.iridescenceMap.value = material.iridescenceMap; + const texture = renderTarget.texture; - } + const renderTargetProperties = properties.get( renderTarget ); + const textureProperties = properties.get( texture ); - if ( material.iridescenceThicknessMap ) { + if ( textureProperties.__webglTexture !== undefined ) { - uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; + _gl.deleteTexture( textureProperties.__webglTexture ); - } + info.memory.textures --; } - if ( material.transmission > 0 ) { - - uniforms.transmission.value = material.transmission; - uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; - uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height ); - - if ( material.transmissionMap ) { + if ( renderTarget.depthTexture ) { - uniforms.transmissionMap.value = material.transmissionMap; + renderTarget.depthTexture.dispose(); - } + } - uniforms.thickness.value = material.thickness; + if ( renderTarget.isWebGLCubeRenderTarget ) { - if ( material.thicknessMap ) { + for ( let i = 0; i < 6; i ++ ) { - uniforms.thicknessMap.value = material.thicknessMap; + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); } - uniforms.attenuationDistance.value = material.attenuationDistance; - uniforms.attenuationColor.value.copy( material.attenuationColor ); + } else { - } + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); + if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); - uniforms.specularIntensity.value = material.specularIntensity; - uniforms.specularColor.value.copy( material.specularColor ); + if ( renderTargetProperties.__webglColorRenderbuffer ) { - if ( material.specularIntensityMap ) { + for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) { - uniforms.specularIntensityMap.value = material.specularIntensityMap; + if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] ); - } + } - if ( material.specularColorMap ) { + } - uniforms.specularColorMap.value = material.specularColorMap; + if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer ); } - } + if ( renderTarget.isWebGLMultipleRenderTargets ) { - function refreshUniformsMatcap( uniforms, material ) { + for ( let i = 0, il = texture.length; i < il; i ++ ) { - if ( material.matcap ) { + const attachmentProperties = properties.get( texture[ i ] ); - uniforms.matcap.value = material.matcap; + if ( attachmentProperties.__webglTexture ) { - } + _gl.deleteTexture( attachmentProperties.__webglTexture ); - } + info.memory.textures --; - function refreshUniformsDistance( uniforms, material ) { + } - uniforms.referencePosition.value.copy( material.referencePosition ); - uniforms.nearDistance.value = material.nearDistance; - uniforms.farDistance.value = material.farDistance; + properties.remove( texture[ i ] ); - } + } - return { - refreshFogUniforms: refreshFogUniforms, - refreshMaterialUniforms: refreshMaterialUniforms - }; + } - } + properties.remove( texture ); + properties.remove( renderTarget ); - function WebGLUniformsGroups( gl, info, capabilities, state ) { + } - let buffers = {}; - let updateList = {}; - let allocatedBindingPoints = []; + // - const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( 35375 ) : 0; // binding points are global whereas block indices are per shader program + let textureUnits = 0; - function bind( uniformsGroup, program ) { + function resetTextureUnits() { - const webglProgram = program.program; - state.uniformBlockBinding( uniformsGroup, webglProgram ); + textureUnits = 0; } - function update( uniformsGroup, program ) { - - let buffer = buffers[ uniformsGroup.id ]; - - if ( buffer === undefined ) { + function allocateTextureUnit() { - prepareUniformsGroup( uniformsGroup ); + const textureUnit = textureUnits; - buffer = createBuffer( uniformsGroup ); - buffers[ uniformsGroup.id ] = buffer; + if ( textureUnit >= maxTextures ) { - uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose ); + console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures ); } - // ensure to update the binding points/block indices mapping for this program - - const webglProgram = program.program; - state.updateUBOMapping( uniformsGroup, webglProgram ); + textureUnits += 1; - // update UBO once per frame + return textureUnit; - const frame = info.render.frame; + } - if ( updateList[ uniformsGroup.id ] !== frame ) { + function getTextureCacheKey( texture ) { - updateBufferData( uniformsGroup ); + const array = []; - updateList[ uniformsGroup.id ] = frame; + array.push( texture.wrapS ); + array.push( texture.wrapT ); + array.push( texture.magFilter ); + array.push( texture.minFilter ); + array.push( texture.anisotropy ); + array.push( texture.internalFormat ); + array.push( texture.format ); + array.push( texture.type ); + array.push( texture.generateMipmaps ); + array.push( texture.premultiplyAlpha ); + array.push( texture.flipY ); + array.push( texture.unpackAlignment ); + array.push( texture.encoding ); - } + return array.join(); } - function createBuffer( uniformsGroup ) { + // - // the setup of an UBO is independent of a particular shader program but global + function setTexture2D( texture, slot ) { - const bindingPointIndex = allocateBindingPointIndex(); - uniformsGroup.__bindingPointIndex = bindingPointIndex; + const textureProperties = properties.get( texture ); - const buffer = gl.createBuffer(); - const size = uniformsGroup.__size; - const usage = uniformsGroup.usage; + if ( texture.isVideoTexture ) updateVideoTexture( texture ); - gl.bindBuffer( 35345, buffer ); - gl.bufferData( 35345, size, usage ); - gl.bindBuffer( 35345, null ); - gl.bindBufferBase( 35345, bindingPointIndex, buffer ); + if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) { - return buffer; + const image = texture.image; - } + if ( image === null ) { - function allocateBindingPointIndex() { + console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' ); - for ( let i = 0; i < maxBindingPoints; i ++ ) { + } else if ( image.complete === false ) { - if ( allocatedBindingPoints.indexOf( i ) === - 1 ) { + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); - allocatedBindingPoints.push( i ); - return i; + } else { + + uploadTexture( textureProperties, texture, slot ); + return; } } - console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); - - return 0; + state.bindTexture( 3553, textureProperties.__webglTexture, 33984 + slot ); } - function updateBufferData( uniformsGroup ) { - - const buffer = buffers[ uniformsGroup.id ]; - const uniforms = uniformsGroup.uniforms; - const cache = uniformsGroup.__cache; - - gl.bindBuffer( 35345, buffer ); + function setTexture2DArray( texture, slot ) { - for ( let i = 0, il = uniforms.length; i < il; i ++ ) { + const textureProperties = properties.get( texture ); - const uniform = uniforms[ i ]; + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - // partly update the buffer if necessary + uploadTexture( textureProperties, texture, slot ); + return; - if ( hasUniformChanged( uniform, i, cache ) === true ) { + } - const value = uniform.value; - const offset = uniform.__offset; + state.bindTexture( 35866, textureProperties.__webglTexture, 33984 + slot ); - if ( typeof value === 'number' ) { + } - uniform.__data[ 0 ] = value; - gl.bufferSubData( 35345, offset, uniform.__data ); + function setTexture3D( texture, slot ) { - } else { + const textureProperties = properties.get( texture ); - if ( uniform.value.isMatrix3 ) { + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - // manually converting 3x3 to 3x4 + uploadTexture( textureProperties, texture, slot ); + return; - uniform.__data[ 0 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 1 ] = uniform.value.elements[ 1 ]; - uniform.__data[ 2 ] = uniform.value.elements[ 2 ]; - uniform.__data[ 3 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 4 ] = uniform.value.elements[ 3 ]; - uniform.__data[ 5 ] = uniform.value.elements[ 4 ]; - uniform.__data[ 6 ] = uniform.value.elements[ 5 ]; - uniform.__data[ 7 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 8 ] = uniform.value.elements[ 6 ]; - uniform.__data[ 9 ] = uniform.value.elements[ 7 ]; - uniform.__data[ 10 ] = uniform.value.elements[ 8 ]; - uniform.__data[ 11 ] = uniform.value.elements[ 0 ]; + } - } else { + state.bindTexture( 32879, textureProperties.__webglTexture, 33984 + slot ); - value.toArray( uniform.__data ); + } - } + function setTextureCube( texture, slot ) { - gl.bufferSubData( 35345, offset, uniform.__data ); + const textureProperties = properties.get( texture ); - } + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - } + uploadCubeTexture( textureProperties, texture, slot ); + return; } - gl.bindBuffer( 35345, null ); + state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); } - function hasUniformChanged( uniform, index, cache ) { + const wrappingToGL = { + [ RepeatWrapping ]: 10497, + [ ClampToEdgeWrapping ]: 33071, + [ MirroredRepeatWrapping ]: 33648 + }; - const value = uniform.value; + const filterToGL = { + [ NearestFilter ]: 9728, + [ NearestMipmapNearestFilter ]: 9984, + [ NearestMipmapLinearFilter ]: 9986, - if ( cache[ index ] === undefined ) { + [ LinearFilter ]: 9729, + [ LinearMipmapNearestFilter ]: 9985, + [ LinearMipmapLinearFilter ]: 9987 + }; - // cache entry does not exist so far + function setTextureParameters( textureType, texture, supportsMips ) { - if ( typeof value === 'number' ) { + if ( supportsMips ) { - cache[ index ] = value; + _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] ); + _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] ); - } else { + if ( textureType === 32879 || textureType === 35866 ) { - cache[ index ] = value.clone(); + _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] ); } - return true; + _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] ); + _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] ); } else { - // compare current value with cached entry + _gl.texParameteri( textureType, 10242, 33071 ); + _gl.texParameteri( textureType, 10243, 33071 ); - if ( typeof value === 'number' ) { + if ( textureType === 32879 || textureType === 35866 ) { - if ( cache[ index ] !== value ) { + _gl.texParameteri( textureType, 32882, 33071 ); - cache[ index ] = value; - return true; + } - } + if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { - } else { + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); - const cachedObject = cache[ index ]; + } - if ( cachedObject.equals( value ) === false ) { + _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); - cachedObject.copy( value ); - return true; + if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { - } + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); } } - return false; + if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - } + const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - function prepareUniformsGroup( uniformsGroup ) { + if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 + if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only - // determine total buffer size according to the STD140 layout - // Hint: STD140 is the only supported layout in WebGL 2 + if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - const uniforms = uniformsGroup.uniforms; + _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); + properties.get( texture ).__currentAnisotropy = texture.anisotropy; - let offset = 0; // global buffer offset in bytes - const chunkSize = 16; // size of a chunk in bytes - let chunkOffset = 0; // offset within a single chunk in bytes + } - for ( let i = 0, l = uniforms.length; i < l; i ++ ) { + } - const uniform = uniforms[ i ]; - const info = getUniformSize( uniform ); + } - // the following two properties will be used for partial buffer updates + function initTexture( textureProperties, texture ) { - uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); - uniform.__offset = offset; + let forceUpload = false; - // + if ( textureProperties.__webglInit === undefined ) { - if ( i > 0 ) { + textureProperties.__webglInit = true; - chunkOffset = offset % chunkSize; + texture.addEventListener( 'dispose', onTextureDispose ); - const remainingSizeInChunk = chunkSize - chunkOffset; + } - // check for chunk overflow + // create Source <-> WebGLTextures mapping if necessary - if ( chunkOffset !== 0 && ( remainingSizeInChunk - info.boundary ) < 0 ) { + const source = texture.source; + let webglTextures = _sources.get( source ); - // add padding and adjust offset + if ( webglTextures === undefined ) { - offset += ( chunkSize - chunkOffset ); - uniform.__offset = offset; + webglTextures = {}; + _sources.set( source, webglTextures ); - } + } - } + // check if there is already a WebGLTexture object for the given texture parameters - offset += info.storage; + const textureCacheKey = getTextureCacheKey( texture ); - } + if ( textureCacheKey !== textureProperties.__cacheKey ) { - // ensure correct final padding + // if not, create a new instance of WebGLTexture - chunkOffset = offset % chunkSize; + if ( webglTextures[ textureCacheKey ] === undefined ) { - if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); + // create new entry - // + webglTextures[ textureCacheKey ] = { + texture: _gl.createTexture(), + usedTimes: 0 + }; - uniformsGroup.__size = offset; - uniformsGroup.__cache = {}; + info.memory.textures ++; - return this; + // when a new instance of WebGLTexture was created, a texture upload is required + // even if the image contents are identical - } + forceUpload = true; - function getUniformSize( uniform ) { + } - const value = uniform.value; + webglTextures[ textureCacheKey ].usedTimes ++; - const info = { - boundary: 0, // bytes - storage: 0 // bytes - }; + // every time the texture cache key changes, it's necessary to check if an instance of + // WebGLTexture can be deleted in order to avoid a memory leak. - // determine sizes according to STD140 + const webglTexture = webglTextures[ textureProperties.__cacheKey ]; - if ( typeof value === 'number' ) { + if ( webglTexture !== undefined ) { - // float/int + webglTextures[ textureProperties.__cacheKey ].usedTimes --; - info.boundary = 4; - info.storage = 4; + if ( webglTexture.usedTimes === 0 ) { - } else if ( value.isVector2 ) { + deleteTexture( texture ); - // vec2 + } - info.boundary = 8; - info.storage = 8; + } - } else if ( value.isVector3 || value.isColor ) { + // store references to cache key and WebGLTexture object - // vec3 + textureProperties.__cacheKey = textureCacheKey; + textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture; - info.boundary = 16; - info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes + } - } else if ( value.isVector4 ) { + return forceUpload; - // vec4 + } - info.boundary = 16; - info.storage = 16; + function uploadTexture( textureProperties, texture, slot ) { - } else if ( value.isMatrix3 ) { + let textureType = 3553; - // mat3 (in STD140 a 3x3 matrix is represented as 3x4) + if ( texture.isDataArrayTexture ) textureType = 35866; + if ( texture.isData3DTexture ) textureType = 32879; - info.boundary = 48; - info.storage = 48; + const forceUpload = initTexture( textureProperties, texture ); + const source = texture.source; - } else if ( value.isMatrix4 ) { + state.bindTexture( textureType, textureProperties.__webglTexture, 33984 + slot ); - // mat4 + const sourceProperties = properties.get( source ); - info.boundary = 64; - info.storage = 64; + if ( source.version !== sourceProperties.__version || forceUpload === true ) { - } else if ( value.isTexture ) { + state.activeTexture( 33984 + slot ); - console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); + _gl.pixelStorei( 37440, texture.flipY ); + _gl.pixelStorei( 37441, texture.premultiplyAlpha ); + _gl.pixelStorei( 3317, texture.unpackAlignment ); + _gl.pixelStorei( 37443, 0 ); - } else { + const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; + let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize ); + image = verifyColorSpace( texture, image ); - console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); + const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, + glFormat = utils.convert( texture.format, texture.encoding ); - } + let glType = utils.convert( texture.type ), + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, texture.isVideoTexture ); - return info; + setTextureParameters( textureType, texture, supportsMips ); - } + let mipmap; + const mipmaps = texture.mipmaps; - function onUniformsGroupsDispose( event ) { + const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); + const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); + const levels = getMipLevels( texture, image, supportsMips ); - const uniformsGroup = event.target; + if ( texture.isDepthTexture ) { - uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); + // populate depth texture with dummy data - const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); - allocatedBindingPoints.splice( index, 1 ); + glInternalFormat = 6402; - gl.deleteBuffer( buffers[ uniformsGroup.id ] ); + if ( isWebGL2 ) { - delete buffers[ uniformsGroup.id ]; - delete updateList[ uniformsGroup.id ]; + if ( texture.type === FloatType ) { - } + glInternalFormat = 36012; - function dispose() { + } else if ( texture.type === UnsignedIntType ) { - for ( const id in buffers ) { + glInternalFormat = 33190; - gl.deleteBuffer( buffers[ id ] ); + } else if ( texture.type === UnsignedInt248Type ) { - } + glInternalFormat = 35056; - allocatedBindingPoints = []; - buffers = {}; - updateList = {}; + } else { - } + glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D - return { + } - bind: bind, - update: update, + } else { - dispose: dispose + if ( texture.type === FloatType ) { - }; + console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' ); - } + } - function createCanvasElement() { + } - const canvas = createElementNS( 'canvas' ); - canvas.style.display = 'block'; - return canvas; + // validation checks for WebGL 1 - } + if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { - function WebGLRenderer( parameters = {} ) { + // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are + // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { - this.isWebGLRenderer = true; + console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); - const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(), - _context = parameters.context !== undefined ? parameters.context : null, + texture.type = UnsignedIntType; + glType = utils.convert( texture.type ); - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default', - _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false; + } - let _alpha; + } - if ( _context !== null ) { + if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) { - _alpha = _context.getContextAttributes().alpha; + // Depth stencil textures need the DEPTH_STENCIL internal format + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + glInternalFormat = 34041; - } else { + // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are + // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + if ( texture.type !== UnsignedInt248Type ) { - _alpha = parameters.alpha !== undefined ? parameters.alpha : false; + console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); - } + texture.type = UnsignedInt248Type; + glType = utils.convert( texture.type ); - let currentRenderList = null; - let currentRenderState = null; + } - // render() can be called from within a callback triggered by another render. - // We track this so that the nested render call gets its list and state isolated from the parent render call. + } - const renderListStack = []; - const renderStateStack = []; + // - // public properties + if ( allocateMemory ) { - this.domElement = _canvas; + if ( useTexStorage ) { - // Debug configuration container - this.debug = { + state.texStorage2D( 3553, 1, glInternalFormat, image.width, image.height ); - /** - * Enables error checking and reporting when shader programs are being compiled - * @type {boolean} - */ - checkShaderErrors: true - }; + } else { - // clearing + state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; + } - // scene graph + } - this.sortObjects = true; + } else if ( texture.isDataTexture ) { - // user-defined clipping + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels - this.clippingPlanes = []; - this.localClippingEnabled = false; + if ( mipmaps.length > 0 && supportsMips ) { - // physically based shading + if ( useTexStorage && allocateMemory ) { - this.outputEncoding = LinearEncoding; + state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - // physical lights + } - this.physicallyCorrectLights = false; + for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - // tone mapping + mipmap = mipmaps[ i ]; - this.toneMapping = NoToneMapping; - this.toneMappingExposure = 1.0; + if ( useTexStorage ) { - // + state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - Object.defineProperties( this, { + } else { - // @deprecated since r136, 0e21088102b4de7e0a0a33140620b7a3424b9e6d + state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - gammaFactor: { - get: function () { + } - console.warn( 'THREE.WebGLRenderer: .gammaFactor has been removed.' ); - return 2; + } - }, - set: function () { + texture.generateMipmaps = false; - console.warn( 'THREE.WebGLRenderer: .gammaFactor has been removed.' ); + } else { - } - } + if ( useTexStorage ) { - } ); + if ( allocateMemory ) { - // internal properties + state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); - const _this = this; + } - let _isContextLost = false; + state.texSubImage2D( 3553, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); - // internal state cache + } else { - let _currentActiveCubeFace = 0; - let _currentActiveMipmapLevel = 0; - let _currentRenderTarget = null; - let _currentMaterialId = - 1; + state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); - let _currentCamera = null; + } - const _currentViewport = new Vector4(); - const _currentScissor = new Vector4(); - let _currentScissorTest = null; + } - // + } else if ( texture.isCompressedTexture ) { - let _width = _canvas.width; - let _height = _canvas.height; + if ( useTexStorage && allocateMemory ) { - let _pixelRatio = 1; - let _opaqueSort = null; - let _transparentSort = null; + state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - const _viewport = new Vector4( 0, 0, _width, _height ); - const _scissor = new Vector4( 0, 0, _width, _height ); - let _scissorTest = false; + } - // frustum + for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - const _frustum = new Frustum(); + mipmap = mipmaps[ i ]; - // clipping + if ( texture.format !== RGBAFormat ) { - let _clippingEnabled = false; - let _localClippingEnabled = false; + if ( glFormat !== null ) { - // transmission + if ( useTexStorage ) { - let _transmissionRenderTarget = null; + state.compressedTexSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); - // camera matrices cache + } else { - const _projScreenMatrix = new Matrix4(); + state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - const _vector2 = new Vector2(); - const _vector3 = new Vector3(); + } - const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; + } else { - function getTargetPixelRatio() { + console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - return _currentRenderTarget === null ? _pixelRatio : 1; + } - } + } else { - // initialize + if ( useTexStorage ) { - let _gl = _context; + state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - function getContext( contextNames, contextAttributes ) { + } else { - for ( let i = 0; i < contextNames.length; i ++ ) { + state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - const contextName = contextNames[ i ]; - const context = _canvas.getContext( contextName, contextAttributes ); - if ( context !== null ) return context; + } - } + } - return null; + } - } + } else if ( texture.isDataArrayTexture ) { - try { + if ( useTexStorage ) { - const contextAttributes = { - alpha: true, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer, - powerPreference: _powerPreference, - failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat - }; + if ( allocateMemory ) { - // OffscreenCanvas does not have setAttribute, see #22811 - if ( 'setAttribute' in _canvas ) _canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); + state.texStorage3D( 35866, levels, glInternalFormat, image.width, image.height, image.depth ); - // event listeners must be registered before WebGL context is created, see #12753 - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + } - if ( _gl === null ) { + state.texSubImage3D( 35866, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); - const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; + } else { - if ( _this.isWebGL1Renderer === true ) { + state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - contextNames.shift(); + } - } + } else if ( texture.isData3DTexture ) { - _gl = getContext( contextNames, contextAttributes ); + if ( useTexStorage ) { - if ( _gl === null ) { + if ( allocateMemory ) { - if ( getContext( contextNames ) ) { + state.texStorage3D( 32879, levels, glInternalFormat, image.width, image.height, image.depth ); - throw new Error( 'Error creating WebGL context with your selected attributes.' ); + } + + state.texSubImage3D( 32879, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); } else { - throw new Error( 'Error creating WebGL context.' ); + state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); } - } + } else if ( texture.isFramebufferTexture ) { - } + if ( allocateMemory ) { - // Some experimental-webgl implementations do not have getShaderPrecisionFormat + if ( useTexStorage ) { - if ( _gl.getShaderPrecisionFormat === undefined ) { + state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); - _gl.getShaderPrecisionFormat = function () { + } else { - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + let width = image.width, height = image.height; - }; + for ( let i = 0; i < levels; i ++ ) { - } + state.texImage2D( 3553, i, glInternalFormat, width, height, 0, glFormat, glType, null ); - } catch ( error ) { + width >>= 1; + height >>= 1; - console.error( 'THREE.WebGLRenderer: ' + error.message ); - throw error; + } - } + } - let extensions, capabilities, state, info; - let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; + } - let background, morphtargets, bufferRenderer, indexedBufferRenderer; + } else { - let utils, bindingStates, uniformsGroups; + // regular Texture (image, video, canvas) - function initGLContext() { + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels - extensions = new WebGLExtensions( _gl ); + if ( mipmaps.length > 0 && supportsMips ) { - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); + if ( useTexStorage && allocateMemory ) { - extensions.init( capabilities ); + state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); - utils = new WebGLUtils( _gl, extensions, capabilities ); + } - state = new WebGLState( _gl, extensions, capabilities ); + for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - info = new WebGLInfo(); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - cubemaps = new WebGLCubeMaps( _this ); - cubeuvmaps = new WebGLCubeUVMaps( _this ); - attributes = new WebGLAttributes( _gl, capabilities ); - bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); - geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); - objects = new WebGLObjects( _gl, geometries, attributes, info ); - morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); - clipping = new WebGLClipping( properties ); - programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); - materials = new WebGLMaterials( _this, properties ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates( extensions, capabilities ); - background = new WebGLBackground( _this, cubemaps, state, objects, _alpha, _premultipliedAlpha ); - shadowMap = new WebGLShadowMap( _this, objects, capabilities ); - uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); + mipmap = mipmaps[ i ]; - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); + if ( useTexStorage ) { - info.programs = programCache.programs; + state.texSubImage2D( 3553, i, 0, 0, glFormat, glType, mipmap ); - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.shadowMap = shadowMap; - _this.state = state; - _this.info = info; + } else { - } + state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); - initGLContext(); + } - // xr + } - const xr = new WebXRManager( _this, _gl ); + texture.generateMipmaps = false; - this.xr = xr; + } else { - // API + if ( useTexStorage ) { - this.getContext = function () { + if ( allocateMemory ) { - return _gl; + state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); - }; + } - this.getContextAttributes = function () { + state.texSubImage2D( 3553, 0, 0, 0, glFormat, glType, image ); - return _gl.getContextAttributes(); + } else { - }; + state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); - this.forceContextLoss = function () { + } - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); + } - }; + } - this.forceContextRestore = function () { + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); + generateMipmap( textureType ); - }; + } - this.getPixelRatio = function () { + sourceProperties.__version = source.version; - return _pixelRatio; + if ( texture.onUpdate ) texture.onUpdate( texture ); - }; + } - this.setPixelRatio = function ( value ) { + textureProperties.__version = texture.version; - if ( value === undefined ) return; + } - _pixelRatio = value; + function uploadCubeTexture( textureProperties, texture, slot ) { - this.setSize( _width, _height, false ); + if ( texture.image.length !== 6 ) return; - }; + const forceUpload = initTexture( textureProperties, texture ); + const source = texture.source; - this.getSize = function ( target ) { + state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); - return target.set( _width, _height ); + const sourceProperties = properties.get( source ); - }; + if ( source.version !== sourceProperties.__version || forceUpload === true ) { - this.setSize = function ( width, height, updateStyle ) { + state.activeTexture( 33984 + slot ); - if ( xr.isPresenting ) { + _gl.pixelStorei( 37440, texture.flipY ); + _gl.pixelStorei( 37441, texture.premultiplyAlpha ); + _gl.pixelStorei( 3317, texture.unpackAlignment ); + _gl.pixelStorei( 37443, 0 ); - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; + const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); + const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); - } + const cubeImage = []; - _width = width; - _height = height; + for ( let i = 0; i < 6; i ++ ) { - _canvas.width = Math.floor( width * _pixelRatio ); - _canvas.height = Math.floor( height * _pixelRatio ); + if ( ! isCompressed && ! isDataTexture ) { - if ( updateStyle !== false ) { + cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize ); - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + } else { - } + cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - this.setViewport( 0, 0, width, height ); + } - }; + cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] ); - this.getDrawingBufferSize = function ( target ) { + } - return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); + const image = cubeImage[ 0 ], + supportsMips = isPowerOfTwo$1( image ) || isWebGL2, + glFormat = utils.convert( texture.format, texture.encoding ), + glType = utils.convert( texture.type ), + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); - }; + const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); + const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); + let levels = getMipLevels( texture, image, supportsMips ); - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { + setTextureParameters( 34067, texture, supportsMips ); - _width = width; - _height = height; + let mipmaps; - _pixelRatio = pixelRatio; + if ( isCompressed ) { - _canvas.width = Math.floor( width * pixelRatio ); - _canvas.height = Math.floor( height * pixelRatio ); + if ( useTexStorage && allocateMemory ) { - this.setViewport( 0, 0, width, height ); + state.texStorage2D( 34067, levels, glInternalFormat, image.width, image.height ); - }; + } - this.getCurrentViewport = function ( target ) { + for ( let i = 0; i < 6; i ++ ) { - return target.copy( _currentViewport ); + mipmaps = cubeImage[ i ].mipmaps; - }; + for ( let j = 0; j < mipmaps.length; j ++ ) { - this.getViewport = function ( target ) { + const mipmap = mipmaps[ j ]; - return target.copy( _viewport ); + if ( texture.format !== RGBAFormat ) { - }; + if ( glFormat !== null ) { - this.setViewport = function ( x, y, width, height ) { + if ( useTexStorage ) { - if ( x.isVector4 ) { + state.compressedTexSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); - _viewport.set( x.x, x.y, x.z, x.w ); + } else { - } else { + state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - _viewport.set( x, y, width, height ); + } - } + } else { - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); + console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); - }; + } - this.getScissor = function ( target ) { + } else { - return target.copy( _scissor ); + if ( useTexStorage ) { - }; + state.texSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); - this.setScissor = function ( x, y, width, height ) { + } else { - if ( x.isVector4 ) { + state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - _scissor.set( x.x, x.y, x.z, x.w ); + } - } else { + } - _scissor.set( x, y, width, height ); + } - } + } - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); + } else { - }; + mipmaps = texture.mipmaps; - this.getScissorTest = function () { + if ( useTexStorage && allocateMemory ) { - return _scissorTest; + // TODO: Uniformly handle mipmap definitions + // Normal textures and compressed cube textures define base level + mips with their mipmap array + // Uncompressed cube textures use their mipmap array only for mips (no base level) - }; + if ( mipmaps.length > 0 ) levels ++; - this.setScissorTest = function ( boolean ) { + state.texStorage2D( 34067, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); - state.setScissorTest( _scissorTest = boolean ); + } - }; + for ( let i = 0; i < 6; i ++ ) { - this.setOpaqueSort = function ( method ) { + if ( isDataTexture ) { - _opaqueSort = method; + if ( useTexStorage ) { - }; + state.texSubImage2D( 34069 + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); - this.setTransparentSort = function ( method ) { + } else { - _transparentSort = method; + state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - }; + } - // Clearing + for ( let j = 0; j < mipmaps.length; j ++ ) { - this.getClearColor = function ( target ) { + const mipmap = mipmaps[ j ]; + const mipmapImage = mipmap.image[ i ].image; - return target.copy( background.getClearColor() ); + if ( useTexStorage ) { - }; + state.texSubImage2D( 34069 + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); - this.setClearColor = function () { + } else { - background.setClearColor.apply( background, arguments ); + state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); - }; + } - this.getClearAlpha = function () { + } - return background.getClearAlpha(); + } else { - }; + if ( useTexStorage ) { - this.setClearAlpha = function () { + state.texSubImage2D( 34069 + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); - background.setClearAlpha.apply( background, arguments ); + } else { - }; + state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); - this.clear = function ( color = true, depth = true, stencil = true ) { + } - let bits = 0; + for ( let j = 0; j < mipmaps.length; j ++ ) { - if ( color ) bits |= 16384; - if ( depth ) bits |= 256; - if ( stencil ) bits |= 1024; + const mipmap = mipmaps[ j ]; - _gl.clear( bits ); + if ( useTexStorage ) { - }; + state.texSubImage2D( 34069 + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); - this.clearColor = function () { + } else { - this.clear( true, false, false ); + state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); - }; + } - this.clearDepth = function () { + } - this.clear( false, true, false ); + } - }; + } - this.clearStencil = function () { + } - this.clear( false, false, true ); + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - }; + // We assume images for cube map have the same size. + generateMipmap( 34067 ); - // + } - this.dispose = function () { + sourceProperties.__version = source.version; - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + if ( texture.onUpdate ) texture.onUpdate( texture ); - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - cubemaps.dispose(); - cubeuvmaps.dispose(); - objects.dispose(); - bindingStates.dispose(); - uniformsGroups.dispose(); - programCache.dispose(); + } - xr.dispose(); + textureProperties.__version = texture.version; - xr.removeEventListener( 'sessionstart', onXRSessionStart ); - xr.removeEventListener( 'sessionend', onXRSessionEnd ); + } - if ( _transmissionRenderTarget ) { + // Render targets - _transmissionRenderTarget.dispose(); - _transmissionRenderTarget = null; + // Setup storage for target texture and bind it to correct framebuffer + function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) { - } + const glFormat = utils.convert( texture.format, texture.encoding ); + const glType = utils.convert( texture.type ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const renderTargetProperties = properties.get( renderTarget ); - animation.stop(); + if ( ! renderTargetProperties.__hasExternalTextures ) { - }; + if ( textureTarget === 32879 || textureTarget === 35866 ) { - // Events + state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null ); - function onContextLost( event ) { + } else { - event.preventDefault(); + state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - console.log( 'THREE.WebGLRenderer: Context Lost.' ); + } - _isContextLost = true; + } - } + state.bindFramebuffer( 36160, framebuffer ); - function onContextRestore( /* event */ ) { + if ( useMultisampledRTT( renderTarget ) ) { - console.log( 'THREE.WebGLRenderer: Context Restored.' ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); - _isContextLost = false; + } else { - const infoAutoReset = info.autoReset; - const shadowMapEnabled = shadowMap.enabled; - const shadowMapAutoUpdate = shadowMap.autoUpdate; - const shadowMapNeedsUpdate = shadowMap.needsUpdate; - const shadowMapType = shadowMap.type; + _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 ); - initGLContext(); + } - info.autoReset = infoAutoReset; - shadowMap.enabled = shadowMapEnabled; - shadowMap.autoUpdate = shadowMapAutoUpdate; - shadowMap.needsUpdate = shadowMapNeedsUpdate; - shadowMap.type = shadowMapType; + state.bindFramebuffer( 36160, null ); } - function onContextCreationError( event ) { - console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); + // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - } + _gl.bindRenderbuffer( 36161, renderbuffer ); - function onMaterialDispose( event ) { + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - const material = event.target; + let glInternalFormat = 33189; - material.removeEventListener( 'dispose', onMaterialDispose ); + if ( isMultisample || useMultisampledRTT( renderTarget ) ) { - deallocateMaterial( material ); + const depthTexture = renderTarget.depthTexture; - } + if ( depthTexture && depthTexture.isDepthTexture ) { - // Buffer deallocation + if ( depthTexture.type === FloatType ) { - function deallocateMaterial( material ) { + glInternalFormat = 36012; - releaseMaterialProgramReferences( material ); + } else if ( depthTexture.type === UnsignedIntType ) { - properties.remove( material ); + glInternalFormat = 33190; - } + } + } - function releaseMaterialProgramReferences( material ) { + const samples = getRenderTargetSamples( renderTarget ); - const programs = properties.get( material ).programs; + if ( useMultisampledRTT( renderTarget ) ) { - if ( programs !== undefined ) { + multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - programs.forEach( function ( program ) { + } else { - programCache.releaseProgram( program ); + _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - } ); + } - if ( material.isShaderMaterial ) { + } else { - programCache.releaseShaderCache( material ); + _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); } - } - - } + _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); - // Buffer rendering + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { + const samples = getRenderTargetSamples( renderTarget ); - if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) + if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); + _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height ); - const program = setProgram( camera, scene, geometry, material, object ); + } else if ( useMultisampledRTT( renderTarget ) ) { - state.setMaterial( material, frontFaceCW ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, 35056, renderTarget.width, renderTarget.height ); - // + } else { - let index = geometry.index; - const position = geometry.attributes.position; + _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); - // + } - if ( index === null ) { - if ( position === undefined || position.count === 0 ) return; + _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); - } else if ( index.count === 0 ) { + } else { - return; + const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - } + for ( let i = 0; i < textures.length; i ++ ) { - // + const texture = textures[ i ]; - let rangeFactor = 1; + const glFormat = utils.convert( texture.format, texture.encoding ); + const glType = utils.convert( texture.type ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const samples = getRenderTargetSamples( renderTarget ); - if ( material.wireframe === true ) { + if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; + _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - } + } else if ( useMultisampledRTT( renderTarget ) ) { - bindingStates.setup( object, material, program, geometry, index ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - let attribute; - let renderer = bufferRenderer; + } else { - if ( index !== null ) { + _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); - attribute = attributes.get( index ); + } - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); + } } - // + _gl.bindRenderbuffer( 36161, null ); - const dataCount = ( index !== null ) ? index.count : position.count; + } - const rangeStart = geometry.drawRange.start * rangeFactor; - const rangeCount = geometry.drawRange.count * rangeFactor; + // Setup resources for a Depth Texture for a FBO (needs an extension) + function setupDepthTexture( framebuffer, renderTarget ) { - const groupStart = group !== null ? group.start * rangeFactor : 0; - const groupCount = group !== null ? group.count * rangeFactor : Infinity; + const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); + if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - const drawStart = Math.max( rangeStart, groupStart ); - const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; + state.bindFramebuffer( 36160, framebuffer ); - const drawCount = Math.max( 0, drawEnd - drawStart + 1 ); + if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { - if ( drawCount === 0 ) return; + throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); - // + } - if ( object.isMesh ) { + // upload an empty depth texture with framebuffer size + if ( ! properties.get( renderTarget.depthTexture ).__webglTexture || + renderTarget.depthTexture.image.width !== renderTarget.width || + renderTarget.depthTexture.image.height !== renderTarget.height ) { - if ( material.wireframe === true ) { + renderTarget.depthTexture.image.width = renderTarget.width; + renderTarget.depthTexture.image.height = renderTarget.height; + renderTarget.depthTexture.needsUpdate = true; - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( 1 ); + } - } else { + setTexture2D( renderTarget.depthTexture, 0 ); - renderer.setMode( 4 ); + const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; + const samples = getRenderTargetSamples( renderTarget ); - } + if ( renderTarget.depthTexture.format === DepthFormat ) { - } else if ( object.isLine ) { + if ( useMultisampledRTT( renderTarget ) ) { - let lineWidth = material.linewidth; + multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 36096, 3553, webglDepthTexture, 0, samples ); - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material + } else { - state.setLineWidth( lineWidth * getTargetPixelRatio() ); + _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); - if ( object.isLineSegments ) { + } - renderer.setMode( 1 ); + } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { - } else if ( object.isLineLoop ) { + if ( useMultisampledRTT( renderTarget ) ) { - renderer.setMode( 2 ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 33306, 3553, webglDepthTexture, 0, samples ); } else { - renderer.setMode( 3 ); + _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); } - } else if ( object.isPoints ) { - - renderer.setMode( 0 ); - - } else if ( object.isSprite ) { + } else { - renderer.setMode( 4 ); + throw new Error( 'Unknown depthTexture format' ); } - if ( object.isInstancedMesh ) { + } - renderer.renderInstances( drawStart, drawCount, object.count ); + // Setup GL resources for a non-texture depth buffer + function setupDepthRenderbuffer( renderTarget ) { - } else if ( geometry.isInstancedBufferGeometry ) { + const renderTargetProperties = properties.get( renderTarget ); + const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount ); + if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) { - renderer.renderInstances( drawStart, drawCount, instanceCount ); + if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); + + setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); } else { - renderer.render( drawStart, drawCount ); + if ( isCube ) { - } + renderTargetProperties.__webglDepthbuffer = []; - }; + for ( let i = 0; i < 6; i ++ ) { - // Compile + state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); + renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); - this.compile = function ( scene, camera ) { + } - function prepare( material, scene, object ) { + } else { - if ( material.transparent === true && material.side === DoubleSide ) { + state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); - material.side = BackSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + } - material.side = FrontSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + } - material.side = DoubleSide; + state.bindFramebuffer( 36160, null ); - } else { + } - getProgram( material, scene, object ); + // rebind framebuffer with external textures + function rebindTextures( renderTarget, colorTexture, depthTexture ) { - } + const renderTargetProperties = properties.get( renderTarget ); - } + if ( colorTexture !== undefined ) { - currentRenderState = renderStates.get( scene ); - currentRenderState.init(); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, 36064, 3553 ); - renderStateStack.push( currentRenderState ); + } - scene.traverseVisible( function ( object ) { + if ( depthTexture !== undefined ) { - if ( object.isLight && object.layers.test( camera.layers ) ) { + setupDepthRenderbuffer( renderTarget ); - currentRenderState.pushLight( object ); + } - if ( object.castShadow ) { + } - currentRenderState.pushShadow( object ); + // Set up GL resources for the render target + function setupRenderTarget( renderTarget ) { - } + const texture = renderTarget.texture; - } + const renderTargetProperties = properties.get( renderTarget ); + const textureProperties = properties.get( texture ); - } ); + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - currentRenderState.setupLights( _this.physicallyCorrectLights ); + if ( renderTarget.isWebGLMultipleRenderTargets !== true ) { - scene.traverse( function ( object ) { + if ( textureProperties.__webglTexture === undefined ) { - const material = object.material; + textureProperties.__webglTexture = _gl.createTexture(); - if ( material ) { + } - if ( Array.isArray( material ) ) { + textureProperties.__version = texture.version; + info.memory.textures ++; - for ( let i = 0; i < material.length; i ++ ) { + } - const material2 = material[ i ]; + const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); + const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); + const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - prepare( material2, scene, object ); + // Setup framebuffer - } + if ( isCube ) { - } else { + renderTargetProperties.__webglFramebuffer = []; - prepare( material, scene, object ); + for ( let i = 0; i < 6; i ++ ) { - } + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); } - } ); - - renderStateStack.pop(); - currentRenderState = null; - - }; + } else { - // Animation Loop + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - let onAnimationFrameCallback = null; + if ( isMultipleRenderTargets ) { - function onAnimationFrame( time ) { + if ( capabilities.drawBuffers ) { - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); + const textures = renderTarget.texture; - } + for ( let i = 0, il = textures.length; i < il; i ++ ) { - function onXRSessionStart() { + const attachmentProperties = properties.get( textures[ i ] ); - animation.stop(); + if ( attachmentProperties.__webglTexture === undefined ) { - } + attachmentProperties.__webglTexture = _gl.createTexture(); - function onXRSessionEnd() { + info.memory.textures ++; - animation.start(); + } - } + } - const animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); + } else { - if ( typeof self !== 'undefined' ) animation.setContext( self ); + console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' ); - this.setAnimationLoop = function ( callback ) { + } - onAnimationFrameCallback = callback; - xr.setAnimationLoop( callback ); + } - ( callback === null ) ? animation.stop() : animation.start(); + if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { - }; + const textures = isMultipleRenderTargets ? texture : [ texture ]; - xr.addEventListener( 'sessionstart', onXRSessionStart ); - xr.addEventListener( 'sessionend', onXRSessionEnd ); + renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); + renderTargetProperties.__webglColorRenderbuffer = []; - // Rendering + state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - this.render = function ( scene, camera ) { + for ( let i = 0; i < textures.length; i ++ ) { - if ( camera !== undefined && camera.isCamera !== true ) { + const texture = textures[ i ]; + renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - } + const glFormat = utils.convert( texture.format, texture.encoding ); + const glType = utils.convert( texture.type ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, renderTarget.isXRRenderTarget === true ); + const samples = getRenderTargetSamples( renderTarget ); + _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - if ( _isContextLost === true ) return; + _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - // update scene graph + } - if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); + _gl.bindRenderbuffer( 36161, null ); - // update camera matrices and frustum + if ( renderTarget.depthBuffer ) { - if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); + renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); - if ( xr.enabled === true && xr.isPresenting === true ) { + } - if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); + state.bindFramebuffer( 36160, null ); - camera = xr.getCamera(); // use XR camera for rendering + } } - // - if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); + // Setup color buffer - currentRenderState = renderStates.get( scene, renderStateStack.length ); - currentRenderState.init(); + if ( isCube ) { - renderStateStack.push( currentRenderState ); + state.bindTexture( 34067, textureProperties.__webglTexture ); + setTextureParameters( 34067, texture, supportsMips ); - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix ); + for ( let i = 0; i < 6; i ++ ) { - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, 36064, 34069 + i ); - currentRenderList = renderLists.get( scene, renderListStack.length ); - currentRenderList.init(); + } - renderListStack.push( currentRenderList ); + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - projectObject( scene, camera, 0, _this.sortObjects ); + generateMipmap( 34067 ); - currentRenderList.finish(); + } - if ( _this.sortObjects === true ) { + state.unbindTexture(); - currentRenderList.sort( _opaqueSort, _transparentSort ); + } else if ( isMultipleRenderTargets ) { - } + const textures = renderTarget.texture; - // + for ( let i = 0, il = textures.length; i < il; i ++ ) { - if ( _clippingEnabled === true ) clipping.beginShadows(); + const attachment = textures[ i ]; + const attachmentProperties = properties.get( attachment ); - const shadowsArray = currentRenderState.state.shadowsArray; + state.bindTexture( 3553, attachmentProperties.__webglTexture ); + setTextureParameters( 3553, attachment, supportsMips ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, 36064 + i, 3553 ); - shadowMap.render( shadowsArray, scene, camera ); + if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { - if ( _clippingEnabled === true ) clipping.endShadows(); + generateMipmap( 3553 ); - // + } - if ( this.info.autoReset === true ) this.info.reset(); + } - // + state.unbindTexture(); - background.render( currentRenderList, scene ); + } else { - // render scene + let glTextureType = 3553; - currentRenderState.setupLights( _this.physicallyCorrectLights ); + if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { - if ( camera.isArrayCamera ) { + if ( isWebGL2 ) { - const cameras = camera.cameras; + glTextureType = renderTarget.isWebGL3DRenderTarget ? 32879 : 35866; - for ( let i = 0, l = cameras.length; i < l; i ++ ) { + } else { - const camera2 = cameras[ i ]; + console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' ); - renderScene( currentRenderList, scene, camera2, camera2.viewport ); + } } - } else { + state.bindTexture( glTextureType, textureProperties.__webglTexture ); + setTextureParameters( glTextureType, texture, supportsMips ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, 36064, glTextureType ); - renderScene( currentRenderList, scene, camera ); + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - } + generateMipmap( glTextureType ); - // + } - if ( _currentRenderTarget !== null ) { + state.unbindTexture(); - // resolve multisample renderbuffers to a single-sample texture if necessary + } - textures.updateMultisampleRenderTarget( _currentRenderTarget ); + // Setup depth and stencil buffers - // Generate mipmap if we're using any kind of mipmap filtering + if ( renderTarget.depthBuffer ) { - textures.updateRenderTargetMipmap( _currentRenderTarget ); + setupDepthRenderbuffer( renderTarget ); } - // - - if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); + } - // _gl.finish(); + function updateRenderTargetMipmap( renderTarget ) { - bindingStates.resetDefaultState(); - _currentMaterialId = - 1; - _currentCamera = null; + const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - renderStateStack.pop(); + const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - if ( renderStateStack.length > 0 ) { + for ( let i = 0, il = textures.length; i < il; i ++ ) { - currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; + const texture = textures[ i ]; - } else { + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - currentRenderState = null; + const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553; + const webglTexture = properties.get( texture ).__webglTexture; - } + state.bindTexture( target, webglTexture ); + generateMipmap( target ); + state.unbindTexture(); - renderListStack.pop(); + } - if ( renderListStack.length > 0 ) { + } - currentRenderList = renderListStack[ renderListStack.length - 1 ]; + } - } else { + function updateMultisampleRenderTarget( renderTarget ) { - currentRenderList = null; + if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { - } - - }; - - function projectObject( object, camera, groupOrder, sortObjects ) { + const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; + const width = renderTarget.width; + const height = renderTarget.height; + let mask = 16384; + const invalidationArray = []; + const depthStyle = renderTarget.stencilBuffer ? 33306 : 36096; + const renderTargetProperties = properties.get( renderTarget ); + const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); - if ( object.visible === false ) return; + // If MRT we need to remove FBO attachments + if ( isMultipleRenderTargets ) { - const visible = object.layers.test( camera.layers ); + for ( let i = 0; i < textures.length; i ++ ) { - if ( visible ) { + state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); + _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, null ); - if ( object.isGroup ) { + state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( 36009, 36064 + i, 3553, null, 0 ); - groupOrder = object.renderOrder; + } - } else if ( object.isLOD ) { + } - if ( object.autoUpdate === true ) object.update( camera ); + state.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer ); - } else if ( object.isLight ) { + for ( let i = 0; i < textures.length; i ++ ) { - currentRenderState.pushLight( object ); + invalidationArray.push( 36064 + i ); - if ( object.castShadow ) { + if ( renderTarget.depthBuffer ) { - currentRenderState.pushShadow( object ); + invalidationArray.push( depthStyle ); } - } else if ( object.isSprite ) { + const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false; - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { + if ( ignoreDepthValues === false ) { - if ( sortObjects ) { + if ( renderTarget.depthBuffer ) mask |= 256; + if ( renderTarget.stencilBuffer ) mask |= 1024; - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + } - } + if ( isMultipleRenderTargets ) { - const geometry = objects.update( object ); - const material = object.material; + _gl.framebufferRenderbuffer( 36008, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - if ( material.visible ) { + } - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + if ( ignoreDepthValues === true ) { - } + _gl.invalidateFramebuffer( 36008, [ depthStyle ] ); + _gl.invalidateFramebuffer( 36009, [ depthStyle ] ); } - } else if ( object.isMesh || object.isLine || object.isPoints ) { + if ( isMultipleRenderTargets ) { - if ( object.isSkinnedMesh ) { + const webglTexture = properties.get( textures[ i ] ).__webglTexture; + _gl.framebufferTexture2D( 36009, 36064, 3553, webglTexture, 0 ); - // update skeleton only once in a frame + } - if ( object.skeleton.frame !== info.render.frame ) { + _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 ); - object.skeleton.update(); - object.skeleton.frame = info.render.frame; + if ( supportsInvalidateFramebuffer ) { - } + _gl.invalidateFramebuffer( 36008, invalidationArray ); } - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - if ( sortObjects ) { + } - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + state.bindFramebuffer( 36008, null ); + state.bindFramebuffer( 36009, null ); - } + // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments + if ( isMultipleRenderTargets ) { - const geometry = objects.update( object ); - const material = object.material; + for ( let i = 0; i < textures.length; i ++ ) { - if ( Array.isArray( material ) ) { + state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); + _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - const groups = geometry.groups; + const webglTexture = properties.get( textures[ i ] ).__webglTexture; - for ( let i = 0, l = groups.length; i < l; i ++ ) { + state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( 36009, 36064 + i, 3553, webglTexture, 0 ); - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; + } - if ( groupMaterial && groupMaterial.visible ) { + } - currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); + state.bindFramebuffer( 36009, renderTargetProperties.__webglMultisampledFramebuffer ); - } + } - } + } - } else if ( material.visible ) { + function getRenderTargetSamples( renderTarget ) { - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + return Math.min( maxSamples, renderTarget.samples ); - } + } - } + function useMultisampledRTT( renderTarget ) { - } + const renderTargetProperties = properties.get( renderTarget ); - } + return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false; - const children = object.children; + } - for ( let i = 0, l = children.length; i < l; i ++ ) { + function updateVideoTexture( texture ) { - projectObject( children[ i ], camera, groupOrder, sortObjects ); + const frame = info.render.frame; - } + // Check the last frame we updated the VideoTexture - } + if ( _videoTextures.get( texture ) !== frame ) { - function renderScene( currentRenderList, scene, camera, viewport ) { + _videoTextures.set( texture, frame ); + texture.update(); - const opaqueObjects = currentRenderList.opaque; - const transmissiveObjects = currentRenderList.transmissive; - const transparentObjects = currentRenderList.transparent; + } - currentRenderState.setupLightsView( camera ); + } - if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera ); + function verifyColorSpace( texture, image ) { - if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); + const encoding = texture.encoding; + const format = texture.format; + const type = texture.type; - if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); - if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); - if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); + if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; - // Ensure depth buffer writing is enabled so it can be cleared on next render + if ( encoding !== LinearEncoding ) { - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); + // sRGB - state.setPolygonOffset( false ); + if ( encoding === sRGBEncoding ) { - } + if ( isWebGL2 === false ) { - function renderTransmissionPass( opaqueObjects, scene, camera ) { + // in WebGL 1, try to use EXT_sRGB extension and unsized formats - const isWebGL2 = capabilities.isWebGL2; + if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) { - if ( _transmissionRenderTarget === null ) { + texture.format = _SRGBAFormat; - _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { - generateMipmaps: true, - type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, - minFilter: LinearMipmapLinearFilter, - samples: ( isWebGL2 && _antialias === true ) ? 4 : 0 - } ); + // it's not possible to generate mips in WebGL 1 with this extension - } + texture.minFilter = LinearFilter; + texture.generateMipmaps = false; - _this.getDrawingBufferSize( _vector2 ); + } else { - if ( isWebGL2 ) { + // slow fallback (CPU decode) - _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); + image = ImageUtils.sRGBToLinear( image ); - } else { + } - _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); + } else { - } + // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format - // + if ( format !== RGBAFormat || type !== UnsignedByteType ) { - const currentRenderTarget = _this.getRenderTarget(); - _this.setRenderTarget( _transmissionRenderTarget ); - _this.clear(); + console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' ); - // Turn off the features which can affect the frag color for opaque objects pass. - // Otherwise they are applied twice in opaque objects pass and transmission objects pass. - const currentToneMapping = _this.toneMapping; - _this.toneMapping = NoToneMapping; + } - renderObjects( opaqueObjects, scene, camera ); + } - _this.toneMapping = currentToneMapping; + } else { - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); + console.error( 'THREE.WebGLTextures: Unsupported texture encoding:', encoding ); - _this.setRenderTarget( currentRenderTarget ); + } - } + } - function renderObjects( renderList, scene, camera ) { + return image; - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; + } - for ( let i = 0, l = renderList.length; i < l; i ++ ) { + // - const renderItem = renderList[ i ]; + this.allocateTextureUnit = allocateTextureUnit; + this.resetTextureUnits = resetTextureUnits; - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = overrideMaterial === null ? renderItem.material : overrideMaterial; - const group = renderItem.group; + this.setTexture2D = setTexture2D; + this.setTexture2DArray = setTexture2DArray; + this.setTexture3D = setTexture3D; + this.setTextureCube = setTextureCube; + this.rebindTextures = rebindTextures; + this.setupRenderTarget = setupRenderTarget; + this.updateRenderTargetMipmap = updateRenderTargetMipmap; + this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; + this.setupDepthRenderbuffer = setupDepthRenderbuffer; + this.setupFrameBufferTexture = setupFrameBufferTexture; + this.useMultisampledRTT = useMultisampledRTT; - if ( object.layers.test( camera.layers ) ) { + } - renderObject( object, scene, camera, geometry, material, group ); + function WebGLUtils( gl, extensions, capabilities ) { - } + const isWebGL2 = capabilities.isWebGL2; - } + function convert( p, encoding = null ) { - } + let extension; - function renderObject( object, scene, camera, geometry, material, group ) { + if ( p === UnsignedByteType ) return 5121; + if ( p === UnsignedShort4444Type ) return 32819; + if ( p === UnsignedShort5551Type ) return 32820; - object.onBeforeRender( _this, scene, camera, geometry, material, group ); + if ( p === ByteType ) return 5120; + if ( p === ShortType ) return 5122; + if ( p === UnsignedShortType ) return 5123; + if ( p === IntType ) return 5124; + if ( p === UnsignedIntType ) return 5125; + if ( p === FloatType ) return 5126; - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + if ( p === HalfFloatType ) { - material.onBeforeRender( _this, scene, camera, geometry, object, group ); + if ( isWebGL2 ) return 5131; - if ( material.transparent === true && material.side === DoubleSide ) { + extension = extensions.get( 'OES_texture_half_float' ); - material.side = BackSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + if ( extension !== null ) { - material.side = FrontSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + return extension.HALF_FLOAT_OES; - material.side = DoubleSide; + } else { - } else { + return null; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + } } - object.onAfterRender( _this, scene, camera, geometry, material, group ); + if ( p === AlphaFormat ) return 6406; + if ( p === RGBAFormat ) return 6408; + if ( p === LuminanceFormat ) return 6409; + if ( p === LuminanceAlphaFormat ) return 6410; + if ( p === DepthFormat ) return 6402; + if ( p === DepthStencilFormat ) return 34041; + if ( p === RedFormat ) return 6403; - } + // @deprecated since r137 - function getProgram( material, scene, object ) { + if ( p === RGBFormat ) { - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + console.warn( 'THREE.WebGLRenderer: THREE.RGBFormat has been removed. Use THREE.RGBAFormat instead. https://github.com/mrdoob/three.js/pull/23228' ); + return 6408; - const materialProperties = properties.get( material ); + } - const lights = currentRenderState.state.lights; - const shadowsArray = currentRenderState.state.shadowsArray; + // WebGL 1 sRGB fallback - const lightsStateVersion = lights.state.version; + if ( p === _SRGBAFormat ) { - const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); - const programCacheKey = programCache.getProgramCacheKey( parameters ); + extension = extensions.get( 'EXT_sRGB' ); - let programs = materialProperties.programs; + if ( extension !== null ) { - // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change + return extension.SRGB_ALPHA_EXT; - materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; - materialProperties.fog = scene.fog; - materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); + } else { - if ( programs === undefined ) { + return null; - // new material + } - material.addEventListener( 'dispose', onMaterialDispose ); + } - programs = new Map(); - materialProperties.programs = programs; + // WebGL2 formats. - } + if ( p === RedIntegerFormat ) return 36244; + if ( p === RGFormat ) return 33319; + if ( p === RGIntegerFormat ) return 33320; + if ( p === RGBAIntegerFormat ) return 36249; - let program = programs.get( programCacheKey ); + // S3TC - if ( program !== undefined ) { + if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - // early out if program and light state is identical + if ( encoding === sRGBEncoding ) { - if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { + extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); - updateCommonMaterialProperties( material, parameters ); + if ( extension !== null ) { - return program; + if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - } + } else { - } else { + return null; - parameters.uniforms = programCache.getUniforms( material ); + } - material.onBuild( object, parameters, _this ); + } else { - material.onBeforeCompile( parameters, _this ); + extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - program = programCache.acquireProgram( parameters, programCacheKey ); - programs.set( programCacheKey, program ); + if ( extension !== null ) { - materialProperties.uniforms = parameters.uniforms; + if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - } + } else { - const uniforms = materialProperties.uniforms; + return null; - if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { + } - uniforms.clippingPlanes = clipping.uniform; + } } - updateCommonMaterialProperties( material, parameters ); - - // store the light setup it was created for + // PVRTC - materialProperties.needsLights = materialNeedsLights( material ); - materialProperties.lightsStateVersion = lightsStateVersion; + if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { - if ( materialProperties.needsLights ) { + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - // wire up the material to this renderer's lighting state + if ( extension !== null ) { - uniforms.ambientLightColor.value = lights.state.ambient; - uniforms.lightProbe.value = lights.state.probe; - uniforms.directionalLights.value = lights.state.directional; - uniforms.directionalLightShadows.value = lights.state.directionalShadow; - uniforms.spotLights.value = lights.state.spot; - uniforms.spotLightShadows.value = lights.state.spotShadow; - uniforms.rectAreaLights.value = lights.state.rectArea; - uniforms.ltc_1.value = lights.state.rectAreaLTC1; - uniforms.ltc_2.value = lights.state.rectAreaLTC2; - uniforms.pointLights.value = lights.state.point; - uniforms.pointLightShadows.value = lights.state.pointShadow; - uniforms.hemisphereLights.value = lights.state.hemi; + if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; - uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; - uniforms.spotShadowMap.value = lights.state.spotShadowMap; - uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; - uniforms.spotLightMap.value = lights.state.spotLightMap; - uniforms.pointShadowMap.value = lights.state.pointShadowMap; - uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; - // TODO (abelnation): add area lights shadow info to uniforms + } else { - } + return null; - const progUniforms = program.getUniforms(); - const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); + } - materialProperties.currentProgram = program; - materialProperties.uniformsList = uniformsList; + } - return program; + // ETC1 - } + if ( p === RGB_ETC1_Format ) { - function updateCommonMaterialProperties( material, parameters ) { + extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); - const materialProperties = properties.get( material ); + if ( extension !== null ) { - materialProperties.outputEncoding = parameters.outputEncoding; - materialProperties.instancing = parameters.instancing; - materialProperties.skinning = parameters.skinning; - materialProperties.morphTargets = parameters.morphTargets; - materialProperties.morphNormals = parameters.morphNormals; - materialProperties.morphColors = parameters.morphColors; - materialProperties.morphTargetsCount = parameters.morphTargetsCount; - materialProperties.numClippingPlanes = parameters.numClippingPlanes; - materialProperties.numIntersection = parameters.numClipIntersection; - materialProperties.vertexAlphas = parameters.vertexAlphas; - materialProperties.vertexTangents = parameters.vertexTangents; - materialProperties.toneMapping = parameters.toneMapping; + return extension.COMPRESSED_RGB_ETC1_WEBGL; - } + } else { - function setProgram( camera, scene, geometry, material, object ) { + return null; - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + } - textures.resetTextureUnits(); + } - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.encoding : LinearEncoding ); - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; - const vertexTangents = !! material.normalMap && !! geometry.attributes.tangent; - const morphTargets = !! geometry.morphAttributes.position; - const morphNormals = !! geometry.morphAttributes.normal; - const morphColors = !! geometry.morphAttributes.color; - const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping; + // ETC2 - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { - const materialProperties = properties.get( material ); - const lights = currentRenderState.state.lights; + extension = extensions.get( 'WEBGL_compressed_texture_etc' ); - if ( _clippingEnabled === true ) { + if ( extension !== null ) { - if ( _localClippingEnabled === true || camera !== _currentCamera ) { + if ( p === RGB_ETC2_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; + if ( p === RGBA_ETC2_EAC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; - const useCache = - camera === _currentCamera && - material.id === _currentMaterialId; + } else { - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - clipping.setState( material, camera, useCache ); + return null; } } - // + // ASTC - let needsProgramChange = false; + if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || + p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || + p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || + p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || + p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) { - if ( material.version === materialProperties.__version ) { + extension = extensions.get( 'WEBGL_compressed_texture_astc' ); - if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { + if ( extension !== null ) { - needsProgramChange = true; + if ( p === RGBA_ASTC_4x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; + if ( p === RGBA_ASTC_5x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; + if ( p === RGBA_ASTC_5x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; + if ( p === RGBA_ASTC_6x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; + if ( p === RGBA_ASTC_6x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; + if ( p === RGBA_ASTC_8x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; + if ( p === RGBA_ASTC_8x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; + if ( p === RGBA_ASTC_8x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; + if ( p === RGBA_ASTC_10x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; + if ( p === RGBA_ASTC_10x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; + if ( p === RGBA_ASTC_10x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; + if ( p === RGBA_ASTC_10x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; + if ( p === RGBA_ASTC_12x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; + if ( p === RGBA_ASTC_12x12_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; - } else if ( materialProperties.outputEncoding !== encoding ) { + } else { - needsProgramChange = true; + return null; - } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { + } - needsProgramChange = true; + } - } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { + // BPTC - needsProgramChange = true; + if ( p === RGBA_BPTC_Format ) { - } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { + extension = extensions.get( 'EXT_texture_compression_bptc' ); - needsProgramChange = true; + if ( extension !== null ) { - } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { + if ( p === RGBA_BPTC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; - needsProgramChange = true; + } else { - } else if ( materialProperties.envMap !== envMap ) { - - needsProgramChange = true; - - } else if ( material.fog === true && materialProperties.fog !== fog ) { + return null; - needsProgramChange = true; + } - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== clipping.numPlanes || - materialProperties.numIntersection !== clipping.numIntersection ) ) { + } - needsProgramChange = true; + // - } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { + if ( p === UnsignedInt248Type ) { - needsProgramChange = true; + if ( isWebGL2 ) return 34042; - } else if ( materialProperties.vertexTangents !== vertexTangents ) { + extension = extensions.get( 'WEBGL_depth_texture' ); - needsProgramChange = true; + if ( extension !== null ) { - } else if ( materialProperties.morphTargets !== morphTargets ) { + return extension.UNSIGNED_INT_24_8_WEBGL; - needsProgramChange = true; + } else { - } else if ( materialProperties.morphNormals !== morphNormals ) { + return null; - needsProgramChange = true; + } - } else if ( materialProperties.morphColors !== morphColors ) { + } - needsProgramChange = true; + // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) - } else if ( materialProperties.toneMapping !== toneMapping ) { + return ( gl[ p ] !== undefined ) ? gl[ p ] : null; - needsProgramChange = true; + } - } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { + return { convert: convert }; - needsProgramChange = true; + } - } + class ArrayCamera extends PerspectiveCamera { - } else { + constructor( array = [] ) { - needsProgramChange = true; - materialProperties.__version = material.version; + super(); - } + this.isArrayCamera = true; - // + this.cameras = array; - let program = materialProperties.currentProgram; + } - if ( needsProgramChange === true ) { + } - program = getProgram( material, scene, object ); + class Group extends Object3D { - } + constructor() { - let refreshProgram = false; - let refreshMaterial = false; - let refreshLights = false; + super(); - const p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.uniforms; + this.isGroup = true; - if ( state.useProgram( program.program ) ) { + this.type = 'Group'; - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; + } - } + } - if ( material.id !== _currentMaterialId ) { + const _moveEvent = { type: 'move' }; - _currentMaterialId = material.id; + class WebXRController { - refreshMaterial = true; + constructor() { - } + this._targetRay = null; + this._grip = null; + this._hand = null; - if ( refreshProgram || _currentCamera !== camera ) { + } - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + getHandSpace() { - if ( capabilities.logarithmicDepthBuffer ) { + if ( this._hand === null ) { - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); + this._hand = new Group(); + this._hand.matrixAutoUpdate = false; + this._hand.visible = false; - } + this._hand.joints = {}; + this._hand.inputState = { pinching: false }; - if ( _currentCamera !== camera ) { + } - _currentCamera = camera; + return this._hand; - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: + } - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done + getTargetRaySpace() { - } + if ( this._targetRay === null ) { - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + this._targetRay = new Group(); + this._targetRay.matrixAutoUpdate = false; + this._targetRay.visible = false; + this._targetRay.hasLinearVelocity = false; + this._targetRay.linearVelocity = new Vector3(); + this._targetRay.hasAngularVelocity = false; + this._targetRay.angularVelocity = new Vector3(); - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshStandardMaterial || - material.envMap ) { + } - const uCamPos = p_uniforms.map.cameraPosition; + return this._targetRay; - if ( uCamPos !== undefined ) { + } - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); + getGripSpace() { - } + if ( this._grip === null ) { - } + this._grip = new Group(); + this._grip.matrixAutoUpdate = false; + this._grip.visible = false; + this._grip.hasLinearVelocity = false; + this._grip.linearVelocity = new Vector3(); + this._grip.hasAngularVelocity = false; + this._grip.angularVelocity = new Vector3(); - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial ) { + } - p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); + return this._grip; - } + } - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.isShadowMaterial || - object.isSkinnedMesh ) { + dispatchEvent( event ) { - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); + if ( this._targetRay !== null ) { - } + this._targetRay.dispatchEvent( event ); } - // skinning and morph target uniforms must be set even if material didn't change - // auto-setting of texture unit for bone and morph texture must go before other textures - // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures + if ( this._grip !== null ) { - if ( object.isSkinnedMesh ) { + this._grip.dispatchEvent( event ); - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); + } - const skeleton = object.skeleton; + if ( this._hand !== null ) { - if ( skeleton ) { + this._hand.dispatchEvent( event ); - if ( capabilities.floatVertexTextures ) { + } - if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); + return this; - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); + } - } else { + disconnect( inputSource ) { - console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); + this.dispatchEvent( { type: 'disconnected', data: inputSource } ); - } + if ( this._targetRay !== null ) { - } + this._targetRay.visible = false; } - const morphAttributes = geometry.morphAttributes; - - if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { + if ( this._grip !== null ) { - morphtargets.update( object, geometry, material, program ); + this._grip.visible = false; } - if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { + if ( this._hand !== null ) { - materialProperties.receiveShadow = object.receiveShadow; - p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); + this._hand.visible = false; } - // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 - - if ( material.isMeshGouraudMaterial && material.envMap !== null ) { - - m_uniforms.envMap.value = envMap; - - m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; + return this; - } + } - if ( refreshMaterial ) { + update( inputSource, frame, referenceSpace ) { - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); + let inputPose = null; + let gripPose = null; + let handPose = null; - if ( materialProperties.needsLights ) { + const targetRay = this._targetRay; + const grip = this._grip; + const hand = this._hand; - // the current material requires lighting info + if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) { - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required + if ( hand && inputSource.hand ) { - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); + handPose = true; - } + for ( const inputjoint of inputSource.hand.values() ) { - // refresh uniforms common to several materials + // Update the joints groups with the XRJoint poses + const jointPose = frame.getJointPose( inputjoint, referenceSpace ); - if ( fog && material.fog === true ) { + if ( hand.joints[ inputjoint.jointName ] === undefined ) { - materials.refreshFogUniforms( m_uniforms, fog ); + // The transform of this joint will be updated with the joint pose on each frame + const joint = new Group(); + joint.matrixAutoUpdate = false; + joint.visible = false; + hand.joints[ inputjoint.jointName ] = joint; + // ?? + hand.add( joint ); - } + } - materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); + const joint = hand.joints[ inputjoint.jointName ]; - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); + if ( jointPose !== null ) { - } + joint.matrix.fromArray( jointPose.transform.matrix ); + joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); + joint.jointRadius = jointPose.radius; - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { + } - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - material.uniformsNeedUpdate = false; + joint.visible = jointPose !== null; - } + } - if ( material.isSpriteMaterial ) { + // Custom events - p_uniforms.setValue( _gl, 'center', object.center ); + // Check pinchz + const indexTip = hand.joints[ 'index-finger-tip' ]; + const thumbTip = hand.joints[ 'thumb-tip' ]; + const distance = indexTip.position.distanceTo( thumbTip.position ); - } + const distanceToPinch = 0.02; + const threshold = 0.005; - // common matrices + if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); + hand.inputState.pinching = false; + this.dispatchEvent( { + type: 'pinchend', + handedness: inputSource.handedness, + target: this + } ); - // UBOs + } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { - if ( material.isShaderMaterial || material.isRawShaderMaterial ) { + hand.inputState.pinching = true; + this.dispatchEvent( { + type: 'pinchstart', + handedness: inputSource.handedness, + target: this + } ); - const groups = material.uniformsGroups; + } - for ( let i = 0, l = groups.length; i < l; i ++ ) { + } else { - if ( capabilities.isWebGL2 ) { + if ( grip !== null && inputSource.gripSpace ) { - const group = groups[ i ]; + gripPose = frame.getPose( inputSource.gripSpace, referenceSpace ); - uniformsGroups.update( group, program ); - uniformsGroups.bind( group, program ); + if ( gripPose !== null ) { - } else { + grip.matrix.fromArray( gripPose.transform.matrix ); + grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); - console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); + if ( gripPose.linearVelocity ) { - } + grip.hasLinearVelocity = true; + grip.linearVelocity.copy( gripPose.linearVelocity ); - } + } else { - } + grip.hasLinearVelocity = false; - return program; + } - } + if ( gripPose.angularVelocity ) { - // If uniforms are marked as clean, they don't need to be loaded to the GPU. + grip.hasAngularVelocity = true; + grip.angularVelocity.copy( gripPose.angularVelocity ); - function markUniformsLightsNeedsUpdate( uniforms, value ) { + } else { - uniforms.ambientLightColor.needsUpdate = value; - uniforms.lightProbe.needsUpdate = value; + grip.hasAngularVelocity = false; - uniforms.directionalLights.needsUpdate = value; - uniforms.directionalLightShadows.needsUpdate = value; - uniforms.pointLights.needsUpdate = value; - uniforms.pointLightShadows.needsUpdate = value; - uniforms.spotLights.needsUpdate = value; - uniforms.spotLightShadows.needsUpdate = value; - uniforms.rectAreaLights.needsUpdate = value; - uniforms.hemisphereLights.needsUpdate = value; + } - } + } - function materialNeedsLights( material ) { + } - return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || - material.isMeshStandardMaterial || material.isShadowMaterial || - ( material.isShaderMaterial && material.lights === true ); + } - } + if ( targetRay !== null ) { - this.getActiveCubeFace = function () { + inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); - return _currentActiveCubeFace; + // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it + if ( inputPose === null && gripPose !== null ) { - }; + inputPose = gripPose; - this.getActiveMipmapLevel = function () { + } - return _currentActiveMipmapLevel; + if ( inputPose !== null ) { - }; + targetRay.matrix.fromArray( inputPose.transform.matrix ); + targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); - this.getRenderTarget = function () { + if ( inputPose.linearVelocity ) { - return _currentRenderTarget; + targetRay.hasLinearVelocity = true; + targetRay.linearVelocity.copy( inputPose.linearVelocity ); - }; + } else { - this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { + targetRay.hasLinearVelocity = false; - properties.get( renderTarget.texture ).__webglTexture = colorTexture; - properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; + } - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__hasExternalTextures = true; + if ( inputPose.angularVelocity ) { - if ( renderTargetProperties.__hasExternalTextures ) { + targetRay.hasAngularVelocity = true; + targetRay.angularVelocity.copy( inputPose.angularVelocity ); - renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; + } else { - if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { + targetRay.hasAngularVelocity = false; - // The multisample_render_to_texture extension doesn't work properly if there - // are midframe flushes and an external depth buffer. Disable use of the extension. - if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { + } - console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); - renderTargetProperties.__useRenderToTexture = false; + this.dispatchEvent( _moveEvent ); } } + } - }; + if ( targetRay !== null ) { - this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { + targetRay.visible = ( inputPose !== null ); - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__webglFramebuffer = defaultFramebuffer; - renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; + } - }; + if ( grip !== null ) { - this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { + grip.visible = ( gripPose !== null ); - _currentRenderTarget = renderTarget; - _currentActiveCubeFace = activeCubeFace; - _currentActiveMipmapLevel = activeMipmapLevel; + } - let useDefaultFramebuffer = true; + if ( hand !== null ) { - if ( renderTarget ) { + hand.visible = ( handPose !== null ); - const renderTargetProperties = properties.get( renderTarget ); + } - if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { + return this; - // We need to make sure to rebind the framebuffer. - state.bindFramebuffer( 36160, null ); - useDefaultFramebuffer = false; + } - } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { + } - textures.setupRenderTarget( renderTarget ); + class DepthTexture extends Texture { - } else if ( renderTargetProperties.__hasExternalTextures ) { + constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - // Color and depth texture must be rebound in order for the swapchain to update. - textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); + format = format !== undefined ? format : DepthFormat; - } + if ( format !== DepthFormat && format !== DepthStencilFormat ) { + + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); } - let framebuffer = null; - let isCube = false; - let isRenderTarget3D = false; + if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; + if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - if ( renderTarget ) { + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - const texture = renderTarget.texture; + this.isDepthTexture = true; - if ( texture.isData3DTexture || texture.isDataArrayTexture ) { + this.image = { width: width, height: height }; - isRenderTarget3D = true; + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - } + this.flipY = false; + this.generateMipmaps = false; - const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; + } - if ( renderTarget.isWebGLCubeRenderTarget ) { - framebuffer = __webglFramebuffer[ activeCubeFace ]; - isCube = true; + } - } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { + class WebXRManager extends EventDispatcher { - framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; + constructor( renderer, gl ) { - } else { + super(); - framebuffer = __webglFramebuffer; + const scope = this; - } + let session = null; + let framebufferScaleFactor = 1.0; - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; + let referenceSpace = null; + let referenceSpaceType = 'local-floor'; + let customReferenceSpace = null; - } else { + let pose = null; + let glBinding = null; + let glProjLayer = null; + let glBaseLayer = null; + let xrFrame = null; + const attributes = gl.getContextAttributes(); + let initialRenderTarget = null; + let newRenderTarget = null; - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); - _currentScissorTest = _scissorTest; + const controllers = []; + const controllerInputSources = []; - } + // - const framebufferBound = state.bindFramebuffer( 36160, framebuffer ); + const cameraL = new PerspectiveCamera(); + cameraL.layers.enable( 1 ); + cameraL.viewport = new Vector4(); - if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { + const cameraR = new PerspectiveCamera(); + cameraR.layers.enable( 2 ); + cameraR.viewport = new Vector4(); - state.drawBuffers( renderTarget, framebuffer ); + const cameras = [ cameraL, cameraR ]; - } + const cameraVR = new ArrayCamera(); + cameraVR.layers.enable( 1 ); + cameraVR.layers.enable( 2 ); - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); + let _currentDepthNear = null; + let _currentDepthFar = null; - if ( isCube ) { + // - const textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); + this.cameraAutoUpdate = true; + this.enabled = false; - } else if ( isRenderTarget3D ) { + this.isPresenting = false; - const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( 36160, 36064, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); + this.getController = function ( index ) { - } + let controller = controllers[ index ]; - _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings + if ( controller === undefined ) { - }; + controller = new WebXRController(); + controllers[ index ] = controller; - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { + } - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { + return controller.getTargetRaySpace(); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + }; - } + this.getControllerGrip = function ( index ) { - let framebuffer = properties.get( renderTarget ).__webglFramebuffer; + let controller = controllers[ index ]; - if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { + if ( controller === undefined ) { - framebuffer = framebuffer[ activeCubeFaceIndex ]; + controller = new WebXRController(); + controllers[ index ] = controller; - } + } - if ( framebuffer ) { + return controller.getGripSpace(); - state.bindFramebuffer( 36160, framebuffer ); + }; - try { + this.getHand = function ( index ) { - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; + let controller = controllers[ index ]; - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { + if ( controller === undefined ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; + controller = new WebXRController(); + controllers[ index ] = controller; - } + } - const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); + return controller.getHandSpace(); - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! halfFloatSupportedByExt ) { + }; - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; + // - } + function onSessionEvent( event ) { - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + const controllerIndex = controllerInputSources.indexOf( event.inputSource ); - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + if ( controllerIndex === - 1 ) { - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); + return; - } + } - } finally { + const controller = controllers[ controllerIndex ]; - // restore framebuffer of current render target if necessary + if ( controller !== undefined ) { - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( 36160, framebuffer ); + controller.dispatchEvent( { type: event.type, data: event.inputSource } ); } } - }; - - this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { + function onSessionEnd() { - const levelScale = Math.pow( 2, - level ); - const width = Math.floor( texture.image.width * levelScale ); - const height = Math.floor( texture.image.height * levelScale ); + session.removeEventListener( 'select', onSessionEvent ); + session.removeEventListener( 'selectstart', onSessionEvent ); + session.removeEventListener( 'selectend', onSessionEvent ); + session.removeEventListener( 'squeeze', onSessionEvent ); + session.removeEventListener( 'squeezestart', onSessionEvent ); + session.removeEventListener( 'squeezeend', onSessionEvent ); + session.removeEventListener( 'end', onSessionEnd ); + session.removeEventListener( 'inputsourceschange', onInputSourcesChange ); - textures.setTexture2D( texture, 0 ); + for ( let i = 0; i < controllers.length; i ++ ) { - _gl.copyTexSubImage2D( 3553, level, 0, 0, position.x, position.y, width, height ); + const inputSource = controllerInputSources[ i ]; - state.unbindTexture(); + if ( inputSource === null ) continue; - }; + controllerInputSources[ i ] = null; - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { + controllers[ i ].disconnect( inputSource ); - const width = srcTexture.image.width; - const height = srcTexture.image.height; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); + } - textures.setTexture2D( dstTexture, 0 ); + _currentDepthNear = null; + _currentDepthFar = null; - // As another texture upload may have changed pixelStorei - // parameters, make sure they are correct for the dstTexture - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + // restore framebuffer/rendering state - if ( srcTexture.isDataTexture ) { + renderer.setRenderTarget( initialRenderTarget ); - _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); + glBaseLayer = null; + glProjLayer = null; + glBinding = null; + session = null; + newRenderTarget = null; - } else { + // - if ( srcTexture.isCompressedTexture ) { + animation.stop(); - _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); + scope.isPresenting = false; - } else { + scope.dispatchEvent( { type: 'sessionend' } ); - _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image ); + } - } + this.setFramebufferScaleFactor = function ( value ) { - } + framebufferScaleFactor = value; - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 ); + if ( scope.isPresenting === true ) { - state.unbindTexture(); + console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); - }; + } - this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { + }; - if ( _this.isWebGL1Renderer ) { + this.setReferenceSpaceType = function ( value ) { - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); - return; + referenceSpaceType = value; - } + if ( scope.isPresenting === true ) { - const width = sourceBox.max.x - sourceBox.min.x + 1; - const height = sourceBox.max.y - sourceBox.min.y + 1; - const depth = sourceBox.max.z - sourceBox.min.z + 1; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - let glTarget; + console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); - if ( dstTexture.isData3DTexture ) { + } - textures.setTexture3D( dstTexture, 0 ); - glTarget = 32879; + }; - } else if ( dstTexture.isDataArrayTexture ) { + this.getReferenceSpace = function () { - textures.setTexture2DArray( dstTexture, 0 ); - glTarget = 35866; + return customReferenceSpace || referenceSpace; - } else { + }; - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); - return; + this.setReferenceSpace = function ( space ) { - } + customReferenceSpace = space; - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + }; - const unpackRowLen = _gl.getParameter( 3314 ); - const unpackImageHeight = _gl.getParameter( 32878 ); - const unpackSkipPixels = _gl.getParameter( 3316 ); - const unpackSkipRows = _gl.getParameter( 3315 ); - const unpackSkipImages = _gl.getParameter( 32877 ); + this.getBaseLayer = function () { - const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image; + return glProjLayer !== null ? glProjLayer : glBaseLayer; - _gl.pixelStorei( 3314, image.width ); - _gl.pixelStorei( 32878, image.height ); - _gl.pixelStorei( 3316, sourceBox.min.x ); - _gl.pixelStorei( 3315, sourceBox.min.y ); - _gl.pixelStorei( 32877, sourceBox.min.z ); + }; - if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { + this.getBinding = function () { - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); + return glBinding; - } else { + }; - if ( srcTexture.isCompressedTexture ) { + this.getFrame = function () { - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); - _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); + return xrFrame; - } else { + }; - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); + this.getSession = function () { - } + return session; - } + }; - _gl.pixelStorei( 3314, unpackRowLen ); - _gl.pixelStorei( 32878, unpackImageHeight ); - _gl.pixelStorei( 3316, unpackSkipPixels ); - _gl.pixelStorei( 3315, unpackSkipRows ); - _gl.pixelStorei( 32877, unpackSkipImages ); + this.setSession = async function ( value ) { - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); + session = value; - state.unbindTexture(); + if ( session !== null ) { - }; + initialRenderTarget = renderer.getRenderTarget(); - this.initTexture = function ( texture ) { + session.addEventListener( 'select', onSessionEvent ); + session.addEventListener( 'selectstart', onSessionEvent ); + session.addEventListener( 'selectend', onSessionEvent ); + session.addEventListener( 'squeeze', onSessionEvent ); + session.addEventListener( 'squeezestart', onSessionEvent ); + session.addEventListener( 'squeezeend', onSessionEvent ); + session.addEventListener( 'end', onSessionEnd ); + session.addEventListener( 'inputsourceschange', onInputSourcesChange ); - if ( texture.isCubeTexture ) { + if ( attributes.xrCompatible !== true ) { - textures.setTextureCube( texture, 0 ); + await gl.makeXRCompatible(); - } else if ( texture.isData3DTexture ) { + } - textures.setTexture3D( texture, 0 ); + if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { - } else if ( texture.isDataArrayTexture ) { + const layerInit = { + antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, + alpha: attributes.alpha, + depth: attributes.depth, + stencil: attributes.stencil, + framebufferScaleFactor: framebufferScaleFactor + }; - textures.setTexture2DArray( texture, 0 ); + glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); - } else { + session.updateRenderState( { baseLayer: glBaseLayer } ); - textures.setTexture2D( texture, 0 ); + newRenderTarget = new WebGLRenderTarget( + glBaseLayer.framebufferWidth, + glBaseLayer.framebufferHeight, + { + format: RGBAFormat, + type: UnsignedByteType, + encoding: renderer.outputEncoding, + stencilBuffer: attributes.stencil + } + ); - } + } else { - state.unbindTexture(); + let depthFormat = null; + let depthType = null; + let glDepthFormat = null; - }; + if ( attributes.depth ) { - this.resetState = function () { + glDepthFormat = attributes.stencil ? 35056 : 33190; + depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; + depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; - _currentActiveCubeFace = 0; - _currentActiveMipmapLevel = 0; - _currentRenderTarget = null; + } - state.reset(); - bindingStates.reset(); + const projectionlayerInit = { + colorFormat: 32856, + depthFormat: glDepthFormat, + scaleFactor: framebufferScaleFactor + }; - }; + glBinding = new XRWebGLBinding( session, gl ); - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + glProjLayer = glBinding.createProjectionLayer( projectionlayerInit ); - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); + session.updateRenderState( { layers: [ glProjLayer ] } ); - } + newRenderTarget = new WebGLRenderTarget( + glProjLayer.textureWidth, + glProjLayer.textureHeight, + { + format: RGBAFormat, + type: UnsignedByteType, + depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), + stencilBuffer: attributes.stencil, + encoding: renderer.outputEncoding, + samples: attributes.antialias ? 4 : 0 + } ); - } + const renderTargetProperties = renderer.properties.get( newRenderTarget ); + renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues; - class WebGL1Renderer extends WebGLRenderer {} + } - WebGL1Renderer.prototype.isWebGL1Renderer = true; + newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 - class FogExp2 { + // Set foveation to maximum. + this.setFoveation( 1.0 ); - constructor( color, density = 0.00025 ) { + customReferenceSpace = null; + referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); - this.isFogExp2 = true; + animation.setContext( session ); + animation.start(); - this.name = ''; + scope.isPresenting = true; - this.color = new Color( color ); - this.density = density; + scope.dispatchEvent( { type: 'sessionstart' } ); - } + } - clone() { + }; - return new FogExp2( this.color, this.density ); + function onInputSourcesChange( event ) { - } + // Notify disconnected - toJSON( /* meta */ ) { + for ( let i = 0; i < event.removed.length; i ++ ) { - return { - type: 'FogExp2', - color: this.color.getHex(), - density: this.density - }; + const inputSource = event.removed[ i ]; + const index = controllerInputSources.indexOf( inputSource ); - } + if ( index >= 0 ) { - } + controllerInputSources[ index ] = null; + controllers[ index ].dispatchEvent( { type: 'disconnected', data: inputSource } ); - class Fog { + } - constructor( color, near = 1, far = 1000 ) { + } - this.isFog = true; + // Notify connected - this.name = ''; + for ( let i = 0; i < event.added.length; i ++ ) { - this.color = new Color( color ); + const inputSource = event.added[ i ]; - this.near = near; - this.far = far; + let controllerIndex = controllerInputSources.indexOf( inputSource ); - } + if ( controllerIndex === - 1 ) { - clone() { + // Assign input source a controller that currently has no input source - return new Fog( this.color, this.near, this.far ); + for ( let i = 0; i < controllers.length; i ++ ) { - } + if ( i >= controllerInputSources.length ) { - toJSON( /* meta */ ) { + controllerInputSources.push( inputSource ); + controllerIndex = i; + break; - return { - type: 'Fog', - color: this.color.getHex(), - near: this.near, - far: this.far - }; + } else if ( controllerInputSources[ i ] === null ) { - } + controllerInputSources[ i ] = inputSource; + controllerIndex = i; + break; - } + } - class Scene extends Object3D { + } - constructor() { + // If all controllers do currently receive input we ignore new ones - super(); + if ( controllerIndex === - 1 ) break; - this.isScene = true; + } - this.type = 'Scene'; + const controller = controllers[ controllerIndex ]; - this.background = null; - this.environment = null; - this.fog = null; + if ( controller ) { - this.overrideMaterial = null; + controller.dispatchEvent( { type: 'connected', data: inputSource } ); - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + } - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); + } } - } + // - copy( source, recursive ) { + const cameraLPos = new Vector3(); + const cameraRPos = new Vector3(); - super.copy( source, recursive ); + /** + * Assumes 2 cameras that are parallel and share an X-axis, and that + * the cameras' projection and world matrices have already been set. + * And that near and far planes are identical for both cameras. + * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 + */ + function setProjectionFromUnion( camera, cameraL, cameraR ) { - if ( source.background !== null ) this.background = source.background.clone(); - if ( source.environment !== null ) this.environment = source.environment.clone(); - if ( source.fog !== null ) this.fog = source.fog.clone(); + cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); + cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); - if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); + const ipd = cameraLPos.distanceTo( cameraRPos ); - this.matrixAutoUpdate = source.matrixAutoUpdate; + const projL = cameraL.projectionMatrix.elements; + const projR = cameraR.projectionMatrix.elements; - return this; + // VR systems will have identical far and near planes, and + // most likely identical top and bottom frustum extents. + // Use the left camera for these values. + const near = projL[ 14 ] / ( projL[ 10 ] - 1 ); + const far = projL[ 14 ] / ( projL[ 10 ] + 1 ); + const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; + const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; - } + const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; + const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; + const left = near * leftFov; + const right = near * rightFov; - toJSON( meta ) { + // Calculate the new camera's position offset from the + // left camera. xOffset should be roughly half `ipd`. + const zOffset = ipd / ( - leftFov + rightFov ); + const xOffset = zOffset * - leftFov; - const data = super.toJSON( meta ); + // TODO: Better way to apply this offset? + cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale ); + camera.translateX( xOffset ); + camera.translateZ( zOffset ); + camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale ); + camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); + // Find the union of the frustum values of the cameras and scale + // the values so that the near plane's position does not change in world space, + // although must now be relative to the new union camera. + const near2 = near + zOffset; + const far2 = far + zOffset; + const left2 = left - xOffset; + const right2 = right + ( ipd - xOffset ); + const top2 = topFov * far / far2 * near2; + const bottom2 = bottomFov * far / far2 * near2; - return data; + camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); - } + } - // @deprecated + function updateCamera( camera, parent ) { - get autoUpdate() { + if ( parent === null ) { - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - return this.matrixWorldAutoUpdate; + camera.matrixWorld.copy( camera.matrix ); - } + } else { - set autoUpdate( value ) { + camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - this.matrixWorldAutoUpdate = value; + } - } + camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - } + } - class InterleavedBuffer { + this.updateCamera = function ( camera ) { - constructor( array, stride ) { + if ( session === null ) return; - this.isInterleavedBuffer = true; + cameraVR.near = cameraR.near = cameraL.near = camera.near; + cameraVR.far = cameraR.far = cameraL.far = camera.far; - this.array = array; - this.stride = stride; - this.count = array !== undefined ? array.length / stride : 0; + if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) { - this.usage = StaticDrawUsage; - this.updateRange = { offset: 0, count: - 1 }; + // Note that the new renderState won't apply until the next frame. See #18320 - this.version = 0; + session.updateRenderState( { + depthNear: cameraVR.near, + depthFar: cameraVR.far + } ); - this.uuid = generateUUID(); + _currentDepthNear = cameraVR.near; + _currentDepthFar = cameraVR.far; - } + } - onUploadCallback() {} + const parent = camera.parent; + const cameras = cameraVR.cameras; - set needsUpdate( value ) { + updateCamera( cameraVR, parent ); - if ( value === true ) this.version ++; + for ( let i = 0; i < cameras.length; i ++ ) { - } + updateCamera( cameras[ i ], parent ); - setUsage( value ) { + } - this.usage = value; + cameraVR.matrixWorld.decompose( cameraVR.position, cameraVR.quaternion, cameraVR.scale ); - return this; + // update user camera and its children - } + camera.matrix.copy( cameraVR.matrix ); + camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); - copy( source ) { + const children = camera.children; - this.array = new source.array.constructor( source.array ); - this.count = source.count; - this.stride = source.stride; - this.usage = source.usage; + for ( let i = 0, l = children.length; i < l; i ++ ) { - return this; + children[ i ].updateMatrixWorld( true ); - } + } - copyAt( index1, attribute, index2 ) { + // update projection matrix for proper view frustum culling - index1 *= this.stride; - index2 *= attribute.stride; + if ( cameras.length === 2 ) { - for ( let i = 0, l = this.stride; i < l; i ++ ) { + setProjectionFromUnion( cameraVR, cameraL, cameraR ); - this.array[ index1 + i ] = attribute.array[ index2 + i ]; + } else { - } + // assume single camera setup (AR) - return this; + cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); - } + } - set( value, offset = 0 ) { + }; - this.array.set( value, offset ); + this.getCamera = function () { - return this; + return cameraVR; - } + }; - clone( data ) { + this.getFoveation = function () { - if ( data.arrayBuffers === undefined ) { + if ( glProjLayer !== null ) { - data.arrayBuffers = {}; + return glProjLayer.fixedFoveation; - } + } - if ( this.array.buffer._uuid === undefined ) { + if ( glBaseLayer !== null ) { - this.array.buffer._uuid = generateUUID(); + return glBaseLayer.fixedFoveation; - } + } - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { + return undefined; - data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; + }; - } + this.setFoveation = function ( foveation ) { - const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); + // 0 = no foveation = full resolution + // 1 = maximum foveation = the edges render at lower resolution - const ib = new this.constructor( array, this.stride ); - ib.setUsage( this.usage ); + if ( glProjLayer !== null ) { - return ib; + glProjLayer.fixedFoveation = foveation; - } + } - onUpload( callback ) { + if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { - this.onUploadCallback = callback; + glBaseLayer.fixedFoveation = foveation; - return this; + } - } + }; - toJSON( data ) { + // Animation Loop - if ( data.arrayBuffers === undefined ) { + let onAnimationFrameCallback = null; - data.arrayBuffers = {}; + function onAnimationFrame( time, frame ) { - } + pose = frame.getViewerPose( customReferenceSpace || referenceSpace ); + xrFrame = frame; - // generate UUID for array buffer if necessary + if ( pose !== null ) { - if ( this.array.buffer._uuid === undefined ) { + const views = pose.views; - this.array.buffer._uuid = generateUUID(); + if ( glBaseLayer !== null ) { - } + renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer ); + renderer.setRenderTarget( newRenderTarget ); - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { + } - data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); + let cameraVRNeedsUpdate = false; - } + // check if it's necessary to rebuild cameraVR's camera list - // + if ( views.length !== cameraVR.cameras.length ) { - return { - uuid: this.uuid, - buffer: this.array.buffer._uuid, - type: this.array.constructor.name, - stride: this.stride - }; + cameraVR.cameras.length = 0; + cameraVRNeedsUpdate = true; - } + } - } + for ( let i = 0; i < views.length; i ++ ) { - const _vector$6 = /*@__PURE__*/ new Vector3(); + const view = views[ i ]; - class InterleavedBufferAttribute { + let viewport = null; - constructor( interleavedBuffer, itemSize, offset, normalized = false ) { + if ( glBaseLayer !== null ) { - this.isInterleavedBufferAttribute = true; + viewport = glBaseLayer.getViewport( view ); - this.name = ''; + } else { - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; + const glSubImage = glBinding.getViewSubImage( glProjLayer, view ); + viewport = glSubImage.viewport; - this.normalized = normalized === true; + // For side-by-side projection, we only produce a single texture for both eyes. + if ( i === 0 ) { - } + renderer.setRenderTargetTextures( + newRenderTarget, + glSubImage.colorTexture, + glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture ); - get count() { + renderer.setRenderTarget( newRenderTarget ); - return this.data.count; + } - } + } - get array() { + let camera = cameras[ i ]; - return this.data.array; + if ( camera === undefined ) { - } + camera = new PerspectiveCamera(); + camera.layers.enable( i ); + camera.viewport = new Vector4(); + cameras[ i ] = camera; - set needsUpdate( value ) { + } - this.data.needsUpdate = value; + camera.matrix.fromArray( view.transform.matrix ); + camera.projectionMatrix.fromArray( view.projectionMatrix ); + camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); - } + if ( i === 0 ) { - applyMatrix4( m ) { + cameraVR.matrix.copy( camera.matrix ); - for ( let i = 0, l = this.data.count; i < l; i ++ ) { + } - _vector$6.fromBufferAttribute( this, i ); + if ( cameraVRNeedsUpdate === true ) { - _vector$6.applyMatrix4( m ); + cameraVR.cameras.push( camera ); - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); + } - } + } - return this; + } - } + // - applyNormalMatrix( m ) { + for ( let i = 0; i < controllers.length; i ++ ) { - for ( let i = 0, l = this.count; i < l; i ++ ) { + const inputSource = controllerInputSources[ i ]; + const controller = controllers[ i ]; - _vector$6.fromBufferAttribute( this, i ); + if ( inputSource !== null && controller !== undefined ) { - _vector$6.applyNormalMatrix( m ); + controller.update( inputSource, frame, customReferenceSpace || referenceSpace ); - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); + } - } + } - return this; + if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame ); - } + xrFrame = null; - transformDirection( m ) { + } - for ( let i = 0, l = this.count; i < l; i ++ ) { + const animation = new WebGLAnimation(); - _vector$6.fromBufferAttribute( this, i ); + animation.setAnimationLoop( onAnimationFrame ); - _vector$6.transformDirection( m ); + this.setAnimationLoop = function ( callback ) { - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); + onAnimationFrameCallback = callback; - } + }; - return this; + this.dispose = function () {}; } - setX( index, x ) { + } - if ( this.normalized ) x = normalize( x, this.array ); + function WebGLMaterials( renderer, properties ) { - this.data.array[ index * this.data.stride + this.offset ] = x; + function refreshFogUniforms( uniforms, fog ) { - return this; + uniforms.fogColor.value.copy( fog.color ); - } + if ( fog.isFog ) { - setY( index, y ) { + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; - if ( this.normalized ) y = normalize( y, this.array ); + } else if ( fog.isFogExp2 ) { - this.data.array[ index * this.data.stride + this.offset + 1 ] = y; + uniforms.fogDensity.value = fog.density; - return this; + } } - setZ( index, z ) { - - if ( this.normalized ) z = normalize( z, this.array ); + function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) { - this.data.array[ index * this.data.stride + this.offset + 2 ] = z; + if ( material.isMeshBasicMaterial ) { - return this; + refreshUniformsCommon( uniforms, material ); - } + } else if ( material.isMeshLambertMaterial ) { - setW( index, w ) { + refreshUniformsCommon( uniforms, material ); - if ( this.normalized ) w = normalize( w, this.array ); + } else if ( material.isMeshToonMaterial ) { - this.data.array[ index * this.data.stride + this.offset + 3 ] = w; + refreshUniformsCommon( uniforms, material ); + refreshUniformsToon( uniforms, material ); - return this; + } else if ( material.isMeshPhongMaterial ) { - } + refreshUniformsCommon( uniforms, material ); + refreshUniformsPhong( uniforms, material ); - getX( index ) { + } else if ( material.isMeshStandardMaterial ) { - let x = this.data.array[ index * this.data.stride + this.offset ]; + refreshUniformsCommon( uniforms, material ); + refreshUniformsStandard( uniforms, material ); - if ( this.normalized ) x = denormalize( x, this.array ); + if ( material.isMeshPhysicalMaterial ) { - return x; + refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ); - } + } - getY( index ) { + } else if ( material.isMeshMatcapMaterial ) { - let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; + refreshUniformsCommon( uniforms, material ); + refreshUniformsMatcap( uniforms, material ); - if ( this.normalized ) y = denormalize( y, this.array ); + } else if ( material.isMeshDepthMaterial ) { - return y; + refreshUniformsCommon( uniforms, material ); - } + } else if ( material.isMeshDistanceMaterial ) { - getZ( index ) { + refreshUniformsCommon( uniforms, material ); + refreshUniformsDistance( uniforms, material ); - let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; + } else if ( material.isMeshNormalMaterial ) { - if ( this.normalized ) z = denormalize( z, this.array ); + refreshUniformsCommon( uniforms, material ); - return z; + } else if ( material.isLineBasicMaterial ) { - } + refreshUniformsLine( uniforms, material ); - getW( index ) { + if ( material.isLineDashedMaterial ) { - let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; + refreshUniformsDash( uniforms, material ); - if ( this.normalized ) w = denormalize( w, this.array ); + } - return w; + } else if ( material.isPointsMaterial ) { - } + refreshUniformsPoints( uniforms, material, pixelRatio, height ); - setXY( index, x, y ) { + } else if ( material.isSpriteMaterial ) { - index = index * this.data.stride + this.offset; + refreshUniformsSprites( uniforms, material ); - if ( this.normalized ) { + } else if ( material.isShadowMaterial ) { - x = normalize( x, this.array ); - y = normalize( y, this.array ); + uniforms.color.value.copy( material.color ); + uniforms.opacity.value = material.opacity; - } + } else if ( material.isShaderMaterial ) { - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; + material.uniformsNeedUpdate = false; // #15581 - return this; + } } - setXYZ( index, x, y, z ) { + function refreshUniformsCommon( uniforms, material ) { - index = index * this.data.stride + this.offset; + uniforms.opacity.value = material.opacity; - if ( this.normalized ) { + if ( material.color ) { - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); + uniforms.diffuse.value.copy( material.color ); } - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; + if ( material.emissive ) { - return this; + uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - } + } - setXYZW( index, x, y, z, w ) { + if ( material.map ) { - index = index * this.data.stride + this.offset; + uniforms.map.value = material.map; - if ( this.normalized ) { + } - x = normalize( x, this.array ); - y = normalize( y, this.array ); - z = normalize( z, this.array ); - w = normalize( w, this.array ); + if ( material.alphaMap ) { + + uniforms.alphaMap.value = material.alphaMap; } - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - this.data.array[ index + 3 ] = w; + if ( material.bumpMap ) { - return this; + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; - } + } - clone( data ) { + if ( material.displacementMap ) { - if ( data === undefined ) { + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will deinterleave buffer data.' ); + } - const array = []; + if ( material.emissiveMap ) { - for ( let i = 0; i < this.count; i ++ ) { + uniforms.emissiveMap.value = material.emissiveMap; - const index = i * this.data.stride + this.offset; + } - for ( let j = 0; j < this.itemSize; j ++ ) { + if ( material.normalMap ) { - array.push( this.data.array[ index + j ] ); + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - } + } - } + if ( material.specularMap ) { - return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); + uniforms.specularMap.value = material.specularMap; - } else { + } - if ( data.interleavedBuffers === undefined ) { + if ( material.alphaTest > 0 ) { - data.interleavedBuffers = {}; + uniforms.alphaTest.value = material.alphaTest; - } + } - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { + const envMap = properties.get( material ).envMap; - data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); + if ( envMap ) { - } + uniforms.envMap.value = envMap; - return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); + uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; + + uniforms.reflectivity.value = material.reflectivity; + uniforms.ior.value = material.ior; + uniforms.refractionRatio.value = material.refractionRatio; } - } + if ( material.lightMap ) { - toJSON( data ) { + uniforms.lightMap.value = material.lightMap; - if ( data === undefined ) { + // artist-friendly light intensity scaling factor + const scaleFactor = ( renderer.physicallyCorrectLights !== true ) ? Math.PI : 1; - console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will deinterleave buffer data.' ); + uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; - const array = []; + } - for ( let i = 0; i < this.count; i ++ ) { + if ( material.aoMap ) { - const index = i * this.data.stride + this.offset; + uniforms.aoMap.value = material.aoMap; + uniforms.aoMapIntensity.value = material.aoMapIntensity; - for ( let j = 0; j < this.itemSize; j ++ ) { + } - array.push( this.data.array[ index + j ] ); + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. displacementMap map + // 4. normal map + // 5. bump map + // 6. roughnessMap map + // 7. metalnessMap map + // 8. alphaMap map + // 9. emissiveMap map + // 10. clearcoat map + // 11. clearcoat normal map + // 12. clearcoat roughnessMap map + // 13. iridescence map + // 14. iridescence thickness map + // 15. specular intensity map + // 16. specular tint map + // 17. transmission map + // 18. thickness map - } + let uvScaleMap; - } + if ( material.map ) { - // deinterleave data and save it as an ordinary buffer attribute for now + uvScaleMap = material.map; - return { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: array, - normalized: this.normalized - }; + } else if ( material.specularMap ) { - } else { + uvScaleMap = material.specularMap; - // save as true interleaved attribtue + } else if ( material.displacementMap ) { - if ( data.interleavedBuffers === undefined ) { + uvScaleMap = material.displacementMap; - data.interleavedBuffers = {}; + } else if ( material.normalMap ) { - } + uvScaleMap = material.normalMap; - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { + } else if ( material.bumpMap ) { - data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); + uvScaleMap = material.bumpMap; - } + } else if ( material.roughnessMap ) { - return { - isInterleavedBufferAttribute: true, - itemSize: this.itemSize, - data: this.data.uuid, - offset: this.offset, - normalized: this.normalized - }; + uvScaleMap = material.roughnessMap; - } + } else if ( material.metalnessMap ) { - } + uvScaleMap = material.metalnessMap; - } + } else if ( material.alphaMap ) { - class SpriteMaterial extends Material { + uvScaleMap = material.alphaMap; - constructor( parameters ) { + } else if ( material.emissiveMap ) { - super(); + uvScaleMap = material.emissiveMap; - this.isSpriteMaterial = true; + } else if ( material.clearcoatMap ) { - this.type = 'SpriteMaterial'; + uvScaleMap = material.clearcoatMap; - this.color = new Color( 0xffffff ); + } else if ( material.clearcoatNormalMap ) { - this.map = null; + uvScaleMap = material.clearcoatNormalMap; - this.alphaMap = null; + } else if ( material.clearcoatRoughnessMap ) { - this.rotation = 0; + uvScaleMap = material.clearcoatRoughnessMap; - this.sizeAttenuation = true; + } else if ( material.iridescenceMap ) { - this.transparent = true; + uvScaleMap = material.iridescenceMap; - this.fog = true; + } else if ( material.iridescenceThicknessMap ) { - this.setValues( parameters ); + uvScaleMap = material.iridescenceThicknessMap; - } + } else if ( material.specularIntensityMap ) { - copy( source ) { + uvScaleMap = material.specularIntensityMap; - super.copy( source ); + } else if ( material.specularColorMap ) { - this.color.copy( source.color ); + uvScaleMap = material.specularColorMap; - this.map = source.map; + } else if ( material.transmissionMap ) { - this.alphaMap = source.alphaMap; + uvScaleMap = material.transmissionMap; - this.rotation = source.rotation; + } else if ( material.thicknessMap ) { - this.sizeAttenuation = source.sizeAttenuation; + uvScaleMap = material.thicknessMap; - this.fog = source.fog; + } else if ( material.sheenColorMap ) { - return this; + uvScaleMap = material.sheenColorMap; - } + } else if ( material.sheenRoughnessMap ) { - } + uvScaleMap = material.sheenRoughnessMap; - let _geometry; + } - const _intersectPoint = /*@__PURE__*/ new Vector3(); - const _worldScale = /*@__PURE__*/ new Vector3(); - const _mvPosition = /*@__PURE__*/ new Vector3(); + if ( uvScaleMap !== undefined ) { - const _alignedPosition = /*@__PURE__*/ new Vector2(); - const _rotatedPosition = /*@__PURE__*/ new Vector2(); - const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); + // backwards compatibility + if ( uvScaleMap.isWebGLRenderTarget ) { - const _vA = /*@__PURE__*/ new Vector3(); - const _vB = /*@__PURE__*/ new Vector3(); - const _vC = /*@__PURE__*/ new Vector3(); + uvScaleMap = uvScaleMap.texture; - const _uvA = /*@__PURE__*/ new Vector2(); - const _uvB = /*@__PURE__*/ new Vector2(); - const _uvC = /*@__PURE__*/ new Vector2(); + } - class Sprite extends Object3D { + if ( uvScaleMap.matrixAutoUpdate === true ) { - constructor( material ) { + uvScaleMap.updateMatrix(); - super(); + } - this.isSprite = true; + uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - this.type = 'Sprite'; + } - if ( _geometry === undefined ) { + // uv repeat and offset setting priorities for uv2 + // 1. ao map + // 2. light map - _geometry = new BufferGeometry(); + let uv2ScaleMap; - const float32Array = new Float32Array( [ - - 0.5, - 0.5, 0, 0, 0, - 0.5, - 0.5, 0, 1, 0, - 0.5, 0.5, 0, 1, 1, - - 0.5, 0.5, 0, 0, 1 - ] ); + if ( material.aoMap ) { - const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); + uv2ScaleMap = material.aoMap; - _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); - _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); - _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); + } else if ( material.lightMap ) { + + uv2ScaleMap = material.lightMap; } - this.geometry = _geometry; - this.material = ( material !== undefined ) ? material : new SpriteMaterial(); + if ( uv2ScaleMap !== undefined ) { - this.center = new Vector2( 0.5, 0.5 ); + // backwards compatibility + if ( uv2ScaleMap.isWebGLRenderTarget ) { - } + uv2ScaleMap = uv2ScaleMap.texture; - raycast( raycaster, intersects ) { + } - if ( raycaster.camera === null ) { + if ( uv2ScaleMap.matrixAutoUpdate === true ) { - console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); + uv2ScaleMap.updateMatrix(); - } + } - _worldScale.setFromMatrixScale( this.matrixWorld ); + uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix ); - _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); - this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); + } - _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); + } - if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { + function refreshUniformsLine( uniforms, material ) { - _worldScale.multiplyScalar( - _mvPosition.z ); + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; - } + } - const rotation = this.material.rotation; - let sin, cos; + function refreshUniformsDash( uniforms, material ) { - if ( rotation !== 0 ) { + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; - cos = Math.cos( rotation ); - sin = Math.sin( rotation ); + } - } + function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { - const center = this.center; + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size * pixelRatio; + uniforms.scale.value = height * 0.5; - transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + if ( material.map ) { - _uvA.set( 0, 0 ); - _uvB.set( 1, 0 ); - _uvC.set( 1, 1 ); + uniforms.map.value = material.map; - // check first triangle - let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint ); + } - if ( intersect === null ) { + if ( material.alphaMap ) { - // check second triangle - transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - _uvB.set( 0, 1 ); + uniforms.alphaMap.value = material.alphaMap; - intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint ); - if ( intersect === null ) { + } - return; + if ( material.alphaTest > 0 ) { - } + uniforms.alphaTest.value = material.alphaTest; } - const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { + // uv repeat and offset setting priorities + // 1. color map + // 2. alpha map - distance: distance, - point: _intersectPoint.clone(), - uv: Triangle.getUV( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ), - face: null, - object: this + let uvScaleMap; - } ); + if ( material.map ) { - } + uvScaleMap = material.map; - copy( source, recursive ) { + } else if ( material.alphaMap ) { - super.copy( source, recursive ); + uvScaleMap = material.alphaMap; - if ( source.center !== undefined ) this.center.copy( source.center ); + } - this.material = source.material; + if ( uvScaleMap !== undefined ) { - return this; + if ( uvScaleMap.matrixAutoUpdate === true ) { - } + uvScaleMap.updateMatrix(); - } + } - function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { + uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - // compute position in camera space - _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); + } - // to check if rotation is not zero - if ( sin !== undefined ) { + } - _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); - _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); + function refreshUniformsSprites( uniforms, material ) { - } else { + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; + uniforms.rotation.value = material.rotation; - _rotatedPosition.copy( _alignedPosition ); + if ( material.map ) { - } + uniforms.map.value = material.map; + } - vertexPosition.copy( mvPosition ); - vertexPosition.x += _rotatedPosition.x; - vertexPosition.y += _rotatedPosition.y; + if ( material.alphaMap ) { - // transform to world space - vertexPosition.applyMatrix4( _viewWorldMatrix ); + uniforms.alphaMap.value = material.alphaMap; - } + } - const _v1$2 = /*@__PURE__*/ new Vector3(); - const _v2$1 = /*@__PURE__*/ new Vector3(); + if ( material.alphaTest > 0 ) { - class LOD extends Object3D { + uniforms.alphaTest.value = material.alphaTest; - constructor() { + } - super(); + // uv repeat and offset setting priorities + // 1. color map + // 2. alpha map - this._currentLevel = 0; + let uvScaleMap; - this.type = 'LOD'; + if ( material.map ) { - Object.defineProperties( this, { - levels: { - enumerable: true, - value: [] - }, - isLOD: { - value: true, - } - } ); + uvScaleMap = material.map; - this.autoUpdate = true; + } else if ( material.alphaMap ) { - } + uvScaleMap = material.alphaMap; - copy( source ) { + } - super.copy( source, false ); + if ( uvScaleMap !== undefined ) { - const levels = source.levels; + if ( uvScaleMap.matrixAutoUpdate === true ) { - for ( let i = 0, l = levels.length; i < l; i ++ ) { + uvScaleMap.updateMatrix(); - const level = levels[ i ]; + } - this.addLevel( level.object.clone(), level.distance ); + uniforms.uvTransform.value.copy( uvScaleMap.matrix ); } - this.autoUpdate = source.autoUpdate; + } - return this; + function refreshUniformsPhong( uniforms, material ) { + + uniforms.specular.value.copy( material.specular ); + uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) } - addLevel( object, distance = 0 ) { + function refreshUniformsToon( uniforms, material ) { - distance = Math.abs( distance ); + if ( material.gradientMap ) { - const levels = this.levels; + uniforms.gradientMap.value = material.gradientMap; - let l; + } - for ( l = 0; l < levels.length; l ++ ) { + } - if ( distance < levels[ l ].distance ) { + function refreshUniformsStandard( uniforms, material ) { - break; + uniforms.roughness.value = material.roughness; + uniforms.metalness.value = material.metalness; - } + if ( material.roughnessMap ) { + + uniforms.roughnessMap.value = material.roughnessMap; } - levels.splice( l, 0, { distance: distance, object: object } ); + if ( material.metalnessMap ) { - this.add( object ); + uniforms.metalnessMap.value = material.metalnessMap; - return this; + } - } + const envMap = properties.get( material ).envMap; - getCurrentLevel() { + if ( envMap ) { - return this._currentLevel; + //uniforms.envMap.value = material.envMap; // part of uniforms common + uniforms.envMapIntensity.value = material.envMapIntensity; - } + } - getObjectForDistance( distance ) { + } - const levels = this.levels; + function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) { - if ( levels.length > 0 ) { + uniforms.ior.value = material.ior; // also part of uniforms common - let i, l; + if ( material.sheen > 0 ) { - for ( i = 1, l = levels.length; i < l; i ++ ) { + uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen ); - if ( distance < levels[ i ].distance ) { + uniforms.sheenRoughness.value = material.sheenRoughness; - break; + if ( material.sheenColorMap ) { - } + uniforms.sheenColorMap.value = material.sheenColorMap; } - return levels[ i - 1 ].object; - - } - - return null; + if ( material.sheenRoughnessMap ) { - } + uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; - raycast( raycaster, intersects ) { + } - const levels = this.levels; + } - if ( levels.length > 0 ) { + if ( material.clearcoat > 0 ) { - _v1$2.setFromMatrixPosition( this.matrixWorld ); + uniforms.clearcoat.value = material.clearcoat; + uniforms.clearcoatRoughness.value = material.clearcoatRoughness; - const distance = raycaster.ray.origin.distanceTo( _v1$2 ); + if ( material.clearcoatMap ) { - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); + uniforms.clearcoatMap.value = material.clearcoatMap; - } + } - } + if ( material.clearcoatRoughnessMap ) { - update( camera ) { + uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; - const levels = this.levels; + } - if ( levels.length > 1 ) { + if ( material.clearcoatNormalMap ) { - _v1$2.setFromMatrixPosition( camera.matrixWorld ); - _v2$1.setFromMatrixPosition( this.matrixWorld ); + uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); + uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; - const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; + if ( material.side === BackSide ) { - levels[ 0 ].object.visible = true; + uniforms.clearcoatNormalScale.value.negate(); - let i, l; + } - for ( i = 1, l = levels.length; i < l; i ++ ) { + } - if ( distance >= levels[ i ].distance ) { + } - levels[ i - 1 ].object.visible = false; - levels[ i ].object.visible = true; + if ( material.iridescence > 0 ) { - } else { + uniforms.iridescence.value = material.iridescence; + uniforms.iridescenceIOR.value = material.iridescenceIOR; + uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ]; + uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ]; - break; + if ( material.iridescenceMap ) { - } + uniforms.iridescenceMap.value = material.iridescenceMap; } - this._currentLevel = i - 1; - - for ( ; i < l; i ++ ) { + if ( material.iridescenceThicknessMap ) { - levels[ i ].object.visible = false; + uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; } } - } + if ( material.transmission > 0 ) { - toJSON( meta ) { + uniforms.transmission.value = material.transmission; + uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; + uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height ); - const data = super.toJSON( meta ); + if ( material.transmissionMap ) { - if ( this.autoUpdate === false ) data.object.autoUpdate = false; + uniforms.transmissionMap.value = material.transmissionMap; - data.object.levels = []; + } - const levels = this.levels; + uniforms.thickness.value = material.thickness; - for ( let i = 0, l = levels.length; i < l; i ++ ) { + if ( material.thicknessMap ) { - const level = levels[ i ]; + uniforms.thicknessMap.value = material.thicknessMap; - data.object.levels.push( { - object: level.object.uuid, - distance: level.distance - } ); + } + + uniforms.attenuationDistance.value = material.attenuationDistance; + uniforms.attenuationColor.value.copy( material.attenuationColor ); } - return data; + uniforms.specularIntensity.value = material.specularIntensity; + uniforms.specularColor.value.copy( material.specularColor ); - } + if ( material.specularIntensityMap ) { - } + uniforms.specularIntensityMap.value = material.specularIntensityMap; - const _basePosition = /*@__PURE__*/ new Vector3(); + } - const _skinIndex = /*@__PURE__*/ new Vector4(); - const _skinWeight = /*@__PURE__*/ new Vector4(); + if ( material.specularColorMap ) { - const _vector$5 = /*@__PURE__*/ new Vector3(); - const _matrix = /*@__PURE__*/ new Matrix4(); + uniforms.specularColorMap.value = material.specularColorMap; - class SkinnedMesh extends Mesh { + } - constructor( geometry, material ) { + } - super( geometry, material ); + function refreshUniformsMatcap( uniforms, material ) { - this.isSkinnedMesh = true; + if ( material.matcap ) { - this.type = 'SkinnedMesh'; + uniforms.matcap.value = material.matcap; - this.bindMode = 'attached'; - this.bindMatrix = new Matrix4(); - this.bindMatrixInverse = new Matrix4(); + } } - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.bindMode = source.bindMode; - this.bindMatrix.copy( source.bindMatrix ); - this.bindMatrixInverse.copy( source.bindMatrixInverse ); - - this.skeleton = source.skeleton; + function refreshUniformsDistance( uniforms, material ) { - return this; + uniforms.referencePosition.value.copy( material.referencePosition ); + uniforms.nearDistance.value = material.nearDistance; + uniforms.farDistance.value = material.farDistance; } - bind( skeleton, bindMatrix ) { - - this.skeleton = skeleton; + return { + refreshFogUniforms: refreshFogUniforms, + refreshMaterialUniforms: refreshMaterialUniforms + }; - if ( bindMatrix === undefined ) { + } - this.updateMatrixWorld( true ); + function WebGLUniformsGroups( gl, info, capabilities, state ) { - this.skeleton.calculateInverses(); + let buffers = {}; + let updateList = {}; + let allocatedBindingPoints = []; - bindMatrix = this.matrixWorld; + const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( 35375 ) : 0; // binding points are global whereas block indices are per shader program - } + function bind( uniformsGroup, program ) { - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.copy( bindMatrix ).invert(); + const webglProgram = program.program; + state.uniformBlockBinding( uniformsGroup, webglProgram ); } - pose() { - - this.skeleton.pose(); + function update( uniformsGroup, program ) { - } + let buffer = buffers[ uniformsGroup.id ]; - normalizeSkinWeights() { + if ( buffer === undefined ) { - const vector = new Vector4(); + prepareUniformsGroup( uniformsGroup ); - const skinWeight = this.geometry.attributes.skinWeight; + buffer = createBuffer( uniformsGroup ); + buffers[ uniformsGroup.id ] = buffer; - for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { + uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose ); - vector.fromBufferAttribute( skinWeight, i ); + } - const scale = 1.0 / vector.manhattanLength(); + // ensure to update the binding points/block indices mapping for this program - if ( scale !== Infinity ) { + const webglProgram = program.program; + state.updateUBOMapping( uniformsGroup, webglProgram ); - vector.multiplyScalar( scale ); + // update UBO once per frame - } else { + const frame = info.render.frame; - vector.set( 1, 0, 0, 0 ); // do something reasonable + if ( updateList[ uniformsGroup.id ] !== frame ) { - } + updateBufferData( uniformsGroup ); - skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); + updateList[ uniformsGroup.id ] = frame; } } - updateMatrixWorld( force ) { + function createBuffer( uniformsGroup ) { - super.updateMatrixWorld( force ); + // the setup of an UBO is independent of a particular shader program but global - if ( this.bindMode === 'attached' ) { + const bindingPointIndex = allocateBindingPointIndex(); + uniformsGroup.__bindingPointIndex = bindingPointIndex; - this.bindMatrixInverse.copy( this.matrixWorld ).invert(); - - } else if ( this.bindMode === 'detached' ) { - - this.bindMatrixInverse.copy( this.bindMatrix ).invert(); - - } else { + const buffer = gl.createBuffer(); + const size = uniformsGroup.__size; + const usage = uniformsGroup.usage; - console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); + gl.bindBuffer( 35345, buffer ); + gl.bufferData( 35345, size, usage ); + gl.bindBuffer( 35345, null ); + gl.bindBufferBase( 35345, bindingPointIndex, buffer ); - } + return buffer; } - boneTransform( index, target ) { - - const skeleton = this.skeleton; - const geometry = this.geometry; + function allocateBindingPointIndex() { - _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); - _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); + for ( let i = 0; i < maxBindingPoints; i ++ ) { - _basePosition.copy( target ).applyMatrix4( this.bindMatrix ); + if ( allocatedBindingPoints.indexOf( i ) === - 1 ) { - target.set( 0, 0, 0 ); + allocatedBindingPoints.push( i ); + return i; - for ( let i = 0; i < 4; i ++ ) { + } - const weight = _skinWeight.getComponent( i ); + } - if ( weight !== 0 ) { + console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); - const boneIndex = _skinIndex.getComponent( i ); + return 0; - _matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); + } - target.addScaledVector( _vector$5.copy( _basePosition ).applyMatrix4( _matrix ), weight ); + function updateBufferData( uniformsGroup ) { - } + const buffer = buffers[ uniformsGroup.id ]; + const uniforms = uniformsGroup.uniforms; + const cache = uniformsGroup.__cache; - } + gl.bindBuffer( 35345, buffer ); - return target.applyMatrix4( this.bindMatrixInverse ); + for ( let i = 0, il = uniforms.length; i < il; i ++ ) { - } + const uniform = uniforms[ i ]; - } + // partly update the buffer if necessary - class Bone extends Object3D { + if ( hasUniformChanged( uniform, i, cache ) === true ) { - constructor() { + const value = uniform.value; + const offset = uniform.__offset; - super(); + if ( typeof value === 'number' ) { - this.isBone = true; + uniform.__data[ 0 ] = value; + gl.bufferSubData( 35345, offset, uniform.__data ); - this.type = 'Bone'; + } else { - } + if ( uniform.value.isMatrix3 ) { - } + // manually converting 3x3 to 3x4 - class DataTexture extends Texture { + uniform.__data[ 0 ] = uniform.value.elements[ 0 ]; + uniform.__data[ 1 ] = uniform.value.elements[ 1 ]; + uniform.__data[ 2 ] = uniform.value.elements[ 2 ]; + uniform.__data[ 3 ] = uniform.value.elements[ 0 ]; + uniform.__data[ 4 ] = uniform.value.elements[ 3 ]; + uniform.__data[ 5 ] = uniform.value.elements[ 4 ]; + uniform.__data[ 6 ] = uniform.value.elements[ 5 ]; + uniform.__data[ 7 ] = uniform.value.elements[ 0 ]; + uniform.__data[ 8 ] = uniform.value.elements[ 6 ]; + uniform.__data[ 9 ] = uniform.value.elements[ 7 ]; + uniform.__data[ 10 ] = uniform.value.elements[ 8 ]; + uniform.__data[ 11 ] = uniform.value.elements[ 0 ]; - constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, encoding ) { + } else { - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + value.toArray( uniform.__data ); - this.isDataTexture = true; + } - this.image = { data: data, width: width, height: height }; + gl.bufferSubData( 35345, offset, uniform.__data ); - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + } - } + } - } + } - const _offsetMatrix = /*@__PURE__*/ new Matrix4(); - const _identityMatrix = /*@__PURE__*/ new Matrix4(); + gl.bindBuffer( 35345, null ); - class Skeleton { + } - constructor( bones = [], boneInverses = [] ) { + function hasUniformChanged( uniform, index, cache ) { - this.uuid = generateUUID(); + const value = uniform.value; - this.bones = bones.slice( 0 ); - this.boneInverses = boneInverses; - this.boneMatrices = null; + if ( cache[ index ] === undefined ) { - this.boneTexture = null; - this.boneTextureSize = 0; + // cache entry does not exist so far - this.frame = - 1; + if ( typeof value === 'number' ) { - this.init(); + cache[ index ] = value; - } + } else { - init() { + cache[ index ] = value.clone(); - const bones = this.bones; - const boneInverses = this.boneInverses; + } - this.boneMatrices = new Float32Array( bones.length * 16 ); + return true; - // calculate inverse bone matrices if necessary + } else { - if ( boneInverses.length === 0 ) { + // compare current value with cached entry - this.calculateInverses(); + if ( typeof value === 'number' ) { - } else { + if ( cache[ index ] !== value ) { - // handle special case + cache[ index ] = value; + return true; - if ( bones.length !== boneInverses.length ) { + } - console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); + } else { - this.boneInverses = []; + const cachedObject = cache[ index ]; - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + if ( cachedObject.equals( value ) === false ) { - this.boneInverses.push( new Matrix4() ); + cachedObject.copy( value ); + return true; } @@ -39785,2701 +71318,2732 @@ var app = (function () { } + return false; + } - calculateInverses() { + function prepareUniformsGroup( uniformsGroup ) { - this.boneInverses.length = 0; + // determine total buffer size according to the STD140 layout + // Hint: STD140 is the only supported layout in WebGL 2 - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + const uniforms = uniformsGroup.uniforms; - const inverse = new Matrix4(); + let offset = 0; // global buffer offset in bytes + const chunkSize = 16; // size of a chunk in bytes + let chunkOffset = 0; // offset within a single chunk in bytes - if ( this.bones[ i ] ) { + for ( let i = 0, l = uniforms.length; i < l; i ++ ) { - inverse.copy( this.bones[ i ].matrixWorld ).invert(); + const uniform = uniforms[ i ]; + const info = getUniformSize( uniform ); - } + // the following two properties will be used for partial buffer updates - this.boneInverses.push( inverse ); + uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); + uniform.__offset = offset; - } + // - } + if ( i > 0 ) { - pose() { + chunkOffset = offset % chunkSize; - // recover the bind-time world matrices + const remainingSizeInChunk = chunkSize - chunkOffset; - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + // check for chunk overflow - const bone = this.bones[ i ]; + if ( chunkOffset !== 0 && ( remainingSizeInChunk - info.boundary ) < 0 ) { - if ( bone ) { + // add padding and adjust offset - bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); + offset += ( chunkSize - chunkOffset ); + uniform.__offset = offset; + + } } + offset += info.storage; + } - // compute the local matrices, positions, rotations and scales + // ensure correct final padding - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + chunkOffset = offset % chunkSize; - const bone = this.bones[ i ]; + if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); - if ( bone ) { + // - if ( bone.parent && bone.parent.isBone ) { + uniformsGroup.__size = offset; + uniformsGroup.__cache = {}; - bone.matrix.copy( bone.parent.matrixWorld ).invert(); - bone.matrix.multiply( bone.matrixWorld ); + return this; - } else { + } - bone.matrix.copy( bone.matrixWorld ); + function getUniformSize( uniform ) { - } + const value = uniform.value; - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + const info = { + boundary: 0, // bytes + storage: 0 // bytes + }; - } + // determine sizes according to STD140 - } + if ( typeof value === 'number' ) { - } + // float/int - update() { + info.boundary = 4; + info.storage = 4; - const bones = this.bones; - const boneInverses = this.boneInverses; - const boneMatrices = this.boneMatrices; - const boneTexture = this.boneTexture; + } else if ( value.isVector2 ) { - // flatten bone matrices to array + // vec2 - for ( let i = 0, il = bones.length; i < il; i ++ ) { + info.boundary = 8; + info.storage = 8; - // compute the offset between the current and the original transform + } else if ( value.isVector3 || value.isColor ) { - const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix; + // vec3 - _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); - _offsetMatrix.toArray( boneMatrices, i * 16 ); + info.boundary = 16; + info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes - } + } else if ( value.isVector4 ) { - if ( boneTexture !== null ) { + // vec4 - boneTexture.needsUpdate = true; + info.boundary = 16; + info.storage = 16; - } + } else if ( value.isMatrix3 ) { - } + // mat3 (in STD140 a 3x3 matrix is represented as 3x4) - clone() { + info.boundary = 48; + info.storage = 48; - return new Skeleton( this.bones, this.boneInverses ); + } else if ( value.isMatrix4 ) { - } + // mat4 - computeBoneTexture() { + info.boundary = 64; + info.storage = 64; - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) + } else if ( value.isTexture ) { - let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix - size = ceilPowerOfTwo( size ); - size = Math.max( size, 4 ); + console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); - const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - boneMatrices.set( this.boneMatrices ); // copy current values + } else { - const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - boneTexture.needsUpdate = true; + console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); - this.boneMatrices = boneMatrices; - this.boneTexture = boneTexture; - this.boneTextureSize = size; + } - return this; + return info; } - getBoneByName( name ) { + function onUniformsGroupsDispose( event ) { - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { + const uniformsGroup = event.target; - const bone = this.bones[ i ]; + uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); - if ( bone.name === name ) { + const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); + allocatedBindingPoints.splice( index, 1 ); - return bone; + gl.deleteBuffer( buffers[ uniformsGroup.id ] ); - } + delete buffers[ uniformsGroup.id ]; + delete updateList[ uniformsGroup.id ]; + + } + + function dispose() { + + for ( const id in buffers ) { + + gl.deleteBuffer( buffers[ id ] ); } - return undefined; + allocatedBindingPoints = []; + buffers = {}; + updateList = {}; } - dispose( ) { + return { - if ( this.boneTexture !== null ) { + bind: bind, + update: update, - this.boneTexture.dispose(); + dispose: dispose - this.boneTexture = null; + }; - } + } - } + function createCanvasElement() { - fromJSON( json, bones ) { + const canvas = createElementNS( 'canvas' ); + canvas.style.display = 'block'; + return canvas; - this.uuid = json.uuid; + } - for ( let i = 0, l = json.bones.length; i < l; i ++ ) { + function WebGLRenderer( parameters = {} ) { - const uuid = json.bones[ i ]; - let bone = bones[ uuid ]; + this.isWebGLRenderer = true; - if ( bone === undefined ) { + const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(), + _context = parameters.context !== undefined ? parameters.context : null, - console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); - bone = new Bone(); + _depth = parameters.depth !== undefined ? parameters.depth : true, + _stencil = parameters.stencil !== undefined ? parameters.stencil : true, + _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, + _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, + _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default', + _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false; - } + let _alpha; - this.bones.push( bone ); - this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); + if ( _context !== null ) { - } + _alpha = _context.getContextAttributes().alpha; - this.init(); + } else { - return this; + _alpha = parameters.alpha !== undefined ? parameters.alpha : false; } - toJSON() { - - const data = { - metadata: { - version: 4.5, - type: 'Skeleton', - generator: 'Skeleton.toJSON' - }, - bones: [], - boneInverses: [] - }; + let currentRenderList = null; + let currentRenderState = null; - data.uuid = this.uuid; + // render() can be called from within a callback triggered by another render. + // We track this so that the nested render call gets its list and state isolated from the parent render call. - const bones = this.bones; - const boneInverses = this.boneInverses; + const renderListStack = []; + const renderStateStack = []; - for ( let i = 0, l = bones.length; i < l; i ++ ) { + // public properties - const bone = bones[ i ]; - data.bones.push( bone.uuid ); + this.domElement = _canvas; - const boneInverse = boneInverses[ i ]; - data.boneInverses.push( boneInverse.toArray() ); + // Debug configuration container + this.debug = { - } + /** + * Enables error checking and reporting when shader programs are being compiled + * @type {boolean} + */ + checkShaderErrors: true + }; - return data; + // clearing - } + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; - } + // scene graph - class InstancedBufferAttribute extends BufferAttribute { + this.sortObjects = true; - constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { + // user-defined clipping - super( array, itemSize, normalized ); + this.clippingPlanes = []; + this.localClippingEnabled = false; - this.isInstancedBufferAttribute = true; + // physically based shading - this.meshPerAttribute = meshPerAttribute; + this.outputEncoding = LinearEncoding; - } + // physical lights - copy( source ) { + this.physicallyCorrectLights = false; - super.copy( source ); + // tone mapping - this.meshPerAttribute = source.meshPerAttribute; + this.toneMapping = NoToneMapping; + this.toneMappingExposure = 1.0; - return this; + // - } + Object.defineProperties( this, { - toJSON() { + // @deprecated since r136, 0e21088102b4de7e0a0a33140620b7a3424b9e6d - const data = super.toJSON(); + gammaFactor: { + get: function () { - data.meshPerAttribute = this.meshPerAttribute; + console.warn( 'THREE.WebGLRenderer: .gammaFactor has been removed.' ); + return 2; - data.isInstancedBufferAttribute = true; + }, + set: function () { - return data; + console.warn( 'THREE.WebGLRenderer: .gammaFactor has been removed.' ); - } + } + } - } + } ); - const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); - const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); + // internal properties - const _instanceIntersects = []; + const _this = this; - const _mesh = /*@__PURE__*/ new Mesh(); + let _isContextLost = false; - class InstancedMesh extends Mesh { + // internal state cache - constructor( geometry, material, count ) { + let _currentActiveCubeFace = 0; + let _currentActiveMipmapLevel = 0; + let _currentRenderTarget = null; + let _currentMaterialId = - 1; - super( geometry, material ); + let _currentCamera = null; - this.isInstancedMesh = true; + const _currentViewport = new Vector4(); + const _currentScissor = new Vector4(); + let _currentScissorTest = null; - this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); - this.instanceColor = null; + // - this.count = count; + let _width = _canvas.width; + let _height = _canvas.height; - this.frustumCulled = false; + let _pixelRatio = 1; + let _opaqueSort = null; + let _transparentSort = null; - } + const _viewport = new Vector4( 0, 0, _width, _height ); + const _scissor = new Vector4( 0, 0, _width, _height ); + let _scissorTest = false; - copy( source, recursive ) { + // frustum - super.copy( source, recursive ); + const _frustum = new Frustum(); - this.instanceMatrix.copy( source.instanceMatrix ); + // clipping - if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); + let _clippingEnabled = false; + let _localClippingEnabled = false; - this.count = source.count; + // transmission - return this; + let _transmissionRenderTarget = null; - } + // camera matrices cache - getColorAt( index, color ) { + const _projScreenMatrix = new Matrix4(); - color.fromArray( this.instanceColor.array, index * 3 ); + const _vector2 = new Vector2(); + const _vector3 = new Vector3(); - } + const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; - getMatrixAt( index, matrix ) { + function getTargetPixelRatio() { - matrix.fromArray( this.instanceMatrix.array, index * 16 ); + return _currentRenderTarget === null ? _pixelRatio : 1; } - raycast( raycaster, intersects ) { + // initialize - const matrixWorld = this.matrixWorld; - const raycastTimes = this.count; + let _gl = _context; - _mesh.geometry = this.geometry; - _mesh.material = this.material; + function getContext( contextNames, contextAttributes ) { - if ( _mesh.material === undefined ) return; + for ( let i = 0; i < contextNames.length; i ++ ) { - for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { + const contextName = contextNames[ i ]; + const context = _canvas.getContext( contextName, contextAttributes ); + if ( context !== null ) return context; - // calculate the world matrix for each instance + } - this.getMatrixAt( instanceId, _instanceLocalMatrix ); + return null; - _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); + } - // the mesh represents this single instance + try { - _mesh.matrixWorld = _instanceWorldMatrix; + const contextAttributes = { + alpha: true, + depth: _depth, + stencil: _stencil, + antialias: _antialias, + premultipliedAlpha: _premultipliedAlpha, + preserveDrawingBuffer: _preserveDrawingBuffer, + powerPreference: _powerPreference, + failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat + }; - _mesh.raycast( raycaster, _instanceIntersects ); + // OffscreenCanvas does not have setAttribute, see #22811 + if ( 'setAttribute' in _canvas ) _canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); - // process the result of raycast + // event listeners must be registered before WebGL context is created, see #12753 + _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); + _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); + _canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { + if ( _gl === null ) { - const intersect = _instanceIntersects[ i ]; - intersect.instanceId = instanceId; - intersect.object = this; - intersects.push( intersect ); + const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; - } + if ( _this.isWebGL1Renderer === true ) { - _instanceIntersects.length = 0; + contextNames.shift(); - } + } - } + _gl = getContext( contextNames, contextAttributes ); - setColorAt( index, color ) { + if ( _gl === null ) { - if ( this.instanceColor === null ) { + if ( getContext( contextNames ) ) { - this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 ); + throw new Error( 'Error creating WebGL context with your selected attributes.' ); - } + } else { - color.toArray( this.instanceColor.array, index * 3 ); + throw new Error( 'Error creating WebGL context.' ); - } + } - setMatrixAt( index, matrix ) { + } - matrix.toArray( this.instanceMatrix.array, index * 16 ); + } - } + // Some experimental-webgl implementations do not have getShaderPrecisionFormat - updateMorphTargets() { + if ( _gl.getShaderPrecisionFormat === undefined ) { - } + _gl.getShaderPrecisionFormat = function () { - dispose() { + return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - this.dispatchEvent( { type: 'dispose' } ); + }; - } + } - } + } catch ( error ) { - class LineBasicMaterial extends Material { + console.error( 'THREE.WebGLRenderer: ' + error.message ); + throw error; - constructor( parameters ) { + } - super(); + let extensions, capabilities, state, info; + let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; + let programCache, materials, renderLists, renderStates, clipping, shadowMap; - this.isLineBasicMaterial = true; + let background, morphtargets, bufferRenderer, indexedBufferRenderer; - this.type = 'LineBasicMaterial'; + let utils, bindingStates, uniformsGroups; - this.color = new Color( 0xffffff ); + function initGLContext() { - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; + extensions = new WebGLExtensions( _gl ); - this.fog = true; + capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - this.setValues( parameters ); + extensions.init( capabilities ); - } + utils = new WebGLUtils( _gl, extensions, capabilities ); + state = new WebGLState( _gl, extensions, capabilities ); - copy( source ) { + info = new WebGLInfo(); + properties = new WebGLProperties(); + textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); + cubemaps = new WebGLCubeMaps( _this ); + cubeuvmaps = new WebGLCubeUVMaps( _this ); + attributes = new WebGLAttributes( _gl, capabilities ); + bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); + geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); + objects = new WebGLObjects( _gl, geometries, attributes, info ); + morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); + clipping = new WebGLClipping( properties ); + programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); + materials = new WebGLMaterials( _this, properties ); + renderLists = new WebGLRenderLists(); + renderStates = new WebGLRenderStates( extensions, capabilities ); + background = new WebGLBackground( _this, cubemaps, state, objects, _alpha, _premultipliedAlpha ); + shadowMap = new WebGLShadowMap( _this, objects, capabilities ); + uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); - super.copy( source ); + bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); + indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - this.color.copy( source.color ); + info.programs = programCache.programs; - this.linewidth = source.linewidth; - this.linecap = source.linecap; - this.linejoin = source.linejoin; + _this.capabilities = capabilities; + _this.extensions = extensions; + _this.properties = properties; + _this.renderLists = renderLists; + _this.shadowMap = shadowMap; + _this.state = state; + _this.info = info; - this.fog = source.fog; + } - return this; + initGLContext(); - } + // xr - } + const xr = new WebXRManager( _this, _gl ); - const _start$1 = /*@__PURE__*/ new Vector3(); - const _end$1 = /*@__PURE__*/ new Vector3(); - const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); - const _ray$1 = /*@__PURE__*/ new Ray(); - const _sphere$1 = /*@__PURE__*/ new Sphere(); + this.xr = xr; - class Line extends Object3D { + // API - constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { + this.getContext = function () { - super(); + return _gl; - this.isLine = true; + }; - this.type = 'Line'; + this.getContextAttributes = function () { - this.geometry = geometry; - this.material = material; + return _gl.getContextAttributes(); - this.updateMorphTargets(); + }; - } + this.forceContextLoss = function () { - copy( source, recursive ) { + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.loseContext(); - super.copy( source, recursive ); + }; - this.material = source.material; - this.geometry = source.geometry; + this.forceContextRestore = function () { - return this; + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.restoreContext(); - } + }; - computeLineDistances() { + this.getPixelRatio = function () { - const geometry = this.geometry; + return _pixelRatio; - // we assume non-indexed geometry + }; - if ( geometry.index === null ) { + this.setPixelRatio = function ( value ) { - const positionAttribute = geometry.attributes.position; - const lineDistances = [ 0 ]; + if ( value === undefined ) return; - for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { + _pixelRatio = value; - _start$1.fromBufferAttribute( positionAttribute, i - 1 ); - _end$1.fromBufferAttribute( positionAttribute, i ); + this.setSize( _width, _height, false ); - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += _start$1.distanceTo( _end$1 ); + }; - } + this.getSize = function ( target ) { - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); + return target.set( _width, _height ); - } else { + }; - console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + this.setSize = function ( width, height, updateStyle ) { - } + if ( xr.isPresenting ) { - return this; + console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); + return; - } + } - raycast( raycaster, intersects ) { + _width = width; + _height = height; - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Line.threshold; - const drawRange = geometry.drawRange; + _canvas.width = Math.floor( width * _pixelRatio ); + _canvas.height = Math.floor( height * _pixelRatio ); - // Checking boundingSphere distance to ray + if ( updateStyle !== false ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; - _sphere$1.copy( geometry.boundingSphere ); - _sphere$1.applyMatrix4( matrixWorld ); - _sphere$1.radius += threshold; + } - if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; + this.setViewport( 0, 0, width, height ); - // + }; - _inverseMatrix$1.copy( matrixWorld ).invert(); - _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); + this.getDrawingBufferSize = function ( target ) { - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; + return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - const vStart = new Vector3(); - const vEnd = new Vector3(); - const interSegment = new Vector3(); - const interRay = new Vector3(); - const step = this.isLineSegments ? 2 : 1; + }; - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; + this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - if ( index !== null ) { + _width = width; + _height = height; - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); + _pixelRatio = pixelRatio; - for ( let i = start, l = end - 1; i < l; i += step ) { + _canvas.width = Math.floor( width * pixelRatio ); + _canvas.height = Math.floor( height * pixelRatio ); - const a = index.getX( i ); - const b = index.getX( i + 1 ); + this.setViewport( 0, 0, width, height ); - vStart.fromBufferAttribute( positionAttribute, a ); - vEnd.fromBufferAttribute( positionAttribute, b ); + }; - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + this.getCurrentViewport = function ( target ) { - if ( distSq > localThresholdSq ) continue; + return target.copy( _currentViewport ); - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + }; - const distance = raycaster.ray.origin.distanceTo( interRay ); + this.getViewport = function ( target ) { - if ( distance < raycaster.near || distance > raycaster.far ) continue; + return target.copy( _viewport ); - intersects.push( { + }; - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this + this.setViewport = function ( x, y, width, height ) { - } ); + if ( x.isVector4 ) { - } + _viewport.set( x.x, x.y, x.z, x.w ); } else { - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); + _viewport.set( x, y, width, height ); - for ( let i = start, l = end - 1; i < l; i += step ) { + } - vStart.fromBufferAttribute( positionAttribute, i ); - vEnd.fromBufferAttribute( positionAttribute, i + 1 ); + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + }; - if ( distSq > localThresholdSq ) continue; + this.getScissor = function ( target ) { - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + return target.copy( _scissor ); - const distance = raycaster.ray.origin.distanceTo( interRay ); + }; - if ( distance < raycaster.near || distance > raycaster.far ) continue; + this.setScissor = function ( x, y, width, height ) { - intersects.push( { + if ( x.isVector4 ) { - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this + _scissor.set( x.x, x.y, x.z, x.w ); - } ); + } else { - } + _scissor.set( x, y, width, height ); } - } + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - updateMorphTargets() { + }; - const geometry = this.geometry; + this.getScissorTest = function () { - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); + return _scissorTest; - if ( keys.length > 0 ) { + }; - const morphAttribute = morphAttributes[ keys[ 0 ] ]; + this.setScissorTest = function ( boolean ) { - if ( morphAttribute !== undefined ) { + state.setScissorTest( _scissorTest = boolean ); - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + }; - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + this.setOpaqueSort = function ( method ) { - const name = morphAttribute[ m ].name || String( m ); + _opaqueSort = method; - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + }; - } + this.setTransparentSort = function ( method ) { - } + _transparentSort = method; - } + }; - } + // Clearing - } + this.getClearColor = function ( target ) { - const _start = /*@__PURE__*/ new Vector3(); - const _end = /*@__PURE__*/ new Vector3(); + return target.copy( background.getClearColor() ); - class LineSegments extends Line { + }; - constructor( geometry, material ) { + this.setClearColor = function () { - super( geometry, material ); + background.setClearColor.apply( background, arguments ); - this.isLineSegments = true; + }; - this.type = 'LineSegments'; + this.getClearAlpha = function () { - } + return background.getClearAlpha(); - computeLineDistances() { + }; - const geometry = this.geometry; + this.setClearAlpha = function () { - // we assume non-indexed geometry + background.setClearAlpha.apply( background, arguments ); - if ( geometry.index === null ) { + }; - const positionAttribute = geometry.attributes.position; - const lineDistances = []; + this.clear = function ( color = true, depth = true, stencil = true ) { - for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { + let bits = 0; - _start.fromBufferAttribute( positionAttribute, i ); - _end.fromBufferAttribute( positionAttribute, i + 1 ); + if ( color ) bits |= 16384; + if ( depth ) bits |= 256; + if ( stencil ) bits |= 1024; - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); + _gl.clear( bits ); - } + }; - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); + this.clearColor = function () { - } else { + this.clear( true, false, false ); - console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + }; - } + this.clearDepth = function () { - return this; + this.clear( false, true, false ); - } + }; - } + this.clearStencil = function () { - class LineLoop extends Line { + this.clear( false, false, true ); - constructor( geometry, material ) { + }; - super( geometry, material ); + // - this.isLineLoop = true; + this.dispose = function () { - this.type = 'LineLoop'; + _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); + _canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - } + renderLists.dispose(); + renderStates.dispose(); + properties.dispose(); + cubemaps.dispose(); + cubeuvmaps.dispose(); + objects.dispose(); + bindingStates.dispose(); + uniformsGroups.dispose(); + programCache.dispose(); - } + xr.dispose(); - class PointsMaterial extends Material { + xr.removeEventListener( 'sessionstart', onXRSessionStart ); + xr.removeEventListener( 'sessionend', onXRSessionEnd ); - constructor( parameters ) { + if ( _transmissionRenderTarget ) { - super(); + _transmissionRenderTarget.dispose(); + _transmissionRenderTarget = null; - this.isPointsMaterial = true; + } - this.type = 'PointsMaterial'; + animation.stop(); - this.color = new Color( 0xffffff ); + }; - this.map = null; + // Events - this.alphaMap = null; + function onContextLost( event ) { - this.size = 1; - this.sizeAttenuation = true; + event.preventDefault(); - this.fog = true; + console.log( 'THREE.WebGLRenderer: Context Lost.' ); - this.setValues( parameters ); + _isContextLost = true; } - copy( source ) { + function onContextRestore( /* event */ ) { - super.copy( source ); + console.log( 'THREE.WebGLRenderer: Context Restored.' ); - this.color.copy( source.color ); + _isContextLost = false; - this.map = source.map; + const infoAutoReset = info.autoReset; + const shadowMapEnabled = shadowMap.enabled; + const shadowMapAutoUpdate = shadowMap.autoUpdate; + const shadowMapNeedsUpdate = shadowMap.needsUpdate; + const shadowMapType = shadowMap.type; - this.alphaMap = source.alphaMap; + initGLContext(); - this.size = source.size; - this.sizeAttenuation = source.sizeAttenuation; + info.autoReset = infoAutoReset; + shadowMap.enabled = shadowMapEnabled; + shadowMap.autoUpdate = shadowMapAutoUpdate; + shadowMap.needsUpdate = shadowMapNeedsUpdate; + shadowMap.type = shadowMapType; - this.fog = source.fog; + } - return this; + function onContextCreationError( event ) { + + console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); } - } + function onMaterialDispose( event ) { - const _inverseMatrix = /*@__PURE__*/ new Matrix4(); - const _ray = /*@__PURE__*/ new Ray(); - const _sphere = /*@__PURE__*/ new Sphere(); - const _position$2 = /*@__PURE__*/ new Vector3(); + const material = event.target; - class Points extends Object3D { + material.removeEventListener( 'dispose', onMaterialDispose ); - constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { + deallocateMaterial( material ); - super(); + } - this.isPoints = true; + // Buffer deallocation - this.type = 'Points'; + function deallocateMaterial( material ) { - this.geometry = geometry; - this.material = material; + releaseMaterialProgramReferences( material ); - this.updateMorphTargets(); + properties.remove( material ); } - copy( source, recursive ) { - super.copy( source, recursive ); + function releaseMaterialProgramReferences( material ) { - this.material = source.material; - this.geometry = source.geometry; + const programs = properties.get( material ).programs; - return this; + if ( programs !== undefined ) { + + programs.forEach( function ( program ) { + + programCache.releaseProgram( program ); + + } ); + + if ( material.isShaderMaterial ) { + + programCache.releaseShaderCache( material ); + + } + + } } - raycast( raycaster, intersects ) { + // Buffer rendering - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Points.threshold; - const drawRange = geometry.drawRange; + this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - // Checking boundingSphere distance to ray + if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - _sphere.copy( geometry.boundingSphere ); - _sphere.applyMatrix4( matrixWorld ); - _sphere.radius += threshold; + const program = setProgram( camera, scene, geometry, material, object ); - if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; + state.setMaterial( material, frontFaceCW ); // - _inverseMatrix.copy( matrixWorld ).invert(); - _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); + let index = geometry.index; + const position = geometry.attributes.position; - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; + // - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; + if ( index === null ) { - if ( index !== null ) { + if ( position === undefined || position.count === 0 ) return; - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); + } else if ( index.count === 0 ) { - for ( let i = start, il = end; i < il; i ++ ) { + return; - const a = index.getX( i ); + } - _position$2.fromBufferAttribute( positionAttribute, a ); + // - testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); + let rangeFactor = 1; - } + if ( material.wireframe === true ) { - } else { + index = geometries.getWireframeAttribute( geometry ); + rangeFactor = 2; - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); + } - for ( let i = start, l = end; i < l; i ++ ) { + bindingStates.setup( object, material, program, geometry, index ); - _position$2.fromBufferAttribute( positionAttribute, i ); + let attribute; + let renderer = bufferRenderer; - testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); + if ( index !== null ) { - } + attribute = attributes.get( index ); + + renderer = indexedBufferRenderer; + renderer.setIndex( attribute ); } - } + // - updateMorphTargets() { + const dataCount = ( index !== null ) ? index.count : position.count; - const geometry = this.geometry; + const rangeStart = geometry.drawRange.start * rangeFactor; + const rangeCount = geometry.drawRange.count * rangeFactor; - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); + const groupStart = group !== null ? group.start * rangeFactor : 0; + const groupCount = group !== null ? group.count * rangeFactor : Infinity; - if ( keys.length > 0 ) { + const drawStart = Math.max( rangeStart, groupStart ); + const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; - const morphAttribute = morphAttributes[ keys[ 0 ] ]; + const drawCount = Math.max( 0, drawEnd - drawStart + 1 ); - if ( morphAttribute !== undefined ) { + if ( drawCount === 0 ) return; - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + // - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + if ( object.isMesh ) { - const name = morphAttribute[ m ].name || String( m ); + if ( material.wireframe === true ) { - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); + renderer.setMode( 1 ); - } + } else { - } + renderer.setMode( 4 ); - } + } - } + } else if ( object.isLine ) { - } + let lineWidth = material.linewidth; - function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { + if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - const rayPointDistanceSq = _ray.distanceSqToPoint( point ); + state.setLineWidth( lineWidth * getTargetPixelRatio() ); - if ( rayPointDistanceSq < localThresholdSq ) { + if ( object.isLineSegments ) { - const intersectPoint = new Vector3(); + renderer.setMode( 1 ); - _ray.closestPointToPoint( point, intersectPoint ); - intersectPoint.applyMatrix4( matrixWorld ); + } else if ( object.isLineLoop ) { - const distance = raycaster.ray.origin.distanceTo( intersectPoint ); + renderer.setMode( 2 ); - if ( distance < raycaster.near || distance > raycaster.far ) return; + } else { - intersects.push( { + renderer.setMode( 3 ); - distance: distance, - distanceToRay: Math.sqrt( rayPointDistanceSq ), - point: intersectPoint, - index: index, - face: null, - object: object + } - } ); + } else if ( object.isPoints ) { - } + renderer.setMode( 0 ); - } + } else if ( object.isSprite ) { - class VideoTexture extends Texture { + renderer.setMode( 4 ); - constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + } - super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + if ( object.isInstancedMesh ) { - this.isVideoTexture = true; + renderer.renderInstances( drawStart, drawCount, object.count ); - this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; - this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; + } else if ( geometry.isInstancedBufferGeometry ) { - this.generateMipmaps = false; + const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount ); - const scope = this; + renderer.renderInstances( drawStart, drawCount, instanceCount ); - function updateVideo() { + } else { - scope.needsUpdate = true; - video.requestVideoFrameCallback( updateVideo ); + renderer.render( drawStart, drawCount ); } - if ( 'requestVideoFrameCallback' in video ) { + }; - video.requestVideoFrameCallback( updateVideo ); + // Compile - } + this.compile = function ( scene, camera ) { - } + function prepare( material, scene, object ) { - clone() { + if ( material.transparent === true && material.side === DoubleSide ) { - return new this.constructor( this.image ).copy( this ); + material.side = BackSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - } + material.side = FrontSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - update() { + material.side = DoubleSide; - const video = this.image; - const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; + } else { - if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { + getProgram( material, scene, object ); - this.needsUpdate = true; + } } - } - - } - - class FramebufferTexture extends Texture { + currentRenderState = renderStates.get( scene ); + currentRenderState.init(); - constructor( width, height, format ) { + renderStateStack.push( currentRenderState ); - super( { width, height } ); + scene.traverseVisible( function ( object ) { - this.isFramebufferTexture = true; + if ( object.isLight && object.layers.test( camera.layers ) ) { - this.format = format; + currentRenderState.pushLight( object ); - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + if ( object.castShadow ) { - this.generateMipmaps = false; + currentRenderState.pushShadow( object ); - this.needsUpdate = true; + } - } + } - } + } ); - class CompressedTexture extends Texture { + currentRenderState.setupLights( _this.physicallyCorrectLights ); - constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { + scene.traverse( function ( object ) { - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + const material = object.material; - this.isCompressedTexture = true; + if ( material ) { - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; + if ( Array.isArray( material ) ) { - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + for ( let i = 0; i < material.length; i ++ ) { - this.flipY = false; + const material2 = material[ i ]; - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + prepare( material2, scene, object ); - this.generateMipmaps = false; + } - } + } else { - } + prepare( material, scene, object ); - class CanvasTexture extends Texture { + } - constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + } - super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + } ); - this.isCanvasTexture = true; + renderStateStack.pop(); + currentRenderState = null; - this.needsUpdate = true; + }; - } + // Animation Loop - } + let onAnimationFrameCallback = null; - /** - * Extensible curve object. - * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following curves inherit from THREE.Curve: - * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve - * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * - * A series of curves can be represented as a THREE.CurvePath. - * - **/ + function onAnimationFrame( time ) { - class Curve { + if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); - constructor() { + } - this.type = 'Curve'; + function onXRSessionStart() { - this.arcLengthDivisions = 200; + animation.stop(); } - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] - - getPoint( /* t, optionalTarget */ ) { + function onXRSessionEnd() { - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; + animation.start(); } - // Get point at relative position in curve according to arc length - // - u [0 .. 1] + const animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - getPointAt( u, optionalTarget ) { + if ( typeof self !== 'undefined' ) animation.setContext( self ); - const t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); + this.setAnimationLoop = function ( callback ) { - } + onAnimationFrameCallback = callback; + xr.setAnimationLoop( callback ); - // Get sequence of points using getPoint( t ) + ( callback === null ) ? animation.stop() : animation.start(); - getPoints( divisions = 5 ) { + }; - const points = []; + xr.addEventListener( 'sessionstart', onXRSessionStart ); + xr.addEventListener( 'sessionend', onXRSessionEnd ); - for ( let d = 0; d <= divisions; d ++ ) { + // Rendering - points.push( this.getPoint( d / divisions ) ); + this.render = function ( scene, camera ) { + + if ( camera !== undefined && camera.isCamera !== true ) { + + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; } - return points; + if ( _isContextLost === true ) return; - } + // update scene graph - // Get sequence of points using getPointAt( u ) + if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - getSpacedPoints( divisions = 5 ) { + // update camera matrices and frustum - const points = []; + if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); - for ( let d = 0; d <= divisions; d ++ ) { + if ( xr.enabled === true && xr.isPresenting === true ) { - points.push( this.getPointAt( d / divisions ) ); + if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); - } + camera = xr.getCamera(); // use XR camera for rendering - return points; + } - } + // + if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); - // Get total curve arc length + currentRenderState = renderStates.get( scene, renderStateStack.length ); + currentRenderState.init(); - getLength() { + renderStateStack.push( currentRenderState ); - const lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromProjectionMatrix( _projScreenMatrix ); - } + _localClippingEnabled = this.localClippingEnabled; + _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); - // Get list of cumulative segment lengths + currentRenderList = renderLists.get( scene, renderListStack.length ); + currentRenderList.init(); - getLengths( divisions = this.arcLengthDivisions ) { + renderListStack.push( currentRenderList ); - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { + projectObject( scene, camera, 0, _this.sortObjects ); - return this.cacheArcLengths; + currentRenderList.finish(); - } + if ( _this.sortObjects === true ) { - this.needsUpdate = false; + currentRenderList.sort( _opaqueSort, _transparentSort ); - const cache = []; - let current, last = this.getPoint( 0 ); - let sum = 0; + } - cache.push( 0 ); + // - for ( let p = 1; p <= divisions; p ++ ) { + if ( _clippingEnabled === true ) clipping.beginShadows(); - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; + const shadowsArray = currentRenderState.state.shadowsArray; - } + shadowMap.render( shadowsArray, scene, camera ); - this.cacheArcLengths = cache; + if ( _clippingEnabled === true ) clipping.endShadows(); - return cache; // { sums: cache, sum: sum }; Sum is in the last element. + // - } + if ( this.info.autoReset === true ) this.info.reset(); - updateArcLengths() { + // - this.needsUpdate = true; - this.getLengths(); + background.render( currentRenderList, scene ); - } + // render scene - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant + currentRenderState.setupLights( _this.physicallyCorrectLights ); - getUtoTmapping( u, distance ) { + if ( camera.isArrayCamera ) { - const arcLengths = this.getLengths(); + const cameras = camera.cameras; - let i = 0; - const il = arcLengths.length; + for ( let i = 0, l = cameras.length; i < l; i ++ ) { - let targetArcLength; // The targeted u distance value to get + const camera2 = cameras[ i ]; - if ( distance ) { + renderScene( currentRenderList, scene, camera2, camera2.viewport ); - targetArcLength = distance; + } } else { - targetArcLength = u * arcLengths[ il - 1 ]; + renderScene( currentRenderList, scene, camera ); } - // binary search for the index with largest value smaller than target u distance - - let low = 0, high = il - 1, comparison; + // - while ( low <= high ) { + if ( _currentRenderTarget !== null ) { - i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats + // resolve multisample renderbuffers to a single-sample texture if necessary - comparison = arcLengths[ i ] - targetArcLength; + textures.updateMultisampleRenderTarget( _currentRenderTarget ); - if ( comparison < 0 ) { + // Generate mipmap if we're using any kind of mipmap filtering - low = i + 1; + textures.updateRenderTargetMipmap( _currentRenderTarget ); - } else if ( comparison > 0 ) { + } - high = i - 1; + // - } else { + if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); - high = i; - break; + // _gl.finish(); - // DONE + bindingStates.resetDefaultState(); + _currentMaterialId = - 1; + _currentCamera = null; - } + renderStateStack.pop(); - } + if ( renderStateStack.length > 0 ) { - i = high; + currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; - if ( arcLengths[ i ] === targetArcLength ) { + } else { - return i / ( il - 1 ); + currentRenderState = null; } - // we could get finer grain at lengths, or use simple interpolation between two points + renderListStack.pop(); - const lengthBefore = arcLengths[ i ]; - const lengthAfter = arcLengths[ i + 1 ]; + if ( renderListStack.length > 0 ) { - const segmentLength = lengthAfter - lengthBefore; + currentRenderList = renderListStack[ renderListStack.length - 1 ]; - // determine where we are between the 'before' and 'after' points + } else { - const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + currentRenderList = null; - // add that fractional amount to t + } - const t = ( i + segmentFraction ) / ( il - 1 ); + }; - return t; + function projectObject( object, camera, groupOrder, sortObjects ) { - } + if ( object.visible === false ) return; - // Returns a unit vector tangent at t - // In case any sub curve does not implement its tangent derivation, - // 2 points a small delta apart will be used to find its gradient - // which seems to give a reasonable approximation + const visible = object.layers.test( camera.layers ); - getTangent( t, optionalTarget ) { + if ( visible ) { - const delta = 0.0001; - let t1 = t - delta; - let t2 = t + delta; + if ( object.isGroup ) { - // Capping in case of danger + groupOrder = object.renderOrder; - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; + } else if ( object.isLOD ) { - const pt1 = this.getPoint( t1 ); - const pt2 = this.getPoint( t2 ); - - const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); + if ( object.autoUpdate === true ) object.update( camera ); - tangent.copy( pt2 ).sub( pt1 ).normalize(); + } else if ( object.isLight ) { - return tangent; + currentRenderState.pushLight( object ); - } + if ( object.castShadow ) { - getTangentAt( u, optionalTarget ) { + currentRenderState.pushShadow( object ); - const t = this.getUtoTmapping( u ); - return this.getTangent( t, optionalTarget ); + } - } + } else if ( object.isSprite ) { - computeFrenetFrames( segments, closed ) { + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + if ( sortObjects ) { - const normal = new Vector3(); + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - const tangents = []; - const normals = []; - const binormals = []; + } - const vec = new Vector3(); - const mat = new Matrix4(); + const geometry = objects.update( object ); + const material = object.material; - // compute the tangent vectors for each segment on the curve + if ( material.visible ) { - for ( let i = 0; i <= segments; i ++ ) { + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - const u = i / segments; + } - tangents[ i ] = this.getTangentAt( u, new Vector3() ); + } - } + } else if ( object.isMesh || object.isLine || object.isPoints ) { - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component + if ( object.isSkinnedMesh ) { - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - let min = Number.MAX_VALUE; - const tx = Math.abs( tangents[ 0 ].x ); - const ty = Math.abs( tangents[ 0 ].y ); - const tz = Math.abs( tangents[ 0 ].z ); + // update skeleton only once in a frame - if ( tx <= min ) { + if ( object.skeleton.frame !== info.render.frame ) { - min = tx; - normal.set( 1, 0, 0 ); + object.skeleton.update(); + object.skeleton.frame = info.render.frame; - } + } - if ( ty <= min ) { + } - min = ty; - normal.set( 0, 1, 0 ); + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - } + if ( sortObjects ) { - if ( tz <= min ) { + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - normal.set( 0, 0, 1 ); + } - } + const geometry = objects.update( object ); + const material = object.material; - vec.crossVectors( tangents[ 0 ], normal ).normalize(); + if ( Array.isArray( material ) ) { - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + const groups = geometry.groups; + for ( let i = 0, l = groups.length; i < l; i ++ ) { - // compute the slowly-varying normal and binormal vectors for each segment on the curve + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; - for ( let i = 1; i <= segments; i ++ ) { + if ( groupMaterial && groupMaterial.visible ) { - normals[ i ] = normals[ i - 1 ].clone(); + currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); - binormals[ i ] = binormals[ i - 1 ].clone(); + } - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); + } - if ( vec.length() > Number.EPSILON ) { + } else if ( material.visible ) { - vec.normalize(); + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + } - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + } } - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - } - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + const children = object.children; - if ( closed === true ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; + projectObject( children[ i ], camera, groupOrder, sortObjects ); - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { + } - theta = - theta; + } - } + function renderScene( currentRenderList, scene, camera, viewport ) { - for ( let i = 1; i <= segments; i ++ ) { + const opaqueObjects = currentRenderList.opaque; + const transmissiveObjects = currentRenderList.transmissive; + const transparentObjects = currentRenderList.transparent; - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + currentRenderState.setupLightsView( camera ); - } + if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera ); - } + if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; + if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); + if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); + if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); - } + // Ensure depth buffer writing is enabled so it can be cleared on next render - clone() { + state.buffers.depth.setTest( true ); + state.buffers.depth.setMask( true ); + state.buffers.color.setMask( true ); - return new this.constructor().copy( this ); + state.setPolygonOffset( false ); } - copy( source ) { + function renderTransmissionPass( opaqueObjects, scene, camera ) { - this.arcLengthDivisions = source.arcLengthDivisions; + const isWebGL2 = capabilities.isWebGL2; - return this; + if ( _transmissionRenderTarget === null ) { - } + _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { + generateMipmaps: true, + type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, + minFilter: LinearMipmapLinearFilter, + samples: ( isWebGL2 && _antialias === true ) ? 4 : 0 + } ); - toJSON() { + } - const data = { - metadata: { - version: 4.5, - type: 'Curve', - generator: 'Curve.toJSON' - } - }; + _this.getDrawingBufferSize( _vector2 ); - data.arcLengthDivisions = this.arcLengthDivisions; - data.type = this.type; + if ( isWebGL2 ) { - return data; + _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); - } + } else { - fromJSON( json ) { + _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); - this.arcLengthDivisions = json.arcLengthDivisions; + } - return this; + // - } + const currentRenderTarget = _this.getRenderTarget(); + _this.setRenderTarget( _transmissionRenderTarget ); + _this.clear(); - } + // Turn off the features which can affect the frag color for opaque objects pass. + // Otherwise they are applied twice in opaque objects pass and transmission objects pass. + const currentToneMapping = _this.toneMapping; + _this.toneMapping = NoToneMapping; - class EllipseCurve extends Curve { + renderObjects( opaqueObjects, scene, camera ); - constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { + _this.toneMapping = currentToneMapping; - super(); + textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); + textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - this.isEllipseCurve = true; + _this.setRenderTarget( currentRenderTarget ); - this.type = 'EllipseCurve'; + } - this.aX = aX; - this.aY = aY; + function renderObjects( renderList, scene, camera ) { - this.xRadius = xRadius; - this.yRadius = yRadius; + const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; + for ( let i = 0, l = renderList.length; i < l; i ++ ) { - this.aClockwise = aClockwise; + const renderItem = renderList[ i ]; - this.aRotation = aRotation; + const object = renderItem.object; + const geometry = renderItem.geometry; + const material = overrideMaterial === null ? renderItem.material : overrideMaterial; + const group = renderItem.group; + + if ( object.layers.test( camera.layers ) ) { + + renderObject( object, scene, camera, geometry, material, group ); + + } + + } } - getPoint( t, optionalTarget ) { + function renderObject( object, scene, camera, geometry, material, group ) { - const point = optionalTarget || new Vector2(); + object.onBeforeRender( _this, scene, camera, geometry, material, group ); - const twoPi = Math.PI * 2; - let deltaAngle = this.aEndAngle - this.aStartAngle; - const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + material.onBeforeRender( _this, scene, camera, geometry, object, group ); - if ( deltaAngle < Number.EPSILON ) { + if ( material.transparent === true && material.side === DoubleSide ) { - if ( samePoints ) { + material.side = BackSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - deltaAngle = 0; + material.side = FrontSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - } else { + material.side = DoubleSide; - deltaAngle = twoPi; + } else { - } + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); } - if ( this.aClockwise === true && ! samePoints ) { + object.onAfterRender( _this, scene, camera, geometry, material, group ); - if ( deltaAngle === twoPi ) { + } - deltaAngle = - twoPi; + function getProgram( material, scene, object ) { - } else { + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - deltaAngle = deltaAngle - twoPi; + const materialProperties = properties.get( material ); - } + const lights = currentRenderState.state.lights; + const shadowsArray = currentRenderState.state.shadowsArray; - } + const lightsStateVersion = lights.state.version; - const angle = this.aStartAngle + t * deltaAngle; - let x = this.aX + this.xRadius * Math.cos( angle ); - let y = this.aY + this.yRadius * Math.sin( angle ); + const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); + const programCacheKey = programCache.getProgramCacheKey( parameters ); - if ( this.aRotation !== 0 ) { + let programs = materialProperties.programs; - const cos = Math.cos( this.aRotation ); - const sin = Math.sin( this.aRotation ); + // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change - const tx = x - this.aX; - const ty = y - this.aY; + materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; + materialProperties.fog = scene.fog; + materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; + if ( programs === undefined ) { - } + // new material - return point.set( x, y ); + material.addEventListener( 'dispose', onMaterialDispose ); - } + programs = new Map(); + materialProperties.programs = programs; - copy( source ) { + } - super.copy( source ); + let program = programs.get( programCacheKey ); - this.aX = source.aX; - this.aY = source.aY; + if ( program !== undefined ) { - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; + // early out if program and light state is identical - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; + if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { - this.aClockwise = source.aClockwise; + updateCommonMaterialProperties( material, parameters ); - this.aRotation = source.aRotation; + return program; - return this; + } - } + } else { - toJSON() { + parameters.uniforms = programCache.getUniforms( material ); - const data = super.toJSON(); + material.onBuild( object, parameters, _this ); - data.aX = this.aX; - data.aY = this.aY; + material.onBeforeCompile( parameters, _this ); - data.xRadius = this.xRadius; - data.yRadius = this.yRadius; + program = programCache.acquireProgram( parameters, programCacheKey ); + programs.set( programCacheKey, program ); - data.aStartAngle = this.aStartAngle; - data.aEndAngle = this.aEndAngle; + materialProperties.uniforms = parameters.uniforms; - data.aClockwise = this.aClockwise; + } - data.aRotation = this.aRotation; + const uniforms = materialProperties.uniforms; - return data; + if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { - } + uniforms.clippingPlanes = clipping.uniform; - fromJSON( json ) { + } - super.fromJSON( json ); + updateCommonMaterialProperties( material, parameters ); - this.aX = json.aX; - this.aY = json.aY; + // store the light setup it was created for - this.xRadius = json.xRadius; - this.yRadius = json.yRadius; + materialProperties.needsLights = materialNeedsLights( material ); + materialProperties.lightsStateVersion = lightsStateVersion; - this.aStartAngle = json.aStartAngle; - this.aEndAngle = json.aEndAngle; + if ( materialProperties.needsLights ) { - this.aClockwise = json.aClockwise; + // wire up the material to this renderer's lighting state - this.aRotation = json.aRotation; + uniforms.ambientLightColor.value = lights.state.ambient; + uniforms.lightProbe.value = lights.state.probe; + uniforms.directionalLights.value = lights.state.directional; + uniforms.directionalLightShadows.value = lights.state.directionalShadow; + uniforms.spotLights.value = lights.state.spot; + uniforms.spotLightShadows.value = lights.state.spotShadow; + uniforms.rectAreaLights.value = lights.state.rectArea; + uniforms.ltc_1.value = lights.state.rectAreaLTC1; + uniforms.ltc_2.value = lights.state.rectAreaLTC2; + uniforms.pointLights.value = lights.state.point; + uniforms.pointLightShadows.value = lights.state.pointShadow; + uniforms.hemisphereLights.value = lights.state.hemi; - return this; + uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; + uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; + uniforms.spotShadowMap.value = lights.state.spotShadowMap; + uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; + uniforms.spotLightMap.value = lights.state.spotLightMap; + uniforms.pointShadowMap.value = lights.state.pointShadowMap; + uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; + // TODO (abelnation): add area lights shadow info to uniforms - } + } - } + const progUniforms = program.getUniforms(); + const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); - class ArcCurve extends EllipseCurve { + materialProperties.currentProgram = program; + materialProperties.uniformsList = uniformsList; - constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + return program; - super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + } - this.isArcCurve = true; + function updateCommonMaterialProperties( material, parameters ) { - this.type = 'ArcCurve'; + const materialProperties = properties.get( material ); + + materialProperties.outputEncoding = parameters.outputEncoding; + materialProperties.instancing = parameters.instancing; + materialProperties.skinning = parameters.skinning; + materialProperties.morphTargets = parameters.morphTargets; + materialProperties.morphNormals = parameters.morphNormals; + materialProperties.morphColors = parameters.morphColors; + materialProperties.morphTargetsCount = parameters.morphTargetsCount; + materialProperties.numClippingPlanes = parameters.numClippingPlanes; + materialProperties.numIntersection = parameters.numClipIntersection; + materialProperties.vertexAlphas = parameters.vertexAlphas; + materialProperties.vertexTangents = parameters.vertexTangents; + materialProperties.toneMapping = parameters.toneMapping; } - } + function setProgram( camera, scene, geometry, material, object ) { - /** - * Centripetal CatmullRom Curve - which is useful for avoiding - * cusps and self-intersections in non-uniform catmull rom curves. - * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf - * - * curve.type accepts centripetal(default), chordal and catmullrom - * curve.tension is used for catmullrom which defaults to 0.5 - */ + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + textures.resetTextureUnits(); - /* - Based on an optimized c++ solution in - - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ - - http://ideone.com/NoEbVM + const fog = scene.fog; + const environment = material.isMeshStandardMaterial ? scene.environment : null; + const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.encoding : LinearEncoding ); + const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); + const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; + const vertexTangents = !! material.normalMap && !! geometry.attributes.tangent; + const morphTargets = !! geometry.morphAttributes.position; + const morphNormals = !! geometry.morphAttributes.normal; + const morphColors = !! geometry.morphAttributes.color; + const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping; - This CubicPoly class could be used for reusing some variables and calculations, - but for three.js curve use, it could be possible inlined and flatten into a single function call - which can be placed in CurveUtils. - */ + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - function CubicPoly() { + const materialProperties = properties.get( material ); + const lights = currentRenderState.state.lights; - let c0 = 0, c1 = 0, c2 = 0, c3 = 0; + if ( _clippingEnabled === true ) { - /* - * Compute coefficients for a cubic polynomial - * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 - * such that - * p(0) = x0, p(1) = x1 - * and - * p'(0) = t0, p'(1) = t1. - */ - function init( x0, x1, t0, t1 ) { + if ( _localClippingEnabled === true || camera !== _currentCamera ) { - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; + const useCache = + camera === _currentCamera && + material.id === _currentMaterialId; - } + // we might want to call this function with some ClippingGroup + // object instead of the material, once it becomes feasible + // (#8465, #8379) + clipping.setState( material, camera, useCache ); - return { + } - initCatmullRom: function ( x0, x1, x2, x3, tension ) { + } - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); + // - }, + let needsProgramChange = false; - initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { + if ( material.version === materialProperties.__version ) { - // compute tangents when parameterized in [t1,t2] - let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; + if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; + needsProgramChange = true; - init( x1, x2, t1, t2 ); + } else if ( materialProperties.outputEncoding !== encoding ) { - }, + needsProgramChange = true; - calc: function ( t ) { + } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { - const t2 = t * t; - const t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; + needsProgramChange = true; - } + } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { - }; + needsProgramChange = true; - } + } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { - // + needsProgramChange = true; - const tmp = /*@__PURE__*/ new Vector3(); - const px = /*@__PURE__*/ new CubicPoly(); - const py = /*@__PURE__*/ new CubicPoly(); - const pz = /*@__PURE__*/ new CubicPoly(); + } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { - class CatmullRomCurve3 extends Curve { + needsProgramChange = true; - constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { + } else if ( materialProperties.envMap !== envMap ) { - super(); + needsProgramChange = true; - this.isCatmullRomCurve3 = true; + } else if ( material.fog === true && materialProperties.fog !== fog ) { - this.type = 'CatmullRomCurve3'; + needsProgramChange = true; - this.points = points; - this.closed = closed; - this.curveType = curveType; - this.tension = tension; + } else if ( materialProperties.numClippingPlanes !== undefined && + ( materialProperties.numClippingPlanes !== clipping.numPlanes || + materialProperties.numIntersection !== clipping.numIntersection ) ) { - } + needsProgramChange = true; - getPoint( t, optionalTarget = new Vector3() ) { + } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { - const point = optionalTarget; + needsProgramChange = true; - const points = this.points; - const l = points.length; + } else if ( materialProperties.vertexTangents !== vertexTangents ) { - const p = ( l - ( this.closed ? 0 : 1 ) ) * t; - let intPoint = Math.floor( p ); - let weight = p - intPoint; + needsProgramChange = true; - if ( this.closed ) { + } else if ( materialProperties.morphTargets !== morphTargets ) { - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; + needsProgramChange = true; - } else if ( weight === 0 && intPoint === l - 1 ) { + } else if ( materialProperties.morphNormals !== morphNormals ) { - intPoint = l - 2; - weight = 1; + needsProgramChange = true; - } + } else if ( materialProperties.morphColors !== morphColors ) { - let p0, p3; // 4 points (p1 & p2 defined below) + needsProgramChange = true; - if ( this.closed || intPoint > 0 ) { + } else if ( materialProperties.toneMapping !== toneMapping ) { - p0 = points[ ( intPoint - 1 ) % l ]; + needsProgramChange = true; - } else { + } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; + needsProgramChange = true; - } + } - const p1 = points[ intPoint % l ]; - const p2 = points[ ( intPoint + 1 ) % l ]; + } else { - if ( this.closed || intPoint + 2 < l ) { + needsProgramChange = true; + materialProperties.__version = material.version; - p3 = points[ ( intPoint + 2 ) % l ]; + } - } else { + // - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; + let program = materialProperties.currentProgram; - } + if ( needsProgramChange === true ) { - if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { + program = getProgram( material, scene, object ); - // init Centripetal / Chordal Catmull-Rom - const pow = this.curveType === 'chordal' ? 0.5 : 0.25; - let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); + } - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; + let refreshProgram = false; + let refreshMaterial = false; + let refreshLights = false; - px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); - py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); - pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); + const p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.uniforms; - } else if ( this.curveType === 'catmullrom' ) { + if ( state.useProgram( program.program ) ) { - px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); - py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); - pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; } - point.set( - px.calc( weight ), - py.calc( weight ), - pz.calc( weight ) - ); + if ( material.id !== _currentMaterialId ) { - return point; + _currentMaterialId = material.id; - } + refreshMaterial = true; - copy( source ) { + } - super.copy( source ); + if ( refreshProgram || _currentCamera !== camera ) { - this.points = []; + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); - for ( let i = 0, l = source.points.length; i < l; i ++ ) { + if ( capabilities.logarithmicDepthBuffer ) { - const point = source.points[ i ]; + p_uniforms.setValue( _gl, 'logDepthBufFC', + 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - this.points.push( point.clone() ); + } - } + if ( _currentCamera !== camera ) { - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; + _currentCamera = camera; - return this; + // lighting uniforms depend on the camera so enforce an update + // now, in case this material supports lights - or later, when + // the next material that does gets activated: - } + refreshMaterial = true; // set to true on material change + refreshLights = true; // remains set until update done - toJSON() { + } - const data = super.toJSON(); + // load material specific uniforms + // (shader material also gets them for the sake of genericity) - data.points = []; + if ( material.isShaderMaterial || + material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshStandardMaterial || + material.envMap ) { - for ( let i = 0, l = this.points.length; i < l; i ++ ) { + const uCamPos = p_uniforms.map.cameraPosition; - const point = this.points[ i ]; - data.points.push( point.toArray() ); + if ( uCamPos !== undefined ) { - } + uCamPos.setValue( _gl, + _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - data.closed = this.closed; - data.curveType = this.curveType; - data.tension = this.tension; + } - return data; + } - } + if ( material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial ) { - fromJSON( json ) { + p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - super.fromJSON( json ); + } - this.points = []; + if ( material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial || + material.isShadowMaterial || + object.isSkinnedMesh ) { - for ( let i = 0, l = json.points.length; i < l; i ++ ) { + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - const point = json.points[ i ]; - this.points.push( new Vector3().fromArray( point ) ); + } } - this.closed = json.closed; - this.curveType = json.curveType; - this.tension = json.tension; + // skinning and morph target uniforms must be set even if material didn't change + // auto-setting of texture unit for bone and morph texture must go before other textures + // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures - return this; + if ( object.isSkinnedMesh ) { - } + p_uniforms.setOptional( _gl, object, 'bindMatrix' ); + p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - } + const skeleton = object.skeleton; - /** - * Bezier Curves formulas obtained from - * https://en.wikipedia.org/wiki/B%C3%A9zier_curve - */ + if ( skeleton ) { - function CatmullRom( t, p0, p1, p2, p3 ) { + if ( capabilities.floatVertexTextures ) { - const v0 = ( p2 - p0 ) * 0.5; - const v1 = ( p3 - p1 ) * 0.5; - const t2 = t * t; - const t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); - } + p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); + p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); - // + } else { - function QuadraticBezierP0( t, p ) { + console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); - const k = 1 - t; - return k * k * p; + } - } + } - function QuadraticBezierP1( t, p ) { + } - return 2 * ( 1 - t ) * t * p; + const morphAttributes = geometry.morphAttributes; - } + if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { - function QuadraticBezierP2( t, p ) { + morphtargets.update( object, geometry, material, program ); - return t * t * p; + } - } + if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - function QuadraticBezier( t, p0, p1, p2 ) { + materialProperties.receiveShadow = object.receiveShadow; + p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); + } - } + // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 - // + if ( material.isMeshGouraudMaterial && material.envMap !== null ) { - function CubicBezierP0( t, p ) { + m_uniforms.envMap.value = envMap; - const k = 1 - t; - return k * k * k * p; + m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - } + } - function CubicBezierP1( t, p ) { + if ( refreshMaterial ) { - const k = 1 - t; - return 3 * k * k * t * p; + p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - } + if ( materialProperties.needsLights ) { - function CubicBezierP2( t, p ) { + // the current material requires lighting info - return 3 * ( 1 - t ) * t * t * p; + // note: all lighting uniforms are always set correctly + // they simply reference the renderer's state for their + // values + // + // use the current material's .needsUpdate flags to set + // the GL state when required - } + markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - function CubicBezierP3( t, p ) { + } - return t * t * t * p; + // refresh uniforms common to several materials - } + if ( fog && material.fog === true ) { - function CubicBezier( t, p0, p1, p2, p3 ) { + materials.refreshFogUniforms( m_uniforms, fog ); - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); + } - } + materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); - class CubicBezierCurve extends Curve { + WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { + } - super(); + if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - this.isCubicBezierCurve = true; + WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); + material.uniformsNeedUpdate = false; - this.type = 'CubicBezierCurve'; + } - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; + if ( material.isSpriteMaterial ) { - } + p_uniforms.setValue( _gl, 'center', object.center ); - getPoint( t, optionalTarget = new Vector2() ) { + } - const point = optionalTarget; + // common matrices - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); + p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); + p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); + // UBOs - return point; + if ( material.isShaderMaterial || material.isRawShaderMaterial ) { - } + const groups = material.uniformsGroups; - copy( source ) { + for ( let i = 0, l = groups.length; i < l; i ++ ) { - super.copy( source ); + if ( capabilities.isWebGL2 ) { - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + const group = groups[ i ]; - return this; + uniformsGroups.update( group, program ); + uniformsGroups.bind( group, program ); - } + } else { - toJSON() { + console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); - const data = super.toJSON(); + } - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); + } - return data; + } + + return program; } - fromJSON( json ) { + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - super.fromJSON( json ); + function markUniformsLightsNeedsUpdate( uniforms, value ) { - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); + uniforms.ambientLightColor.needsUpdate = value; + uniforms.lightProbe.needsUpdate = value; - return this; + uniforms.directionalLights.needsUpdate = value; + uniforms.directionalLightShadows.needsUpdate = value; + uniforms.pointLights.needsUpdate = value; + uniforms.pointLightShadows.needsUpdate = value; + uniforms.spotLights.needsUpdate = value; + uniforms.spotLightShadows.needsUpdate = value; + uniforms.rectAreaLights.needsUpdate = value; + uniforms.hemisphereLights.needsUpdate = value; } - } + function materialNeedsLights( material ) { - class CubicBezierCurve3 extends Curve { + return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || + material.isMeshStandardMaterial || material.isShadowMaterial || + ( material.isShaderMaterial && material.lights === true ); - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { + } - super(); + this.getActiveCubeFace = function () { - this.isCubicBezierCurve3 = true; + return _currentActiveCubeFace; - this.type = 'CubicBezierCurve3'; + }; - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; + this.getActiveMipmapLevel = function () { - } + return _currentActiveMipmapLevel; - getPoint( t, optionalTarget = new Vector3() ) { + }; - const point = optionalTarget; + this.getRenderTarget = function () { - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + return _currentRenderTarget; - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) - ); + }; - return point; + this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { - } + properties.get( renderTarget.texture ).__webglTexture = colorTexture; + properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; - copy( source ) { + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__hasExternalTextures = true; - super.copy( source ); + if ( renderTargetProperties.__hasExternalTextures ) { - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; - return this; + if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { - } + // The multisample_render_to_texture extension doesn't work properly if there + // are midframe flushes and an external depth buffer. Disable use of the extension. + if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { - toJSON() { + console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); + renderTargetProperties.__useRenderToTexture = false; - const data = super.toJSON(); + } - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); + } - return data; + } - } + }; - fromJSON( json ) { + this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { - super.fromJSON( json ); + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__webglFramebuffer = defaultFramebuffer; + renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); + }; - return this; + this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { - } + _currentRenderTarget = renderTarget; + _currentActiveCubeFace = activeCubeFace; + _currentActiveMipmapLevel = activeMipmapLevel; - } + let useDefaultFramebuffer = true; - class LineCurve extends Curve { + if ( renderTarget ) { - constructor( v1 = new Vector2(), v2 = new Vector2() ) { + const renderTargetProperties = properties.get( renderTarget ); - super(); + if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { - this.isLineCurve = true; + // We need to make sure to rebind the framebuffer. + state.bindFramebuffer( 36160, null ); + useDefaultFramebuffer = false; - this.type = 'LineCurve'; + } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { - this.v1 = v1; - this.v2 = v2; + textures.setupRenderTarget( renderTarget ); - } + } else if ( renderTargetProperties.__hasExternalTextures ) { - getPoint( t, optionalTarget = new Vector2() ) { + // Color and depth texture must be rebound in order for the swapchain to update. + textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); - const point = optionalTarget; + } - if ( t === 1 ) { + } - point.copy( this.v2 ); + let framebuffer = null; + let isCube = false; + let isRenderTarget3D = false; - } else { + if ( renderTarget ) { - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + const texture = renderTarget.texture; - } + if ( texture.isData3DTexture || texture.isDataArrayTexture ) { - return point; + isRenderTarget3D = true; - } + } - // Line curve is linear, so we can overwrite default getPointAt - getPointAt( u, optionalTarget ) { + const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - return this.getPoint( u, optionalTarget ); + if ( renderTarget.isWebGLCubeRenderTarget ) { - } + framebuffer = __webglFramebuffer[ activeCubeFace ]; + isCube = true; - getTangent( t, optionalTarget ) { + } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { - const tangent = optionalTarget || new Vector2(); + framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - tangent.copy( this.v2 ).sub( this.v1 ).normalize(); + } else { - return tangent; + framebuffer = __webglFramebuffer; - } + } - copy( source ) { + _currentViewport.copy( renderTarget.viewport ); + _currentScissor.copy( renderTarget.scissor ); + _currentScissorTest = renderTarget.scissorTest; - super.copy( source ); + } else { - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); + _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); + _currentScissorTest = _scissorTest; - return this; + } - } - - toJSON() { + const framebufferBound = state.bindFramebuffer( 36160, framebuffer ); - const data = super.toJSON(); + if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + state.drawBuffers( renderTarget, framebuffer ); - return data; + } - } + state.viewport( _currentViewport ); + state.scissor( _currentScissor ); + state.setScissorTest( _currentScissorTest ); - fromJSON( json ) { + if ( isCube ) { - super.fromJSON( json ); + const textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + } else if ( isRenderTarget3D ) { - return this; + const textureProperties = properties.get( renderTarget.texture ); + const layer = activeCubeFace || 0; + _gl.framebufferTextureLayer( 36160, 36064, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); - } + } - } + _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings - class LineCurve3 extends Curve { + }; - constructor( v1 = new Vector3(), v2 = new Vector3() ) { + this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - super(); + if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - this.isLineCurve3 = true; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - this.type = 'LineCurve3'; + } - this.v1 = v1; - this.v2 = v2; + let framebuffer = properties.get( renderTarget ).__webglFramebuffer; - } - getPoint( t, optionalTarget = new Vector3() ) { + if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { - const point = optionalTarget; + framebuffer = framebuffer[ activeCubeFaceIndex ]; - if ( t === 1 ) { + } - point.copy( this.v2 ); + if ( framebuffer ) { - } else { + state.bindFramebuffer( 36160, framebuffer ); - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + try { - } + const texture = renderTarget.texture; + const textureFormat = texture.format; + const textureType = texture.type; - return point; + if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { - } - // Line curve is linear, so we can overwrite default getPointAt - getPointAt( u, optionalTarget ) { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; - return this.getPoint( u, optionalTarget ); + } - } - copy( source ) { + const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); - super.copy( source ); + if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // Edge and Chrome Mac < 52 (#9513) + ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox + ! halfFloatSupportedByExt ) { - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; - return this; + } - } - toJSON() { + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - const data = super.toJSON(); + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - return data; + } - } - fromJSON( json ) { + } finally { - super.fromJSON( json ); + // restore framebuffer of current render target if necessary - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; + state.bindFramebuffer( 36160, framebuffer ); - return this; + } - } + } - } + }; - class QuadraticBezierCurve extends Curve { + this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { + const levelScale = Math.pow( 2, - level ); + const width = Math.floor( texture.image.width * levelScale ); + const height = Math.floor( texture.image.height * levelScale ); - super(); + textures.setTexture2D( texture, 0 ); - this.isQuadraticBezierCurve = true; + _gl.copyTexSubImage2D( 3553, level, 0, 0, position.x, position.y, width, height ); - this.type = 'QuadraticBezierCurve'; + state.unbindTexture(); - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + }; - } + this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { - getPoint( t, optionalTarget = new Vector2() ) { + const width = srcTexture.image.width; + const height = srcTexture.image.height; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); - const point = optionalTarget; + textures.setTexture2D( dstTexture, 0 ); - const v0 = this.v0, v1 = this.v1, v2 = this.v2; + // As another texture upload may have changed pixelStorei + // parameters, make sure they are correct for the dstTexture + _gl.pixelStorei( 37440, dstTexture.flipY ); + _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); + if ( srcTexture.isDataTexture ) { - return point; + _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - } + } else { - copy( source ) { + if ( srcTexture.isCompressedTexture ) { - super.copy( source ); + _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + } else { - return this; + _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image ); - } + } - toJSON() { + } - const data = super.toJSON(); + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 ); - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + state.unbindTexture(); - return data; + }; - } + this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { - fromJSON( json ) { + if ( _this.isWebGL1Renderer ) { - super.fromJSON( json ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); + return; - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + } - return this; + const width = sourceBox.max.x - sourceBox.min.x + 1; + const height = sourceBox.max.y - sourceBox.min.y + 1; + const depth = sourceBox.max.z - sourceBox.min.z + 1; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); + let glTarget; - } + if ( dstTexture.isData3DTexture ) { - } + textures.setTexture3D( dstTexture, 0 ); + glTarget = 32879; - class QuadraticBezierCurve3 extends Curve { + } else if ( dstTexture.isDataArrayTexture ) { - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { + textures.setTexture2DArray( dstTexture, 0 ); + glTarget = 35866; - super(); + } else { - this.isQuadraticBezierCurve3 = true; + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); + return; - this.type = 'QuadraticBezierCurve3'; + } - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; + _gl.pixelStorei( 37440, dstTexture.flipY ); + _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); - } + const unpackRowLen = _gl.getParameter( 3314 ); + const unpackImageHeight = _gl.getParameter( 32878 ); + const unpackSkipPixels = _gl.getParameter( 3316 ); + const unpackSkipRows = _gl.getParameter( 3315 ); + const unpackSkipImages = _gl.getParameter( 32877 ); - getPoint( t, optionalTarget = new Vector3() ) { + const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image; - const point = optionalTarget; + _gl.pixelStorei( 3314, image.width ); + _gl.pixelStorei( 32878, image.height ); + _gl.pixelStorei( 3316, sourceBox.min.x ); + _gl.pixelStorei( 3315, sourceBox.min.y ); + _gl.pixelStorei( 32877, sourceBox.min.z ); - const v0 = this.v0, v1 = this.v1, v2 = this.v2; + if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ), - QuadraticBezier( t, v0.z, v1.z, v2.z ) - ); + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); - return point; + } else { - } + if ( srcTexture.isCompressedTexture ) { - copy( source ) { + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); + _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); - super.copy( source ); + } else { - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); - return this; + } - } + } - toJSON() { + _gl.pixelStorei( 3314, unpackRowLen ); + _gl.pixelStorei( 32878, unpackImageHeight ); + _gl.pixelStorei( 3316, unpackSkipPixels ); + _gl.pixelStorei( 3315, unpackSkipRows ); + _gl.pixelStorei( 32877, unpackSkipImages ); - const data = super.toJSON(); + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + state.unbindTexture(); - return data; + }; - } + this.initTexture = function ( texture ) { - fromJSON( json ) { + if ( texture.isCubeTexture ) { - super.fromJSON( json ); + textures.setTextureCube( texture, 0 ); - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + } else if ( texture.isData3DTexture ) { - return this; + textures.setTexture3D( texture, 0 ); - } + } else if ( texture.isDataArrayTexture ) { - } + textures.setTexture2DArray( texture, 0 ); - class SplineCurve extends Curve { + } else { - constructor( points = [] ) { + textures.setTexture2D( texture, 0 ); - super(); + } - this.isSplineCurve = true; + state.unbindTexture(); - this.type = 'SplineCurve'; + }; - this.points = points; + this.resetState = function () { - } + _currentActiveCubeFace = 0; + _currentActiveMipmapLevel = 0; + _currentRenderTarget = null; - getPoint( t, optionalTarget = new Vector2() ) { + state.reset(); + bindingStates.reset(); - const point = optionalTarget; + }; - const points = this.points; - const p = ( points.length - 1 ) * t; + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - const intPoint = Math.floor( p ); - const weight = p - intPoint; + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); - const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - const p1 = points[ intPoint ]; - const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; + } - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); + } - return point; + class WebGL1Renderer extends WebGLRenderer {} - } + WebGL1Renderer.prototype.isWebGL1Renderer = true; - copy( source ) { + class FogExp2 { - super.copy( source ); + constructor( color, density = 0.00025 ) { - this.points = []; + this.isFogExp2 = true; - for ( let i = 0, l = source.points.length; i < l; i ++ ) { + this.name = ''; - const point = source.points[ i ]; + this.color = new Color( color ); + this.density = density; - this.points.push( point.clone() ); + } - } + clone() { - return this; + return new FogExp2( this.color, this.density ); } - toJSON() { + toJSON( /* meta */ ) { - const data = super.toJSON(); + return { + type: 'FogExp2', + color: this.color.getHex(), + density: this.density + }; - data.points = []; + } - for ( let i = 0, l = this.points.length; i < l; i ++ ) { + } - const point = this.points[ i ]; - data.points.push( point.toArray() ); + class Fog { - } + constructor( color, near = 1, far = 1000 ) { - return data; + this.isFog = true; - } + this.name = ''; - fromJSON( json ) { + this.color = new Color( color ); - super.fromJSON( json ); + this.near = near; + this.far = far; - this.points = []; + } - for ( let i = 0, l = json.points.length; i < l; i ++ ) { + clone() { - const point = json.points[ i ]; - this.points.push( new Vector2().fromArray( point ) ); + return new Fog( this.color, this.near, this.far ); - } + } - return this; + toJSON( /* meta */ ) { + + return { + type: 'Fog', + color: this.color.getHex(), + near: this.near, + far: this.far + }; } } - var Curves = /*#__PURE__*/Object.freeze({ - __proto__: null, - ArcCurve: ArcCurve, - CatmullRomCurve3: CatmullRomCurve3, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - EllipseCurve: EllipseCurve, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - SplineCurve: SplineCurve - }); - - /************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ - - class CurvePath extends Curve { + class Scene extends Object3D { constructor() { super(); - this.type = 'CurvePath'; + this.isScene = true; - this.curves = []; - this.autoClose = false; // Automatically closes the path + this.type = 'Scene'; - } + this.background = null; + this.environment = null; + this.fog = null; - add( curve ) { + this.overrideMaterial = null; - this.curves.push( curve ); + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); + + } } - closePath() { + copy( source, recursive ) { - // Add a line curve if start and end of lines are not connected - const startPoint = this.curves[ 0 ].getPoint( 0 ); - const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); + super.copy( source, recursive ); - if ( ! startPoint.equals( endPoint ) ) { + if ( source.background !== null ) this.background = source.background.clone(); + if ( source.environment !== null ) this.environment = source.environment.clone(); + if ( source.fog !== null ) this.fog = source.fog.clone(); - this.curves.push( new LineCurve( endPoint, startPoint ) ); + if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); - } + this.matrixAutoUpdate = source.matrixAutoUpdate; + + return this; } - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: + toJSON( meta ) { - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') + const data = super.toJSON( meta ); - getPoint( t, optionalTarget ) { + if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - const d = t * this.getLength(); - const curveLengths = this.getCurveLengths(); - let i = 0; + return data; - // To think about boundaries points. + } - while ( i < curveLengths.length ) { + // @deprecated - if ( curveLengths[ i ] >= d ) { + get autoUpdate() { - const diff = curveLengths[ i ] - d; - const curve = this.curves[ i ]; + console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); + return this.matrixWorldAutoUpdate; - const segmentLength = curve.getLength(); - const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + } - return curve.getPointAt( u, optionalTarget ); + set autoUpdate( value ) { - } + console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); + this.matrixWorldAutoUpdate = value; - i ++; + } - } + } - return null; + class InterleavedBuffer { - // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { + if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - points.push( points[ 0 ] ); + data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); } - return points; + // - } + return { + uuid: this.uuid, + buffer: this.array.buffer._uuid, + type: this.array.constructor.name, + stride: this.stride + }; - copy( source ) { + } - super.copy( source ); + } - this.curves = []; + const _vector$6 = /*@__PURE__*/ new Vector3(); - for ( let i = 0, l = source.curves.length; i < l; i ++ ) { + class InterleavedBufferAttribute { - const curve = source.curves[ i ]; + constructor( interleavedBuffer, itemSize, offset, normalized = false ) { - this.curves.push( curve.clone() ); + this.isInterleavedBufferAttribute = true; - } + this.name = ''; - this.autoClose = source.autoClose; + this.data = interleavedBuffer; + this.itemSize = itemSize; + this.offset = offset; - return this; + this.normalized = normalized === true; } - toJSON() { + get count() { - const data = super.toJSON(); + return this.data.count; - data.autoClose = this.autoClose; - data.curves = []; + } - for ( let i = 0, l = this.curves.length; i < l; i ++ ) { + get array() { - const curve = this.curves[ i ]; - data.curves.push( curve.toJSON() ); + return this.data.array; - } + } - return data; + set needsUpdate( value ) { + + this.data.needsUpdate = value; } - fromJSON( json ) { + applyMatrix4( m ) { - super.fromJSON( json ); + for ( let i = 0, l = this.data.count; i < l; i ++ ) { - this.autoClose = json.autoClose; - this.curves = []; + _vector$6.fromBufferAttribute( this, i ); - for ( let i = 0, l = json.curves.length; i < l; i ++ ) { + _vector$6.applyMatrix4( m ); - const curve = json.curves[ i ]; - this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); + this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); } @@ -42487,33 +74051,31 @@ var app = (function () { } - } - - class Path extends CurvePath { - - constructor( points ) { - - super(); + applyNormalMatrix( m ) { - this.type = 'Path'; + for ( let i = 0, l = this.count; i < l; i ++ ) { - this.currentPoint = new Vector2(); + _vector$6.fromBufferAttribute( this, i ); - if ( points ) { + _vector$6.applyNormalMatrix( m ); - this.setFromPoints( points ); + this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); } + return this; + } - setFromPoints( points ) { + transformDirection( m ) { - this.moveTo( points[ 0 ].x, points[ 0 ].y ); + for ( let i = 0, l = this.count; i < l; i ++ ) { - for ( let i = 1, l = points.length; i < l; i ++ ) { + _vector$6.fromBufferAttribute( this, i ); - this.lineTo( points[ i ].x, points[ i ].y ); + _vector$6.transformDirection( m ); + + this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); } @@ -42521,1279 +74083,1114 @@ var app = (function () { } - moveTo( x, y ) { + setX( index, x ) { - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? + if ( this.normalized ) x = normalize( x, this.array ); + + this.data.array[ index * this.data.stride + this.offset ] = x; return this; } - lineTo( x, y ) { + setY( index, y ) { - const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); + if ( this.normalized ) y = normalize( y, this.array ); - this.currentPoint.set( x, y ); + this.data.array[ index * this.data.stride + this.offset + 1 ] = y; return this; } - quadraticCurveTo( aCPx, aCPy, aX, aY ) { - - const curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); + setZ( index, z ) { - this.curves.push( curve ); + if ( this.normalized ) z = normalize( z, this.array ); - this.currentPoint.set( aX, aY ); + this.data.array[ index * this.data.stride + this.offset + 2 ] = z; return this; } - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - const curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); + setW( index, w ) { - this.curves.push( curve ); + if ( this.normalized ) w = normalize( w, this.array ); - this.currentPoint.set( aX, aY ); + this.data.array[ index * this.data.stride + this.offset + 3 ] = w; return this; } - splineThru( pts /*Array of Vector*/ ) { - - const npts = [ this.currentPoint.clone() ].concat( pts ); + getX( index ) { - const curve = new SplineCurve( npts ); - this.curves.push( curve ); + let x = this.data.array[ index * this.data.stride + this.offset ]; - this.currentPoint.copy( pts[ pts.length - 1 ] ); + if ( this.normalized ) x = denormalize( x, this.array ); - return this; + return x; } - arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + getY( index ) { - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; + let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); + if ( this.normalized ) y = denormalize( y, this.array ); - return this; + return y; } - absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + getZ( index ) { - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; - return this; + if ( this.normalized ) z = denormalize( z, this.array ); + + return z; } - ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + getW( index ) { - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; + let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + if ( this.normalized ) w = denormalize( w, this.array ); - return this; + return w; } - absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - if ( this.curves.length > 0 ) { - - // if a previous curve is present, attempt to join - const firstPoint = curve.getPoint( 0 ); + setXY( index, x, y ) { - if ( ! firstPoint.equals( this.currentPoint ) ) { + index = index * this.data.stride + this.offset; - this.lineTo( firstPoint.x, firstPoint.y ); + if ( this.normalized ) { - } + x = normalize( x, this.array ); + y = normalize( y, this.array ); } - this.curves.push( curve ); - - const lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; return this; } - copy( source ) { + setXYZ( index, x, y, z ) { - super.copy( source ); + index = index * this.data.stride + this.offset; - this.currentPoint.copy( source.currentPoint ); + if ( this.normalized ) { - return this; + x = normalize( x, this.array ); + y = normalize( y, this.array ); + z = normalize( z, this.array ); - } + } - toJSON() { + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; - const data = super.toJSON(); + return this; - data.currentPoint = this.currentPoint.toArray(); + } - return data; + setXYZW( index, x, y, z, w ) { - } + index = index * this.data.stride + this.offset; - fromJSON( json ) { + if ( this.normalized ) { - super.fromJSON( json ); + x = normalize( x, this.array ); + y = normalize( y, this.array ); + z = normalize( z, this.array ); + w = normalize( w, this.array ); - this.currentPoint.fromArray( json.currentPoint ); + } + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + this.data.array[ index + 3 ] = w; return this; } - } + clone( data ) { - class LatheGeometry extends BufferGeometry { + if ( data === undefined ) { - constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { + console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will deinterleave buffer data.' ); - super(); + const array = []; - this.type = 'LatheGeometry'; + for ( let i = 0; i < this.count; i ++ ) { - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; + const index = i * this.data.stride + this.offset; - segments = Math.floor( segments ); + for ( let j = 0; j < this.itemSize; j ++ ) { - // clamp phiLength so it's in range of [ 0, 2PI ] + array.push( this.data.array[ index + j ] ); - phiLength = clamp( phiLength, 0, Math.PI * 2 ); + } - // buffers + } - const indices = []; - const vertices = []; - const uvs = []; - const initNormals = []; - const normals = []; + return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); - // helper variables + } else { - const inverseSegments = 1.0 / segments; - const vertex = new Vector3(); - const uv = new Vector2(); - const normal = new Vector3(); - const curNormal = new Vector3(); - const prevNormal = new Vector3(); - let dx = 0; - let dy = 0; + if ( data.interleavedBuffers === undefined ) { - // pre-compute normals for initial "meridian" + data.interleavedBuffers = {}; - for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { + } - switch ( j ) { + if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - case 0: // special handling for 1st vertex on path + data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); - dx = points[ j + 1 ].x - points[ j ].x; - dy = points[ j + 1 ].y - points[ j ].y; + } - normal.x = dy * 1.0; - normal.y = - dx; - normal.z = dy * 0.0; + return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); - prevNormal.copy( normal ); + } - normal.normalize(); + } - initNormals.push( normal.x, normal.y, normal.z ); + toJSON( data ) { - break; + if ( data === undefined ) { - case ( points.length - 1 ): // special handling for last Vertex on path + console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will deinterleave buffer data.' ); - initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z ); + const array = []; - break; + for ( let i = 0; i < this.count; i ++ ) { - default: // default handling for all vertices in between + const index = i * this.data.stride + this.offset; - dx = points[ j + 1 ].x - points[ j ].x; - dy = points[ j + 1 ].y - points[ j ].y; + for ( let j = 0; j < this.itemSize; j ++ ) { - normal.x = dy * 1.0; - normal.y = - dx; - normal.z = dy * 0.0; + array.push( this.data.array[ index + j ] ); - curNormal.copy( normal ); + } - normal.x += prevNormal.x; - normal.y += prevNormal.y; - normal.z += prevNormal.z; + } - normal.normalize(); + // deinterleave data and save it as an ordinary buffer attribute for now - initNormals.push( normal.x, normal.y, normal.z ); + return { + itemSize: this.itemSize, + type: this.array.constructor.name, + array: array, + normalized: this.normalized + }; - prevNormal.copy( curNormal ); + } else { - } + // save as true interleaved attribtue - } + if ( data.interleavedBuffers === undefined ) { - // generate vertices, uvs and normals + data.interleavedBuffers = {}; - for ( let i = 0; i <= segments; i ++ ) { + } - const phi = phiStart + i * inverseSegments * phiLength; + if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - const sin = Math.sin( phi ); - const cos = Math.cos( phi ); + data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); - for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { + } - // vertex + return { + isInterleavedBufferAttribute: true, + itemSize: this.itemSize, + data: this.data.uuid, + offset: this.offset, + normalized: this.normalized + }; - vertex.x = points[ j ].x * sin; - vertex.y = points[ j ].y; - vertex.z = points[ j ].x * cos; + } - vertices.push( vertex.x, vertex.y, vertex.z ); + } - // uv + } - uv.x = i / segments; - uv.y = j / ( points.length - 1 ); + class SpriteMaterial extends Material { - uvs.push( uv.x, uv.y ); + constructor( parameters ) { - // normal + super(); - const x = initNormals[ 3 * j + 0 ] * sin; - const y = initNormals[ 3 * j + 1 ]; - const z = initNormals[ 3 * j + 0 ] * cos; + this.isSpriteMaterial = true; - normals.push( x, y, z ); + this.type = 'SpriteMaterial'; - } + this.color = new Color( 0xffffff ); - } + this.map = null; - // indices + this.alphaMap = null; - for ( let i = 0; i < segments; i ++ ) { + this.rotation = 0; - for ( let j = 0; j < ( points.length - 1 ); j ++ ) { + this.sizeAttenuation = true; - const base = j + i * points.length; + this.transparent = true; - const a = base; - const b = base + points.length; - const c = base + points.length + 1; - const d = base + 1; + this.fog = true; - // faces + this.setValues( parameters ); - indices.push( a, b, d ); - indices.push( c, d, b ); + } - } + copy( source ) { - } + super.copy( source ); - // build geometry + this.color.copy( source.color ); - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.map = source.map; - } + this.alphaMap = source.alphaMap; - static fromJSON( data ) { + this.rotation = source.rotation; - return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); + this.sizeAttenuation = source.sizeAttenuation; + + this.fog = source.fog; + + return this; } } - class CapsuleGeometry extends LatheGeometry { - - constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) { + let _geometry; - const path = new Path(); - path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 ); - path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 ); + const _intersectPoint = /*@__PURE__*/ new Vector3(); + const _worldScale = /*@__PURE__*/ new Vector3(); + const _mvPosition = /*@__PURE__*/ new Vector3(); - super( path.getPoints( capSegments ), radialSegments ); + const _alignedPosition = /*@__PURE__*/ new Vector2(); + const _rotatedPosition = /*@__PURE__*/ new Vector2(); + const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); - this.type = 'CapsuleGeometry'; - - this.parameters = { - radius: radius, - height: length, - capSegments: capSegments, - radialSegments: radialSegments, - }; - - } - - static fromJSON( data ) { - - return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments ); - - } + const _vA = /*@__PURE__*/ new Vector3(); + const _vB = /*@__PURE__*/ new Vector3(); + const _vC = /*@__PURE__*/ new Vector3(); - } + const _uvA = /*@__PURE__*/ new Vector2(); + const _uvB = /*@__PURE__*/ new Vector2(); + const _uvC = /*@__PURE__*/ new Vector2(); - class CircleGeometry extends BufferGeometry { + class Sprite extends Object3D { - constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) { + constructor( material ) { super(); - this.type = 'CircleGeometry'; + this.isSprite = true; - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + this.type = 'Sprite'; - segments = Math.max( 3, segments ); + if ( _geometry === undefined ) { - // buffers + _geometry = new BufferGeometry(); - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + const float32Array = new Float32Array( [ + - 0.5, - 0.5, 0, 0, 0, + 0.5, - 0.5, 0, 1, 0, + 0.5, 0.5, 0, 1, 1, + - 0.5, 0.5, 0, 0, 1 + ] ); - // helper variables + const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); - const vertex = new Vector3(); - const uv = new Vector2(); + _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); + _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); + _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); - // center point + } - vertices.push( 0, 0, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( 0.5, 0.5 ); + this.geometry = _geometry; + this.material = ( material !== undefined ) ? material : new SpriteMaterial(); - for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { + this.center = new Vector2( 0.5, 0.5 ); - const segment = thetaStart + s / segments * thetaLength; + } - // vertex + raycast( raycaster, intersects ) { - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + if ( raycaster.camera === null ) { - vertices.push( vertex.x, vertex.y, vertex.z ); + console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); - // normal + } - normals.push( 0, 0, 1 ); + _worldScale.setFromMatrixScale( this.matrixWorld ); - // uvs + _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); + this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); - uv.x = ( vertices[ i ] / radius + 1 ) / 2; - uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; + _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); - uvs.push( uv.x, uv.y ); + if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { + + _worldScale.multiplyScalar( - _mvPosition.z ); } - // indices + const rotation = this.material.rotation; + let sin, cos; - for ( let i = 1; i <= segments; i ++ ) { + if ( rotation !== 0 ) { - indices.push( i, i + 1, 0 ); + cos = Math.cos( rotation ); + sin = Math.sin( rotation ); } - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + const center = this.center; - } + transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - static fromJSON( data ) { + _uvA.set( 0, 0 ); + _uvB.set( 1, 0 ); + _uvC.set( 1, 1 ); - return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); + // check first triangle + let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint ); - } + if ( intersect === null ) { - } + // check second triangle + transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + _uvB.set( 0, 1 ); - class CylinderGeometry extends BufferGeometry { + intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint ); + if ( intersect === null ) { - constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { + return; - super(); + } - this.type = 'CylinderGeometry'; + } - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); - const scope = this; + if ( distance < raycaster.near || distance > raycaster.far ) return; - radialSegments = Math.floor( radialSegments ); - heightSegments = Math.floor( heightSegments ); + intersects.push( { - // buffers + distance: distance, + point: _intersectPoint.clone(), + uv: Triangle.getUV( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ), + face: null, + object: this - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + } ); - // helper variables + } - let index = 0; - const indexArray = []; - const halfHeight = height / 2; - let groupStart = 0; + copy( source, recursive ) { - // generate geometry + super.copy( source, recursive ); - generateTorso(); + if ( source.center !== undefined ) this.center.copy( source.center ); - if ( openEnded === false ) { + this.material = source.material; - if ( radiusTop > 0 ) generateCap( true ); - if ( radiusBottom > 0 ) generateCap( false ); + return this; - } + } - // build geometry + } - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { - function generateTorso() { + // compute position in camera space + _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); - const normal = new Vector3(); - const vertex = new Vector3(); + // to check if rotation is not zero + if ( sin !== undefined ) { - let groupCount = 0; + _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); + _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); - // this will be used to calculate the normal - const slope = ( radiusBottom - radiusTop ) / height; + } else { - // generate vertices, normals and uvs + _rotatedPosition.copy( _alignedPosition ); - for ( let y = 0; y <= heightSegments; y ++ ) { + } - const indexRow = []; - const v = y / heightSegments; + vertexPosition.copy( mvPosition ); + vertexPosition.x += _rotatedPosition.x; + vertexPosition.y += _rotatedPosition.y; - // calculate the radius of the current row + // transform to world space + vertexPosition.applyMatrix4( _viewWorldMatrix ); - const radius = v * ( radiusBottom - radiusTop ) + radiusTop; + } - for ( let x = 0; x <= radialSegments; x ++ ) { + const _v1$2 = /*@__PURE__*/ new Vector3(); + const _v2$1 = /*@__PURE__*/ new Vector3(); - const u = x / radialSegments; + class LOD extends Object3D { - const theta = u * thetaLength + thetaStart; + constructor() { - const sinTheta = Math.sin( theta ); - const cosTheta = Math.cos( theta ); + super(); - // vertex + this._currentLevel = 0; - vertex.x = radius * sinTheta; - vertex.y = - v * height + halfHeight; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); + this.type = 'LOD'; - // normal + Object.defineProperties( this, { + levels: { + enumerable: true, + value: [] + }, + isLOD: { + value: true, + } + } ); - normal.set( sinTheta, slope, cosTheta ).normalize(); - normals.push( normal.x, normal.y, normal.z ); + this.autoUpdate = true; - // uv + } - uvs.push( u, 1 - v ); + copy( source ) { - // save index of vertex in respective row + super.copy( source, false ); - indexRow.push( index ++ ); + const levels = source.levels; - } + for ( let i = 0, l = levels.length; i < l; i ++ ) { - // now save vertices of the row in our index array + const level = levels[ i ]; - indexArray.push( indexRow ); + this.addLevel( level.object.clone(), level.distance ); - } + } - // generate indices + this.autoUpdate = source.autoUpdate; - for ( let x = 0; x < radialSegments; x ++ ) { + return this; - for ( let y = 0; y < heightSegments; y ++ ) { + } - // we use the index array to access the correct indices + addLevel( object, distance = 0 ) { - const a = indexArray[ y ][ x ]; - const b = indexArray[ y + 1 ][ x ]; - const c = indexArray[ y + 1 ][ x + 1 ]; - const d = indexArray[ y ][ x + 1 ]; + distance = Math.abs( distance ); - // faces + const levels = this.levels; - indices.push( a, b, d ); - indices.push( b, c, d ); + let l; - // update group counter + for ( l = 0; l < levels.length; l ++ ) { - groupCount += 6; + if ( distance < levels[ l ].distance ) { - } + break; } - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, 0 ); - - // calculate new start value for groups - - groupStart += groupCount; - } - function generateCap( top ) { + levels.splice( l, 0, { distance: distance, object: object } ); - // save the index of the first center vertex - const centerIndexStart = index; + this.add( object ); - const uv = new Vector2(); - const vertex = new Vector3(); + return this; - let groupCount = 0; + } - const radius = ( top === true ) ? radiusTop : radiusBottom; - const sign = ( top === true ) ? 1 : - 1; + getCurrentLevel() { - // first we generate the center vertex data of the cap. - // because the geometry needs one set of uvs per face, - // we must generate a center vertex per face/segment + return this._currentLevel; - for ( let x = 1; x <= radialSegments; x ++ ) { + } - // vertex + getObjectForDistance( distance ) { - vertices.push( 0, halfHeight * sign, 0 ); + const levels = this.levels; - // normal + if ( levels.length > 0 ) { - normals.push( 0, sign, 0 ); + let i, l; - // uv + for ( i = 1, l = levels.length; i < l; i ++ ) { - uvs.push( 0.5, 0.5 ); + if ( distance < levels[ i ].distance ) { - // increase index + break; - index ++; + } } - // save the index of the last center vertex - const centerIndexEnd = index; + return levels[ i - 1 ].object; - // now we generate the surrounding vertices, normals and uvs + } - for ( let x = 0; x <= radialSegments; x ++ ) { + return null; - const u = x / radialSegments; - const theta = u * thetaLength + thetaStart; + } - const cosTheta = Math.cos( theta ); - const sinTheta = Math.sin( theta ); + raycast( raycaster, intersects ) { - // vertex + const levels = this.levels; - vertex.x = radius * sinTheta; - vertex.y = halfHeight * sign; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); + if ( levels.length > 0 ) { - // normal + _v1$2.setFromMatrixPosition( this.matrixWorld ); - normals.push( 0, sign, 0 ); + const distance = raycaster.ray.origin.distanceTo( _v1$2 ); - // uv + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - uv.x = ( cosTheta * 0.5 ) + 0.5; - uv.y = ( sinTheta * 0.5 * sign ) + 0.5; - uvs.push( uv.x, uv.y ); + } - // increase index + } - index ++; + update( camera ) { - } + const levels = this.levels; - // generate indices + if ( levels.length > 1 ) { - for ( let x = 0; x < radialSegments; x ++ ) { + _v1$2.setFromMatrixPosition( camera.matrixWorld ); + _v2$1.setFromMatrixPosition( this.matrixWorld ); - const c = centerIndexStart + x; - const i = centerIndexEnd + x; + const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; - if ( top === true ) { + levels[ 0 ].object.visible = true; - // face top + let i, l; - indices.push( i, i + 1, c ); + for ( i = 1, l = levels.length; i < l; i ++ ) { - } else { + if ( distance >= levels[ i ].distance ) { - // face bottom + levels[ i - 1 ].object.visible = false; + levels[ i ].object.visible = true; - indices.push( i + 1, i, c ); + } else { - } + break; - groupCount += 3; + } } - // add a group to the geometry. this will ensure multi material support + this._currentLevel = i - 1; - scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); + for ( ; i < l; i ++ ) { - // calculate new start value for groups + levels[ i ].object.visible = false; - groupStart += groupCount; + } } } - static fromJSON( data ) { + toJSON( meta ) { - return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); + const data = super.toJSON( meta ); - } + if ( this.autoUpdate === false ) data.object.autoUpdate = false; - } + data.object.levels = []; - class ConeGeometry extends CylinderGeometry { + const levels = this.levels; - constructor( radius = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { + for ( let i = 0, l = levels.length; i < l; i ++ ) { - super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + const level = levels[ i ]; - this.type = 'ConeGeometry'; + data.object.levels.push( { + object: level.object.uuid, + distance: level.distance + } ); - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + } + + return data; } - static fromJSON( data ) { + } - return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); + const _basePosition = /*@__PURE__*/ new Vector3(); - } + const _skinIndex = /*@__PURE__*/ new Vector4(); + const _skinWeight = /*@__PURE__*/ new Vector4(); - } + const _vector$5 = /*@__PURE__*/ new Vector3(); + const _matrix = /*@__PURE__*/ new Matrix4(); - class PolyhedronGeometry extends BufferGeometry { + class SkinnedMesh extends Mesh { - constructor( vertices = [], indices = [], radius = 1, detail = 0 ) { + constructor( geometry, material ) { - super(); + super( geometry, material ); - this.type = 'PolyhedronGeometry'; + this.isSkinnedMesh = true; - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; + this.type = 'SkinnedMesh'; - // default buffer data + this.bindMode = 'attached'; + this.bindMatrix = new Matrix4(); + this.bindMatrixInverse = new Matrix4(); - const vertexBuffer = []; - const uvBuffer = []; + } - // the subdivision creates the vertex buffer data + copy( source, recursive ) { - subdivide( detail ); + super.copy( source, recursive ); - // all vertices should lie on a conceptual sphere with a given radius + this.bindMode = source.bindMode; + this.bindMatrix.copy( source.bindMatrix ); + this.bindMatrixInverse.copy( source.bindMatrixInverse ); - applyRadius( radius ); + this.skeleton = source.skeleton; - // finally, create the uv data + return this; - generateUVs(); + } - // build non-indexed geometry + bind( skeleton, bindMatrix ) { - this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); + this.skeleton = skeleton; - if ( detail === 0 ) { + if ( bindMatrix === undefined ) { - this.computeVertexNormals(); // flat normals + this.updateMatrixWorld( true ); - } else { + this.skeleton.calculateInverses(); - this.normalizeNormals(); // smooth normals + bindMatrix = this.matrixWorld; } - // helper functions + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.copy( bindMatrix ).invert(); - function subdivide( detail ) { + } - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); + pose() { - // iterate over all faces and apply a subdivison with the given detail value + this.skeleton.pose(); - for ( let i = 0; i < indices.length; i += 3 ) { + } - // get the vertices of the face + normalizeSkinWeights() { - getVertexByIndex( indices[ i + 0 ], a ); - getVertexByIndex( indices[ i + 1 ], b ); - getVertexByIndex( indices[ i + 2 ], c ); + const vector = new Vector4(); - // perform subdivision + const skinWeight = this.geometry.attributes.skinWeight; - subdivideFace( a, b, c, detail ); + for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { - } + vector.fromBufferAttribute( skinWeight, i ); - } + const scale = 1.0 / vector.manhattanLength(); - function subdivideFace( a, b, c, detail ) { + if ( scale !== Infinity ) { - const cols = detail + 1; + vector.multiplyScalar( scale ); - // we use this multidimensional array as a data structure for creating the subdivision - - const v = []; - - // construct all of the vertices for this subdivision - - for ( let i = 0; i <= cols; i ++ ) { - - v[ i ] = []; + } else { - const aj = a.clone().lerp( c, i / cols ); - const bj = b.clone().lerp( c, i / cols ); + vector.set( 1, 0, 0, 0 ); // do something reasonable - const rows = cols - i; + } - for ( let j = 0; j <= rows; j ++ ) { + skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); - if ( j === 0 && i === cols ) { + } - v[ i ][ j ] = aj; + } - } else { + updateMatrixWorld( force ) { - v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); + super.updateMatrixWorld( force ); - } + if ( this.bindMode === 'attached' ) { - } + this.bindMatrixInverse.copy( this.matrixWorld ).invert(); - } + } else if ( this.bindMode === 'detached' ) { - // construct all of the faces + this.bindMatrixInverse.copy( this.bindMatrix ).invert(); - for ( let i = 0; i < cols; i ++ ) { + } else { - for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { + console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); - const k = Math.floor( j / 2 ); + } - if ( j % 2 === 0 ) { + } - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - pushVertex( v[ i ][ k ] ); + boneTransform( index, target ) { - } else { + const skeleton = this.skeleton; + const geometry = this.geometry; - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); + _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); + _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); - } + _basePosition.copy( target ).applyMatrix4( this.bindMatrix ); - } + target.set( 0, 0, 0 ); - } + for ( let i = 0; i < 4; i ++ ) { - } + const weight = _skinWeight.getComponent( i ); - function applyRadius( radius ) { + if ( weight !== 0 ) { - const vertex = new Vector3(); + const boneIndex = _skinIndex.getComponent( i ); - // iterate over the entire buffer and apply the radius to each vertex + _matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { + target.addScaledVector( _vector$5.copy( _basePosition ).applyMatrix4( _matrix ), weight ); - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; + } - vertex.normalize().multiplyScalar( radius ); + } - vertexBuffer[ i + 0 ] = vertex.x; - vertexBuffer[ i + 1 ] = vertex.y; - vertexBuffer[ i + 2 ] = vertex.z; + return target.applyMatrix4( this.bindMatrixInverse ); - } + } - } + } - function generateUVs() { + class Bone extends Object3D { - const vertex = new Vector3(); + constructor() { - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { + super(); - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; + this.isBone = true; - const u = azimuth( vertex ) / 2 / Math.PI + 0.5; - const v = inclination( vertex ) / Math.PI + 0.5; - uvBuffer.push( u, 1 - v ); + this.type = 'Bone'; - } + } - correctUVs(); + } - correctSeam(); + class DataTexture extends Texture { - } + constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, encoding ) { - function correctSeam() { + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - // handle case when face straddles the seam, see #3269 + this.isDataTexture = true; - for ( let i = 0; i < uvBuffer.length; i += 6 ) { + this.image = { data: data, width: width, height: height }; - // uv data of a single face + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; - const x0 = uvBuffer[ i + 0 ]; - const x1 = uvBuffer[ i + 2 ]; - const x2 = uvBuffer[ i + 4 ]; + } - const max = Math.max( x0, x1, x2 ); - const min = Math.min( x0, x1, x2 ); + } - // 0.9 is somewhat arbitrary + const _offsetMatrix = /*@__PURE__*/ new Matrix4(); + const _identityMatrix = /*@__PURE__*/ new Matrix4(); - if ( max > 0.9 && min < 0.1 ) { + class Skeleton { - if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; - if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; - if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; + constructor( bones = [], boneInverses = [] ) { - } + this.uuid = generateUUID(); - } + this.bones = bones.slice( 0 ); + this.boneInverses = boneInverses; + this.boneMatrices = null; - } + this.boneTexture = null; + this.boneTextureSize = 0; - function pushVertex( vertex ) { + this.frame = - 1; - vertexBuffer.push( vertex.x, vertex.y, vertex.z ); + this.init(); - } + } - function getVertexByIndex( index, vertex ) { + init() { - const stride = index * 3; + const bones = this.bones; + const boneInverses = this.boneInverses; - vertex.x = vertices[ stride + 0 ]; - vertex.y = vertices[ stride + 1 ]; - vertex.z = vertices[ stride + 2 ]; + this.boneMatrices = new Float32Array( bones.length * 16 ); - } + // calculate inverse bone matrices if necessary - function correctUVs() { + if ( boneInverses.length === 0 ) { - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); + this.calculateInverses(); - const centroid = new Vector3(); + } else { - const uvA = new Vector2(); - const uvB = new Vector2(); - const uvC = new Vector2(); + // handle special case - for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { + if ( bones.length !== boneInverses.length ) { - a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); - b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); - c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); + console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); - uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); - uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); - uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); + this.boneInverses = []; - centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - const azi = azimuth( centroid ); + this.boneInverses.push( new Matrix4() ); - correctUV( uvA, j + 0, a, azi ); - correctUV( uvB, j + 2, b, azi ); - correctUV( uvC, j + 4, c, azi ); + } } } - function correctUV( uv, stride, vector, azimuth ) { - - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - - uvBuffer[ stride ] = uv.x - 1; + } - } + calculateInverses() { - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { + this.boneInverses.length = 0; - uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - } + const inverse = new Matrix4(); - } + if ( this.bones[ i ] ) { - // Angle around the Y axis, counter-clockwise when looking from above. + inverse.copy( this.bones[ i ].matrixWorld ).invert(); - function azimuth( vector ) { + } - return Math.atan2( vector.z, - vector.x ); + this.boneInverses.push( inverse ); } + } - // Angle above the XZ plane. - - function inclination( vector ) { + pose() { - return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + // recover the bind-time world matrices - } + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - } + const bone = this.bones[ i ]; - static fromJSON( data ) { + if ( bone ) { - return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details ); + bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); - } + } - } + } - class DodecahedronGeometry extends PolyhedronGeometry { + // compute the local matrices, positions, rotations and scales - constructor( radius = 1, detail = 0 ) { + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - const t = ( 1 + Math.sqrt( 5 ) ) / 2; - const r = 1 / t; + const bone = this.bones[ i ]; - const vertices = [ + if ( bone ) { - // (±1, ±1, ±1) - - 1, - 1, - 1, - 1, - 1, 1, - - 1, 1, - 1, - 1, 1, 1, - 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, 1, 1, 1, + if ( bone.parent && bone.parent.isBone ) { - // (0, ±1/φ, ±φ) - 0, - r, - t, 0, - r, t, - 0, r, - t, 0, r, t, + bone.matrix.copy( bone.parent.matrixWorld ).invert(); + bone.matrix.multiply( bone.matrixWorld ); - // (±1/φ, ±φ, 0) - - r, - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, + } else { - // (±φ, 0, ±1/φ) - - t, 0, - r, t, 0, - r, - - t, 0, r, t, 0, r - ]; + bone.matrix.copy( bone.matrixWorld ); - const indices = [ - 3, 11, 7, 3, 7, 15, 3, 15, 13, - 7, 19, 17, 7, 17, 6, 7, 6, 15, - 17, 4, 8, 17, 8, 10, 17, 10, 6, - 8, 0, 16, 8, 16, 2, 8, 2, 10, - 0, 12, 1, 0, 1, 18, 0, 18, 16, - 6, 10, 2, 6, 2, 13, 6, 13, 15, - 2, 16, 18, 2, 18, 3, 2, 3, 13, - 18, 1, 9, 18, 9, 11, 18, 11, 3, - 4, 14, 12, 4, 12, 0, 4, 0, 8, - 11, 9, 5, 11, 5, 19, 11, 19, 7, - 19, 5, 14, 19, 14, 4, 19, 4, 17, - 1, 12, 14, 1, 14, 5, 1, 5, 9 - ]; + } - super( vertices, indices, radius, detail ); + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - this.type = 'DodecahedronGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + } } - static fromJSON( data ) { - - return new DodecahedronGeometry( data.radius, data.detail ); + update() { - } + const bones = this.bones; + const boneInverses = this.boneInverses; + const boneMatrices = this.boneMatrices; + const boneTexture = this.boneTexture; - } + // flatten bone matrices to array - const _v0 = /*@__PURE__*/ new Vector3(); - const _v1$1 = /*@__PURE__*/ new Vector3(); - const _normal = /*@__PURE__*/ new Vector3(); - const _triangle = /*@__PURE__*/ new Triangle(); + for ( let i = 0, il = bones.length; i < il; i ++ ) { - class EdgesGeometry extends BufferGeometry { + // compute the offset between the current and the original transform - constructor( geometry = null, thresholdAngle = 1 ) { + const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix; - super(); + _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); + _offsetMatrix.toArray( boneMatrices, i * 16 ); - this.type = 'EdgesGeometry'; + } - this.parameters = { - geometry: geometry, - thresholdAngle: thresholdAngle - }; + if ( boneTexture !== null ) { - if ( geometry !== null ) { + boneTexture.needsUpdate = true; - const precisionPoints = 4; - const precision = Math.pow( 10, precisionPoints ); - const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); + } - const indexAttr = geometry.getIndex(); - const positionAttr = geometry.getAttribute( 'position' ); - const indexCount = indexAttr ? indexAttr.count : positionAttr.count; + } - const indexArr = [ 0, 0, 0 ]; - const vertKeys = [ 'a', 'b', 'c' ]; - const hashes = new Array( 3 ); + clone() { - const edgeData = {}; - const vertices = []; - for ( let i = 0; i < indexCount; i += 3 ) { + return new Skeleton( this.bones, this.boneInverses ); - if ( indexAttr ) { + } - indexArr[ 0 ] = indexAttr.getX( i ); - indexArr[ 1 ] = indexAttr.getX( i + 1 ); - indexArr[ 2 ] = indexAttr.getX( i + 2 ); + computeBoneTexture() { - } else { + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) + // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) + // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) + // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) - indexArr[ 0 ] = i; - indexArr[ 1 ] = i + 1; - indexArr[ 2 ] = i + 2; + let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix + size = ceilPowerOfTwo( size ); + size = Math.max( size, 4 ); - } + const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel + boneMatrices.set( this.boneMatrices ); // copy current values - const { a, b, c } = _triangle; - a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); - b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); - c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); - _triangle.getNormal( _normal ); + const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); + boneTexture.needsUpdate = true; - // create hashes for the edge from the vertices - hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; - hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; - hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; + this.boneMatrices = boneMatrices; + this.boneTexture = boneTexture; + this.boneTextureSize = size; - // skip degenerate triangles - if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { + return this; - continue; + } - } + getBoneByName( name ) { - // iterate over every edge - for ( let j = 0; j < 3; j ++ ) { + for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - // get the first and next vertex making up the edge - const jNext = ( j + 1 ) % 3; - const vecHash0 = hashes[ j ]; - const vecHash1 = hashes[ jNext ]; - const v0 = _triangle[ vertKeys[ j ] ]; - const v1 = _triangle[ vertKeys[ jNext ] ]; + const bone = this.bones[ i ]; - const hash = `${ vecHash0 }_${ vecHash1 }`; - const reverseHash = `${ vecHash1 }_${ vecHash0 }`; + if ( bone.name === name ) { - if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { + return bone; - // if we found a sibling edge add it into the vertex array if - // it meets the angle threshold and delete the edge from the map. - if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { + } - vertices.push( v0.x, v0.y, v0.z ); - vertices.push( v1.x, v1.y, v1.z ); + } - } + return undefined; - edgeData[ reverseHash ] = null; + } - } else if ( ! ( hash in edgeData ) ) { + dispose( ) { - // if we've already got an edge here then skip adding a new one - edgeData[ hash ] = { + if ( this.boneTexture !== null ) { - index0: indexArr[ j ], - index1: indexArr[ jNext ], - normal: _normal.clone(), + this.boneTexture.dispose(); - }; + this.boneTexture = null; - } + } - } + } - } + fromJSON( json, bones ) { - // iterate over all remaining, unmatched edges and add them to the vertex array - for ( const key in edgeData ) { + this.uuid = json.uuid; - if ( edgeData[ key ] ) { + for ( let i = 0, l = json.bones.length; i < l; i ++ ) { - const { index0, index1 } = edgeData[ key ]; - _v0.fromBufferAttribute( positionAttr, index0 ); - _v1$1.fromBufferAttribute( positionAttr, index1 ); + const uuid = json.bones[ i ]; + let bone = bones[ uuid ]; - vertices.push( _v0.x, _v0.y, _v0.z ); - vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); + if ( bone === undefined ) { - } + console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); + bone = new Bone(); } - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.bones.push( bone ); + this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); } - } - - } - - class Shape extends Path { - - constructor( points ) { + this.init(); - super( points ); + return this; - this.uuid = generateUUID(); + } - this.type = 'Shape'; + toJSON() { - this.holes = []; + const data = { + metadata: { + version: 4.5, + type: 'Skeleton', + generator: 'Skeleton.toJSON' + }, + bones: [], + boneInverses: [] + }; - } + data.uuid = this.uuid; - getPointsHoles( divisions ) { + const bones = this.bones; + const boneInverses = this.boneInverses; - const holesPts = []; + for ( let i = 0, l = bones.length; i < l; i ++ ) { - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { + const bone = bones[ i ]; + data.bones.push( bone.uuid ); - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); + const boneInverse = boneInverses[ i ]; + data.boneInverses.push( boneInverse.toArray() ); } - return holesPts; + return data; } - // get points of shape and holes (keypoints based on segments parameter) + } - extractPoints( divisions ) { + class InstancedBufferAttribute extends BufferAttribute { - return { + constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) + super( array, itemSize, normalized ); - }; + this.isInstancedBufferAttribute = true; + + this.meshPerAttribute = meshPerAttribute; } @@ -43801,15 +75198,7 @@ var app = (function () { super.copy( source ); - this.holes = []; - - for ( let i = 0, l = source.holes.length; i < l; i ++ ) { - - const hole = source.holes[ i ]; - - this.holes.push( hole.clone() ); - - } + this.meshPerAttribute = source.meshPerAttribute; return this; @@ -43819,6787 +75208,6773 @@ var app = (function () { const data = super.toJSON(); - data.uuid = this.uuid; - data.holes = []; - - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - - const hole = this.holes[ i ]; - data.holes.push( hole.toJSON() ); + data.meshPerAttribute = this.meshPerAttribute; - } + data.isInstancedBufferAttribute = true; return data; } - fromJSON( json ) { + } - super.fromJSON( json ); + const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); + const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); - this.uuid = json.uuid; - this.holes = []; - - for ( let i = 0, l = json.holes.length; i < l; i ++ ) { + const _instanceIntersects = []; - const hole = json.holes[ i ]; - this.holes.push( new Path().fromJSON( hole ) ); + const _mesh = /*@__PURE__*/ new Mesh(); - } + class InstancedMesh extends Mesh { - return this; + constructor( geometry, material, count ) { - } + super( geometry, material ); - } + this.isInstancedMesh = true; - /** - * Port from https://github.com/mapbox/earcut (v2.2.2) - */ + this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); + this.instanceColor = null; - const Earcut = { + this.count = count; - triangulate: function ( data, holeIndices, dim = 2 ) { + this.frustumCulled = false; - const hasHoles = holeIndices && holeIndices.length; - const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length; - let outerNode = linkedList( data, 0, outerLen, dim, true ); - const triangles = []; + } - if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles; + copy( source, recursive ) { - let minX, minY, maxX, maxY, x, y, invSize; + super.copy( source, recursive ); - if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); + this.instanceMatrix.copy( source.instanceMatrix ); - // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox - if ( data.length > 80 * dim ) { + if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); - minX = maxX = data[ 0 ]; - minY = maxY = data[ 1 ]; + this.count = source.count; - for ( let i = dim; i < outerLen; i += dim ) { + return this; - x = data[ i ]; - y = data[ i + 1 ]; - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; + } - } + getColorAt( index, color ) { - // minX, minY and invSize are later used to transform coords into integers for z-order calculation - invSize = Math.max( maxX - minX, maxY - minY ); - invSize = invSize !== 0 ? 1 / invSize : 0; + color.fromArray( this.instanceColor.array, index * 3 ); - } + } - earcutLinked( outerNode, triangles, dim, minX, minY, invSize ); + getMatrixAt( index, matrix ) { - return triangles; + matrix.fromArray( this.instanceMatrix.array, index * 16 ); } - }; + raycast( raycaster, intersects ) { - // create a circular doubly linked list from polygon points in the specified winding order - function linkedList( data, start, end, dim, clockwise ) { + const matrixWorld = this.matrixWorld; + const raycastTimes = this.count; - let i, last; + _mesh.geometry = this.geometry; + _mesh.material = this.material; - if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { + if ( _mesh.material === undefined ) return; - for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { - } else { + // calculate the world matrix for each instance - for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + this.getMatrixAt( instanceId, _instanceLocalMatrix ); - } + _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); - if ( last && equals( last, last.next ) ) { + // the mesh represents this single instance - removeNode( last ); - last = last.next; + _mesh.matrixWorld = _instanceWorldMatrix; - } + _mesh.raycast( raycaster, _instanceIntersects ); - return last; + // process the result of raycast - } + for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { - // eliminate colinear or duplicate points - function filterPoints( start, end ) { + const intersect = _instanceIntersects[ i ]; + intersect.instanceId = instanceId; + intersect.object = this; + intersects.push( intersect ); - if ( ! start ) return start; - if ( ! end ) end = start; + } - let p = start, - again; - do { + _instanceIntersects.length = 0; - again = false; + } - if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { + } - removeNode( p ); - p = end = p.prev; - if ( p === p.next ) break; - again = true; + setColorAt( index, color ) { - } else { + if ( this.instanceColor === null ) { - p = p.next; + this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 ); } - } while ( again || p !== end ); + color.toArray( this.instanceColor.array, index * 3 ); - return end; + } - } + setMatrixAt( index, matrix ) { - // main ear slicing loop which triangulates a polygon (given as a linked list) - function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { + matrix.toArray( this.instanceMatrix.array, index * 16 ); - if ( ! ear ) return; + } - // interlink polygon nodes in z-order - if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); + updateMorphTargets() { - let stop = ear, - prev, next; + } - // iterate through ears, slicing them one by one - while ( ear.prev !== ear.next ) { + dispose() { - prev = ear.prev; - next = ear.next; + this.dispatchEvent( { type: 'dispose' } ); - if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { + } - // cut off the triangle - triangles.push( prev.i / dim ); - triangles.push( ear.i / dim ); - triangles.push( next.i / dim ); + } - removeNode( ear ); + class LineBasicMaterial extends Material { - // skipping the next vertex leads to less sliver triangles - ear = next.next; - stop = next.next; + constructor( parameters ) { - continue; + super(); - } + this.isLineBasicMaterial = true; - ear = next; + this.type = 'LineBasicMaterial'; - // if we looped through the whole remaining polygon and can't find any more ears - if ( ear === stop ) { + this.color = new Color( 0xffffff ); - // try filtering points and slicing again - if ( ! pass ) { + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; - earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); + this.fog = true; - // if this didn't work, try curing all small self-intersections locally + this.setValues( parameters ); - } else if ( pass === 1 ) { + } - ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); - earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); - // as a last resort, try splitting the remaining polygon into two + copy( source ) { - } else if ( pass === 2 ) { + super.copy( source ); - splitEarcut( ear, triangles, dim, minX, minY, invSize ); + this.color.copy( source.color ); - } + this.linewidth = source.linewidth; + this.linecap = source.linecap; + this.linejoin = source.linejoin; - break; + this.fog = source.fog; - } + return this; } } - // check whether a polygon node forms a valid ear with adjacent nodes - function isEar( ear ) { + const _start$1 = /*@__PURE__*/ new Vector3(); + const _end$1 = /*@__PURE__*/ new Vector3(); + const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); + const _ray$1 = /*@__PURE__*/ new Ray(); + const _sphere$1 = /*@__PURE__*/ new Sphere(); - const a = ear.prev, - b = ear, - c = ear.next; + class Line extends Object3D { - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { - // now make sure we don't have other points inside the potential ear - let p = ear.next.next; + super(); - while ( p !== ear.prev ) { + this.isLine = true; - if ( pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.next; + this.type = 'Line'; - } + this.geometry = geometry; + this.material = material; - return true; + this.updateMorphTargets(); - } + } - function isEarHashed( ear, minX, minY, invSize ) { + copy( source, recursive ) { - const a = ear.prev, - b = ear, - c = ear.next; + super.copy( source, recursive ); - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + this.material = source.material; + this.geometry = source.geometry; - // triangle bbox; min & max are calculated like this for speed - const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ), - minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ), - maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ), - maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y ); + return this; - // z-order range for the current triangle bbox; - const minZ = zOrder( minTX, minTY, minX, minY, invSize ), - maxZ = zOrder( maxTX, maxTY, minX, minY, invSize ); + } - let p = ear.prevZ, - n = ear.nextZ; + computeLineDistances() { - // look for points inside the triangle in both directions - while ( p && p.z >= minZ && n && n.z <= maxZ ) { + const geometry = this.geometry; - if ( p !== ear.prev && p !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; + // we assume non-indexed geometry - if ( n !== ear.prev && n !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) && - area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; + if ( geometry.index === null ) { - } + const positionAttribute = geometry.attributes.position; + const lineDistances = [ 0 ]; - // look for remaining points in decreasing z-order - while ( p && p.z >= minZ ) { + for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { - if ( p !== ear.prev && p !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; + _start$1.fromBufferAttribute( positionAttribute, i - 1 ); + _end$1.fromBufferAttribute( positionAttribute, i ); - } + lineDistances[ i ] = lineDistances[ i - 1 ]; + lineDistances[ i ] += _start$1.distanceTo( _end$1 ); - // look for remaining points in increasing z-order - while ( n && n.z <= maxZ ) { + } - if ( n !== ear.prev && n !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) && - area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; + geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - } + } else { - return true; + console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - } + } - // go through all polygon nodes and cure small local self-intersections - function cureLocalIntersections( start, triangles, dim ) { + return this; - let p = start; - do { + } - const a = p.prev, - b = p.next.next; + raycast( raycaster, intersects ) { - if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { + const geometry = this.geometry; + const matrixWorld = this.matrixWorld; + const threshold = raycaster.params.Line.threshold; + const drawRange = geometry.drawRange; - triangles.push( a.i / dim ); - triangles.push( p.i / dim ); - triangles.push( b.i / dim ); + // Checking boundingSphere distance to ray - // remove two nodes involved - removeNode( p ); - removeNode( p.next ); + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - p = start = b; + _sphere$1.copy( geometry.boundingSphere ); + _sphere$1.applyMatrix4( matrixWorld ); + _sphere$1.radius += threshold; - } + if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; - p = p.next; + // - } while ( p !== start ); + _inverseMatrix$1.copy( matrixWorld ).invert(); + _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); - return filterPoints( p ); + const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + const localThresholdSq = localThreshold * localThreshold; - } + const vStart = new Vector3(); + const vEnd = new Vector3(); + const interSegment = new Vector3(); + const interRay = new Vector3(); + const step = this.isLineSegments ? 2 : 1; - // try splitting polygon into two and triangulate them independently - function splitEarcut( start, triangles, dim, minX, minY, invSize ) { + const index = geometry.index; + const attributes = geometry.attributes; + const positionAttribute = attributes.position; - // look for a valid diagonal that divides the polygon into two - let a = start; - do { + if ( index !== null ) { - let b = a.next.next; - while ( b !== a.prev ) { + const start = Math.max( 0, drawRange.start ); + const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - if ( a.i !== b.i && isValidDiagonal( a, b ) ) { + for ( let i = start, l = end - 1; i < l; i += step ) { - // split the polygon in two by the diagonal - let c = splitPolygon( a, b ); + const a = index.getX( i ); + const b = index.getX( i + 1 ); - // filter colinear points around the cuts - a = filterPoints( a, a.next ); - c = filterPoints( c, c.next ); + vStart.fromBufferAttribute( positionAttribute, a ); + vEnd.fromBufferAttribute( positionAttribute, b ); - // run earcut on each half - earcutLinked( a, triangles, dim, minX, minY, invSize ); - earcutLinked( c, triangles, dim, minX, minY, invSize ); - return; + const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - } + if ( distSq > localThresholdSq ) continue; - b = b.next; + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - } + const distance = raycaster.ray.origin.distanceTo( interRay ); - a = a.next; + if ( distance < raycaster.near || distance > raycaster.far ) continue; - } while ( a !== start ); + intersects.push( { - } + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + face: null, + faceIndex: null, + object: this - // link every hole into the outer loop, producing a single-ring polygon without holes - function eliminateHoles( data, holeIndices, outerNode, dim ) { + } ); - const queue = []; - let i, len, start, end, list; + } - for ( i = 0, len = holeIndices.length; i < len; i ++ ) { + } else { - start = holeIndices[ i ] * dim; - end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length; - list = linkedList( data, start, end, dim, false ); - if ( list === list.next ) list.steiner = true; - queue.push( getLeftmost( list ) ); + const start = Math.max( 0, drawRange.start ); + const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - } + for ( let i = start, l = end - 1; i < l; i += step ) { - queue.sort( compareX ); + vStart.fromBufferAttribute( positionAttribute, i ); + vEnd.fromBufferAttribute( positionAttribute, i + 1 ); - // process holes from left to right - for ( i = 0; i < queue.length; i ++ ) { + const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - eliminateHole( queue[ i ], outerNode ); - outerNode = filterPoints( outerNode, outerNode.next ); + if ( distSq > localThresholdSq ) continue; - } + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - return outerNode; + const distance = raycaster.ray.origin.distanceTo( interRay ); - } + if ( distance < raycaster.near || distance > raycaster.far ) continue; - function compareX( a, b ) { + intersects.push( { - return a.x - b.x; + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( this.matrixWorld ), + index: i, + face: null, + faceIndex: null, + object: this - } + } ); - // find a bridge between vertices that connects hole with an outer ring and link it - function eliminateHole( hole, outerNode ) { + } - outerNode = findHoleBridge( hole, outerNode ); - if ( outerNode ) { + } - const b = splitPolygon( outerNode, hole ); + } - // filter collinear points around the cuts - filterPoints( outerNode, outerNode.next ); - filterPoints( b, b.next ); + updateMorphTargets() { - } + const geometry = this.geometry; - } + const morphAttributes = geometry.morphAttributes; + const keys = Object.keys( morphAttributes ); - // David Eberly's algorithm for finding a bridge between hole and outer polygon - function findHoleBridge( hole, outerNode ) { + if ( keys.length > 0 ) { - let p = outerNode; - const hx = hole.x; - const hy = hole.y; - let qx = - Infinity, m; + const morphAttribute = morphAttributes[ keys[ 0 ] ]; - // find a segment intersected by a ray from the hole's leftmost point to the left; - // segment's endpoint with lesser x will be potential connection point - do { + if ( morphAttribute !== undefined ) { - if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); - if ( x <= hx && x > qx ) { + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - qx = x; - if ( x === hx ) { + const name = morphAttribute[ m ].name || String( m ); - if ( hy === p.y ) return p; - if ( hy === p.next.y ) return p.next; + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; } - m = p.x < p.next.x ? p : p.next; - } } - p = p.next; + } - } while ( p !== outerNode ); + } - if ( ! m ) return null; + const _start = /*@__PURE__*/ new Vector3(); + const _end = /*@__PURE__*/ new Vector3(); - if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint + class LineSegments extends Line { - // look for points inside the triangle of hole point, segment intersection and endpoint; - // if there are no points found, we have a valid connection; - // otherwise choose the point of the minimum angle with the ray as connection point + constructor( geometry, material ) { - const stop = m, - mx = m.x, - my = m.y; - let tanMin = Infinity, tan; + super( geometry, material ); - p = m; + this.isLineSegments = true; - do { + this.type = 'LineSegments'; - if ( hx >= p.x && p.x >= mx && hx !== p.x && - pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) { + } - tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential + computeLineDistances() { - if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { + const geometry = this.geometry; - m = p; - tanMin = tan; + // we assume non-indexed geometry - } + if ( geometry.index === null ) { - } + const positionAttribute = geometry.attributes.position; + const lineDistances = []; - p = p.next; + for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { - } while ( p !== stop ); + _start.fromBufferAttribute( positionAttribute, i ); + _end.fromBufferAttribute( positionAttribute, i + 1 ); - return m; + lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; + lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); - } + } - // whether sector in vertex m contains sector in vertex p in the same coordinates - function sectorContainsSector( m, p ) { + geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; - - } - - // interlink polygon nodes in z-order - function indexCurve( start, minX, minY, invSize ) { - - let p = start; - do { + } else { - if ( p.z === null ) p.z = zOrder( p.x, p.y, minX, minY, invSize ); - p.prevZ = p.prev; - p.nextZ = p.next; - p = p.next; + console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - } while ( p !== start ); + } - p.prevZ.nextZ = null; - p.prevZ = null; + return this; - sortLinked( p ); + } } - // Simon Tatham's linked list merge sort algorithm - // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html - function sortLinked( list ) { - - let i, p, q, e, tail, numMerges, pSize, qSize, - inSize = 1; - - do { - - p = list; - list = null; - tail = null; - numMerges = 0; - - while ( p ) { - - numMerges ++; - q = p; - pSize = 0; - for ( i = 0; i < inSize; i ++ ) { - - pSize ++; - q = q.nextZ; - if ( ! q ) break; - - } + class LineLoop extends Line { - qSize = inSize; + constructor( geometry, material ) { - while ( pSize > 0 || ( qSize > 0 && q ) ) { + super( geometry, material ); - if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { + this.isLineLoop = true; - e = p; - p = p.nextZ; - pSize --; + this.type = 'LineLoop'; - } else { + } - e = q; - q = q.nextZ; - qSize --; + } - } + class PointsMaterial extends Material { - if ( tail ) tail.nextZ = e; - else list = e; + constructor( parameters ) { - e.prevZ = tail; - tail = e; + super(); - } + this.isPointsMaterial = true; - p = q; + this.type = 'PointsMaterial'; - } + this.color = new Color( 0xffffff ); - tail.nextZ = null; - inSize *= 2; + this.map = null; - } while ( numMerges > 1 ); + this.alphaMap = null; - return list; + this.size = 1; + this.sizeAttenuation = true; - } + this.fog = true; - // z-order of a point given coords and inverse of the longer side of data bbox - function zOrder( x, y, minX, minY, invSize ) { + this.setValues( parameters ); - // coords are transformed into non-negative 15-bit integer range - x = 32767 * ( x - minX ) * invSize; - y = 32767 * ( y - minY ) * invSize; + } - x = ( x | ( x << 8 ) ) & 0x00FF00FF; - x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; - x = ( x | ( x << 2 ) ) & 0x33333333; - x = ( x | ( x << 1 ) ) & 0x55555555; + copy( source ) { - y = ( y | ( y << 8 ) ) & 0x00FF00FF; - y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; - y = ( y | ( y << 2 ) ) & 0x33333333; - y = ( y | ( y << 1 ) ) & 0x55555555; + super.copy( source ); - return x | ( y << 1 ); + this.color.copy( source.color ); - } + this.map = source.map; - // find the leftmost node of a polygon ring - function getLeftmost( start ) { + this.alphaMap = source.alphaMap; - let p = start, - leftmost = start; - do { + this.size = source.size; + this.sizeAttenuation = source.sizeAttenuation; - if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p; - p = p.next; + this.fog = source.fog; - } while ( p !== start ); + return this; - return leftmost; + } } - // check if a point lies within a convex triangle - function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { - - return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 && - ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 && - ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0; + const _inverseMatrix = /*@__PURE__*/ new Matrix4(); + const _ray = /*@__PURE__*/ new Ray(); + const _sphere = /*@__PURE__*/ new Sphere(); + const _position$2 = /*@__PURE__*/ new Vector3(); - } + class Points extends Object3D { - // check if a diagonal between two polygon nodes is valid (lies in polygon interior) - function isValidDiagonal( a, b ) { + constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { - return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // doesn't intersect other edges - ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible - ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors - equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case + super(); - } + this.isPoints = true; - // signed area of a triangle - function area( p, q, r ) { + this.type = 'Points'; - return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); + this.geometry = geometry; + this.material = material; - } + this.updateMorphTargets(); - // check if two points are equal - function equals( p1, p2 ) { + } - return p1.x === p2.x && p1.y === p2.y; + copy( source, recursive ) { - } + super.copy( source, recursive ); - // check if two segments intersect - function intersects( p1, q1, p2, q2 ) { + this.material = source.material; + this.geometry = source.geometry; - const o1 = sign( area( p1, q1, p2 ) ); - const o2 = sign( area( p1, q1, q2 ) ); - const o3 = sign( area( p2, q2, p1 ) ); - const o4 = sign( area( p2, q2, q1 ) ); + return this; - if ( o1 !== o2 && o3 !== o4 ) return true; // general case + } - if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 - if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 - if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 - if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 + raycast( raycaster, intersects ) { - return false; + const geometry = this.geometry; + const matrixWorld = this.matrixWorld; + const threshold = raycaster.params.Points.threshold; + const drawRange = geometry.drawRange; - } + // Checking boundingSphere distance to ray - // for collinear points p, q, r, check if point q lies on segment pr - function onSegment( p, q, r ) { + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y ); + _sphere.copy( geometry.boundingSphere ); + _sphere.applyMatrix4( matrixWorld ); + _sphere.radius += threshold; - } + if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; - function sign( num ) { + // - return num > 0 ? 1 : num < 0 ? - 1 : 0; + _inverseMatrix.copy( matrixWorld ).invert(); + _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); - } + const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + const localThresholdSq = localThreshold * localThreshold; - // check if a polygon diagonal intersects any polygon segments - function intersectsPolygon( a, b ) { + const index = geometry.index; + const attributes = geometry.attributes; + const positionAttribute = attributes.position; - let p = a; - do { + if ( index !== null ) { - if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && - intersects( p, p.next, a, b ) ) return true; - p = p.next; + const start = Math.max( 0, drawRange.start ); + const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - } while ( p !== a ); + for ( let i = start, il = end; i < il; i ++ ) { - return false; + const a = index.getX( i ); - } + _position$2.fromBufferAttribute( positionAttribute, a ); - // check if a polygon diagonal is locally inside the polygon - function locallyInside( a, b ) { + testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); - return area( a.prev, a, a.next ) < 0 ? - area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 : - area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0; + } - } + } else { - // check if the middle point of a polygon diagonal is inside the polygon - function middleInside( a, b ) { + const start = Math.max( 0, drawRange.start ); + const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - let p = a, - inside = false; - const px = ( a.x + b.x ) / 2, - py = ( a.y + b.y ) / 2; - do { + for ( let i = start, l = end; i < l; i ++ ) { - if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y && - ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) - inside = ! inside; - p = p.next; + _position$2.fromBufferAttribute( positionAttribute, i ); - } while ( p !== a ); + testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); - return inside; + } - } + } - // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; - // if one belongs to the outer ring and another to a hole, it merges it into a single ring - function splitPolygon( a, b ) { + } - const a2 = new Node( a.i, a.x, a.y ), - b2 = new Node( b.i, b.x, b.y ), - an = a.next, - bp = b.prev; + updateMorphTargets() { - a.next = b; - b.prev = a; + const geometry = this.geometry; - a2.next = an; - an.prev = a2; + const morphAttributes = geometry.morphAttributes; + const keys = Object.keys( morphAttributes ); - b2.next = a2; - a2.prev = b2; + if ( keys.length > 0 ) { - bp.next = b2; - b2.prev = bp; + const morphAttribute = morphAttributes[ keys[ 0 ] ]; - return b2; + if ( morphAttribute !== undefined ) { - } + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - // create a node and optionally link it with previous one (in a circular doubly linked list) - function insertNode( i, x, y, last ) { + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - const p = new Node( i, x, y ); + const name = morphAttribute[ m ].name || String( m ); - if ( ! last ) { + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; - p.prev = p; - p.next = p; + } - } else { + } - p.next = last.next; - p.prev = last; - last.next.prev = p; - last.next = p; + } } - return p; - } - function removeNode( p ) { + function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { - p.next.prev = p.prev; - p.prev.next = p.next; + const rayPointDistanceSq = _ray.distanceSqToPoint( point ); - if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; - if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; + if ( rayPointDistanceSq < localThresholdSq ) { - } + const intersectPoint = new Vector3(); - function Node( i, x, y ) { + _ray.closestPointToPoint( point, intersectPoint ); + intersectPoint.applyMatrix4( matrixWorld ); - // vertex index in coordinates array - this.i = i; + const distance = raycaster.ray.origin.distanceTo( intersectPoint ); - // vertex coordinates - this.x = x; - this.y = y; + if ( distance < raycaster.near || distance > raycaster.far ) return; - // previous and next vertex nodes in a polygon ring - this.prev = null; - this.next = null; + intersects.push( { - // z-order curve value - this.z = null; + distance: distance, + distanceToRay: Math.sqrt( rayPointDistanceSq ), + point: intersectPoint, + index: index, + face: null, + object: object - // previous and next nodes in z-order - this.prevZ = null; - this.nextZ = null; + } ); - // indicates whether this is a steiner point - this.steiner = false; + } } - function signedArea( data, start, end, dim ) { + class VideoTexture extends Texture { - let sum = 0; - for ( let i = start, j = end - dim; i < end; i += dim ) { + constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); - j = i; + super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - } + this.isVideoTexture = true; - return sum; + this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; + this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - } + this.generateMipmaps = false; - class ShapeUtils { + const scope = this; - // calculate area of the contour polygon + function updateVideo() { - static area( contour ) { + scope.needsUpdate = true; + video.requestVideoFrameCallback( updateVideo ); - const n = contour.length; - let a = 0.0; + } - for ( let p = n - 1, q = 0; q < n; p = q ++ ) { + if ( 'requestVideoFrameCallback' in video ) { - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + video.requestVideoFrameCallback( updateVideo ); } - return a * 0.5; - } - static isClockWise( pts ) { + clone() { - return ShapeUtils.area( pts ) < 0; + return new this.constructor( this.image ).copy( this ); } - static triangulateShape( contour, holes ) { - - const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] - const holeIndices = []; // array of hole indices - const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] + update() { - removeDupEndPts( contour ); - addContour( vertices, contour ); + const video = this.image; + const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; - // + if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { - let holeIndex = contour.length; + this.needsUpdate = true; - holes.forEach( removeDupEndPts ); + } - for ( let i = 0; i < holes.length; i ++ ) { + } - holeIndices.push( holeIndex ); - holeIndex += holes[ i ].length; - addContour( vertices, holes[ i ] ); + } - } + class FramebufferTexture extends Texture { - // + constructor( width, height, format ) { - const triangles = Earcut.triangulate( vertices, holeIndices ); + super( { width, height } ); - // + this.isFramebufferTexture = true; - for ( let i = 0; i < triangles.length; i += 3 ) { + this.format = format; - faces.push( triangles.slice( i, i + 3 ) ); + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - } + this.generateMipmaps = false; - return faces; + this.needsUpdate = true; } } - function removeDupEndPts( points ) { + class CompressedTexture extends Texture { - const l = points.length; + constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - points.pop(); + this.isCompressedTexture = true; + + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + this.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + this.generateMipmaps = false; } } - function addContour( vertices, contour ) { + class CanvasTexture extends Texture { - for ( let i = 0; i < contour.length; i ++ ) { + constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - vertices.push( contour[ i ].x ); - vertices.push( contour[ i ].y ); + super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.isCanvasTexture = true; + + this.needsUpdate = true; } } /** - * Creates extruded geometry from a path shape. + * Extensible curve object. * - * parameters = { + * Some common of curve methods: + * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) + * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() * - * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too - * depth: , // Depth to extrude the shape + * This following curves inherit from THREE.Curve: * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into the original shape bevel goes - * bevelSize: , // how far from shape outline (including bevelOffset) is bevel - * bevelOffset: , // how far from shape outline does bevel start - * bevelSegments: , // number of bevel layers + * -- 2D curves -- + * THREE.ArcCurve + * THREE.CubicBezierCurve + * THREE.EllipseCurve + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.SplineCurve * - * extrudePath: // curve to extrude shape along + * -- 3D curves -- + * THREE.CatmullRomCurve3 + * THREE.CubicBezierCurve3 + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 * - * UVGenerator: // object that provides UV generator functions + * A series of curves can be represented as a THREE.CurvePath. * - * } - */ + **/ - class ExtrudeGeometry extends BufferGeometry { + class Curve { - constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) { + constructor() { - super(); + this.type = 'Curve'; - this.type = 'ExtrudeGeometry'; + this.arcLengthDivisions = 200; - this.parameters = { - shapes: shapes, - options: options - }; + } - shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; + // Virtual base class method to overwrite and implement in subclasses + // - t [0 .. 1] - const scope = this; + getPoint( /* t, optionalTarget */ ) { - const verticesArray = []; - const uvArray = []; + console.warn( 'THREE.Curve: .getPoint() not implemented.' ); + return null; - for ( let i = 0, l = shapes.length; i < l; i ++ ) { + } - const shape = shapes[ i ]; - addShape( shape ); + // Get point at relative position in curve according to arc length + // - u [0 .. 1] - } + getPointAt( u, optionalTarget ) { - // build geometry + const t = this.getUtoTmapping( u ); + return this.getPoint( t, optionalTarget ); - this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); + } - this.computeVertexNormals(); + // Get sequence of points using getPoint( t ) - // functions + getPoints( divisions = 5 ) { - function addShape( shape ) { + const points = []; - const placeholder = []; + for ( let d = 0; d <= divisions; d ++ ) { - // options + points.push( this.getPoint( d / divisions ) ); - const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - const steps = options.steps !== undefined ? options.steps : 1; - const depth = options.depth !== undefined ? options.depth : 1; + } - let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; - let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; - let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; - let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; - let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + return points; - const extrudePath = options.extrudePath; + } - const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; + // Get sequence of points using getPointAt( u ) - // + getSpacedPoints( divisions = 5 ) { - let extrudePts, extrudeByPath = false; - let splineTube, binormal, normal, position2; + const points = []; - if ( extrudePath ) { + for ( let d = 0; d <= divisions; d ++ ) { - extrudePts = extrudePath.getSpacedPoints( steps ); + points.push( this.getPointAt( d / divisions ) ); - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion + } - // SETUP TNB variables + return points; - // TODO1 - have a .isClosed in spline? + } - splineTube = extrudePath.computeFrenetFrames( steps, false ); + // Get total curve arc length - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + getLength() { - binormal = new Vector3(); - normal = new Vector3(); - position2 = new Vector3(); + const lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; - } + } - // Safeguards if bevels are not enabled + // Get list of cumulative segment lengths - if ( ! bevelEnabled ) { + getLengths( divisions = this.arcLengthDivisions ) { - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; - bevelOffset = 0; + if ( this.cacheArcLengths && + ( this.cacheArcLengths.length === divisions + 1 ) && + ! this.needsUpdate ) { - } + return this.cacheArcLengths; - // Variables initialization + } - const shapePoints = shape.extractPoints( curveSegments ); + this.needsUpdate = false; - let vertices = shapePoints.shape; - const holes = shapePoints.holes; + const cache = []; + let current, last = this.getPoint( 0 ); + let sum = 0; - const reverse = ! ShapeUtils.isClockWise( vertices ); + cache.push( 0 ); - if ( reverse ) { + for ( let p = 1; p <= divisions; p ++ ) { - vertices = vertices.reverse(); + current = this.getPoint( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; - // Maybe we should also check if holes are in the opposite direction, just to be safe ... + } - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + this.cacheArcLengths = cache; - const ahole = holes[ h ]; + return cache; // { sums: cache, sum: sum }; Sum is in the last element. - if ( ShapeUtils.isClockWise( ahole ) ) { + } - holes[ h ] = ahole.reverse(); + updateArcLengths() { - } + this.needsUpdate = true; + this.getLengths(); - } + } - } + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant + getUtoTmapping( u, distance ) { - const faces = ShapeUtils.triangulateShape( vertices, holes ); + const arcLengths = this.getLengths(); - /* Vertices */ + let i = 0; + const il = arcLengths.length; - const contour = vertices; // vertices has all points but contour has only points of circumference + let targetArcLength; // The targeted u distance value to get - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + if ( distance ) { - const ahole = holes[ h ]; + targetArcLength = distance; - vertices = vertices.concat( ahole ); + } else { - } + targetArcLength = u * arcLengths[ il - 1 ]; + } - function scalePt2( pt, vec, size ) { + // binary search for the index with largest value smaller than target u distance - if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); + let low = 0, high = il - 1, comparison; - return vec.clone().multiplyScalar( size ).add( pt ); + while ( low <= high ) { - } + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - const vlen = vertices.length, flen = faces.length; + comparison = arcLengths[ i ] - targetArcLength; + if ( comparison < 0 ) { - // Find directions for point movement + low = i + 1; + } else if ( comparison > 0 ) { - function getBevelVec( inPt, inPrev, inNext ) { + high = i - 1; - // computes for inPt the corresponding point inPt' on a new contour - // shifted by 1 unit (length of normalized vector) to the left - // if we walk along contour clockwise, this new contour is outside the old one - // - // inPt' is the intersection of the two lines parallel to the two - // adjacent edges of inPt at a distance of 1 unit on the left side. + } else { - let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt + high = i; + break; - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html + // DONE - const v_prev_x = inPt.x - inPrev.x, - v_prev_y = inPt.y - inPrev.y; - const v_next_x = inNext.x - inPt.x, - v_next_y = inNext.y - inPt.y; + } - const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); + } - // check for collinear edges - const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + i = high; - if ( Math.abs( collinear0 ) > Number.EPSILON ) { + if ( arcLengths[ i ] === targetArcLength ) { - // not collinear + return i / ( il - 1 ); - // length of vectors for normalizing + } - const v_prev_len = Math.sqrt( v_prev_lensq ); - const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); + // we could get finer grain at lengths, or use simple interpolation between two points - // shift adjacent points by unit vectors to the left + const lengthBefore = arcLengths[ i ]; + const lengthAfter = arcLengths[ i + 1 ]; - const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + const segmentLength = lengthAfter - lengthBefore; - const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + // determine where we are between the 'before' and 'after' points - // scaling factor for v_prev to intersection point + const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + // add that fractional amount to t - // vector from inPt to intersection point + const t = ( i + segmentFraction ) / ( il - 1 ); - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + return t; - // Don't normalize!, otherwise sharp corners become ugly - // but prevent crazy spikes - const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); - if ( v_trans_lensq <= 2 ) { + } - return new Vector2( v_trans_x, v_trans_y ); + // Returns a unit vector tangent at t + // In case any sub curve does not implement its tangent derivation, + // 2 points a small delta apart will be used to find its gradient + // which seems to give a reasonable approximation - } else { + getTangent( t, optionalTarget ) { - shrink_by = Math.sqrt( v_trans_lensq / 2 ); + const delta = 0.0001; + let t1 = t - delta; + let t2 = t + delta; - } + // Capping in case of danger - } else { + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; - // handle special case of collinear edges + const pt1 = this.getPoint( t1 ); + const pt2 = this.getPoint( t2 ); - let direction_eq = false; // assumes: opposite + const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); - if ( v_prev_x > Number.EPSILON ) { + tangent.copy( pt2 ).sub( pt1 ).normalize(); - if ( v_next_x > Number.EPSILON ) { + return tangent; - direction_eq = true; + } - } + getTangentAt( u, optionalTarget ) { - } else { + const t = this.getUtoTmapping( u ); + return this.getTangent( t, optionalTarget ); - if ( v_prev_x < - Number.EPSILON ) { + } - if ( v_next_x < - Number.EPSILON ) { + computeFrenetFrames( segments, closed ) { - direction_eq = true; + // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf - } + const normal = new Vector3(); - } else { + const tangents = []; + const normals = []; + const binormals = []; - if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { + const vec = new Vector3(); + const mat = new Matrix4(); - direction_eq = true; + // compute the tangent vectors for each segment on the curve - } + for ( let i = 0; i <= segments; i ++ ) { - } + const u = i / segments; - } + tangents[ i ] = this.getTangentAt( u, new Vector3() ); - if ( direction_eq ) { + } - // console.log("Warning: lines are a straight sequence"); - v_trans_x = - v_prev_y; - v_trans_y = v_prev_x; - shrink_by = Math.sqrt( v_prev_lensq ); + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the minimum tangent xyz component - } else { + normals[ 0 ] = new Vector3(); + binormals[ 0 ] = new Vector3(); + let min = Number.MAX_VALUE; + const tx = Math.abs( tangents[ 0 ].x ); + const ty = Math.abs( tangents[ 0 ].y ); + const tz = Math.abs( tangents[ 0 ].z ); - // console.log("Warning: lines are a straight spike"); - v_trans_x = v_prev_x; - v_trans_y = v_prev_y; - shrink_by = Math.sqrt( v_prev_lensq / 2 ); + if ( tx <= min ) { - } + min = tx; + normal.set( 1, 0, 0 ); - } + } - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); + if ( ty <= min ) { - } + min = ty; + normal.set( 0, 1, 0 ); + } - const contourMovements = []; + if ( tz <= min ) { - for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + normal.set( 0, 0, 1 ); - if ( j === il ) j = 0; - if ( k === il ) k = 0; + } - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) + vec.crossVectors( tangents[ 0 ], normal ).normalize(); - contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - } - const holesMovements = []; - let oneHoleMovements, verticesMovements = contourMovements.concat(); + // compute the slowly-varying normal and binormal vectors for each segment on the curve - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + for ( let i = 1; i <= segments; i ++ ) { - const ahole = holes[ h ]; + normals[ i ] = normals[ i - 1 ].clone(); - oneHoleMovements = []; + binormals[ i ] = binormals[ i - 1 ].clone(); - for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - if ( j === il ) j = 0; - if ( k === il ) k = 0; + if ( vec.length() > Number.EPSILON ) { - // (j)---(i)---(k) - oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + vec.normalize(); - } + const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); } + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - // Loop bevelSegments, 1 for the front, 1 for the back + } - for ( let b = 0; b < bevelSegments; b ++ ) { + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - //for ( b = bevelSegments; b > 0; b -- ) { + if ( closed === true ) { - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; + let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); + theta /= segments; - // contract shape + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - for ( let i = 0, il = contour.length; i < il; i ++ ) { + theta = - theta; - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + } - v( vert.x, vert.y, - z ); + for ( let i = 1; i <= segments; i ++ ) { - } + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - // expand holes + } - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + } - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + return { + tangents: tangents, + normals: normals, + binormals: binormals + }; - for ( let i = 0, il = ahole.length; i < il; i ++ ) { + } - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + clone() { - v( vert.x, vert.y, - z ); + return new this.constructor().copy( this ); - } + } - } + copy( source ) { - } + this.arcLengthDivisions = source.arcLengthDivisions; - const bs = bevelSize + bevelOffset; + return this; - // Back facing vertices + } - for ( let i = 0; i < vlen; i ++ ) { + toJSON() { - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + const data = { + metadata: { + version: 4.5, + type: 'Curve', + generator: 'Curve.toJSON' + } + }; - if ( ! extrudeByPath ) { + data.arcLengthDivisions = this.arcLengthDivisions; + data.type = this.type; - v( vert.x, vert.y, 0 ); + return data; - } else { + } - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + fromJSON( json ) { - normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); + this.arcLengthDivisions = json.arcLengthDivisions; - position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); + return this; - v( position2.x, position2.y, position2.z ); + } - } + } - } + class EllipseCurve extends Curve { - // Add stepped vertices... - // Including front facing vertices + constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { - for ( let s = 1; s <= steps; s ++ ) { + super(); - for ( let i = 0; i < vlen; i ++ ) { + this.isEllipseCurve = true; - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + this.type = 'EllipseCurve'; - if ( ! extrudeByPath ) { + this.aX = aX; + this.aY = aY; - v( vert.x, vert.y, depth / steps * s ); + this.xRadius = xRadius; + this.yRadius = yRadius; - } else { + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + this.aClockwise = aClockwise; - normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); + this.aRotation = aRotation; - position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); + } - v( position2.x, position2.y, position2.z ); + getPoint( t, optionalTarget ) { - } + const point = optionalTarget || new Vector2(); - } + const twoPi = Math.PI * 2; + let deltaAngle = this.aEndAngle - this.aStartAngle; + const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - } + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) deltaAngle += twoPi; + while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + if ( deltaAngle < Number.EPSILON ) { - // Add bevel segments planes + if ( samePoints ) { - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( let b = bevelSegments - 1; b >= 0; b -- ) { + deltaAngle = 0; - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; + } else { - // contract shape + deltaAngle = twoPi; - for ( let i = 0, il = contour.length; i < il; i ++ ) { + } - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, depth + z ); + } - } + if ( this.aClockwise === true && ! samePoints ) { - // expand holes + if ( deltaAngle === twoPi ) { - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + deltaAngle = - twoPi; - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + } else { - for ( let i = 0, il = ahole.length; i < il; i ++ ) { + deltaAngle = deltaAngle - twoPi; - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + } - if ( ! extrudeByPath ) { + } - v( vert.x, vert.y, depth + z ); + const angle = this.aStartAngle + t * deltaAngle; + let x = this.aX + this.xRadius * Math.cos( angle ); + let y = this.aY + this.yRadius * Math.sin( angle ); - } else { + if ( this.aRotation !== 0 ) { - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + const cos = Math.cos( this.aRotation ); + const sin = Math.sin( this.aRotation ); - } + const tx = x - this.aX; + const ty = y - this.aY; - } + // Rotate the point about the center of the ellipse. + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; - } + } - } + return point.set( x, y ); - /* Faces */ + } - // Top and bottom faces + copy( source ) { - buildLidFaces(); + super.copy( source ); - // Sides faces + this.aX = source.aX; + this.aY = source.aY; - buildSideFaces(); + this.xRadius = source.xRadius; + this.yRadius = source.yRadius; + this.aStartAngle = source.aStartAngle; + this.aEndAngle = source.aEndAngle; - ///// Internal functions + this.aClockwise = source.aClockwise; - function buildLidFaces() { + this.aRotation = source.aRotation; - const start = verticesArray.length / 3; + return this; - if ( bevelEnabled ) { + } - let layer = 0; // steps + 1 - let offset = vlen * layer; + toJSON() { - // Bottom faces + const data = super.toJSON(); - for ( let i = 0; i < flen; i ++ ) { + data.aX = this.aX; + data.aY = this.aY; - const face = faces[ i ]; - f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); + data.xRadius = this.xRadius; + data.yRadius = this.yRadius; - } + data.aStartAngle = this.aStartAngle; + data.aEndAngle = this.aEndAngle; - layer = steps + bevelSegments * 2; - offset = vlen * layer; + data.aClockwise = this.aClockwise; - // Top faces + data.aRotation = this.aRotation; - for ( let i = 0; i < flen; i ++ ) { + return data; - const face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); + } - } + fromJSON( json ) { - } else { + super.fromJSON( json ); - // Bottom faces + this.aX = json.aX; + this.aY = json.aY; - for ( let i = 0; i < flen; i ++ ) { + this.xRadius = json.xRadius; + this.yRadius = json.yRadius; - const face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ] ); + this.aStartAngle = json.aStartAngle; + this.aEndAngle = json.aEndAngle; - } + this.aClockwise = json.aClockwise; - // Top faces + this.aRotation = json.aRotation; - for ( let i = 0; i < flen; i ++ ) { + return this; - const face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); + } - } + } - } + class ArcCurve extends EllipseCurve { - scope.addGroup( start, verticesArray.length / 3 - start, 0 ); + constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - } + super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - // Create faces for the z-sides of the shape + this.isArcCurve = true; - function buildSideFaces() { + this.type = 'ArcCurve'; - const start = verticesArray.length / 3; - let layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; + } - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { + } - const ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); + /** + * Centripetal CatmullRom Curve - which is useful for avoiding + * cusps and self-intersections in non-uniform catmull rom curves. + * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + * + * curve.type accepts centripetal(default), chordal and catmullrom + * curve.tension is used for catmullrom which defaults to 0.5 + */ - //, true - layeroffset += ahole.length; - } + /* + Based on an optimized c++ solution in + - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ + - http://ideone.com/NoEbVM + This CubicPoly class could be used for reusing some variables and calculations, + but for three.js curve use, it could be possible inlined and flatten into a single function call + which can be placed in CurveUtils. + */ - scope.addGroup( start, verticesArray.length / 3 - start, 1 ); + function CubicPoly() { + let c0 = 0, c1 = 0, c2 = 0, c3 = 0; - } + /* + * Compute coefficients for a cubic polynomial + * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 + * such that + * p(0) = x0, p(1) = x1 + * and + * p'(0) = t0, p'(1) = t1. + */ + function init( x0, x1, t0, t1 ) { - function sidewalls( contour, layeroffset ) { + c0 = x0; + c1 = t0; + c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + c3 = 2 * x0 - 2 * x1 + t0 + t1; - let i = contour.length; + } - while ( -- i >= 0 ) { + return { - const j = i; - let k = i - 1; - if ( k < 0 ) k = contour.length - 1; + initCatmullRom: function ( x0, x1, x2, x3, tension ) { - //console.log('b', i,j, i-1, k,vertices.length); + init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { + }, - const slen1 = vlen * s; - const slen2 = vlen * ( s + 1 ); + initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - const a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; + // compute tangents when parameterized in [t1,t2] + let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; + let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - f4( a, b, c, d ); + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; - } + init( x1, x2, t1, t2 ); - } + }, - } + calc: function ( t ) { - function v( x, y, z ) { + const t2 = t * t; + const t3 = t2 * t; + return c0 + c1 * t + c2 * t2 + c3 * t3; - placeholder.push( x ); - placeholder.push( y ); - placeholder.push( z ); + } - } + }; + } - function f3( a, b, c ) { + // - addVertex( a ); - addVertex( b ); - addVertex( c ); + const tmp = /*@__PURE__*/ new Vector3(); + const px = /*@__PURE__*/ new CubicPoly(); + const py = /*@__PURE__*/ new CubicPoly(); + const pz = /*@__PURE__*/ new CubicPoly(); - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + class CatmullRomCurve3 extends Curve { - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); + constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { - } + super(); - function f4( a, b, c, d ) { + this.isCatmullRomCurve3 = true; - addVertex( a ); - addVertex( b ); - addVertex( d ); + this.type = 'CatmullRomCurve3'; - addVertex( b ); - addVertex( c ); - addVertex( d ); + this.points = points; + this.closed = closed; + this.curveType = curveType; + this.tension = tension; + } - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + getPoint( t, optionalTarget = new Vector3() ) { - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 3 ] ); + const point = optionalTarget; - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - addUV( uvs[ 3 ] ); + const points = this.points; + const l = points.length; - } + const p = ( l - ( this.closed ? 0 : 1 ) ) * t; + let intPoint = Math.floor( p ); + let weight = p - intPoint; - function addVertex( index ) { + if ( this.closed ) { - verticesArray.push( placeholder[ index * 3 + 0 ] ); - verticesArray.push( placeholder[ index * 3 + 1 ] ); - verticesArray.push( placeholder[ index * 3 + 2 ] ); + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; - } + } else if ( weight === 0 && intPoint === l - 1 ) { + intPoint = l - 2; + weight = 1; - function addUV( vector2 ) { + } - uvArray.push( vector2.x ); - uvArray.push( vector2.y ); + let p0, p3; // 4 points (p1 & p2 defined below) - } + if ( this.closed || intPoint > 0 ) { - } + p0 = points[ ( intPoint - 1 ) % l ]; - } + } else { - toJSON() { + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; - const data = super.toJSON(); + } - const shapes = this.parameters.shapes; - const options = this.parameters.options; + const p1 = points[ intPoint % l ]; + const p2 = points[ ( intPoint + 1 ) % l ]; - return toJSON$1( shapes, options, data ); + if ( this.closed || intPoint + 2 < l ) { - } + p3 = points[ ( intPoint + 2 ) % l ]; - static fromJSON( data, shapes ) { + } else { - const geometryShapes = []; + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); + p3 = tmp; - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { + } - const shape = shapes[ data.shapes[ j ] ]; + if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - geometryShapes.push( shape ); + // init Centripetal / Chordal Catmull-Rom + const pow = this.curveType === 'chordal' ? 0.5 : 0.25; + let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - } + // safety check for repeated points + if ( dt1 < 1e-4 ) dt1 = 1.0; + if ( dt0 < 1e-4 ) dt0 = dt1; + if ( dt2 < 1e-4 ) dt2 = dt1; - const extrudePath = data.options.extrudePath; + px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); + py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); + pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - if ( extrudePath !== undefined ) { + } else if ( this.curveType === 'catmullrom' ) { - data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); + px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); + py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); + pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); } - return new ExtrudeGeometry( geometryShapes, data.options ); + point.set( + px.calc( weight ), + py.calc( weight ), + pz.calc( weight ) + ); + + return point; } - } + copy( source ) { - const WorldUVGenerator = { + super.copy( source ); - generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { + this.points = []; - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; + for ( let i = 0, l = source.points.length; i < l; i ++ ) { - return [ - new Vector2( a_x, a_y ), - new Vector2( b_x, b_y ), - new Vector2( c_x, c_y ) - ]; + const point = source.points[ i ]; - }, + this.points.push( point.clone() ); - generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { + } - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const a_z = vertices[ indexA * 3 + 2 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const b_z = vertices[ indexB * 3 + 2 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; - const c_z = vertices[ indexC * 3 + 2 ]; - const d_x = vertices[ indexD * 3 ]; - const d_y = vertices[ indexD * 3 + 1 ]; - const d_z = vertices[ indexD * 3 + 2 ]; + this.closed = source.closed; + this.curveType = source.curveType; + this.tension = source.tension; - if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { + return this; - return [ - new Vector2( a_x, 1 - a_z ), - new Vector2( b_x, 1 - b_z ), - new Vector2( c_x, 1 - c_z ), - new Vector2( d_x, 1 - d_z ) - ]; + } - } else { + toJSON() { - return [ - new Vector2( a_y, 1 - a_z ), - new Vector2( b_y, 1 - b_z ), - new Vector2( c_y, 1 - c_z ), - new Vector2( d_y, 1 - d_z ) - ]; + const data = super.toJSON(); + + data.points = []; + + for ( let i = 0, l = this.points.length; i < l; i ++ ) { + + const point = this.points[ i ]; + data.points.push( point.toArray() ); } - } + data.closed = this.closed; + data.curveType = this.curveType; + data.tension = this.tension; - }; + return data; - function toJSON$1( shapes, options, data ) { + } - data.shapes = []; + fromJSON( json ) { - if ( Array.isArray( shapes ) ) { + super.fromJSON( json ); - for ( let i = 0, l = shapes.length; i < l; i ++ ) { + this.points = []; - const shape = shapes[ i ]; + for ( let i = 0, l = json.points.length; i < l; i ++ ) { - data.shapes.push( shape.uuid ); + const point = json.points[ i ]; + this.points.push( new Vector3().fromArray( point ) ); } - } else { + this.closed = json.closed; + this.curveType = json.curveType; + this.tension = json.tension; - data.shapes.push( shapes.uuid ); + return this; } - data.options = Object.assign( {}, options ); + } - if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); + /** + * Bezier Curves formulas obtained from + * https://en.wikipedia.org/wiki/B%C3%A9zier_curve + */ - return data; + function CatmullRom( t, p0, p1, p2, p3 ) { + + const v0 = ( p2 - p0 ) * 0.5; + const v1 = ( p3 - p1 ) * 0.5; + const t2 = t * t; + const t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; } - class IcosahedronGeometry extends PolyhedronGeometry { + // - constructor( radius = 1, detail = 0 ) { + function QuadraticBezierP0( t, p ) { - const t = ( 1 + Math.sqrt( 5 ) ) / 2; + const k = 1 - t; + return k * k * p; - const vertices = [ - - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, - 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, - t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 - ]; + } - const indices = [ - 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, - 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, - 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, - 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 - ]; + function QuadraticBezierP1( t, p ) { - super( vertices, indices, radius, detail ); + return 2 * ( 1 - t ) * t * p; - this.type = 'IcosahedronGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + function QuadraticBezierP2( t, p ) { - } + return t * t * p; - static fromJSON( data ) { + } - return new IcosahedronGeometry( data.radius, data.detail ); + function QuadraticBezier( t, p0, p1, p2 ) { - } + return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + + QuadraticBezierP2( t, p2 ); } - class OctahedronGeometry extends PolyhedronGeometry { + // - constructor( radius = 1, detail = 0 ) { + function CubicBezierP0( t, p ) { - const vertices = [ - 1, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, - 1, 0, 0, 0, 1, 0, 0, - 1 - ]; + const k = 1 - t; + return k * k * k * p; - const indices = [ - 0, 2, 4, 0, 4, 3, 0, 3, 5, - 0, 5, 2, 1, 2, 5, 1, 5, 3, - 1, 3, 4, 1, 4, 2 - ]; + } - super( vertices, indices, radius, detail ); + function CubicBezierP1( t, p ) { - this.type = 'OctahedronGeometry'; + const k = 1 - t; + return 3 * k * k * t * p; - this.parameters = { - radius: radius, - detail: detail - }; + } - } + function CubicBezierP2( t, p ) { - static fromJSON( data ) { + return 3 * ( 1 - t ) * t * t * p; - return new OctahedronGeometry( data.radius, data.detail ); + } - } + function CubicBezierP3( t, p ) { + + return t * t * t * p; } - class RingGeometry extends BufferGeometry { + function CubicBezier( t, p0, p1, p2, p3 ) { - constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 8, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { + return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + + CubicBezierP3( t, p3 ); - super(); + } - this.type = 'RingGeometry'; + class CubicBezierCurve extends Curve { - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { - thetaSegments = Math.max( 3, thetaSegments ); - phiSegments = Math.max( 1, phiSegments ); + super(); - // buffers + this.isCubicBezierCurve = true; - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + this.type = 'CubicBezierCurve'; - // some helper variables + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; - let radius = innerRadius; - const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - const vertex = new Vector3(); - const uv = new Vector2(); + } - // generate vertices, normals and uvs + getPoint( t, optionalTarget = new Vector2() ) { - for ( let j = 0; j <= phiSegments; j ++ ) { + const point = optionalTarget; - for ( let i = 0; i <= thetaSegments; i ++ ) { + const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - // values are generate from the inside of the ring to the outside + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) + ); - const segment = thetaStart + i / thetaSegments * thetaLength; + return point; - // vertex + } - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + copy( source ) { - vertices.push( vertex.x, vertex.y, vertex.z ); + super.copy( source ); - // normal + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - normals.push( 0, 0, 1 ); + return this; - // uv + } - uv.x = ( vertex.x / outerRadius + 1 ) / 2; - uv.y = ( vertex.y / outerRadius + 1 ) / 2; + toJSON() { - uvs.push( uv.x, uv.y ); - - } + const data = super.toJSON(); - // increase the radius for next row of vertices + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - radius += radiusStep; + return data; - } + } - // indices + fromJSON( json ) { - for ( let j = 0; j < phiSegments; j ++ ) { + super.fromJSON( json ); - const thetaSegmentLevel = j * ( thetaSegments + 1 ); + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - for ( let i = 0; i < thetaSegments; i ++ ) { + return this; - const segment = i + thetaSegmentLevel; + } - const a = segment; - const b = segment + thetaSegments + 1; - const c = segment + thetaSegments + 2; - const d = segment + 1; + } - // faces + class CubicBezierCurve3 extends Curve { - indices.push( a, b, d ); - indices.push( b, c, d ); + constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { - } + super(); - } + this.isCubicBezierCurve3 = true; - // build geometry + this.type = 'CubicBezierCurve3'; - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; } - static fromJSON( data ) { + getPoint( t, optionalTarget = new Vector3() ) { - return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); + const point = optionalTarget; + + const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), + CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) + ); + + return point; } - } + copy( source ) { - class ShapeGeometry extends BufferGeometry { + super.copy( source ); - constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) { + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - super(); + return this; - this.type = 'ShapeGeometry'; + } - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; + toJSON() { - // buffers + const data = super.toJSON(); - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - // helper variables + return data; - let groupStart = 0; - let groupCount = 0; + } - // allow single and array values for "shapes" parameter + fromJSON( json ) { - if ( Array.isArray( shapes ) === false ) { + super.fromJSON( json ); - addShape( shapes ); + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - } else { + return this; - for ( let i = 0; i < shapes.length; i ++ ) { + } - addShape( shapes[ i ] ); + } - this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support + class LineCurve extends Curve { - groupStart += groupCount; - groupCount = 0; + constructor( v1 = new Vector2(), v2 = new Vector2() ) { - } + super(); - } + this.isLineCurve = true; - // build geometry + this.type = 'LineCurve'; - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + this.v1 = v1; + this.v2 = v2; + } - // helper functions + getPoint( t, optionalTarget = new Vector2() ) { - function addShape( shape ) { + const point = optionalTarget; - const indexOffset = vertices.length / 3; - const points = shape.extractPoints( curveSegments ); + if ( t === 1 ) { - let shapeVertices = points.shape; - const shapeHoles = points.holes; + point.copy( this.v2 ); - // check direction of vertices + } else { - if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); - shapeVertices = shapeVertices.reverse(); + } - } + return point; - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { + } - const shapeHole = shapeHoles[ i ]; + // Line curve is linear, so we can overwrite default getPointAt + getPointAt( u, optionalTarget ) { - if ( ShapeUtils.isClockWise( shapeHole ) === true ) { + return this.getPoint( u, optionalTarget ); - shapeHoles[ i ] = shapeHole.reverse(); + } - } + getTangent( t, optionalTarget ) { - } + const tangent = optionalTarget || new Vector2(); - const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); + tangent.copy( this.v2 ).sub( this.v1 ).normalize(); - // join vertices of inner and outer paths to a single array + return tangent; - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { + } - const shapeHole = shapeHoles[ i ]; - shapeVertices = shapeVertices.concat( shapeHole ); + copy( source ) { - } + super.copy( source ); - // vertices, normals, uvs + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { + return this; - const vertex = shapeVertices[ i ]; + } - vertices.push( vertex.x, vertex.y, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( vertex.x, vertex.y ); // world uvs + toJSON() { - } + const data = super.toJSON(); - // incides + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - for ( let i = 0, l = faces.length; i < l; i ++ ) { + return data; - const face = faces[ i ]; + } - const a = face[ 0 ] + indexOffset; - const b = face[ 1 ] + indexOffset; - const c = face[ 2 ] + indexOffset; + fromJSON( json ) { - indices.push( a, b, c ); - groupCount += 3; + super.fromJSON( json ); - } + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - } + return this; } - toJSON() { + } - const data = super.toJSON(); + class LineCurve3 extends Curve { - const shapes = this.parameters.shapes; + constructor( v1 = new Vector3(), v2 = new Vector3() ) { - return toJSON( shapes, data ); + super(); + + this.isLineCurve3 = true; + + this.type = 'LineCurve3'; + + this.v1 = v1; + this.v2 = v2; } + getPoint( t, optionalTarget = new Vector3() ) { - static fromJSON( data, shapes ) { + const point = optionalTarget; - const geometryShapes = []; + if ( t === 1 ) { - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { + point.copy( this.v2 ); - const shape = shapes[ data.shapes[ j ] ]; + } else { - geometryShapes.push( shape ); + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); } - return new ShapeGeometry( geometryShapes, data.curveSegments ); + return point; } + // Line curve is linear, so we can overwrite default getPointAt + getPointAt( u, optionalTarget ) { - } - - function toJSON( shapes, data ) { + return this.getPoint( u, optionalTarget ); - data.shapes = []; + } + copy( source ) { - if ( Array.isArray( shapes ) ) { + super.copy( source ); - for ( let i = 0, l = shapes.length; i < l; i ++ ) { + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - const shape = shapes[ i ]; + return this; - data.shapes.push( shape.uuid ); + } + toJSON() { - } + const data = super.toJSON(); - } else { + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - data.shapes.push( shapes.uuid ); + return data; } + fromJSON( json ) { - return data; + super.fromJSON( json ); - } + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - class SphereGeometry extends BufferGeometry { + return this; - constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { + } - super(); + } - this.type = 'SphereGeometry'; + class QuadraticBezierCurve extends Curve { - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { - widthSegments = Math.max( 3, Math.floor( widthSegments ) ); - heightSegments = Math.max( 2, Math.floor( heightSegments ) ); + super(); - const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); + this.isQuadraticBezierCurve = true; - let index = 0; - const grid = []; + this.type = 'QuadraticBezierCurve'; - const vertex = new Vector3(); - const normal = new Vector3(); + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; - // buffers + } - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + getPoint( t, optionalTarget = new Vector2() ) { - // generate vertices, normals and uvs + const point = optionalTarget; - for ( let iy = 0; iy <= heightSegments; iy ++ ) { + const v0 = this.v0, v1 = this.v1, v2 = this.v2; - const verticesRow = []; + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ) + ); - const v = iy / heightSegments; + return point; - // special case for the poles + } - let uOffset = 0; + copy( source ) { - if ( iy == 0 && thetaStart == 0 ) { + super.copy( source ); - uOffset = 0.5 / widthSegments; + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - } else if ( iy == heightSegments && thetaEnd == Math.PI ) { + return this; - uOffset = - 0.5 / widthSegments; + } - } + toJSON() { - for ( let ix = 0; ix <= widthSegments; ix ++ ) { + const data = super.toJSON(); - const u = ix / widthSegments; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - // vertex + return data; - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + } - vertices.push( vertex.x, vertex.y, vertex.z ); + fromJSON( json ) { - // normal + super.fromJSON( json ); - normal.copy( vertex ).normalize(); - normals.push( normal.x, normal.y, normal.z ); + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - // uv + return this; - uvs.push( u + uOffset, 1 - v ); + } - verticesRow.push( index ++ ); + } - } + class QuadraticBezierCurve3 extends Curve { - grid.push( verticesRow ); + constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { - } + super(); - // indices + this.isQuadraticBezierCurve3 = true; - for ( let iy = 0; iy < heightSegments; iy ++ ) { + this.type = 'QuadraticBezierCurve3'; - for ( let ix = 0; ix < widthSegments; ix ++ ) { + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; - const a = grid[ iy ][ ix + 1 ]; - const b = grid[ iy ][ ix ]; - const c = grid[ iy + 1 ][ ix ]; - const d = grid[ iy + 1 ][ ix + 1 ]; + } - if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); - if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); + getPoint( t, optionalTarget = new Vector3() ) { - } + const point = optionalTarget; - } + const v0 = this.v0, v1 = this.v1, v2 = this.v2; - // build geometry + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ), + QuadraticBezier( t, v0.z, v1.z, v2.z ) + ); - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + return point; } - static fromJSON( data ) { + copy( source ) { - return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); + super.copy( source ); - } + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - } + return this; - class TetrahedronGeometry extends PolyhedronGeometry { + } - constructor( radius = 1, detail = 0 ) { + toJSON() { - const vertices = [ - 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 - ]; + const data = super.toJSON(); - const indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - super( vertices, indices, radius, detail ); + return data; - this.type = 'TetrahedronGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + fromJSON( json ) { - } + super.fromJSON( json ); - static fromJSON( data ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - return new TetrahedronGeometry( data.radius, data.detail ); + return this; } } - class TorusGeometry extends BufferGeometry { + class SplineCurve extends Curve { - constructor( radius = 1, tube = 0.4, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2 ) { + constructor( points = [] ) { super(); - this.type = 'TorusGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; - - radialSegments = Math.floor( radialSegments ); - tubularSegments = Math.floor( tubularSegments ); + this.isSplineCurve = true; - // buffers + this.type = 'SplineCurve'; - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + this.points = points; - // helper variables + } - const center = new Vector3(); - const vertex = new Vector3(); - const normal = new Vector3(); + getPoint( t, optionalTarget = new Vector2() ) { - // generate vertices, normals and uvs + const point = optionalTarget; - for ( let j = 0; j <= radialSegments; j ++ ) { + const points = this.points; + const p = ( points.length - 1 ) * t; - for ( let i = 0; i <= tubularSegments; i ++ ) { + const intPoint = Math.floor( p ); + const weight = p - intPoint; - const u = i / tubularSegments * arc; - const v = j / radialSegments * Math.PI * 2; + const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; + const p1 = points[ intPoint ]; + const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - // vertex + point.set( + CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), + CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) + ); - vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); - vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); - vertex.z = tube * Math.sin( v ); + return point; - vertices.push( vertex.x, vertex.y, vertex.z ); + } - // normal + copy( source ) { - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - normal.subVectors( vertex, center ).normalize(); + super.copy( source ); - normals.push( normal.x, normal.y, normal.z ); + this.points = []; - // uv + for ( let i = 0, l = source.points.length; i < l; i ++ ) { - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); + const point = source.points[ i ]; - } + this.points.push( point.clone() ); } - // generate indices + return this; - for ( let j = 1; j <= radialSegments; j ++ ) { + } - for ( let i = 1; i <= tubularSegments; i ++ ) { + toJSON() { - // indices - - const a = ( tubularSegments + 1 ) * j + i - 1; - const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; - const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; - const d = ( tubularSegments + 1 ) * j + i; + const data = super.toJSON(); - // faces + data.points = []; - indices.push( a, b, d ); - indices.push( b, c, d ); + for ( let i = 0, l = this.points.length; i < l; i ++ ) { - } + const point = this.points[ i ]; + data.points.push( point.toArray() ); } - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + return data; } - static fromJSON( data ) { + fromJSON( json ) { - return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); + super.fromJSON( json ); + + this.points = []; + + for ( let i = 0, l = json.points.length; i < l; i ++ ) { + + const point = json.points[ i ]; + this.points.push( new Vector2().fromArray( point ) ); + + } + + return this; } } - class TorusKnotGeometry extends BufferGeometry { + var Curves = /*#__PURE__*/Object.freeze({ + __proto__: null, + ArcCurve: ArcCurve, + CatmullRomCurve3: CatmullRomCurve3, + CubicBezierCurve: CubicBezierCurve, + CubicBezierCurve3: CubicBezierCurve3, + EllipseCurve: EllipseCurve, + LineCurve: LineCurve, + LineCurve3: LineCurve3, + QuadraticBezierCurve: QuadraticBezierCurve, + QuadraticBezierCurve3: QuadraticBezierCurve3, + SplineCurve: SplineCurve + }); - constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { + /************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ + + class CurvePath extends Curve { + + constructor() { super(); - this.type = 'TorusKnotGeometry'; + this.type = 'CurvePath'; - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; + this.curves = []; + this.autoClose = false; // Automatically closes the path - tubularSegments = Math.floor( tubularSegments ); - radialSegments = Math.floor( radialSegments ); + } - // buffers + add( curve ) { - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; + this.curves.push( curve ); - // helper variables + } - const vertex = new Vector3(); - const normal = new Vector3(); + closePath() { - const P1 = new Vector3(); - const P2 = new Vector3(); + // Add a line curve if start and end of lines are not connected + const startPoint = this.curves[ 0 ].getPoint( 0 ); + const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); - const B = new Vector3(); - const T = new Vector3(); - const N = new Vector3(); + if ( ! startPoint.equals( endPoint ) ) { - // generate vertices, normals and uvs + this.curves.push( new LineCurve( endPoint, startPoint ) ); - for ( let i = 0; i <= tubularSegments; ++ i ) { + } - // the radian "u" is used to calculate the position on the torus curve of the current tubular segment + } - const u = i / tubularSegments * p * Math.PI * 2; + // To get accurate point with reference to + // entire path distance at time t, + // following has to be done: - // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. - // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions + // 1. Length of each sub path have to be known + // 2. Locate and identify type of curve + // 3. Get t for the curve + // 4. Return curve.getPointAt(t') - calculatePositionOnCurve( u, p, q, radius, P1 ); - calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); + getPoint( t, optionalTarget ) { - // calculate orthonormal basis + const d = t * this.getLength(); + const curveLengths = this.getCurveLengths(); + let i = 0; - T.subVectors( P2, P1 ); - N.addVectors( P2, P1 ); - B.crossVectors( T, N ); - N.crossVectors( B, T ); + // To think about boundaries points. - // normalize B, N. T can be ignored, we don't use it + while ( i < curveLengths.length ) { - B.normalize(); - N.normalize(); + if ( curveLengths[ i ] >= d ) { - for ( let j = 0; j <= radialSegments; ++ j ) { + const diff = curveLengths[ i ] - d; + const curve = this.curves[ i ]; - // now calculate the vertices. they are nothing more than an extrusion of the torus curve. - // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. + const segmentLength = curve.getLength(); + const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; - const v = j / radialSegments * Math.PI * 2; - const cx = - tube * Math.cos( v ); - const cy = tube * Math.sin( v ); + return curve.getPointAt( u, optionalTarget ); - // now calculate the final vertex position. - // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve + } - vertex.x = P1.x + ( cx * N.x + cy * B.x ); - vertex.y = P1.y + ( cx * N.y + cy * B.y ); - vertex.z = P1.z + ( cx * N.z + cy * B.z ); + i ++; - vertices.push( vertex.x, vertex.y, vertex.z ); + } - // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) + return null; - normal.subVectors( vertex, P1 ).normalize(); + // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { - for ( let i = 0; i < tubularSegments; i ++ ) { + points.push( points[ 0 ] ); - generateSegment( i ); + } - } + return points; - // if the geometry is not closed, generate the last row of vertices and normals - // at the regular position on the given path - // - // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) + } - generateSegment( ( closed === false ) ? tubularSegments : 0 ); + copy( source ) { - // uvs are generated in a separate function. - // this makes it easy compute correct values for closed geometries + super.copy( source ); - generateUVs(); + this.curves = []; - // finally create faces + for ( let i = 0, l = source.curves.length; i < l; i ++ ) { - generateIndices(); + const curve = source.curves[ i ]; + + this.curves.push( curve.clone() ); } - function generateSegment( i ) { + this.autoClose = source.autoClose; - // we use getPointAt to sample evenly distributed points from the given path + return this; - P = path.getPointAt( i / tubularSegments, P ); + } - // retrieve corresponding normal and binormal + toJSON() { - const N = frames.normals[ i ]; - const B = frames.binormals[ i ]; + const data = super.toJSON(); - // generate normals and vertices for the current segment + data.autoClose = this.autoClose; + data.curves = []; - for ( let j = 0; j <= radialSegments; j ++ ) { + for ( let i = 0, l = this.curves.length; i < l; i ++ ) { - const v = j / radialSegments * Math.PI * 2; + const curve = this.curves[ i ]; + data.curves.push( curve.toJSON() ); - const sin = Math.sin( v ); - const cos = - Math.cos( v ); + } - // normal + return data; - normal.x = ( cos * N.x + sin * B.x ); - normal.y = ( cos * N.y + sin * B.y ); - normal.z = ( cos * N.z + sin * B.z ); - normal.normalize(); + } - normals.push( normal.x, normal.y, normal.z ); + fromJSON( json ) { - // vertex + super.fromJSON( json ); - vertex.x = P.x + radius * normal.x; - vertex.y = P.y + radius * normal.y; - vertex.z = P.z + radius * normal.z; + this.autoClose = json.autoClose; + this.curves = []; - vertices.push( vertex.x, vertex.y, vertex.z ); + for ( let i = 0, l = json.curves.length; i < l; i ++ ) { - } + const curve = json.curves[ i ]; + this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); } - function generateIndices() { + return this; - for ( let j = 1; j <= tubularSegments; j ++ ) { + } - for ( let i = 1; i <= radialSegments; i ++ ) { + } - const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - const b = ( radialSegments + 1 ) * j + ( i - 1 ); - const c = ( radialSegments + 1 ) * j + i; - const d = ( radialSegments + 1 ) * ( j - 1 ) + i; + class Path extends CurvePath { - // faces + constructor( points ) { - indices.push( a, b, d ); - indices.push( b, c, d ); + super(); - } + this.type = 'Path'; - } + this.currentPoint = new Vector2(); - } + if ( points ) { - function generateUVs() { + this.setFromPoints( points ); - for ( let i = 0; i <= tubularSegments; i ++ ) { + } - for ( let j = 0; j <= radialSegments; j ++ ) { + } - uv.x = i / tubularSegments; - uv.y = j / radialSegments; + setFromPoints( points ) { - uvs.push( uv.x, uv.y ); + this.moveTo( points[ 0 ].x, points[ 0 ].y ); - } + for ( let i = 1, l = points.length; i < l; i ++ ) { - } + this.lineTo( points[ i ].x, points[ i ].y ); } - } + return this; - toJSON() { + } - const data = super.toJSON(); + moveTo( x, y ) { - data.path = this.parameters.path.toJSON(); + this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? - return data; + return this; } - static fromJSON( data ) { + lineTo( x, y ) { - // This only works for built-in curves (e.g. CatmullRomCurve3). - // User defined curves or instances of CurvePath will not be deserialized. - return new TubeGeometry( - new Curves[ data.path.type ]().fromJSON( data.path ), - data.tubularSegments, - data.radius, - data.radialSegments, - data.closed - ); + const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); + this.curves.push( curve ); - } + this.currentPoint.set( x, y ); - } + return this; - class WireframeGeometry extends BufferGeometry { + } - constructor( geometry = null ) { + quadraticCurveTo( aCPx, aCPy, aX, aY ) { - super(); + const curve = new QuadraticBezierCurve( + this.currentPoint.clone(), + new Vector2( aCPx, aCPy ), + new Vector2( aX, aY ) + ); - this.type = 'WireframeGeometry'; + this.curves.push( curve ); - this.parameters = { - geometry: geometry - }; + this.currentPoint.set( aX, aY ); - if ( geometry !== null ) { + return this; - // buffer + } - const vertices = []; - const edges = new Set(); + bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - // helper variables + const curve = new CubicBezierCurve( + this.currentPoint.clone(), + new Vector2( aCP1x, aCP1y ), + new Vector2( aCP2x, aCP2y ), + new Vector2( aX, aY ) + ); - const start = new Vector3(); - const end = new Vector3(); + this.curves.push( curve ); - if ( geometry.index !== null ) { + this.currentPoint.set( aX, aY ); - // indexed BufferGeometry + return this; - const position = geometry.attributes.position; - const indices = geometry.index; - let groups = geometry.groups; + } - if ( groups.length === 0 ) { + splineThru( pts /*Array of Vector*/ ) { - groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; + const npts = [ this.currentPoint.clone() ].concat( pts ); - } + const curve = new SplineCurve( npts ); + this.curves.push( curve ); - // create a data structure that contains all edges without duplicates + this.currentPoint.copy( pts[ pts.length - 1 ] ); - for ( let o = 0, ol = groups.length; o < ol; ++ o ) { + return this; - const group = groups[ o ]; + } - const groupStart = group.start; - const groupCount = group.count; + arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { + const x0 = this.currentPoint.x; + const y0 = this.currentPoint.y; - for ( let j = 0; j < 3; j ++ ) { + this.absarc( aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); - const index1 = indices.getX( i + j ); - const index2 = indices.getX( i + ( j + 1 ) % 3 ); + return this; - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); + } - if ( isUniqueEdge( start, end, edges ) === true ) { + absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - } + return this; - } + } - } + ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - } + const x0 = this.currentPoint.x; + const y0 = this.currentPoint.y; - } else { + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - // non-indexed BufferGeometry + return this; - const position = geometry.attributes.position; + } - for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { + absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - for ( let j = 0; j < 3; j ++ ) { + const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - // three edges per triangle, an edge is represented as (index1, index2) - // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) + if ( this.curves.length > 0 ) { - const index1 = 3 * i + j; - const index2 = 3 * i + ( ( j + 1 ) % 3 ); + // if a previous curve is present, attempt to join + const firstPoint = curve.getPoint( 0 ); - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); + if ( ! firstPoint.equals( this.currentPoint ) ) { - if ( isUniqueEdge( start, end, edges ) === true ) { + this.lineTo( firstPoint.x, firstPoint.y ); - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); + } - } + } - } + this.curves.push( curve ); - } + const lastPoint = curve.getPoint( 1 ); + this.currentPoint.copy( lastPoint ); - } + return this; - // build geometry + } - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + copy( source ) { - } + super.copy( source ); + + this.currentPoint.copy( source.currentPoint ); + + return this; } - } + toJSON() { - function isUniqueEdge( start, end, edges ) { + const data = super.toJSON(); - const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; - const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge + data.currentPoint = this.currentPoint.toArray(); - if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { + return data; - return false; + } - } else { + fromJSON( json ) { - edges.add( hash1 ); - edges.add( hash2 ); - return true; + super.fromJSON( json ); + + this.currentPoint.fromArray( json.currentPoint ); + + return this; } } - var Geometries = /*#__PURE__*/Object.freeze({ - __proto__: null, - BoxGeometry: BoxGeometry, - CapsuleGeometry: CapsuleGeometry, - CircleGeometry: CircleGeometry, - ConeGeometry: ConeGeometry, - CylinderGeometry: CylinderGeometry, - DodecahedronGeometry: DodecahedronGeometry, - EdgesGeometry: EdgesGeometry, - ExtrudeGeometry: ExtrudeGeometry, - IcosahedronGeometry: IcosahedronGeometry, - LatheGeometry: LatheGeometry, - OctahedronGeometry: OctahedronGeometry, - PlaneGeometry: PlaneGeometry, - PolyhedronGeometry: PolyhedronGeometry, - RingGeometry: RingGeometry, - ShapeGeometry: ShapeGeometry, - SphereGeometry: SphereGeometry, - TetrahedronGeometry: TetrahedronGeometry, - TorusGeometry: TorusGeometry, - TorusKnotGeometry: TorusKnotGeometry, - TubeGeometry: TubeGeometry, - WireframeGeometry: WireframeGeometry - }); - - class ShadowMaterial extends Material { + class LatheGeometry extends BufferGeometry { - constructor( parameters ) { + constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { super(); - this.isShadowMaterial = true; + this.type = 'LatheGeometry'; - this.type = 'ShadowMaterial'; + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; - this.color = new Color( 0x000000 ); - this.transparent = true; + segments = Math.floor( segments ); - this.fog = true; + // clamp phiLength so it's in range of [ 0, 2PI ] - this.setValues( parameters ); + phiLength = clamp( phiLength, 0, Math.PI * 2 ); - } + // buffers - copy( source ) { + const indices = []; + const vertices = []; + const uvs = []; + const initNormals = []; + const normals = []; - super.copy( source ); + // helper variables - this.color.copy( source.color ); + const inverseSegments = 1.0 / segments; + const vertex = new Vector3(); + const uv = new Vector2(); + const normal = new Vector3(); + const curNormal = new Vector3(); + const prevNormal = new Vector3(); + let dx = 0; + let dy = 0; - this.fog = source.fog; + // pre-compute normals for initial "meridian" - return this; + for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { - } + switch ( j ) { - } + case 0: // special handling for 1st vertex on path - class RawShaderMaterial extends ShaderMaterial { + dx = points[ j + 1 ].x - points[ j ].x; + dy = points[ j + 1 ].y - points[ j ].y; - constructor( parameters ) { + normal.x = dy * 1.0; + normal.y = - dx; + normal.z = dy * 0.0; - super( parameters ); + prevNormal.copy( normal ); - this.isRawShaderMaterial = true; + normal.normalize(); - this.type = 'RawShaderMaterial'; + initNormals.push( normal.x, normal.y, normal.z ); - } + break; - } + case ( points.length - 1 ): // special handling for last Vertex on path - class MeshStandardMaterial extends Material { + initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z ); - constructor( parameters ) { + break; - super(); + default: // default handling for all vertices in between - this.isMeshStandardMaterial = true; + dx = points[ j + 1 ].x - points[ j ].x; + dy = points[ j + 1 ].y - points[ j ].y; - this.defines = { 'STANDARD': '' }; + normal.x = dy * 1.0; + normal.y = - dx; + normal.z = dy * 0.0; - this.type = 'MeshStandardMaterial'; + curNormal.copy( normal ); - this.color = new Color( 0xffffff ); // diffuse - this.roughness = 1.0; - this.metalness = 0.0; + normal.x += prevNormal.x; + normal.y += prevNormal.y; + normal.z += prevNormal.z; - this.map = null; + normal.normalize(); - this.lightMap = null; - this.lightMapIntensity = 1.0; + initNormals.push( normal.x, normal.y, normal.z ); - this.aoMap = null; - this.aoMapIntensity = 1.0; + prevNormal.copy( curNormal ); - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; + } - this.bumpMap = null; - this.bumpScale = 1; + } - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + // generate vertices, uvs and normals - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + for ( let i = 0; i <= segments; i ++ ) { - this.roughnessMap = null; + const phi = phiStart + i * inverseSegments * phiLength; - this.metalnessMap = null; + const sin = Math.sin( phi ); + const cos = Math.cos( phi ); - this.alphaMap = null; + for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { - this.envMap = null; - this.envMapIntensity = 1.0; + // vertex - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + vertex.x = points[ j ].x * sin; + vertex.y = points[ j ].y; + vertex.z = points[ j ].x * cos; - this.flatShading = false; + vertices.push( vertex.x, vertex.y, vertex.z ); - this.fog = true; + // uv - this.setValues( parameters ); + uv.x = i / segments; + uv.y = j / ( points.length - 1 ); - } + uvs.push( uv.x, uv.y ); - copy( source ) { + // normal - super.copy( source ); + const x = initNormals[ 3 * j + 0 ] * sin; + const y = initNormals[ 3 * j + 1 ]; + const z = initNormals[ 3 * j + 0 ] * cos; - this.defines = { 'STANDARD': '' }; + normals.push( x, y, z ); - this.color.copy( source.color ); - this.roughness = source.roughness; - this.metalness = source.metalness; + } - this.map = source.map; + } - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + // indices - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + for ( let i = 0; i < segments; i ++ ) { - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + for ( let j = 0; j < ( points.length - 1 ); j ++ ) { - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + const base = j + i * points.length; - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + const a = base; + const b = base + points.length; + const c = base + points.length + 1; + const d = base + 1; - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + // faces - this.roughnessMap = source.roughnessMap; + indices.push( a, b, d ); + indices.push( c, d, b ); - this.metalnessMap = source.metalnessMap; + } - this.alphaMap = source.alphaMap; + } - this.envMap = source.envMap; - this.envMapIntensity = source.envMapIntensity; + // build geometry - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.flatShading = source.flatShading; + } - this.fog = source.fog; + static fromJSON( data ) { - return this; + return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); } } - class MeshPhysicalMaterial extends MeshStandardMaterial { - - constructor( parameters ) { + class CapsuleGeometry extends LatheGeometry { - super(); + constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) { - this.isMeshPhysicalMaterial = true; + const path = new Path(); + path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 ); + path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 ); - this.defines = { + super( path.getPoints( capSegments ), radialSegments ); - 'STANDARD': '', - 'PHYSICAL': '' + this.type = 'CapsuleGeometry'; + this.parameters = { + radius: radius, + height: length, + capSegments: capSegments, + radialSegments: radialSegments, }; - this.type = 'MeshPhysicalMaterial'; + } - this.clearcoatMap = null; - this.clearcoatRoughness = 0.0; - this.clearcoatRoughnessMap = null; - this.clearcoatNormalScale = new Vector2( 1, 1 ); - this.clearcoatNormalMap = null; + static fromJSON( data ) { - this.ior = 1.5; + return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments ); - Object.defineProperty( this, 'reflectivity', { - get: function () { + } - return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); + } - }, - set: function ( reflectivity ) { + class CircleGeometry extends BufferGeometry { - this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); + constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) { - } - } ); + super(); - this.iridescenceMap = null; - this.iridescenceIOR = 1.3; - this.iridescenceThicknessRange = [ 100, 400 ]; - this.iridescenceThicknessMap = null; + this.type = 'CircleGeometry'; - this.sheenColor = new Color( 0x000000 ); - this.sheenColorMap = null; - this.sheenRoughness = 1.0; - this.sheenRoughnessMap = null; + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.transmissionMap = null; + segments = Math.max( 3, segments ); - this.thickness = 0; - this.thicknessMap = null; - this.attenuationDistance = Infinity; - this.attenuationColor = new Color( 1, 1, 1 ); + // buffers - this.specularIntensity = 1.0; - this.specularIntensityMap = null; - this.specularColor = new Color( 1, 1, 1 ); - this.specularColorMap = null; + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - this._sheen = 0.0; - this._clearcoat = 0; - this._iridescence = 0; - this._transmission = 0; + // helper variables - this.setValues( parameters ); + const vertex = new Vector3(); + const uv = new Vector2(); - } + // center point - get sheen() { + vertices.push( 0, 0, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( 0.5, 0.5 ); - return this._sheen; + for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { - } + const segment = thetaStart + s / segments * thetaLength; - set sheen( value ) { + // vertex - if ( this._sheen > 0 !== value > 0 ) { + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - this.version ++; + vertices.push( vertex.x, vertex.y, vertex.z ); - } + // normal - this._sheen = value; + normals.push( 0, 0, 1 ); - } + // uvs - get clearcoat() { + uv.x = ( vertices[ i ] / radius + 1 ) / 2; + uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - return this._clearcoat; + uvs.push( uv.x, uv.y ); - } + } - set clearcoat( value ) { + // indices - if ( this._clearcoat > 0 !== value > 0 ) { + for ( let i = 1; i <= segments; i ++ ) { - this.version ++; + indices.push( i, i + 1, 0 ); } - this._clearcoat = value; + // build geometry + + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); } - get iridescence() { + static fromJSON( data ) { - return this._iridescence; + return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); } - set iridescence( value ) { + } - if ( this._iridescence > 0 !== value > 0 ) { + class CylinderGeometry extends BufferGeometry { - this.version ++; + constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - } + super(); - this._iridescence = value; + this.type = 'CylinderGeometry'; - } + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - get transmission() { + const scope = this; - return this._transmission; + radialSegments = Math.floor( radialSegments ); + heightSegments = Math.floor( heightSegments ); - } + // buffers - set transmission( value ) { + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - if ( this._transmission > 0 !== value > 0 ) { + // helper variables - this.version ++; + let index = 0; + const indexArray = []; + const halfHeight = height / 2; + let groupStart = 0; - } + // generate geometry - this._transmission = value; + generateTorso(); - } + if ( openEnded === false ) { - copy( source ) { + if ( radiusTop > 0 ) generateCap( true ); + if ( radiusBottom > 0 ) generateCap( false ); - super.copy( source ); + } - this.defines = { + // build geometry - 'STANDARD': '', - 'PHYSICAL': '' + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - }; + function generateTorso() { - this.clearcoat = source.clearcoat; - this.clearcoatMap = source.clearcoatMap; - this.clearcoatRoughness = source.clearcoatRoughness; - this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; - this.clearcoatNormalMap = source.clearcoatNormalMap; - this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); + const normal = new Vector3(); + const vertex = new Vector3(); - this.ior = source.ior; + let groupCount = 0; - this.iridescence = source.iridescence; - this.iridescenceMap = source.iridescenceMap; - this.iridescenceIOR = source.iridescenceIOR; - this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ]; - this.iridescenceThicknessMap = source.iridescenceThicknessMap; + // this will be used to calculate the normal + const slope = ( radiusBottom - radiusTop ) / height; - this.sheen = source.sheen; - this.sheenColor.copy( source.sheenColor ); - this.sheenColorMap = source.sheenColorMap; - this.sheenRoughness = source.sheenRoughness; - this.sheenRoughnessMap = source.sheenRoughnessMap; + // generate vertices, normals and uvs - this.transmission = source.transmission; - this.transmissionMap = source.transmissionMap; + for ( let y = 0; y <= heightSegments; y ++ ) { - this.thickness = source.thickness; - this.thicknessMap = source.thicknessMap; - this.attenuationDistance = source.attenuationDistance; - this.attenuationColor.copy( source.attenuationColor ); + const indexRow = []; - this.specularIntensity = source.specularIntensity; - this.specularIntensityMap = source.specularIntensityMap; - this.specularColor.copy( source.specularColor ); - this.specularColorMap = source.specularColorMap; + const v = y / heightSegments; - return this; + // calculate the radius of the current row - } + const radius = v * ( radiusBottom - radiusTop ) + radiusTop; - } + for ( let x = 0; x <= radialSegments; x ++ ) { - class MeshPhongMaterial extends Material { + const u = x / radialSegments; - constructor( parameters ) { + const theta = u * thetaLength + thetaStart; - super(); + const sinTheta = Math.sin( theta ); + const cosTheta = Math.cos( theta ); - this.isMeshPhongMaterial = true; + // vertex - this.type = 'MeshPhongMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.specular = new Color( 0x111111 ); - this.shininess = 30; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; + vertex.x = radius * sinTheta; + vertex.y = - v * height + halfHeight; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); - this.bumpMap = null; - this.bumpScale = 1; + // normal - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + normal.set( sinTheta, slope, cosTheta ).normalize(); + normals.push( normal.x, normal.y, normal.z ); - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + // uv - this.specularMap = null; + uvs.push( u, 1 - v ); - this.alphaMap = null; + // save index of vertex in respective row - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + indexRow.push( index ++ ); - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + } - this.flatShading = false; + // now save vertices of the row in our index array - this.fog = true; + indexArray.push( indexRow ); - this.setValues( parameters ); + } - } + // generate indices - copy( source ) { + for ( let x = 0; x < radialSegments; x ++ ) { - super.copy( source ); + for ( let y = 0; y < heightSegments; y ++ ) { - this.color.copy( source.color ); - this.specular.copy( source.specular ); - this.shininess = source.shininess; + // we use the index array to access the correct indices - this.map = source.map; + const a = indexArray[ y ][ x ]; + const b = indexArray[ y + 1 ][ x ]; + const c = indexArray[ y + 1 ][ x + 1 ]; + const d = indexArray[ y ][ x + 1 ]; - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + // faces - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + indices.push( a, b, d ); + indices.push( b, c, d ); - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + // update group counter - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + groupCount += 6; - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + } - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + } - this.specularMap = source.specularMap; + // add a group to the geometry. this will ensure multi material support - this.alphaMap = source.alphaMap; + scope.addGroup( groupStart, groupCount, 0 ); - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; + // calculate new start value for groups - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + groupStart += groupCount; - this.flatShading = source.flatShading; + } - this.fog = source.fog; + function generateCap( top ) { - return this; + // save the index of the first center vertex + const centerIndexStart = index; - } + const uv = new Vector2(); + const vertex = new Vector3(); - } + let groupCount = 0; - class MeshToonMaterial extends Material { + const radius = ( top === true ) ? radiusTop : radiusBottom; + const sign = ( top === true ) ? 1 : - 1; - constructor( parameters ) { + // first we generate the center vertex data of the cap. + // because the geometry needs one set of uvs per face, + // we must generate a center vertex per face/segment - super(); + for ( let x = 1; x <= radialSegments; x ++ ) { - this.isMeshToonMaterial = true; + // vertex - this.defines = { 'TOON': '' }; + vertices.push( 0, halfHeight * sign, 0 ); - this.type = 'MeshToonMaterial'; + // normal - this.color = new Color( 0xffffff ); + normals.push( 0, sign, 0 ); - this.map = null; - this.gradientMap = null; + // uv - this.lightMap = null; - this.lightMapIntensity = 1.0; + uvs.push( 0.5, 0.5 ); - this.aoMap = null; - this.aoMapIntensity = 1.0; + // increase index - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; + index ++; - this.bumpMap = null; - this.bumpScale = 1; + } - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + // save the index of the last center vertex + const centerIndexEnd = index; - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + // now we generate the surrounding vertices, normals and uvs - this.alphaMap = null; + for ( let x = 0; x <= radialSegments; x ++ ) { - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + const u = x / radialSegments; + const theta = u * thetaLength + thetaStart; - this.fog = true; + const cosTheta = Math.cos( theta ); + const sinTheta = Math.sin( theta ); - this.setValues( parameters ); + // vertex - } + vertex.x = radius * sinTheta; + vertex.y = halfHeight * sign; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); - copy( source ) { + // normal - super.copy( source ); + normals.push( 0, sign, 0 ); - this.color.copy( source.color ); + // uv - this.map = source.map; - this.gradientMap = source.gradientMap; + uv.x = ( cosTheta * 0.5 ) + 0.5; + uv.y = ( sinTheta * 0.5 * sign ) + 0.5; + uvs.push( uv.x, uv.y ); - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + // increase index - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + index ++; - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + } - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + // generate indices - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + for ( let x = 0; x < radialSegments; x ++ ) { - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + const c = centerIndexStart + x; + const i = centerIndexEnd + x; - this.alphaMap = source.alphaMap; + if ( top === true ) { - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + // face top - this.fog = source.fog; + indices.push( i, i + 1, c ); - return this; + } else { - } + // face bottom - } + indices.push( i + 1, i, c ); - class MeshNormalMaterial extends Material { + } - constructor( parameters ) { + groupCount += 3; - super(); + } - this.isMeshNormalMaterial = true; + // add a group to the geometry. this will ensure multi material support - this.type = 'MeshNormalMaterial'; + scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); - this.bumpMap = null; - this.bumpScale = 1; + // calculate new start value for groups - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + groupStart += groupCount; - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + } - this.wireframe = false; - this.wireframeLinewidth = 1; + } - this.flatShading = false; + static fromJSON( data ) { - this.setValues( parameters ); + return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); } - copy( source ) { + } - super.copy( source ); + class ConeGeometry extends CylinderGeometry { - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + constructor( radius = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + this.type = 'ConeGeometry'; - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.flatShading = source.flatShading; + } - return this; + static fromJSON( data ) { + + return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); } } - class MeshLambertMaterial extends Material { + class PolyhedronGeometry extends BufferGeometry { - constructor( parameters ) { + constructor( vertices = [], indices = [], radius = 1, detail = 0 ) { super(); - this.isMeshLambertMaterial = true; + this.type = 'PolyhedronGeometry'; - this.type = 'MeshLambertMaterial'; + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - this.color = new Color( 0xffffff ); // diffuse + // default buffer data - this.map = null; + const vertexBuffer = []; + const uvBuffer = []; - this.lightMap = null; - this.lightMapIntensity = 1.0; + // the subdivision creates the vertex buffer data - this.aoMap = null; - this.aoMapIntensity = 1.0; + subdivide( detail ); - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; + // all vertices should lie on a conceptual sphere with a given radius - this.bumpMap = null; - this.bumpScale = 1; + applyRadius( radius ); - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + // finally, create the uv data - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + generateUVs(); - this.specularMap = null; + // build non-indexed geometry - this.alphaMap = null; + this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + if ( detail === 0 ) { - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + this.computeVertexNormals(); // flat normals - this.flatShading = false; + } else { - this.fog = true; + this.normalizeNormals(); // smooth normals - this.setValues( parameters ); + } - } + // helper functions - copy( source ) { + function subdivide( detail ) { - super.copy( source ); + const a = new Vector3(); + const b = new Vector3(); + const c = new Vector3(); - this.color.copy( source.color ); + // iterate over all faces and apply a subdivison with the given detail value - this.map = source.map; + for ( let i = 0; i < indices.length; i += 3 ) { - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + // get the vertices of the face - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + getVertexByIndex( indices[ i + 0 ], a ); + getVertexByIndex( indices[ i + 1 ], b ); + getVertexByIndex( indices[ i + 2 ], c ); - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + // perform subdivision - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + subdivideFace( a, b, c, detail ); - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + } - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + } - this.specularMap = source.specularMap; + function subdivideFace( a, b, c, detail ) { - this.alphaMap = source.alphaMap; + const cols = detail + 1; - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; + // we use this multidimensional array as a data structure for creating the subdivision - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + const v = []; - this.flatShading = source.flatShading; + // construct all of the vertices for this subdivision - this.fog = source.fog; + for ( let i = 0; i <= cols; i ++ ) { - return this; + v[ i ] = []; - } + const aj = a.clone().lerp( c, i / cols ); + const bj = b.clone().lerp( c, i / cols ); - } + const rows = cols - i; - class MeshMatcapMaterial extends Material { + for ( let j = 0; j <= rows; j ++ ) { - constructor( parameters ) { + if ( j === 0 && i === cols ) { - super(); + v[ i ][ j ] = aj; - this.isMeshMatcapMaterial = true; + } else { - this.defines = { 'MATCAP': '' }; + v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); - this.type = 'MeshMatcapMaterial'; + } - this.color = new Color( 0xffffff ); // diffuse + } - this.matcap = null; + } - this.map = null; + // construct all of the faces - this.bumpMap = null; - this.bumpScale = 1; + for ( let i = 0; i < cols; i ++ ) { - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + const k = Math.floor( j / 2 ); - this.alphaMap = null; + if ( j % 2 === 0 ) { - this.flatShading = false; + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); + pushVertex( v[ i ][ k ] ); - this.fog = true; + } else { - this.setValues( parameters ); + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); - } + } + } - copy( source ) { + } - super.copy( source ); + } - this.defines = { 'MATCAP': '' }; + function applyRadius( radius ) { - this.color.copy( source.color ); + const vertex = new Vector3(); - this.matcap = source.matcap; + // iterate over the entire buffer and apply the radius to each vertex - this.map = source.map; + for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + vertex.normalize().multiplyScalar( radius ); - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + vertexBuffer[ i + 0 ] = vertex.x; + vertexBuffer[ i + 1 ] = vertex.y; + vertexBuffer[ i + 2 ] = vertex.z; - this.alphaMap = source.alphaMap; + } - this.flatShading = source.flatShading; + } - this.fog = source.fog; + function generateUVs() { - return this; + const vertex = new Vector3(); - } + for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - } + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; - class LineDashedMaterial extends LineBasicMaterial { + const u = azimuth( vertex ) / 2 / Math.PI + 0.5; + const v = inclination( vertex ) / Math.PI + 0.5; + uvBuffer.push( u, 1 - v ); - constructor( parameters ) { + } - super(); + correctUVs(); - this.isLineDashedMaterial = true; + correctSeam(); - this.type = 'LineDashedMaterial'; + } - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; + function correctSeam() { - this.setValues( parameters ); + // handle case when face straddles the seam, see #3269 - } + for ( let i = 0; i < uvBuffer.length; i += 6 ) { - copy( source ) { + // uv data of a single face - super.copy( source ); + const x0 = uvBuffer[ i + 0 ]; + const x1 = uvBuffer[ i + 2 ]; + const x2 = uvBuffer[ i + 4 ]; - this.scale = source.scale; - this.dashSize = source.dashSize; - this.gapSize = source.gapSize; + const max = Math.max( x0, x1, x2 ); + const min = Math.min( x0, x1, x2 ); - return this; + // 0.9 is somewhat arbitrary - } + if ( max > 0.9 && min < 0.1 ) { - } + if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; + if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; + if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; - // same as Array.prototype.slice, but also works on typed arrays - function arraySlice( array, from, to ) { + } - if ( isTypedArray( array ) ) { + } - // in ios9 array.subarray(from, undefined) will return empty array - // but array.subarray(from) or array.subarray(from, len) is correct - return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); + } - } + function pushVertex( vertex ) { - return array.slice( from, to ); + vertexBuffer.push( vertex.x, vertex.y, vertex.z ); - } + } - // converts an array to a specific type - function convertArray( array, type, forceClone ) { + function getVertexByIndex( index, vertex ) { - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; + const stride = index * 3; - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + vertex.x = vertices[ stride + 0 ]; + vertex.y = vertices[ stride + 1 ]; + vertex.z = vertices[ stride + 2 ]; - return new type( array ); // create typed array + } - } + function correctUVs() { - return Array.prototype.slice.call( array ); // create Array + const a = new Vector3(); + const b = new Vector3(); + const c = new Vector3(); - } + const centroid = new Vector3(); - function isTypedArray( object ) { + const uvA = new Vector2(); + const uvB = new Vector2(); + const uvC = new Vector2(); - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); + for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { - } + a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); + b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); + c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); - // returns an array by which times and values can be sorted - function getKeyframeOrder( times ) { + uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); + uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); + uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); - function compareTime( i, j ) { + centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); - return times[ i ] - times[ j ]; + const azi = azimuth( centroid ); - } + correctUV( uvA, j + 0, a, azi ); + correctUV( uvB, j + 2, b, azi ); + correctUV( uvC, j + 4, c, azi ); - const n = times.length; - const result = new Array( n ); - for ( let i = 0; i !== n; ++ i ) result[ i ] = i; + } - result.sort( compareTime ); + } - return result; + function correctUV( uv, stride, vector, azimuth ) { - } + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - // uses the array previously returned by 'getKeyframeOrder' to sort data - function sortedArray( values, stride, order ) { + uvBuffer[ stride ] = uv.x - 1; - const nValues = values.length; - const result = new values.constructor( nValues ); + } - for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { - const srcOffset = order[ i ] * stride; + uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; - for ( let j = 0; j !== stride; ++ j ) { + } - result[ dstOffset ++ ] = values[ srcOffset + j ]; + } + + // Angle around the Y axis, counter-clockwise when looking from above. + + function azimuth( vector ) { + + return Math.atan2( vector.z, - vector.x ); } - } - return result; + // Angle above the XZ plane. - } + function inclination( vector ) { - // function for parsing AOS keyframe formats - function flattenJSON( jsonKeys, times, values, valuePropertyName ) { + return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - let i = 1, key = jsonKeys[ 0 ]; + } - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + } - key = jsonKeys[ i ++ ]; + static fromJSON( data ) { + + return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details ); } - if ( key === undefined ) return; // no data + } - let value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data + class DodecahedronGeometry extends PolyhedronGeometry { - if ( Array.isArray( value ) ) { + constructor( radius = 1, detail = 0 ) { - do { + const t = ( 1 + Math.sqrt( 5 ) ) / 2; + const r = 1 / t; - value = key[ valuePropertyName ]; + const vertices = [ - if ( value !== undefined ) { + // (±1, ±1, ±1) + - 1, - 1, - 1, - 1, - 1, 1, + - 1, 1, - 1, - 1, 1, 1, + 1, - 1, - 1, 1, - 1, 1, + 1, 1, - 1, 1, 1, 1, - times.push( key.time ); - values.push.apply( values, value ); // push all elements + // (0, ±1/φ, ±φ) + 0, - r, - t, 0, - r, t, + 0, r, - t, 0, r, t, - } + // (±1/φ, ±φ, 0) + - r, - t, 0, - r, t, 0, + r, - t, 0, r, t, 0, - key = jsonKeys[ i ++ ]; + // (±φ, 0, ±1/φ) + - t, 0, - r, t, 0, - r, + - t, 0, r, t, 0, r + ]; - } while ( key !== undefined ); + const indices = [ + 3, 11, 7, 3, 7, 15, 3, 15, 13, + 7, 19, 17, 7, 17, 6, 7, 6, 15, + 17, 4, 8, 17, 8, 10, 17, 10, 6, + 8, 0, 16, 8, 16, 2, 8, 2, 10, + 0, 12, 1, 0, 1, 18, 0, 18, 16, + 6, 10, 2, 6, 2, 13, 6, 13, 15, + 2, 16, 18, 2, 18, 3, 2, 3, 13, + 18, 1, 9, 18, 9, 11, 18, 11, 3, + 4, 14, 12, 4, 12, 0, 4, 0, 8, + 11, 9, 5, 11, 5, 19, 11, 19, 7, + 19, 5, 14, 19, 14, 4, 19, 4, 17, + 1, 12, 14, 1, 14, 5, 1, 5, 9 + ]; - } else if ( value.toArray !== undefined ) { + super( vertices, indices, radius, detail ); - // ...assume THREE.Math-ish + this.type = 'DodecahedronGeometry'; - do { + this.parameters = { + radius: radius, + detail: detail + }; - value = key[ valuePropertyName ]; + } - if ( value !== undefined ) { + static fromJSON( data ) { - times.push( key.time ); - value.toArray( values, values.length ); + return new DodecahedronGeometry( data.radius, data.detail ); - } + } - key = jsonKeys[ i ++ ]; + } - } while ( key !== undefined ); + const _v0 = /*@__PURE__*/ new Vector3(); + const _v1$1 = /*@__PURE__*/ new Vector3(); + const _normal = /*@__PURE__*/ new Vector3(); + const _triangle = /*@__PURE__*/ new Triangle(); - } else { + class EdgesGeometry extends BufferGeometry { - // otherwise push as-is + constructor( geometry = null, thresholdAngle = 1 ) { - do { + super(); - value = key[ valuePropertyName ]; + this.type = 'EdgesGeometry'; - if ( value !== undefined ) { + this.parameters = { + geometry: geometry, + thresholdAngle: thresholdAngle + }; - times.push( key.time ); - values.push( value ); + if ( geometry !== null ) { - } + const precisionPoints = 4; + const precision = Math.pow( 10, precisionPoints ); + const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); - key = jsonKeys[ i ++ ]; + const indexAttr = geometry.getIndex(); + const positionAttr = geometry.getAttribute( 'position' ); + const indexCount = indexAttr ? indexAttr.count : positionAttr.count; - } while ( key !== undefined ); + const indexArr = [ 0, 0, 0 ]; + const vertKeys = [ 'a', 'b', 'c' ]; + const hashes = new Array( 3 ); - } + const edgeData = {}; + const vertices = []; + for ( let i = 0; i < indexCount; i += 3 ) { - } + if ( indexAttr ) { - function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { + indexArr[ 0 ] = indexAttr.getX( i ); + indexArr[ 1 ] = indexAttr.getX( i + 1 ); + indexArr[ 2 ] = indexAttr.getX( i + 2 ); - const clip = sourceClip.clone(); + } else { - clip.name = name; + indexArr[ 0 ] = i; + indexArr[ 1 ] = i + 1; + indexArr[ 2 ] = i + 2; - const tracks = []; + } - for ( let i = 0; i < clip.tracks.length; ++ i ) { + const { a, b, c } = _triangle; + a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); + b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); + c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); + _triangle.getNormal( _normal ); - const track = clip.tracks[ i ]; - const valueSize = track.getValueSize(); + // create hashes for the edge from the vertices + hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; + hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; + hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; - const times = []; - const values = []; + // skip degenerate triangles + if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { - for ( let j = 0; j < track.times.length; ++ j ) { + continue; - const frame = track.times[ j ] * fps; + } - if ( frame < startFrame || frame >= endFrame ) continue; + // iterate over every edge + for ( let j = 0; j < 3; j ++ ) { - times.push( track.times[ j ] ); + // get the first and next vertex making up the edge + const jNext = ( j + 1 ) % 3; + const vecHash0 = hashes[ j ]; + const vecHash1 = hashes[ jNext ]; + const v0 = _triangle[ vertKeys[ j ] ]; + const v1 = _triangle[ vertKeys[ jNext ] ]; - for ( let k = 0; k < valueSize; ++ k ) { + const hash = `${ vecHash0 }_${ vecHash1 }`; + const reverseHash = `${ vecHash1 }_${ vecHash0 }`; - values.push( track.values[ j * valueSize + k ] ); + if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { - } + // if we found a sibling edge add it into the vertex array if + // it meets the angle threshold and delete the edge from the map. + if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { - } + vertices.push( v0.x, v0.y, v0.z ); + vertices.push( v1.x, v1.y, v1.z ); - if ( times.length === 0 ) continue; + } - track.times = convertArray( times, track.times.constructor ); - track.values = convertArray( values, track.values.constructor ); + edgeData[ reverseHash ] = null; - tracks.push( track ); + } else if ( ! ( hash in edgeData ) ) { - } + // if we've already got an edge here then skip adding a new one + edgeData[ hash ] = { - clip.tracks = tracks; + index0: indexArr[ j ], + index1: indexArr[ jNext ], + normal: _normal.clone(), - // find minimum .times value across all tracks in the trimmed clip + }; - let minStartTime = Infinity; + } - for ( let i = 0; i < clip.tracks.length; ++ i ) { + } - if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { + } - minStartTime = clip.tracks[ i ].times[ 0 ]; + // iterate over all remaining, unmatched edges and add them to the vertex array + for ( const key in edgeData ) { - } + if ( edgeData[ key ] ) { - } + const { index0, index1 } = edgeData[ key ]; + _v0.fromBufferAttribute( positionAttr, index0 ); + _v1$1.fromBufferAttribute( positionAttr, index1 ); - // shift all tracks such that clip begins at t=0 + vertices.push( _v0.x, _v0.y, _v0.z ); + vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); - for ( let i = 0; i < clip.tracks.length; ++ i ) { + } - clip.tracks[ i ].shift( - 1 * minStartTime ); + } - } + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - clip.resetDuration(); + } - return clip; + } } - function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { + class Shape extends Path { - if ( fps <= 0 ) fps = 30; + constructor( points ) { - const numTracks = referenceClip.tracks.length; - const referenceTime = referenceFrame / fps; + super( points ); - // Make each track's values relative to the values at the reference frame - for ( let i = 0; i < numTracks; ++ i ) { + this.uuid = generateUUID(); - const referenceTrack = referenceClip.tracks[ i ]; - const referenceTrackType = referenceTrack.ValueTypeName; + this.type = 'Shape'; - // Skip this track if it's non-numeric - if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; + this.holes = []; - // Find the track in the target clip whose name and type matches the reference track - const targetTrack = targetClip.tracks.find( function ( track ) { + } - return track.name === referenceTrack.name - && track.ValueTypeName === referenceTrackType; + getPointsHoles( divisions ) { - } ); + const holesPts = []; - if ( targetTrack === undefined ) continue; + for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - let referenceOffset = 0; - const referenceValueSize = referenceTrack.getValueSize(); + holesPts[ i ] = this.holes[ i ].getPoints( divisions ); - if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { + } - referenceOffset = referenceValueSize / 3; + return holesPts; - } + } - let targetOffset = 0; - const targetValueSize = targetTrack.getValueSize(); + // get points of shape and holes (keypoints based on segments parameter) - if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { + extractPoints( divisions ) { - targetOffset = targetValueSize / 3; + return { - } + shape: this.getPoints( divisions ), + holes: this.getPointsHoles( divisions ) - const lastIndex = referenceTrack.times.length - 1; - let referenceValue; + }; - // Find the value to subtract out of the track - if ( referenceTime <= referenceTrack.times[ 0 ] ) { + } - // Reference frame is earlier than the first keyframe, so just use the first keyframe - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - referenceValue = arraySlice( referenceTrack.values, startIndex, endIndex ); + copy( source ) { - } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { + super.copy( source ); - // Reference frame is after the last keyframe, so just use the last keyframe - const startIndex = lastIndex * referenceValueSize + referenceOffset; - const endIndex = startIndex + referenceValueSize - referenceOffset; - referenceValue = arraySlice( referenceTrack.values, startIndex, endIndex ); + this.holes = []; - } else { + for ( let i = 0, l = source.holes.length; i < l; i ++ ) { - // Interpolate to the reference value - const interpolant = referenceTrack.createInterpolant(); - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - interpolant.evaluate( referenceTime ); - referenceValue = arraySlice( interpolant.resultBuffer, startIndex, endIndex ); + const hole = source.holes[ i ]; + + this.holes.push( hole.clone() ); } - // Conjugate the quaternion - if ( referenceTrackType === 'quaternion' ) { + return this; - const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); - referenceQuat.toArray( referenceValue ); + } - } + toJSON() { - // Subtract the reference value from all of the track values + const data = super.toJSON(); - const numTimes = targetTrack.times.length; - for ( let j = 0; j < numTimes; ++ j ) { + data.uuid = this.uuid; + data.holes = []; - const valueStart = j * targetValueSize + targetOffset; + for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - if ( referenceTrackType === 'quaternion' ) { + const hole = this.holes[ i ]; + data.holes.push( hole.toJSON() ); - // Multiply the conjugate for quaternion track types - Quaternion.multiplyQuaternionsFlat( - targetTrack.values, - valueStart, - referenceValue, - 0, - targetTrack.values, - valueStart - ); + } - } else { + return data; - const valueEnd = targetValueSize - targetOffset * 2; + } - // Subtract each value for all other numeric track types - for ( let k = 0; k < valueEnd; ++ k ) { + fromJSON( json ) { - targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; + super.fromJSON( json ); - } + this.uuid = json.uuid; + this.holes = []; - } + for ( let i = 0, l = json.holes.length; i < l; i ++ ) { - } + const hole = json.holes[ i ]; + this.holes.push( new Path().fromJSON( hole ) ); - } + } - targetClip.blendMode = AdditiveAnimationBlendMode; + return this; - return targetClip; + } } - var AnimationUtils = /*#__PURE__*/Object.freeze({ - __proto__: null, - arraySlice: arraySlice, - convertArray: convertArray, - isTypedArray: isTypedArray, - getKeyframeOrder: getKeyframeOrder, - sortedArray: sortedArray, - flattenJSON: flattenJSON, - subclip: subclip, - makeClipAdditive: makeClipAdditive - }); - /** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * + * Port from https://github.com/mapbox/earcut (v2.2.2) */ - class Interpolant { + const Earcut = { - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + triangulate: function ( data, holeIndices, dim = 2 ) { - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; + const hasHoles = holeIndices && holeIndices.length; + const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length; + let outerNode = linkedList( data, 0, outerLen, dim, true ); + const triangles = []; - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; + if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles; - this.settings = null; - this.DefaultSettings_ = {}; + let minX, minY, maxX, maxY, x, y, invSize; - } + if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); - evaluate( t ) { + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + if ( data.length > 80 * dim ) { - const pp = this.parameterPositions; - let i1 = this._cachedIndex, - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; + minX = maxX = data[ 0 ]; + minY = maxY = data[ 1 ]; - validate_interval: { - - seek: { + for ( let i = dim; i < outerLen; i += dim ) { - let right; + x = data[ i ]; + y = data[ i + 1 ]; + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; - linear_scan: { + } - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { + // minX, minY and invSize are later used to transform coords into integers for z-order calculation + invSize = Math.max( maxX - minX, maxY - minY ); + invSize = invSize !== 0 ? 1 / invSize : 0; - for ( let giveUpAt = i1 + 2; ; ) { + } - if ( t1 === undefined ) { + earcutLinked( outerNode, triangles, dim, minX, minY, invSize ); - if ( t < t0 ) break forward_scan; + return triangles; - // after end + } - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); + }; - } + // create a circular doubly linked list from polygon points in the specified winding order + function linkedList( data, start, end, dim, clockwise ) { - if ( i1 === giveUpAt ) break; // this loop + let i, last; - t0 = t1; - t1 = pp[ ++ i1 ]; + if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { - if ( t < t1 ) { + for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - // we have arrived at the sought interval - break seek; + } else { - } + for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - } + } - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; + if ( last && equals( last, last.next ) ) { - } + removeNode( last ); + last = last.next; - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { + } - // looping? + return last; - const t1global = pp[ 1 ]; + } - if ( t < t1global ) { + // eliminate colinear or duplicate points + function filterPoints( start, end ) { - i1 = 2; // + 1, using the scan for the details - t0 = t1global; + if ( ! start ) return start; + if ( ! end ) end = start; - } + let p = start, + again; + do { - // linear reverse scan + again = false; - for ( let giveUpAt = i1 - 2; ; ) { + if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { - if ( t0 === undefined ) { + removeNode( p ); + p = end = p.prev; + if ( p === p.next ) break; + again = true; - // before start + } else { - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); + p = p.next; - } + } - if ( i1 === giveUpAt ) break; // this loop + } while ( again || p !== end ); - t1 = t0; - t0 = pp[ -- i1 - 1 ]; + return end; - if ( t >= t0 ) { + } - // we have arrived at the sought interval - break seek; + // main ear slicing loop which triangulates a polygon (given as a linked list) + function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { - } + if ( ! ear ) return; - } + // interlink polygon nodes in z-order + if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; + let stop = ear, + prev, next; - } + // iterate through ears, slicing them one by one + while ( ear.prev !== ear.next ) { - // the interval is valid + prev = ear.prev; + next = ear.next; - break validate_interval; + if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { - } // linear scan + // cut off the triangle + triangles.push( prev.i / dim ); + triangles.push( ear.i / dim ); + triangles.push( next.i / dim ); - // binary search + removeNode( ear ); - while ( i1 < right ) { + // skipping the next vertex leads to less sliver triangles + ear = next.next; + stop = next.next; - const mid = ( i1 + right ) >>> 1; + continue; - if ( t < pp[ mid ] ) { + } - right = mid; + ear = next; - } else { + // if we looped through the whole remaining polygon and can't find any more ears + if ( ear === stop ) { - i1 = mid + 1; + // try filtering points and slicing again + if ( ! pass ) { - } + earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); - } + // if this didn't work, try curing all small self-intersections locally - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; + } else if ( pass === 1 ) { - // check boundary cases, again + ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); + earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); - if ( t0 === undefined ) { + // as a last resort, try splitting the remaining polygon into two - this._cachedIndex = 0; - return this.copySampleValue_( 0 ); + } else if ( pass === 2 ) { - } + splitEarcut( ear, triangles, dim, minX, minY, invSize ); - if ( t1 === undefined ) { + } - i1 = pp.length; - this._cachedIndex = i1; - return this.copySampleValue_( i1 - 1 ); + break; - } + } - } // seek + } - this._cachedIndex = i1; + } - this.intervalChanged_( i1, t0, t1 ); + // check whether a polygon node forms a valid ear with adjacent nodes + function isEar( ear ) { - } // validate_interval + const a = ear.prev, + b = ear, + c = ear.next; - return this.interpolate_( i1, t0, t, t1 ); + if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - } + // now make sure we don't have other points inside the potential ear + let p = ear.next.next; - getSettings_() { + while ( p !== ear.prev ) { - return this.settings || this.DefaultSettings_; + if ( pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && + area( p.prev, p, p.next ) >= 0 ) return false; + p = p.next; } - copySampleValue_( index ) { + return true; - // copies a sample value to the result buffer + } - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; + function isEarHashed( ear, minX, minY, invSize ) { - for ( let i = 0; i !== stride; ++ i ) { + const a = ear.prev, + b = ear, + c = ear.next; - result[ i ] = values[ offset + i ]; + if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - } + // triangle bbox; min & max are calculated like this for speed + const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ), + minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ), + maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ), + maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y ); - return result; + // z-order range for the current triangle bbox; + const minZ = zOrder( minTX, minTY, minX, minY, invSize ), + maxZ = zOrder( maxTX, maxTY, minX, minY, invSize ); - } + let p = ear.prevZ, + n = ear.nextZ; - // Template methods for derived classes: + // look for points inside the triangle in both directions + while ( p && p.z >= minZ && n && n.z <= maxZ ) { - interpolate_( /* i1, t0, t, t1 */ ) { + if ( p !== ear.prev && p !== ear.next && + pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && + area( p.prev, p, p.next ) >= 0 ) return false; + p = p.prevZ; - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer + if ( n !== ear.prev && n !== ear.next && + pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) && + area( n.prev, n, n.next ) >= 0 ) return false; + n = n.nextZ; } - intervalChanged_( /* i1, t0, t1 */ ) { + // look for remaining points in decreasing z-order + while ( p && p.z >= minZ ) { - // empty + if ( p !== ear.prev && p !== ear.next && + pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && + area( p.prev, p, p.next ) >= 0 ) return false; + p = p.prevZ; } - } - - /** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - */ + // look for remaining points in increasing z-order + while ( n && n.z <= maxZ ) { - class CubicInterpolant extends Interpolant { + if ( n !== ear.prev && n !== ear.next && + pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) && + area( n.prev, n, n.next ) >= 0 ) return false; + n = n.nextZ; - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + } - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + return true; - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; + } - this.DefaultSettings_ = { + // go through all polygon nodes and cure small local self-intersections + function cureLocalIntersections( start, triangles, dim ) { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding + let p = start; + do { - }; + const a = p.prev, + b = p.next.next; - } + if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { - intervalChanged_( i1, t0, t1 ) { + triangles.push( a.i / dim ); + triangles.push( p.i / dim ); + triangles.push( b.i / dim ); - const pp = this.parameterPositions; - let iPrev = i1 - 2, - iNext = i1 + 1, + // remove two nodes involved + removeNode( p ); + removeNode( p.next ); - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; + p = start = b; - if ( tPrev === undefined ) { + } - switch ( this.getSettings_().endingStart ) { + p = p.next; - case ZeroSlopeEnding: + } while ( p !== start ); - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; + return filterPoints( p ); - break; + } - case WrapAroundEnding: + // try splitting polygon into two and triangulate them independently + function splitEarcut( start, triangles, dim, minX, minY, invSize ) { - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + // look for a valid diagonal that divides the polygon into two + let a = start; + do { - break; + let b = a.next.next; + while ( b !== a.prev ) { - default: // ZeroCurvatureEnding + if ( a.i !== b.i && isValidDiagonal( a, b ) ) { - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; + // split the polygon in two by the diagonal + let c = splitPolygon( a, b ); - } + // filter colinear points around the cuts + a = filterPoints( a, a.next ); + c = filterPoints( c, c.next ); - } + // run earcut on each half + earcutLinked( a, triangles, dim, minX, minY, invSize ); + earcutLinked( c, triangles, dim, minX, minY, invSize ); + return; - if ( tNext === undefined ) { + } - switch ( this.getSettings_().endingEnd ) { + b = b.next; - case ZeroSlopeEnding: + } - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; + a = a.next; - break; + } while ( a !== start ); - case WrapAroundEnding: + } - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; + // link every hole into the outer loop, producing a single-ring polygon without holes + function eliminateHoles( data, holeIndices, outerNode, dim ) { - break; + const queue = []; + let i, len, start, end, list; - default: // ZeroCurvatureEnding + for ( i = 0, len = holeIndices.length; i < len; i ++ ) { - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; + start = holeIndices[ i ] * dim; + end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length; + list = linkedList( data, start, end, dim, false ); + if ( list === list.next ) list.steiner = true; + queue.push( getLeftmost( list ) ); - } + } - } + queue.sort( compareX ); - const halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; + // process holes from left to right + for ( i = 0; i < queue.length; i ++ ) { - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; + eliminateHole( queue[ i ], outerNode ); + outerNode = filterPoints( outerNode, outerNode.next ); } - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, + return outerNode; - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; + } - // evaluate polynomials + function compareX( a, b ) { - const sP = - wP * ppp + 2 * wP * pp - wP * p; - const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - const sN = wN * ppp - wN * pp; + return a.x - b.x; - // combine data linearly + } - for ( let i = 0; i !== stride; ++ i ) { + // find a bridge between vertices that connects hole with an outer ring and link it + function eliminateHole( hole, outerNode ) { - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; + outerNode = findHoleBridge( hole, outerNode ); + if ( outerNode ) { - } + const b = splitPolygon( outerNode, hole ); - return result; + // filter collinear points around the cuts + filterPoints( outerNode, outerNode.next ); + filterPoints( b, b.next ); } } - class LinearInterpolant extends Interpolant { + // David Eberly's algorithm for finding a bridge between hole and outer polygon + function findHoleBridge( hole, outerNode ) { - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + let p = outerNode; + const hx = hole.x; + const hy = hole.y; + let qx = - Infinity, m; - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + // find a segment intersected by a ray from the hole's leftmost point to the left; + // segment's endpoint with lesser x will be potential connection point + do { - } + if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { - interpolate_( i1, t0, t, t1 ) { + const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); + if ( x <= hx && x > qx ) { - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + qx = x; + if ( x === hx ) { - offset1 = i1 * stride, - offset0 = offset1 - stride, + if ( hy === p.y ) return p; + if ( hy === p.next.y ) return p.next; - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; + } - for ( let i = 0; i !== stride; ++ i ) { + m = p.x < p.next.x ? p : p.next; - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; + } } - return result; + p = p.next; - } + } while ( p !== outerNode ); - } + if ( ! m ) return null; - /** - * - * Interpolant that evaluates to the sample value at the position preceding - * the parameter. - */ + if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint - class DiscreteInterpolant extends Interpolant { + // look for points inside the triangle of hole point, segment intersection and endpoint; + // if there are no points found, we have a valid connection; + // otherwise choose the point of the minimum angle with the ray as connection point - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + const stop = m, + mx = m.x, + my = m.y; + let tanMin = Infinity, tan; - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + p = m; - } + do { - interpolate_( i1 /*, t0, t, t1 */ ) { + if ( hx >= p.x && p.x >= mx && hx !== p.x && + pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) { - return this.copySampleValue_( i1 - 1 ); + tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential - } + if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { - } + m = p; + tanMin = tan; - class KeyframeTrack { + } - constructor( name, times, values, interpolation ) { + } - if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); - if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); + p = p.next; - this.name = name; + } while ( p !== stop ); - this.times = convertArray( times, this.TimeBufferType ); - this.values = convertArray( values, this.ValueBufferType ); + return m; - this.setInterpolation( interpolation || this.DefaultInterpolation ); + } - } + // whether sector in vertex m contains sector in vertex p in the same coordinates + function sectorContainsSector( m, p ) { - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): + return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; - static toJSON( track ) { + } - const trackType = track.constructor; + // interlink polygon nodes in z-order + function indexCurve( start, minX, minY, invSize ) { - let json; + let p = start; + do { - // derived classes can define a static toJSON method - if ( trackType.toJSON !== this.toJSON ) { + if ( p.z === null ) p.z = zOrder( p.x, p.y, minX, minY, invSize ); + p.prevZ = p.prev; + p.nextZ = p.next; + p = p.next; - json = trackType.toJSON( track ); + } while ( p !== start ); - } else { + p.prevZ.nextZ = null; + p.prevZ = null; - // by default, we assume the data can be serialized as-is - json = { + sortLinked( p ); - 'name': track.name, - 'times': convertArray( track.times, Array ), - 'values': convertArray( track.values, Array ) + } - }; + // Simon Tatham's linked list merge sort algorithm + // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + function sortLinked( list ) { - const interpolation = track.getInterpolation(); + let i, p, q, e, tail, numMerges, pSize, qSize, + inSize = 1; - if ( interpolation !== track.DefaultInterpolation ) { + do { - json.interpolation = interpolation; + p = list; + list = null; + tail = null; + numMerges = 0; - } + while ( p ) { - } + numMerges ++; + q = p; + pSize = 0; + for ( i = 0; i < inSize; i ++ ) { - json.type = track.ValueTypeName; // mandatory + pSize ++; + q = q.nextZ; + if ( ! q ) break; - return json; + } - } + qSize = inSize; - InterpolantFactoryMethodDiscrete( result ) { + while ( pSize > 0 || ( qSize > 0 && q ) ) { - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); + if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { - } + e = p; + p = p.nextZ; + pSize --; - InterpolantFactoryMethodLinear( result ) { + } else { - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); + e = q; + q = q.nextZ; + qSize --; - } + } - InterpolantFactoryMethodSmooth( result ) { + if ( tail ) tail.nextZ = e; + else list = e; - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); + e.prevZ = tail; + tail = e; - } + } - setInterpolation( interpolation ) { + p = q; - let factoryMethod; + } - switch ( interpolation ) { + tail.nextZ = null; + inSize *= 2; - case InterpolateDiscrete: + } while ( numMerges > 1 ); - factoryMethod = this.InterpolantFactoryMethodDiscrete; + return list; - break; + } - case InterpolateLinear: + // z-order of a point given coords and inverse of the longer side of data bbox + function zOrder( x, y, minX, minY, invSize ) { - factoryMethod = this.InterpolantFactoryMethodLinear; + // coords are transformed into non-negative 15-bit integer range + x = 32767 * ( x - minX ) * invSize; + y = 32767 * ( y - minY ) * invSize; - break; + x = ( x | ( x << 8 ) ) & 0x00FF00FF; + x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; + x = ( x | ( x << 2 ) ) & 0x33333333; + x = ( x | ( x << 1 ) ) & 0x55555555; - case InterpolateSmooth: + y = ( y | ( y << 8 ) ) & 0x00FF00FF; + y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; + y = ( y | ( y << 2 ) ) & 0x33333333; + y = ( y | ( y << 1 ) ) & 0x55555555; - factoryMethod = this.InterpolantFactoryMethodSmooth; + return x | ( y << 1 ); - break; + } - } + // find the leftmost node of a polygon ring + function getLeftmost( start ) { - if ( factoryMethod === undefined ) { + let p = start, + leftmost = start; + do { - const message = 'unsupported interpolation for ' + - this.ValueTypeName + ' keyframe track named ' + this.name; + if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p; + p = p.next; - if ( this.createInterpolant === undefined ) { + } while ( p !== start ); - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { + return leftmost; - this.setInterpolation( this.DefaultInterpolation ); + } - } else { + // check if a point lies within a convex triangle + function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { - throw new Error( message ); // fatal, in this case + return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 && + ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 && + ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0; - } + } - } + // check if a diagonal between two polygon nodes is valid (lies in polygon interior) + function isValidDiagonal( a, b ) { - console.warn( 'THREE.KeyframeTrack:', message ); - return this; + return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // doesn't intersect other edges + ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible + ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors + equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case - } + } - this.createInterpolant = factoryMethod; + // signed area of a triangle + function area( p, q, r ) { - return this; + return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); - } + } - getInterpolation() { + // check if two points are equal + function equals( p1, p2 ) { - switch ( this.createInterpolant ) { + return p1.x === p2.x && p1.y === p2.y; - case this.InterpolantFactoryMethodDiscrete: + } - return InterpolateDiscrete; + // check if two segments intersect + function intersects( p1, q1, p2, q2 ) { - case this.InterpolantFactoryMethodLinear: + const o1 = sign( area( p1, q1, p2 ) ); + const o2 = sign( area( p1, q1, q2 ) ); + const o3 = sign( area( p2, q2, p1 ) ); + const o4 = sign( area( p2, q2, q1 ) ); - return InterpolateLinear; + if ( o1 !== o2 && o3 !== o4 ) return true; // general case - case this.InterpolantFactoryMethodSmooth: + if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 - return InterpolateSmooth; + return false; - } + } - } + // for collinear points p, q, r, check if point q lies on segment pr + function onSegment( p, q, r ) { - getValueSize() { + return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y ); - return this.values.length / this.times.length; + } - } + function sign( num ) { - // move all keyframes either forwards or backwards in time - shift( timeOffset ) { + return num > 0 ? 1 : num < 0 ? - 1 : 0; - if ( timeOffset !== 0.0 ) { + } - const times = this.times; + // check if a polygon diagonal intersects any polygon segments + function intersectsPolygon( a, b ) { - for ( let i = 0, n = times.length; i !== n; ++ i ) { + let p = a; + do { - times[ i ] += timeOffset; + if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && + intersects( p, p.next, a, b ) ) return true; + p = p.next; - } + } while ( p !== a ); - } + return false; - return this; + } - } + // check if a polygon diagonal is locally inside the polygon + function locallyInside( a, b ) { - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale( timeScale ) { + return area( a.prev, a, a.next ) < 0 ? + area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 : + area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0; - if ( timeScale !== 1.0 ) { + } - const times = this.times; + // check if the middle point of a polygon diagonal is inside the polygon + function middleInside( a, b ) { - for ( let i = 0, n = times.length; i !== n; ++ i ) { + let p = a, + inside = false; + const px = ( a.x + b.x ) / 2, + py = ( a.y + b.y ) / 2; + do { - times[ i ] *= timeScale; + if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y && + ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) + inside = ! inside; + p = p.next; - } + } while ( p !== a ); - } + return inside; - return this; + } - } + // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; + // if one belongs to the outer ring and another to a hole, it merges it into a single ring + function splitPolygon( a, b ) { - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim( startTime, endTime ) { + const a2 = new Node( a.i, a.x, a.y ), + b2 = new Node( b.i, b.x, b.y ), + an = a.next, + bp = b.prev; - const times = this.times, - nKeys = times.length; + a.next = b; + b.prev = a; - let from = 0, - to = nKeys - 1; + a2.next = an; + an.prev = a2; - while ( from !== nKeys && times[ from ] < startTime ) { + b2.next = a2; + a2.prev = b2; - ++ from; + bp.next = b2; + b2.prev = bp; - } + return b2; - while ( to !== - 1 && times[ to ] > endTime ) { + } - -- to; + // create a node and optionally link it with previous one (in a circular doubly linked list) + function insertNode( i, x, y, last ) { - } + const p = new Node( i, x, y ); - ++ to; // inclusive -> exclusive bound + if ( ! last ) { - if ( from !== 0 || to !== nKeys ) { + p.prev = p; + p.next = p; - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) { + } else { - to = Math.max( to, 1 ); - from = to - 1; + p.next = last.next; + p.prev = last; + last.next.prev = p; + last.next = p; - } + } - const stride = this.getValueSize(); - this.times = arraySlice( times, from, to ); - this.values = arraySlice( this.values, from * stride, to * stride ); + return p; - } + } - return this; + function removeNode( p ) { - } + p.next.prev = p.prev; + p.prev.next = p.next; - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate() { + if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; + if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; - let valid = true; + } - const valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { + function Node( i, x, y ) { - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; + // vertex index in coordinates array + this.i = i; - } + // vertex coordinates + this.x = x; + this.y = y; - const times = this.times, - values = this.values, + // previous and next vertex nodes in a polygon ring + this.prev = null; + this.next = null; - nKeys = times.length; + // z-order curve value + this.z = null; - if ( nKeys === 0 ) { + // previous and next nodes in z-order + this.prevZ = null; + this.nextZ = null; - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; + // indicates whether this is a steiner point + this.steiner = false; - } + } - let prevTime = null; + function signedArea( data, start, end, dim ) { - for ( let i = 0; i !== nKeys; i ++ ) { + let sum = 0; + for ( let i = start, j = end - dim; i < end; i += dim ) { - const currTime = times[ i ]; + sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); + j = i; - if ( typeof currTime === 'number' && isNaN( currTime ) ) { + } - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; + return sum; - } + } - if ( prevTime !== null && prevTime > currTime ) { + class ShapeUtils { - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; + // calculate area of the contour polygon - } + static area( contour ) { - prevTime = currTime; + const n = contour.length; + let a = 0.0; - } + for ( let p = n - 1, q = 0; q < n; p = q ++ ) { - if ( values !== undefined ) { + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - if ( isTypedArray( values ) ) { + } - for ( let i = 0, n = values.length; i !== n; ++ i ) { + return a * 0.5; - const value = values[ i ]; + } - if ( isNaN( value ) ) { + static isClockWise( pts ) { - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; + return ShapeUtils.area( pts ) < 0; - } + } - } + static triangulateShape( contour, holes ) { - } + const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] + const holeIndices = []; // array of hole indices + const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] - } + removeDupEndPts( contour ); + addContour( vertices, contour ); - return valid; + // - } + let holeIndex = contour.length; - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize() { + holes.forEach( removeDupEndPts ); - // times or values may be shared with other tracks, so overwriting is unsafe - const times = arraySlice( this.times ), - values = arraySlice( this.values ), - stride = this.getValueSize(), + for ( let i = 0; i < holes.length; i ++ ) { - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + holeIndices.push( holeIndex ); + holeIndex += holes[ i ].length; + addContour( vertices, holes[ i ] ); - lastIndex = times.length - 1; + } - let writeIndex = 1; + // - for ( let i = 1; i < lastIndex; ++ i ) { + const triangles = Earcut.triangulate( vertices, holeIndices ); - let keep = false; + // - const time = times[ i ]; - const timeNext = times[ i + 1 ]; + for ( let i = 0; i < triangles.length; i += 3 ) { - // remove adjacent keyframes scheduled at the same time + faces.push( triangles.slice( i, i + 3 ) ); - if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { + } - if ( ! smoothInterpolation ) { + return faces; - // remove unnecessary keyframes same as their neighbors + } - const offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; + } - for ( let j = 0; j !== stride; ++ j ) { + function removeDupEndPts( points ) { - const value = values[ offset + j ]; + const l = points.length; - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { + if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - keep = true; - break; + points.pop(); - } + } - } + } - } else { + function addContour( vertices, contour ) { - keep = true; + for ( let i = 0; i < contour.length; i ++ ) { - } + vertices.push( contour[ i ].x ); + vertices.push( contour[ i ].y ); - } + } - // in-place compaction + } - if ( keep ) { + /** + * Creates extruded geometry from a path shape. + * + * parameters = { + * + * curveSegments: , // number of points on the curves + * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too + * depth: , // Depth to extrude the shape + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into the original shape bevel goes + * bevelSize: , // how far from shape outline (including bevelOffset) is bevel + * bevelOffset: , // how far from shape outline does bevel start + * bevelSegments: , // number of bevel layers + * + * extrudePath: // curve to extrude shape along + * + * UVGenerator: // object that provides UV generator functions + * + * } + */ - if ( i !== writeIndex ) { + class ExtrudeGeometry extends BufferGeometry { - times[ writeIndex ] = times[ i ]; + constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) { - const readOffset = i * stride, - writeOffset = writeIndex * stride; + super(); - for ( let j = 0; j !== stride; ++ j ) { + this.type = 'ExtrudeGeometry'; - values[ writeOffset + j ] = values[ readOffset + j ]; + this.parameters = { + shapes: shapes, + options: options + }; - } + shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - } + const scope = this; - ++ writeIndex; + const verticesArray = []; + const uvArray = []; - } + for ( let i = 0, l = shapes.length; i < l; i ++ ) { + + const shape = shapes[ i ]; + addShape( shape ); } - // flush last keyframe (compaction looks ahead) + // build geometry - if ( lastIndex > 0 ) { + this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); - times[ writeIndex ] = times[ lastIndex ]; + this.computeVertexNormals(); - for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { + // functions - values[ writeOffset + j ] = values[ readOffset + j ]; + function addShape( shape ) { - } + const placeholder = []; - ++ writeIndex; + // options - } + const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + const steps = options.steps !== undefined ? options.steps : 1; + const depth = options.depth !== undefined ? options.depth : 1; - if ( writeIndex !== times.length ) { + let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; + let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; + let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; + let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; + let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - this.times = arraySlice( times, 0, writeIndex ); - this.values = arraySlice( values, 0, writeIndex * stride ); + const extrudePath = options.extrudePath; - } else { + const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; - this.times = times; - this.values = values; + // - } + let extrudePts, extrudeByPath = false; + let splineTube, binormal, normal, position2; - return this; + if ( extrudePath ) { - } + extrudePts = extrudePath.getSpacedPoints( steps ); - clone() { + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion - const times = arraySlice( this.times, 0 ); - const values = arraySlice( this.values, 0 ); + // SETUP TNB variables - const TypedKeyframeTrack = this.constructor; - const track = new TypedKeyframeTrack( this.name, times, values ); + // TODO1 - have a .isClosed in spline? - // Interpolant argument to constructor is not saved, so copy the factory method directly. - track.createInterpolant = this.createInterpolant; + splineTube = extrudePath.computeFrenetFrames( steps, false ); - return track; + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - } + binormal = new Vector3(); + normal = new Vector3(); + position2 = new Vector3(); - } + } - KeyframeTrack.prototype.TimeBufferType = Float32Array; - KeyframeTrack.prototype.ValueBufferType = Float32Array; - KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; + // Safeguards if bevels are not enabled - /** - * A Track of Boolean keyframe values. - */ - class BooleanKeyframeTrack extends KeyframeTrack {} + if ( ! bevelEnabled ) { - BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; - BooleanKeyframeTrack.prototype.ValueBufferType = Array; - BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; - BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; - BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; + bevelOffset = 0; - /** - * A Track of keyframe values that represent color. - */ - class ColorKeyframeTrack extends KeyframeTrack {} + } - ColorKeyframeTrack.prototype.ValueTypeName = 'color'; + // Variables initialization - /** - * A Track of numeric keyframe values. - */ - class NumberKeyframeTrack extends KeyframeTrack {} + const shapePoints = shape.extractPoints( curveSegments ); - NumberKeyframeTrack.prototype.ValueTypeName = 'number'; + let vertices = shapePoints.shape; + const holes = shapePoints.holes; - /** - * Spherical linear unit quaternion interpolant. - */ + const reverse = ! ShapeUtils.isClockWise( vertices ); - class QuaternionLinearInterpolant extends Interpolant { + if ( reverse ) { - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + vertices = vertices.reverse(); - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); + // Maybe we should also check if holes are in the opposite direction, just to be safe ... - } + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - interpolate_( i1, t0, t, t1 ) { + const ahole = holes[ h ]; - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + if ( ShapeUtils.isClockWise( ahole ) ) { - alpha = ( t - t0 ) / ( t1 - t0 ); + holes[ h ] = ahole.reverse(); - let offset = i1 * stride; + } - for ( let end = offset + stride; offset !== end; offset += 4 ) { + } - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); + } - } - return result; + const faces = ShapeUtils.triangulateShape( vertices, holes ); - } + /* Vertices */ - } + const contour = vertices; // vertices has all points but contour has only points of circumference - /** - * A Track of quaternion keyframe values. - */ - class QuaternionKeyframeTrack extends KeyframeTrack { + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - InterpolantFactoryMethodLinear( result ) { + const ahole = holes[ h ]; - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); + vertices = vertices.concat( ahole ); - } + } - } - QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; - // ValueBufferType is inherited - QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; - QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; + function scalePt2( pt, vec, size ) { - /** - * A Track that interpolates Strings - */ - class StringKeyframeTrack extends KeyframeTrack {} + if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); - StringKeyframeTrack.prototype.ValueTypeName = 'string'; - StringKeyframeTrack.prototype.ValueBufferType = Array; - StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; - StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; - StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; + return vec.clone().multiplyScalar( size ).add( pt ); - /** - * A Track of vectored keyframe values. - */ - class VectorKeyframeTrack extends KeyframeTrack {} + } - VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; + const vlen = vertices.length, flen = faces.length; - class AnimationClip { - constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) { + // Find directions for point movement - this.name = name; - this.tracks = tracks; - this.duration = duration; - this.blendMode = blendMode; - this.uuid = generateUUID(); + function getBevelVec( inPt, inPrev, inNext ) { - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { + // computes for inPt the corresponding point inPt' on a new contour + // shifted by 1 unit (length of normalized vector) to the left + // if we walk along contour clockwise, this new contour is outside the old one + // + // inPt' is the intersection of the two lines parallel to the two + // adjacent edges of inPt at a distance of 1 unit on the left side. - this.resetDuration(); + let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt - } + // good reading for geometry algorithms (here: line-line intersection) + // http://geomalgorithms.com/a05-_intersect-1.html - } + const v_prev_x = inPt.x - inPrev.x, + v_prev_y = inPt.y - inPrev.y; + const v_next_x = inNext.x - inPt.x, + v_next_y = inNext.y - inPt.y; + const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); - static parse( json ) { + // check for collinear edges + const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - const tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); + if ( Math.abs( collinear0 ) > Number.EPSILON ) { - for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { + // not collinear - tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); + // length of vectors for normalizing - } + const v_prev_len = Math.sqrt( v_prev_lensq ); + const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); - const clip = new this( json.name, json.duration, tracks, json.blendMode ); - clip.uuid = json.uuid; + // shift adjacent points by unit vectors to the left - return clip; + const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - } + const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - static toJSON( clip ) { + // scaling factor for v_prev to intersection point - const tracks = [], - clipTracks = clip.tracks; + const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - + ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / + ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - const json = { + // vector from inPt to intersection point - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks, - 'uuid': clip.uuid, - 'blendMode': clip.blendMode + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - }; + // Don't normalize!, otherwise sharp corners become ugly + // but prevent crazy spikes + const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); + if ( v_trans_lensq <= 2 ) { - for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { + return new Vector2( v_trans_x, v_trans_y ); - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + } else { - } + shrink_by = Math.sqrt( v_trans_lensq / 2 ); - return json; + } - } + } else { - static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { + // handle special case of collinear edges - const numMorphTargets = morphTargetSequence.length; - const tracks = []; + let direction_eq = false; // assumes: opposite - for ( let i = 0; i < numMorphTargets; i ++ ) { + if ( v_prev_x > Number.EPSILON ) { - let times = []; - let values = []; + if ( v_next_x > Number.EPSILON ) { - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); + direction_eq = true; - values.push( 0, 1, 0 ); + } - const order = getKeyframeOrder( times ); - times = sortedArray( times, 1, order ); - values = sortedArray( values, 1, order ); + } else { - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { + if ( v_prev_x < - Number.EPSILON ) { - times.push( numMorphTargets ); - values.push( values[ 0 ] ); + if ( v_next_x < - Number.EPSILON ) { - } + direction_eq = true; - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); + } - } + } else { - return new this( name, - 1, tracks ); + if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - } + direction_eq = true; - static findByName( objectOrClipArray, name ) { + } - let clipArray = objectOrClipArray; + } - if ( ! Array.isArray( objectOrClipArray ) ) { + } - const o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; + if ( direction_eq ) { - } + // console.log("Warning: lines are a straight sequence"); + v_trans_x = - v_prev_y; + v_trans_y = v_prev_x; + shrink_by = Math.sqrt( v_prev_lensq ); - for ( let i = 0; i < clipArray.length; i ++ ) { + } else { - if ( clipArray[ i ].name === name ) { + // console.log("Warning: lines are a straight spike"); + v_trans_x = v_prev_x; + v_trans_y = v_prev_y; + shrink_by = Math.sqrt( v_prev_lensq / 2 ); - return clipArray[ i ]; + } + + } + + return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); } - } - return null; + const contourMovements = []; - } + for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { + if ( j === il ) j = 0; + if ( k === il ) k = 0; - const animationToMorphTargets = {}; + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - const pattern = /^([\w-]*?)([\d]+)$/; + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { + } - const morphTarget = morphTargets[ i ]; - const parts = morphTarget.name.match( pattern ); + const holesMovements = []; + let oneHoleMovements, verticesMovements = contourMovements.concat(); - if ( parts && parts.length > 1 ) { + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - const name = parts[ 1 ]; + const ahole = holes[ h ]; - let animationMorphTargets = animationToMorphTargets[ name ]; + oneHoleMovements = []; - if ( ! animationMorphTargets ) { + for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - animationToMorphTargets[ name ] = animationMorphTargets = []; + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); } - animationMorphTargets.push( morphTarget ); + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); } - } - const clips = []; + // Loop bevelSegments, 1 for the front, 1 for the back - for ( const name in animationToMorphTargets ) { + for ( let b = 0; b < bevelSegments; b ++ ) { - clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); + //for ( b = bevelSegments; b > 0; b -- ) { - } + const t = b / bevelSegments; + const z = bevelThickness * Math.cos( t * Math.PI / 2 ); + const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - return clips; + // contract shape - } + for ( let i = 0, il = contour.length; i < il; i ++ ) { - // parse the animation.hierarchy format - static parseAnimation( animation, bones ) { + const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - if ( ! animation ) { + v( vert.x, vert.y, - z ); - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; + } - } + // expand holes - const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { + const ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - const times = []; - const values = []; + for ( let i = 0, il = ahole.length; i < il; i ++ ) { - flattenJSON( animationKeys, times, values, propertyName ); + const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { + v( vert.x, vert.y, - z ); - destTracks.push( new trackType( trackName, times, values ) ); + } } } - }; + const bs = bevelSize + bevelOffset; - const tracks = []; + // Back facing vertices - const clipName = animation.name || 'default'; - const fps = animation.fps || 30; - const blendMode = animation.blendMode; + for ( let i = 0; i < vlen; i ++ ) { - // automatic length determination in AnimationClip. - let duration = animation.length || - 1; + const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - const hierarchyTracks = animation.hierarchy || []; + if ( ! extrudeByPath ) { - for ( let h = 0; h < hierarchyTracks.length; h ++ ) { + v( vert.x, vert.y, 0 ); - const animationKeys = hierarchyTracks[ h ].keys; + } else { - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { + normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); - // figure out all morph targets used in this track - const morphTargetNames = {}; + position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - let k; + v( position2.x, position2.y, position2.z ); - for ( k = 0; k < animationKeys.length; k ++ ) { + } - if ( animationKeys[ k ].morphTargets ) { + } - for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + // Add stepped vertices... + // Including front facing vertices - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; + for ( let s = 1; s <= steps; s ++ ) { - } + for ( let i = 0; i < vlen; i ++ ) { - } + const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - } + if ( ! extrudeByPath ) { - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( const morphTargetName in morphTargetNames ) { + v( vert.x, vert.y, depth / steps * s ); - const times = []; - const values = []; + } else { - for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - const animationKey = animationKeys[ k ]; + normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); + position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - } + v( position2.x, position2.y, position2.z ); - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + } } - duration = morphTargetNames.length * fps; + } - } else { - // ...assume skeletal animation + // Add bevel segments planes - const boneName = '.bones[' + bones[ h ].name + ']'; + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( let b = bevelSegments - 1; b >= 0; b -- ) { - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); + const t = b / bevelSegments; + const z = bevelThickness * Math.cos( t * Math.PI / 2 ); + const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); + // contract shape - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); + for ( let i = 0, il = contour.length; i < il; i ++ ) { - } + const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, depth + z ); - } + } - if ( tracks.length === 0 ) { + // expand holes - return null; + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - } + const ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - const clip = new this( clipName, duration, tracks, blendMode ); + for ( let i = 0, il = ahole.length; i < il; i ++ ) { - return clip; + const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - } + if ( ! extrudeByPath ) { - resetDuration() { + v( vert.x, vert.y, depth + z ); - const tracks = this.tracks; - let duration = 0; + } else { - for ( let i = 0, n = tracks.length; i !== n; ++ i ) { + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - const track = this.tracks[ i ]; + } - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + } - } + } - this.duration = duration; + } - return this; + /* Faces */ - } + // Top and bottom faces - trim() { + buildLidFaces(); - for ( let i = 0; i < this.tracks.length; i ++ ) { + // Sides faces - this.tracks[ i ].trim( 0, this.duration ); + buildSideFaces(); - } - return this; + ///// Internal functions - } + function buildLidFaces() { - validate() { + const start = verticesArray.length / 3; - let valid = true; + if ( bevelEnabled ) { - for ( let i = 0; i < this.tracks.length; i ++ ) { + let layer = 0; // steps + 1 + let offset = vlen * layer; - valid = valid && this.tracks[ i ].validate(); + // Bottom faces - } + for ( let i = 0; i < flen; i ++ ) { - return valid; + const face = faces[ i ]; + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - } + } - optimize() { + layer = steps + bevelSegments * 2; + offset = vlen * layer; - for ( let i = 0; i < this.tracks.length; i ++ ) { + // Top faces - this.tracks[ i ].optimize(); + for ( let i = 0; i < flen; i ++ ) { - } + const face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); - return this; + } - } + } else { - clone() { + // Bottom faces - const tracks = []; + for ( let i = 0; i < flen; i ++ ) { - for ( let i = 0; i < this.tracks.length; i ++ ) { + const face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - tracks.push( this.tracks[ i ].clone() ); + } - } + // Top faces - return new this.constructor( this.name, this.duration, tracks, this.blendMode ); + for ( let i = 0; i < flen; i ++ ) { - } + const face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - toJSON() { + } - return this.constructor.toJSON( this ); + } - } + scope.addGroup( start, verticesArray.length / 3 - start, 0 ); - } + } - function getTrackTypeForValueTypeName( typeName ) { + // Create faces for the z-sides of the shape - switch ( typeName.toLowerCase() ) { + function buildSideFaces() { - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': + const start = verticesArray.length / 3; + let layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; - return NumberKeyframeTrack; + for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': + const ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); - return VectorKeyframeTrack; + //, true + layeroffset += ahole.length; - case 'color': + } - return ColorKeyframeTrack; - case 'quaternion': + scope.addGroup( start, verticesArray.length / 3 - start, 1 ); - return QuaternionKeyframeTrack; - case 'bool': - case 'boolean': + } - return BooleanKeyframeTrack; + function sidewalls( contour, layeroffset ) { - case 'string': + let i = contour.length; - return StringKeyframeTrack; + while ( -- i >= 0 ) { - } + const j = i; + let k = i - 1; + if ( k < 0 ) k = contour.length - 1; - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); + //console.log('b', i,j, i-1, k,vertices.length); - } + for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { - function parseKeyframeTrack( json ) { + const slen1 = vlen * s; + const slen2 = vlen * ( s + 1 ); - if ( json.type === undefined ) { + const a = layeroffset + j + slen1, + b = layeroffset + k + slen1, + c = layeroffset + k + slen2, + d = layeroffset + j + slen2; - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); + f4( a, b, c, d ); - } + } - const trackType = getTrackTypeForValueTypeName( json.type ); + } - if ( json.times === undefined ) { + } - const times = [], values = []; + function v( x, y, z ) { - flattenJSON( json.keys, times, values, 'value' ); + placeholder.push( x ); + placeholder.push( y ); + placeholder.push( z ); - json.times = times; - json.values = values; + } - } - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { + function f3( a, b, c ) { - return trackType.parse( json ); + addVertex( a ); + addVertex( b ); + addVertex( c ); - } else { + const nextIndex = verticesArray.length / 3; + const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); - } + } - } + function f4( a, b, c, d ) { - const Cache = { + addVertex( a ); + addVertex( b ); + addVertex( d ); - enabled: false, + addVertex( b ); + addVertex( c ); + addVertex( d ); - files: {}, - add: function ( key, file ) { + const nextIndex = verticesArray.length / 3; + const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - if ( this.enabled === false ) return; + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 3 ] ); - // console.log( 'THREE.Cache', 'Adding key:', key ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); + addUV( uvs[ 3 ] ); - this.files[ key ] = file; + } - }, + function addVertex( index ) { - get: function ( key ) { + verticesArray.push( placeholder[ index * 3 + 0 ] ); + verticesArray.push( placeholder[ index * 3 + 1 ] ); + verticesArray.push( placeholder[ index * 3 + 2 ] ); - if ( this.enabled === false ) return; + } - // console.log( 'THREE.Cache', 'Checking key:', key ); - return this.files[ key ]; + function addUV( vector2 ) { - }, + uvArray.push( vector2.x ); + uvArray.push( vector2.y ); - remove: function ( key ) { + } - delete this.files[ key ]; + } - }, + } - clear: function () { + toJSON() { - this.files = {}; + const data = super.toJSON(); + + const shapes = this.parameters.shapes; + const options = this.parameters.options; + + return toJSON$1( shapes, options, data ); } - }; + static fromJSON( data, shapes ) { - class LoadingManager { + const geometryShapes = []; - constructor( onLoad, onProgress, onError ) { + for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - const scope = this; + const shape = shapes[ data.shapes[ j ] ]; - let isLoading = false; - let itemsLoaded = 0; - let itemsTotal = 0; - let urlModifier = undefined; - const handlers = []; + geometryShapes.push( shape ); - // Refer to #5689 for the reason why we don't set .onStart - // in the constructor + } - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; + const extrudePath = data.options.extrudePath; - this.itemStart = function ( url ) { + if ( extrudePath !== undefined ) { - itemsTotal ++; + data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); - if ( isLoading === false ) { + } - if ( scope.onStart !== undefined ) { + return new ExtrudeGeometry( geometryShapes, data.options ); - scope.onStart( url, itemsLoaded, itemsTotal ); + } - } + } - } + const WorldUVGenerator = { - isLoading = true; + generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - }; + const a_x = vertices[ indexA * 3 ]; + const a_y = vertices[ indexA * 3 + 1 ]; + const b_x = vertices[ indexB * 3 ]; + const b_y = vertices[ indexB * 3 + 1 ]; + const c_x = vertices[ indexC * 3 ]; + const c_y = vertices[ indexC * 3 + 1 ]; - this.itemEnd = function ( url ) { + return [ + new Vector2( a_x, a_y ), + new Vector2( b_x, b_y ), + new Vector2( c_x, c_y ) + ]; - itemsLoaded ++; + }, - if ( scope.onProgress !== undefined ) { + generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { - scope.onProgress( url, itemsLoaded, itemsTotal ); + const a_x = vertices[ indexA * 3 ]; + const a_y = vertices[ indexA * 3 + 1 ]; + const a_z = vertices[ indexA * 3 + 2 ]; + const b_x = vertices[ indexB * 3 ]; + const b_y = vertices[ indexB * 3 + 1 ]; + const b_z = vertices[ indexB * 3 + 2 ]; + const c_x = vertices[ indexC * 3 ]; + const c_y = vertices[ indexC * 3 + 1 ]; + const c_z = vertices[ indexC * 3 + 2 ]; + const d_x = vertices[ indexD * 3 ]; + const d_y = vertices[ indexD * 3 + 1 ]; + const d_z = vertices[ indexD * 3 + 2 ]; - } + if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { - if ( itemsLoaded === itemsTotal ) { + return [ + new Vector2( a_x, 1 - a_z ), + new Vector2( b_x, 1 - b_z ), + new Vector2( c_x, 1 - c_z ), + new Vector2( d_x, 1 - d_z ) + ]; - isLoading = false; + } else { - if ( scope.onLoad !== undefined ) { + return [ + new Vector2( a_y, 1 - a_z ), + new Vector2( b_y, 1 - b_z ), + new Vector2( c_y, 1 - c_z ), + new Vector2( d_y, 1 - d_z ) + ]; - scope.onLoad(); + } - } + } - } + }; - }; + function toJSON$1( shapes, options, data ) { - this.itemError = function ( url ) { + data.shapes = []; - if ( scope.onError !== undefined ) { + if ( Array.isArray( shapes ) ) { - scope.onError( url ); + for ( let i = 0, l = shapes.length; i < l; i ++ ) { - } + const shape = shapes[ i ]; - }; + data.shapes.push( shape.uuid ); - this.resolveURL = function ( url ) { + } - if ( urlModifier ) { + } else { - return urlModifier( url ); + data.shapes.push( shapes.uuid ); - } + } - return url; + data.options = Object.assign( {}, options ); - }; + if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); - this.setURLModifier = function ( transform ) { + return data; - urlModifier = transform; + } - return this; + class IcosahedronGeometry extends PolyhedronGeometry { - }; + constructor( radius = 1, detail = 0 ) { - this.addHandler = function ( regex, loader ) { + const t = ( 1 + Math.sqrt( 5 ) ) / 2; - handlers.push( regex, loader ); + const vertices = [ + - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, + 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, + t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 + ]; - return this; + const indices = [ + 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, + 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, + 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, + 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 + ]; - }; + super( vertices, indices, radius, detail ); - this.removeHandler = function ( regex ) { + this.type = 'IcosahedronGeometry'; - const index = handlers.indexOf( regex ); + this.parameters = { + radius: radius, + detail: detail + }; - if ( index !== - 1 ) { + } - handlers.splice( index, 2 ); + static fromJSON( data ) { - } + return new IcosahedronGeometry( data.radius, data.detail ); - return this; + } - }; + } - this.getHandler = function ( file ) { + class OctahedronGeometry extends PolyhedronGeometry { - for ( let i = 0, l = handlers.length; i < l; i += 2 ) { + constructor( radius = 1, detail = 0 ) { - const regex = handlers[ i ]; - const loader = handlers[ i + 1 ]; + const vertices = [ + 1, 0, 0, - 1, 0, 0, 0, 1, 0, + 0, - 1, 0, 0, 0, 1, 0, 0, - 1 + ]; - if ( regex.global ) regex.lastIndex = 0; // see #17920 + const indices = [ + 0, 2, 4, 0, 4, 3, 0, 3, 5, + 0, 5, 2, 1, 2, 5, 1, 5, 3, + 1, 3, 4, 1, 4, 2 + ]; - if ( regex.test( file ) ) { + super( vertices, indices, radius, detail ); - return loader; + this.type = 'OctahedronGeometry'; - } + this.parameters = { + radius: radius, + detail: detail + }; - } + } - return null; + static fromJSON( data ) { - }; + return new OctahedronGeometry( data.radius, data.detail ); } } - const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); + class RingGeometry extends BufferGeometry { - class Loader { + constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 8, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { - constructor( manager ) { + super(); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.type = 'RingGeometry'; - this.crossOrigin = 'anonymous'; - this.withCredentials = false; - this.path = ''; - this.resourcePath = ''; - this.requestHeader = {}; + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - } + thetaSegments = Math.max( 3, thetaSegments ); + phiSegments = Math.max( 1, phiSegments ); - load( /* url, onLoad, onProgress, onError */ ) {} + // buffers - loadAsync( url, onProgress ) { + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - const scope = this; + // some helper variables - return new Promise( function ( resolve, reject ) { + let radius = innerRadius; + const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + const vertex = new Vector3(); + const uv = new Vector2(); - scope.load( url, resolve, onProgress, reject ); + // generate vertices, normals and uvs - } ); + for ( let j = 0; j <= phiSegments; j ++ ) { - } + for ( let i = 0; i <= thetaSegments; i ++ ) { - parse( /* data */ ) {} + // values are generate from the inside of the ring to the outside - setCrossOrigin( crossOrigin ) { + const segment = thetaStart + i / thetaSegments * thetaLength; - this.crossOrigin = crossOrigin; - return this; + // vertex - } + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - setWithCredentials( value ) { + vertices.push( vertex.x, vertex.y, vertex.z ); - this.withCredentials = value; - return this; + // normal - } + normals.push( 0, 0, 1 ); - setPath( path ) { + // uv - this.path = path; - return this; + uv.x = ( vertex.x / outerRadius + 1 ) / 2; + uv.y = ( vertex.y / outerRadius + 1 ) / 2; - } + uvs.push( uv.x, uv.y ); - setResourcePath( resourcePath ) { + } - this.resourcePath = resourcePath; - return this; + // increase the radius for next row of vertices - } + radius += radiusStep; - setRequestHeader( requestHeader ) { + } - this.requestHeader = requestHeader; - return this; + // indices - } + for ( let j = 0; j < phiSegments; j ++ ) { - } + const thetaSegmentLevel = j * ( thetaSegments + 1 ); - const loading = {}; + for ( let i = 0; i < thetaSegments; i ++ ) { - class HttpError extends Error { + const segment = i + thetaSegmentLevel; - constructor( message, response ) { + const a = segment; + const b = segment + thetaSegments + 1; + const c = segment + thetaSegments + 2; + const d = segment + 1; - super( message ); - this.response = response; + // faces - } + indices.push( a, b, d ); + indices.push( b, c, d ); - } + } - class FileLoader extends Loader { + } - constructor( manager ) { + // build geometry - super( manager ); + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); } - load( url, onLoad, onProgress, onError ) { + static fromJSON( data ) { - if ( url === undefined ) url = ''; + return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); - if ( this.path !== undefined ) url = this.path + url; + } - url = this.manager.resolveURL( url ); + } - const cached = Cache.get( url ); + class ShapeGeometry extends BufferGeometry { - if ( cached !== undefined ) { + constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) { - this.manager.itemStart( url ); + super(); - setTimeout( () => { + this.type = 'ShapeGeometry'; - if ( onLoad ) onLoad( cached ); + this.parameters = { + shapes: shapes, + curveSegments: curveSegments + }; - this.manager.itemEnd( url ); + // buffers - }, 0 ); + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - return cached; + // helper variables - } + let groupStart = 0; + let groupCount = 0; - // Check if request is duplicate + // allow single and array values for "shapes" parameter - if ( loading[ url ] !== undefined ) { + if ( Array.isArray( shapes ) === false ) { - loading[ url ].push( { + addShape( shapes ); - onLoad: onLoad, - onProgress: onProgress, - onError: onError + } else { - } ); + for ( let i = 0; i < shapes.length; i ++ ) { - return; + addShape( shapes[ i ] ); - } + this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support - // Initialise array for duplicate requests - loading[ url ] = []; + groupStart += groupCount; + groupCount = 0; - loading[ url ].push( { - onLoad: onLoad, - onProgress: onProgress, - onError: onError, - } ); + } - // create request - const req = new Request( url, { - headers: new Headers( this.requestHeader ), - credentials: this.withCredentials ? 'include' : 'same-origin', - // An abort controller could be added within a future PR - } ); + } - // record states ( avoid data race ) - const mimeType = this.mimeType; - const responseType = this.responseType; + // build geometry - // start the fetch - fetch( req ) - .then( response => { + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - if ( response.status === 200 || response.status === 0 ) { - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. + // helper functions - if ( response.status === 0 ) { + function addShape( shape ) { - console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); + const indexOffset = vertices.length / 3; + const points = shape.extractPoints( curveSegments ); - } + let shapeVertices = points.shape; + const shapeHoles = points.holes; - // Workaround: Checking if response.body === undefined for Alipay browser #23548 + // check direction of vertices - if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { + if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { - return response; + shapeVertices = shapeVertices.reverse(); - } + } - const callbacks = loading[ url ]; - const reader = response.body.getReader(); - const contentLength = response.headers.get( 'Content-Length' ); - const total = contentLength ? parseInt( contentLength ) : 0; - const lengthComputable = total !== 0; - let loaded = 0; + for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - // periodically read data into the new stream tracking while download progress - const stream = new ReadableStream( { - start( controller ) { + const shapeHole = shapeHoles[ i ]; - readData(); + if ( ShapeUtils.isClockWise( shapeHole ) === true ) { - function readData() { + shapeHoles[ i ] = shapeHole.reverse(); - reader.read().then( ( { done, value } ) => { + } - if ( done ) { + } - controller.close(); + const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); - } else { + // join vertices of inner and outer paths to a single array - loaded += value.byteLength; + for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + const shapeHole = shapeHoles[ i ]; + shapeVertices = shapeVertices.concat( shapeHole ); - const callback = callbacks[ i ]; - if ( callback.onProgress ) callback.onProgress( event ); + } - } + // vertices, normals, uvs - controller.enqueue( value ); - readData(); + for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { - } + const vertex = shapeVertices[ i ]; - } ); + vertices.push( vertex.x, vertex.y, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( vertex.x, vertex.y ); // world uvs - } + } - } + // incides - } ); + for ( let i = 0, l = faces.length; i < l; i ++ ) { - return new Response( stream ); + const face = faces[ i ]; - } else { + const a = face[ 0 ] + indexOffset; + const b = face[ 1 ] + indexOffset; + const c = face[ 2 ] + indexOffset; - throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); + indices.push( a, b, c ); + groupCount += 3; - } + } - } ) - .then( response => { + } - switch ( responseType ) { + } - case 'arraybuffer': + toJSON() { - return response.arrayBuffer(); + const data = super.toJSON(); - case 'blob': + const shapes = this.parameters.shapes; - return response.blob(); + return toJSON( shapes, data ); - case 'document': + } - return response.text() - .then( text => { + static fromJSON( data, shapes ) { - const parser = new DOMParser(); - return parser.parseFromString( text, mimeType ); + const geometryShapes = []; - } ); + for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - case 'json': + const shape = shapes[ data.shapes[ j ] ]; - return response.json(); + geometryShapes.push( shape ); - default: + } - if ( mimeType === undefined ) { + return new ShapeGeometry( geometryShapes, data.curveSegments ); - return response.text(); + } - } else { + } - // sniff encoding - const re = /charset="?([^;"\s]*)"?/i; - const exec = re.exec( mimeType ); - const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; - const decoder = new TextDecoder( label ); - return response.arrayBuffer().then( ab => decoder.decode( ab ) ); + function toJSON( shapes, data ) { - } + data.shapes = []; - } + if ( Array.isArray( shapes ) ) { - } ) - .then( data => { + for ( let i = 0, l = shapes.length; i < l; i ++ ) { - // Add to cache only on HTTP success, so that we do not cache - // error response bodies as proper responses to requests. - Cache.add( url, data ); + const shape = shapes[ i ]; - const callbacks = loading[ url ]; - delete loading[ url ]; + data.shapes.push( shape.uuid ); - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + } - const callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( data ); + } else { - } + data.shapes.push( shapes.uuid ); - } ) - .catch( err => { + } - // Abort errors and other errors are handled the same + return data; - const callbacks = loading[ url ]; + } - if ( callbacks === undefined ) { + class SphereGeometry extends BufferGeometry { - // When onLoad was called and url was deleted in `loading` - this.manager.itemError( url ); - throw err; + constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { - } + super(); - delete loading[ url ]; + this.type = 'SphereGeometry'; - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - const callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( err ); + widthSegments = Math.max( 3, Math.floor( widthSegments ) ); + heightSegments = Math.max( 2, Math.floor( heightSegments ) ); - } + const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); - this.manager.itemError( url ); + let index = 0; + const grid = []; - } ) - .finally( () => { + const vertex = new Vector3(); + const normal = new Vector3(); - this.manager.itemEnd( url ); + // buffers - } ); + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - this.manager.itemStart( url ); + // generate vertices, normals and uvs - } + for ( let iy = 0; iy <= heightSegments; iy ++ ) { - setResponseType( value ) { + const verticesRow = []; - this.responseType = value; - return this; + const v = iy / heightSegments; - } + // special case for the poles - setMimeType( value ) { + let uOffset = 0; - this.mimeType = value; - return this; + if ( iy == 0 && thetaStart == 0 ) { - } + uOffset = 0.5 / widthSegments; - } + } else if ( iy == heightSegments && thetaEnd == Math.PI ) { - class AnimationLoader extends Loader { + uOffset = - 0.5 / widthSegments; - constructor( manager ) { + } - super( manager ); + for ( let ix = 0; ix <= widthSegments; ix ++ ) { - } + const u = ix / widthSegments; - load( url, onLoad, onProgress, onError ) { + // vertex - const scope = this; + vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + vertices.push( vertex.x, vertex.y, vertex.z ); - try { + // normal - onLoad( scope.parse( JSON.parse( text ) ) ); + normal.copy( vertex ).normalize(); + normals.push( normal.x, normal.y, normal.z ); - } catch ( e ) { + // uv - if ( onError ) { + uvs.push( u + uOffset, 1 - v ); - onError( e ); + verticesRow.push( index ++ ); - } else { + } - console.error( e ); + grid.push( verticesRow ); - } + } - scope.manager.itemError( url ); + // indices - } + for ( let iy = 0; iy < heightSegments; iy ++ ) { - }, onProgress, onError ); + for ( let ix = 0; ix < widthSegments; ix ++ ) { - } + const a = grid[ iy ][ ix + 1 ]; + const b = grid[ iy ][ ix ]; + const c = grid[ iy + 1 ][ ix ]; + const d = grid[ iy + 1 ][ ix + 1 ]; - parse( json ) { + if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); + if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); - const animations = []; + } - for ( let i = 0; i < json.length; i ++ ) { + } - const clip = AnimationClip.parse( json[ i ] ); + // build geometry - animations.push( clip ); + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - } + } - return animations; + static fromJSON( data ) { + + return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); } } - /** - * Abstract Base class to block based textures loader (dds, pvr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - - class CompressedTextureLoader extends Loader { + class TetrahedronGeometry extends PolyhedronGeometry { - constructor( manager ) { + constructor( radius = 1, detail = 0 ) { - super( manager ); + const vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; - } + const indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; - load( url, onLoad, onProgress, onError ) { + super( vertices, indices, radius, detail ); - const scope = this; + this.type = 'TetrahedronGeometry'; - const images = []; + this.parameters = { + radius: radius, + detail: detail + }; - const texture = new CompressedTexture(); + } - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); + static fromJSON( data ) { - let loaded = 0; + return new TetrahedronGeometry( data.radius, data.detail ); - function loadTexture( i ) { + } - loader.load( url[ i ], function ( buffer ) { + } - const texDatas = scope.parse( buffer, true ); + class TorusGeometry extends BufferGeometry { - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; + constructor( radius = 1, tube = 0.4, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2 ) { - loaded += 1; + super(); - if ( loaded === 6 ) { + this.type = 'TorusGeometry'; - if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; - texture.image = images; - texture.format = texDatas.format; - texture.needsUpdate = true; + radialSegments = Math.floor( radialSegments ); + tubularSegments = Math.floor( tubularSegments ); - if ( onLoad ) onLoad( texture ); + // buffers - } + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - }, onProgress, onError ); + // helper variables - } + const center = new Vector3(); + const vertex = new Vector3(); + const normal = new Vector3(); - if ( Array.isArray( url ) ) { + // generate vertices, normals and uvs - for ( let i = 0, il = url.length; i < il; ++ i ) { + for ( let j = 0; j <= radialSegments; j ++ ) { - loadTexture( i ); + for ( let i = 0; i <= tubularSegments; i ++ ) { - } + const u = i / tubularSegments * arc; + const v = j / radialSegments * Math.PI * 2; - } else { + // vertex - // compressed cubemap texture stored in a single DDS file + vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); + vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); + vertex.z = tube * Math.sin( v ); - loader.load( url, function ( buffer ) { + vertices.push( vertex.x, vertex.y, vertex.z ); - const texDatas = scope.parse( buffer, true ); + // normal - if ( texDatas.isCubemap ) { + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); + normal.subVectors( vertex, center ).normalize(); - const faces = texDatas.mipmaps.length / texDatas.mipmapCount; + normals.push( normal.x, normal.y, normal.z ); - for ( let f = 0; f < faces; f ++ ) { + // uv - images[ f ] = { mipmaps: [] }; + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); - for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { + } - images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); - images[ f ].format = texDatas.format; - images[ f ].width = texDatas.width; - images[ f ].height = texDatas.height; + } - } + // generate indices - } + for ( let j = 1; j <= radialSegments; j ++ ) { - texture.image = images; + for ( let i = 1; i <= tubularSegments; i ++ ) { - } else { + // indices - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; + const a = ( tubularSegments + 1 ) * j + i - 1; + const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; + const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; + const d = ( tubularSegments + 1 ) * j + i; - } + // faces - if ( texDatas.mipmapCount === 1 ) { + indices.push( a, b, d ); + indices.push( b, c, d ); - texture.minFilter = LinearFilter; + } - } + } - texture.format = texDatas.format; - texture.needsUpdate = true; + // build geometry - if ( onLoad ) onLoad( texture ); + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - }, onProgress, onError ); + } - } + static fromJSON( data ) { - return texture; + return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); } } - class ImageLoader extends Loader { - - constructor( manager ) { - - super( manager ); + class TorusKnotGeometry extends BufferGeometry { - } + constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { - load( url, onLoad, onProgress, onError ) { + super(); - if ( this.path !== undefined ) url = this.path + url; + this.type = 'TorusKnotGeometry'; - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); + this.parameters = { + radius: radius, + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q + }; - scope.manager.itemEnd( url ); + tubularSegments = Math.floor( tubularSegments ); + radialSegments = Math.floor( radialSegments ); - }, 0 ); + // buffers - return cached; + const indices = []; + const vertices = []; + const normals = []; + const uvs = []; - } + // helper variables - const image = createElementNS( 'img' ); + const vertex = new Vector3(); + const normal = new Vector3(); - function onImageLoad() { + const P1 = new Vector3(); + const P2 = new Vector3(); - removeEventListeners(); + const B = new Vector3(); + const T = new Vector3(); + const N = new Vector3(); - Cache.add( url, this ); + // generate vertices, normals and uvs - if ( onLoad ) onLoad( this ); + for ( let i = 0; i <= tubularSegments; ++ i ) { - scope.manager.itemEnd( url ); + // the radian "u" is used to calculate the position on the torus curve of the current tubular segment - } + const u = i / tubularSegments * p * Math.PI * 2; - function onImageError( event ) { + // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. + // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions - removeEventListeners(); + calculatePositionOnCurve( u, p, q, radius, P1 ); + calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); - if ( onError ) onError( event ); + // calculate orthonormal basis - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + T.subVectors( P2, P1 ); + N.addVectors( P2, P1 ); + B.crossVectors( T, N ); + N.crossVectors( B, T ); - } + // normalize B, N. T can be ignored, we don't use it - function removeEventListeners() { + B.normalize(); + N.normalize(); - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); + for ( let j = 0; j <= radialSegments; ++ j ) { - } + // now calculate the vertices. they are nothing more than an extrusion of the torus curve. + // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. - image.addEventListener( 'load', onImageLoad, false ); - image.addEventListener( 'error', onImageError, false ); + const v = j / radialSegments * Math.PI * 2; + const cx = - tube * Math.cos( v ); + const cy = tube * Math.sin( v ); - if ( url.slice( 0, 5 ) !== 'data:' ) { + // now calculate the final vertex position. + // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + vertex.x = P1.x + ( cx * N.x + cy * B.x ); + vertex.y = P1.y + ( cx * N.y + cy * B.y ); + vertex.z = P1.z + ( cx * N.z + cy * B.z ); - } + vertices.push( vertex.x, vertex.y, vertex.z ); - scope.manager.itemStart( url ); + // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) - image.src = url; + normal.subVectors( vertex, P1 ).normalize(); - return image; + normals.push( normal.x, normal.y, normal.z ); - } + // uv - } + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); - class CubeTextureLoader extends Loader { + } - constructor( manager ) { + } - super( manager ); + // generate indices - } + for ( let j = 1; j <= tubularSegments; j ++ ) { - load( urls, onLoad, onProgress, onError ) { + for ( let i = 1; i <= radialSegments; i ++ ) { - const texture = new CubeTexture(); + // indices - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); + const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); + const b = ( radialSegments + 1 ) * j + ( i - 1 ); + const c = ( radialSegments + 1 ) * j + i; + const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - let loaded = 0; + // faces - function loadTexture( i ) { + indices.push( a, b, d ); + indices.push( b, c, d ); - loader.load( urls[ i ], function ( image ) { + } - texture.images[ i ] = image; + } - loaded ++; + // build geometry - if ( loaded === 6 ) { + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - texture.needsUpdate = true; + // this function calculates the current position on the torus curve - if ( onLoad ) onLoad( texture ); + function calculatePositionOnCurve( u, p, q, radius, position ) { - } + const cu = Math.cos( u ); + const su = Math.sin( u ); + const quOverP = q / p * u; + const cs = Math.cos( quOverP ); - }, undefined, onError ); + position.x = radius * ( 2 + cs ) * 0.5 * cu; + position.y = radius * ( 2 + cs ) * su * 0.5; + position.z = radius * Math.sin( quOverP ) * 0.5; } - for ( let i = 0; i < urls.length; ++ i ) { - - loadTexture( i ); + } - } + static fromJSON( data ) { - return texture; + return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q ); } } - /** - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - - class DataTextureLoader extends Loader { + class TubeGeometry extends BufferGeometry { - constructor( manager ) { + constructor( path = new QuadraticBezierCurve3( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) { - super( manager ); + super(); - } + this.type = 'TubeGeometry'; - load( url, onLoad, onProgress, onError ) { + this.parameters = { + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; - const scope = this; + const frames = path.computeFrenetFrames( tubularSegments, closed ); - const texture = new DataTexture(); + // expose internals - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setPath( this.path ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( buffer ) { + this.tangents = frames.tangents; + this.normals = frames.normals; + this.binormals = frames.binormals; - const texData = scope.parse( buffer ); + // helper variables - if ( ! texData ) return; + const vertex = new Vector3(); + const normal = new Vector3(); + const uv = new Vector2(); + let P = new Vector3(); - if ( texData.image !== undefined ) { + // buffer - texture.image = texData.image; + const vertices = []; + const normals = []; + const uvs = []; + const indices = []; - } else if ( texData.data !== undefined ) { + // create buffer data - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; + generateBufferData(); - } + // build geometry - texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; - texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; + // functions - texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; + function generateBufferData() { - if ( texData.encoding !== undefined ) { + for ( let i = 0; i < tubularSegments; i ++ ) { - texture.encoding = texData.encoding; + generateSegment( i ); } - if ( texData.flipY !== undefined ) { - - texture.flipY = texData.flipY; + // if the geometry is not closed, generate the last row of vertices and normals + // at the regular position on the given path + // + // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) - } + generateSegment( ( closed === false ) ? tubularSegments : 0 ); - if ( texData.format !== undefined ) { + // uvs are generated in a separate function. + // this makes it easy compute correct values for closed geometries - texture.format = texData.format; + generateUVs(); - } + // finally create faces - if ( texData.type !== undefined ) { + generateIndices(); - texture.type = texData.type; + } - } + function generateSegment( i ) { - if ( texData.mipmaps !== undefined ) { + // we use getPointAt to sample evenly distributed points from the given path - texture.mipmaps = texData.mipmaps; - texture.minFilter = LinearMipmapLinearFilter; // presumably... + P = path.getPointAt( i / tubularSegments, P ); - } + // retrieve corresponding normal and binormal - if ( texData.mipmapCount === 1 ) { + const N = frames.normals[ i ]; + const B = frames.binormals[ i ]; - texture.minFilter = LinearFilter; + // generate normals and vertices for the current segment - } + for ( let j = 0; j <= radialSegments; j ++ ) { - if ( texData.generateMipmaps !== undefined ) { + const v = j / radialSegments * Math.PI * 2; - texture.generateMipmaps = texData.generateMipmaps; + const sin = Math.sin( v ); + const cos = - Math.cos( v ); - } + // normal - texture.needsUpdate = true; + normal.x = ( cos * N.x + sin * B.x ); + normal.y = ( cos * N.y + sin * B.y ); + normal.z = ( cos * N.z + sin * B.z ); + normal.normalize(); - if ( onLoad ) onLoad( texture, texData ); + normals.push( normal.x, normal.y, normal.z ); - }, onProgress, onError ); + // vertex + vertex.x = P.x + radius * normal.x; + vertex.y = P.y + radius * normal.y; + vertex.z = P.z + radius * normal.z; - return texture; + vertices.push( vertex.x, vertex.y, vertex.z ); - } + } - } + } - class TextureLoader extends Loader { + function generateIndices() { - constructor( manager ) { + for ( let j = 1; j <= tubularSegments; j ++ ) { - super( manager ); + for ( let i = 1; i <= radialSegments; i ++ ) { - } + const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); + const b = ( radialSegments + 1 ) * j + ( i - 1 ); + const c = ( radialSegments + 1 ) * j + i; + const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - load( url, onLoad, onProgress, onError ) { + // faces - const texture = new Texture(); + indices.push( a, b, d ); + indices.push( b, c, d ); - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); + } - loader.load( url, function ( image ) { + } - texture.image = image; - texture.needsUpdate = true; + } - if ( onLoad !== undefined ) { + function generateUVs() { - onLoad( texture ); + for ( let i = 0; i <= tubularSegments; i ++ ) { - } + for ( let j = 0; j <= radialSegments; j ++ ) { - }, onProgress, onError ); + uv.x = i / tubularSegments; + uv.y = j / radialSegments; - return texture; + uvs.push( uv.x, uv.y ); - } + } - } + } - class Light extends Object3D { + } - constructor( color, intensity = 1 ) { + } - super(); + toJSON() { - this.isLight = true; + const data = super.toJSON(); - this.type = 'Light'; + data.path = this.parameters.path.toJSON(); - this.color = new Color( color ); - this.intensity = intensity; + return data; } - dispose() { + static fromJSON( data ) { - // Empty here in base class; some subclasses override. + // This only works for built-in curves (e.g. CatmullRomCurve3). + // User defined curves or instances of CurvePath will not be deserialized. + return new TubeGeometry( + new Curves[ data.path.type ]().fromJSON( data.path ), + data.tubularSegments, + data.radius, + data.radialSegments, + data.closed + ); } - copy( source, recursive ) { + } - super.copy( source, recursive ); + class WireframeGeometry extends BufferGeometry { - this.color.copy( source.color ); - this.intensity = source.intensity; + constructor( geometry = null ) { - return this; + super(); - } + this.type = 'WireframeGeometry'; - toJSON( meta ) { + this.parameters = { + geometry: geometry + }; - const data = super.toJSON( meta ); + if ( geometry !== null ) { - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; + // buffer - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + const vertices = []; + const edges = new Set(); - if ( this.distance !== undefined ) data.object.distance = this.distance; - if ( this.angle !== undefined ) data.object.angle = this.angle; - if ( this.decay !== undefined ) data.object.decay = this.decay; - if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; + // helper variables - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + const start = new Vector3(); + const end = new Vector3(); - return data; + if ( geometry.index !== null ) { - } + // indexed BufferGeometry - } + const position = geometry.attributes.position; + const indices = geometry.index; + let groups = geometry.groups; - class HemisphereLight extends Light { + if ( groups.length === 0 ) { - constructor( skyColor, groundColor, intensity ) { + groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; - super( skyColor, intensity ); + } - this.isHemisphereLight = true; + // create a data structure that contains all edges without duplicates - this.type = 'HemisphereLight'; + for ( let o = 0, ol = groups.length; o < ol; ++ o ) { - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + const group = groups[ o ]; - this.groundColor = new Color( groundColor ); + const groupStart = group.start; + const groupCount = group.count; - } + for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { - copy( source, recursive ) { + for ( let j = 0; j < 3; j ++ ) { - super.copy( source, recursive ); + const index1 = indices.getX( i + j ); + const index2 = indices.getX( i + ( j + 1 ) % 3 ); - this.groundColor.copy( source.groundColor ); + start.fromBufferAttribute( position, index1 ); + end.fromBufferAttribute( position, index2 ); - return this; + if ( isUniqueEdge( start, end, edges ) === true ) { - } + vertices.push( start.x, start.y, start.z ); + vertices.push( end.x, end.y, end.z ); - } + } - const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); - const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); - const _lookTarget$1 = /*@__PURE__*/ new Vector3(); + } - class LightShadow { + } - constructor( camera ) { + } - this.camera = camera; + } else { - this.bias = 0; - this.normalBias = 0; - this.radius = 1; - this.blurSamples = 8; + // non-indexed BufferGeometry - this.mapSize = new Vector2( 512, 512 ); + const position = geometry.attributes.position; - this.map = null; - this.mapPass = null; - this.matrix = new Matrix4(); + for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { - this.autoUpdate = true; - this.needsUpdate = false; + for ( let j = 0; j < 3; j ++ ) { - this._frustum = new Frustum(); - this._frameExtents = new Vector2( 1, 1 ); + // three edges per triangle, an edge is represented as (index1, index2) + // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) - this._viewportCount = 1; + const index1 = 3 * i + j; + const index2 = 3 * i + ( ( j + 1 ) % 3 ); - this._viewports = [ + start.fromBufferAttribute( position, index1 ); + end.fromBufferAttribute( position, index2 ); - new Vector4( 0, 0, 1, 1 ) + if ( isUniqueEdge( start, end, edges ) === true ) { - ]; + vertices.push( start.x, start.y, start.z ); + vertices.push( end.x, end.y, end.z ); - } + } - getViewportCount() { + } - return this._viewportCount; + } - } + } - getFrustum() { + // build geometry - return this._frustum; + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + + } } - updateMatrices( light ) { + } - const shadowCamera = this.camera; - const shadowMatrix = this.matrix; + function isUniqueEdge( start, end, edges ) { - _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld$1 ); + const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; + const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge - _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget$1 ); - shadowCamera.updateMatrixWorld(); + if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { - _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); + return false; - shadowMatrix.set( - 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 - ); + } else { - shadowMatrix.multiply( _projScreenMatrix$1 ); + edges.add( hash1 ); + edges.add( hash2 ); + return true; } - getViewport( viewportIndex ) { - - return this._viewports[ viewportIndex ]; - - } + } - getFrameExtents() { - - return this._frameExtents; + var Geometries = /*#__PURE__*/Object.freeze({ + __proto__: null, + BoxGeometry: BoxGeometry, + CapsuleGeometry: CapsuleGeometry, + CircleGeometry: CircleGeometry, + ConeGeometry: ConeGeometry, + CylinderGeometry: CylinderGeometry, + DodecahedronGeometry: DodecahedronGeometry, + EdgesGeometry: EdgesGeometry, + ExtrudeGeometry: ExtrudeGeometry, + IcosahedronGeometry: IcosahedronGeometry, + LatheGeometry: LatheGeometry, + OctahedronGeometry: OctahedronGeometry, + PlaneGeometry: PlaneGeometry, + PolyhedronGeometry: PolyhedronGeometry, + RingGeometry: RingGeometry, + ShapeGeometry: ShapeGeometry, + SphereGeometry: SphereGeometry, + TetrahedronGeometry: TetrahedronGeometry, + TorusGeometry: TorusGeometry, + TorusKnotGeometry: TorusKnotGeometry, + TubeGeometry: TubeGeometry, + WireframeGeometry: WireframeGeometry + }); - } + class ShadowMaterial extends Material { - dispose() { + constructor( parameters ) { - if ( this.map ) { + super(); - this.map.dispose(); + this.isShadowMaterial = true; - } + this.type = 'ShadowMaterial'; - if ( this.mapPass ) { + this.color = new Color( 0x000000 ); + this.transparent = true; - this.mapPass.dispose(); + this.fog = true; - } + this.setValues( parameters ); } copy( source ) { - this.camera = source.camera.clone(); + super.copy( source ); - this.bias = source.bias; - this.radius = source.radius; + this.color.copy( source.color ); - this.mapSize.copy( source.mapSize ); + this.fog = source.fog; return this; } - clone() { - - return new this.constructor().copy( this ); - - } + } - toJSON() { + class RawShaderMaterial extends ShaderMaterial { - const object = {}; + constructor( parameters ) { - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); + super( parameters ); - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; + this.isRawShaderMaterial = true; - return object; + this.type = 'RawShaderMaterial'; } } - class SpotLightShadow extends LightShadow { - - constructor() { - - super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - - this.isSpotLightShadow = true; - - this.focus = 1; + class MeshStandardMaterial extends Material { - } + constructor( parameters ) { - updateMatrices( light ) { + super(); - const camera = this.camera; + this.isMeshStandardMaterial = true; - const fov = RAD2DEG * 2 * light.angle * this.focus; - const aspect = this.mapSize.width / this.mapSize.height; - const far = light.distance || camera.far; + this.defines = { 'STANDARD': '' }; - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + this.type = 'MeshStandardMaterial'; - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); + this.color = new Color( 0xffffff ); // diffuse + this.roughness = 1.0; + this.metalness = 0.0; - } + this.map = null; - super.updateMatrices( light ); + this.lightMap = null; + this.lightMapIntensity = 1.0; - } + this.aoMap = null; + this.aoMapIntensity = 1.0; - copy( source ) { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - super.copy( source ); + this.bumpMap = null; + this.bumpScale = 1; - this.focus = source.focus; + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - return this; + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - } + this.roughnessMap = null; - } + this.metalnessMap = null; - class SpotLight extends Light { + this.alphaMap = null; - constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 1 ) { + this.envMap = null; + this.envMapIntensity = 1.0; - super( color, intensity ); + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - this.isSpotLight = true; + this.flatShading = false; - this.type = 'SpotLight'; + this.fog = true; - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + this.setValues( parameters ); - this.target = new Object3D(); + } - this.distance = distance; - this.angle = angle; - this.penumbra = penumbra; - this.decay = decay; // for physically correct lights, should be 2. + copy( source ) { - this.map = null; + super.copy( source ); - this.shadow = new SpotLightShadow(); + this.defines = { 'STANDARD': '' }; - } + this.color.copy( source.color ); + this.roughness = source.roughness; + this.metalness = source.metalness; - get power() { + this.map = source.map; - // compute the light's luminous power (in lumens) from its intensity (in candela) - // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) - return this.intensity * Math.PI; + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - } + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - set power( power ) { + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / Math.PI; + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - } + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - dispose() { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - this.shadow.dispose(); + this.roughnessMap = source.roughnessMap; - } + this.metalnessMap = source.metalnessMap; - copy( source, recursive ) { + this.alphaMap = source.alphaMap; - super.copy( source, recursive ); + this.envMap = source.envMap; + this.envMapIntensity = source.envMapIntensity; - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - this.target = source.target.clone(); + this.flatShading = source.flatShading; - this.shadow = source.shadow.clone(); + this.fog = source.fog; return this; @@ -50607,190 +81982,191 @@ var app = (function () { } - const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); - const _lightPositionWorld = /*@__PURE__*/ new Vector3(); - const _lookTarget = /*@__PURE__*/ new Vector3(); + class MeshPhysicalMaterial extends MeshStandardMaterial { - class PointLightShadow extends LightShadow { + constructor( parameters ) { - constructor() { + super(); - super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + this.isMeshPhysicalMaterial = true; - this.isPointLightShadow = true; + this.defines = { - this._frameExtents = new Vector2( 4, 2 ); + 'STANDARD': '', + 'PHYSICAL': '' - this._viewportCount = 6; + }; - this._viewports = [ - // These viewports map a cube-map onto a 2D texture with the - // following orientation: - // - // xzXZ - // y Y - // - // X - Positive x direction - // x - Negative x direction - // Y - Positive y direction - // y - Negative y direction - // Z - Positive z direction - // z - Negative z direction + this.type = 'MeshPhysicalMaterial'; - // positive X - new Vector4( 2, 1, 1, 1 ), - // negative X - new Vector4( 0, 1, 1, 1 ), - // positive Z - new Vector4( 3, 1, 1, 1 ), - // negative Z - new Vector4( 1, 1, 1, 1 ), - // positive Y - new Vector4( 3, 0, 1, 1 ), - // negative Y - new Vector4( 1, 0, 1, 1 ) - ]; + this.clearcoatMap = null; + this.clearcoatRoughness = 0.0; + this.clearcoatRoughnessMap = null; + this.clearcoatNormalScale = new Vector2( 1, 1 ); + this.clearcoatNormalMap = null; - this._cubeDirections = [ - new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), - new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) - ]; + this.ior = 1.5; - this._cubeUps = [ - new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), - new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) - ]; + Object.defineProperty( this, 'reflectivity', { + get: function () { - } + return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); - updateMatrices( light, viewportIndex = 0 ) { + }, + set: function ( reflectivity ) { - const camera = this.camera; - const shadowMatrix = this.matrix; + this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); - const far = light.distance || camera.far; + } + } ); - if ( far !== camera.far ) { + this.iridescenceMap = null; + this.iridescenceIOR = 1.3; + this.iridescenceThicknessRange = [ 100, 400 ]; + this.iridescenceThicknessMap = null; - camera.far = far; - camera.updateProjectionMatrix(); + this.sheenColor = new Color( 0x000000 ); + this.sheenColorMap = null; + this.sheenRoughness = 1.0; + this.sheenRoughnessMap = null; - } + this.transmissionMap = null; - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - camera.position.copy( _lightPositionWorld ); + this.thickness = 0; + this.thicknessMap = null; + this.attenuationDistance = Infinity; + this.attenuationColor = new Color( 1, 1, 1 ); - _lookTarget.copy( camera.position ); - _lookTarget.add( this._cubeDirections[ viewportIndex ] ); - camera.up.copy( this._cubeUps[ viewportIndex ] ); - camera.lookAt( _lookTarget ); - camera.updateMatrixWorld(); + this.specularIntensity = 1.0; + this.specularIntensityMap = null; + this.specularColor = new Color( 1, 1, 1 ); + this.specularColorMap = null; - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); + this._sheen = 0.0; + this._clearcoat = 0; + this._iridescence = 0; + this._transmission = 0; - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix ); + this.setValues( parameters ); } - } + get sheen() { - class PointLight extends Light { + return this._sheen; - constructor( color, intensity, distance = 0, decay = 1 ) { + } - super( color, intensity ); + set sheen( value ) { - this.isPointLight = true; + if ( this._sheen > 0 !== value > 0 ) { - this.type = 'PointLight'; + this.version ++; - this.distance = distance; - this.decay = decay; // for physically correct lights, should be 2. + } - this.shadow = new PointLightShadow(); + this._sheen = value; } - get power() { + get clearcoat() { - // compute the light's luminous power (in lumens) from its intensity (in candela) - // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) - return this.intensity * 4 * Math.PI; + return this._clearcoat; } - set power( power ) { + set clearcoat( value ) { - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / ( 4 * Math.PI ); + if ( this._clearcoat > 0 !== value > 0 ) { - } + this.version ++; - dispose() { + } - this.shadow.dispose(); + this._clearcoat = value; } - copy( source, recursive ) { + get iridescence() { - super.copy( source, recursive ); + return this._iridescence; - this.distance = source.distance; - this.decay = source.decay; + } - this.shadow = source.shadow.clone(); + set iridescence( value ) { - return this; + if ( this._iridescence > 0 !== value > 0 ) { - } + this.version ++; - } + } - class DirectionalLightShadow extends LightShadow { + this._iridescence = value; - constructor() { + } - super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + get transmission() { - this.isDirectionalLightShadow = true; + return this._transmission; } - } + set transmission( value ) { - class DirectionalLight extends Light { + if ( this._transmission > 0 !== value > 0 ) { - constructor( color, intensity ) { + this.version ++; - super( color, intensity ); + } - this.isDirectionalLight = true; + this._transmission = value; - this.type = 'DirectionalLight'; + } - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + copy( source ) { - this.target = new Object3D(); + super.copy( source ); - this.shadow = new DirectionalLightShadow(); + this.defines = { - } + 'STANDARD': '', + 'PHYSICAL': '' - dispose() { + }; - this.shadow.dispose(); + this.clearcoat = source.clearcoat; + this.clearcoatMap = source.clearcoatMap; + this.clearcoatRoughness = source.clearcoatRoughness; + this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; + this.clearcoatNormalMap = source.clearcoatNormalMap; + this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); - } + this.ior = source.ior; - copy( source ) { + this.iridescence = source.iridescence; + this.iridescenceMap = source.iridescenceMap; + this.iridescenceIOR = source.iridescenceIOR; + this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ]; + this.iridescenceThicknessMap = source.iridescenceThicknessMap; - super.copy( source ); + this.sheen = source.sheen; + this.sheenColor.copy( source.sheenColor ); + this.sheenColorMap = source.sheenColorMap; + this.sheenRoughness = source.sheenRoughness; + this.sheenRoughnessMap = source.sheenRoughnessMap; - this.target = source.target.clone(); - this.shadow = source.shadow.clone(); + this.transmission = source.transmission; + this.transmissionMap = source.transmissionMap; + + this.thickness = source.thickness; + this.thicknessMap = source.thicknessMap; + this.attenuationDistance = source.attenuationDistance; + this.attenuationColor.copy( source.attenuationColor ); + + this.specularIntensity = source.specularIntensity; + this.specularIntensityMap = source.specularIntensityMap; + this.specularColor.copy( source.specularColor ); + this.specularColorMap = source.specularColorMap; return this; @@ -50798,46 +82174,62 @@ var app = (function () { } - class AmbientLight extends Light { + class MeshPhongMaterial extends Material { - constructor( color, intensity ) { + constructor( parameters ) { - super( color, intensity ); + super(); - this.isAmbientLight = true; + this.isMeshPhongMaterial = true; - this.type = 'AmbientLight'; + this.type = 'MeshPhongMaterial'; - } + this.color = new Color( 0xffffff ); // diffuse + this.specular = new Color( 0x111111 ); + this.shininess = 30; - } + this.map = null; - class RectAreaLight extends Light { + this.lightMap = null; + this.lightMapIntensity = 1.0; - constructor( color, intensity, width = 10, height = 10 ) { + this.aoMap = null; + this.aoMapIntensity = 1.0; - super( color, intensity ); + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - this.isRectAreaLight = true; + this.bumpMap = null; + this.bumpScale = 1; - this.type = 'RectAreaLight'; + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - this.width = width; - this.height = height; + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - } + this.specularMap = null; - get power() { + this.alphaMap = null; - // compute the light's luminous power (in lumens) from its intensity (in nits) - return this.intensity * this.width * this.height * Math.PI; + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - } + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - set power( power ) { + this.flatShading = false; - // set the light's intensity (in nits) from the desired luminous power (in lumens) - this.intensity = power / ( this.width * this.height * Math.PI ); + this.fog = true; + + this.setValues( parameters ); } @@ -50845,275 +82237,409 @@ var app = (function () { super.copy( source ); - this.width = source.width; - this.height = source.height; - - return this; + this.color.copy( source.color ); + this.specular.copy( source.specular ); + this.shininess = source.shininess; - } + this.map = source.map; - toJSON( meta ) { + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - const data = super.toJSON( meta ); + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - data.object.width = this.width; - data.object.height = this.height; + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - return data; + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.flatShading = source.flatShading; + + this.fog = source.fog; + + return this; } } - /** - * Primary reference: - * https://graphics.stanford.edu/papers/envmap/envmap.pdf - * - * Secondary reference: - * https://www.ppsloan.org/publications/StupidSH36.pdf - */ + class MeshToonMaterial extends Material { - // 3-band SH defined by 9 coefficients + constructor( parameters ) { - class SphericalHarmonics3 { + super(); - constructor() { + this.isMeshToonMaterial = true; - this.isSphericalHarmonics3 = true; + this.defines = { 'TOON': '' }; - this.coefficients = []; + this.type = 'MeshToonMaterial'; - for ( let i = 0; i < 9; i ++ ) { + this.color = new Color( 0xffffff ); - this.coefficients.push( new Vector3() ); + this.map = null; + this.gradientMap = null; - } + this.lightMap = null; + this.lightMapIntensity = 1.0; - } + this.aoMap = null; + this.aoMapIntensity = 1.0; - set( coefficients ) { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - for ( let i = 0; i < 9; i ++ ) { + this.bumpMap = null; + this.bumpScale = 1; - this.coefficients[ i ].copy( coefficients[ i ] ); + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - } + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - return this; + this.alphaMap = null; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.fog = true; + + this.setValues( parameters ); } - zero() { + copy( source ) { - for ( let i = 0; i < 9; i ++ ) { + super.copy( source ); - this.coefficients[ i ].set( 0, 0, 0 ); + this.color.copy( source.color ); - } + this.map = source.map; + this.gradientMap = source.gradientMap; - return this; + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - } + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - // get the radiance in the direction of the normal - // target is a Vector3 - getAt( normal, target ) { + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - // normal is assumed to be unit length + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - const x = normal.x, y = normal.y, z = normal.z; + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - const coeff = this.coefficients; + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); + this.alphaMap = source.alphaMap; - // band 1 - target.addScaledVector( coeff[ 1 ], 0.488603 * y ); - target.addScaledVector( coeff[ 2 ], 0.488603 * z ); - target.addScaledVector( coeff[ 3 ], 0.488603 * x ); + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - // band 2 - target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); - target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); - target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); - target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); - target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); + this.fog = source.fog; - return target; + return this; } - // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal - // target is a Vector3 - // https://graphics.stanford.edu/papers/envmap/envmap.pdf - getIrradianceAt( normal, target ) { + } - // normal is assumed to be unit length + class MeshNormalMaterial extends Material { - const x = normal.x, y = normal.y, z = normal.z; + constructor( parameters ) { - const coeff = this.coefficients; + super(); - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 + this.isMeshNormalMaterial = true; - // band 1 - target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 - target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); - target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); + this.type = 'MeshNormalMaterial'; - // band 2 - target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 - target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); - target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 - target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); - target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 + this.bumpMap = null; + this.bumpScale = 1; - return target; + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - } + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - add( sh ) { + this.wireframe = false; + this.wireframeLinewidth = 1; - for ( let i = 0; i < 9; i ++ ) { + this.flatShading = false; - this.coefficients[ i ].add( sh.coefficients[ i ] ); + this.setValues( parameters ); - } + } - return this; + copy( source ) { - } + super.copy( source ); - addScaledSH( sh, s ) { + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - for ( let i = 0; i < 9; i ++ ) { + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - } + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + + this.flatShading = source.flatShading; return this; } - scale( s ) { + } - for ( let i = 0; i < 9; i ++ ) { + class MeshLambertMaterial extends Material { - this.coefficients[ i ].multiplyScalar( s ); + constructor( parameters ) { - } + super(); - return this; + this.isMeshLambertMaterial = true; - } + this.type = 'MeshLambertMaterial'; - lerp( sh, alpha ) { + this.color = new Color( 0xffffff ); // diffuse - for ( let i = 0; i < 9; i ++ ) { + this.map = null; - this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); + this.lightMap = null; + this.lightMapIntensity = 1.0; - } + this.aoMap = null; + this.aoMapIntensity = 1.0; - return this; + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - } + this.bumpMap = null; + this.bumpScale = 1; - equals( sh ) { + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - for ( let i = 0; i < 9; i ++ ) { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { + this.specularMap = null; - return false; + this.alphaMap = null; - } + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - } + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - return true; + this.flatShading = false; + + this.fog = true; + + this.setValues( parameters ); } - copy( sh ) { + copy( source ) { - return this.set( sh.coefficients ); + super.copy( source ); - } + this.color.copy( source.color ); - clone() { + this.map = source.map; - return new this.constructor().copy( this ); + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - } + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - fromArray( array, offset = 0 ) { + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - const coefficients = this.coefficients; + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - for ( let i = 0; i < 9; i ++ ) { + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - } + this.specularMap = source.specularMap; + + this.alphaMap = source.alphaMap; + + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; + + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; + + this.flatShading = source.flatShading; + + this.fog = source.fog; return this; } - toArray( array = [], offset = 0 ) { + } - const coefficients = this.coefficients; + class MeshMatcapMaterial extends Material { - for ( let i = 0; i < 9; i ++ ) { + constructor( parameters ) { - coefficients[ i ].toArray( array, offset + ( i * 3 ) ); + super(); - } + this.isMeshMatcapMaterial = true; - return array; + this.defines = { 'MATCAP': '' }; + + this.type = 'MeshMatcapMaterial'; + + this.color = new Color( 0xffffff ); // diffuse + + this.matcap = null; + + this.map = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); + + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; + + this.alphaMap = null; + + this.flatShading = false; + + this.fog = true; + + this.setValues( parameters ); } - // evaluate the basis functions - // shBasis is an Array[ 9 ] - static getBasisAt( normal, shBasis ) { - // normal is assumed to be unit length + copy( source ) { - const x = normal.x, y = normal.y, z = normal.z; + super.copy( source ); - // band 0 - shBasis[ 0 ] = 0.282095; + this.defines = { 'MATCAP': '' }; - // band 1 - shBasis[ 1 ] = 0.488603 * y; - shBasis[ 2 ] = 0.488603 * z; - shBasis[ 3 ] = 0.488603 * x; + this.color.copy( source.color ); - // band 2 - shBasis[ 4 ] = 1.092548 * x * y; - shBasis[ 5 ] = 1.092548 * y * z; - shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); - shBasis[ 7 ] = 1.092548 * x * z; - shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); + this.matcap = source.matcap; + + this.map = source.map; + + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; + + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); + + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; + + this.alphaMap = source.alphaMap; + + this.flatShading = source.flatShading; + + this.fog = source.fog; + + return this; } } - class LightProbe extends Light { + class LineDashedMaterial extends LineBasicMaterial { - constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { + constructor( parameters ) { - super( undefined, intensity ); + super(); - this.isLightProbe = true; + this.isLineDashedMaterial = true; - this.sh = sh; + this.type = 'LineDashedMaterial'; + + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; + + this.setValues( parameters ); } @@ -51121,1089 +82647,1124 @@ var app = (function () { super.copy( source ); - this.sh.copy( source.sh ); + this.scale = source.scale; + this.dashSize = source.dashSize; + this.gapSize = source.gapSize; return this; } - fromJSON( json ) { + } - this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); - this.sh.fromArray( json.sh ); + // same as Array.prototype.slice, but also works on typed arrays + function arraySlice( array, from, to ) { - return this; + if ( isTypedArray( array ) ) { + + // in ios9 array.subarray(from, undefined) will return empty array + // but array.subarray(from) or array.subarray(from, len) is correct + return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); } - toJSON( meta ) { + return array.slice( from, to ); - const data = super.toJSON( meta ); + } - data.object.sh = this.sh.toArray(); + // converts an array to a specific type + function convertArray( array, type, forceClone ) { - return data; + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) return array; + + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + + return new type( array ); // create typed array } + return Array.prototype.slice.call( array ); // create Array + } - class MaterialLoader extends Loader { + function isTypedArray( object ) { - constructor( manager ) { + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); - super( manager ); - this.textures = {}; + } - } + // returns an array by which times and values can be sorted + function getKeyframeOrder( times ) { - load( url, onLoad, onProgress, onError ) { + function compareTime( i, j ) { - const scope = this; + return times[ i ] - times[ j ]; - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { + } - try { + const n = times.length; + const result = new Array( n ); + for ( let i = 0; i !== n; ++ i ) result[ i ] = i; - onLoad( scope.parse( JSON.parse( text ) ) ); + result.sort( compareTime ); - } catch ( e ) { + return result; - if ( onError ) { + } - onError( e ); + // uses the array previously returned by 'getKeyframeOrder' to sort data + function sortedArray( values, stride, order ) { - } else { + const nValues = values.length; + const result = new values.constructor( nValues ); - console.error( e ); + for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - } + const srcOffset = order[ i ] * stride; - scope.manager.itemError( url ); + for ( let j = 0; j !== stride; ++ j ) { - } + result[ dstOffset ++ ] = values[ srcOffset + j ]; - }, onProgress, onError ); + } } - parse( json ) { + return result; - const textures = this.textures; + } - function getTexture( name ) { + // function for parsing AOS keyframe formats + function flattenJSON( jsonKeys, times, values, valuePropertyName ) { - if ( textures[ name ] === undefined ) { + let i = 1, key = jsonKeys[ 0 ]; - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { - } + key = jsonKeys[ i ++ ]; - return textures[ name ]; + } - } + if ( key === undefined ) return; // no data - const material = MaterialLoader.createMaterialFromType( json.type ); + let value = key[ valuePropertyName ]; + if ( value === undefined ) return; // no data - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.sheen !== undefined ) material.sheen = json.sheen; - if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); - if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; - if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; - if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; - if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; - if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; - if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; - if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; - if ( json.transmission !== undefined ) material.transmission = json.transmission; - if ( json.thickness !== undefined ) material.thickness = json.thickness; - if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; - if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.combine !== undefined ) material.combine = json.combine; - if ( json.side !== undefined ) material.side = json.side; - if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - - if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; - if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; - if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; - if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; - if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; - if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; - if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; - if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; - - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; + if ( Array.isArray( value ) ) { - if ( json.rotation !== undefined ) material.rotation = json.rotation; + do { - if ( json.linewidth !== 1 ) material.linewidth = json.linewidth; - if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; - if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; - if ( json.scale !== undefined ) material.scale = json.scale; + value = key[ valuePropertyName ]; - if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; - if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; - if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; + if ( value !== undefined ) { - if ( json.dithering !== undefined ) material.dithering = json.dithering; + times.push( key.time ); + values.push.apply( values, value ); // push all elements - if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; - if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; + } - if ( json.visible !== undefined ) material.visible = json.visible; + key = jsonKeys[ i ++ ]; - if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; + } while ( key !== undefined ); - if ( json.userData !== undefined ) material.userData = json.userData; + } else if ( value.toArray !== undefined ) { - if ( json.vertexColors !== undefined ) { + // ...assume THREE.Math-ish - if ( typeof json.vertexColors === 'number' ) { + do { - material.vertexColors = ( json.vertexColors > 0 ) ? true : false; + value = key[ valuePropertyName ]; - } else { + if ( value !== undefined ) { - material.vertexColors = json.vertexColors; + times.push( key.time ); + value.toArray( values, values.length ); } - } - - // Shader Material + key = jsonKeys[ i ++ ]; - if ( json.uniforms !== undefined ) { + } while ( key !== undefined ); - for ( const name in json.uniforms ) { + } else { - const uniform = json.uniforms[ name ]; + // otherwise push as-is - material.uniforms[ name ] = {}; + do { - switch ( uniform.type ) { + value = key[ valuePropertyName ]; - case 't': - material.uniforms[ name ].value = getTexture( uniform.value ); - break; + if ( value !== undefined ) { - case 'c': - material.uniforms[ name ].value = new Color().setHex( uniform.value ); - break; + times.push( key.time ); + values.push( value ); - case 'v2': - material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); - break; + } - case 'v3': - material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); - break; + key = jsonKeys[ i ++ ]; - case 'v4': - material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); - break; + } while ( key !== undefined ); - case 'm3': - material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); - break; + } - case 'm4': - material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); - break; + } - default: - material.uniforms[ name ].value = uniform.value; + function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { - } + const clip = sourceClip.clone(); - } + clip.name = name; - } + const tracks = []; - if ( json.defines !== undefined ) material.defines = json.defines; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; + for ( let i = 0; i < clip.tracks.length; ++ i ) { - if ( json.extensions !== undefined ) { + const track = clip.tracks[ i ]; + const valueSize = track.getValueSize(); - for ( const key in json.extensions ) { + const times = []; + const values = []; - material.extensions[ key ] = json.extensions[ key ]; + for ( let j = 0; j < track.times.length; ++ j ) { - } + const frame = track.times[ j ] * fps; - } + if ( frame < startFrame || frame >= endFrame ) continue; - // for PointsMaterial + times.push( track.times[ j ] ); - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + for ( let k = 0; k < valueSize; ++ k ) { - // maps + values.push( track.values[ j * valueSize + k ] ); - if ( json.map !== undefined ) material.map = getTexture( json.map ); - if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); + } - if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); + } - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; + if ( times.length === 0 ) continue; - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; - if ( json.normalScale !== undefined ) { + track.times = convertArray( times, track.times.constructor ); + track.values = convertArray( values, track.values.constructor ); - let normalScale = json.normalScale; + tracks.push( track ); - if ( Array.isArray( normalScale ) === false ) { + } - // Blender exporter used to export a scalar. See #7459 + clip.tracks = tracks; - normalScale = [ normalScale, normalScale ]; + // find minimum .times value across all tracks in the trimmed clip - } + let minStartTime = Infinity; - material.normalScale = new Vector2().fromArray( normalScale ); + for ( let i = 0; i < clip.tracks.length; ++ i ) { - } + if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { - if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); - if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; - if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; + minStartTime = clip.tracks[ i ].times[ 0 ]; - if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); - if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); + } - if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); - if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; + } - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); - if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); + // shift all tracks such that clip begins at t=0 - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; + for ( let i = 0; i < clip.tracks.length; ++ i ) { - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; + clip.tracks[ i ].shift( - 1 * minStartTime ); - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; + } - if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); - if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; + clip.resetDuration(); - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); + return clip; - if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); - if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); - if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); - if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); + } - if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); - if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); + function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { - if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); - if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); + if ( fps <= 0 ) fps = 30; - if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); - if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); + const numTracks = referenceClip.tracks.length; + const referenceTime = referenceFrame / fps; - return material; + // Make each track's values relative to the values at the reference frame + for ( let i = 0; i < numTracks; ++ i ) { - } + const referenceTrack = referenceClip.tracks[ i ]; + const referenceTrackType = referenceTrack.ValueTypeName; - setTextures( value ) { + // Skip this track if it's non-numeric + if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; - this.textures = value; - return this; + // Find the track in the target clip whose name and type matches the reference track + const targetTrack = targetClip.tracks.find( function ( track ) { - } + return track.name === referenceTrack.name + && track.ValueTypeName === referenceTrackType; - static createMaterialFromType( type ) { + } ); - const materialLib = { - ShadowMaterial, - SpriteMaterial, - RawShaderMaterial, - ShaderMaterial, - PointsMaterial, - MeshPhysicalMaterial, - MeshStandardMaterial, - MeshPhongMaterial, - MeshToonMaterial, - MeshNormalMaterial, - MeshLambertMaterial, - MeshDepthMaterial, - MeshDistanceMaterial, - MeshBasicMaterial, - MeshMatcapMaterial, - LineDashedMaterial, - LineBasicMaterial, - Material - }; + if ( targetTrack === undefined ) continue; - return new materialLib[ type ](); + let referenceOffset = 0; + const referenceValueSize = referenceTrack.getValueSize(); - } + if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - } + referenceOffset = referenceValueSize / 3; - class LoaderUtils { + } - static decodeText( array ) { + let targetOffset = 0; + const targetValueSize = targetTrack.getValueSize(); - if ( typeof TextDecoder !== 'undefined' ) { + if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - return new TextDecoder().decode( array ); + targetOffset = targetValueSize / 3; } - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. + const lastIndex = referenceTrack.times.length - 1; + let referenceValue; - let s = ''; + // Find the value to subtract out of the track + if ( referenceTime <= referenceTrack.times[ 0 ] ) { - for ( let i = 0, il = array.length; i < il; i ++ ) { + // Reference frame is earlier than the first keyframe, so just use the first keyframe + const startIndex = referenceOffset; + const endIndex = referenceValueSize - referenceOffset; + referenceValue = arraySlice( referenceTrack.values, startIndex, endIndex ); - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); + } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { - } + // Reference frame is after the last keyframe, so just use the last keyframe + const startIndex = lastIndex * referenceValueSize + referenceOffset; + const endIndex = startIndex + referenceValueSize - referenceOffset; + referenceValue = arraySlice( referenceTrack.values, startIndex, endIndex ); - try { + } else { - // merges multi-byte utf-8 characters. + // Interpolate to the reference value + const interpolant = referenceTrack.createInterpolant(); + const startIndex = referenceOffset; + const endIndex = referenceValueSize - referenceOffset; + interpolant.evaluate( referenceTime ); + referenceValue = arraySlice( interpolant.resultBuffer, startIndex, endIndex ); - return decodeURIComponent( escape( s ) ); + } - } catch ( e ) { // see #16358 + // Conjugate the quaternion + if ( referenceTrackType === 'quaternion' ) { - return s; + const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); + referenceQuat.toArray( referenceValue ); } - } + // Subtract the reference value from all of the track values - static extractUrlBase( url ) { + const numTimes = targetTrack.times.length; + for ( let j = 0; j < numTimes; ++ j ) { - const index = url.lastIndexOf( '/' ); + const valueStart = j * targetValueSize + targetOffset; - if ( index === - 1 ) return './'; + if ( referenceTrackType === 'quaternion' ) { - return url.slice( 0, index + 1 ); + // Multiply the conjugate for quaternion track types + Quaternion.multiplyQuaternionsFlat( + targetTrack.values, + valueStart, + referenceValue, + 0, + targetTrack.values, + valueStart + ); - } + } else { - static resolveURL( url, path ) { + const valueEnd = targetValueSize - targetOffset * 2; - // Invalid URL - if ( typeof url !== 'string' || url === '' ) return ''; + // Subtract each value for all other numeric track types + for ( let k = 0; k < valueEnd; ++ k ) { - // Host Relative URL - if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { + targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; - path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); + } + + } } - // Absolute URL http://,https://,// - if ( /^(https?:)?\/\//i.test( url ) ) return url; + } - // Data URI - if ( /^data:.*,.*$/i.test( url ) ) return url; + targetClip.blendMode = AdditiveAnimationBlendMode; - // Blob URL - if ( /^blob:.*$/i.test( url ) ) return url; + return targetClip; - // Relative URL - return path + url; + } - } + var AnimationUtils = /*#__PURE__*/Object.freeze({ + __proto__: null, + arraySlice: arraySlice, + convertArray: convertArray, + isTypedArray: isTypedArray, + getKeyframeOrder: getKeyframeOrder, + sortedArray: sortedArray, + flattenJSON: flattenJSON, + subclip: subclip, + makeClipAdditive: makeClipAdditive + }); - } + /** + * Abstract base class of interpolants over parametric samples. + * + * The parameter domain is one dimensional, typically the time or a path + * along a curve defined by the data. + * + * The sample values can have any dimensionality and derived classes may + * apply special interpretations to the data. + * + * This class provides the interval seek in a Template Method, deferring + * the actual interpolation to derived classes. + * + * Time complexity is O(1) for linear access crossing at most two points + * and O(log N) for random access, where N is the number of positions. + * + * References: + * + * http://www.oodesign.com/template-method-pattern.html + * + */ - class InstancedBufferGeometry extends BufferGeometry { + class Interpolant { - constructor() { + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - super(); + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; - this.isInstancedBufferGeometry = true; + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; - this.type = 'InstancedBufferGeometry'; - this.instanceCount = Infinity; + this.settings = null; + this.DefaultSettings_ = {}; } - copy( source ) { + evaluate( t ) { - super.copy( source ); + const pp = this.parameterPositions; + let i1 = this._cachedIndex, + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; - this.instanceCount = source.instanceCount; + validate_interval: { - return this; + seek: { - } + let right; - clone() { + linear_scan: { - return new this.constructor().copy( this ); + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { - } + for ( let giveUpAt = i1 + 2; ; ) { - toJSON() { + if ( t1 === undefined ) { - const data = super.toJSON( this ); + if ( t < t0 ) break forward_scan; - data.instanceCount = this.instanceCount; + // after end - data.isInstancedBufferGeometry = true; + i1 = pp.length; + this._cachedIndex = i1; + return this.copySampleValue_( i1 - 1 ); - return data; + } - } + if ( i1 === giveUpAt ) break; // this loop - } + t0 = t1; + t1 = pp[ ++ i1 ]; - class BufferGeometryLoader extends Loader { + if ( t < t1 ) { - constructor( manager ) { + // we have arrived at the sought interval + break seek; - super( manager ); + } - } + } - load( url, onLoad, onProgress, onError ) { + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; - const scope = this; + } - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { + //- slower code: + //- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { - try { + // looping? - onLoad( scope.parse( JSON.parse( text ) ) ); + const t1global = pp[ 1 ]; - } catch ( e ) { + if ( t < t1global ) { - if ( onError ) { + i1 = 2; // + 1, using the scan for the details + t0 = t1global; - onError( e ); + } - } else { + // linear reverse scan - console.error( e ); + for ( let giveUpAt = i1 - 2; ; ) { - } + if ( t0 === undefined ) { - scope.manager.itemError( url ); + // before start - } + this._cachedIndex = 0; + return this.copySampleValue_( 0 ); - }, onProgress, onError ); + } - } + if ( i1 === giveUpAt ) break; // this loop - parse( json ) { + t1 = t0; + t0 = pp[ -- i1 - 1 ]; - const interleavedBufferMap = {}; - const arrayBufferMap = {}; + if ( t >= t0 ) { - function getInterleavedBuffer( json, uuid ) { + // we have arrived at the sought interval + break seek; - if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; + } - const interleavedBuffers = json.interleavedBuffers; - const interleavedBuffer = interleavedBuffers[ uuid ]; + } - const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; - const array = getTypedArray( interleavedBuffer.type, buffer ); - const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); - ib.uuid = interleavedBuffer.uuid; + } - interleavedBufferMap[ uuid ] = ib; + // the interval is valid - return ib; + break validate_interval; - } + } // linear scan - function getArrayBuffer( json, uuid ) { + // binary search - if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; + while ( i1 < right ) { - const arrayBuffers = json.arrayBuffers; - const arrayBuffer = arrayBuffers[ uuid ]; + const mid = ( i1 + right ) >>> 1; - const ab = new Uint32Array( arrayBuffer ).buffer; + if ( t < pp[ mid ] ) { - arrayBufferMap[ uuid ] = ab; + right = mid; - return ab; + } else { - } + i1 = mid + 1; - const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); + } - const index = json.data.index; + } - if ( index !== undefined ) { + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; - const typedArray = getTypedArray( index.type, index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); + // check boundary cases, again - } + if ( t0 === undefined ) { - const attributes = json.data.attributes; + this._cachedIndex = 0; + return this.copySampleValue_( 0 ); - for ( const key in attributes ) { + } - const attribute = attributes[ key ]; - let bufferAttribute; + if ( t1 === undefined ) { - if ( attribute.isInterleavedBufferAttribute ) { + i1 = pp.length; + this._cachedIndex = i1; + return this.copySampleValue_( i1 - 1 ); - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); + } - } else { + } // seek - const typedArray = getTypedArray( attribute.type, attribute.array ); - const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; - bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); + this._cachedIndex = i1; - } + this.intervalChanged_( i1, t0, t1 ); - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); + } // validate_interval - if ( attribute.updateRange !== undefined ) { + return this.interpolate_( i1, t0, t, t1 ); - bufferAttribute.updateRange.offset = attribute.updateRange.offset; - bufferAttribute.updateRange.count = attribute.updateRange.count; + } - } + getSettings_() { - geometry.setAttribute( key, bufferAttribute ); + return this.settings || this.DefaultSettings_; - } + } - const morphAttributes = json.data.morphAttributes; + copySampleValue_( index ) { - if ( morphAttributes ) { + // copies a sample value to the result buffer - for ( const key in morphAttributes ) { + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; - const attributeArray = morphAttributes[ key ]; + for ( let i = 0; i !== stride; ++ i ) { - const array = []; + result[ i ] = values[ offset + i ]; - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { + } - const attribute = attributeArray[ i ]; - let bufferAttribute; + return result; - if ( attribute.isInterleavedBufferAttribute ) { + } - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); + // Template methods for derived classes: - } else { + interpolate_( /* i1, t0, t, t1 */ ) { - const typedArray = getTypedArray( attribute.type, attribute.array ); - bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); + throw new Error( 'call to abstract method' ); + // implementations shall return this.resultBuffer - } + } - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - array.push( bufferAttribute ); + intervalChanged_( /* i1, t0, t1 */ ) { - } + // empty - geometry.morphAttributes[ key ] = array; + } - } + } - } + /** + * Fast and simple cubic spline interpolant. + * + * It was derived from a Hermitian construction setting the first derivative + * at each sample position to the linear slope between neighboring positions + * over their parameter interval. + */ - const morphTargetsRelative = json.data.morphTargetsRelative; + class CubicInterpolant extends Interpolant { - if ( morphTargetsRelative ) { + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - geometry.morphTargetsRelative = true; + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - } + this._weightPrev = - 0; + this._offsetPrev = - 0; + this._weightNext = - 0; + this._offsetNext = - 0; - const groups = json.data.groups || json.data.drawcalls || json.data.offsets; + this.DefaultSettings_ = { - if ( groups !== undefined ) { + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding - for ( let i = 0, n = groups.length; i !== n; ++ i ) { + }; - const group = groups[ i ]; + } - geometry.addGroup( group.start, group.count, group.materialIndex ); + intervalChanged_( i1, t0, t1 ) { - } + const pp = this.parameterPositions; + let iPrev = i1 - 2, + iNext = i1 + 1, - } + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; - const boundingSphere = json.data.boundingSphere; + if ( tPrev === undefined ) { - if ( boundingSphere !== undefined ) { + switch ( this.getSettings_().endingStart ) { - const center = new Vector3(); + case ZeroSlopeEnding: - if ( boundingSphere.center !== undefined ) { + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; - center.fromArray( boundingSphere.center ); + break; - } + case WrapAroundEnding: - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; + + } } - if ( json.name ) geometry.name = json.name; - if ( json.userData ) geometry.userData = json.userData; + if ( tNext === undefined ) { - return geometry; + switch ( this.getSettings_().endingEnd ) { - } + case ZeroSlopeEnding: - } + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; - class ObjectLoader extends Loader { + break; - constructor( manager ) { + case WrapAroundEnding: - super( manager ); + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; - } + break; - load( url, onLoad, onProgress, onError ) { + default: // ZeroCurvatureEnding - const scope = this; + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; + } - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + } - let json = null; + const halfDt = ( t1 - t0 ) * 0.5, + stride = this.valueSize; - try { + this._weightPrev = halfDt / ( t0 - tPrev ); + this._weightNext = halfDt / ( tNext - t1 ); + this._offsetPrev = iPrev * stride; + this._offsetNext = iNext * stride; - json = JSON.parse( text ); + } - } catch ( error ) { + interpolate_( i1, t0, t, t1 ) { - if ( onError !== undefined ) onError( error ); + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, - return; + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; - } + // evaluate polynomials - const metadata = json.metadata; + const sP = - wP * ppp + 2 * wP * pp - wP * p; + const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; + const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; + const sN = wN * ppp - wN * pp; - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + // combine data linearly - console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); - return; + for ( let i = 0; i !== stride; ++ i ) { - } + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; - scope.parse( json, onLoad ); + } - }, onProgress, onError ); + return result; } - async loadAsync( url, onProgress ) { - - const scope = this; + } - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; + class LinearInterpolant extends Interpolant { - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - const text = await loader.loadAsync( url, onProgress ); + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - const json = JSON.parse( text ); + } - const metadata = json.metadata; + interpolate_( i1, t0, t, t1 ) { - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); + offset1 = i1 * stride, + offset0 = offset1 - stride, - } + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; - return await scope.parseAsync( json ); + for ( let i = 0; i !== stride; ++ i ) { - } + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; - parse( json, onLoad ) { + } - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); + return result; - const images = this.parseImages( json.images, function () { + } - if ( onLoad !== undefined ) onLoad( object ); + } - } ); + /** + * + * Interpolant that evaluates to the sample value at the position preceding + * the parameter. + */ - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); + class DiscreteInterpolant extends Interpolant { - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - this.bindSkeletons( object, skeletons ); + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - // + } - if ( onLoad !== undefined ) { + interpolate_( i1 /*, t0, t, t1 */ ) { - let hasImages = false; + return this.copySampleValue_( i1 - 1 ); - for ( const uuid in images ) { + } - if ( images[ uuid ].data instanceof HTMLImageElement ) { + } - hasImages = true; - break; + class KeyframeTrack { - } + constructor( name, times, values, interpolation ) { - } + if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); + if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); - if ( hasImages === false ) onLoad( object ); + this.name = name; - } + this.times = convertArray( times, this.TimeBufferType ); + this.values = convertArray( values, this.ValueBufferType ); - return object; + this.setInterpolation( interpolation || this.DefaultInterpolation ); } - async parseAsync( json ) { - - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): - const images = await this.parseImagesAsync( json.images ); + static toJSON( track ) { - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); + const trackType = track.constructor; - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); + let json; - this.bindSkeletons( object, skeletons ); + // derived classes can define a static toJSON method + if ( trackType.toJSON !== this.toJSON ) { - return object; + json = trackType.toJSON( track ); - } + } else { - parseShapes( json ) { + // by default, we assume the data can be serialized as-is + json = { - const shapes = {}; + 'name': track.name, + 'times': convertArray( track.times, Array ), + 'values': convertArray( track.values, Array ) - if ( json !== undefined ) { + }; - for ( let i = 0, l = json.length; i < l; i ++ ) { + const interpolation = track.getInterpolation(); - const shape = new Shape().fromJSON( json[ i ] ); + if ( interpolation !== track.DefaultInterpolation ) { - shapes[ shape.uuid ] = shape; + json.interpolation = interpolation; } } - return shapes; + json.type = track.ValueTypeName; // mandatory - } + return json; - parseSkeletons( json, object ) { + } - const skeletons = {}; - const bones = {}; + InterpolantFactoryMethodDiscrete( result ) { - // generate bone lookup table + return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - object.traverse( function ( child ) { + } - if ( child.isBone ) bones[ child.uuid ] = child; + InterpolantFactoryMethodLinear( result ) { - } ); + return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - // create skeletons + } - if ( json !== undefined ) { + InterpolantFactoryMethodSmooth( result ) { - for ( let i = 0, l = json.length; i < l; i ++ ) { + return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - const skeleton = new Skeleton().fromJSON( json[ i ], bones ); + } - skeletons[ skeleton.uuid ] = skeleton; + setInterpolation( interpolation ) { - } + let factoryMethod; - } + switch ( interpolation ) { - return skeletons; + case InterpolateDiscrete: - } + factoryMethod = this.InterpolantFactoryMethodDiscrete; - parseGeometries( json, shapes ) { + break; - const geometries = {}; + case InterpolateLinear: - if ( json !== undefined ) { + factoryMethod = this.InterpolantFactoryMethodLinear; - const bufferGeometryLoader = new BufferGeometryLoader(); + break; - for ( let i = 0, l = json.length; i < l; i ++ ) { + case InterpolateSmooth: - let geometry; - const data = json[ i ]; + factoryMethod = this.InterpolantFactoryMethodSmooth; - switch ( data.type ) { + break; - case 'BufferGeometry': - case 'InstancedBufferGeometry': + } - geometry = bufferGeometryLoader.parse( data ); - break; + if ( factoryMethod === undefined ) { - default: + const message = 'unsupported interpolation for ' + + this.ValueTypeName + ' keyframe track named ' + this.name; - if ( data.type in Geometries ) { + if ( this.createInterpolant === undefined ) { - geometry = Geometries[ data.type ].fromJSON( data, shapes ); + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { - } else { + this.setInterpolation( this.DefaultInterpolation ); - console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); + } else { - } + throw new Error( message ); // fatal, in this case } - geometry.uuid = data.uuid; - - if ( data.name !== undefined ) geometry.name = data.name; - if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData; - - geometries[ data.uuid ] = geometry; - } - } - - return geometries; + console.warn( 'THREE.KeyframeTrack:', message ); + return this; - } + } - parseMaterials( json, textures ) { + this.createInterpolant = factoryMethod; - const cache = {}; // MultiMaterial - const materials = {}; + return this; - if ( json !== undefined ) { + } - const loader = new MaterialLoader(); - loader.setTextures( textures ); + getInterpolation() { - for ( let i = 0, l = json.length; i < l; i ++ ) { + switch ( this.createInterpolant ) { - const data = json[ i ]; + case this.InterpolantFactoryMethodDiscrete: - if ( cache[ data.uuid ] === undefined ) { + return InterpolateDiscrete; - cache[ data.uuid ] = loader.parse( data ); + case this.InterpolantFactoryMethodLinear: - } + return InterpolateLinear; - materials[ data.uuid ] = cache[ data.uuid ]; + case this.InterpolantFactoryMethodSmooth: - } + return InterpolateSmooth; } - return materials; - } - parseAnimations( json ) { + getValueSize() { - const animations = {}; + return this.values.length / this.times.length; - if ( json !== undefined ) { + } - for ( let i = 0; i < json.length; i ++ ) { + // move all keyframes either forwards or backwards in time + shift( timeOffset ) { - const data = json[ i ]; + if ( timeOffset !== 0.0 ) { - const clip = AnimationClip.parse( data ); + const times = this.times; - animations[ clip.uuid ] = clip; + for ( let i = 0, n = times.length; i !== n; ++ i ) { + + times[ i ] += timeOffset; } } - return animations; + return this; } - parseImages( json, onLoad ) { - - const scope = this; - const images = {}; + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale( timeScale ) { - let loader; + if ( timeScale !== 1.0 ) { - function loadImage( url ) { + const times = this.times; - scope.manager.itemStart( url ); + for ( let i = 0, n = times.length; i !== n; ++ i ) { - return loader.load( url, function () { + times[ i ] *= timeScale; - scope.manager.itemEnd( url ); + } - }, undefined, function () { + } - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + return this; - } ); + } - } + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim( startTime, endTime ) { - function deserializeImage( image ) { + const times = this.times, + nKeys = times.length; - if ( typeof image === 'string' ) { + let from = 0, + to = nKeys - 1; - const url = image; + while ( from !== nKeys && times[ from ] < startTime ) { - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; + ++ from; - return loadImage( path ); + } - } else { + while ( to !== - 1 && times[ to ] > endTime ) { - if ( image.data ) { + -- to; - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; + } - } else { + ++ to; // inclusive -> exclusive bound - return null; + if ( from !== 0 || to !== nKeys ) { - } + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) { + + to = Math.max( to, 1 ); + from = to - 1; } + const stride = this.getValueSize(); + this.times = arraySlice( times, from, to ); + this.values = arraySlice( this.values, from * stride, to * stride ); + } - if ( json !== undefined && json.length > 0 ) { + return this; - const manager = new LoadingManager( onLoad ); + } - loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + validate() { - for ( let i = 0, il = json.length; i < il; i ++ ) { + let valid = true; - const image = json[ i ]; - const url = image.url; + const valueSize = this.getValueSize(); + if ( valueSize - Math.floor( valueSize ) !== 0 ) { - if ( Array.isArray( url ) ) { + console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); + valid = false; - // load array of images e.g CubeTexture + } - const imageArray = []; + const times = this.times, + values = this.values, - for ( let j = 0, jl = url.length; j < jl; j ++ ) { + nKeys = times.length; - const currentUrl = url[ j ]; + if ( nKeys === 0 ) { - const deserializedImage = deserializeImage( currentUrl ); + console.error( 'THREE.KeyframeTrack: Track is empty.', this ); + valid = false; - if ( deserializedImage !== null ) { + } - if ( deserializedImage instanceof HTMLImageElement ) { + let prevTime = null; - imageArray.push( deserializedImage ); + for ( let i = 0; i !== nKeys; i ++ ) { - } else { + const currTime = times[ i ]; - // special case: handle array of data textures for cube textures + if ( typeof currTime === 'number' && isNaN( currTime ) ) { - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); + console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); + valid = false; + break; - } + } - } + if ( prevTime !== null && prevTime > currTime ) { - } + console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); + valid = false; + break; - images[ image.uuid ] = new Source( imageArray ); + } - } else { + prevTime = currTime; - // load single image + } - const deserializedImage = deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); + if ( values !== undefined ) { + + if ( isTypedArray( values ) ) { + + for ( let i = 0, n = values.length; i !== n; ++ i ) { + + const value = values[ i ]; + + if ( isNaN( value ) ) { + + console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); + valid = false; + break; + } } @@ -52211,4645 +83772,4659 @@ var app = (function () { } - return images; + return valid; } - async parseImagesAsync( json ) { + // removes equivalent sequential keys as common in morph target sequences + // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) + optimize() { - const scope = this; - const images = {}; + // times or values may be shared with other tracks, so overwriting is unsafe + const times = arraySlice( this.times ), + values = arraySlice( this.values ), + stride = this.getValueSize(), - let loader; + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - async function deserializeImage( image ) { + lastIndex = times.length - 1; - if ( typeof image === 'string' ) { + let writeIndex = 1; - const url = image; + for ( let i = 1; i < lastIndex; ++ i ) { - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; + let keep = false; - return await loader.loadAsync( path ); + const time = times[ i ]; + const timeNext = times[ i + 1 ]; - } else { + // remove adjacent keyframes scheduled at the same time - if ( image.data ) { + if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; + if ( ! smoothInterpolation ) { - } else { + // remove unnecessary keyframes same as their neighbors - return null; + const offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; - } + for ( let j = 0; j !== stride; ++ j ) { - } + const value = values[ offset + j ]; - } + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { - if ( json !== undefined && json.length > 0 ) { + keep = true; + break; - loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); + } - for ( let i = 0, il = json.length; i < il; i ++ ) { + } - const image = json[ i ]; - const url = image.url; + } else { - if ( Array.isArray( url ) ) { + keep = true; - // load array of images e.g CubeTexture + } - const imageArray = []; + } - for ( let j = 0, jl = url.length; j < jl; j ++ ) { + // in-place compaction - const currentUrl = url[ j ]; + if ( keep ) { - const deserializedImage = await deserializeImage( currentUrl ); + if ( i !== writeIndex ) { - if ( deserializedImage !== null ) { + times[ writeIndex ] = times[ i ]; - if ( deserializedImage instanceof HTMLImageElement ) { + const readOffset = i * stride, + writeOffset = writeIndex * stride; - imageArray.push( deserializedImage ); + for ( let j = 0; j !== stride; ++ j ) { - } else { + values[ writeOffset + j ] = values[ readOffset + j ]; - // special case: handle array of data textures for cube textures + } - imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); + } - } + ++ writeIndex; - } + } - } + } - images[ image.uuid ] = new Source( imageArray ); + // flush last keyframe (compaction looks ahead) - } else { + if ( lastIndex > 0 ) { - // load single image + times[ writeIndex ] = times[ lastIndex ]; - const deserializedImage = await deserializeImage( image.url ); - images[ image.uuid ] = new Source( deserializedImage ); + for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - } + values[ writeOffset + j ] = values[ readOffset + j ]; } - } - - return images; - - } + ++ writeIndex; - parseTextures( json, images ) { + } - function parseConstant( value, type ) { + if ( writeIndex !== times.length ) { - if ( typeof value === 'number' ) return value; + this.times = arraySlice( times, 0, writeIndex ); + this.values = arraySlice( values, 0, writeIndex * stride ); - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + } else { - return type[ value ]; + this.times = times; + this.values = values; } - const textures = {}; - - if ( json !== undefined ) { + return this; - for ( let i = 0, l = json.length; i < l; i ++ ) { + } - const data = json[ i ]; + clone() { - if ( data.image === undefined ) { + const times = arraySlice( this.times, 0 ); + const values = arraySlice( this.values, 0 ); - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + const TypedKeyframeTrack = this.constructor; + const track = new TypedKeyframeTrack( this.name, times, values ); - } + // Interpolant argument to constructor is not saved, so copy the factory method directly. + track.createInterpolant = this.createInterpolant; - if ( images[ data.image ] === undefined ) { + return track; - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + } - } + } - const source = images[ data.image ]; - const image = source.data; + KeyframeTrack.prototype.TimeBufferType = Float32Array; + KeyframeTrack.prototype.ValueBufferType = Float32Array; + KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; - let texture; + /** + * A Track of Boolean keyframe values. + */ + class BooleanKeyframeTrack extends KeyframeTrack {} - if ( Array.isArray( image ) ) { + BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; + BooleanKeyframeTrack.prototype.ValueBufferType = Array; + BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; + BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; + BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - texture = new CubeTexture(); + /** + * A Track of keyframe values that represent color. + */ + class ColorKeyframeTrack extends KeyframeTrack {} - if ( image.length === 6 ) texture.needsUpdate = true; + ColorKeyframeTrack.prototype.ValueTypeName = 'color'; - } else { + /** + * A Track of numeric keyframe values. + */ + class NumberKeyframeTrack extends KeyframeTrack {} - if ( image && image.data ) { + NumberKeyframeTrack.prototype.ValueTypeName = 'number'; - texture = new DataTexture(); + /** + * Spherical linear unit quaternion interpolant. + */ - } else { + class QuaternionLinearInterpolant extends Interpolant { - texture = new Texture(); + constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - } + super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - if ( image ) texture.needsUpdate = true; // textures can have undefined image data + } - } + interpolate_( i1, t0, t, t1 ) { - texture.source = source; + const result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - texture.uuid = data.uuid; + alpha = ( t - t0 ) / ( t1 - t0 ); - if ( data.name !== undefined ) texture.name = data.name; + let offset = i1 * stride; - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); + for ( let end = offset + stride; offset !== end; offset += 4 ) { - if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); - if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); - if ( data.center !== undefined ) texture.center.fromArray( data.center ); - if ( data.rotation !== undefined ) texture.rotation = data.rotation; + Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); - if ( data.wrap !== undefined ) { + } - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); + return result; - } + } - if ( data.format !== undefined ) texture.format = data.format; - if ( data.type !== undefined ) texture.type = data.type; - if ( data.encoding !== undefined ) texture.encoding = data.encoding; + } - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + /** + * A Track of quaternion keyframe values. + */ + class QuaternionKeyframeTrack extends KeyframeTrack { - if ( data.flipY !== undefined ) texture.flipY = data.flipY; + InterpolantFactoryMethodLinear( result ) { - if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; - if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; + return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); - if ( data.userData !== undefined ) texture.userData = data.userData; + } - textures[ data.uuid ] = texture; + } - } + QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; + // ValueBufferType is inherited + QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; + QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - } + /** + * A Track that interpolates Strings + */ + class StringKeyframeTrack extends KeyframeTrack {} - return textures; + StringKeyframeTrack.prototype.ValueTypeName = 'string'; + StringKeyframeTrack.prototype.ValueBufferType = Array; + StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; + StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; + StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - } + /** + * A Track of vectored keyframe values. + */ + class VectorKeyframeTrack extends KeyframeTrack {} - parseObject( data, geometries, materials, textures, animations ) { + VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; - let object; + class AnimationClip { - function getGeometry( name ) { + constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) { - if ( geometries[ name ] === undefined ) { + this.name = name; + this.tracks = tracks; + this.duration = duration; + this.blendMode = blendMode; - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + this.uuid = generateUUID(); - } + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { - return geometries[ name ]; + this.resetDuration(); } - function getMaterial( name ) { + } - if ( name === undefined ) return undefined; - if ( Array.isArray( name ) ) { + static parse( json ) { - const array = []; + const tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); - for ( let i = 0, l = name.length; i < l; i ++ ) { + for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { - const uuid = name[ i ]; + tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); - if ( materials[ uuid ] === undefined ) { + } - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + const clip = new this( json.name, json.duration, tracks, json.blendMode ); + clip.uuid = json.uuid; - } + return clip; - array.push( materials[ uuid ] ); + } - } + static toJSON( clip ) { - return array; + const tracks = [], + clipTracks = clip.tracks; - } + const json = { - if ( materials[ name ] === undefined ) { + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks, + 'uuid': clip.uuid, + 'blendMode': clip.blendMode - console.warn( 'THREE.ObjectLoader: Undefined material', name ); + }; - } + for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { - return materials[ name ]; + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); } - function getTexture( uuid ) { + return json; - if ( textures[ uuid ] === undefined ) { + } - console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); + static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { - } + const numMorphTargets = morphTargetSequence.length; + const tracks = []; - return textures[ uuid ]; + for ( let i = 0; i < numMorphTargets; i ++ ) { - } + let times = []; + let values = []; - let geometry, material; + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); - switch ( data.type ) { + values.push( 0, 1, 0 ); - case 'Scene': + const order = getKeyframeOrder( times ); + times = sortedArray( times, 1, order ); + values = sortedArray( values, 1, order ); - object = new Scene(); + // if there is a key at the first frame, duplicate it as the + // last frame as well for perfect loop. + if ( ! noLoop && times[ 0 ] === 0 ) { - if ( data.background !== undefined ) { + times.push( numMorphTargets ); + values.push( values[ 0 ] ); - if ( Number.isInteger( data.background ) ) { + } - object.background = new Color( data.background ); + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); - } else { + } - object.background = getTexture( data.background ); + return new this( name, - 1, tracks ); - } + } - } + static findByName( objectOrClipArray, name ) { - if ( data.environment !== undefined ) { + let clipArray = objectOrClipArray; - object.environment = getTexture( data.environment ); + if ( ! Array.isArray( objectOrClipArray ) ) { - } + const o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; - if ( data.fog !== undefined ) { + } - if ( data.fog.type === 'Fog' ) { + for ( let i = 0; i < clipArray.length; i ++ ) { - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); + if ( clipArray[ i ].name === name ) { - } else if ( data.fog.type === 'FogExp2' ) { + return clipArray[ i ]; - object.fog = new FogExp2( data.fog.color, data.fog.density ); + } - } + } - } + return null; - break; - - case 'PerspectiveCamera': - - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + } - if ( data.focus !== undefined ) object.focus = data.focus; - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; - if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { - break; + const animationToMorphTargets = {}; - case 'OrthographicCamera': + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + const pattern = /^([\w-]*?)([\d]+)$/; - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + // sort morph target names into animation groups based + // patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + const morphTarget = morphTargets[ i ]; + const parts = morphTarget.name.match( pattern ); - break; + if ( parts && parts.length > 1 ) { - case 'AmbientLight': + const name = parts[ 1 ]; - object = new AmbientLight( data.color, data.intensity ); + let animationMorphTargets = animationToMorphTargets[ name ]; - break; + if ( ! animationMorphTargets ) { - case 'DirectionalLight': + animationToMorphTargets[ name ] = animationMorphTargets = []; - object = new DirectionalLight( data.color, data.intensity ); + } - break; + animationMorphTargets.push( morphTarget ); - case 'PointLight': + } - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + } - break; + const clips = []; - case 'RectAreaLight': + for ( const name in animationToMorphTargets ) { - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - break; + } - case 'SpotLight': + return clips; - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); + } - break; + // parse the animation.hierarchy format + static parseAnimation( animation, bones ) { - case 'HemisphereLight': + if ( ! animation ) { - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); + return null; - break; + } - case 'LightProbe': + const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - object = new LightProbe().fromJSON( data ); + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { - break; + const times = []; + const values = []; - case 'SkinnedMesh': + flattenJSON( animationKeys, times, values, propertyName ); - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { - object = new SkinnedMesh( geometry, material ); + destTracks.push( new trackType( trackName, times, values ) ); - if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; - if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); - if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; + } - break; + } - case 'Mesh': + }; - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); + const tracks = []; - object = new Mesh( geometry, material ); + const clipName = animation.name || 'default'; + const fps = animation.fps || 30; + const blendMode = animation.blendMode; - break; + // automatic length determination in AnimationClip. + let duration = animation.length || - 1; - case 'InstancedMesh': + const hierarchyTracks = animation.hierarchy || []; - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - const count = data.count; - const instanceMatrix = data.instanceMatrix; - const instanceColor = data.instanceColor; + for ( let h = 0; h < hierarchyTracks.length; h ++ ) { - object = new InstancedMesh( geometry, material, count ); - object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); - if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); + const animationKeys = hierarchyTracks[ h ].keys; - break; + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) continue; - case 'LOD': + // process morph targets + if ( animationKeys[ 0 ].morphTargets ) { - object = new LOD(); + // figure out all morph targets used in this track + const morphTargetNames = {}; - break; + let k; - case 'Line': + for ( k = 0; k < animationKeys.length; k ++ ) { - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); + if ( animationKeys[ k ].morphTargets ) { - break; + for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - case 'LineLoop': + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + } - break; + } - case 'LineSegments': + } - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + // create a track for each morph target with all zero + // morphTargetInfluences except for the keys in which + // the morphTarget is named. + for ( const morphTargetName in morphTargetNames ) { - break; + const times = []; + const values = []; - case 'PointCloud': - case 'Points': + for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + const animationKey = animationKeys[ k ]; - break; + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - case 'Sprite': + } - object = new Sprite( getMaterial( data.material ) ); + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - break; + } - case 'Group': + duration = morphTargetNames.length * fps; - object = new Group(); + } else { - break; + // ...assume skeletal animation - case 'Bone': + const boneName = '.bones[' + bones[ h ].name + ']'; - object = new Bone(); + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); - break; + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); - default: + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); - object = new Object3D(); + } } - object.uuid = data.uuid; + if ( tracks.length === 0 ) { - if ( data.name !== undefined ) object.name = data.name; + return null; - if ( data.matrix !== undefined ) { + } - object.matrix.fromArray( data.matrix ); + const clip = new this( clipName, duration, tracks, blendMode ); - if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; - if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); + return clip; - } else { + } - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + resetDuration() { - } + const tracks = this.tracks; + let duration = 0; - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + for ( let i = 0, n = tracks.length; i !== n; ++ i ) { - if ( data.shadow ) { + const track = this.tracks[ i ]; - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); } - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; - if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; - if ( data.userData !== undefined ) object.userData = data.userData; - if ( data.layers !== undefined ) object.layers.mask = data.layers; + this.duration = duration; - if ( data.children !== undefined ) { + return this; - const children = data.children; + } - for ( let i = 0; i < children.length; i ++ ) { + trim() { - object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); + for ( let i = 0; i < this.tracks.length; i ++ ) { - } + this.tracks[ i ].trim( 0, this.duration ); } - if ( data.animations !== undefined ) { + return this; - const objectAnimations = data.animations; + } - for ( let i = 0; i < objectAnimations.length; i ++ ) { + validate() { - const uuid = objectAnimations[ i ]; + let valid = true; - object.animations.push( animations[ uuid ] ); + for ( let i = 0; i < this.tracks.length; i ++ ) { - } + valid = valid && this.tracks[ i ].validate(); } - if ( data.type === 'LOD' ) { - - if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; - - const levels = data.levels; - - for ( let l = 0; l < levels.length; l ++ ) { - - const level = levels[ l ]; - const child = object.getObjectByProperty( 'uuid', level.object ); + return valid; - if ( child !== undefined ) { + } - object.addLevel( child, level.distance ); + optimize() { - } + for ( let i = 0; i < this.tracks.length; i ++ ) { - } + this.tracks[ i ].optimize(); } - return object; + return this; } - bindSkeletons( object, skeletons ) { - - if ( Object.keys( skeletons ).length === 0 ) return; - - object.traverse( function ( child ) { - - if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { + clone() { - const skeleton = skeletons[ child.skeleton ]; + const tracks = []; - if ( skeleton === undefined ) { + for ( let i = 0; i < this.tracks.length; i ++ ) { - console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); + tracks.push( this.tracks[ i ].clone() ); - } else { + } - child.bind( skeleton, child.bindMatrix ); + return new this.constructor( this.name, this.duration, tracks, this.blendMode ); - } + } - } + toJSON() { - } ); + return this.constructor.toJSON( this ); } } - const TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping - }; + function getTrackTypeForValueTypeName( typeName ) { - const TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping - }; + switch ( typeName.toLowerCase() ) { - const TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipmapNearestFilter: NearestMipmapNearestFilter, - NearestMipmapLinearFilter: NearestMipmapLinearFilter, - LinearFilter: LinearFilter, - LinearMipmapNearestFilter: LinearMipmapNearestFilter, - LinearMipmapLinearFilter: LinearMipmapLinearFilter - }; + case 'scalar': + case 'double': + case 'float': + case 'number': + case 'integer': - class ImageBitmapLoader extends Loader { + return NumberKeyframeTrack; - constructor( manager ) { + case 'vector': + case 'vector2': + case 'vector3': + case 'vector4': - super( manager ); + return VectorKeyframeTrack; - this.isImageBitmapLoader = true; + case 'color': - if ( typeof createImageBitmap === 'undefined' ) { + return ColorKeyframeTrack; - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); + case 'quaternion': - } + return QuaternionKeyframeTrack; - if ( typeof fetch === 'undefined' ) { + case 'bool': + case 'boolean': - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); + return BooleanKeyframeTrack; - } + case 'string': - this.options = { premultiplyAlpha: 'none' }; + return StringKeyframeTrack; } - setOptions( options ) { + throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - this.options = options; + } - return this; + function parseKeyframeTrack( json ) { + + if ( json.type === undefined ) { + + throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); } - load( url, onLoad, onProgress, onError ) { + const trackType = getTrackTypeForValueTypeName( json.type ); - if ( url === undefined ) url = ''; + if ( json.times === undefined ) { - if ( this.path !== undefined ) url = this.path + url; + const times = [], values = []; - url = this.manager.resolveURL( url ); + flattenJSON( json.keys, times, values, 'value' ); - const scope = this; + json.times = times; + json.values = values; - const cached = Cache.get( url ); + } - if ( cached !== undefined ) { + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { - scope.manager.itemStart( url ); + return trackType.parse( json ); - setTimeout( function () { + } else { - if ( onLoad ) onLoad( cached ); + // by default, we assume a constructor compatible with the base + return new trackType( json.name, json.times, json.values, json.interpolation ); - scope.manager.itemEnd( url ); + } - }, 0 ); + } - return cached; + const Cache = { - } + enabled: false, - const fetchOptions = {}; - fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; - fetchOptions.headers = this.requestHeader; + files: {}, - fetch( url, fetchOptions ).then( function ( res ) { + add: function ( key, file ) { - return res.blob(); + if ( this.enabled === false ) return; - } ).then( function ( blob ) { + // console.log( 'THREE.Cache', 'Adding key:', key ); - return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); + this.files[ key ] = file; - } ).then( function ( imageBitmap ) { + }, - Cache.add( url, imageBitmap ); + get: function ( key ) { - if ( onLoad ) onLoad( imageBitmap ); + if ( this.enabled === false ) return; - scope.manager.itemEnd( url ); + // console.log( 'THREE.Cache', 'Checking key:', key ); - } ).catch( function ( e ) { + return this.files[ key ]; - if ( onError ) onError( e ); + }, - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + remove: function ( key ) { - } ); + delete this.files[ key ]; - scope.manager.itemStart( url ); + }, - } + clear: function () { - } + this.files = {}; - let _context; + } - const AudioContext = { + }; - getContext: function () { + class LoadingManager { - if ( _context === undefined ) { + constructor( onLoad, onProgress, onError ) { - _context = new ( window.AudioContext || window.webkitAudioContext )(); + const scope = this; - } + let isLoading = false; + let itemsLoaded = 0; + let itemsTotal = 0; + let urlModifier = undefined; + const handlers = []; - return _context; + // Refer to #5689 for the reason why we don't set .onStart + // in the constructor - }, + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; - setContext: function ( value ) { + this.itemStart = function ( url ) { - _context = value; + itemsTotal ++; - } + if ( isLoading === false ) { - }; + if ( scope.onStart !== undefined ) { - class AudioLoader extends Loader { + scope.onStart( url, itemsLoaded, itemsTotal ); - constructor( manager ) { + } - super( manager ); + } - } + isLoading = true; - load( url, onLoad, onProgress, onError ) { + }; - const scope = this; + this.itemEnd = function ( url ) { - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( buffer ) { + itemsLoaded ++; - try { + if ( scope.onProgress !== undefined ) { - // Create a copy of the buffer. The `decodeAudioData` method - // detaches the buffer when complete, preventing reuse. - const bufferCopy = buffer.slice( 0 ); + scope.onProgress( url, itemsLoaded, itemsTotal ); - const context = AudioContext.getContext(); - context.decodeAudioData( bufferCopy, function ( audioBuffer ) { + } - onLoad( audioBuffer ); + if ( itemsLoaded === itemsTotal ) { - } ); + isLoading = false; - } catch ( e ) { + if ( scope.onLoad !== undefined ) { - if ( onError ) { + scope.onLoad(); - onError( e ); + } - } else { + } - console.error( e ); + }; - } + this.itemError = function ( url ) { - scope.manager.itemError( url ); + if ( scope.onError !== undefined ) { + + scope.onError( url ); } - }, onProgress, onError ); + }; - } + this.resolveURL = function ( url ) { - } + if ( urlModifier ) { - class HemisphereLightProbe extends LightProbe { + return urlModifier( url ); - constructor( skyColor, groundColor, intensity = 1 ) { + } - super( undefined, intensity ); + return url; - this.isHemisphereLightProbe = true; + }; - const color1 = new Color().set( skyColor ); - const color2 = new Color().set( groundColor ); + this.setURLModifier = function ( transform ) { - const sky = new Vector3( color1.r, color1.g, color1.b ); - const ground = new Vector3( color2.r, color2.g, color2.b ); + urlModifier = transform; - // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI ); - const c0 = Math.sqrt( Math.PI ); - const c1 = c0 * Math.sqrt( 0.75 ); + return this; - this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 ); - this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 ); + }; - } + this.addHandler = function ( regex, loader ) { - } + handlers.push( regex, loader ); - class AmbientLightProbe extends LightProbe { + return this; - constructor( color, intensity = 1 ) { + }; - super( undefined, intensity ); + this.removeHandler = function ( regex ) { - this.isAmbientLightProbe = true; + const index = handlers.indexOf( regex ); - const color1 = new Color().set( color ); + if ( index !== - 1 ) { - // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI ); - this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) ); + handlers.splice( index, 2 ); - } + } - } + return this; - const _eyeRight = /*@__PURE__*/ new Matrix4(); - const _eyeLeft = /*@__PURE__*/ new Matrix4(); - const _projectionMatrix = /*@__PURE__*/ new Matrix4(); + }; - class StereoCamera { + this.getHandler = function ( file ) { - constructor() { + for ( let i = 0, l = handlers.length; i < l; i += 2 ) { - this.type = 'StereoCamera'; + const regex = handlers[ i ]; + const loader = handlers[ i + 1 ]; - this.aspect = 1; + if ( regex.global ) regex.lastIndex = 0; // see #17920 - this.eyeSep = 0.064; + if ( regex.test( file ) ) { - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; + return loader; - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; + } + + } + + return null; - this._cache = { - focus: null, - fov: null, - aspect: null, - near: null, - far: null, - zoom: null, - eyeSep: null }; } - update( camera ) { + } - const cache = this._cache; + const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); - const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || - cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || - cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; + class Loader { - if ( needsUpdate ) { + constructor( manager ) { - cache.focus = camera.focus; - cache.fov = camera.fov; - cache.aspect = camera.aspect * this.aspect; - cache.near = camera.near; - cache.far = camera.far; - cache.zoom = camera.zoom; - cache.eyeSep = this.eyeSep; + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ + this.crossOrigin = 'anonymous'; + this.withCredentials = false; + this.path = ''; + this.resourcePath = ''; + this.requestHeader = {}; - _projectionMatrix.copy( camera.projectionMatrix ); - const eyeSepHalf = cache.eyeSep / 2; - const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; - const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; - let xmin, xmax; + } - // translate xOffset + load( /* url, onLoad, onProgress, onError */ ) {} - _eyeLeft.elements[ 12 ] = - eyeSepHalf; - _eyeRight.elements[ 12 ] = eyeSepHalf; + loadAsync( url, onProgress ) { - // for left eye + const scope = this; - xmin = - ymax * cache.aspect + eyeSepOnProjection; - xmax = ymax * cache.aspect + eyeSepOnProjection; + return new Promise( function ( resolve, reject ) { - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + scope.load( url, resolve, onProgress, reject ); - this.cameraL.projectionMatrix.copy( _projectionMatrix ); + } ); - // for right eye + } - xmin = - ymax * cache.aspect - eyeSepOnProjection; - xmax = ymax * cache.aspect - eyeSepOnProjection; + parse( /* data */ ) {} - _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + setCrossOrigin( crossOrigin ) { - this.cameraR.projectionMatrix.copy( _projectionMatrix ); + this.crossOrigin = crossOrigin; + return this; - } + } - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); + setWithCredentials( value ) { + + this.withCredentials = value; + return this; } - } + setPath( path ) { - class Clock { + this.path = path; + return this; - constructor( autoStart = true ) { + } - this.autoStart = autoStart; + setResourcePath( resourcePath ) { - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; + this.resourcePath = resourcePath; + return this; - this.running = false; + } + + setRequestHeader( requestHeader ) { + + this.requestHeader = requestHeader; + return this; } - start() { + } - this.startTime = now(); + const loading = {}; - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; + class HttpError extends Error { + + constructor( message, response ) { + + super( message ); + this.response = response; } - stop() { + } - this.getElapsedTime(); - this.running = false; - this.autoStart = false; + class FileLoader extends Loader { + + constructor( manager ) { + + super( manager ); } - getElapsedTime() { + load( url, onLoad, onProgress, onError ) { - this.getDelta(); - return this.elapsedTime; + if ( url === undefined ) url = ''; - } + if ( this.path !== undefined ) url = this.path + url; - getDelta() { + url = this.manager.resolveURL( url ); - let diff = 0; + const cached = Cache.get( url ); - if ( this.autoStart && ! this.running ) { + if ( cached !== undefined ) { - this.start(); - return 0; + this.manager.itemStart( url ); - } + setTimeout( () => { - if ( this.running ) { + if ( onLoad ) onLoad( cached ); - const newTime = now(); + this.manager.itemEnd( url ); - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; + }, 0 ); - this.elapsedTime += diff; + return cached; } - return diff; + // Check if request is duplicate - } + if ( loading[ url ] !== undefined ) { - } + loading[ url ].push( { - function now() { + onLoad: onLoad, + onProgress: onProgress, + onError: onError - return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 + } ); - } + return; - const _position$1 = /*@__PURE__*/ new Vector3(); - const _quaternion$1 = /*@__PURE__*/ new Quaternion(); - const _scale$1 = /*@__PURE__*/ new Vector3(); - const _orientation$1 = /*@__PURE__*/ new Vector3(); + } - class AudioListener extends Object3D { + // Initialise array for duplicate requests + loading[ url ] = []; - constructor() { + loading[ url ].push( { + onLoad: onLoad, + onProgress: onProgress, + onError: onError, + } ); - super(); + // create request + const req = new Request( url, { + headers: new Headers( this.requestHeader ), + credentials: this.withCredentials ? 'include' : 'same-origin', + // An abort controller could be added within a future PR + } ); - this.type = 'AudioListener'; + // record states ( avoid data race ) + const mimeType = this.mimeType; + const responseType = this.responseType; - this.context = AudioContext.getContext(); + // start the fetch + fetch( req ) + .then( response => { - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); + if ( response.status === 200 || response.status === 0 ) { - this.filter = null; + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. - this.timeDelta = 0; + if ( response.status === 0 ) { - // private + console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); - this._clock = new Clock(); + } - } + // Workaround: Checking if response.body === undefined for Alipay browser #23548 - getInput() { + if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { - return this.gain; + return response; - } + } - removeFilter() { + const callbacks = loading[ url ]; + const reader = response.body.getReader(); + const contentLength = response.headers.get( 'Content-Length' ); + const total = contentLength ? parseInt( contentLength ) : 0; + const lengthComputable = total !== 0; + let loaded = 0; - if ( this.filter !== null ) { + // periodically read data into the new stream tracking while download progress + const stream = new ReadableStream( { + start( controller ) { - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; + readData(); - } + function readData() { - return this; + reader.read().then( ( { done, value } ) => { - } + if ( done ) { - getFilter() { + controller.close(); - return this.filter; + } else { - } + loaded += value.byteLength; - setFilter( value ) { + const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - if ( this.filter !== null ) { + const callback = callbacks[ i ]; + if ( callback.onProgress ) callback.onProgress( event ); - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); + } - } else { + controller.enqueue( value ); + readData(); - this.gain.disconnect( this.context.destination ); + } - } + } ); - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); + } - return this; + } - } + } ); - getMasterVolume() { + return new Response( stream ); - return this.gain.gain.value; + } else { - } + throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); - setMasterVolume( value ) { + } - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + } ) + .then( response => { - return this; + switch ( responseType ) { - } + case 'arraybuffer': - updateMatrixWorld( force ) { + return response.arrayBuffer(); - super.updateMatrixWorld( force ); + case 'blob': - const listener = this.context.listener; - const up = this.up; + return response.blob(); - this.timeDelta = this._clock.getDelta(); + case 'document': - this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); + return response.text() + .then( text => { - _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); + const parser = new DOMParser(); + return parser.parseFromString( text, mimeType ); - if ( listener.positionX ) { + } ); - // code path for Chrome (see #14393) + case 'json': - const endTime = this.context.currentTime + this.timeDelta; + return response.json(); - listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); - listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); - listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); - listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); - listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); - listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); - listener.upX.linearRampToValueAtTime( up.x, endTime ); - listener.upY.linearRampToValueAtTime( up.y, endTime ); - listener.upZ.linearRampToValueAtTime( up.z, endTime ); + default: - } else { + if ( mimeType === undefined ) { - listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); - listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); + return response.text(); - } + } else { - } + // sniff encoding + const re = /charset="?([^;"\s]*)"?/i; + const exec = re.exec( mimeType ); + const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; + const decoder = new TextDecoder( label ); + return response.arrayBuffer().then( ab => decoder.decode( ab ) ); - } + } - class Audio extends Object3D { + } - constructor( listener ) { + } ) + .then( data => { - super(); + // Add to cache only on HTTP success, so that we do not cache + // error response bodies as proper responses to requests. + Cache.add( url, data ); - this.type = 'Audio'; + const callbacks = loading[ url ]; + delete loading[ url ]; - this.listener = listener; - this.context = listener.context; + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); + const callback = callbacks[ i ]; + if ( callback.onLoad ) callback.onLoad( data ); - this.autoplay = false; + } - this.buffer = null; - this.detune = 0; - this.loop = false; - this.loopStart = 0; - this.loopEnd = 0; - this.offset = 0; - this.duration = undefined; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.source = null; - this.sourceType = 'empty'; + } ) + .catch( err => { - this._startedAt = 0; - this._progress = 0; - this._connected = false; + // Abort errors and other errors are handled the same - this.filters = []; + const callbacks = loading[ url ]; - } + if ( callbacks === undefined ) { - getOutput() { + // When onLoad was called and url was deleted in `loading` + this.manager.itemError( url ); + throw err; - return this.gain; + } - } + delete loading[ url ]; - setNodeSource( audioNode ) { + for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); + const callback = callbacks[ i ]; + if ( callback.onError ) callback.onError( err ); - return this; + } - } + this.manager.itemError( url ); - setMediaElementSource( mediaElement ) { + } ) + .finally( () => { - this.hasPlaybackControl = false; - this.sourceType = 'mediaNode'; - this.source = this.context.createMediaElementSource( mediaElement ); - this.connect(); + this.manager.itemEnd( url ); - return this; + } ); - } + this.manager.itemStart( url ); - setMediaStreamSource( mediaStream ) { + } - this.hasPlaybackControl = false; - this.sourceType = 'mediaStreamNode'; - this.source = this.context.createMediaStreamSource( mediaStream ); - this.connect(); + setResponseType( value ) { + this.responseType = value; return this; } - setBuffer( audioBuffer ) { - - this.buffer = audioBuffer; - this.sourceType = 'buffer'; - - if ( this.autoplay ) this.play(); + setMimeType( value ) { + this.mimeType = value; return this; } - play( delay = 0 ) { + } - if ( this.isPlaying === true ) { + class AnimationLoader extends Loader { - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; + constructor( manager ) { - } + super( manager ); - if ( this.hasPlaybackControl === false ) { + } - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + load( url, onLoad, onProgress, onError ) { - } + const scope = this; - this._startedAt = this.context.currentTime + delay; + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { - const source = this.context.createBufferSource(); - source.buffer = this.buffer; - source.loop = this.loop; - source.loopStart = this.loopStart; - source.loopEnd = this.loopEnd; - source.onended = this.onEnded.bind( this ); - source.start( this._startedAt, this._progress + this.offset, this.duration ); + try { - this.isPlaying = true; + onLoad( scope.parse( JSON.parse( text ) ) ); - this.source = source; + } catch ( e ) { - this.setDetune( this.detune ); - this.setPlaybackRate( this.playbackRate ); + if ( onError ) { - return this.connect(); + onError( e ); - } + } else { - pause() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + console.error( e ); - } + } - if ( this.isPlaying === true ) { + scope.manager.itemError( url ); - // update current progress + } - this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; + }, onProgress, onError ); - if ( this.loop === true ) { + } - // ensure _progress does not exceed duration with looped audios + parse( json ) { - this._progress = this._progress % ( this.duration || this.buffer.duration ); + const animations = []; - } + for ( let i = 0; i < json.length; i ++ ) { - this.source.stop(); - this.source.onended = null; + const clip = AnimationClip.parse( json[ i ] ); - this.isPlaying = false; + animations.push( clip ); } - return this; + return animations; } - stop() { + } - if ( this.hasPlaybackControl === false ) { + /** + * Abstract Base class to block based textures loader (dds, pvr, ...) + * + * Sub classes have to implement the parse() method which will be used in load(). + */ - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + class CompressedTextureLoader extends Loader { - } + constructor( manager ) { - this._progress = 0; + super( manager ); - this.source.stop(); - this.source.onended = null; - this.isPlaying = false; + } - return this; + load( url, onLoad, onProgress, onError ) { - } + const scope = this; - connect() { + const images = []; - if ( this.filters.length > 0 ) { + const texture = new CompressedTexture(); - this.source.connect( this.filters[ 0 ] ); + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { + let loaded = 0; - this.filters[ i - 1 ].connect( this.filters[ i ] ); + function loadTexture( i ) { - } + loader.load( url[ i ], function ( buffer ) { - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); + const texDatas = scope.parse( buffer, true ); - } else { + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; - this.source.connect( this.getOutput() ); + loaded += 1; - } + if ( loaded === 6 ) { - this._connected = true; + if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; - return this; + texture.image = images; + texture.format = texDatas.format; + texture.needsUpdate = true; - } + if ( onLoad ) onLoad( texture ); - disconnect() { + } - if ( this.filters.length > 0 ) { + }, onProgress, onError ); - this.source.disconnect( this.filters[ 0 ] ); + } - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { + if ( Array.isArray( url ) ) { - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); + for ( let i = 0, il = url.length; i < il; ++ i ) { - } + loadTexture( i ); - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); + } } else { - this.source.disconnect( this.getOutput() ); - - } + // compressed cubemap texture stored in a single DDS file - this._connected = false; + loader.load( url, function ( buffer ) { - return this; + const texDatas = scope.parse( buffer, true ); - } + if ( texDatas.isCubemap ) { - getFilters() { + const faces = texDatas.mipmaps.length / texDatas.mipmapCount; - return this.filters; + for ( let f = 0; f < faces; f ++ ) { - } + images[ f ] = { mipmaps: [] }; - setFilters( value ) { + for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { - if ( ! value ) value = []; + images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); + images[ f ].format = texDatas.format; + images[ f ].width = texDatas.width; + images[ f ].height = texDatas.height; - if ( this._connected === true ) { + } - this.disconnect(); - this.filters = value.slice(); - this.connect(); + } - } else { + texture.image = images; - this.filters = value.slice(); + } else { - } + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; - return this; + } - } + if ( texDatas.mipmapCount === 1 ) { - setDetune( value ) { + texture.minFilter = LinearFilter; - this.detune = value; + } - if ( this.source.detune === undefined ) return; // only set detune when available + texture.format = texDatas.format; + texture.needsUpdate = true; - if ( this.isPlaying === true ) { + if ( onLoad ) onLoad( texture ); - this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); + }, onProgress, onError ); } - return this; + return texture; } - getDetune() { - - return this.detune; + } - } + class ImageLoader extends Loader { - getFilter() { + constructor( manager ) { - return this.getFilters()[ 0 ]; + super( manager ); } - setFilter( filter ) { + load( url, onLoad, onProgress, onError ) { - return this.setFilters( filter ? [ filter ] : [] ); + if ( this.path !== undefined ) url = this.path + url; - } + url = this.manager.resolveURL( url ); - setPlaybackRate( value ) { + const scope = this; - if ( this.hasPlaybackControl === false ) { + const cached = Cache.get( url ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + if ( cached !== undefined ) { - } + scope.manager.itemStart( url ); - this.playbackRate = value; + setTimeout( function () { - if ( this.isPlaying === true ) { + if ( onLoad ) onLoad( cached ); - this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); + scope.manager.itemEnd( url ); + + }, 0 ); + + return cached; } - return this; + const image = createElementNS( 'img' ); - } + function onImageLoad() { - getPlaybackRate() { + removeEventListeners(); - return this.playbackRate; + Cache.add( url, this ); - } + if ( onLoad ) onLoad( this ); - onEnded() { + scope.manager.itemEnd( url ); - this.isPlaying = false; + } - } + function onImageError( event ) { - getLoop() { + removeEventListeners(); - if ( this.hasPlaybackControl === false ) { + if ( onError ) onError( event ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); } - return this.loop; + function removeEventListeners() { - } + image.removeEventListener( 'load', onImageLoad, false ); + image.removeEventListener( 'error', onImageError, false ); - setLoop( value ) { + } - if ( this.hasPlaybackControl === false ) { + image.addEventListener( 'load', onImageLoad, false ); + image.addEventListener( 'error', onImageError, false ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + if ( url.slice( 0, 5 ) !== 'data:' ) { + + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; } - this.loop = value; + scope.manager.itemStart( url ); - if ( this.isPlaying === true ) { + image.src = url; - this.source.loop = this.loop; + return image; - } + } - return this; + } + + class CubeTextureLoader extends Loader { + + constructor( manager ) { + + super( manager ); } - setLoopStart( value ) { + load( urls, onLoad, onProgress, onError ) { - this.loopStart = value; + const texture = new CubeTexture(); - return this; + const loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - } + let loaded = 0; - setLoopEnd( value ) { + function loadTexture( i ) { - this.loopEnd = value; + loader.load( urls[ i ], function ( image ) { - return this; + texture.images[ i ] = image; - } + loaded ++; - getVolume() { + if ( loaded === 6 ) { - return this.gain.gain.value; + texture.needsUpdate = true; - } + if ( onLoad ) onLoad( texture ); - setVolume( value ) { + } - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + }, undefined, onError ); - return this; + } + + for ( let i = 0; i < urls.length; ++ i ) { + + loadTexture( i ); + + } + + return texture; } } - const _position = /*@__PURE__*/ new Vector3(); - const _quaternion = /*@__PURE__*/ new Quaternion(); - const _scale = /*@__PURE__*/ new Vector3(); - const _orientation = /*@__PURE__*/ new Vector3(); - - class PositionalAudio extends Audio { + /** + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + * + * Sub classes have to implement the parse() method which will be used in load(). + */ - constructor( listener ) { + class DataTextureLoader extends Loader { - super( listener ); + constructor( manager ) { - this.panner = this.context.createPanner(); - this.panner.panningModel = 'HRTF'; - this.panner.connect( this.gain ); + super( manager ); } - disconnect() { + load( url, onLoad, onProgress, onError ) { - super.disconnect(); + const scope = this; - this.panner.disconnect( this.gain ); + const texture = new DataTexture(); - } + const loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setPath( this.path ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( buffer ) { - getOutput() { + const texData = scope.parse( buffer ); - return this.panner; + if ( ! texData ) return; - } + if ( texData.image !== undefined ) { - getRefDistance() { + texture.image = texData.image; - return this.panner.refDistance; + } else if ( texData.data !== undefined ) { - } + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; - setRefDistance( value ) { + } - this.panner.refDistance = value; + texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; + texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; - return this; + texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; + texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; - } + texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; - getRolloffFactor() { + if ( texData.encoding !== undefined ) { - return this.panner.rolloffFactor; + texture.encoding = texData.encoding; - } + } - setRolloffFactor( value ) { + if ( texData.flipY !== undefined ) { - this.panner.rolloffFactor = value; + texture.flipY = texData.flipY; - return this; + } - } + if ( texData.format !== undefined ) { - getDistanceModel() { + texture.format = texData.format; - return this.panner.distanceModel; + } - } + if ( texData.type !== undefined ) { - setDistanceModel( value ) { + texture.type = texData.type; - this.panner.distanceModel = value; + } - return this; + if ( texData.mipmaps !== undefined ) { - } + texture.mipmaps = texData.mipmaps; + texture.minFilter = LinearMipmapLinearFilter; // presumably... - getMaxDistance() { + } - return this.panner.maxDistance; + if ( texData.mipmapCount === 1 ) { - } + texture.minFilter = LinearFilter; - setMaxDistance( value ) { + } - this.panner.maxDistance = value; + if ( texData.generateMipmaps !== undefined ) { - return this; + texture.generateMipmaps = texData.generateMipmaps; - } + } - setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { + texture.needsUpdate = true; - this.panner.coneInnerAngle = coneInnerAngle; - this.panner.coneOuterAngle = coneOuterAngle; - this.panner.coneOuterGain = coneOuterGain; + if ( onLoad ) onLoad( texture, texData ); - return this; + }, onProgress, onError ); + + + return texture; } - updateMatrixWorld( force ) { + } - super.updateMatrixWorld( force ); + class TextureLoader extends Loader { - if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; + constructor( manager ) { - this.matrixWorld.decompose( _position, _quaternion, _scale ); + super( manager ); - _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); + } - const panner = this.panner; + load( url, onLoad, onProgress, onError ) { - if ( panner.positionX ) { + const texture = new Texture(); - // code path for Chrome and Firefox (see #14393) + const loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - const endTime = this.context.currentTime + this.listener.timeDelta; + loader.load( url, function ( image ) { - panner.positionX.linearRampToValueAtTime( _position.x, endTime ); - panner.positionY.linearRampToValueAtTime( _position.y, endTime ); - panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); - panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); - panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); - panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); + texture.image = image; + texture.needsUpdate = true; - } else { + if ( onLoad !== undefined ) { - panner.setPosition( _position.x, _position.y, _position.z ); - panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); + onLoad( texture ); - } + } + + }, onProgress, onError ); + + return texture; } } - class AudioAnalyser { + class Light extends Object3D { - constructor( audio, fftSize = 2048 ) { + constructor( color, intensity = 1 ) { - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize; + super(); - this.data = new Uint8Array( this.analyser.frequencyBinCount ); + this.isLight = true; - audio.getOutput().connect( this.analyser ); + this.type = 'Light'; + + this.color = new Color( color ); + this.intensity = intensity; } + dispose() { - getFrequencyData() { + // Empty here in base class; some subclasses override. - this.analyser.getByteFrequencyData( this.data ); + } - return this.data; + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.color.copy( source.color ); + this.intensity = source.intensity; + + return this; } - getAverageFrequency() { + toJSON( meta ) { - let value = 0; - const data = this.getFrequencyData(); + const data = super.toJSON( meta ); - for ( let i = 0; i < data.length; i ++ ) { + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; - value += data[ i ]; + if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - } + if ( this.distance !== undefined ) data.object.distance = this.distance; + if ( this.angle !== undefined ) data.object.angle = this.angle; + if ( this.decay !== undefined ) data.object.decay = this.decay; + if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - return value / data.length; + if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + + return data; } } - class PropertyMixer { + class HemisphereLight extends Light { - constructor( binding, typeName, valueSize ) { + constructor( skyColor, groundColor, intensity ) { - this.binding = binding; - this.valueSize = valueSize; + super( skyColor, intensity ); - let mixFunction, - mixFunctionAdditive, - setIdentity; + this.isHemisphereLight = true; - // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] - // - // interpolators can use .buffer as their .result - // the data then goes to 'incoming' - // - // 'accu0' and 'accu1' are used frame-interleaved for - // the cumulative result and are compared to detect - // changes - // - // 'orig' stores the original state of the property - // - // 'add' is used for additive cumulative results - // - // 'work' is optional and is only present for quaternion types. It is used - // to store intermediate quaternion multiplication results + this.type = 'HemisphereLight'; - switch ( typeName ) { + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - case 'quaternion': - mixFunction = this._slerp; - mixFunctionAdditive = this._slerpAdditive; - setIdentity = this._setAdditiveIdentityQuaternion; - - this.buffer = new Float64Array( valueSize * 6 ); - this._workIndex = 5; - break; + this.groundColor = new Color( groundColor ); - case 'string': - case 'bool': - mixFunction = this._select; + } - // Use the regular mix function and for additive on these types, - // additive is not relevant for non-numeric types - mixFunctionAdditive = this._select; + copy( source, recursive ) { - setIdentity = this._setAdditiveIdentityOther; + super.copy( source, recursive ); - this.buffer = new Array( valueSize * 5 ); - break; + this.groundColor.copy( source.groundColor ); - default: - mixFunction = this._lerp; - mixFunctionAdditive = this._lerpAdditive; - setIdentity = this._setAdditiveIdentityNumeric; + return this; - this.buffer = new Float64Array( valueSize * 5 ); + } - } + } - this._mixBufferRegion = mixFunction; - this._mixBufferRegionAdditive = mixFunctionAdditive; - this._setIdentity = setIdentity; - this._origIndex = 3; - this._addIndex = 4; + const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); + const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); + const _lookTarget$1 = /*@__PURE__*/ new Vector3(); - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; + class LightShadow { - this.useCount = 0; - this.referenceCount = 0; + constructor( camera ) { - } + this.camera = camera; - // accumulate data in the 'incoming' region into 'accu' - accumulate( accuIndex, weight ) { + this.bias = 0; + this.normalBias = 0; + this.radius = 1; + this.blurSamples = 8; - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place + this.mapSize = new Vector2( 512, 512 ); - const buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride; + this.map = null; + this.mapPass = null; + this.matrix = new Matrix4(); - let currentWeight = this.cumulativeWeight; + this.autoUpdate = true; + this.needsUpdate = false; - if ( currentWeight === 0 ) { + this._frustum = new Frustum(); + this._frameExtents = new Vector2( 1, 1 ); - // accuN := incoming * weight + this._viewportCount = 1; - for ( let i = 0; i !== stride; ++ i ) { + this._viewports = [ - buffer[ offset + i ] = buffer[ i ]; + new Vector4( 0, 0, 1, 1 ) - } + ]; - currentWeight = weight; + } - } else { + getViewportCount() { - // accuN := accuN + incoming * weight + return this._viewportCount; - currentWeight += weight; - const mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); + } - } + getFrustum() { - this.cumulativeWeight = currentWeight; + return this._frustum; } - // accumulate data in the 'incoming' region into 'add' - accumulateAdditive( weight ) { - - const buffer = this.buffer, - stride = this.valueSize, - offset = stride * this._addIndex; + updateMatrices( light ) { - if ( this.cumulativeWeightAdditive === 0 ) { + const shadowCamera = this.camera; + const shadowMatrix = this.matrix; - // add = identity + _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( _lightPositionWorld$1 ); - this._setIdentity(); + _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _lookTarget$1 ); + shadowCamera.updateMatrixWorld(); - } + _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); - // add := add + incoming * weight + shadowMatrix.set( + 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 + ); - this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); - this.cumulativeWeightAdditive += weight; + shadowMatrix.multiply( _projScreenMatrix$1 ); } - // apply the state of 'accu' to the binding when accus differ - apply( accuIndex ) { + getViewport( viewportIndex ) { - const stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, + return this._viewports[ viewportIndex ]; - weight = this.cumulativeWeight, - weightAdditive = this.cumulativeWeightAdditive, + } - binding = this.binding; + getFrameExtents() { - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; + return this._frameExtents; - if ( weight < 1 ) { + } - // accuN := accuN + original * ( 1 - cumulativeWeight ) + dispose() { - const originalValueOffset = stride * this._origIndex; + if ( this.map ) { - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); + this.map.dispose(); } - if ( weightAdditive > 0 ) { - - // accuN := accuN + additive accuN + if ( this.mapPass ) { - this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); + this.mapPass.dispose(); } - for ( let i = stride, e = stride + stride; i !== e; ++ i ) { + } - if ( buffer[ i ] !== buffer[ i + stride ] ) { + copy( source ) { - // value has changed -> update scene graph + this.camera = source.camera.clone(); - binding.setValue( buffer, offset ); - break; + this.bias = source.bias; + this.radius = source.radius; - } + this.mapSize.copy( source.mapSize ); - } + return this; } - // remember the state of the bound property and copy it to both accus - saveOriginalState() { + clone() { - const binding = this.binding; + return new this.constructor().copy( this ); - const buffer = this.buffer, - stride = this.valueSize, + } - originalValueOffset = stride * this._origIndex; + toJSON() { - binding.getValue( buffer, originalValueOffset ); + const object = {}; - // accu[0..1] := orig -- initially detect changes against the original - for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { + if ( this.bias !== 0 ) object.bias = this.bias; + if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; + if ( this.radius !== 1 ) object.radius = this.radius; + if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; - } + return object; - // Add to identity for additive - this._setIdentity(); + } - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; + } - } + class SpotLightShadow extends LightShadow { - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState() { + constructor() { - const originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); + super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); + + this.isSpotLightShadow = true; + + this.focus = 1; } - _setAdditiveIdentityNumeric() { + updateMatrices( light ) { - const startIndex = this._addIndex * this.valueSize; - const endIndex = startIndex + this.valueSize; + const camera = this.camera; - for ( let i = startIndex; i < endIndex; i ++ ) { + const fov = RAD2DEG * 2 * light.angle * this.focus; + const aspect = this.mapSize.width / this.mapSize.height; + const far = light.distance || camera.far; - this.buffer[ i ] = 0; + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); } - } + super.updateMatrices( light ); - _setAdditiveIdentityQuaternion() { + } - this._setAdditiveIdentityNumeric(); - this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; + copy( source ) { - } + super.copy( source ); - _setAdditiveIdentityOther() { + this.focus = source.focus; - const startIndex = this._origIndex * this.valueSize; - const targetIndex = this._addIndex * this.valueSize; + return this; - for ( let i = 0; i < this.valueSize; i ++ ) { + } - this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; + } - } + class SpotLight extends Light { - } + constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 1 ) { + super( color, intensity ); - // mix functions + this.isSpotLight = true; - _select( buffer, dstOffset, srcOffset, t, stride ) { + this.type = 'SpotLight'; - if ( t >= 0.5 ) { + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - for ( let i = 0; i !== stride; ++ i ) { + this.target = new Object3D(); - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; + this.distance = distance; + this.angle = angle; + this.penumbra = penumbra; + this.decay = decay; // for physically correct lights, should be 2. - } + this.map = null; - } + this.shadow = new SpotLightShadow(); } - _slerp( buffer, dstOffset, srcOffset, t ) { + get power() { - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); + // compute the light's luminous power (in lumens) from its intensity (in candela) + // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) + return this.intensity * Math.PI; } - _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { + set power( power ) { - const workOffset = this._workIndex * stride; + // set the light's intensity (in candela) from the desired luminous power (in lumens) + this.intensity = power / Math.PI; - // Store result in intermediate buffer offset - Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); + } - // Slerp to the intermediate result - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); + dispose() { + + this.shadow.dispose(); } - _lerp( buffer, dstOffset, srcOffset, t, stride ) { + copy( source, recursive ) { - const s = 1 - t; + super.copy( source, recursive ); - for ( let i = 0; i !== stride; ++ i ) { + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; - const j = dstOffset + i; + this.target = source.target.clone(); - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; + this.shadow = source.shadow.clone(); - } + return this; } - _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { + } - for ( let i = 0; i !== stride; ++ i ) { + const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); + const _lightPositionWorld = /*@__PURE__*/ new Vector3(); + const _lookTarget = /*@__PURE__*/ new Vector3(); - const j = dstOffset + i; + class PointLightShadow extends LightShadow { - buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; + constructor() { - } + super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - } + this.isPointLightShadow = true; - } + this._frameExtents = new Vector2( 4, 2 ); - // Characters [].:/ are reserved for track binding syntax. - const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; - const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); + this._viewportCount = 6; - // Attempts to allow node names from any language. ES5's `\w` regexp matches - // only latin characters, and the unicode \p{L} is not yet supported. So - // instead, we exclude reserved characters and match everything else. - const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; - const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; + this._viewports = [ + // These viewports map a cube-map onto a 2D texture with the + // following orientation: + // + // xzXZ + // y Y + // + // X - Positive x direction + // x - Negative x direction + // Y - Positive y direction + // y - Negative y direction + // Z - Positive z direction + // z - Negative z direction - // Parent directories, delimited by '/' or ':'. Currently unused, but must - // be matched to parse the rest of the track name. - const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); + // positive X + new Vector4( 2, 1, 1, 1 ), + // negative X + new Vector4( 0, 1, 1, 1 ), + // positive Z + new Vector4( 3, 1, 1, 1 ), + // negative Z + new Vector4( 1, 1, 1, 1 ), + // positive Y + new Vector4( 3, 0, 1, 1 ), + // negative Y + new Vector4( 1, 0, 1, 1 ) + ]; - // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. - const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); + this._cubeDirections = [ + new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), + new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) + ]; - // Object on target node, and accessor. May not contain reserved - // characters. Accessor may contain any character except closing bracket. - const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); + this._cubeUps = [ + new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), + new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) + ]; - // Property and accessor. May not contain reserved characters. Accessor may - // contain any non-bracket characters. - const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); + } - const _trackRe = new RegExp( '' - + '^' - + _directoryRe - + _nodeRe - + _objectRe - + _propertyRe - + '$' - ); + updateMatrices( light, viewportIndex = 0 ) { - const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; + const camera = this.camera; + const shadowMatrix = this.matrix; - class Composite { + const far = light.distance || camera.far; - constructor( targetGroup, path, optionalParsedPath ) { + if ( far !== camera.far ) { - const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); + camera.far = far; + camera.updateProjectionMatrix(); - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); + } + + _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + camera.position.copy( _lightPositionWorld ); + + _lookTarget.copy( camera.position ); + _lookTarget.add( this._cubeDirections[ viewportIndex ] ); + camera.up.copy( this._cubeUps[ viewportIndex ] ); + camera.lookAt( _lookTarget ); + camera.updateMatrixWorld(); + + shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( _projScreenMatrix ); } - getValue( array, offset ) { + } - this.bind(); // bind all binding + class PointLight extends Light { - const firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; + constructor( color, intensity, distance = 0, decay = 1 ) { - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); + super( color, intensity ); - } + this.isPointLight = true; - setValue( array, offset ) { + this.type = 'PointLight'; - const bindings = this._bindings; + this.distance = distance; + this.decay = decay; // for physically correct lights, should be 2. - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + this.shadow = new PointLightShadow(); - bindings[ i ].setValue( array, offset ); + } - } + get power() { + + // compute the light's luminous power (in lumens) from its intensity (in candela) + // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) + return this.intensity * 4 * Math.PI; } - bind() { + set power( power ) { - const bindings = this._bindings; + // set the light's intensity (in candela) from the desired luminous power (in lumens) + this.intensity = power / ( 4 * Math.PI ); - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + } - bindings[ i ].bind(); + dispose() { - } + this.shadow.dispose(); } - unbind() { + copy( source, recursive ) { - const bindings = this._bindings; + super.copy( source, recursive ); - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { + this.distance = source.distance; + this.decay = source.decay; - bindings[ i ].unbind(); + this.shadow = source.shadow.clone(); - } + return this; } } - // Note: This class uses a State pattern on a per-method basis: - // 'bind' sets 'this.getValue' / 'setValue' and shadows the - // prototype version of these methods with one that represents - // the bound state. When the property is not found, the methods - // become no-ops. - class PropertyBinding { + class DirectionalLightShadow extends LightShadow { - constructor( rootNode, path, parsedPath ) { + constructor() { - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); + super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; + this.isDirectionalLightShadow = true; - this.rootNode = rootNode; + } - // initial state of these methods that calls 'bind' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; + } - } + class DirectionalLight extends Light { + constructor( color, intensity ) { - static create( root, path, parsedPath ) { + super( color, intensity ); - if ( ! ( root && root.isAnimationObjectGroup ) ) { + this.isDirectionalLight = true; - return new PropertyBinding( root, path, parsedPath ); + this.type = 'DirectionalLight'; - } else { + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - return new PropertyBinding.Composite( root, path, parsedPath ); + this.target = new Object3D(); - } + this.shadow = new DirectionalLightShadow(); } - /** - * Replaces spaces with underscores and removes unsupported characters from - * node names, to ensure compatibility with parseTrackName(). - * - * @param {string} name Node name to be sanitized. - * @return {string} - */ - static sanitizeNodeName( name ) { + dispose() { - return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); + this.shadow.dispose(); } - static parseTrackName( trackName ) { + copy( source ) { - const matches = _trackRe.exec( trackName ); + super.copy( source ); - if ( matches === null ) { + this.target = source.target.clone(); + this.shadow = source.shadow.clone(); - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); + return this; - } + } - const results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; + } - const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); + class AmbientLight extends Light { - if ( lastDot !== undefined && lastDot !== - 1 ) { + constructor( color, intensity ) { - const objectName = results.nodeName.substring( lastDot + 1 ); + super( color, intensity ); - // Object names must be checked against an allowlist. Otherwise, there - // is no way to parse 'foo.bar.baz': 'baz' must be a property, but - // 'bar' could be the objectName, or part of a nodeName (which can - // include '.' characters). - if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { + this.isAmbientLight = true; - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; + this.type = 'AmbientLight'; - } + } - } + } - if ( results.propertyName === null || results.propertyName.length === 0 ) { + class RectAreaLight extends Light { - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); + constructor( color, intensity, width = 10, height = 10 ) { - } + super( color, intensity ); - return results; + this.isRectAreaLight = true; - } + this.type = 'RectAreaLight'; - static findNode( root, nodeName ) { + this.width = width; + this.height = height; - if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { + } - return root; + get power() { - } + // compute the light's luminous power (in lumens) from its intensity (in nits) + return this.intensity * this.width * this.height * Math.PI; - // search into skeleton bones. - if ( root.skeleton ) { + } - const bone = root.skeleton.getBoneByName( nodeName ); + set power( power ) { - if ( bone !== undefined ) { + // set the light's intensity (in nits) from the desired luminous power (in lumens) + this.intensity = power / ( this.width * this.height * Math.PI ); - return bone; + } - } + copy( source ) { - } + super.copy( source ); - // search into node subtree. - if ( root.children ) { + this.width = source.width; + this.height = source.height; - const searchNodeSubtree = function ( children ) { + return this; - for ( let i = 0; i < children.length; i ++ ) { + } - const childNode = children[ i ]; + toJSON( meta ) { - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { + const data = super.toJSON( meta ); - return childNode; + data.object.width = this.width; + data.object.height = this.height; - } + return data; - const result = searchNodeSubtree( childNode.children ); + } - if ( result ) return result; + } - } + /** + * Primary reference: + * https://graphics.stanford.edu/papers/envmap/envmap.pdf + * + * Secondary reference: + * https://www.ppsloan.org/publications/StupidSH36.pdf + */ - return null; + // 3-band SH defined by 9 coefficients - }; + class SphericalHarmonics3 { - const subTreeNode = searchNodeSubtree( root.children ); + constructor() { - if ( subTreeNode ) { + this.isSphericalHarmonics3 = true; - return subTreeNode; + this.coefficients = []; - } + for ( let i = 0; i < 9; i ++ ) { - } + this.coefficients.push( new Vector3() ); - return null; + } } - // these are used to "bind" a nonexistent property - _getValue_unavailable() {} - _setValue_unavailable() {} + set( coefficients ) { - // Getters + for ( let i = 0; i < 9; i ++ ) { - _getValue_direct( buffer, offset ) { + this.coefficients[ i ].copy( coefficients[ i ] ); - buffer[ offset ] = this.targetObject[ this.propertyName ]; + } - } + return this; - _getValue_array( buffer, offset ) { + } - const source = this.resolvedProperty; + zero() { - for ( let i = 0, n = source.length; i !== n; ++ i ) { + for ( let i = 0; i < 9; i ++ ) { - buffer[ offset ++ ] = source[ i ]; + this.coefficients[ i ].set( 0, 0, 0 ); } - } + return this; - _getValue_arrayElement( buffer, offset ) { + } - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; + // get the radiance in the direction of the normal + // target is a Vector3 + getAt( normal, target ) { - } + // normal is assumed to be unit length - _getValue_toArray( buffer, offset ) { + const x = normal.x, y = normal.y, z = normal.z; - this.resolvedProperty.toArray( buffer, offset ); + const coeff = this.coefficients; - } + // band 0 + target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); - // Direct + // band 1 + target.addScaledVector( coeff[ 1 ], 0.488603 * y ); + target.addScaledVector( coeff[ 2 ], 0.488603 * z ); + target.addScaledVector( coeff[ 3 ], 0.488603 * x ); - _setValue_direct( buffer, offset ) { + // band 2 + target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); + target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); + target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); + target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); + target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); - this.targetObject[ this.propertyName ] = buffer[ offset ]; + return target; } - _setValue_direct_setNeedsUpdate( buffer, offset ) { + // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal + // target is a Vector3 + // https://graphics.stanford.edu/papers/envmap/envmap.pdf + getIrradianceAt( normal, target ) { - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; + // normal is assumed to be unit length - } + const x = normal.x, y = normal.y, z = normal.z; - _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { + const coeff = this.coefficients; - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; + // band 0 + target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 - } + // band 1 + target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 + target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); + target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); - // EntireArray + // band 2 + target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 + target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); + target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 + target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); + target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 - _setValue_array( buffer, offset ) { + return target; - const dest = this.resolvedProperty; + } - for ( let i = 0, n = dest.length; i !== n; ++ i ) { + add( sh ) { - dest[ i ] = buffer[ offset ++ ]; + for ( let i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].add( sh.coefficients[ i ] ); } - } + return this; - _setValue_array_setNeedsUpdate( buffer, offset ) { + } - const dest = this.resolvedProperty; + addScaledSH( sh, s ) { - for ( let i = 0, n = dest.length; i !== n; ++ i ) { + for ( let i = 0; i < 9; i ++ ) { - dest[ i ] = buffer[ offset ++ ]; + this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); } - this.targetObject.needsUpdate = true; + return this; } - _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - - const dest = this.resolvedProperty; + scale( s ) { - for ( let i = 0, n = dest.length; i !== n; ++ i ) { + for ( let i = 0; i < 9; i ++ ) { - dest[ i ] = buffer[ offset ++ ]; + this.coefficients[ i ].multiplyScalar( s ); } - this.targetObject.matrixWorldNeedsUpdate = true; + return this; } - // ArrayElement - - _setValue_arrayElement( buffer, offset ) { + lerp( sh, alpha ) { - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + for ( let i = 0; i < 9; i ++ ) { - } + this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); - _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { + } - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; + return this; } - _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { + equals( sh ) { - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; + for ( let i = 0; i < 9; i ++ ) { - } + if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { - // HasToFromArray + return false; - _setValue_fromArray( buffer, offset ) { + } - this.resolvedProperty.fromArray( buffer, offset ); + } + + return true; } - _setValue_fromArray_setNeedsUpdate( buffer, offset ) { + copy( sh ) { - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; + return this.set( sh.coefficients ); } - _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { + clone() { - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; + return new this.constructor().copy( this ); } - _getValue_unbound( targetArray, offset ) { + fromArray( array, offset = 0 ) { - this.bind(); - this.getValue( targetArray, offset ); + const coefficients = this.coefficients; - } + for ( let i = 0; i < 9; i ++ ) { - _setValue_unbound( sourceArray, offset ) { + coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); - this.bind(); - this.setValue( sourceArray, offset ); + } + + return this; } - // create getter / setter pair for a property in the scene graph - bind() { + toArray( array = [], offset = 0 ) { - let targetObject = this.node; - const parsedPath = this.parsedPath; + const coefficients = this.coefficients; - const objectName = parsedPath.objectName; - const propertyName = parsedPath.propertyName; - let propertyIndex = parsedPath.propertyIndex; + for ( let i = 0; i < 9; i ++ ) { - if ( ! targetObject ) { + coefficients[ i ].toArray( array, offset + ( i * 3 ) ); - targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode; + } - this.node = targetObject; + return array; - } + } - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; + // evaluate the basis functions + // shBasis is an Array[ 9 ] + static getBasisAt( normal, shBasis ) { - // ensure there is a value node - if ( ! targetObject ) { + // normal is assumed to be unit length - console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' ); - return; + const x = normal.x, y = normal.y, z = normal.z; - } + // band 0 + shBasis[ 0 ] = 0.282095; - if ( objectName ) { + // band 1 + shBasis[ 1 ] = 0.488603 * y; + shBasis[ 2 ] = 0.488603 * z; + shBasis[ 3 ] = 0.488603 * x; - let objectIndex = parsedPath.objectIndex; + // band 2 + shBasis[ 4 ] = 1.092548 * x * y; + shBasis[ 5 ] = 1.092548 * y * z; + shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); + shBasis[ 7 ] = 1.092548 * x * z; + shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { + } - case 'materials': + } - if ( ! targetObject.material ) { + class LightProbe extends Light { - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; + constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { - } + super( undefined, intensity ); - if ( ! targetObject.material.materials ) { + this.isLightProbe = true; - console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); - return; + this.sh = sh; - } + } - targetObject = targetObject.material.materials; + copy( source ) { - break; + super.copy( source ); - case 'bones': + this.sh.copy( source.sh ); - if ( ! targetObject.skeleton ) { + return this; - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; + } - } + fromJSON( json ) { - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. + this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); + this.sh.fromArray( json.sh ); - targetObject = targetObject.skeleton.bones; + return this; - // support resolving morphTarget names into indices. - for ( let i = 0; i < targetObject.length; i ++ ) { + } - if ( targetObject[ i ].name === objectIndex ) { + toJSON( meta ) { - objectIndex = i; - break; + const data = super.toJSON( meta ); - } + data.object.sh = this.sh.toArray(); - } + return data; - break; + } - case 'map': + } - if ( 'map' in targetObject ) { + class MaterialLoader extends Loader { - targetObject = targetObject.map; - break; + constructor( manager ) { - } + super( manager ); + this.textures = {}; - if ( ! targetObject.material ) { + } - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; + load( url, onLoad, onProgress, onError ) { - } + const scope = this; - if ( ! targetObject.material.map ) { + const loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( text ) { - console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); - return; + try { - } + onLoad( scope.parse( JSON.parse( text ) ) ); - targetObject = targetObject.material.map; - break; + } catch ( e ) { - default: + if ( onError ) { - if ( targetObject[ objectName ] === undefined ) { + onError( e ); - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; + } else { - } + console.error( e ); - targetObject = targetObject[ objectName ]; + } + + scope.manager.itemError( url ); } + }, onProgress, onError ); - if ( objectIndex !== undefined ) { + } - if ( targetObject[ objectIndex ] === undefined ) { + parse( json ) { - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; + const textures = this.textures; - } + function getTexture( name ) { - targetObject = targetObject[ objectIndex ]; + if ( textures[ name ] === undefined ) { + + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); } + return textures[ name ]; + } - // resolve property - const nodeProperty = targetObject[ propertyName ]; + const material = MaterialLoader.createMaterialFromType( json.type ); - if ( nodeProperty === undefined ) { + if ( json.uuid !== undefined ) material.uuid = json.uuid; + if ( json.name !== undefined ) material.name = json.name; + if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metalness !== undefined ) material.metalness = json.metalness; + if ( json.sheen !== undefined ) material.sheen = json.sheen; + if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); + if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; + if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; + if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; + if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; + if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; + if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; + if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; + if ( json.transmission !== undefined ) material.transmission = json.transmission; + if ( json.thickness !== undefined ) material.thickness = json.thickness; + if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; + if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); + if ( json.fog !== undefined ) material.fog = json.fog; + if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.combine !== undefined ) material.combine = json.combine; + if ( json.side !== undefined ) material.side = json.side; + if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; + if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; + if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; + if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - const nodeName = parsedPath.nodeName; + if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; + if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; + if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; + if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; + if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; + if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; + if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; + if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; + if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; + if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - } + if ( json.rotation !== undefined ) material.rotation = json.rotation; - // determine versioning scheme - let versioning = this.Versioning.None; + if ( json.linewidth !== 1 ) material.linewidth = json.linewidth; + if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; + if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; + if ( json.scale !== undefined ) material.scale = json.scale; - this.targetObject = targetObject; + if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; + if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; + if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; - if ( targetObject.needsUpdate !== undefined ) { // material + if ( json.dithering !== undefined ) material.dithering = json.dithering; - versioning = this.Versioning.NeedsUpdate; + if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; + if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + if ( json.visible !== undefined ) material.visible = json.visible; - versioning = this.Versioning.MatrixWorldNeedsUpdate; + if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; - } + if ( json.userData !== undefined ) material.userData = json.userData; - // determine how the property gets bound - let bindingType = this.BindingType.Direct; + if ( json.vertexColors !== undefined ) { - if ( propertyIndex !== undefined ) { + if ( typeof json.vertexColors === 'number' ) { - // access a sub element of the property array (only primitives are supported right now) + material.vertexColors = ( json.vertexColors > 0 ) ? true : false; - if ( propertyName === 'morphTargetInfluences' ) { + } else { - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + material.vertexColors = json.vertexColors; - // support resolving morphTarget names into indices. - if ( ! targetObject.geometry ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); - return; - - } - - if ( ! targetObject.geometry.morphAttributes ) { + } - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; + } - } + // Shader Material - if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { + if ( json.uniforms !== undefined ) { - propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; + for ( const name in json.uniforms ) { - } + const uniform = json.uniforms[ name ]; - } + material.uniforms[ name ] = {}; - bindingType = this.BindingType.ArrayElement; + switch ( uniform.type ) { - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; + case 't': + material.uniforms[ name ].value = getTexture( uniform.value ); + break; - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { + case 'c': + material.uniforms[ name ].value = new Color().setHex( uniform.value ); + break; - // must use copy for Object3D.Euler/Quaternion + case 'v2': + material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); + break; - bindingType = this.BindingType.HasFromToArray; + case 'v3': + material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); + break; - this.resolvedProperty = nodeProperty; + case 'v4': + material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); + break; - } else if ( Array.isArray( nodeProperty ) ) { + case 'm3': + material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); + break; - bindingType = this.BindingType.EntireArray; + case 'm4': + material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); + break; - this.resolvedProperty = nodeProperty; + default: + material.uniforms[ name ].value = uniform.value; - } else { + } - this.propertyName = propertyName; + } } - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; + if ( json.defines !== undefined ) material.defines = json.defines; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; - } + if ( json.extensions !== undefined ) { - unbind() { + for ( const key in json.extensions ) { - this.node = null; + material.extensions[ key ] = json.extensions[ key ]; - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; + } - } + } - } + // for PointsMaterial - PropertyBinding.Composite = Composite; + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - PropertyBinding.prototype.BindingType = { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 - }; + // maps - PropertyBinding.prototype.Versioning = { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 - }; + if ( json.map !== undefined ) material.map = getTexture( json.map ); + if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); - PropertyBinding.prototype.GetterByBindingType = [ + if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); - PropertyBinding.prototype._getValue_direct, - PropertyBinding.prototype._getValue_array, - PropertyBinding.prototype._getValue_arrayElement, - PropertyBinding.prototype._getValue_toArray, + if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - ]; + if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); + if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; + if ( json.normalScale !== undefined ) { - PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ + let normalScale = json.normalScale; - [ - // Direct - PropertyBinding.prototype._setValue_direct, - PropertyBinding.prototype._setValue_direct_setNeedsUpdate, - PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, + if ( Array.isArray( normalScale ) === false ) { - ], [ + // Blender exporter used to export a scalar. See #7459 - // EntireArray + normalScale = [ normalScale, normalScale ]; - PropertyBinding.prototype._setValue_array, - PropertyBinding.prototype._setValue_array_setNeedsUpdate, - PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, + } - ], [ + material.normalScale = new Vector2().fromArray( normalScale ); - // ArrayElement - PropertyBinding.prototype._setValue_arrayElement, - PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, - PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, + } - ], [ + if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); + if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; + if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; - // HasToFromArray - PropertyBinding.prototype._setValue_fromArray, - PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, - PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, + if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); + if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - ] + if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); + if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; - ]; + if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); + if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); + if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); - /** - * - * A group of objects that receives a shared animation state. - * - * Usage: - * - * - Add objects you would otherwise pass as 'root' to the - * constructor or the .clipAction method of AnimationMixer. - * - * - Instead pass this object as 'root'. - * - * - You can also add and remove objects later when the mixer - * is running. - * - * Note: - * - * Objects of this class appear as one object to the mixer, - * so cache control of the individual objects must be done - * on the group. - * - * Limitation: - * - * - The animated properties must be compatible among the - * all objects in the group. - * - * - A single property can either be controlled through a - * target group or directly, but not both. - */ + if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; - class AnimationObjectGroup { + if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; - constructor() { + if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - this.isAnimationObjectGroup = true; + if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - this.uuid = generateUUID(); + if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); + if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); + if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); + if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); + if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite + if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); + if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); - const indices = {}; - this._indicesByUUID = indices; // for bookkeeping + if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); + if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); + if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); - indices[ arguments[ i ].uuid ] = i; + return material; - } + } - this._paths = []; // inside: string - this._parsedPaths = []; // inside: { we don't care, here } - this._bindings = []; // inside: Array< PropertyBinding > - this._bindingsIndicesByPath = {}; // inside: indices in these arrays + setTextures( value ) { - const scope = this; + this.textures = value; + return this; - this.stats = { + } - objects: { - get total() { + static createMaterialFromType( type ) { - return scope._objects.length; + const materialLib = { + ShadowMaterial, + SpriteMaterial, + RawShaderMaterial, + ShaderMaterial, + PointsMaterial, + MeshPhysicalMaterial, + MeshStandardMaterial, + MeshPhongMaterial, + MeshToonMaterial, + MeshNormalMaterial, + MeshLambertMaterial, + MeshDepthMaterial, + MeshDistanceMaterial, + MeshBasicMaterial, + MeshMatcapMaterial, + LineDashedMaterial, + LineBasicMaterial, + Material + }; - }, - get inUse() { + return new materialLib[ type ](); - return this.total - scope.nCachedObjects_; + } - } - }, - get bindingsPerObject() { + } - return scope._bindings.length; + class LoaderUtils { - } + static decodeText( array ) { - }; + if ( typeof TextDecoder !== 'undefined' ) { - } + return new TextDecoder().decode( array ); - add() { + } - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - nBindings = bindings.length; + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. - let knownObject = undefined, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_; + let s = ''; - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + for ( let i = 0, il = array.length; i < il; i ++ ) { - const object = arguments[ i ], - uuid = object.uuid; - let index = indicesByUUID[ uuid ]; + // Implicitly assumes little-endian. + s += String.fromCharCode( array[ i ] ); - if ( index === undefined ) { + } - // unknown object -> add it to the ACTIVE region + try { - index = nObjects ++; - indicesByUUID[ uuid ] = index; - objects.push( object ); + // merges multi-byte utf-8 characters. - // accounting is done, now do the same for all bindings + return decodeURIComponent( escape( s ) ); - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + } catch ( e ) { // see #16358 - bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); + return s; - } + } - } else if ( index < nCachedObjects ) { + } - knownObject = objects[ index ]; + static extractUrlBase( url ) { - // move existing object to the ACTIVE region + const index = url.lastIndexOf( '/' ); - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; + if ( index === - 1 ) return './'; - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; + return url.slice( 0, index + 1 ); - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; + } - // accounting is done, now do the same for all bindings + static resolveURL( url, path ) { - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + // Invalid URL + if ( typeof url !== 'string' || url === '' ) return ''; - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ]; + // Host Relative URL + if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { - let binding = bindingsForPath[ index ]; + path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); - bindingsForPath[ index ] = lastCached; + } - if ( binding === undefined ) { + // Absolute URL http://,https://,// + if ( /^(https?:)?\/\//i.test( url ) ) return url; - // since we do not bother to create new bindings - // for objects that are cached, the binding may - // or may not exist + // Data URI + if ( /^data:.*,.*$/i.test( url ) ) return url; - binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); + // Blob URL + if ( /^blob:.*$/i.test( url ) ) return url; - } + // Relative URL + return path + url; - bindingsForPath[ firstActiveIndex ] = binding; + } - } + } - } else if ( objects[ index ] !== knownObject ) { + class InstancedBufferGeometry extends BufferGeometry { - console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + - 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); + constructor() { - } // else the object is already where we want it to be + super(); - } // for arguments + this.isInstancedBufferGeometry = true; - this.nCachedObjects_ = nCachedObjects; + this.type = 'InstancedBufferGeometry'; + this.instanceCount = Infinity; } - remove() { + copy( source ) { - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; + super.copy( source ); - let nCachedObjects = this.nCachedObjects_; + this.instanceCount = source.instanceCount; - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + return this; - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + } - if ( index !== undefined && index >= nCachedObjects ) { + clone() { - // move existing object into the CACHED region + return new this.constructor().copy( this ); - const lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; + } - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; + toJSON() { - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; + const data = super.toJSON( this ); - // accounting is done, now do the same for all bindings + data.instanceCount = this.instanceCount; - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + data.isInstancedBufferGeometry = true; - const bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; + return data; - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; + } - } + } - } + class BufferGeometryLoader extends Loader { - } // for arguments + constructor( manager ) { - this.nCachedObjects_ = nCachedObjects; + super( manager ); } - // remove & forget - uncache() { + load( url, onLoad, onProgress, onError ) { - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; + const scope = this; - let nCachedObjects = this.nCachedObjects_, - nObjects = objects.length; + const loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.setWithCredentials( scope.withCredentials ); + loader.load( url, function ( text ) { - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { + try { - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + onLoad( scope.parse( JSON.parse( text ) ) ); - if ( index !== undefined ) { + } catch ( e ) { - delete indicesByUUID[ uuid ]; + if ( onError ) { - if ( index < nCachedObjects ) { + onError( e ); - // object is cached, shrink the CACHED region + } else { - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ], - lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; + console.error( e ); - // last cached object takes this object's place - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; + } - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); + scope.manager.itemError( url ); - // accounting is done, now do the same for all bindings + } - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + }, onProgress, onError ); - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; + } - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); + parse( json ) { - } + const interleavedBufferMap = {}; + const arrayBufferMap = {}; - } else { + function getInterleavedBuffer( json, uuid ) { - // object is active, just swap with the last and pop + if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; - const lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; + const interleavedBuffers = json.interleavedBuffers; + const interleavedBuffer = interleavedBuffers[ uuid ]; - if ( lastIndex > 0 ) { + const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); - indicesByUUID[ lastObject.uuid ] = index; + const array = getTypedArray( interleavedBuffer.type, buffer ); + const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); + ib.uuid = interleavedBuffer.uuid; - } + interleavedBufferMap[ uuid ] = ib; - objects[ index ] = lastObject; - objects.pop(); + return ib; - // accounting is done, now do the same for all bindings + } - for ( let j = 0, m = nBindings; j !== m; ++ j ) { + function getArrayBuffer( json, uuid ) { - const bindingsForPath = bindings[ j ]; + if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); + const arrayBuffers = json.arrayBuffers; + const arrayBuffer = arrayBuffers[ uuid ]; - } + const ab = new Uint32Array( arrayBuffer ).buffer; - } // cached or active + arrayBufferMap[ uuid ] = ab; - } // if object is known + return ab; - } // for arguments + } - this.nCachedObjects_ = nCachedObjects; + const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); - } + const index = json.data.index; - // Internal interface used by befriended PropertyBinding.Composite: + if ( index !== undefined ) { - subscribe_( path, parsedPath ) { + const typedArray = getTypedArray( index.type, index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group + } - const indicesByPath = this._bindingsIndicesByPath; - let index = indicesByPath[ path ]; - const bindings = this._bindings; + const attributes = json.data.attributes; - if ( index !== undefined ) return bindings[ index ]; + for ( const key in attributes ) { - const paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); + const attribute = attributes[ key ]; + let bufferAttribute; - index = bindings.length; + if ( attribute.isInterleavedBufferAttribute ) { - indicesByPath[ path ] = index; + const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); + bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); + } else { - for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { + const typedArray = getTypedArray( attribute.type, attribute.array ); + const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; + bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); - const object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); + } - } + if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; + if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); - return bindingsForPath; + if ( attribute.updateRange !== undefined ) { - } + bufferAttribute.updateRange.offset = attribute.updateRange.offset; + bufferAttribute.updateRange.count = attribute.updateRange.count; - unsubscribe_( path ) { + } - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' + geometry.setAttribute( key, bufferAttribute ); - const indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; + } - if ( index !== undefined ) { + const morphAttributes = json.data.morphAttributes; - const paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; + if ( morphAttributes ) { - indicesByPath[ lastBindingsPath ] = index; + for ( const key in morphAttributes ) { - bindings[ index ] = lastBindings; - bindings.pop(); + const attributeArray = morphAttributes[ key ]; - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); + const array = []; - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); + for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - } + const attribute = attributeArray[ i ]; + let bufferAttribute; - } + if ( attribute.isInterleavedBufferAttribute ) { - } + const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); + bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - class AnimationAction { + } else { - constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { + const typedArray = getTypedArray( attribute.type, attribute.array ); + bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot; - this.blendMode = blendMode; + } - const tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); + if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; + array.push( bufferAttribute ); - const interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; + } - for ( let i = 0; i !== nTracks; ++ i ) { + geometry.morphAttributes[ key ] = array; - const interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; + } } - this._interpolantSettings = interpolantSettings; + const morphTargetsRelative = json.data.morphTargetsRelative; - this._interpolants = interpolants; // bound by the mixer + if ( morphTargetsRelative ) { - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); + geometry.morphTargetsRelative = true; - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager + } - this._timeScaleInterpolant = null; - this._weightInterpolant = null; + const groups = json.data.groups || json.data.drawcalls || json.data.offsets; - this.loop = LoopRepeat; - this._loopCount = - 1; + if ( groups !== undefined ) { - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; + for ( let i = 0, n = groups.length; i !== n; ++ i ) { - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; + const group = groups[ i ]; - this.timeScale = 1; - this._effectiveTimeScale = 1; + geometry.addGroup( group.start, group.count, group.materialIndex ); - this.weight = 1; - this._effectiveWeight = 1; + } - this.repetitions = Infinity; // no. of repetitions when looping + } - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight + const boundingSphere = json.data.boundingSphere; - this.clampWhenFinished = false;// keep feeding the last frame? + if ( boundingSphere !== undefined ) { - this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true;// clips for start, loop and end + const center = new Vector3(); - } + if ( boundingSphere.center !== undefined ) { - // State & Scheduling + center.fromArray( boundingSphere.center ); - play() { + } - this._mixer._activateAction( this ); + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - return this; + } + + if ( json.name ) geometry.name = json.name; + if ( json.userData ) geometry.userData = json.userData; + + return geometry; } - stop() { + } - this._mixer._deactivateAction( this ); + class ObjectLoader extends Loader { - return this.reset(); + constructor( manager ) { + + super( manager ); } - reset() { + load( url, onLoad, onProgress, onError ) { - this.paused = false; - this.enabled = true; + const scope = this; - this.time = 0; // restart clip - this._loopCount = - 1;// forget previous loops - this._startTime = null;// forget scheduling + const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; - return this.stopFading().stopWarping(); + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { - } + let json = null; - isRunning() { + try { - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); + json = JSON.parse( text ); - } + } catch ( error ) { - // return true when play has been called - isScheduled() { + if ( onError !== undefined ) onError( error ); - return this._mixer._isActiveAction( this ); + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - } + return; - startAt( time ) { + } - this._startTime = time; + const metadata = json.metadata; - return this; + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - } + console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); + return; - setLoop( mode, repetitions ) { + } - this.loop = mode; - this.repetitions = repetitions; + scope.parse( json, onLoad ); - return this; + }, onProgress, onError ); } - // Weight + async loadAsync( url, onProgress ) { - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight( weight ) { + const scope = this; - this.weight = weight; + const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); - return this.stopFading(); + const text = await loader.loadAsync( url, onProgress ); - } + const json = JSON.parse( text ); - // return the weight considering fading and .enabled - getEffectiveWeight() { + const metadata = json.metadata; - return this._effectiveWeight; + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - } + throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); - fadeIn( duration ) { + } - return this._scheduleFading( duration, 0, 1 ); + return await scope.parseAsync( json ); } - fadeOut( duration ) { - - return this._scheduleFading( duration, 1, 0 ); - - } + parse( json, onLoad ) { - crossFadeFrom( fadeOutAction, duration, warp ) { + const animations = this.parseAnimations( json.animations ); + const shapes = this.parseShapes( json.shapes ); + const geometries = this.parseGeometries( json.geometries, shapes ); - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); + const images = this.parseImages( json.images, function () { - if ( warp ) { + if ( onLoad !== undefined ) onLoad( object ); - const fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, + } ); - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; + const textures = this.parseTextures( json.textures, images ); + const materials = this.parseMaterials( json.materials, textures ); - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); + const object = this.parseObject( json.object, geometries, materials, textures, animations ); + const skeletons = this.parseSkeletons( json.skeletons, object ); - } + this.bindSkeletons( object, skeletons ); - return this; + // - } + if ( onLoad !== undefined ) { - crossFadeTo( fadeInAction, duration, warp ) { + let hasImages = false; - return fadeInAction.crossFadeFrom( this, duration, warp ); + for ( const uuid in images ) { - } + if ( images[ uuid ].data instanceof HTMLImageElement ) { - stopFading() { + hasImages = true; + break; - const weightInterpolant = this._weightInterpolant; + } - if ( weightInterpolant !== null ) { + } - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); + if ( hasImages === false ) onLoad( object ); } - return this; + return object; } - // Time Scale Control + async parseAsync( json ) { - // set the time scale stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale( timeScale ) { + const animations = this.parseAnimations( json.animations ); + const shapes = this.parseShapes( json.shapes ); + const geometries = this.parseGeometries( json.geometries, shapes ); - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 : timeScale; + const images = await this.parseImagesAsync( json.images ); - return this.stopWarping(); + const textures = this.parseTextures( json.textures, images ); + const materials = this.parseMaterials( json.materials, textures ); - } + const object = this.parseObject( json.object, geometries, materials, textures, animations ); + const skeletons = this.parseSkeletons( json.skeletons, object ); - // return the time scale considering warping and .paused - getEffectiveTimeScale() { + this.bindSkeletons( object, skeletons ); - return this._effectiveTimeScale; + return object; } - setDuration( duration ) { - - this.timeScale = this._clip.duration / duration; + parseShapes( json ) { - return this.stopWarping(); + const shapes = {}; - } + if ( json !== undefined ) { - syncWith( action ) { + for ( let i = 0, l = json.length; i < l; i ++ ) { - this.time = action.time; - this.timeScale = action.timeScale; + const shape = new Shape().fromJSON( json[ i ] ); - return this.stopWarping(); + shapes[ shape.uuid ] = shape; - } + } - halt( duration ) { + } - return this.warp( this._effectiveTimeScale, 0, duration ); + return shapes; } - warp( startTimeScale, endTimeScale, duration ) { - - const mixer = this._mixer, - now = mixer.time, - timeScale = this.timeScale; - - let interpolant = this._timeScaleInterpolant; - - if ( interpolant === null ) { + parseSkeletons( json, object ) { - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; + const skeletons = {}; + const bones = {}; - } + // generate bone lookup table - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; + object.traverse( function ( child ) { - times[ 0 ] = now; - times[ 1 ] = now + duration; + if ( child.isBone ) bones[ child.uuid ] = child; - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; + } ); - return this; + // create skeletons - } + if ( json !== undefined ) { - stopWarping() { + for ( let i = 0, l = json.length; i < l; i ++ ) { - const timeScaleInterpolant = this._timeScaleInterpolant; + const skeleton = new Skeleton().fromJSON( json[ i ], bones ); - if ( timeScaleInterpolant !== null ) { + skeletons[ skeleton.uuid ] = skeleton; - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); + } } - return this; + return skeletons; } - // Object Accessors + parseGeometries( json, shapes ) { - getMixer() { + const geometries = {}; - return this._mixer; + if ( json !== undefined ) { - } + const bufferGeometryLoader = new BufferGeometryLoader(); - getClip() { + for ( let i = 0, l = json.length; i < l; i ++ ) { - return this._clip; + let geometry; + const data = json[ i ]; - } + switch ( data.type ) { - getRoot() { + case 'BufferGeometry': + case 'InstancedBufferGeometry': - return this._localRoot || this._mixer._root; + geometry = bufferGeometryLoader.parse( data ); + break; - } + default: - // Interna + if ( data.type in Geometries ) { - _update( time, deltaTime, timeDirection, accuIndex ) { + geometry = Geometries[ data.type ].fromJSON( data, shapes ); - // called by the mixer + } else { - if ( ! this.enabled ) { + console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); - // call ._updateWeight() to update ._effectiveWeight + } - this._updateWeight( time ); - return; + } - } + geometry.uuid = data.uuid; - const startTime = this._startTime; + if ( data.name !== undefined ) geometry.name = data.name; + if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData; - if ( startTime !== null ) { + geometries[ data.uuid ] = geometry; - // check for scheduled start of action + } - const timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { + } - deltaTime = 0; + return geometries; - } else { + } + parseMaterials( json, textures ) { - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; + const cache = {}; // MultiMaterial + const materials = {}; - } + if ( json !== undefined ) { - } + const loader = new MaterialLoader(); + loader.setTextures( textures ); - // apply time scale and advance time + for ( let i = 0, l = json.length; i < l; i ++ ) { - deltaTime *= this._updateTimeScale( time ); - const clipTime = this._updateTime( deltaTime ); + const data = json[ i ]; - // note: _updateTime may disable the action resulting in - // an effective weight of 0 + if ( cache[ data.uuid ] === undefined ) { - const weight = this._updateWeight( time ); + cache[ data.uuid ] = loader.parse( data ); - if ( weight > 0 ) { + } - const interpolants = this._interpolants; - const propertyMixers = this._propertyBindings; + materials[ data.uuid ] = cache[ data.uuid ]; - switch ( this.blendMode ) { + } - case AdditiveAnimationBlendMode: + } - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { + return materials; - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulateAdditive( weight ); + } - } + parseAnimations( json ) { - break; + const animations = {}; - case NormalAnimationBlendMode: - default: + if ( json !== undefined ) { - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { + for ( let i = 0; i < json.length; i ++ ) { - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); + const data = json[ i ]; - } + const clip = AnimationClip.parse( data ); + + animations[ clip.uuid ] = clip; } } + return animations; + } - _updateWeight( time ) { + parseImages( json, onLoad ) { - let weight = 0; + const scope = this; + const images = {}; - if ( this.enabled ) { + let loader; - weight = this.weight; - const interpolant = this._weightInterpolant; + function loadImage( url ) { - if ( interpolant !== null ) { + scope.manager.itemStart( url ); - const interpolantValue = interpolant.evaluate( time )[ 0 ]; + return loader.load( url, function () { - weight *= interpolantValue; + scope.manager.itemEnd( url ); - if ( time > interpolant.parameterPositions[ 1 ] ) { + }, undefined, function () { - this.stopFading(); + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - if ( interpolantValue === 0 ) { + } ); - // faded out, disable - this.enabled = false; + } - } + function deserializeImage( image ) { - } + if ( typeof image === 'string' ) { - } - - } - - this._effectiveWeight = weight; - return weight; - - } - - _updateTimeScale( time ) { + const url = image; - let timeScale = 0; + const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - if ( ! this.paused ) { + return loadImage( path ); - timeScale = this.timeScale; + } else { - const interpolant = this._timeScaleInterpolant; + if ( image.data ) { - if ( interpolant !== null ) { + return { + data: getTypedArray( image.type, image.data ), + width: image.width, + height: image.height + }; - const interpolantValue = interpolant.evaluate( time )[ 0 ]; + } else { - timeScale *= interpolantValue; + return null; - if ( time > interpolant.parameterPositions[ 1 ] ) { + } - this.stopWarping(); + } - if ( timeScale === 0 ) { + } - // motion has halted, pause - this.paused = true; + if ( json !== undefined && json.length > 0 ) { - } else { + const manager = new LoadingManager( onLoad ); - // warp done - apply final time scale - this.timeScale = timeScale; + loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - } + for ( let i = 0, il = json.length; i < il; i ++ ) { - } + const image = json[ i ]; + const url = image.url; - } + if ( Array.isArray( url ) ) { - } + // load array of images e.g CubeTexture - this._effectiveTimeScale = timeScale; - return timeScale; + const imageArray = []; - } + for ( let j = 0, jl = url.length; j < jl; j ++ ) { - _updateTime( deltaTime ) { + const currentUrl = url[ j ]; - const duration = this._clip.duration; - const loop = this.loop; + const deserializedImage = deserializeImage( currentUrl ); - let time = this.time + deltaTime; - let loopCount = this._loopCount; + if ( deserializedImage !== null ) { - const pingPong = ( loop === LoopPingPong ); + if ( deserializedImage instanceof HTMLImageElement ) { - if ( deltaTime === 0 ) { + imageArray.push( deserializedImage ); - if ( loopCount === - 1 ) return time; + } else { - return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; + // special case: handle array of data textures for cube textures - } + imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - if ( loop === LoopOnce ) { + } - if ( loopCount === - 1 ) { + } - // just started + } - this._loopCount = 0; - this._setEndings( true, true, false ); + images[ image.uuid ] = new Source( imageArray ); - } + } else { - handle_stop: { + // load single image - if ( time >= duration ) { + const deserializedImage = deserializeImage( image.url ); + images[ image.uuid ] = new Source( deserializedImage ); - time = duration; - } else if ( time < 0 ) { + } - time = 0; + } - } else { + } - this.time = time; + return images; - break handle_stop; + } - } + async parseImagesAsync( json ) { - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; + const scope = this; + const images = {}; - this.time = time; + let loader; - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? - 1 : 1 - } ); + async function deserializeImage( image ) { - } + if ( typeof image === 'string' ) { - } else { // repetitive Repeat or PingPong + const url = image; - if ( loopCount === - 1 ) { + const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - // just started + return await loader.loadAsync( path ); - if ( deltaTime >= 0 ) { + } else { - loopCount = 0; + if ( image.data ) { - this._setEndings( true, this.repetitions === 0, pingPong ); + return { + data: getTypedArray( image.type, image.data ), + width: image.width, + height: image.height + }; } else { - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 - - this._setEndings( this.repetitions === 0, true, pingPong ); + return null; } } - if ( time >= duration || time < 0 ) { + } - // wrap around + if ( json !== undefined && json.length > 0 ) { - const loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; + loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); - loopCount += Math.abs( loopDelta ); + for ( let i = 0, il = json.length; i < il; i ++ ) { - const pending = this.repetitions - loopCount; + const image = json[ i ]; + const url = image.url; - if ( pending <= 0 ) { + if ( Array.isArray( url ) ) { - // have to stop (switch state, clamp time, fire event) + // load array of images e.g CubeTexture - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; + const imageArray = []; - time = deltaTime > 0 ? duration : 0; + for ( let j = 0, jl = url.length; j < jl; j ++ ) { - this.time = time; + const currentUrl = url[ j ]; - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : - 1 - } ); + const deserializedImage = await deserializeImage( currentUrl ); - } else { + if ( deserializedImage !== null ) { - // keep running + if ( deserializedImage instanceof HTMLImageElement ) { - if ( pending === 1 ) { + imageArray.push( deserializedImage ); - // entering the last round + } else { - const atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); + // special case: handle array of data textures for cube textures - } else { + imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - this._setEndings( false, false, pingPong ); + } + + } } - this._loopCount = loopCount; + images[ image.uuid ] = new Source( imageArray ); - this.time = time; + } else { - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); + // load single image + + const deserializedImage = await deserializeImage( image.url ); + images[ image.uuid ] = new Source( deserializedImage ); } - } else { + } - this.time = time; + } - } + return images; - if ( pingPong && ( loopCount & 1 ) === 1 ) { + } - // invert time for the "pong round" + parseTextures( json, images ) { - return duration - time; + function parseConstant( value, type ) { - } + if ( typeof value === 'number' ) return value; + + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + + return type[ value ]; } - return time; + const textures = {}; - } + if ( json !== undefined ) { - _setEndings( atStart, atEnd, pingPong ) { + for ( let i = 0, l = json.length; i < l; i ++ ) { - const settings = this._interpolantSettings; + const data = json[ i ]; - if ( pingPong ) { + if ( data.image === undefined ) { - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - } else { + } - // assuming for LoopOnce atStart == atEnd == true + if ( images[ data.image ] === undefined ) { - if ( atStart ) { + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; + } - } else { + const source = images[ data.image ]; + const image = source.data; - settings.endingStart = WrapAroundEnding; + let texture; - } + if ( Array.isArray( image ) ) { - if ( atEnd ) { + texture = new CubeTexture(); - settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; + if ( image.length === 6 ) texture.needsUpdate = true; - } else { + } else { - settings.endingEnd = WrapAroundEnding; + if ( image && image.data ) { - } + texture = new DataTexture(); - } + } else { - } + texture = new Texture(); - _scheduleFading( duration, weightNow, weightThen ) { + } - const mixer = this._mixer, now = mixer.time; - let interpolant = this._weightInterpolant; + if ( image ) texture.needsUpdate = true; // textures can have undefined image data - if ( interpolant === null ) { + } - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; + texture.source = source; - } + texture.uuid = data.uuid; - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; + if ( data.name !== undefined ) texture.name = data.name; - times[ 0 ] = now; - values[ 0 ] = weightNow; - times[ 1 ] = now + duration; - values[ 1 ] = weightThen; + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - return this; + if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); + if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); + if ( data.center !== undefined ) texture.center.fromArray( data.center ); + if ( data.rotation !== undefined ) texture.rotation = data.rotation; - } + if ( data.wrap !== undefined ) { - } + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - const _controlInterpolantsResultBuffer = new Float32Array( 1 ); + } + if ( data.format !== undefined ) texture.format = data.format; + if ( data.type !== undefined ) texture.type = data.type; + if ( data.encoding !== undefined ) texture.encoding = data.encoding; - class AnimationMixer extends EventDispatcher { + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - constructor( root ) { + if ( data.flipY !== undefined ) texture.flipY = data.flipY; - super(); + if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; + if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; - this.time = 0; - this.timeScale = 1.0; + if ( data.userData !== undefined ) texture.userData = data.userData; - } + textures[ data.uuid ] = texture; - _bindAction( action, prototypeAction ) { + } - const root = action._localRoot || this._root, - tracks = action._clip.tracks, - nTracks = tracks.length, - bindings = action._propertyBindings, - interpolants = action._interpolants, - rootUuid = root.uuid, - bindingsByRoot = this._bindingsByRootAndName; + } - let bindingsByName = bindingsByRoot[ rootUuid ]; + return textures; - if ( bindingsByName === undefined ) { + } - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; + parseObject( data, geometries, materials, textures, animations ) { - } + let object; - for ( let i = 0; i !== nTracks; ++ i ) { + function getGeometry( name ) { - const track = tracks[ i ], - trackName = track.name; + if ( geometries[ name ] === undefined ) { - let binding = bindingsByName[ trackName ]; + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - if ( binding !== undefined ) { + } - ++ binding.referenceCount; - bindings[ i ] = binding; + return geometries[ name ]; - } else { + } - binding = bindings[ i ]; + function getMaterial( name ) { - if ( binding !== undefined ) { + if ( name === undefined ) return undefined; - // existing binding, make sure the cache knows + if ( Array.isArray( name ) ) { - if ( binding._cacheIndex === null ) { + const array = []; - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + for ( let i = 0, l = name.length; i < l; i ++ ) { + + const uuid = name[ i ]; + + if ( materials[ uuid ] === undefined ) { + + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); } - continue; + array.push( materials[ uuid ] ); } - const path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; + return array; - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); + } - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + if ( materials[ name ] === undefined ) { - bindings[ i ] = binding; + console.warn( 'THREE.ObjectLoader: Undefined material', name ); } - interpolants[ i ].resultBuffer = binding.buffer; + return materials[ name ]; } - } + function getTexture( uuid ) { - _activateAction( action ) { + if ( textures[ uuid ] === undefined ) { - if ( ! this._isActiveAction( action ) ) { + console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); - if ( action._cacheIndex === null ) { + } - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind + return textures[ uuid ]; - const rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; + } - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); + let geometry, material; - this._addInactiveAction( action, clipUuid, rootUuid ); + switch ( data.type ) { - } + case 'Scene': - const bindings = action._propertyBindings; + object = new Scene(); - // increment reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + if ( data.background !== undefined ) { - const binding = bindings[ i ]; + if ( Number.isInteger( data.background ) ) { - if ( binding.useCount ++ === 0 ) { + object.background = new Color( data.background ); - this._lendBinding( binding ); - binding.saveOriginalState(); + } else { - } + object.background = getTexture( data.background ); - } + } - this._lendAction( action ); + } - } + if ( data.environment !== undefined ) { - } + object.environment = getTexture( data.environment ); - _deactivateAction( action ) { + } - if ( this._isActiveAction( action ) ) { + if ( data.fog !== undefined ) { - const bindings = action._propertyBindings; + if ( data.fog.type === 'Fog' ) { - // decrement reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - const binding = bindings[ i ]; + } else if ( data.fog.type === 'FogExp2' ) { - if ( -- binding.useCount === 0 ) { + object.fog = new FogExp2( data.fog.color, data.fog.density ); - binding.restoreOriginalState(); - this._takeBackBinding( binding ); + } } - } + break; - this._takeBackAction( action ); + case 'PerspectiveCamera': - } + object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - } + if ( data.focus !== undefined ) object.focus = data.focus; + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; + if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - // Memory manager + break; - _initMemoryManager() { + case 'OrthographicCamera': - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + break; - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; + case 'AmbientLight': - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > + object = new AmbientLight( data.color, data.intensity ); + break; - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; + case 'DirectionalLight': - const scope = this; + object = new DirectionalLight( data.color, data.intensity ); - this.stats = { + break; - actions: { - get total() { + case 'PointLight': - return scope._actions.length; + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - }, - get inUse() { + break; - return scope._nActiveActions; + case 'RectAreaLight': - } - }, - bindings: { - get total() { + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); - return scope._bindings.length; + break; - }, - get inUse() { + case 'SpotLight': - return scope._nActiveBindings; + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - } - }, - controlInterpolants: { - get total() { + break; - return scope._controlInterpolants.length; + case 'HemisphereLight': - }, - get inUse() { + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - return scope._nActiveControlInterpolants; + break; - } - } + case 'LightProbe': - }; + object = new LightProbe().fromJSON( data ); - } + break; - // Memory management for AnimationAction objects + case 'SkinnedMesh': - _isActiveAction( action ) { + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); - const index = action._cacheIndex; - return index !== null && index < this._nActiveActions; + object = new SkinnedMesh( geometry, material ); - } + if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; + if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); + if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; - _addInactiveAction( action, clipUuid, rootUuid ) { + break; - const actions = this._actions, - actionsByClip = this._actionsByClip; + case 'Mesh': - let actionsForClip = actionsByClip[ clipUuid ]; + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); - if ( actionsForClip === undefined ) { + object = new Mesh( geometry, material ); - actionsForClip = { + break; - knownActions: [ action ], - actionByRoot: {} + case 'InstancedMesh': - }; + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); + const count = data.count; + const instanceMatrix = data.instanceMatrix; + const instanceColor = data.instanceColor; - action._byClipCacheIndex = 0; + object = new InstancedMesh( geometry, material, count ); + object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); + if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); - actionsByClip[ clipUuid ] = actionsForClip; + break; - } else { + case 'LOD': - const knownActions = actionsForClip.knownActions; + object = new LOD(); - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); + break; - } + case 'Line': - action._cacheIndex = actions.length; - actions.push( action ); + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); - actionsForClip.actionByRoot[ rootUuid ] = action; + break; - } + case 'LineLoop': - _removeInactiveAction( action ) { + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - const actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; + break; - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + case 'LineSegments': - action._cacheIndex = null; + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + break; - const clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, + case 'PointCloud': + case 'Points': - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - byClipCacheIndex = action._byClipCacheIndex; + break; - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); + case 'Sprite': - action._byClipCacheIndex = null; + object = new Sprite( getMaterial( data.material ) ); + break; - const actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; + case 'Group': - delete actionByRoot[ rootUuid ]; + object = new Group(); - if ( knownActionsForClip.length === 0 ) { + break; - delete actionsByClip[ clipUuid ]; + case 'Bone': - } + object = new Bone(); - this._removeInactiveBindingsForAction( action ); + break; - } + default: - _removeInactiveBindingsForAction( action ) { + object = new Object3D(); - const bindings = action._propertyBindings; + } - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + object.uuid = data.uuid; - const binding = bindings[ i ]; + if ( data.name !== undefined ) object.name = data.name; - if ( -- binding.referenceCount === 0 ) { + if ( data.matrix !== undefined ) { - this._removeInactiveBinding( binding ); + object.matrix.fromArray( data.matrix ); - } + if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; + if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); - } + } else { - } + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - _lendAction( action ) { + } - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s + if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - const actions = this._actions, - prevIndex = action._cacheIndex, + if ( data.shadow ) { - lastActiveIndex = this._nActiveActions ++, + if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; + if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; + if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; + if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); + if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); - firstInactiveAction = actions[ lastActiveIndex ]; + } - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; + if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; + if ( data.userData !== undefined ) object.userData = data.userData; + if ( data.layers !== undefined ) object.layers.mask = data.layers; - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; + if ( data.children !== undefined ) { - } + const children = data.children; - _takeBackAction( action ) { + for ( let i = 0; i < children.length; i ++ ) { - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a + object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); - const actions = this._actions, - prevIndex = action._cacheIndex, + } - firstInactiveIndex = -- this._nActiveActions, + } - lastActiveAction = actions[ firstInactiveIndex ]; + if ( data.animations !== undefined ) { - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; + const objectAnimations = data.animations; - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; + for ( let i = 0; i < objectAnimations.length; i ++ ) { - } + const uuid = objectAnimations[ i ]; - // Memory management for PropertyMixer objects + object.animations.push( animations[ uuid ] ); - _addInactiveBinding( binding, rootUuid, trackName ) { + } - const bindingsByRoot = this._bindingsByRootAndName, - bindings = this._bindings; + } - let bindingByName = bindingsByRoot[ rootUuid ]; + if ( data.type === 'LOD' ) { - if ( bindingByName === undefined ) { + if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; + const levels = data.levels; - } + for ( let l = 0; l < levels.length; l ++ ) { - bindingByName[ trackName ] = binding; + const level = levels[ l ]; + const child = object.getObjectByProperty( 'uuid', level.object ); - binding._cacheIndex = bindings.length; - bindings.push( binding ); + if ( child !== undefined ) { - } + object.addLevel( child, level.distance ); - _removeInactiveBinding( binding ) { + } - const bindings = this._bindings, - propBinding = binding.binding, - rootUuid = propBinding.rootNode.uuid, - trackName = propBinding.path, - bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], + } - lastInactiveBinding = bindings[ bindings.length - 1 ], - cacheIndex = binding._cacheIndex; + } - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); + return object; - delete bindingByName[ trackName ]; + } - if ( Object.keys( bindingByName ).length === 0 ) { + bindSkeletons( object, skeletons ) { - delete bindingsByRoot[ rootUuid ]; + if ( Object.keys( skeletons ).length === 0 ) return; - } + object.traverse( function ( child ) { - } + if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { - _lendBinding( binding ) { + const skeleton = skeletons[ child.skeleton ]; - const bindings = this._bindings, - prevIndex = binding._cacheIndex, + if ( skeleton === undefined ) { - lastActiveIndex = this._nActiveBindings ++, + console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); - firstInactiveBinding = bindings[ lastActiveIndex ]; + } else { - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; + child.bind( skeleton, child.bindMatrix ); - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; + } - } + } - _takeBackBinding( binding ) { + } ); - const bindings = this._bindings, - prevIndex = binding._cacheIndex, + } - firstInactiveIndex = -- this._nActiveBindings, + } - lastActiveBinding = bindings[ firstInactiveIndex ]; + const TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping + }; - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; + const TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping + }; - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; + const TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipmapNearestFilter: NearestMipmapNearestFilter, + NearestMipmapLinearFilter: NearestMipmapLinearFilter, + LinearFilter: LinearFilter, + LinearMipmapNearestFilter: LinearMipmapNearestFilter, + LinearMipmapLinearFilter: LinearMipmapLinearFilter + }; - } + class ImageBitmapLoader extends Loader { + constructor( manager ) { - // Memory management of Interpolants for weight and time scale + super( manager ); - _lendControlInterpolant() { + this.isImageBitmapLoader = true; - const interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++; + if ( typeof createImageBitmap === 'undefined' ) { - let interpolant = interpolants[ lastActiveIndex ]; + console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - if ( interpolant === undefined ) { + } - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, _controlInterpolantsResultBuffer ); + if ( typeof fetch === 'undefined' ) { - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; + console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); } - return interpolant; + this.options = { premultiplyAlpha: 'none' }; } - _takeBackControlInterpolant( interpolant ) { - - const interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, + setOptions( options ) { - firstInactiveIndex = -- this._nActiveControlInterpolants, + this.options = options; - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; + return this; - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; + } - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; + load( url, onLoad, onProgress, onError ) { - } + if ( url === undefined ) url = ''; - // return an action for a clip optionally using a custom root target - // object (this method allocates a lot of dynamic memory in case a - // previously unknown clip/root combination is specified) - clipAction( clip, optionalRoot, blendMode ) { + if ( this.path !== undefined ) url = this.path + url; - const root = optionalRoot || this._root, - rootUuid = root.uuid; + url = this.manager.resolveURL( url ); - let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; + const scope = this; - const clipUuid = clipObject !== null ? clipObject.uuid : clip; + const cached = Cache.get( url ); - const actionsForClip = this._actionsByClip[ clipUuid ]; - let prototypeAction = null; + if ( cached !== undefined ) { - if ( blendMode === undefined ) { + scope.manager.itemStart( url ); - if ( clipObject !== null ) { + setTimeout( function () { - blendMode = clipObject.blendMode; + if ( onLoad ) onLoad( cached ); - } else { + scope.manager.itemEnd( url ); - blendMode = NormalAnimationBlendMode; + }, 0 ); - } + return cached; } - if ( actionsForClip !== undefined ) { + const fetchOptions = {}; + fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; + fetchOptions.headers = this.requestHeader; - const existingAction = actionsForClip.actionByRoot[ rootUuid ]; + fetch( url, fetchOptions ).then( function ( res ) { - if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { + return res.blob(); - return existingAction; + } ).then( function ( blob ) { - } + return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; + } ).then( function ( imageBitmap ) { - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; + Cache.add( url, imageBitmap ); - } + if ( onLoad ) onLoad( imageBitmap ); - // clip must be known when specified via string - if ( clipObject === null ) return null; + scope.manager.itemEnd( url ); - // allocate all resources required to run it - const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); + } ).catch( function ( e ) { - this._bindAction( newAction, prototypeAction ); + if ( onError ) onError( e ); - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - return newAction; + } ); - } + scope.manager.itemStart( url ); - // get an existing action - existingAction( clip, optionalRoot ) { + } - const root = optionalRoot || this._root, - rootUuid = root.uuid, + } - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, + let _context; - clipUuid = clipObject ? clipObject.uuid : clip, + const AudioContext = { - actionsForClip = this._actionsByClip[ clipUuid ]; + getContext: function () { - if ( actionsForClip !== undefined ) { + if ( _context === undefined ) { - return actionsForClip.actionByRoot[ rootUuid ] || null; + _context = new ( window.AudioContext || window.webkitAudioContext )(); } - return null; + return _context; - } + }, - // deactivates all previously scheduled actions - stopAllAction() { + setContext: function ( value ) { - const actions = this._actions, - nActions = this._nActiveActions; + _context = value; - for ( let i = nActions - 1; i >= 0; -- i ) { + } - actions[ i ].stop(); + }; - } + class AudioLoader extends Loader { - return this; + constructor( manager ) { + + super( manager ); } - // advance the time and update apply the animation - update( deltaTime ) { + load( url, onLoad, onProgress, onError ) { - deltaTime *= this.timeScale; + const scope = this; - const actions = this._actions, - nActions = this._nActiveActions, + const loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( buffer ) { - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), + try { - accuIndex = this._accuIndex ^= 1; + // Create a copy of the buffer. The `decodeAudioData` method + // detaches the buffer when complete, preventing reuse. + const bufferCopy = buffer.slice( 0 ); - // run active actions + const context = AudioContext.getContext(); + context.decodeAudioData( bufferCopy, function ( audioBuffer ) { - for ( let i = 0; i !== nActions; ++ i ) { + onLoad( audioBuffer ); - const action = actions[ i ]; + } ); - action._update( time, deltaTime, timeDirection, accuIndex ); + } catch ( e ) { - } + if ( onError ) { - // update scene graph + onError( e ); - const bindings = this._bindings, - nBindings = this._nActiveBindings; + } else { - for ( let i = 0; i !== nBindings; ++ i ) { + console.error( e ); - bindings[ i ].apply( accuIndex ); + } - } + scope.manager.itemError( url ); - return this; + } + + }, onProgress, onError ); } - // Allows you to seek to a specific time in an animation. - setTime( timeInSeconds ) { + } - this.time = 0; // Zero out time attribute for AnimationMixer object; - for ( let i = 0; i < this._actions.length; i ++ ) { + class HemisphereLightProbe extends LightProbe { - this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. + constructor( skyColor, groundColor, intensity = 1 ) { - } + super( undefined, intensity ); - return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. + this.isHemisphereLightProbe = true; - } + const color1 = new Color().set( skyColor ); + const color2 = new Color().set( groundColor ); - // return this mixer's root target object - getRoot() { + const sky = new Vector3( color1.r, color1.g, color1.b ); + const ground = new Vector3( color2.r, color2.g, color2.b ); - return this._root; + // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI ); + const c0 = Math.sqrt( Math.PI ); + const c1 = c0 * Math.sqrt( 0.75 ); + + this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 ); + this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 ); } - // free all resources specific to a particular clip - uncacheClip( clip ) { + } - const actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; + class AmbientLightProbe extends LightProbe { - if ( actionsForClip !== undefined ) { + constructor( color, intensity = 1 ) { - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away + super( undefined, intensity ); - const actionsToRemove = actionsForClip.knownActions; + this.isAmbientLightProbe = true; - for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { + const color1 = new Color().set( color ); - const action = actionsToRemove[ i ]; + // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI ); + this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) ); - this._deactivateAction( action ); + } - const cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; + } - action._cacheIndex = null; - action._byClipCacheIndex = null; + const _eyeRight = /*@__PURE__*/ new Matrix4(); + const _eyeLeft = /*@__PURE__*/ new Matrix4(); + const _projectionMatrix = /*@__PURE__*/ new Matrix4(); - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + class StereoCamera { - this._removeInactiveBindingsForAction( action ); + constructor() { - } + this.type = 'StereoCamera'; - delete actionsByClip[ clipUuid ]; + this.aspect = 1; - } + this.eyeSep = 0.064; - } + this.cameraL = new PerspectiveCamera(); + this.cameraL.layers.enable( 1 ); + this.cameraL.matrixAutoUpdate = false; - // free all resources specific to a particular root target object - uncacheRoot( root ) { + this.cameraR = new PerspectiveCamera(); + this.cameraR.layers.enable( 2 ); + this.cameraR.matrixAutoUpdate = false; - const rootUuid = root.uuid, - actionsByClip = this._actionsByClip; + this._cache = { + focus: null, + fov: null, + aspect: null, + near: null, + far: null, + zoom: null, + eyeSep: null + }; - for ( const clipUuid in actionsByClip ) { + } - const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; + update( camera ) { - if ( action !== undefined ) { + const cache = this._cache; - this._deactivateAction( action ); - this._removeInactiveAction( action ); + const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || + cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || + cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; - } + if ( needsUpdate ) { - } + cache.focus = camera.focus; + cache.fov = camera.fov; + cache.aspect = camera.aspect * this.aspect; + cache.near = camera.near; + cache.far = camera.far; + cache.zoom = camera.zoom; + cache.eyeSep = this.eyeSep; - const bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; + // Off-axis stereoscopic effect based on + // http://paulbourke.net/stereographics/stereorender/ - if ( bindingByName !== undefined ) { + _projectionMatrix.copy( camera.projectionMatrix ); + const eyeSepHalf = cache.eyeSep / 2; + const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; + const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; + let xmin, xmax; - for ( const trackName in bindingByName ) { + // translate xOffset - const binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); + _eyeLeft.elements[ 12 ] = - eyeSepHalf; + _eyeRight.elements[ 12 ] = eyeSepHalf; - } + // for left eye - } + xmin = - ymax * cache.aspect + eyeSepOnProjection; + xmax = ymax * cache.aspect + eyeSepOnProjection; - } + _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - // remove a targeted clip from the cache - uncacheAction( clip, optionalRoot ) { + this.cameraL.projectionMatrix.copy( _projectionMatrix ); - const action = this.existingAction( clip, optionalRoot ); + // for right eye - if ( action !== null ) { + xmin = - ymax * cache.aspect - eyeSepOnProjection; + xmax = ymax * cache.aspect - eyeSepOnProjection; - this._deactivateAction( action ); - this._removeInactiveAction( action ); + _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + + this.cameraR.projectionMatrix.copy( _projectionMatrix ); } + this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); + this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); + } } - class Uniform { - - constructor( value ) { + class Clock { - this.value = value; + constructor( autoStart = true ) { - } + this.autoStart = autoStart; - clone() { + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); + this.running = false; } - } + start() { - let id = 0; + this.startTime = now(); - class UniformsGroup extends EventDispatcher { + this.oldTime = this.startTime; + this.elapsedTime = 0; + this.running = true; - constructor() { + } - super(); + stop() { - this.isUniformsGroup = true; + this.getElapsedTime(); + this.running = false; + this.autoStart = false; - Object.defineProperty( this, 'id', { value: id ++ } ); + } - this.name = ''; + getElapsedTime() { - this.usage = StaticDrawUsage; - this.uniforms = []; + this.getDelta(); + return this.elapsedTime; } - add( uniform ) { + getDelta() { - this.uniforms.push( uniform ); + let diff = 0; - return this; + if ( this.autoStart && ! this.running ) { - } + this.start(); + return 0; - remove( uniform ) { + } - const index = this.uniforms.indexOf( uniform ); + if ( this.running ) { - if ( index !== - 1 ) this.uniforms.splice( index, 1 ); + const newTime = now(); - return this; + diff = ( newTime - this.oldTime ) / 1000; + this.oldTime = newTime; + + this.elapsedTime += diff; + + } + + return diff; } - setName( name ) { + } - this.name = name; + function now() { - return this; + return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 - } + } - setUsage( value ) { + const _position$1 = /*@__PURE__*/ new Vector3(); + const _quaternion$1 = /*@__PURE__*/ new Quaternion(); + const _scale$1 = /*@__PURE__*/ new Vector3(); + const _orientation$1 = /*@__PURE__*/ new Vector3(); - this.usage = value; + class AudioListener extends Object3D { - return this; + constructor() { - } + super(); - dispose() { + this.type = 'AudioListener'; - this.dispatchEvent( { type: 'dispose' } ); + this.context = AudioContext.getContext(); - return this; + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); + + this.filter = null; + + this.timeDelta = 0; + + // private + + this._clock = new Clock(); } - copy( source ) { + getInput() { - this.name = source.name; - this.usage = source.usage; + return this.gain; - const uniformsSource = source.uniforms; + } - this.uniforms.length = 0; + removeFilter() { - for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { + if ( this.filter !== null ) { - this.uniforms.push( uniformsSource[ i ].clone() ); + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + this.gain.connect( this.context.destination ); + this.filter = null; } @@ -56857,290 +88432,335 @@ var app = (function () { } - clone() { + getFilter() { - return new this.constructor().copy( this ); + return this.filter; } - } + setFilter( value ) { - class InstancedInterleavedBuffer extends InterleavedBuffer { + if ( this.filter !== null ) { - constructor( array, stride, meshPerAttribute = 1 ) { + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); - super( array, stride ); + } else { - this.isInstancedInterleavedBuffer = true; + this.gain.disconnect( this.context.destination ); - this.meshPerAttribute = meshPerAttribute; + } + + this.filter = value; + this.gain.connect( this.filter ); + this.filter.connect( this.context.destination ); + + return this; } - copy( source ) { + getMasterVolume() { - super.copy( source ); + return this.gain.gain.value; - this.meshPerAttribute = source.meshPerAttribute; + } + + setMasterVolume( value ) { + + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); return this; } - clone( data ) { + updateMatrixWorld( force ) { - const ib = super.clone( data ); + super.updateMatrixWorld( force ); - ib.meshPerAttribute = this.meshPerAttribute; + const listener = this.context.listener; + const up = this.up; - return ib; + this.timeDelta = this._clock.getDelta(); - } + this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); - toJSON( data ) { + _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); - const json = super.toJSON( data ); + if ( listener.positionX ) { - json.isInstancedInterleavedBuffer = true; - json.meshPerAttribute = this.meshPerAttribute; + // code path for Chrome (see #14393) - return json; + const endTime = this.context.currentTime + this.timeDelta; + + listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); + listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); + listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); + listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); + listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); + listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); + listener.upX.linearRampToValueAtTime( up.x, endTime ); + listener.upY.linearRampToValueAtTime( up.y, endTime ); + listener.upZ.linearRampToValueAtTime( up.z, endTime ); + + } else { + + listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); + listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); + + } } } - class GLBufferAttribute { + class Audio extends Object3D { - constructor( buffer, type, itemSize, elementSize, count ) { + constructor( listener ) { - this.isGLBufferAttribute = true; + super(); - this.buffer = buffer; - this.type = type; - this.itemSize = itemSize; - this.elementSize = elementSize; - this.count = count; + this.type = 'Audio'; - this.version = 0; + this.listener = listener; + this.context = listener.context; + + this.gain = this.context.createGain(); + this.gain.connect( listener.getInput() ); + + this.autoplay = false; + + this.buffer = null; + this.detune = 0; + this.loop = false; + this.loopStart = 0; + this.loopEnd = 0; + this.offset = 0; + this.duration = undefined; + this.playbackRate = 1; + this.isPlaying = false; + this.hasPlaybackControl = true; + this.source = null; + this.sourceType = 'empty'; + + this._startedAt = 0; + this._progress = 0; + this._connected = false; + + this.filters = []; } - set needsUpdate( value ) { + getOutput() { - if ( value === true ) this.version ++; + return this.gain; } - setBuffer( buffer ) { + setNodeSource( audioNode ) { - this.buffer = buffer; + this.hasPlaybackControl = false; + this.sourceType = 'audioNode'; + this.source = audioNode; + this.connect(); return this; } - setType( type, elementSize ) { + setMediaElementSource( mediaElement ) { - this.type = type; - this.elementSize = elementSize; + this.hasPlaybackControl = false; + this.sourceType = 'mediaNode'; + this.source = this.context.createMediaElementSource( mediaElement ); + this.connect(); return this; } - setItemSize( itemSize ) { + setMediaStreamSource( mediaStream ) { - this.itemSize = itemSize; + this.hasPlaybackControl = false; + this.sourceType = 'mediaStreamNode'; + this.source = this.context.createMediaStreamSource( mediaStream ); + this.connect(); return this; } - setCount( count ) { + setBuffer( audioBuffer ) { - this.count = count; + this.buffer = audioBuffer; + this.sourceType = 'buffer'; + + if ( this.autoplay ) this.play(); return this; } - } - - class Raycaster { + play( delay = 0 ) { - constructor( origin, direction, near = 0, far = Infinity ) { + if ( this.isPlaying === true ) { - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) + console.warn( 'THREE.Audio: Audio is already playing.' ); + return; - this.near = near; - this.far = far; - this.camera = null; - this.layers = new Layers(); + } - this.params = { - Mesh: {}, - Line: { threshold: 1 }, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; + if ( this.hasPlaybackControl === false ) { - } + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - set( origin, direction ) { + } - // direction is assumed to be normalized (for accurate distance calculations) + this._startedAt = this.context.currentTime + delay; - this.ray.set( origin, direction ); + const source = this.context.createBufferSource(); + source.buffer = this.buffer; + source.loop = this.loop; + source.loopStart = this.loopStart; + source.loopEnd = this.loopEnd; + source.onended = this.onEnded.bind( this ); + source.start( this._startedAt, this._progress + this.offset, this.duration ); - } + this.isPlaying = true; - setFromCamera( coords, camera ) { + this.source = source; - if ( camera.isPerspectiveCamera ) { + this.setDetune( this.detune ); + this.setPlaybackRate( this.playbackRate ); - this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - this.camera = camera; + return this.connect(); - } else if ( camera.isOrthographicCamera ) { + } - this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera - this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - this.camera = camera; + pause() { - } else { + if ( this.hasPlaybackControl === false ) { - console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; } - } + if ( this.isPlaying === true ) { - intersectObject( object, recursive = true, intersects = [] ) { + // update current progress - intersectObject( object, this, intersects, recursive ); + this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; - intersects.sort( ascSort ); + if ( this.loop === true ) { - return intersects; + // ensure _progress does not exceed duration with looped audios - } + this._progress = this._progress % ( this.duration || this.buffer.duration ); - intersectObjects( objects, recursive = true, intersects = [] ) { + } - for ( let i = 0, l = objects.length; i < l; i ++ ) { + this.source.stop(); + this.source.onended = null; - intersectObject( objects[ i ], this, intersects, recursive ); + this.isPlaying = false; } - intersects.sort( ascSort ); - - return intersects; + return this; } - } + stop() { - function ascSort( a, b ) { + if ( this.hasPlaybackControl === false ) { - return a.distance - b.distance; + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - } + } - function intersectObject( object, raycaster, intersects, recursive ) { + this._progress = 0; - if ( object.layers.test( raycaster.layers ) ) { + this.source.stop(); + this.source.onended = null; + this.isPlaying = false; - object.raycast( raycaster, intersects ); + return this; } - if ( recursive === true ) { + connect() { - const children = object.children; + if ( this.filters.length > 0 ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + this.source.connect( this.filters[ 0 ] ); - intersectObject( children[ i ], raycaster, intersects, true ); + for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - } + this.filters[ i - 1 ].connect( this.filters[ i ] ); - } + } - } + this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - /** - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up. - * The azimuthal angle (theta) is measured from the positive z-axis. - */ + } else { - class Spherical { + this.source.connect( this.getOutput() ); - constructor( radius = 1, phi = 0, theta = 0 ) { + } - this.radius = radius; - this.phi = phi; // polar angle - this.theta = theta; // azimuthal angle + this._connected = true; return this; } - set( radius, phi, theta ) { + disconnect() { - this.radius = radius; - this.phi = phi; - this.theta = theta; + if ( this.filters.length > 0 ) { - return this; + this.source.disconnect( this.filters[ 0 ] ); - } + for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - copy( other ) { + this.filters[ i - 1 ].disconnect( this.filters[ i ] ); - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; + } - return this; + this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); - } + } else { - // restrict phi to be between EPS and PI-EPS - makeSafe() { + this.source.disconnect( this.getOutput() ); - const EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); + } + + this._connected = false; return this; } - setFromVector3( v ) { + getFilters() { - return this.setFromCartesianCoords( v.x, v.y, v.z ); + return this.filters; } - setFromCartesianCoords( x, y, z ) { + setFilters( value ) { - this.radius = Math.sqrt( x * x + y * y + z * z ); + if ( ! value ) value = []; - if ( this.radius === 0 ) { + if ( this._connected === true ) { - this.theta = 0; - this.phi = 0; + this.disconnect(); + this.filters = value.slice(); + this.connect(); } else { - this.theta = Math.atan2( x, z ); - this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) ); + this.filters = value.slice(); } @@ -57148,3907 +88768,7468 @@ var app = (function () { } - clone() { - - return new this.constructor().copy( this ); - - } + setDetune( value ) { - } + this.detune = value; - /** - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - */ + if ( this.source.detune === undefined ) return; // only set detune when available - class Cylindrical { + if ( this.isPlaying === true ) { - constructor( radius = 1, theta = 0, y = 0 ) { + this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); - this.radius = radius; // distance from the origin to a point in the x-z plane - this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = y; // height above the x-z plane + } return this; } - set( radius, theta, y ) { - - this.radius = radius; - this.theta = theta; - this.y = y; + getDetune() { - return this; + return this.detune; } - copy( other ) { - - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; + getFilter() { - return this; + return this.getFilters()[ 0 ]; } - setFromVector3( v ) { + setFilter( filter ) { - return this.setFromCartesianCoords( v.x, v.y, v.z ); + return this.setFilters( filter ? [ filter ] : [] ); } - setFromCartesianCoords( x, y, z ) { - - this.radius = Math.sqrt( x * x + z * z ); - this.theta = Math.atan2( x, z ); - this.y = y; + setPlaybackRate( value ) { - return this; + if ( this.hasPlaybackControl === false ) { - } + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - clone() { + } - return new this.constructor().copy( this ); + this.playbackRate = value; - } + if ( this.isPlaying === true ) { - } + this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); - const _vector$4 = /*@__PURE__*/ new Vector2(); + } - class Box2 { + return this; - constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { + } - this.isBox2 = true; + getPlaybackRate() { - this.min = min; - this.max = max; + return this.playbackRate; } - set( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); + onEnded() { - return this; + this.isPlaying = false; } - setFromPoints( points ) { - - this.makeEmpty(); + getLoop() { - for ( let i = 0, il = points.length; i < il; i ++ ) { + if ( this.hasPlaybackControl === false ) { - this.expandByPoint( points[ i ] ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return false; } - return this; + return this.loop; } - setFromCenterAndSize( center, size ) { - - const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + setLoop( value ) { - return this; + if ( this.hasPlaybackControl === false ) { - } + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - clone() { + } - return new this.constructor().copy( this ); + this.loop = value; - } + if ( this.isPlaying === true ) { - copy( box ) { + this.source.loop = this.loop; - this.min.copy( box.min ); - this.max.copy( box.max ); + } return this; } - makeEmpty() { + setLoopStart( value ) { - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; + this.loopStart = value; return this; } - isEmpty() { + setLoopEnd( value ) { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + this.loopEnd = value; - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + return this; } - getCenter( target ) { + getVolume() { - return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + return this.gain.gain.value; } - getSize( target ) { + setVolume( value ) { - return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - } + return this; - expandByPoint( point ) { + } - this.min.min( point ); - this.max.max( point ); + } - return this; + const _position = /*@__PURE__*/ new Vector3(); + const _quaternion = /*@__PURE__*/ new Quaternion(); + const _scale = /*@__PURE__*/ new Vector3(); + const _orientation = /*@__PURE__*/ new Vector3(); - } + class PositionalAudio extends Audio { - expandByVector( vector ) { + constructor( listener ) { - this.min.sub( vector ); - this.max.add( vector ); + super( listener ); - return this; + this.panner = this.context.createPanner(); + this.panner.panningModel = 'HRTF'; + this.panner.connect( this.gain ); } - expandByScalar( scalar ) { + disconnect() { - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + super.disconnect(); - return this; + this.panner.disconnect( this.gain ); } - containsPoint( point ) { + getOutput() { - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ? false : true; + return this.panner; } - containsBox( box ) { + getRefDistance() { - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y; + return this.panner.refDistance; } - getParameter( point, target ) { + setRefDistance( value ) { - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + this.panner.refDistance = value; - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); + return this; } - intersectsBox( box ) { - - // using 4 splitting planes to rule out intersections + getRolloffFactor() { - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ? false : true; + return this.panner.rolloffFactor; } - clampPoint( point, target ) { + setRolloffFactor( value ) { - return target.copy( point ).clamp( this.min, this.max ); + this.panner.rolloffFactor = value; + + return this; } - distanceToPoint( point ) { + getDistanceModel() { - const clampedPoint = _vector$4.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); + return this.panner.distanceModel; } - intersect( box ) { + setDistanceModel( value ) { - this.min.max( box.min ); - this.max.min( box.max ); + this.panner.distanceModel = value; return this; } - union( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); + getMaxDistance() { - return this; + return this.panner.maxDistance; } - translate( offset ) { + setMaxDistance( value ) { - this.min.add( offset ); - this.max.add( offset ); + this.panner.maxDistance = value; return this; } - equals( box ) { + setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { - return box.min.equals( this.min ) && box.max.equals( this.max ); + this.panner.coneInnerAngle = coneInnerAngle; + this.panner.coneOuterAngle = coneOuterAngle; + this.panner.coneOuterGain = coneOuterGain; + + return this; } - } + updateMatrixWorld( force ) { - const _startP = /*@__PURE__*/ new Vector3(); - const _startEnd = /*@__PURE__*/ new Vector3(); + super.updateMatrixWorld( force ); - class Line3 { + if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; - constructor( start = new Vector3(), end = new Vector3() ) { + this.matrixWorld.decompose( _position, _quaternion, _scale ); - this.start = start; - this.end = end; + _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); - } + const panner = this.panner; - set( start, end ) { + if ( panner.positionX ) { - this.start.copy( start ); - this.end.copy( end ); + // code path for Chrome and Firefox (see #14393) - return this; + const endTime = this.context.currentTime + this.listener.timeDelta; - } + panner.positionX.linearRampToValueAtTime( _position.x, endTime ); + panner.positionY.linearRampToValueAtTime( _position.y, endTime ); + panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); + panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); + panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); + panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); - copy( line ) { + } else { - this.start.copy( line.start ); - this.end.copy( line.end ); + panner.setPosition( _position.x, _position.y, _position.z ); + panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); - return this; + } } - getCenter( target ) { + } - return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + class AudioAnalyser { - } + constructor( audio, fftSize = 2048 ) { - delta( target ) { + this.analyser = audio.context.createAnalyser(); + this.analyser.fftSize = fftSize; - return target.subVectors( this.end, this.start ); + this.data = new Uint8Array( this.analyser.frequencyBinCount ); + + audio.getOutput().connect( this.analyser ); } - distanceSq() { - return this.start.distanceToSquared( this.end ); + getFrequencyData() { + + this.analyser.getByteFrequencyData( this.data ); + + return this.data; } - distance() { + getAverageFrequency() { - return this.start.distanceTo( this.end ); + let value = 0; + const data = this.getFrequencyData(); - } + for ( let i = 0; i < data.length; i ++ ) { - at( t, target ) { + value += data[ i ]; - return this.delta( target ).multiplyScalar( t ).add( this.start ); + } + + return value / data.length; } - closestPointToPointParameter( point, clampToLine ) { + } - _startP.subVectors( point, this.start ); - _startEnd.subVectors( this.end, this.start ); + class PropertyMixer { - const startEnd2 = _startEnd.dot( _startEnd ); - const startEnd_startP = _startEnd.dot( _startP ); + constructor( binding, typeName, valueSize ) { - let t = startEnd_startP / startEnd2; + this.binding = binding; + this.valueSize = valueSize; - if ( clampToLine ) { + let mixFunction, + mixFunctionAdditive, + setIdentity; - t = clamp( t, 0, 1 ); + // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] + // + // interpolators can use .buffer as their .result + // the data then goes to 'incoming' + // + // 'accu0' and 'accu1' are used frame-interleaved for + // the cumulative result and are compared to detect + // changes + // + // 'orig' stores the original state of the property + // + // 'add' is used for additive cumulative results + // + // 'work' is optional and is only present for quaternion types. It is used + // to store intermediate quaternion multiplication results - } + switch ( typeName ) { - return t; + case 'quaternion': + mixFunction = this._slerp; + mixFunctionAdditive = this._slerpAdditive; + setIdentity = this._setAdditiveIdentityQuaternion; - } + this.buffer = new Float64Array( valueSize * 6 ); + this._workIndex = 5; + break; - closestPointToPoint( point, clampToLine, target ) { + case 'string': + case 'bool': + mixFunction = this._select; - const t = this.closestPointToPointParameter( point, clampToLine ); + // Use the regular mix function and for additive on these types, + // additive is not relevant for non-numeric types + mixFunctionAdditive = this._select; - return this.delta( target ).multiplyScalar( t ).add( this.start ); + setIdentity = this._setAdditiveIdentityOther; - } + this.buffer = new Array( valueSize * 5 ); + break; - applyMatrix4( matrix ) { + default: + mixFunction = this._lerp; + mixFunctionAdditive = this._lerpAdditive; + setIdentity = this._setAdditiveIdentityNumeric; - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); + this.buffer = new Float64Array( valueSize * 5 ); - return this; + } - } + this._mixBufferRegion = mixFunction; + this._mixBufferRegionAdditive = mixFunctionAdditive; + this._setIdentity = setIdentity; + this._origIndex = 3; + this._addIndex = 4; - equals( line ) { + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - return line.start.equals( this.start ) && line.end.equals( this.end ); + this.useCount = 0; + this.referenceCount = 0; } - clone() { + // accumulate data in the 'incoming' region into 'accu' + accumulate( accuIndex, weight ) { - return new this.constructor().copy( this ); + // note: happily accumulating nothing when weight = 0, the caller knows + // the weight and shouldn't have made the call in the first place - } + const buffer = this.buffer, + stride = this.valueSize, + offset = accuIndex * stride + stride; - } + let currentWeight = this.cumulativeWeight; - const _vector$3 = /*@__PURE__*/ new Vector3(); + if ( currentWeight === 0 ) { - class SpotLightHelper extends Object3D { + // accuN := incoming * weight - constructor( light, color ) { + for ( let i = 0; i !== stride; ++ i ) { - super(); + buffer[ offset + i ] = buffer[ i ]; - this.light = light; - this.light.updateMatrixWorld(); + } - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + currentWeight = weight; - this.color = color; + } else { - const geometry = new BufferGeometry(); + // accuN := accuN + incoming * weight - const positions = [ - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 1, - 0, 0, 0, - 1, 0, 1, - 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, - 1, 1 - ]; + currentWeight += weight; + const mix = weight / currentWeight; + this._mixBufferRegion( buffer, offset, 0, mix, stride ); - for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { + } - const p1 = ( i / l ) * Math.PI * 2; - const p2 = ( j / l ) * Math.PI * 2; + this.cumulativeWeight = currentWeight; - positions.push( - Math.cos( p1 ), Math.sin( p1 ), 1, - Math.cos( p2 ), Math.sin( p2 ), 1 - ); + } - } + // accumulate data in the 'incoming' region into 'add' + accumulateAdditive( weight ) { - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + const buffer = this.buffer, + stride = this.valueSize, + offset = stride * this._addIndex; - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); + if ( this.cumulativeWeightAdditive === 0 ) { - this.cone = new LineSegments( geometry, material ); - this.add( this.cone ); + // add = identity - this.update(); + this._setIdentity(); - } + } - dispose() { + // add := add + incoming * weight - this.cone.geometry.dispose(); - this.cone.material.dispose(); + this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); + this.cumulativeWeightAdditive += weight; } - update() { - - this.light.updateMatrixWorld(); + // apply the state of 'accu' to the binding when accus differ + apply( accuIndex ) { - const coneLength = this.light.distance ? this.light.distance : 1000; - const coneWidth = coneLength * Math.tan( this.light.angle ); + const stride = this.valueSize, + buffer = this.buffer, + offset = accuIndex * stride + stride, - this.cone.scale.set( coneWidth, coneWidth, coneLength ); + weight = this.cumulativeWeight, + weightAdditive = this.cumulativeWeightAdditive, - _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); + binding = this.binding; - this.cone.lookAt( _vector$3 ); + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - if ( this.color !== undefined ) { + if ( weight < 1 ) { - this.cone.material.color.set( this.color ); + // accuN := accuN + original * ( 1 - cumulativeWeight ) - } else { + const originalValueOffset = stride * this._origIndex; - this.cone.material.color.copy( this.light.color ); + this._mixBufferRegion( + buffer, offset, originalValueOffset, 1 - weight, stride ); } - } + if ( weightAdditive > 0 ) { - } + // accuN := accuN + additive accuN - const _vector$2 = /*@__PURE__*/ new Vector3(); - const _boneMatrix = /*@__PURE__*/ new Matrix4(); - const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); + this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); + } - class SkeletonHelper extends LineSegments { + for ( let i = stride, e = stride + stride; i !== e; ++ i ) { - constructor( object ) { + if ( buffer[ i ] !== buffer[ i + stride ] ) { - const bones = getBoneList( object ); + // value has changed -> update scene graph - const geometry = new BufferGeometry(); + binding.setValue( buffer, offset ); + break; - const vertices = []; - const colors = []; + } - const color1 = new Color( 0, 0, 1 ); - const color2 = new Color( 0, 1, 0 ); + } - for ( let i = 0; i < bones.length; i ++ ) { + } - const bone = bones[ i ]; + // remember the state of the bound property and copy it to both accus + saveOriginalState() { - if ( bone.parent && bone.parent.isBone ) { + const binding = this.binding; - vertices.push( 0, 0, 0 ); - vertices.push( 0, 0, 0 ); - colors.push( color1.r, color1.g, color1.b ); - colors.push( color2.r, color2.g, color2.b ); + const buffer = this.buffer, + stride = this.valueSize, - } + originalValueOffset = stride * this._origIndex; + + binding.getValue( buffer, originalValueOffset ); + + // accu[0..1] := orig -- initially detect changes against the original + for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { + + buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; } - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + // Add to identity for additive + this._setIdentity(); - const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - super( geometry, material ); + } - this.isSkeletonHelper = true; + // apply the state previously taken via 'saveOriginalState' to the binding + restoreOriginalState() { - this.type = 'SkeletonHelper'; + const originalValueOffset = this.valueSize * 3; + this.binding.setValue( this.buffer, originalValueOffset ); - this.root = object; - this.bones = bones; + } - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + _setAdditiveIdentityNumeric() { + + const startIndex = this._addIndex * this.valueSize; + const endIndex = startIndex + this.valueSize; + + for ( let i = startIndex; i < endIndex; i ++ ) { + + this.buffer[ i ] = 0; + + } } - updateMatrixWorld( force ) { + _setAdditiveIdentityQuaternion() { - const bones = this.bones; + this._setAdditiveIdentityNumeric(); + this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; - const geometry = this.geometry; - const position = geometry.getAttribute( 'position' ); + } - _matrixWorldInv.copy( this.root.matrixWorld ).invert(); + _setAdditiveIdentityOther() { - for ( let i = 0, j = 0; i < bones.length; i ++ ) { + const startIndex = this._origIndex * this.valueSize; + const targetIndex = this._addIndex * this.valueSize; - const bone = bones[ i ]; + for ( let i = 0; i < this.valueSize; i ++ ) { - if ( bone.parent && bone.parent.isBone ) { + this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); + } - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); + } - j += 2; + + // mix functions + + _select( buffer, dstOffset, srcOffset, t, stride ) { + + if ( t >= 0.5 ) { + + for ( let i = 0; i !== stride; ++ i ) { + + buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; } } - geometry.getAttribute( 'position' ).needsUpdate = true; + } - super.updateMatrixWorld( force ); + _slerp( buffer, dstOffset, srcOffset, t ) { + + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); } - dispose() { + _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - this.geometry.dispose(); - this.material.dispose(); + const workOffset = this._workIndex * stride; + + // Store result in intermediate buffer offset + Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); + + // Slerp to the intermediate result + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); } - } + _lerp( buffer, dstOffset, srcOffset, t, stride ) { + const s = 1 - t; - function getBoneList( object ) { + for ( let i = 0; i !== stride; ++ i ) { - const boneList = []; + const j = dstOffset + i; - if ( object.isBone === true ) { + buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - boneList.push( object ); + } } - for ( let i = 0; i < object.children.length; i ++ ) { + _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); + for ( let i = 0; i !== stride; ++ i ) { - } + const j = dstOffset + i; - return boneList; + buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; + + } + + } } - class PointLightHelper extends Mesh { + // Characters [].:/ are reserved for track binding syntax. + const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; + const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); - constructor( light, sphereSize, color ) { + // Attempts to allow node names from any language. ES5's `\w` regexp matches + // only latin characters, and the unicode \p{L} is not yet supported. So + // instead, we exclude reserved characters and match everything else. + const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; + const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; - const geometry = new SphereGeometry( sphereSize, 4, 2 ); - const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + // Parent directories, delimited by '/' or ':'. Currently unused, but must + // be matched to parse the rest of the track name. + const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); - super( geometry, material ); + // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. + const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); - this.light = light; - this.light.updateMatrixWorld(); + // Object on target node, and accessor. May not contain reserved + // characters. Accessor may contain any character except closing bracket. + const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); - this.color = color; + // Property and accessor. May not contain reserved characters. Accessor may + // contain any non-bracket characters. + const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); - this.type = 'PointLightHelper'; + const _trackRe = new RegExp( '' + + '^' + + _directoryRe + + _nodeRe + + _objectRe + + _propertyRe + + '$' + ); - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; + const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; - this.update(); + class Composite { + constructor( targetGroup, path, optionalParsedPath ) { - /* - // TODO: delete this comment? - const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + this._targetGroup = targetGroup; + this._bindings = targetGroup.subscribe_( path, parsedPath ); - const d = light.distance; + } - if ( d === 0.0 ) { + getValue( array, offset ) { - this.lightDistance.visible = false; + this.bind(); // bind all binding - } else { + const firstValidIndex = this._targetGroup.nCachedObjects_, + binding = this._bindings[ firstValidIndex ]; - this.lightDistance.scale.set( d, d, d ); + // and only call .getValue on the first + if ( binding !== undefined ) binding.getValue( array, offset ); } - this.add( this.lightDistance ); - */ + setValue( array, offset ) { - } + const bindings = this._bindings; - dispose() { + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - this.geometry.dispose(); - this.material.dispose(); + bindings[ i ].setValue( array, offset ); - } + } - update() { + } - if ( this.color !== undefined ) { + bind() { - this.material.color.set( this.color ); + const bindings = this._bindings; - } else { + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - this.material.color.copy( this.light.color ); + bindings[ i ].bind(); } - /* - const d = this.light.distance; + } - if ( d === 0.0 ) { + unbind() { - this.lightDistance.visible = false; + const bindings = this._bindings; - } else { + for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); + bindings[ i ].unbind(); } - */ } } - const _vector$1 = /*@__PURE__*/ new Vector3(); - const _color1 = /*@__PURE__*/ new Color(); - const _color2 = /*@__PURE__*/ new Color(); + // Note: This class uses a State pattern on a per-method basis: + // 'bind' sets 'this.getValue' / 'setValue' and shadows the + // prototype version of these methods with one that represents + // the bound state. When the property is not found, the methods + // become no-ops. + class PropertyBinding { - class HemisphereLightHelper extends Object3D { + constructor( rootNode, path, parsedPath ) { - constructor( light, size, color ) { + this.path = path; + this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - super(); + this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; - this.light = light; - this.light.updateMatrixWorld(); + this.rootNode = rootNode; - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + // initial state of these methods that calls 'bind' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; - this.color = color; + } - const geometry = new OctahedronGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); - this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - if ( this.color === undefined ) this.material.vertexColors = true; + static create( root, path, parsedPath ) { - const position = geometry.getAttribute( 'position' ); - const colors = new Float32Array( position.count * 3 ); + if ( ! ( root && root.isAnimationObjectGroup ) ) { - geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); + return new PropertyBinding( root, path, parsedPath ); - this.add( new Mesh( geometry, this.material ) ); + } else { - this.update(); + return new PropertyBinding.Composite( root, path, parsedPath ); + + } } - dispose() { + /** + * Replaces spaces with underscores and removes unsupported characters from + * node names, to ensure compatibility with parseTrackName(). + * + * @param {string} name Node name to be sanitized. + * @return {string} + */ + static sanitizeNodeName( name ) { - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); + return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); } - update() { + static parseTrackName( trackName ) { - const mesh = this.children[ 0 ]; + const matches = _trackRe.exec( trackName ); - if ( this.color !== undefined ) { + if ( matches === null ) { - this.material.color.set( this.color ); + throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - } else { + } - const colors = mesh.geometry.getAttribute( 'color' ); + const results = { + // directoryName: matches[ 1 ], // (tschw) currently unused + nodeName: matches[ 2 ], + objectName: matches[ 3 ], + objectIndex: matches[ 4 ], + propertyName: matches[ 5 ], // required + propertyIndex: matches[ 6 ] + }; - _color1.copy( this.light.color ); - _color2.copy( this.light.groundColor ); + const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - for ( let i = 0, l = colors.count; i < l; i ++ ) { + if ( lastDot !== undefined && lastDot !== - 1 ) { - const color = ( i < ( l / 2 ) ) ? _color1 : _color2; + const objectName = results.nodeName.substring( lastDot + 1 ); - colors.setXYZ( i, color.r, color.g, color.b ); + // Object names must be checked against an allowlist. Otherwise, there + // is no way to parse 'foo.bar.baz': 'baz' must be a property, but + // 'bar' could be the objectName, or part of a nodeName (which can + // include '.' characters). + if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { + + results.nodeName = results.nodeName.substring( 0, lastDot ); + results.objectName = objectName; } - colors.needsUpdate = true; + } + + if ( results.propertyName === null || results.propertyName.length === 0 ) { + + throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); } - mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + return results; } - } - - class GridHelper extends LineSegments { + static findNode( root, nodeName ) { - constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { + if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - color1 = new Color( color1 ); - color2 = new Color( color2 ); + return root; - const center = divisions / 2; - const step = size / divisions; - const halfSize = size / 2; + } - const vertices = [], colors = []; + // search into skeleton bones. + if ( root.skeleton ) { - for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { + const bone = root.skeleton.getBoneByName( nodeName ); - vertices.push( - halfSize, 0, k, halfSize, 0, k ); - vertices.push( k, 0, - halfSize, k, 0, halfSize ); + if ( bone !== undefined ) { - const color = i === center ? color1 : color2; + return bone; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; + } } - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + // search into node subtree. + if ( root.children ) { - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + const searchNodeSubtree = function ( children ) { - super( geometry, material ); + for ( let i = 0; i < children.length; i ++ ) { - this.type = 'GridHelper'; + const childNode = children[ i ]; - } + if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - dispose() { + return childNode; - this.geometry.dispose(); - this.material.dispose(); + } - } + const result = searchNodeSubtree( childNode.children ); - } + if ( result ) return result; - class PolarGridHelper extends LineSegments { + } - constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { + return null; - color1 = new Color( color1 ); - color2 = new Color( color2 ); + }; - const vertices = []; - const colors = []; + const subTreeNode = searchNodeSubtree( root.children ); - // create the sectors + if ( subTreeNode ) { - if ( sectors > 1 ) { + return subTreeNode; - for ( let i = 0; i < sectors; i ++ ) { + } - const v = ( i / sectors ) * ( Math.PI * 2 ); + } - const x = Math.sin( v ) * radius; - const z = Math.cos( v ) * radius; + return null; - vertices.push( 0, 0, 0 ); - vertices.push( x, 0, z ); + } - const color = ( i & 1 ) ? color1 : color2; + // these are used to "bind" a nonexistent property + _getValue_unavailable() {} + _setValue_unavailable() {} - colors.push( color.r, color.g, color.b ); - colors.push( color.r, color.g, color.b ); + // Getters - } + _getValue_direct( buffer, offset ) { - } + buffer[ offset ] = this.targetObject[ this.propertyName ]; - // create the rings + } - for ( let i = 0; i < rings; i ++ ) { + _getValue_array( buffer, offset ) { - const color = ( i & 1 ) ? color1 : color2; + const source = this.resolvedProperty; - const r = radius - ( radius / rings * i ); + for ( let i = 0, n = source.length; i !== n; ++ i ) { - for ( let j = 0; j < divisions; j ++ ) { + buffer[ offset ++ ] = source[ i ]; - // first vertex + } - let v = ( j / divisions ) * ( Math.PI * 2 ); + } - let x = Math.sin( v ) * r; - let z = Math.cos( v ) * r; + _getValue_arrayElement( buffer, offset ) { - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - // second vertex + } - v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); + _getValue_toArray( buffer, offset ) { - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; + this.resolvedProperty.toArray( buffer, offset ); - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + } - } + // Direct - } + _setValue_direct( buffer, offset ) { - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + this.targetObject[ this.propertyName ] = buffer[ offset ]; - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + } - super( geometry, material ); + _setValue_direct_setNeedsUpdate( buffer, offset ) { - this.type = 'PolarGridHelper'; + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; } - dispose() { + _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - this.geometry.dispose(); - this.material.dispose(); + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; } - } - - const _v1 = /*@__PURE__*/ new Vector3(); - const _v2 = /*@__PURE__*/ new Vector3(); - const _v3 = /*@__PURE__*/ new Vector3(); - - class DirectionalLightHelper extends Object3D { + // EntireArray - constructor( light, size, color ) { + _setValue_array( buffer, offset ) { - super(); + const dest = this.resolvedProperty; - this.light = light; - this.light.updateMatrixWorld(); + for ( let i = 0, n = dest.length; i !== n; ++ i ) { - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + dest[ i ] = buffer[ offset ++ ]; - this.color = color; + } - if ( size === undefined ) size = 1; + } - let geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ - - size, size, 0, - size, size, 0, - size, - size, 0, - - size, - size, 0, - - size, size, 0 - ], 3 ) ); + _setValue_array_setNeedsUpdate( buffer, offset ) { - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); + const dest = this.resolvedProperty; - this.lightPlane = new Line( geometry, material ); - this.add( this.lightPlane ); + for ( let i = 0, n = dest.length; i !== n; ++ i ) { - geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); + dest[ i ] = buffer[ offset ++ ]; - this.targetLine = new Line( geometry, material ); - this.add( this.targetLine ); + } - this.update(); + this.targetObject.needsUpdate = true; } - dispose() { - - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); - - } + _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - update() { + const dest = this.resolvedProperty; - _v1.setFromMatrixPosition( this.light.matrixWorld ); - _v2.setFromMatrixPosition( this.light.target.matrixWorld ); - _v3.subVectors( _v2, _v1 ); + for ( let i = 0, n = dest.length; i !== n; ++ i ) { - this.lightPlane.lookAt( _v2 ); + dest[ i ] = buffer[ offset ++ ]; - if ( this.color !== undefined ) { + } - this.lightPlane.material.color.set( this.color ); - this.targetLine.material.color.set( this.color ); + this.targetObject.matrixWorldNeedsUpdate = true; - } else { + } - this.lightPlane.material.color.copy( this.light.color ); - this.targetLine.material.color.copy( this.light.color ); + // ArrayElement - } + _setValue_arrayElement( buffer, offset ) { - this.targetLine.lookAt( _v2 ); - this.targetLine.scale.z = _v3.length(); + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; } - } + _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { - const _vector = /*@__PURE__*/ new Vector3(); - const _camera = /*@__PURE__*/ new Camera(); + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; - /** - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html - */ + } - class CameraHelper extends LineSegments { + _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - constructor( camera ) { + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; - const geometry = new BufferGeometry(); - const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); + } - const vertices = []; - const colors = []; + // HasToFromArray - const pointMap = {}; + _setValue_fromArray( buffer, offset ) { - // near + this.resolvedProperty.fromArray( buffer, offset ); - addLine( 'n1', 'n2' ); - addLine( 'n2', 'n4' ); - addLine( 'n4', 'n3' ); - addLine( 'n3', 'n1' ); + } - // far + _setValue_fromArray_setNeedsUpdate( buffer, offset ) { - addLine( 'f1', 'f2' ); - addLine( 'f2', 'f4' ); - addLine( 'f4', 'f3' ); - addLine( 'f3', 'f1' ); + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.needsUpdate = true; - // sides + } - addLine( 'n1', 'f1' ); - addLine( 'n2', 'f2' ); - addLine( 'n3', 'f3' ); - addLine( 'n4', 'f4' ); + _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - // cone + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.matrixWorldNeedsUpdate = true; - addLine( 'p', 'n1' ); - addLine( 'p', 'n2' ); - addLine( 'p', 'n3' ); - addLine( 'p', 'n4' ); + } - // up + _getValue_unbound( targetArray, offset ) { - addLine( 'u1', 'u2' ); - addLine( 'u2', 'u3' ); - addLine( 'u3', 'u1' ); + this.bind(); + this.getValue( targetArray, offset ); - // target + } - addLine( 'c', 't' ); - addLine( 'p', 'c' ); + _setValue_unbound( sourceArray, offset ) { - // cross + this.bind(); + this.setValue( sourceArray, offset ); - addLine( 'cn1', 'cn2' ); - addLine( 'cn3', 'cn4' ); + } - addLine( 'cf1', 'cf2' ); - addLine( 'cf3', 'cf4' ); + // create getter / setter pair for a property in the scene graph + bind() { - function addLine( a, b ) { + let targetObject = this.node; + const parsedPath = this.parsedPath; - addPoint( a ); - addPoint( b ); + const objectName = parsedPath.objectName; + const propertyName = parsedPath.propertyName; + let propertyIndex = parsedPath.propertyIndex; - } + if ( ! targetObject ) { - function addPoint( id ) { + targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode; - vertices.push( 0, 0, 0 ); - colors.push( 0, 0, 0 ); + this.node = targetObject; - if ( pointMap[ id ] === undefined ) { + } - pointMap[ id ] = []; + // set fail state so we can just 'return' on error + this.getValue = this._getValue_unavailable; + this.setValue = this._setValue_unavailable; - } + // ensure there is a value node + if ( ! targetObject ) { - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); + console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' ); + return; } - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - super( geometry, material ); + if ( objectName ) { - this.type = 'CameraHelper'; + let objectIndex = parsedPath.objectIndex; - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); + // special cases were we need to reach deeper into the hierarchy to get the face materials.... + switch ( objectName ) { - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; + case 'materials': - this.pointMap = pointMap; + if ( ! targetObject.material ) { - this.update(); + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; - // colors + } - const colorFrustum = new Color( 0xffaa00 ); - const colorCone = new Color( 0xff0000 ); - const colorUp = new Color( 0x00aaff ); - const colorTarget = new Color( 0xffffff ); - const colorCross = new Color( 0x333333 ); + if ( ! targetObject.material.materials ) { - this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); + console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); + return; - } + } - setColors( frustum, cone, up, target, cross ) { + targetObject = targetObject.material.materials; - const geometry = this.geometry; + break; - const colorAttribute = geometry.getAttribute( 'color' ); + case 'bones': - // near + if ( ! targetObject.skeleton ) { - colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 - colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 - colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 - colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 + console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); + return; - // far + } - colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 - colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 - colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 - colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 + // potential future optimization: skip this if propertyIndex is already an integer + // and convert the integer string to a true integer. - // sides + targetObject = targetObject.skeleton.bones; - colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 - colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 - colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 - colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 + // support resolving morphTarget names into indices. + for ( let i = 0; i < targetObject.length; i ++ ) { - // cone + if ( targetObject[ i ].name === objectIndex ) { - colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 - colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 - colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 - colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 + objectIndex = i; + break; - // up + } - colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 - colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 - colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 + } - // target + break; - colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t - colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c + case 'map': - // cross + if ( 'map' in targetObject ) { - colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 - colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 + targetObject = targetObject.map; + break; - colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 - colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 + } - colorAttribute.needsUpdate = true; + if ( ! targetObject.material ) { - } + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; - update() { + } - const geometry = this.geometry; - const pointMap = this.pointMap; + if ( ! targetObject.material.map ) { - const w = 1, h = 1; + console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); + return; - // we need just camera projection matrix inverse - // world matrix must be identity + } - _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); + targetObject = targetObject.material.map; + break; - // center / target + default: - setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); - setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); + if ( targetObject[ objectName ] === undefined ) { - // near + console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); + return; - setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); + } - // far + targetObject = targetObject[ objectName ]; - setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 ); - setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 ); - setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 ); - setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 ); + } - // up - setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); + if ( objectIndex !== undefined ) { - // cross + if ( targetObject[ objectIndex ] === undefined ) { - setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 ); - setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 ); - setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); - setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); + console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); + return; - setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); + } - geometry.getAttribute( 'position' ).needsUpdate = true; + targetObject = targetObject[ objectIndex ]; - } + } - dispose() { + } - this.geometry.dispose(); - this.material.dispose(); + // resolve property + const nodeProperty = targetObject[ propertyName ]; - } + if ( nodeProperty === undefined ) { - } + const nodeName = parsedPath.nodeName; + console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + + '.' + propertyName + ' but it wasn\'t found.', targetObject ); + return; - function setPoint( point, pointMap, geometry, camera, x, y, z ) { + } - _vector.set( x, y, z ).unproject( camera ); + // determine versioning scheme + let versioning = this.Versioning.None; - const points = pointMap[ point ]; + this.targetObject = targetObject; - if ( points !== undefined ) { + if ( targetObject.needsUpdate !== undefined ) { // material - const position = geometry.getAttribute( 'position' ); + versioning = this.Versioning.NeedsUpdate; - for ( let i = 0, l = points.length; i < l; i ++ ) { + } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); + versioning = this.Versioning.MatrixWorldNeedsUpdate; } - } + // determine how the property gets bound + let bindingType = this.BindingType.Direct; - } + if ( propertyIndex !== undefined ) { - const _box = /*@__PURE__*/ new Box3(); + // access a sub element of the property array (only primitives are supported right now) - class BoxHelper extends LineSegments { + if ( propertyName === 'morphTargetInfluences' ) { - constructor( object, color = 0xffff00 ) { + // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - const positions = new Float32Array( 8 * 3 ); + // support resolving morphTarget names into indices. + if ( ! targetObject.geometry ) { - const geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); + return; - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + } - this.object = object; - this.type = 'BoxHelper'; + if ( ! targetObject.geometry.morphAttributes ) { - this.matrixAutoUpdate = false; + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); + return; - this.update(); + } - } + if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { - update( object ) { + propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; - if ( object !== undefined ) { + } - console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); + } - } + bindingType = this.BindingType.ArrayElement; - if ( this.object !== undefined ) { + this.resolvedProperty = nodeProperty; + this.propertyIndex = propertyIndex; - _box.setFromObject( this.object ); + } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - } + // must use copy for Object3D.Euler/Quaternion - if ( _box.isEmpty() ) return; + bindingType = this.BindingType.HasFromToArray; - const min = _box.min; - const max = _box.max; + this.resolvedProperty = nodeProperty; - /* - 5____4 - 1/___0/| - | 6__|_7 - 2/___3/ + } else if ( Array.isArray( nodeProperty ) ) { - 0: max.x, max.y, max.z - 1: min.x, max.y, max.z - 2: min.x, min.y, max.z - 3: max.x, min.y, max.z - 4: max.x, max.y, min.z - 5: min.x, max.y, min.z - 6: min.x, min.y, min.z - 7: max.x, min.y, min.z - */ + bindingType = this.BindingType.EntireArray; - const position = this.geometry.attributes.position; - const array = position.array; + this.resolvedProperty = nodeProperty; - array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; - array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; - array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; - array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; - array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; - array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; - array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; - array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; + } else { - position.needsUpdate = true; + this.propertyName = propertyName; - this.geometry.computeBoundingSphere(); + } + + // select getter / setter + this.getValue = this.GetterByBindingType[ bindingType ]; + this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; } - setFromObject( object ) { + unbind() { - this.object = object; - this.update(); + this.node = null; - return this; + // back to the prototype version of getValue / setValue + // note: avoiding to mutate the shape of 'this' via 'delete' + this.getValue = this._getValue_unbound; + this.setValue = this._setValue_unbound; } - copy( source, recursive ) { + } - super.copy( source, recursive ); + PropertyBinding.Composite = Composite; - this.object = source.object; + PropertyBinding.prototype.BindingType = { + Direct: 0, + EntireArray: 1, + ArrayElement: 2, + HasFromToArray: 3 + }; - return this; + PropertyBinding.prototype.Versioning = { + None: 0, + NeedsUpdate: 1, + MatrixWorldNeedsUpdate: 2 + }; - } + PropertyBinding.prototype.GetterByBindingType = [ - dispose() { + PropertyBinding.prototype._getValue_direct, + PropertyBinding.prototype._getValue_array, + PropertyBinding.prototype._getValue_arrayElement, + PropertyBinding.prototype._getValue_toArray, - this.geometry.dispose(); - this.material.dispose(); + ]; - } + PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ - } + [ + // Direct + PropertyBinding.prototype._setValue_direct, + PropertyBinding.prototype._setValue_direct_setNeedsUpdate, + PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, - class Box3Helper extends LineSegments { + ], [ - constructor( box, color = 0xffff00 ) { + // EntireArray - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + PropertyBinding.prototype._setValue_array, + PropertyBinding.prototype._setValue_array_setNeedsUpdate, + PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, - const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; + ], [ - const geometry = new BufferGeometry(); + // ArrayElement + PropertyBinding.prototype._setValue_arrayElement, + PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, + PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, - geometry.setIndex( new BufferAttribute( indices, 1 ) ); + ], [ - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + // HasToFromArray + PropertyBinding.prototype._setValue_fromArray, + PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, + PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + ] - this.box = box; + ]; - this.type = 'Box3Helper'; + /** + * + * A group of objects that receives a shared animation state. + * + * Usage: + * + * - Add objects you would otherwise pass as 'root' to the + * constructor or the .clipAction method of AnimationMixer. + * + * - Instead pass this object as 'root'. + * + * - You can also add and remove objects later when the mixer + * is running. + * + * Note: + * + * Objects of this class appear as one object to the mixer, + * so cache control of the individual objects must be done + * on the group. + * + * Limitation: + * + * - The animated properties must be compatible among the + * all objects in the group. + * + * - A single property can either be controlled through a + * target group or directly, but not both. + */ - this.geometry.computeBoundingSphere(); + class AnimationObjectGroup { - } + constructor() { - updateMatrixWorld( force ) { + this.isAnimationObjectGroup = true; - const box = this.box; + this.uuid = generateUUID(); - if ( box.isEmpty() ) return; - - box.getCenter( this.position ); + // cached objects followed by the active ones + this._objects = Array.prototype.slice.call( arguments ); - box.getSize( this.scale ); + this.nCachedObjects_ = 0; // threshold + // note: read by PropertyBinding.Composite - this.scale.multiplyScalar( 0.5 ); + const indices = {}; + this._indicesByUUID = indices; // for bookkeeping - super.updateMatrixWorld( force ); + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - } + indices[ arguments[ i ].uuid ] = i; - dispose() { + } - this.geometry.dispose(); - this.material.dispose(); + this._paths = []; // inside: string + this._parsedPaths = []; // inside: { we don't care, here } + this._bindings = []; // inside: Array< PropertyBinding > + this._bindingsIndicesByPath = {}; // inside: indices in these arrays - } + const scope = this; - } + this.stats = { - class PlaneHelper extends Line { + objects: { + get total() { - constructor( plane, size = 1, hex = 0xffff00 ) { + return scope._objects.length; - const color = hex; + }, + get inUse() { - const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; + return this.total - scope.nCachedObjects_; - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - geometry.computeBoundingSphere(); + } + }, + get bindingsPerObject() { - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + return scope._bindings.length; - this.type = 'PlaneHelper'; + } - this.plane = plane; + }; - this.size = size; + } - const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; + add() { - const geometry2 = new BufferGeometry(); - geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); - geometry2.computeBoundingSphere(); + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + nBindings = bindings.length; - this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); + let knownObject = undefined, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_; - } + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - updateMatrixWorld( force ) { + const object = arguments[ i ], + uuid = object.uuid; + let index = indicesByUUID[ uuid ]; - this.position.set( 0, 0, 0 ); + if ( index === undefined ) { - this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); + // unknown object -> add it to the ACTIVE region - this.lookAt( this.plane.normal ); + index = nObjects ++; + indicesByUUID[ uuid ] = index; + objects.push( object ); - this.translateZ( - this.plane.constant ); + // accounting is done, now do the same for all bindings - super.updateMatrixWorld( force ); + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - } + bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); - dispose() { + } - this.geometry.dispose(); - this.material.dispose(); - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); + } else if ( index < nCachedObjects ) { - } + knownObject = objects[ index ]; - } + // move existing object to the ACTIVE region - const _axis = /*@__PURE__*/ new Vector3(); - let _lineGeometry, _coneGeometry; + const firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ]; - class ArrowHelper extends Object3D { + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; - // dir is assumed to be normalized + indicesByUUID[ uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = object; - constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + // accounting is done, now do the same for all bindings - super(); + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - this.type = 'ArrowHelper'; + const bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ]; - if ( _lineGeometry === undefined ) { + let binding = bindingsForPath[ index ]; - _lineGeometry = new BufferGeometry(); - _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + bindingsForPath[ index ] = lastCached; - _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); - _coneGeometry.translate( 0, - 0.5, 0 ); + if ( binding === undefined ) { - } + // since we do not bother to create new bindings + // for objects that are cached, the binding may + // or may not exist - this.position.copy( origin ); + binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); - this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); + } - this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); + bindingsForPath[ firstActiveIndex ] = binding; - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); + } - } + } else if ( objects[ index ] !== knownObject ) { - setDirection( dir ) { + console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + + 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); - // dir is assumed to be normalized + } // else the object is already where we want it to be - if ( dir.y > 0.99999 ) { + } // for arguments - this.quaternion.set( 0, 0, 0, 1 ); + this.nCachedObjects_ = nCachedObjects; - } else if ( dir.y < - 0.99999 ) { + } - this.quaternion.set( 1, 0, 0, 0 ); + remove() { - } else { + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - _axis.set( dir.z, 0, - dir.x ).normalize(); + let nCachedObjects = this.nCachedObjects_; - const radians = Math.acos( dir.y ); + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - this.quaternion.setFromAxisAngle( _axis, radians ); + const object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - } + if ( index !== undefined && index >= nCachedObjects ) { - } + // move existing object into the CACHED region - setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + const lastCachedIndex = nCachedObjects ++, + firstActiveObject = objects[ lastCachedIndex ]; - this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 - this.line.updateMatrix(); + indicesByUUID[ firstActiveObject.uuid ] = index; + objects[ index ] = firstActiveObject; - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); + indicesByUUID[ uuid ] = lastCachedIndex; + objects[ lastCachedIndex ] = object; - } + // accounting is done, now do the same for all bindings - setColor( color ) { + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - this.line.material.color.set( color ); - this.cone.material.color.set( color ); + const bindingsForPath = bindings[ j ], + firstActive = bindingsForPath[ lastCachedIndex ], + binding = bindingsForPath[ index ]; - } + bindingsForPath[ index ] = firstActive; + bindingsForPath[ lastCachedIndex ] = binding; - copy( source ) { + } - super.copy( source, false ); + } - this.line.copy( source.line ); - this.cone.copy( source.cone ); + } // for arguments - return this; + this.nCachedObjects_ = nCachedObjects; } - dispose() { - - this.line.geometry.dispose(); - this.line.material.dispose(); - this.cone.geometry.dispose(); - this.cone.material.dispose(); + // remove & forget + uncache() { - } + const objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - } + let nCachedObjects = this.nCachedObjects_, + nObjects = objects.length; - class AxesHelper extends LineSegments { + for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - constructor( size = 1 ) { + const object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - const vertices = [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ]; + if ( index !== undefined ) { - const colors = [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ]; + delete indicesByUUID[ uuid ]; - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + if ( index < nCachedObjects ) { - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + // object is cached, shrink the CACHED region - super( geometry, material ); + const firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ], + lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; - this.type = 'AxesHelper'; + // last cached object takes this object's place + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; - } + // last object goes to the activated slot and pop + indicesByUUID[ lastObject.uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = lastObject; + objects.pop(); - setColors( xAxisColor, yAxisColor, zAxisColor ) { + // accounting is done, now do the same for all bindings - const color = new Color(); - const array = this.geometry.attributes.color.array; + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - color.set( xAxisColor ); - color.toArray( array, 0 ); - color.toArray( array, 3 ); + const bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + last = bindingsForPath[ lastIndex ]; - color.set( yAxisColor ); - color.toArray( array, 6 ); - color.toArray( array, 9 ); + bindingsForPath[ index ] = lastCached; + bindingsForPath[ firstActiveIndex ] = last; + bindingsForPath.pop(); - color.set( zAxisColor ); - color.toArray( array, 12 ); - color.toArray( array, 15 ); + } - this.geometry.attributes.color.needsUpdate = true; + } else { - return this; + // object is active, just swap with the last and pop - } + const lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; - dispose() { + if ( lastIndex > 0 ) { - this.geometry.dispose(); - this.material.dispose(); + indicesByUUID[ lastObject.uuid ] = index; - } + } - } + objects[ index ] = lastObject; + objects.pop(); - class ShapePath { + // accounting is done, now do the same for all bindings - constructor() { + for ( let j = 0, m = nBindings; j !== m; ++ j ) { - this.type = 'ShapePath'; + const bindingsForPath = bindings[ j ]; - this.color = new Color(); + bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; + bindingsForPath.pop(); - this.subPaths = []; - this.currentPath = null; + } - } + } // cached or active - moveTo( x, y ) { + } // if object is known - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); + } // for arguments - return this; + this.nCachedObjects_ = nCachedObjects; } - lineTo( x, y ) { - - this.currentPath.lineTo( x, y ); - - return this; + // Internal interface used by befriended PropertyBinding.Composite: - } + subscribe_( path, parsedPath ) { - quadraticCurveTo( aCPx, aCPy, aX, aY ) { + // returns an array of bindings for the given path that is changed + // according to the contained objects in the group - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + const indicesByPath = this._bindingsIndicesByPath; + let index = indicesByPath[ path ]; + const bindings = this._bindings; - return this; + if ( index !== undefined ) return bindings[ index ]; - } + const paths = this._paths, + parsedPaths = this._parsedPaths, + objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + bindingsForPath = new Array( nObjects ); - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + index = bindings.length; - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); + indicesByPath[ path ] = index; - return this; + paths.push( path ); + parsedPaths.push( parsedPath ); + bindings.push( bindingsForPath ); - } + for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - splineThru( pts ) { + const object = objects[ i ]; + bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - this.currentPath.splineThru( pts ); + } - return this; + return bindingsForPath; } - toShapes( isCCW ) { + unsubscribe_( path ) { - function toShapesNoHoles( inSubpaths ) { + // tells the group to forget about a property path and no longer + // update the array previously obtained with 'subscribe_' - const shapes = []; + const indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ]; - for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { + if ( index !== undefined ) { - const tmpPath = inSubpaths[ i ]; + const paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + lastBindingsIndex = bindings.length - 1, + lastBindings = bindings[ lastBindingsIndex ], + lastBindingsPath = path[ lastBindingsIndex ]; - const tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; + indicesByPath[ lastBindingsPath ] = index; - shapes.push( tmpShape ); + bindings[ index ] = lastBindings; + bindings.pop(); - } + parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; + parsedPaths.pop(); - return shapes; + paths[ index ] = paths[ lastBindingsIndex ]; + paths.pop(); } - function isPointInsidePolygon( inPt, inPolygon ) { + } - const polyLen = inPolygon.length; + } - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - let inside = false; - for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { + class AnimationAction { - let edgeLowPt = inPolygon[ p ]; - let edgeHighPt = inPolygon[ q ]; + constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { - let edgeDx = edgeHighPt.x - edgeLowPt.x; - let edgeDy = edgeHighPt.y - edgeLowPt.y; + this._mixer = mixer; + this._clip = clip; + this._localRoot = localRoot; + this.blendMode = blendMode; - if ( Math.abs( edgeDy ) > Number.EPSILON ) { + const tracks = clip.tracks, + nTracks = tracks.length, + interpolants = new Array( nTracks ); - // not parallel - if ( edgeDy < 0 ) { + const interpolantSettings = { + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + }; - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + for ( let i = 0; i !== nTracks; ++ i ) { - } + const interpolant = tracks[ i ].createInterpolant( null ); + interpolants[ i ] = interpolant; + interpolant.settings = interpolantSettings; - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + } - if ( inPt.y === edgeLowPt.y ) { + this._interpolantSettings = interpolantSettings; - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! + this._interpolants = interpolants; // bound by the mixer - } else { + // inside: PropertyMixer (managed by the mixer) + this._propertyBindings = new Array( nTracks ); - const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); - if ( perpEdge === 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = ! inside; // true intersection left of inPt + this._cacheIndex = null; // for the memory manager + this._byClipCacheIndex = null; // for the memory manager - } + this._timeScaleInterpolant = null; + this._weightInterpolant = null; - } else { + this.loop = LoopRepeat; + this._loopCount = - 1; - // parallel or collinear - if ( inPt.y !== edgeLowPt.y ) continue; // parallel - // edge lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; + // global mixer time when the action is to be started + // it's set back to 'null' upon start of the action + this._startTime = null; - } + // scaled local time of the action + // gets clamped or wrapped to 0..clip.duration according to loop + this.time = 0; - } + this.timeScale = 1; + this._effectiveTimeScale = 1; - return inside; + this.weight = 1; + this._effectiveWeight = 1; - } + this.repetitions = Infinity; // no. of repetitions when looping - const isClockWise = ShapeUtils.isClockWise; + this.paused = false; // true -> zero effective time scale + this.enabled = true; // false -> zero effective weight - const subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; + this.clampWhenFinished = false;// keep feeding the last frame? - let solid, tmpPath, tmpShape; - const shapes = []; + this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate + this.zeroSlopeAtEnd = true;// clips for start, loop and end - if ( subPaths.length === 1 ) { + } - tmpPath = subPaths[ 0 ]; - tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; + // State & Scheduling - } + play() { - let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? ! holesFirst : holesFirst; + this._mixer._activateAction( this ); - // console.log("Holes first", holesFirst); + return this; - const betterShapeHoles = []; - const newShapes = []; - let newShapeHoles = []; - let mainIdx = 0; - let tmpPoints; + } - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; + stop() { - for ( let i = 0, l = subPaths.length; i < l; i ++ ) { + this._mixer._deactivateAction( this ); - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; + return this.reset(); - if ( solid ) { + } - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; + reset() { - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; + this.paused = false; + this.enabled = true; - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; + this.time = 0; // restart clip + this._loopCount = - 1;// forget previous loops + this._startTime = null;// forget scheduling - //console.log('cw', i); + return this.stopFading().stopWarping(); - } else { + } - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); + isRunning() { - //console.log('ccw', i); + return this.enabled && ! this.paused && this.timeScale !== 0 && + this._startTime === null && this._mixer._isActiveAction( this ); - } + } - } + // return true when play has been called + isScheduled() { - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); + return this._mixer._isActiveAction( this ); + } - if ( newShapes.length > 1 ) { + startAt( time ) { - let ambiguous = false; - let toChange = 0; + this._startTime = time; - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + return this; - betterShapeHoles[ sIdx ] = []; + } - } + setLoop( mode, repetitions ) { - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + this.loop = mode; + this.repetitions = repetitions; - const sho = newShapeHoles[ sIdx ]; + return this; - for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { + } - const ho = sho[ hIdx ]; - let hole_unassigned = true; + // Weight - for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + // set the weight stopping any scheduled fading + // although .enabled = false yields an effective weight of zero, this + // method does *not* change .enabled, because it would be confusing + setEffectiveWeight( weight ) { - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { + this.weight = weight; - if ( sIdx !== s2Idx ) toChange ++; + // note: same logic as when updated at runtime + this._effectiveWeight = this.enabled ? weight : 0; - if ( hole_unassigned ) { + return this.stopFading(); - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); + } - } else { + // return the weight considering fading and .enabled + getEffectiveWeight() { - ambiguous = true; + return this._effectiveWeight; - } + } - } + fadeIn( duration ) { - } + return this._scheduleFading( duration, 0, 1 ); - if ( hole_unassigned ) { + } - betterShapeHoles[ sIdx ].push( ho ); + fadeOut( duration ) { - } + return this._scheduleFading( duration, 1, 0 ); - } + } - } + crossFadeFrom( fadeOutAction, duration, warp ) { - if ( toChange > 0 && ambiguous === false ) { + fadeOutAction.fadeOut( duration ); + this.fadeIn( duration ); - newShapeHoles = betterShapeHoles; + if ( warp ) { - } + const fadeInDuration = this._clip.duration, + fadeOutDuration = fadeOutAction._clip.duration, + + startEndRatio = fadeOutDuration / fadeInDuration, + endStartRatio = fadeInDuration / fadeOutDuration; + + fadeOutAction.warp( 1.0, startEndRatio, duration ); + this.warp( endStartRatio, 1.0, duration ); } - let tmpHoles; + return this; - for ( let i = 0, il = newShapes.length; i < il; i ++ ) { + } - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; + crossFadeTo( fadeInAction, duration, warp ) { - for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + return fadeInAction.crossFadeFrom( this, duration, warp ); - tmpShape.holes.push( tmpHoles[ j ].h ); + } - } + stopFading() { - } + const weightInterpolant = this._weightInterpolant; - //console.log("shape", shapes); + if ( weightInterpolant !== null ) { - return shapes; + this._weightInterpolant = null; + this._mixer._takeBackControlInterpolant( weightInterpolant ); + + } + + return this; } - } + // Time Scale Control - // Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf + // set the time scale stopping any scheduled warping + // although .paused = true yields an effective time scale of zero, this + // method does *not* change .paused, because it would be confusing + setEffectiveTimeScale( timeScale ) { - const _tables = /*@__PURE__*/ _generateTables(); + this.timeScale = timeScale; + this._effectiveTimeScale = this.paused ? 0 : timeScale; - function _generateTables() { + return this.stopWarping(); - // float32 to float16 helpers + } - const buffer = new ArrayBuffer( 4 ); - const floatView = new Float32Array( buffer ); - const uint32View = new Uint32Array( buffer ); + // return the time scale considering warping and .paused + getEffectiveTimeScale() { - const baseTable = new Uint32Array( 512 ); - const shiftTable = new Uint32Array( 512 ); + return this._effectiveTimeScale; - for ( let i = 0; i < 256; ++ i ) { + } - const e = i - 127; + setDuration( duration ) { - // very small number (0, -0) + this.timeScale = this._clip.duration / duration; - if ( e < - 27 ) { + return this.stopWarping(); - baseTable[ i ] = 0x0000; - baseTable[ i | 0x100 ] = 0x8000; - shiftTable[ i ] = 24; - shiftTable[ i | 0x100 ] = 24; + } - // small number (denorm) + syncWith( action ) { - } else if ( e < - 14 ) { + this.time = action.time; + this.timeScale = action.timeScale; - baseTable[ i ] = 0x0400 >> ( - e - 14 ); - baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000; - shiftTable[ i ] = - e - 1; - shiftTable[ i | 0x100 ] = - e - 1; + return this.stopWarping(); - // normal number + } - } else if ( e <= 15 ) { + halt( duration ) { - baseTable[ i ] = ( e + 15 ) << 10; - baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000; - shiftTable[ i ] = 13; - shiftTable[ i | 0x100 ] = 13; + return this.warp( this._effectiveTimeScale, 0, duration ); - // large number (Infinity, -Infinity) + } - } else if ( e < 128 ) { + warp( startTimeScale, endTimeScale, duration ) { - baseTable[ i ] = 0x7c00; - baseTable[ i | 0x100 ] = 0xfc00; - shiftTable[ i ] = 24; - shiftTable[ i | 0x100 ] = 24; + const mixer = this._mixer, + now = mixer.time, + timeScale = this.timeScale; - // stay (NaN, Infinity, -Infinity) + let interpolant = this._timeScaleInterpolant; - } else { + if ( interpolant === null ) { - baseTable[ i ] = 0x7c00; - baseTable[ i | 0x100 ] = 0xfc00; - shiftTable[ i ] = 13; - shiftTable[ i | 0x100 ] = 13; + interpolant = mixer._lendControlInterpolant(); + this._timeScaleInterpolant = interpolant; } - } + const times = interpolant.parameterPositions, + values = interpolant.sampleValues; - // float16 to float32 helpers + times[ 0 ] = now; + times[ 1 ] = now + duration; - const mantissaTable = new Uint32Array( 2048 ); - const exponentTable = new Uint32Array( 64 ); - const offsetTable = new Uint32Array( 64 ); + values[ 0 ] = startTimeScale / timeScale; + values[ 1 ] = endTimeScale / timeScale; - for ( let i = 1; i < 1024; ++ i ) { + return this; - let m = i << 13; // zero pad mantissa bits - let e = 0; // zero exponent + } - // normalized - while ( ( m & 0x00800000 ) === 0 ) { + stopWarping() { - m <<= 1; - e -= 0x00800000; // decrement exponent + const timeScaleInterpolant = this._timeScaleInterpolant; - } + if ( timeScaleInterpolant !== null ) { - m &= ~ 0x00800000; // clear leading 1 bit - e += 0x38800000; // adjust bias + this._timeScaleInterpolant = null; + this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - mantissaTable[ i ] = m | e; + } + + return this; } - for ( let i = 1024; i < 2048; ++ i ) { + // Object Accessors - mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 ); + getMixer() { + + return this._mixer; } - for ( let i = 1; i < 31; ++ i ) { + getClip() { - exponentTable[ i ] = i << 23; + return this._clip; } - exponentTable[ 31 ] = 0x47800000; - exponentTable[ 32 ] = 0x80000000; - - for ( let i = 33; i < 63; ++ i ) { + getRoot() { - exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 ); + return this._localRoot || this._mixer._root; } - exponentTable[ 63 ] = 0xc7800000; + // Interna - for ( let i = 1; i < 64; ++ i ) { + _update( time, deltaTime, timeDirection, accuIndex ) { - if ( i !== 32 ) { + // called by the mixer - offsetTable[ i ] = 1024; + if ( ! this.enabled ) { + + // call ._updateWeight() to update ._effectiveWeight + + this._updateWeight( time ); + return; } - } + const startTime = this._startTime; - return { - floatView: floatView, - uint32View: uint32View, - baseTable: baseTable, - shiftTable: shiftTable, - mantissaTable: mantissaTable, - exponentTable: exponentTable, - offsetTable: offsetTable - }; + if ( startTime !== null ) { - } + // check for scheduled start of action - // float32 to float16 + const timeRunning = ( time - startTime ) * timeDirection; + if ( timeRunning < 0 || timeDirection === 0 ) { - function toHalfFloat( val ) { + deltaTime = 0; - if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); + } else { - val = clamp( val, - 65504, 65504 ); - _tables.floatView[ 0 ] = val; - const f = _tables.uint32View[ 0 ]; - const e = ( f >> 23 ) & 0x1ff; - return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); + this._startTime = null; // unschedule + deltaTime = timeDirection * timeRunning; - } + } - // float16 to float32 + } - function fromHalfFloat( val ) { + // apply time scale and advance time - const m = val >> 10; - _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; - return _tables.floatView[ 0 ]; + deltaTime *= this._updateTimeScale( time ); + const clipTime = this._updateTime( deltaTime ); - } + // note: _updateTime may disable the action resulting in + // an effective weight of 0 - var DataUtils = /*#__PURE__*/Object.freeze({ - __proto__: null, - toHalfFloat: toHalfFloat, - fromHalfFloat: fromHalfFloat - }); + const weight = this._updateWeight( time ); - // r134, d65e0af06644fe5a84a6fc0e372f4318f95a04c0 + if ( weight > 0 ) { - function ImmediateRenderObject() { + const interpolants = this._interpolants; + const propertyMixers = this._propertyBindings; - console.error( 'THREE.ImmediateRenderObject has been removed.' ); + switch ( this.blendMode ) { - } + case AdditiveAnimationBlendMode: - // r138, 48b05d3500acc084df50be9b4c90781ad9b8cb17 + for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - class WebGLMultisampleRenderTarget extends WebGLRenderTarget { + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulateAdditive( weight ); - constructor( width, height, options ) { + } - console.error( 'THREE.WebGLMultisampleRenderTarget has been removed. Use a normal render target and set the "samples" property to greater 0 to enable multisampling.' ); - super( width, height, options ); - this.samples = 4; + break; - } + case NormalAnimationBlendMode: + default: - } + for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - // r138, f9cd9cab03b7b64244e304900a3a2eeaa3a588ce + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulate( accuIndex, weight ); - class DataTexture2DArray extends DataArrayTexture { + } - constructor( data, width, height, depth ) { + } - console.warn( 'THREE.DataTexture2DArray has been renamed to DataArrayTexture.' ); - super( data, width, height, depth ); + } } - } + _updateWeight( time ) { - // r138, f9cd9cab03b7b64244e304900a3a2eeaa3a588ce + let weight = 0; - class DataTexture3D extends Data3DTexture { + if ( this.enabled ) { - constructor( data, width, height, depth ) { + weight = this.weight; + const interpolant = this._weightInterpolant; - console.warn( 'THREE.DataTexture3D has been renamed to Data3DTexture.' ); - super( data, width, height, depth ); + if ( interpolant !== null ) { - } + const interpolantValue = interpolant.evaluate( time )[ 0 ]; - } + weight *= interpolantValue; - // r144 + if ( time > interpolant.parameterPositions[ 1 ] ) { - class BoxBufferGeometry extends BoxGeometry { + this.stopFading(); - constructor( width, height, depth, widthSegments, heightSegments, depthSegments ) { + if ( interpolantValue === 0 ) { - console.warn( 'THREE.BoxBufferGeometry has been renamed to THREE.BoxGeometry.' ); - super( width, height, depth, widthSegments, heightSegments, depthSegments ); + // faded out, disable + this.enabled = false; + } - } + } - } + } - // r144 + } - class CapsuleBufferGeometry extends CapsuleGeometry { + this._effectiveWeight = weight; + return weight; - constructor( radius, length, capSegments, radialSegments ) { + } - console.warn( 'THREE.CapsuleBufferGeometry has been renamed to THREE.CapsuleGeometry.' ); - super( radius, length, capSegments, radialSegments ); + _updateTimeScale( time ) { - } + let timeScale = 0; - } + if ( ! this.paused ) { - // r144 + timeScale = this.timeScale; - class CircleBufferGeometry extends CircleGeometry { + const interpolant = this._timeScaleInterpolant; - constructor( radius, segments, thetaStart, thetaLength ) { + if ( interpolant !== null ) { - console.warn( 'THREE.CircleBufferGeometry has been renamed to THREE.CircleGeometry.' ); - super( radius, segments, thetaStart, thetaLength ); + const interpolantValue = interpolant.evaluate( time )[ 0 ]; - } + timeScale *= interpolantValue; - } + if ( time > interpolant.parameterPositions[ 1 ] ) { - // r144 + this.stopWarping(); - class ConeBufferGeometry extends ConeGeometry { + if ( timeScale === 0 ) { - constructor( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + // motion has halted, pause + this.paused = true; - console.warn( 'THREE.ConeBufferGeometry has been renamed to THREE.ConeGeometry.' ); - super( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + } else { - } + // warp done - apply final time scale + this.timeScale = timeScale; - } + } - // r144 + } - class CylinderBufferGeometry extends CylinderGeometry { + } - constructor( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + } - console.warn( 'THREE.CylinderBufferGeometry has been renamed to THREE.CylinderGeometry.' ); - super( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + this._effectiveTimeScale = timeScale; + return timeScale; } - } + _updateTime( deltaTime ) { - // r144 + const duration = this._clip.duration; + const loop = this.loop; - class DodecahedronBufferGeometry extends DodecahedronGeometry { + let time = this.time + deltaTime; + let loopCount = this._loopCount; - constructor( radius, detail ) { + const pingPong = ( loop === LoopPingPong ); - console.warn( 'THREE.DodecahedronBufferGeometry has been renamed to THREE.DodecahedronGeometry.' ); - super( radius, detail ); + if ( deltaTime === 0 ) { - } + if ( loopCount === - 1 ) return time; - } + return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; - // r144 + } - class ExtrudeBufferGeometry extends ExtrudeGeometry { + if ( loop === LoopOnce ) { - constructor( shapes, options ) { + if ( loopCount === - 1 ) { - console.warn( 'THREE.ExtrudeBufferGeometry has been renamed to THREE.ExtrudeGeometry.' ); - super( shapes, options ); + // just started - } + this._loopCount = 0; + this._setEndings( true, true, false ); - } + } - // r144 + handle_stop: { - class IcosahedronBufferGeometry extends IcosahedronGeometry { + if ( time >= duration ) { - constructor( radius, detail ) { + time = duration; - console.warn( 'THREE.IcosahedronBufferGeometry has been renamed to THREE.IcosahedronGeometry.' ); - super( radius, detail ); + } else if ( time < 0 ) { - } + time = 0; - } + } else { - // r144 + this.time = time; - class LatheBufferGeometry extends LatheGeometry { + break handle_stop; - constructor( points, segments, phiStart, phiLength ) { + } - console.warn( 'THREE.LatheBufferGeometry has been renamed to THREE.LatheGeometry.' ); - super( points, segments, phiStart, phiLength ); + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; - } + this.time = time; - } + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime < 0 ? - 1 : 1 + } ); - // r144 + } - class OctahedronBufferGeometry extends OctahedronGeometry { + } else { // repetitive Repeat or PingPong - constructor( radius, detail ) { + if ( loopCount === - 1 ) { - console.warn( 'THREE.OctahedronBufferGeometry has been renamed to THREE.OctahedronGeometry.' ); - super( radius, detail ); + // just started - } + if ( deltaTime >= 0 ) { - } + loopCount = 0; - // r144 + this._setEndings( true, this.repetitions === 0, pingPong ); - class PlaneBufferGeometry extends PlaneGeometry { + } else { - constructor( width, height, widthSegments, heightSegments ) { + // when looping in reverse direction, the initial + // transition through zero counts as a repetition, + // so leave loopCount at -1 - console.warn( 'THREE.PlaneBufferGeometry has been renamed to THREE.PlaneGeometry.' ); - super( width, height, widthSegments, heightSegments ); + this._setEndings( this.repetitions === 0, true, pingPong ); - } + } - } + } - // r144 + if ( time >= duration || time < 0 ) { - class PolyhedronBufferGeometry extends PolyhedronGeometry { + // wrap around - constructor( vertices, indices, radius, detail ) { + const loopDelta = Math.floor( time / duration ); // signed + time -= duration * loopDelta; - console.warn( 'THREE.PolyhedronBufferGeometry has been renamed to THREE.PolyhedronGeometry.' ); - super( vertices, indices, radius, detail ); + loopCount += Math.abs( loopDelta ); + + const pending = this.repetitions - loopCount; + + if ( pending <= 0 ) { + + // have to stop (switch state, clamp time, fire event) + + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; + + time = deltaTime > 0 ? duration : 0; + + this.time = time; + + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime > 0 ? 1 : - 1 + } ); + + } else { + + // keep running + + if ( pending === 1 ) { + + // entering the last round + + const atStart = deltaTime < 0; + this._setEndings( atStart, ! atStart, pingPong ); + + } else { + + this._setEndings( false, false, pingPong ); + + } + + this._loopCount = loopCount; + + this.time = time; + + this._mixer.dispatchEvent( { + type: 'loop', action: this, loopDelta: loopDelta + } ); + + } + + } else { + + this.time = time; + + } + + if ( pingPong && ( loopCount & 1 ) === 1 ) { + + // invert time for the "pong round" + + return duration - time; + + } + + } + + return time; } - } + _setEndings( atStart, atEnd, pingPong ) { - // r144 + const settings = this._interpolantSettings; - class RingBufferGeometry extends RingGeometry { + if ( pingPong ) { - constructor( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + settings.endingStart = ZeroSlopeEnding; + settings.endingEnd = ZeroSlopeEnding; - console.warn( 'THREE.RingBufferGeometry has been renamed to THREE.RingGeometry.' ); - super( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ); + } else { + + // assuming for LoopOnce atStart == atEnd == true + + if ( atStart ) { + + settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; + + } else { + + settings.endingStart = WrapAroundEnding; + + } + + if ( atEnd ) { + + settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; + + } else { + + settings.endingEnd = WrapAroundEnding; + + } + + } } - } + _scheduleFading( duration, weightNow, weightThen ) { - // r144 + const mixer = this._mixer, now = mixer.time; + let interpolant = this._weightInterpolant; - class ShapeBufferGeometry extends ShapeGeometry { + if ( interpolant === null ) { - constructor( shapes, curveSegments ) { + interpolant = mixer._lendControlInterpolant(); + this._weightInterpolant = interpolant; - console.warn( 'THREE.ShapeBufferGeometry has been renamed to THREE.ShapeGeometry.' ); - super( shapes, curveSegments ); + } + + const times = interpolant.parameterPositions, + values = interpolant.sampleValues; + + times[ 0 ] = now; + values[ 0 ] = weightNow; + times[ 1 ] = now + duration; + values[ 1 ] = weightThen; + + return this; } } - // r144 + const _controlInterpolantsResultBuffer = new Float32Array( 1 ); - class SphereBufferGeometry extends SphereGeometry { - constructor( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + class AnimationMixer extends EventDispatcher { - console.warn( 'THREE.SphereBufferGeometry has been renamed to THREE.SphereGeometry.' ); - super( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ); + constructor( root ) { + + super(); + + this._root = root; + this._initMemoryManager(); + this._accuIndex = 0; + this.time = 0; + this.timeScale = 1.0; } - } + _bindAction( action, prototypeAction ) { - // r144 + const root = action._localRoot || this._root, + tracks = action._clip.tracks, + nTracks = tracks.length, + bindings = action._propertyBindings, + interpolants = action._interpolants, + rootUuid = root.uuid, + bindingsByRoot = this._bindingsByRootAndName; - class TetrahedronBufferGeometry extends TetrahedronGeometry { + let bindingsByName = bindingsByRoot[ rootUuid ]; - constructor( radius, detail ) { + if ( bindingsByName === undefined ) { - console.warn( 'THREE.TetrahedronBufferGeometry has been renamed to THREE.TetrahedronGeometry.' ); - super( radius, detail ); + bindingsByName = {}; + bindingsByRoot[ rootUuid ] = bindingsByName; + + } + + for ( let i = 0; i !== nTracks; ++ i ) { + + const track = tracks[ i ], + trackName = track.name; + + let binding = bindingsByName[ trackName ]; + + if ( binding !== undefined ) { + + ++ binding.referenceCount; + bindings[ i ] = binding; + + } else { + + binding = bindings[ i ]; + + if ( binding !== undefined ) { + + // existing binding, make sure the cache knows + + if ( binding._cacheIndex === null ) { + + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); + + } + + continue; + + } + + const path = prototypeAction && prototypeAction. + _propertyBindings[ i ].binding.parsedPath; + + binding = new PropertyMixer( + PropertyBinding.create( root, trackName, path ), + track.ValueTypeName, track.getValueSize() ); + + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); + + bindings[ i ] = binding; + + } + + interpolants[ i ].resultBuffer = binding.buffer; + + } } - } + _activateAction( action ) { - // r144 + if ( ! this._isActiveAction( action ) ) { - class TorusBufferGeometry extends TorusGeometry { + if ( action._cacheIndex === null ) { - constructor( radius, tube, radialSegments, tubularSegments, arc ) { + // this action has been forgotten by the cache, but the user + // appears to be still using it -> rebind - console.warn( 'THREE.TorusBufferGeometry has been renamed to THREE.TorusGeometry.' ); - super( radius, tube, radialSegments, tubularSegments, arc ); + const rootUuid = ( action._localRoot || this._root ).uuid, + clipUuid = action._clip.uuid, + actionsForClip = this._actionsByClip[ clipUuid ]; + + this._bindAction( action, + actionsForClip && actionsForClip.knownActions[ 0 ] ); + + this._addInactiveAction( action, clipUuid, rootUuid ); + + } + + const bindings = action._propertyBindings; + + // increment reference counts / sort out state + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { + + const binding = bindings[ i ]; + + if ( binding.useCount ++ === 0 ) { + + this._lendBinding( binding ); + binding.saveOriginalState(); + + } + + } + + this._lendAction( action ); + + } } - } + _deactivateAction( action ) { - // r144 + if ( this._isActiveAction( action ) ) { - class TorusKnotBufferGeometry extends TorusKnotGeometry { + const bindings = action._propertyBindings; - constructor( radius, tube, tubularSegments, radialSegments, p, q ) { + // decrement reference counts / sort out state + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - console.warn( 'THREE.TorusKnotBufferGeometry has been renamed to THREE.TorusKnotGeometry.' ); - super( radius, tube, tubularSegments, radialSegments, p, q ); + const binding = bindings[ i ]; + + if ( -- binding.useCount === 0 ) { + + binding.restoreOriginalState(); + this._takeBackBinding( binding ); + + } + + } + + this._takeBackAction( action ); + + } } - } + // Memory manager - // r144 + _initMemoryManager() { - class TubeBufferGeometry extends TubeGeometry { + this._actions = []; // 'nActiveActions' followed by inactive ones + this._nActiveActions = 0; - constructor( path, tubularSegments, radius, radialSegments, closed ) { + this._actionsByClip = {}; + // inside: + // { + // knownActions: Array< AnimationAction > - used as prototypes + // actionByRoot: AnimationAction - lookup + // } - console.warn( 'THREE.TubeBufferGeometry has been renamed to THREE.TubeGeometry.' ); - super( path, tubularSegments, radius, radialSegments, closed ); + + this._bindings = []; // 'nActiveBindings' followed by inactive ones + this._nActiveBindings = 0; + + this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > + + + this._controlInterpolants = []; // same game as above + this._nActiveControlInterpolants = 0; + + const scope = this; + + this.stats = { + + actions: { + get total() { + + return scope._actions.length; + + }, + get inUse() { + + return scope._nActiveActions; + + } + }, + bindings: { + get total() { + + return scope._bindings.length; + + }, + get inUse() { + + return scope._nActiveBindings; + + } + }, + controlInterpolants: { + get total() { + + return scope._controlInterpolants.length; + + }, + get inUse() { + + return scope._nActiveControlInterpolants; + + } + } + + }; } - } + // Memory management for AnimationAction objects - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + _isActiveAction( action ) { - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { - revision: REVISION, - } } ) ); + const index = action._cacheIndex; + return index !== null && index < this._nActiveActions; - } + } - if ( typeof window !== 'undefined' ) { + _addInactiveAction( action, clipUuid, rootUuid ) { - if ( window.__THREE__ ) { + const actions = this._actions, + actionsByClip = this._actionsByClip; - console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); + let actionsForClip = actionsByClip[ clipUuid ]; - } else { + if ( actionsForClip === undefined ) { - window.__THREE__ = REVISION; + actionsForClip = { + + knownActions: [ action ], + actionByRoot: {} + + }; + + action._byClipCacheIndex = 0; + + actionsByClip[ clipUuid ] = actionsForClip; + + } else { + + const knownActions = actionsForClip.knownActions; + + action._byClipCacheIndex = knownActions.length; + knownActions.push( action ); + + } + + action._cacheIndex = actions.length; + actions.push( action ); + + actionsForClip.actionByRoot[ rootUuid ] = action; } - } + _removeInactiveAction( action ) { - var THREE = /*#__PURE__*/Object.freeze({ - __proto__: null, - ACESFilmicToneMapping: ACESFilmicToneMapping, - AddEquation: AddEquation, - AddOperation: AddOperation, - AdditiveAnimationBlendMode: AdditiveAnimationBlendMode, - AdditiveBlending: AdditiveBlending, - AlphaFormat: AlphaFormat, - AlwaysDepth: AlwaysDepth, - AlwaysStencilFunc: AlwaysStencilFunc, - AmbientLight: AmbientLight, - AmbientLightProbe: AmbientLightProbe, - AnimationClip: AnimationClip, - AnimationLoader: AnimationLoader, - AnimationMixer: AnimationMixer, - AnimationObjectGroup: AnimationObjectGroup, - AnimationUtils: AnimationUtils, - ArcCurve: ArcCurve, - ArrayCamera: ArrayCamera, - ArrowHelper: ArrowHelper, - Audio: Audio, - AudioAnalyser: AudioAnalyser, - AudioContext: AudioContext, - AudioListener: AudioListener, - AudioLoader: AudioLoader, - AxesHelper: AxesHelper, - BackSide: BackSide, - BasicDepthPacking: BasicDepthPacking, - BasicShadowMap: BasicShadowMap, - Bone: Bone, - BooleanKeyframeTrack: BooleanKeyframeTrack, - Box2: Box2, - Box3: Box3, - Box3Helper: Box3Helper, - BoxBufferGeometry: BoxBufferGeometry, - BoxGeometry: BoxGeometry, - BoxHelper: BoxHelper, - BufferAttribute: BufferAttribute, - BufferGeometry: BufferGeometry, - BufferGeometryLoader: BufferGeometryLoader, - ByteType: ByteType, - Cache: Cache, - Camera: Camera, - CameraHelper: CameraHelper, - CanvasTexture: CanvasTexture, - CapsuleBufferGeometry: CapsuleBufferGeometry, - CapsuleGeometry: CapsuleGeometry, - CatmullRomCurve3: CatmullRomCurve3, - CineonToneMapping: CineonToneMapping, - CircleBufferGeometry: CircleBufferGeometry, - CircleGeometry: CircleGeometry, - ClampToEdgeWrapping: ClampToEdgeWrapping, - Clock: Clock, - Color: Color, - ColorKeyframeTrack: ColorKeyframeTrack, - ColorManagement: ColorManagement, - CompressedTexture: CompressedTexture, - CompressedTextureLoader: CompressedTextureLoader, - ConeBufferGeometry: ConeBufferGeometry, - ConeGeometry: ConeGeometry, - CubeCamera: CubeCamera, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - CubeTexture: CubeTexture, - CubeTextureLoader: CubeTextureLoader, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - CubicInterpolant: CubicInterpolant, - CullFaceBack: CullFaceBack, - CullFaceFront: CullFaceFront, - CullFaceFrontBack: CullFaceFrontBack, - CullFaceNone: CullFaceNone, - Curve: Curve, - CurvePath: CurvePath, - CustomBlending: CustomBlending, - CustomToneMapping: CustomToneMapping, - CylinderBufferGeometry: CylinderBufferGeometry, - CylinderGeometry: CylinderGeometry, - Cylindrical: Cylindrical, - Data3DTexture: Data3DTexture, - DataArrayTexture: DataArrayTexture, - DataTexture: DataTexture, - DataTexture2DArray: DataTexture2DArray, - DataTexture3D: DataTexture3D, - DataTextureLoader: DataTextureLoader, - DataUtils: DataUtils, - DecrementStencilOp: DecrementStencilOp, - DecrementWrapStencilOp: DecrementWrapStencilOp, - DefaultLoadingManager: DefaultLoadingManager, - DepthFormat: DepthFormat, - DepthStencilFormat: DepthStencilFormat, - DepthTexture: DepthTexture, - DirectionalLight: DirectionalLight, - DirectionalLightHelper: DirectionalLightHelper, - DiscreteInterpolant: DiscreteInterpolant, - DodecahedronBufferGeometry: DodecahedronBufferGeometry, - DodecahedronGeometry: DodecahedronGeometry, - DoubleSide: DoubleSide, - DstAlphaFactor: DstAlphaFactor, - DstColorFactor: DstColorFactor, - DynamicCopyUsage: DynamicCopyUsage, - DynamicDrawUsage: DynamicDrawUsage, - DynamicReadUsage: DynamicReadUsage, - EdgesGeometry: EdgesGeometry, - EllipseCurve: EllipseCurve, - EqualDepth: EqualDepth, - EqualStencilFunc: EqualStencilFunc, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - Euler: Euler, - EventDispatcher: EventDispatcher, - ExtrudeBufferGeometry: ExtrudeBufferGeometry, - ExtrudeGeometry: ExtrudeGeometry, - FileLoader: FileLoader, - Float16BufferAttribute: Float16BufferAttribute, - Float32BufferAttribute: Float32BufferAttribute, - Float64BufferAttribute: Float64BufferAttribute, - FloatType: FloatType, - Fog: Fog, - FogExp2: FogExp2, - FramebufferTexture: FramebufferTexture, - FrontSide: FrontSide, - Frustum: Frustum, - GLBufferAttribute: GLBufferAttribute, - GLSL1: GLSL1, - GLSL3: GLSL3, - GreaterDepth: GreaterDepth, - GreaterEqualDepth: GreaterEqualDepth, - GreaterEqualStencilFunc: GreaterEqualStencilFunc, - GreaterStencilFunc: GreaterStencilFunc, - GridHelper: GridHelper, - Group: Group, - HalfFloatType: HalfFloatType, - HemisphereLight: HemisphereLight, - HemisphereLightHelper: HemisphereLightHelper, - HemisphereLightProbe: HemisphereLightProbe, - IcosahedronBufferGeometry: IcosahedronBufferGeometry, - IcosahedronGeometry: IcosahedronGeometry, - ImageBitmapLoader: ImageBitmapLoader, - ImageLoader: ImageLoader, - ImageUtils: ImageUtils, - ImmediateRenderObject: ImmediateRenderObject, - IncrementStencilOp: IncrementStencilOp, - IncrementWrapStencilOp: IncrementWrapStencilOp, - InstancedBufferAttribute: InstancedBufferAttribute, - InstancedBufferGeometry: InstancedBufferGeometry, - InstancedInterleavedBuffer: InstancedInterleavedBuffer, - InstancedMesh: InstancedMesh, - Int16BufferAttribute: Int16BufferAttribute, - Int32BufferAttribute: Int32BufferAttribute, - Int8BufferAttribute: Int8BufferAttribute, - IntType: IntType, - InterleavedBuffer: InterleavedBuffer, - InterleavedBufferAttribute: InterleavedBufferAttribute, - Interpolant: Interpolant, - InterpolateDiscrete: InterpolateDiscrete, - InterpolateLinear: InterpolateLinear, - InterpolateSmooth: InterpolateSmooth, - InvertStencilOp: InvertStencilOp, - KeepStencilOp: KeepStencilOp, - KeyframeTrack: KeyframeTrack, - LOD: LOD, - LatheBufferGeometry: LatheBufferGeometry, - LatheGeometry: LatheGeometry, - Layers: Layers, - LessDepth: LessDepth, - LessEqualDepth: LessEqualDepth, - LessEqualStencilFunc: LessEqualStencilFunc, - LessStencilFunc: LessStencilFunc, - Light: Light, - LightProbe: LightProbe, - Line: Line, - Line3: Line3, - LineBasicMaterial: LineBasicMaterial, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - LineDashedMaterial: LineDashedMaterial, - LineLoop: LineLoop, - LineSegments: LineSegments, - LinearEncoding: LinearEncoding, - LinearFilter: LinearFilter, - LinearInterpolant: LinearInterpolant, - LinearMipMapLinearFilter: LinearMipMapLinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipmapLinearFilter: LinearMipmapLinearFilter, - LinearMipmapNearestFilter: LinearMipmapNearestFilter, - LinearSRGBColorSpace: LinearSRGBColorSpace, - LinearToneMapping: LinearToneMapping, - Loader: Loader, - LoaderUtils: LoaderUtils, - LoadingManager: LoadingManager, - LoopOnce: LoopOnce, - LoopPingPong: LoopPingPong, - LoopRepeat: LoopRepeat, - LuminanceAlphaFormat: LuminanceAlphaFormat, - LuminanceFormat: LuminanceFormat, - MOUSE: MOUSE, - Material: Material, - MaterialLoader: MaterialLoader, - MathUtils: MathUtils, - Matrix3: Matrix3, - Matrix4: Matrix4, - MaxEquation: MaxEquation, - Mesh: Mesh, - MeshBasicMaterial: MeshBasicMaterial, - MeshDepthMaterial: MeshDepthMaterial, - MeshDistanceMaterial: MeshDistanceMaterial, - MeshLambertMaterial: MeshLambertMaterial, - MeshMatcapMaterial: MeshMatcapMaterial, - MeshNormalMaterial: MeshNormalMaterial, - MeshPhongMaterial: MeshPhongMaterial, - MeshPhysicalMaterial: MeshPhysicalMaterial, - MeshStandardMaterial: MeshStandardMaterial, - MeshToonMaterial: MeshToonMaterial, - MinEquation: MinEquation, - MirroredRepeatWrapping: MirroredRepeatWrapping, - MixOperation: MixOperation, - MultiplyBlending: MultiplyBlending, - MultiplyOperation: MultiplyOperation, - NearestFilter: NearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipmapLinearFilter: NearestMipmapLinearFilter, - NearestMipmapNearestFilter: NearestMipmapNearestFilter, - NeverDepth: NeverDepth, - NeverStencilFunc: NeverStencilFunc, - NoBlending: NoBlending, - NoColorSpace: NoColorSpace, - NoToneMapping: NoToneMapping, - NormalAnimationBlendMode: NormalAnimationBlendMode, - NormalBlending: NormalBlending, - NotEqualDepth: NotEqualDepth, - NotEqualStencilFunc: NotEqualStencilFunc, - NumberKeyframeTrack: NumberKeyframeTrack, - Object3D: Object3D, - ObjectLoader: ObjectLoader, - ObjectSpaceNormalMap: ObjectSpaceNormalMap, - OctahedronBufferGeometry: OctahedronBufferGeometry, - OctahedronGeometry: OctahedronGeometry, - OneFactor: OneFactor, - OneMinusDstAlphaFactor: OneMinusDstAlphaFactor, - OneMinusDstColorFactor: OneMinusDstColorFactor, - OneMinusSrcAlphaFactor: OneMinusSrcAlphaFactor, - OneMinusSrcColorFactor: OneMinusSrcColorFactor, - OrthographicCamera: OrthographicCamera, - PCFShadowMap: PCFShadowMap, - PCFSoftShadowMap: PCFSoftShadowMap, - PMREMGenerator: PMREMGenerator, - Path: Path, - PerspectiveCamera: PerspectiveCamera, - Plane: Plane, - PlaneBufferGeometry: PlaneBufferGeometry, - PlaneGeometry: PlaneGeometry, - PlaneHelper: PlaneHelper, - PointLight: PointLight, - PointLightHelper: PointLightHelper, - Points: Points, - PointsMaterial: PointsMaterial, - PolarGridHelper: PolarGridHelper, - PolyhedronBufferGeometry: PolyhedronBufferGeometry, - PolyhedronGeometry: PolyhedronGeometry, - PositionalAudio: PositionalAudio, - PropertyBinding: PropertyBinding, - PropertyMixer: PropertyMixer, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - Quaternion: Quaternion, - QuaternionKeyframeTrack: QuaternionKeyframeTrack, - QuaternionLinearInterpolant: QuaternionLinearInterpolant, - REVISION: REVISION, - RGBADepthPacking: RGBADepthPacking, - RGBAFormat: RGBAFormat, - RGBAIntegerFormat: RGBAIntegerFormat, - RGBA_ASTC_10x10_Format: RGBA_ASTC_10x10_Format, - RGBA_ASTC_10x5_Format: RGBA_ASTC_10x5_Format, - RGBA_ASTC_10x6_Format: RGBA_ASTC_10x6_Format, - RGBA_ASTC_10x8_Format: RGBA_ASTC_10x8_Format, - RGBA_ASTC_12x10_Format: RGBA_ASTC_12x10_Format, - RGBA_ASTC_12x12_Format: RGBA_ASTC_12x12_Format, - RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, - RGBA_ASTC_5x4_Format: RGBA_ASTC_5x4_Format, - RGBA_ASTC_5x5_Format: RGBA_ASTC_5x5_Format, - RGBA_ASTC_6x5_Format: RGBA_ASTC_6x5_Format, - RGBA_ASTC_6x6_Format: RGBA_ASTC_6x6_Format, - RGBA_ASTC_8x5_Format: RGBA_ASTC_8x5_Format, - RGBA_ASTC_8x6_Format: RGBA_ASTC_8x6_Format, - RGBA_ASTC_8x8_Format: RGBA_ASTC_8x8_Format, - RGBA_BPTC_Format: RGBA_BPTC_Format, - RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, - RGBA_PVRTC_2BPPV1_Format: RGBA_PVRTC_2BPPV1_Format, - RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, - RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format, - RGBA_S3TC_DXT3_Format: RGBA_S3TC_DXT3_Format, - RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, - RGBFormat: RGBFormat, - RGB_ETC1_Format: RGB_ETC1_Format, - RGB_ETC2_Format: RGB_ETC2_Format, - RGB_PVRTC_2BPPV1_Format: RGB_PVRTC_2BPPV1_Format, - RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, - RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format, - RGFormat: RGFormat, - RGIntegerFormat: RGIntegerFormat, - RawShaderMaterial: RawShaderMaterial, - Ray: Ray, - Raycaster: Raycaster, - RectAreaLight: RectAreaLight, - RedFormat: RedFormat, - RedIntegerFormat: RedIntegerFormat, - ReinhardToneMapping: ReinhardToneMapping, - RepeatWrapping: RepeatWrapping, - ReplaceStencilOp: ReplaceStencilOp, - ReverseSubtractEquation: ReverseSubtractEquation, - RingBufferGeometry: RingBufferGeometry, - RingGeometry: RingGeometry, - SRGBColorSpace: SRGBColorSpace, - Scene: Scene, - ShaderChunk: ShaderChunk, - ShaderLib: ShaderLib, - ShaderMaterial: ShaderMaterial, - ShadowMaterial: ShadowMaterial, - Shape: Shape, - ShapeBufferGeometry: ShapeBufferGeometry, - ShapeGeometry: ShapeGeometry, - ShapePath: ShapePath, - ShapeUtils: ShapeUtils, - ShortType: ShortType, - Skeleton: Skeleton, - SkeletonHelper: SkeletonHelper, - SkinnedMesh: SkinnedMesh, - Source: Source, - Sphere: Sphere, - SphereBufferGeometry: SphereBufferGeometry, - SphereGeometry: SphereGeometry, - Spherical: Spherical, - SphericalHarmonics3: SphericalHarmonics3, - SplineCurve: SplineCurve, - SpotLight: SpotLight, - SpotLightHelper: SpotLightHelper, - Sprite: Sprite, - SpriteMaterial: SpriteMaterial, - SrcAlphaFactor: SrcAlphaFactor, - SrcAlphaSaturateFactor: SrcAlphaSaturateFactor, - SrcColorFactor: SrcColorFactor, - StaticCopyUsage: StaticCopyUsage, - StaticDrawUsage: StaticDrawUsage, - StaticReadUsage: StaticReadUsage, - StereoCamera: StereoCamera, - StreamCopyUsage: StreamCopyUsage, - StreamDrawUsage: StreamDrawUsage, - StreamReadUsage: StreamReadUsage, - StringKeyframeTrack: StringKeyframeTrack, - SubtractEquation: SubtractEquation, - SubtractiveBlending: SubtractiveBlending, - TOUCH: TOUCH, - TangentSpaceNormalMap: TangentSpaceNormalMap, - TetrahedronBufferGeometry: TetrahedronBufferGeometry, - TetrahedronGeometry: TetrahedronGeometry, - Texture: Texture, - TextureLoader: TextureLoader, - TorusBufferGeometry: TorusBufferGeometry, - TorusGeometry: TorusGeometry, - TorusKnotBufferGeometry: TorusKnotBufferGeometry, - TorusKnotGeometry: TorusKnotGeometry, - Triangle: Triangle, - TriangleFanDrawMode: TriangleFanDrawMode, - TriangleStripDrawMode: TriangleStripDrawMode, - TrianglesDrawMode: TrianglesDrawMode, - TubeBufferGeometry: TubeBufferGeometry, - TubeGeometry: TubeGeometry, - UVMapping: UVMapping, - Uint16BufferAttribute: Uint16BufferAttribute, - Uint32BufferAttribute: Uint32BufferAttribute, - Uint8BufferAttribute: Uint8BufferAttribute, - Uint8ClampedBufferAttribute: Uint8ClampedBufferAttribute, - Uniform: Uniform, - UniformsGroup: UniformsGroup, - UniformsLib: UniformsLib, - UniformsUtils: UniformsUtils, - UnsignedByteType: UnsignedByteType, - UnsignedInt248Type: UnsignedInt248Type, - UnsignedIntType: UnsignedIntType, - UnsignedShort4444Type: UnsignedShort4444Type, - UnsignedShort5551Type: UnsignedShort5551Type, - UnsignedShortType: UnsignedShortType, - VSMShadowMap: VSMShadowMap, - Vector2: Vector2, - Vector3: Vector3, - Vector4: Vector4, - VectorKeyframeTrack: VectorKeyframeTrack, - VideoTexture: VideoTexture, - WebGL1Renderer: WebGL1Renderer, - WebGL3DRenderTarget: WebGL3DRenderTarget, - WebGLArrayRenderTarget: WebGLArrayRenderTarget, - WebGLCubeRenderTarget: WebGLCubeRenderTarget, - WebGLMultipleRenderTargets: WebGLMultipleRenderTargets, - WebGLMultisampleRenderTarget: WebGLMultisampleRenderTarget, - WebGLRenderTarget: WebGLRenderTarget, - WebGLRenderer: WebGLRenderer, - WebGLUtils: WebGLUtils, - WireframeGeometry: WireframeGeometry, - WrapAroundEnding: WrapAroundEnding, - ZeroCurvatureEnding: ZeroCurvatureEnding, - ZeroFactor: ZeroFactor, - ZeroSlopeEnding: ZeroSlopeEnding, - ZeroStencilOp: ZeroStencilOp, - _SRGBAFormat: _SRGBAFormat, - sRGBEncoding: sRGBEncoding - }); - - /* src\MovingDotSpaceModalBrainstorm.svelte generated by Svelte v3.59.2 */ - const file$e = "src\\MovingDotSpaceModalBrainstorm.svelte"; + const actions = this._actions, + lastInactiveAction = actions[ actions.length - 1 ], + cacheIndex = action._cacheIndex; - function create_fragment$e(ctx) { - let div; + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); - const block = { - c: function create() { - div = element("div"); - attr_dev(div, "class", "svelte-1kuj9kb"); - add_location(div, file$e, 95, 0, 3254); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, div, anchor); - /*div_binding*/ ctx[1](div); - }, - p: noop, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(div); - /*div_binding*/ ctx[1](null); - } - }; + action._cacheIndex = null; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$e.name, - type: "component", - source: "", - ctx - }); - return block; - } + const clipUuid = action._clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ], + knownActionsForClip = actionsForClip.knownActions, - function instance$e($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('MovingDotSpaceModalBrainstorm', slots, []); - let container; - let scene, camera, renderer, geometry, material, mesh; + lastKnownAction = + knownActionsForClip[ knownActionsForClip.length - 1 ], - onMount(() => { - init(); - animate(); - }); + byClipCacheIndex = action._byClipCacheIndex; - function init() { - // Create scene - scene = new Scene(); + lastKnownAction._byClipCacheIndex = byClipCacheIndex; + knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; + knownActionsForClip.pop(); - // Create camera - camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); + action._byClipCacheIndex = null; - camera.position.z = 5; - // Create renderer - renderer = new WebGLRenderer({ antialias: true }); + const actionByRoot = actionsForClip.actionByRoot, + rootUuid = ( action._localRoot || this._root ).uuid; - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); + delete actionByRoot[ rootUuid ]; - // Create geometry - geometry = new TorusKnotGeometry(1, 0.3, 100, 20); + if ( knownActionsForClip.length === 0 ) { - // Create material - material = new MeshBasicMaterial({ color: 0x00ff00, wireframe: true }); + delete actionsByClip[ clipUuid ]; - // Create mesh - mesh = new Mesh(geometry, material); + } - scene.add(mesh); - } + this._removeInactiveBindingsForAction( action ); - function animate() { - requestAnimationFrame(animate); - mesh.rotation.x += 0.01; - mesh.rotation.y += 0.02; - renderer.render(scene, camera); } - const writable_props = []; + _removeInactiveBindingsForAction( action ) { - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); + const bindings = action._propertyBindings; - function div_binding($$value) { - binding_callbacks[$$value ? 'unshift' : 'push'](() => { - container = $$value; - $$invalidate(0, container); - }); - } + for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - $$self.$capture_state = () => ({ - onMount, - THREE, - container, - scene, - camera, - renderer, - geometry, - material, - mesh, - init, - animate - }); + const binding = bindings[ i ]; - $$self.$inject_state = $$props => { - if ('container' in $$props) $$invalidate(0, container = $$props.container); - if ('scene' in $$props) scene = $$props.scene; - if ('camera' in $$props) camera = $$props.camera; - if ('renderer' in $$props) renderer = $$props.renderer; - if ('geometry' in $$props) geometry = $$props.geometry; - if ('material' in $$props) material = $$props.material; - if ('mesh' in $$props) mesh = $$props.mesh; - }; + if ( -- binding.referenceCount === 0 ) { - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + this._removeInactiveBinding( binding ); - return [container, div_binding]; - } + } - class MovingDotSpaceModalBrainstorm extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$e, create_fragment$e, safe_not_equal, {}); + } - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "MovingDotSpaceModalBrainstorm", - options, - id: create_fragment$e.name - }); } - } - /* src\MovingDotSpaceGameFind.svelte generated by Svelte v3.59.2 */ + _lendAction( action ) { - const file$d = "src\\MovingDotSpaceGameFind.svelte"; + // [ active actions | inactive actions ] + // [ active actions >| inactive actions ] + // s a + // <-swap-> + // a s - function get_each_context$a(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[9] = list[i]; - child_ctx[11] = i; - return child_ctx; - } + const actions = this._actions, + prevIndex = action._cacheIndex, - function get_each_context_1$4(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[12] = list[i]; - child_ctx[14] = i; - return child_ctx; - } + lastActiveIndex = this._nActiveActions ++, - // (63:4) {:else} - function create_else_block$1(ctx) { - let p; + firstInactiveAction = actions[ lastActiveIndex ]; - const block = { - c: function create() { - p = element("p"); - p.textContent = "Game over. Try again!"; - add_location(p, file$d, 63, 6, 1832); - }, - m: function mount(target, anchor) { - insert_dev(target, p, anchor); - }, - p: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(p); - } - }; + action._cacheIndex = lastActiveIndex; + actions[ lastActiveIndex ] = action; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_else_block$1.name, - type: "else", - source: "(63:4) {:else}", - ctx - }); + firstInactiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = firstInactiveAction; - return block; - } + } - // (61:34) - function create_if_block_1$3(ctx) { - let p; + _takeBackAction( action ) { - const block = { - c: function create() { - p = element("p"); - p.textContent = "You won! 🎉"; - add_location(p, file$d, 61, 6, 1793); - }, - m: function mount(target, anchor) { - insert_dev(target, p, anchor); - }, - p: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(p); - } - }; + // [ active actions | inactive actions ] + // [ active actions |< inactive actions ] + // a s + // <-swap-> + // s a - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block_1$3.name, - type: "if", - source: "(61:34) ", - ctx - }); - - return block; - } - - // (59:4) {#if gameState === 'playing'} - function create_if_block$6(ctx) { - let p; - let t0; - let t1; + const actions = this._actions, + prevIndex = action._cacheIndex, - const block = { - c: function create() { - p = element("p"); - t0 = text("Presses Remaining: "); - t1 = text(/*pressesRemaining*/ ctx[0]); - add_location(p, file$d, 59, 6, 1705); - }, - m: function mount(target, anchor) { - insert_dev(target, p, anchor); - append_dev(p, t0); - append_dev(p, t1); - }, - p: function update(ctx, dirty) { - if (dirty & /*pressesRemaining*/ 1) set_data_dev(t1, /*pressesRemaining*/ ctx[0]); - }, - d: function destroy(detaching) { - if (detaching) detach_dev(p); - } - }; + firstInactiveIndex = -- this._nActiveActions, - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block$6.name, - type: "if", - source: "(59:4) {#if gameState === 'playing'}", - ctx - }); + lastActiveAction = actions[ firstInactiveIndex ]; - return block; - } + action._cacheIndex = firstInactiveIndex; + actions[ firstInactiveIndex ] = action; - // (71:6) {#each row as cell, colIndex} - function create_each_block_1$4(ctx) { - let button; + lastActiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = lastActiveAction; - let t0_value = (/*cell*/ ctx[12].pressed - ? /*rowIndex*/ ctx[11] === /*correctItem*/ ctx[1].row && /*colIndex*/ ctx[14] === /*correctItem*/ ctx[1].col - ? '✅' - : '❌' - : '') + ""; + } - let t0; - let t1; - let button_disabled_value; - let mounted; - let dispose; + // Memory management for PropertyMixer objects - function click_handler() { - return /*click_handler*/ ctx[6](/*rowIndex*/ ctx[11], /*colIndex*/ ctx[14]); - } + _addInactiveBinding( binding, rootUuid, trackName ) { - const block = { - c: function create() { - button = element("button"); - t0 = text(t0_value); - t1 = space(); - button.disabled = button_disabled_value = /*gameState*/ ctx[2] !== 'playing'; - attr_dev(button, "class", "svelte-p3ubim"); - toggle_class(button, "pressed", /*cell*/ ctx[12].pressed); - add_location(button, file$d, 71, 8, 2045); - }, - m: function mount(target, anchor) { - insert_dev(target, button, anchor); - append_dev(button, t0); - append_dev(button, t1); + const bindingsByRoot = this._bindingsByRootAndName, + bindings = this._bindings; - if (!mounted) { - dispose = listen_dev(button, "click", click_handler, false, false, false, false); - mounted = true; - } - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; + let bindingByName = bindingsByRoot[ rootUuid ]; - if (dirty & /*grid, correctItem*/ 10 && t0_value !== (t0_value = (/*cell*/ ctx[12].pressed - ? /*rowIndex*/ ctx[11] === /*correctItem*/ ctx[1].row && /*colIndex*/ ctx[14] === /*correctItem*/ ctx[1].col - ? '✅' - : '❌' - : '') + "")) set_data_dev(t0, t0_value); + if ( bindingByName === undefined ) { - if (dirty & /*gameState*/ 4 && button_disabled_value !== (button_disabled_value = /*gameState*/ ctx[2] !== 'playing')) { - prop_dev(button, "disabled", button_disabled_value); - } + bindingByName = {}; + bindingsByRoot[ rootUuid ] = bindingByName; - if (dirty & /*grid*/ 8) { - toggle_class(button, "pressed", /*cell*/ ctx[12].pressed); - } - }, - d: function destroy(detaching) { - if (detaching) detach_dev(button); - mounted = false; - dispose(); } - }; - - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block_1$4.name, - type: "each", - source: "(71:6) {#each row as cell, colIndex}", - ctx - }); - return block; - } + bindingByName[ trackName ] = binding; - // (70:4) {#each grid as row, rowIndex} - function create_each_block$a(ctx) { - let each_1_anchor; - let each_value_1 = /*row*/ ctx[9]; - validate_each_argument(each_value_1); - let each_blocks = []; + binding._cacheIndex = bindings.length; + bindings.push( binding ); - for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks[i] = create_each_block_1$4(get_each_context_1$4(ctx, each_value_1, i)); } - const block = { - c: function create() { - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + _removeInactiveBinding( binding ) { - each_1_anchor = empty(); - }, - m: function mount(target, anchor) { - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(target, anchor); - } - } + const bindings = this._bindings, + propBinding = binding.binding, + rootUuid = propBinding.rootNode.uuid, + trackName = propBinding.path, + bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ], - insert_dev(target, each_1_anchor, anchor); - }, - p: function update(ctx, dirty) { - if (dirty & /*gameState, grid, pressButton, correctItem*/ 30) { - each_value_1 = /*row*/ ctx[9]; - validate_each_argument(each_value_1); - let i; + lastInactiveBinding = bindings[ bindings.length - 1 ], + cacheIndex = binding._cacheIndex; - for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$4(ctx, each_value_1, i); + lastInactiveBinding._cacheIndex = cacheIndex; + bindings[ cacheIndex ] = lastInactiveBinding; + bindings.pop(); - if (each_blocks[i]) { - each_blocks[i].p(child_ctx, dirty); - } else { - each_blocks[i] = create_each_block_1$4(child_ctx); - each_blocks[i].c(); - each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); - } - } + delete bindingByName[ trackName ]; - for (; i < each_blocks.length; i += 1) { - each_blocks[i].d(1); - } + if ( Object.keys( bindingByName ).length === 0 ) { + + delete bindingsByRoot[ rootUuid ]; - each_blocks.length = each_value_1.length; - } - }, - d: function destroy(detaching) { - destroy_each(each_blocks, detaching); - if (detaching) detach_dev(each_1_anchor); } - }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block$a.name, - type: "each", - source: "(70:4) {#each grid as row, rowIndex}", - ctx - }); + } - return block; - } + _lendBinding( binding ) { - function create_fragment$d(ctx) { - let div0; - let t0; - let button; - let t2; - let div1; - let mounted; - let dispose; + const bindings = this._bindings, + prevIndex = binding._cacheIndex, - function select_block_type(ctx, dirty) { - if (/*gameState*/ ctx[2] === 'playing') return create_if_block$6; - if (/*gameState*/ ctx[2] === 'won') return create_if_block_1$3; - return create_else_block$1; - } + lastActiveIndex = this._nActiveBindings ++, - let current_block_type = select_block_type(ctx); - let if_block = current_block_type(ctx); - let each_value = /*grid*/ ctx[3]; - validate_each_argument(each_value); - let each_blocks = []; + firstInactiveBinding = bindings[ lastActiveIndex ]; - for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$a(get_each_context$a(ctx, each_value, i)); - } + binding._cacheIndex = lastActiveIndex; + bindings[ lastActiveIndex ] = binding; - const block = { - c: function create() { - div0 = element("div"); - if_block.c(); - t0 = space(); - button = element("button"); - button.textContent = "Restart Game"; - t2 = space(); - div1 = element("div"); + firstInactiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = firstInactiveBinding; - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + } - attr_dev(button, "class", "svelte-p3ubim"); - add_location(button, file$d, 65, 4, 1877); - add_location(div0, file$d, 57, 2, 1657); - attr_dev(div1, "class", "grid svelte-p3ubim"); - add_location(div1, file$d, 68, 2, 1945); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, div0, anchor); - if_block.m(div0, null); - append_dev(div0, t0); - append_dev(div0, button); - insert_dev(target, t2, anchor); - insert_dev(target, div1, anchor); + _takeBackBinding( binding ) { - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(div1, null); - } - } + const bindings = this._bindings, + prevIndex = binding._cacheIndex, - if (!mounted) { - dispose = listen_dev(button, "click", /*resetGame*/ ctx[5], false, false, false, false); - mounted = true; - } - }, - p: function update(ctx, [dirty]) { - if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block) { - if_block.p(ctx, dirty); - } else { - if_block.d(1); - if_block = current_block_type(ctx); + firstInactiveIndex = -- this._nActiveBindings, - if (if_block) { - if_block.c(); - if_block.m(div0, t0); - } - } + lastActiveBinding = bindings[ firstInactiveIndex ]; - if (dirty & /*grid, gameState, pressButton, correctItem*/ 30) { - each_value = /*grid*/ ctx[3]; - validate_each_argument(each_value); - let i; + binding._cacheIndex = firstInactiveIndex; + bindings[ firstInactiveIndex ] = binding; - for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$a(ctx, each_value, i); + lastActiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = lastActiveBinding; - if (each_blocks[i]) { - each_blocks[i].p(child_ctx, dirty); - } else { - each_blocks[i] = create_each_block$a(child_ctx); - each_blocks[i].c(); - each_blocks[i].m(div1, null); - } - } + } - for (; i < each_blocks.length; i += 1) { - each_blocks[i].d(1); - } - each_blocks.length = each_value.length; - } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(div0); - if_block.d(); - if (detaching) detach_dev(t2); - if (detaching) detach_dev(div1); - destroy_each(each_blocks, detaching); - mounted = false; - dispose(); - } - }; + // Memory management of Interpolants for weight and time scale - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$d.name, - type: "component", - source: "", - ctx - }); + _lendControlInterpolant() { - return block; - } + const interpolants = this._controlInterpolants, + lastActiveIndex = this._nActiveControlInterpolants ++; - function instance$d($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('MovingDotSpaceGameFind', slots, []); - let gridSize = 10; - let maxPresses = 20; // Maximum number of presses allowed - let pressesRemaining = maxPresses; + let interpolant = interpolants[ lastActiveIndex ]; - let correctItem = { - row: Math.floor(Math.random() * gridSize), - col: Math.floor(Math.random() * gridSize) - }; + if ( interpolant === undefined ) { - let gameState = "playing"; // Can be "playing", "won", or "lost" + interpolant = new LinearInterpolant( + new Float32Array( 2 ), new Float32Array( 2 ), + 1, _controlInterpolantsResultBuffer ); - // Generate initial grid state - let grid = Array(gridSize).fill().map(() => Array(gridSize).fill().map(() => ({ pressed: false }))); + interpolant.__cacheIndex = lastActiveIndex; + interpolants[ lastActiveIndex ] = interpolant; - function pressButton(row, col) { - if (grid[row][col].pressed || pressesRemaining === 0 || gameState !== "playing") { - return; // Ignore if already pressed or no presses left or game not in playing state } - $$invalidate(3, grid[row][col].pressed = true, grid); - $$invalidate(0, pressesRemaining -= 1); + return interpolant; - // Check for win condition - if (row === correctItem.row && col === correctItem.col) { - $$invalidate(2, gameState = "won"); - } else if (pressesRemaining === 0) { - $$invalidate(2, gameState = "lost"); - } } - function resetGame() { - $$invalidate(0, pressesRemaining = maxPresses); + _takeBackControlInterpolant( interpolant ) { - $$invalidate(1, correctItem = { - row: Math.floor(Math.random() * gridSize), - col: Math.floor(Math.random() * gridSize) - }); + const interpolants = this._controlInterpolants, + prevIndex = interpolant.__cacheIndex, - $$invalidate(3, grid = Array(gridSize).fill().map(() => Array(gridSize).fill().map(() => ({ pressed: false })))); - $$invalidate(2, gameState = "playing"); - } + firstInactiveIndex = -- this._nActiveControlInterpolants, - const writable_props = []; + lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); + interpolant.__cacheIndex = firstInactiveIndex; + interpolants[ firstInactiveIndex ] = interpolant; - const click_handler = (rowIndex, colIndex) => pressButton(rowIndex, colIndex); + lastActiveInterpolant.__cacheIndex = prevIndex; + interpolants[ prevIndex ] = lastActiveInterpolant; - $$self.$capture_state = () => ({ - gridSize, - maxPresses, - pressesRemaining, - correctItem, - gameState, - grid, - pressButton, - resetGame - }); + } - $$self.$inject_state = $$props => { - if ('gridSize' in $$props) gridSize = $$props.gridSize; - if ('maxPresses' in $$props) maxPresses = $$props.maxPresses; - if ('pressesRemaining' in $$props) $$invalidate(0, pressesRemaining = $$props.pressesRemaining); - if ('correctItem' in $$props) $$invalidate(1, correctItem = $$props.correctItem); - if ('gameState' in $$props) $$invalidate(2, gameState = $$props.gameState); - if ('grid' in $$props) $$invalidate(3, grid = $$props.grid); - }; + // return an action for a clip optionally using a custom root target + // object (this method allocates a lot of dynamic memory in case a + // previously unknown clip/root combination is specified) + clipAction( clip, optionalRoot, blendMode ) { - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + const root = optionalRoot || this._root, + rootUuid = root.uuid; - return [ - pressesRemaining, - correctItem, - gameState, - grid, - pressButton, - resetGame, - click_handler - ]; - } + let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; - class MovingDotSpaceGameFind extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$d, create_fragment$d, safe_not_equal, {}); + const clipUuid = clipObject !== null ? clipObject.uuid : clip; - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "MovingDotSpaceGameFind", - options, - id: create_fragment$d.name - }); - } - } + const actionsForClip = this._actionsByClip[ clipUuid ]; + let prototypeAction = null; - /* src\MovingDotSpaceGameOrder.svelte generated by Svelte v3.59.2 */ + if ( blendMode === undefined ) { - const file$c = "src\\MovingDotSpaceGameOrder.svelte"; + if ( clipObject !== null ) { - function get_each_context$9(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[10] = list[i]; - child_ctx[12] = i; - return child_ctx; - } + blendMode = clipObject.blendMode; - // (72:39) - function create_if_block_2(ctx) { - let p; + } else { + + blendMode = NormalAnimationBlendMode; + + } - const block = { - c: function create() { - p = element("p"); - p.textContent = "Incorrect order. Try again!"; - add_location(p, file$c, 72, 4, 2206); - }, - m: function mount(target, anchor) { - insert_dev(target, p, anchor); - }, - d: function destroy(detaching) { - if (detaching) detach_dev(p); } - }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block_2.name, - type: "if", - source: "(72:39) ", - ctx - }); + if ( actionsForClip !== undefined ) { - return block; - } + const existingAction = actionsForClip.actionByRoot[ rootUuid ]; - // (70:2) {#if gameStatus === "correct"} - function create_if_block_1$2(ctx) { - let p; + if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { - const block = { - c: function create() { - p = element("p"); - p.textContent = "You guessed the correct order! 🎉"; - add_location(p, file$c, 70, 4, 2119); - }, - m: function mount(target, anchor) { - insert_dev(target, p, anchor); - }, - d: function destroy(detaching) { - if (detaching) detach_dev(p); - } - }; + return existingAction; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block_1$2.name, - type: "if", - source: "(70:2) {#if gameStatus === \\\"correct\\\"}", - ctx - }); + } - return block; - } + // we know the clip, so we don't have to parse all + // the bindings again but can just copy + prototypeAction = actionsForClip.knownActions[ 0 ]; - // (79:4) {#each Array(gridSize) as _, i} - function create_each_block$9(ctx) { - let button; - let t0_value = /*i*/ ctx[12] + 1 + ""; - let t0; - let t1; - let mounted; - let dispose; + // also, take the clip from the prototype action + if ( clipObject === null ) + clipObject = prototypeAction._clip; - function click_handler() { - return /*click_handler*/ ctx[8](/*i*/ ctx[12]); - } + } - const block = { - c: function create() { - button = element("button"); - t0 = text(t0_value); - t1 = space(); - attr_dev(button, "data-number", /*i*/ ctx[12] + 1); - attr_dev(button, "class", "svelte-7k1yf9"); - toggle_class(button, "pressed", /*userOrder*/ ctx[0].includes(/*i*/ ctx[12] + 1)); - add_location(button, file$c, 79, 6, 2378); - }, - m: function mount(target, anchor) { - insert_dev(target, button, anchor); - append_dev(button, t0); - append_dev(button, t1); + // clip must be known when specified via string + if ( clipObject === null ) return null; - if (!mounted) { - dispose = listen_dev(button, "click", click_handler, false, false, false, false); - mounted = true; - } - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; + // allocate all resources required to run it + const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); + + this._bindAction( newAction, prototypeAction ); + + // and make the action known to the memory manager + this._addInactiveAction( newAction, clipUuid, rootUuid ); + + return newAction; + + } + + // get an existing action + existingAction( clip, optionalRoot ) { + + const root = optionalRoot || this._root, + rootUuid = root.uuid, + + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, + + clipUuid = clipObject ? clipObject.uuid : clip, + + actionsForClip = this._actionsByClip[ clipUuid ]; + + if ( actionsForClip !== undefined ) { + + return actionsForClip.actionByRoot[ rootUuid ] || null; - if (dirty & /*userOrder*/ 1) { - toggle_class(button, "pressed", /*userOrder*/ ctx[0].includes(/*i*/ ctx[12] + 1)); - } - }, - d: function destroy(detaching) { - if (detaching) detach_dev(button); - mounted = false; - dispose(); } - }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block$9.name, - type: "each", - source: "(79:4) {#each Array(gridSize) as _, i}", - ctx - }); + return null; - return block; - } + } - // (86:2) {#if !checkOnEveryPress && gameStatus === ""} - function create_if_block$5(ctx) { - let button; - let t; - let button_disabled_value; - let mounted; - let dispose; + // deactivates all previously scheduled actions + stopAllAction() { - const block = { - c: function create() { - button = element("button"); - t = text("Check Order"); - button.disabled = button_disabled_value = /*userOrder*/ ctx[0].length !== /*gridSize*/ ctx[3]; - attr_dev(button, "class", "svelte-7k1yf9"); - add_location(button, file$c, 86, 4, 2600); - }, - m: function mount(target, anchor) { - insert_dev(target, button, anchor); - append_dev(button, t); + const actions = this._actions, + nActions = this._nActiveActions; + + for ( let i = nActions - 1; i >= 0; -- i ) { + + actions[ i ].stop(); - if (!mounted) { - dispose = listen_dev(button, "click", /*checkOrder*/ ctx[5], false, false, false, false); - mounted = true; - } - }, - p: function update(ctx, dirty) { - if (dirty & /*userOrder*/ 1 && button_disabled_value !== (button_disabled_value = /*userOrder*/ ctx[0].length !== /*gridSize*/ ctx[3])) { - prop_dev(button, "disabled", button_disabled_value); - } - }, - d: function destroy(detaching) { - if (detaching) detach_dev(button); - mounted = false; - dispose(); } - }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block$5.name, - type: "if", - source: "(86:2) {#if !checkOnEveryPress && gameStatus === \\\"\\\"}", - ctx - }); + return this; - return block; - } + } - function create_fragment$c(ctx) { - let div0; - let input; - let t0; - let label; - let t2; - let t3; - let button; - let t5; - let div1; - let t6; - let if_block1_anchor; - let mounted; - let dispose; + // advance the time and update apply the animation + update( deltaTime ) { + + deltaTime *= this.timeScale; + + const actions = this._actions, + nActions = this._nActiveActions, + + time = this.time += deltaTime, + timeDirection = Math.sign( deltaTime ), + + accuIndex = this._accuIndex ^= 1; + + // run active actions + + for ( let i = 0; i !== nActions; ++ i ) { + + const action = actions[ i ]; + + action._update( time, deltaTime, timeDirection, accuIndex ); + + } + + // update scene graph + + const bindings = this._bindings, + nBindings = this._nActiveBindings; + + for ( let i = 0; i !== nBindings; ++ i ) { + + bindings[ i ].apply( accuIndex ); + + } + + return this; - function select_block_type(ctx, dirty) { - if (/*gameStatus*/ ctx[2] === "correct") return create_if_block_1$2; - if (/*gameStatus*/ ctx[2] === "incorrect") return create_if_block_2; } - let current_block_type = select_block_type(ctx); - let if_block0 = current_block_type && current_block_type(ctx); - let each_value = Array(/*gridSize*/ ctx[3]); - validate_each_argument(each_value); - let each_blocks = []; + // Allows you to seek to a specific time in an animation. + setTime( timeInSeconds ) { + + this.time = 0; // Zero out time attribute for AnimationMixer object; + for ( let i = 0; i < this._actions.length; i ++ ) { + + this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. + + } + + return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. - for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$9(get_each_context$9(ctx, each_value, i)); } - let if_block1 = !/*checkOnEveryPress*/ ctx[1] && /*gameStatus*/ ctx[2] === "" && create_if_block$5(ctx); + // return this mixer's root target object + getRoot() { - const block = { - c: function create() { - div0 = element("div"); - input = element("input"); - t0 = space(); - label = element("label"); - label.textContent = "Check order on every press"; - t2 = space(); - if (if_block0) if_block0.c(); - t3 = space(); - button = element("button"); - button.textContent = "Restart Game"; - t5 = space(); - div1 = element("div"); + return this._root; - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + } - t6 = space(); - if (if_block1) if_block1.c(); - if_block1_anchor = empty(); - attr_dev(input, "type", "checkbox"); - add_location(input, file$c, 65, 4, 1962); - add_location(label, file$c, 66, 4, 2024); - attr_dev(div0, "class", "controls svelte-7k1yf9"); - add_location(div0, file$c, 64, 2, 1934); - attr_dev(button, "class", "svelte-7k1yf9"); - add_location(button, file$c, 75, 2, 2257); - attr_dev(div1, "class", "grid svelte-7k1yf9"); - add_location(div1, file$c, 77, 2, 2315); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, div0, anchor); - append_dev(div0, input); - input.checked = /*checkOnEveryPress*/ ctx[1]; - append_dev(div0, t0); - append_dev(div0, label); - insert_dev(target, t2, anchor); - if (if_block0) if_block0.m(target, anchor); - insert_dev(target, t3, anchor); - insert_dev(target, button, anchor); - insert_dev(target, t5, anchor); - insert_dev(target, div1, anchor); + // free all resources specific to a particular clip + uncacheClip( clip ) { - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(div1, null); - } - } + const actions = this._actions, + clipUuid = clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; - insert_dev(target, t6, anchor); - if (if_block1) if_block1.m(target, anchor); - insert_dev(target, if_block1_anchor, anchor); + if ( actionsForClip !== undefined ) { - if (!mounted) { - dispose = [ - listen_dev(input, "change", /*input_change_handler*/ ctx[7]), - listen_dev(button, "click", /*resetGame*/ ctx[6], false, false, false, false) - ]; + // note: just calling _removeInactiveAction would mess up the + // iteration state and also require updating the state we can + // just throw away - mounted = true; - } - }, - p: function update(ctx, [dirty]) { - if (dirty & /*checkOnEveryPress*/ 2) { - input.checked = /*checkOnEveryPress*/ ctx[1]; - } + const actionsToRemove = actionsForClip.knownActions; - if (current_block_type !== (current_block_type = select_block_type(ctx))) { - if (if_block0) if_block0.d(1); - if_block0 = current_block_type && current_block_type(ctx); + for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - if (if_block0) { - if_block0.c(); - if_block0.m(t3.parentNode, t3); - } - } + const action = actionsToRemove[ i ]; - if (dirty & /*userOrder, handlePress*/ 17) { - each_value = Array(/*gridSize*/ ctx[3]); - validate_each_argument(each_value); - let i; + this._deactivateAction( action ); - for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$9(ctx, each_value, i); + const cacheIndex = action._cacheIndex, + lastInactiveAction = actions[ actions.length - 1 ]; - if (each_blocks[i]) { - each_blocks[i].p(child_ctx, dirty); - } else { - each_blocks[i] = create_each_block$9(child_ctx); - each_blocks[i].c(); - each_blocks[i].m(div1, null); - } - } + action._cacheIndex = null; + action._byClipCacheIndex = null; - for (; i < each_blocks.length; i += 1) { - each_blocks[i].d(1); - } + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); - each_blocks.length = each_value.length; - } + this._removeInactiveBindingsForAction( action ); - if (!/*checkOnEveryPress*/ ctx[1] && /*gameStatus*/ ctx[2] === "") { - if (if_block1) { - if_block1.p(ctx, dirty); - } else { - if_block1 = create_if_block$5(ctx); - if_block1.c(); - if_block1.m(if_block1_anchor.parentNode, if_block1_anchor); - } - } else if (if_block1) { - if_block1.d(1); - if_block1 = null; } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(div0); - if (detaching) detach_dev(t2); - if (if_block0) { - if_block0.d(detaching); - } + delete actionsByClip[ clipUuid ]; - if (detaching) detach_dev(t3); - if (detaching) detach_dev(button); - if (detaching) detach_dev(t5); - if (detaching) detach_dev(div1); - destroy_each(each_blocks, detaching); - if (detaching) detach_dev(t6); - if (if_block1) if_block1.d(detaching); - if (detaching) detach_dev(if_block1_anchor); - mounted = false; - run_all(dispose); } - }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$c.name, - type: "component", - source: "", - ctx - }); + } - return block; - } + // free all resources specific to a particular root target object + uncacheRoot( root ) { - function instance$c($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('MovingDotSpaceGameOrder', slots, []); - let gridSize = 4; // Grid size for simplicity - let correctOrder = Array.from({ length: gridSize }, (_, i) => i + 1).sort(() => 0.5 - Math.random()); // Randomized correct order - let userOrder = []; // User's order - let checkOnEveryPress = false; // Start with manual check - let gameStatus = ""; // "", "correct", or "incorrect" + const rootUuid = root.uuid, + actionsByClip = this._actionsByClip; - function handlePress(number) { - if (userOrder.includes(number) || gameStatus) return; // Ignore if already pressed or game has ended - userOrder.push(number); + for ( const clipUuid in actionsByClip ) { - if (!checkOnEveryPress) { - // Add the "pressed" class to the pressed button - const pressedButton = document.querySelector(`button[data-number="${number}"]`); + const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, + action = actionByRoot[ rootUuid ]; + + if ( action !== undefined ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + + } - pressedButton.classList.add("pressed"); - } else { - checkOrder(); } - } - function checkOrder() { - for (let i = 0; i < userOrder.length; i++) { - if (userOrder[i] !== correctOrder[i]) { - $$invalidate(2, gameStatus = "incorrect"); - return; + const bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ]; + + if ( bindingByName !== undefined ) { + + for ( const trackName in bindingByName ) { + + const binding = bindingByName[ trackName ]; + binding.restoreOriginalState(); + this._removeInactiveBinding( binding ); + } + } - if (userOrder.length === correctOrder.length) { - $$invalidate(2, gameStatus = "correct"); + } + + // remove a targeted clip from the cache + uncacheAction( clip, optionalRoot ) { + + const action = this.existingAction( clip, optionalRoot ); + + if ( action !== null ) { + + this._deactivateAction( action ); + this._removeInactiveAction( action ); + } + } - function resetGame() { - $$invalidate(0, userOrder = []); - $$invalidate(2, gameStatus = ""); - correctOrder.sort(() => 0.5 - Math.random()); // Shuffle for a new game + } - // Remove the "pressed" class from all buttons - const pressedButtons = document.querySelectorAll(".pressed"); + class Uniform { + + constructor( value ) { + + this.value = value; - pressedButtons.forEach(button => button.classList.remove("pressed")); } - const writable_props = []; + clone() { - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); + return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); - function input_change_handler() { - checkOnEveryPress = this.checked; - $$invalidate(1, checkOnEveryPress); } - const click_handler = i => handlePress(i + 1); + } - $$self.$capture_state = () => ({ - gridSize, - correctOrder, - userOrder, - checkOnEveryPress, - gameStatus, - handlePress, - checkOrder, - resetGame - }); + let id = 0; - $$self.$inject_state = $$props => { - if ('gridSize' in $$props) $$invalidate(3, gridSize = $$props.gridSize); - if ('correctOrder' in $$props) correctOrder = $$props.correctOrder; - if ('userOrder' in $$props) $$invalidate(0, userOrder = $$props.userOrder); - if ('checkOnEveryPress' in $$props) $$invalidate(1, checkOnEveryPress = $$props.checkOnEveryPress); - if ('gameStatus' in $$props) $$invalidate(2, gameStatus = $$props.gameStatus); - }; + class UniformsGroup extends EventDispatcher { + + constructor() { + + super(); + + this.isUniformsGroup = true; + + Object.defineProperty( this, 'id', { value: id ++ } ); + + this.name = ''; + + this.usage = StaticDrawUsage; + this.uniforms = []; - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); } - return [ - userOrder, - checkOnEveryPress, - gameStatus, - gridSize, - handlePress, - checkOrder, - resetGame, - input_change_handler, - click_handler - ]; - } + add( uniform ) { - class MovingDotSpaceGameOrder extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$c, create_fragment$c, safe_not_equal, {}); + this.uniforms.push( uniform ); + + return this; - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "MovingDotSpaceGameOrder", - options, - id: create_fragment$c.name - }); } - } - // themeConfig.js - - const themes = { - 'User Custom': { - background: '/AutoGameBackgrounds/theme_background.png', - inventory: [ - { type: "weapon", name: "Random waepon", description: "A powerful weapon." }, - // ... more space items - ], - skills: [ - { branch: "Skill Group 1", name: "Skill One", learned: false }, - // ... more space skills - ], - persistentTargets: [ - { name: "Background Target 1", x: 500, y: 500, collisionType: "alert", collisiontext: "First Test"}, - ], - // ... and so on for targets - story: [ - { - part: 0, - objectives: [ - { id: 1, - name: "Mission Details", - complete: false, - progress: 0, - inventoryRequired: [], }, - ], - targets: [ - { name: "Target 1", x: 150, y: 150, collisionType: "alert", collisiontext: "First Test"}, - ], + remove( uniform ) { + + const index = this.uniforms.indexOf( uniform ); + + if ( index !== - 1 ) this.uniforms.splice( index, 1 ); + + return this; + + } + + setName( name ) { + + this.name = name; + + return this; + + } + + setUsage( value ) { + + this.usage = value; + + return this; + + } + + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); + + return this; + + } + + copy( source ) { + + this.name = source.name; + this.usage = source.usage; + + const uniformsSource = source.uniforms; + + this.uniforms.length = 0; + + for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { + + this.uniforms.push( uniformsSource[ i ].clone() ); + + } + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + } + + class InstancedInterleavedBuffer extends InterleavedBuffer { + + constructor( array, stride, meshPerAttribute = 1 ) { + + super( array, stride ); + + this.isInstancedInterleavedBuffer = true; + + this.meshPerAttribute = meshPerAttribute; + + } + + copy( source ) { + + super.copy( source ); + + this.meshPerAttribute = source.meshPerAttribute; + + return this; + + } + + clone( data ) { + + const ib = super.clone( data ); + + ib.meshPerAttribute = this.meshPerAttribute; + + return ib; + + } + + toJSON( data ) { + + const json = super.toJSON( data ); + + json.isInstancedInterleavedBuffer = true; + json.meshPerAttribute = this.meshPerAttribute; + + return json; + + } + + } + + class GLBufferAttribute { + + constructor( buffer, type, itemSize, elementSize, count ) { + + this.isGLBufferAttribute = true; + + this.buffer = buffer; + this.type = type; + this.itemSize = itemSize; + this.elementSize = elementSize; + this.count = count; + + this.version = 0; + + } + + set needsUpdate( value ) { + + if ( value === true ) this.version ++; + + } + + setBuffer( buffer ) { + + this.buffer = buffer; + + return this; + + } + + setType( type, elementSize ) { + + this.type = type; + this.elementSize = elementSize; + + return this; + + } + + setItemSize( itemSize ) { + + this.itemSize = itemSize; + + return this; + + } + + setCount( count ) { + + this.count = count; + + return this; + + } + + } + + class Raycaster { + + constructor( origin, direction, near = 0, far = Infinity ) { + + this.ray = new Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + this.near = near; + this.far = far; + this.camera = null; + this.layers = new Layers(); + + this.params = { + Mesh: {}, + Line: { threshold: 1 }, + LOD: {}, + Points: { threshold: 1 }, + Sprite: {} + }; + + } + + set( origin, direction ) { + + // direction is assumed to be normalized (for accurate distance calculations) + + this.ray.set( origin, direction ); + + } + + setFromCamera( coords, camera ) { + + if ( camera.isPerspectiveCamera ) { + + this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); + this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); + this.camera = camera; + + } else if ( camera.isOrthographicCamera ) { + + this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera + this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); + this.camera = camera; + + } else { + + console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); + + } + + } + + intersectObject( object, recursive = true, intersects = [] ) { + + intersectObject( object, this, intersects, recursive ); + + intersects.sort( ascSort ); + + return intersects; + + } + + intersectObjects( objects, recursive = true, intersects = [] ) { + + for ( let i = 0, l = objects.length; i < l; i ++ ) { + + intersectObject( objects[ i ], this, intersects, recursive ); + + } + + intersects.sort( ascSort ); + + return intersects; + + } + + } + + function ascSort( a, b ) { + + return a.distance - b.distance; + + } + + function intersectObject( object, raycaster, intersects, recursive ) { + + if ( object.layers.test( raycaster.layers ) ) { + + object.raycast( raycaster, intersects ); + + } + + if ( recursive === true ) { + + const children = object.children; + + for ( let i = 0, l = children.length; i < l; i ++ ) { + + intersectObject( children[ i ], raycaster, intersects, true ); + + } + + } + + } + + /** + * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system + * + * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up. + * The azimuthal angle (theta) is measured from the positive z-axis. + */ + + class Spherical { + + constructor( radius = 1, phi = 0, theta = 0 ) { + + this.radius = radius; + this.phi = phi; // polar angle + this.theta = theta; // azimuthal angle + + return this; + + } + + set( radius, phi, theta ) { + + this.radius = radius; + this.phi = phi; + this.theta = theta; + + return this; + + } + + copy( other ) { + + this.radius = other.radius; + this.phi = other.phi; + this.theta = other.theta; + + return this; + + } + + // restrict phi to be between EPS and PI-EPS + makeSafe() { + + const EPS = 0.000001; + this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); + + return this; + + } + + setFromVector3( v ) { + + return this.setFromCartesianCoords( v.x, v.y, v.z ); + + } + + setFromCartesianCoords( x, y, z ) { + + this.radius = Math.sqrt( x * x + y * y + z * z ); + + if ( this.radius === 0 ) { + + this.theta = 0; + this.phi = 0; + + } else { + + this.theta = Math.atan2( x, z ); + this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) ); + + } + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + } + + /** + * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system + */ + + class Cylindrical { + + constructor( radius = 1, theta = 0, y = 0 ) { + + this.radius = radius; // distance from the origin to a point in the x-z plane + this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis + this.y = y; // height above the x-z plane + + return this; + + } + + set( radius, theta, y ) { + + this.radius = radius; + this.theta = theta; + this.y = y; + + return this; + + } + + copy( other ) { + + this.radius = other.radius; + this.theta = other.theta; + this.y = other.y; + + return this; + + } + + setFromVector3( v ) { + + return this.setFromCartesianCoords( v.x, v.y, v.z ); + + } + + setFromCartesianCoords( x, y, z ) { + + this.radius = Math.sqrt( x * x + z * z ); + this.theta = Math.atan2( x, z ); + this.y = y; + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + } + + const _vector$4 = /*@__PURE__*/ new Vector2(); + + class Box2 { + + constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { + + this.isBox2 = true; + + this.min = min; + this.max = max; + + } + + set( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + } + + setFromPoints( points ) { + + this.makeEmpty(); + + for ( let i = 0, il = points.length; i < il; i ++ ) { + + this.expandByPoint( points[ i ] ); + + } + + return this; + + } + + setFromCenterAndSize( center, size ) { + + const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + copy( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + } + + makeEmpty() { + + this.min.x = this.min.y = + Infinity; + this.max.x = this.max.y = - Infinity; + + return this; + + } + + isEmpty() { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + + } + + getCenter( target ) { + + return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + } + + getSize( target ) { + + return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); + + } + + expandByPoint( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + + } + + expandByVector( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + + } + + expandByScalar( scalar ) { + + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); + + return this; + + } + + containsPoint( point ) { + + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ? false : true; + + } + + containsBox( box ) { + + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y; + + } + + getParameter( point, target ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + return target.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ) + ); + + } + + intersectsBox( box ) { + + // using 4 splitting planes to rule out intersections + + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y ? false : true; + + } + + clampPoint( point, target ) { + + return target.copy( point ).clamp( this.min, this.max ); + + } + + distanceToPoint( point ) { + + const clampedPoint = _vector$4.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + } + + intersect( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + return this; + + } + + union( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + } + + translate( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + } + + equals( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + } + + } + + const _startP = /*@__PURE__*/ new Vector3(); + const _startEnd = /*@__PURE__*/ new Vector3(); + + class Line3 { + + constructor( start = new Vector3(), end = new Vector3() ) { + + this.start = start; + this.end = end; + + } + + set( start, end ) { + + this.start.copy( start ); + this.end.copy( end ); + + return this; + + } + + copy( line ) { + + this.start.copy( line.start ); + this.end.copy( line.end ); + + return this; + + } + + getCenter( target ) { + + return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + + } + + delta( target ) { + + return target.subVectors( this.end, this.start ); + + } + + distanceSq() { + + return this.start.distanceToSquared( this.end ); + + } + + distance() { + + return this.start.distanceTo( this.end ); + + } + + at( t, target ) { + + return this.delta( target ).multiplyScalar( t ).add( this.start ); + + } + + closestPointToPointParameter( point, clampToLine ) { + + _startP.subVectors( point, this.start ); + _startEnd.subVectors( this.end, this.start ); + + const startEnd2 = _startEnd.dot( _startEnd ); + const startEnd_startP = _startEnd.dot( _startP ); + + let t = startEnd_startP / startEnd2; + + if ( clampToLine ) { + + t = clamp( t, 0, 1 ); + + } + + return t; + + } + + closestPointToPoint( point, clampToLine, target ) { + + const t = this.closestPointToPointParameter( point, clampToLine ); + + return this.delta( target ).multiplyScalar( t ).add( this.start ); + + } + + applyMatrix4( matrix ) { + + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); + + return this; + + } + + equals( line ) { + + return line.start.equals( this.start ) && line.end.equals( this.end ); + + } + + clone() { + + return new this.constructor().copy( this ); + + } + + } + + const _vector$3 = /*@__PURE__*/ new Vector3(); + + class SpotLightHelper extends Object3D { + + constructor( light, color ) { + + super(); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + this.color = color; + + const geometry = new BufferGeometry(); + + const positions = [ + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 1, + 0, 0, 0, - 1, 0, 1, + 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, - 1, 1 + ]; + + for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { + + const p1 = ( i / l ) * Math.PI * 2; + const p2 = ( j / l ) * Math.PI * 2; + + positions.push( + Math.cos( p1 ), Math.sin( p1 ), 1, + Math.cos( p2 ), Math.sin( p2 ), 1 + ); + + } + + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + + const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); + + this.cone = new LineSegments( geometry, material ); + this.add( this.cone ); + + this.update(); + + } + + dispose() { + + this.cone.geometry.dispose(); + this.cone.material.dispose(); + + } + + update() { + + this.light.updateMatrixWorld(); + + const coneLength = this.light.distance ? this.light.distance : 1000; + const coneWidth = coneLength * Math.tan( this.light.angle ); + + this.cone.scale.set( coneWidth, coneWidth, coneLength ); + + _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); + + this.cone.lookAt( _vector$3 ); + + if ( this.color !== undefined ) { + + this.cone.material.color.set( this.color ); + + } else { + + this.cone.material.color.copy( this.light.color ); + + } + + } + + } + + const _vector$2 = /*@__PURE__*/ new Vector3(); + const _boneMatrix = /*@__PURE__*/ new Matrix4(); + const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); + + + class SkeletonHelper extends LineSegments { + + constructor( object ) { + + const bones = getBoneList( object ); + + const geometry = new BufferGeometry(); + + const vertices = []; + const colors = []; + + const color1 = new Color( 0, 0, 1 ); + const color2 = new Color( 0, 1, 0 ); + + for ( let i = 0; i < bones.length; i ++ ) { + + const bone = bones[ i ]; + + if ( bone.parent && bone.parent.isBone ) { + + vertices.push( 0, 0, 0 ); + vertices.push( 0, 0, 0 ); + colors.push( color1.r, color1.g, color1.b ); + colors.push( color2.r, color2.g, color2.b ); + + } + + } + + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); + + super( geometry, material ); + + this.isSkeletonHelper = true; + + this.type = 'SkeletonHelper'; + + this.root = object; + this.bones = bones; + + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; + + } + + updateMatrixWorld( force ) { + + const bones = this.bones; + + const geometry = this.geometry; + const position = geometry.getAttribute( 'position' ); + + _matrixWorldInv.copy( this.root.matrixWorld ).invert(); + + for ( let i = 0, j = 0; i < bones.length; i ++ ) { + + const bone = bones[ i ]; + + if ( bone.parent && bone.parent.isBone ) { + + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); + _vector$2.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); + + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); + _vector$2.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); + + j += 2; + + } + + } + + geometry.getAttribute( 'position' ).needsUpdate = true; + + super.updateMatrixWorld( force ); + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + } + + + function getBoneList( object ) { + + const boneList = []; + + if ( object.isBone === true ) { + + boneList.push( object ); + + } + + for ( let i = 0; i < object.children.length; i ++ ) { + + boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); + + } + + return boneList; + + } + + class PointLightHelper extends Mesh { + + constructor( light, sphereSize, color ) { + + const geometry = new SphereGeometry( sphereSize, 4, 2 ); + const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + + super( geometry, material ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.color = color; + + this.type = 'PointLightHelper'; + + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; + + this.update(); + + + /* + // TODO: delete this comment? + const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + + const d = light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.scale.set( d, d, d ); + + } + + this.add( this.lightDistance ); + */ + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + update() { + + if ( this.color !== undefined ) { + + this.material.color.set( this.color ); + + } else { + + this.material.color.copy( this.light.color ); + + } + + /* + const d = this.light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); + + } + */ + + } + + } + + const _vector$1 = /*@__PURE__*/ new Vector3(); + const _color1 = /*@__PURE__*/ new Color(); + const _color2 = /*@__PURE__*/ new Color(); + + class HemisphereLightHelper extends Object3D { + + constructor( light, size, color ) { + + super(); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + this.color = color; + + const geometry = new OctahedronGeometry( size ); + geometry.rotateY( Math.PI * 0.5 ); + + this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + if ( this.color === undefined ) this.material.vertexColors = true; + + const position = geometry.getAttribute( 'position' ); + const colors = new Float32Array( position.count * 3 ); + + geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); + + this.add( new Mesh( geometry, this.material ) ); + + this.update(); + + } + + dispose() { + + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); + + } + + update() { + + const mesh = this.children[ 0 ]; + + if ( this.color !== undefined ) { + + this.material.color.set( this.color ); + + } else { + + const colors = mesh.geometry.getAttribute( 'color' ); + + _color1.copy( this.light.color ); + _color2.copy( this.light.groundColor ); + + for ( let i = 0, l = colors.count; i < l; i ++ ) { + + const color = ( i < ( l / 2 ) ) ? _color1 : _color2; + + colors.setXYZ( i, color.r, color.g, color.b ); + + } + + colors.needsUpdate = true; + + } + + mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + + } + + } + + class GridHelper extends LineSegments { + + constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { + + color1 = new Color( color1 ); + color2 = new Color( color2 ); + + const center = divisions / 2; + const step = size / divisions; + const halfSize = size / 2; + + const vertices = [], colors = []; + + for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { + + vertices.push( - halfSize, 0, k, halfSize, 0, k ); + vertices.push( k, 0, - halfSize, k, 0, halfSize ); + + const color = i === center ? color1 : color2; + + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + + } + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + + super( geometry, material ); + + this.type = 'GridHelper'; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + } + + class PolarGridHelper extends LineSegments { + + constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { + + color1 = new Color( color1 ); + color2 = new Color( color2 ); + + const vertices = []; + const colors = []; + + // create the sectors + + if ( sectors > 1 ) { + + for ( let i = 0; i < sectors; i ++ ) { + + const v = ( i / sectors ) * ( Math.PI * 2 ); + + const x = Math.sin( v ) * radius; + const z = Math.cos( v ) * radius; + + vertices.push( 0, 0, 0 ); + vertices.push( x, 0, z ); + + const color = ( i & 1 ) ? color1 : color2; + + colors.push( color.r, color.g, color.b ); + colors.push( color.r, color.g, color.b ); + + } + + } + + // create the rings + + for ( let i = 0; i < rings; i ++ ) { + + const color = ( i & 1 ) ? color1 : color2; + + const r = radius - ( radius / rings * i ); + + for ( let j = 0; j < divisions; j ++ ) { + + // first vertex + + let v = ( j / divisions ) * ( Math.PI * 2 ); + + let x = Math.sin( v ) * r; + let z = Math.cos( v ) * r; + + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); + + // second vertex + + v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); + + x = Math.sin( v ) * r; + z = Math.cos( v ) * r; + + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); + + } + + } + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + + super( geometry, material ); + + this.type = 'PolarGridHelper'; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + } + + const _v1 = /*@__PURE__*/ new Vector3(); + const _v2 = /*@__PURE__*/ new Vector3(); + const _v3 = /*@__PURE__*/ new Vector3(); + + class DirectionalLightHelper extends Object3D { + + constructor( light, size, color ) { + + super(); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; + + this.color = color; + + if ( size === undefined ) size = 1; + + let geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ + - size, size, 0, + size, size, 0, + size, - size, 0, + - size, - size, 0, + - size, size, 0 + ], 3 ) ); + + const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); + + this.lightPlane = new Line( geometry, material ); + this.add( this.lightPlane ); + + geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); + + this.targetLine = new Line( geometry, material ); + this.add( this.targetLine ); + + this.update(); + + } + + dispose() { + + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); + + } + + update() { + + _v1.setFromMatrixPosition( this.light.matrixWorld ); + _v2.setFromMatrixPosition( this.light.target.matrixWorld ); + _v3.subVectors( _v2, _v1 ); + + this.lightPlane.lookAt( _v2 ); + + if ( this.color !== undefined ) { + + this.lightPlane.material.color.set( this.color ); + this.targetLine.material.color.set( this.color ); + + } else { + + this.lightPlane.material.color.copy( this.light.color ); + this.targetLine.material.color.copy( this.light.color ); + + } + + this.targetLine.lookAt( _v2 ); + this.targetLine.scale.z = _v3.length(); + + } + + } + + const _vector = /*@__PURE__*/ new Vector3(); + const _camera = /*@__PURE__*/ new Camera(); + + /** + * - shows frustum, line of sight and up of the camera + * - suitable for fast updates + * - based on frustum visualization in lightgl.js shadowmap example + * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html + */ + + class CameraHelper extends LineSegments { + + constructor( camera ) { + + const geometry = new BufferGeometry(); + const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); + + const vertices = []; + const colors = []; + + const pointMap = {}; + + // near + + addLine( 'n1', 'n2' ); + addLine( 'n2', 'n4' ); + addLine( 'n4', 'n3' ); + addLine( 'n3', 'n1' ); + + // far + + addLine( 'f1', 'f2' ); + addLine( 'f2', 'f4' ); + addLine( 'f4', 'f3' ); + addLine( 'f3', 'f1' ); + + // sides + + addLine( 'n1', 'f1' ); + addLine( 'n2', 'f2' ); + addLine( 'n3', 'f3' ); + addLine( 'n4', 'f4' ); + + // cone + + addLine( 'p', 'n1' ); + addLine( 'p', 'n2' ); + addLine( 'p', 'n3' ); + addLine( 'p', 'n4' ); + + // up + + addLine( 'u1', 'u2' ); + addLine( 'u2', 'u3' ); + addLine( 'u3', 'u1' ); + + // target + + addLine( 'c', 't' ); + addLine( 'p', 'c' ); + + // cross + + addLine( 'cn1', 'cn2' ); + addLine( 'cn3', 'cn4' ); + + addLine( 'cf1', 'cf2' ); + addLine( 'cf3', 'cf4' ); + + function addLine( a, b ) { + + addPoint( a ); + addPoint( b ); + + } + + function addPoint( id ) { + + vertices.push( 0, 0, 0 ); + colors.push( 0, 0, 0 ); + + if ( pointMap[ id ] === undefined ) { + + pointMap[ id ] = []; + + } + + pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); + + } + + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + super( geometry, material ); + + this.type = 'CameraHelper'; + + this.camera = camera; + if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); + + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; + + this.pointMap = pointMap; + + this.update(); + + // colors + + const colorFrustum = new Color( 0xffaa00 ); + const colorCone = new Color( 0xff0000 ); + const colorUp = new Color( 0x00aaff ); + const colorTarget = new Color( 0xffffff ); + const colorCross = new Color( 0x333333 ); + + this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); + + } + + setColors( frustum, cone, up, target, cross ) { + + const geometry = this.geometry; + + const colorAttribute = geometry.getAttribute( 'color' ); + + // near + + colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 + colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 + colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 + colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 + + // far + + colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 + colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 + colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 + colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 + + // sides + + colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 + colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 + colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 + colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 + + // cone + + colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 + colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 + colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 + colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 + + // up + + colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 + colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 + colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 + + // target + + colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t + colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c + + // cross + + colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 + colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 + + colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 + colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 + + colorAttribute.needsUpdate = true; + + } + + update() { + + const geometry = this.geometry; + const pointMap = this.pointMap; + + const w = 1, h = 1; + + // we need just camera projection matrix inverse + // world matrix must be identity + + _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); + + // center / target + + setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); + setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); + + // near + + setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); + setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); + setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); + setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); + + // far + + setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 ); + setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 ); + setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 ); + setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 ); + + // up + + setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); + setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); + setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); + + // cross + + setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 ); + setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 ); + setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); + setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); + + setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); + setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); + setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); + setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); + + geometry.getAttribute( 'position' ).needsUpdate = true; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + } + + + function setPoint( point, pointMap, geometry, camera, x, y, z ) { + + _vector.set( x, y, z ).unproject( camera ); + + const points = pointMap[ point ]; + + if ( points !== undefined ) { + + const position = geometry.getAttribute( 'position' ); + + for ( let i = 0, l = points.length; i < l; i ++ ) { + + position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); + + } + + } + + } + + const _box = /*@__PURE__*/ new Box3(); + + class BoxHelper extends LineSegments { + + constructor( object, color = 0xffff00 ) { + + const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + const positions = new Float32Array( 8 * 3 ); + + const geometry = new BufferGeometry(); + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); + + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + + this.object = object; + this.type = 'BoxHelper'; + + this.matrixAutoUpdate = false; + + this.update(); + + } + + update( object ) { + + if ( object !== undefined ) { + + console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); + + } + + if ( this.object !== undefined ) { + + _box.setFromObject( this.object ); + + } + + if ( _box.isEmpty() ) return; + + const min = _box.min; + const max = _box.max; + + /* + 5____4 + 1/___0/| + | 6__|_7 + 2/___3/ + + 0: max.x, max.y, max.z + 1: min.x, max.y, max.z + 2: min.x, min.y, max.z + 3: max.x, min.y, max.z + 4: max.x, max.y, min.z + 5: min.x, max.y, min.z + 6: min.x, min.y, min.z + 7: max.x, min.y, min.z + */ + + const position = this.geometry.attributes.position; + const array = position.array; + + array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; + array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; + array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; + array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; + array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; + array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; + array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; + array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; + + position.needsUpdate = true; + + this.geometry.computeBoundingSphere(); + + } + + setFromObject( object ) { + + this.object = object; + this.update(); + + return this; + + } + + copy( source, recursive ) { + + super.copy( source, recursive ); + + this.object = source.object; + + return this; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + } + + class Box3Helper extends LineSegments { + + constructor( box, color = 0xffff00 ) { + + const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + + const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; + + const geometry = new BufferGeometry(); + + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + + this.box = box; + + this.type = 'Box3Helper'; + + this.geometry.computeBoundingSphere(); + + } + + updateMatrixWorld( force ) { + + const box = this.box; + + if ( box.isEmpty() ) return; + + box.getCenter( this.position ); + + box.getSize( this.scale ); + + this.scale.multiplyScalar( 0.5 ); + + super.updateMatrixWorld( force ); + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + } + + class PlaneHelper extends Line { + + constructor( plane, size = 1, hex = 0xffff00 ) { + + const color = hex; + + const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + geometry.computeBoundingSphere(); + + super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + + this.type = 'PlaneHelper'; + + this.plane = plane; + + this.size = size; + + const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; + + const geometry2 = new BufferGeometry(); + geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); + geometry2.computeBoundingSphere(); + + this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); + + } + + updateMatrixWorld( force ) { + + this.position.set( 0, 0, 0 ); + + this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); + + this.lookAt( this.plane.normal ); + + this.translateZ( - this.plane.constant ); + + super.updateMatrixWorld( force ); + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); + + } + + } + + const _axis = /*@__PURE__*/ new Vector3(); + let _lineGeometry, _coneGeometry; + + class ArrowHelper extends Object3D { + + // dir is assumed to be normalized + + constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + + super(); + + this.type = 'ArrowHelper'; + + if ( _lineGeometry === undefined ) { + + _lineGeometry = new BufferGeometry(); + _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + + _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); + _coneGeometry.translate( 0, - 0.5, 0 ); + + } + + this.position.copy( origin ); + + this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); + + this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); + + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); + + } + + setDirection( dir ) { + + // dir is assumed to be normalized + + if ( dir.y > 0.99999 ) { + + this.quaternion.set( 0, 0, 0, 1 ); + + } else if ( dir.y < - 0.99999 ) { + + this.quaternion.set( 1, 0, 0, 0 ); + + } else { + + _axis.set( dir.z, 0, - dir.x ).normalize(); + + const radians = Math.acos( dir.y ); + + this.quaternion.setFromAxisAngle( _axis, radians ); + + } + + } + + setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { + + this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 + this.line.updateMatrix(); + + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); + + } + + setColor( color ) { + + this.line.material.color.set( color ); + this.cone.material.color.set( color ); + + } + + copy( source ) { + + super.copy( source, false ); + + this.line.copy( source.line ); + this.cone.copy( source.cone ); + + return this; + + } + + dispose() { + + this.line.geometry.dispose(); + this.line.material.dispose(); + this.cone.geometry.dispose(); + this.cone.material.dispose(); + + } + + } + + class AxesHelper extends LineSegments { + + constructor( size = 1 ) { + + const vertices = [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ]; + + const colors = [ + 1, 0, 0, 1, 0.6, 0, + 0, 1, 0, 0.6, 1, 0, + 0, 0, 1, 0, 0.6, 1 + ]; + + const geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + + super( geometry, material ); + + this.type = 'AxesHelper'; + + } + + setColors( xAxisColor, yAxisColor, zAxisColor ) { + + const color = new Color(); + const array = this.geometry.attributes.color.array; + + color.set( xAxisColor ); + color.toArray( array, 0 ); + color.toArray( array, 3 ); + + color.set( yAxisColor ); + color.toArray( array, 6 ); + color.toArray( array, 9 ); + + color.set( zAxisColor ); + color.toArray( array, 12 ); + color.toArray( array, 15 ); + + this.geometry.attributes.color.needsUpdate = true; + + return this; + + } + + dispose() { + + this.geometry.dispose(); + this.material.dispose(); + + } + + } + + class ShapePath { + + constructor() { + + this.type = 'ShapePath'; + + this.color = new Color(); + + this.subPaths = []; + this.currentPath = null; + + } + + moveTo( x, y ) { + + this.currentPath = new Path(); + this.subPaths.push( this.currentPath ); + this.currentPath.moveTo( x, y ); + + return this; + + } + + lineTo( x, y ) { + + this.currentPath.lineTo( x, y ); + + return this; + + } + + quadraticCurveTo( aCPx, aCPy, aX, aY ) { + + this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + + return this; + + } + + bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + + this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); + + return this; + + } + + splineThru( pts ) { + + this.currentPath.splineThru( pts ); + + return this; + + } + + toShapes( isCCW ) { + + function toShapesNoHoles( inSubpaths ) { + + const shapes = []; + + for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { + + const tmpPath = inSubpaths[ i ]; + + const tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + + shapes.push( tmpShape ); + + } + + return shapes; + + } + + function isPointInsidePolygon( inPt, inPolygon ) { + + const polyLen = inPolygon.length; + + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + let inside = false; + for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { + + let edgeLowPt = inPolygon[ p ]; + let edgeHighPt = inPolygon[ q ]; + + let edgeDx = edgeHighPt.x - edgeLowPt.x; + let edgeDy = edgeHighPt.y - edgeLowPt.y; + + if ( Math.abs( edgeDy ) > Number.EPSILON ) { + + // not parallel + if ( edgeDy < 0 ) { + + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + + } + + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + + if ( inPt.y === edgeLowPt.y ) { + + if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! + + } else { + + const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); + if ( perpEdge === 0 ) return true; // inPt is on contour ? + if ( perpEdge < 0 ) continue; + inside = ! inside; // true intersection left of inPt + + } + + } else { + + // parallel or collinear + if ( inPt.y !== edgeLowPt.y ) continue; // parallel + // edge lies on the same horizontal line as inPt + if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || + ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! + // continue; + + } + + } + + return inside; + + } + + const isClockWise = ShapeUtils.isClockWise; + + const subPaths = this.subPaths; + if ( subPaths.length === 0 ) return []; + + let solid, tmpPath, tmpShape; + const shapes = []; + + if ( subPaths.length === 1 ) { + + tmpPath = subPaths[ 0 ]; + tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; + + } + + let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; + + // console.log("Holes first", holesFirst); + + const betterShapeHoles = []; + const newShapes = []; + let newShapeHoles = []; + let mainIdx = 0; + let tmpPoints; + + newShapes[ mainIdx ] = undefined; + newShapeHoles[ mainIdx ] = []; + + for ( let i = 0, l = subPaths.length; i < l; i ++ ) { + + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; + + if ( solid ) { + + if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; + + newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; + newShapes[ mainIdx ].s.curves = tmpPath.curves; + + if ( holesFirst ) mainIdx ++; + newShapeHoles[ mainIdx ] = []; + + //console.log('cw', i); + + } else { + + newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); + + //console.log('ccw', i); + + } + + } + + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); + + + if ( newShapes.length > 1 ) { + + let ambiguous = false; + let toChange = 0; + + for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + + betterShapeHoles[ sIdx ] = []; + + } + + for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + + const sho = newShapeHoles[ sIdx ]; + + for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { + + const ho = sho[ hIdx ]; + let hole_unassigned = true; + + for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + + if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { + + if ( sIdx !== s2Idx ) toChange ++; + + if ( hole_unassigned ) { + + hole_unassigned = false; + betterShapeHoles[ s2Idx ].push( ho ); + + } else { + + ambiguous = true; + + } + + } + + } + + if ( hole_unassigned ) { + + betterShapeHoles[ sIdx ].push( ho ); + + } + + } + + } + + if ( toChange > 0 && ambiguous === false ) { + + newShapeHoles = betterShapeHoles; + + } + + } + + let tmpHoles; + + for ( let i = 0, il = newShapes.length; i < il; i ++ ) { + + tmpShape = newShapes[ i ].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[ i ]; + + for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + + tmpShape.holes.push( tmpHoles[ j ].h ); + + } + + } + + //console.log("shape", shapes); + + return shapes; + + } + + } + + // Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf + + const _tables = /*@__PURE__*/ _generateTables(); + + function _generateTables() { + + // float32 to float16 helpers + + const buffer = new ArrayBuffer( 4 ); + const floatView = new Float32Array( buffer ); + const uint32View = new Uint32Array( buffer ); + + const baseTable = new Uint32Array( 512 ); + const shiftTable = new Uint32Array( 512 ); + + for ( let i = 0; i < 256; ++ i ) { + + const e = i - 127; + + // very small number (0, -0) + + if ( e < - 27 ) { + + baseTable[ i ] = 0x0000; + baseTable[ i | 0x100 ] = 0x8000; + shiftTable[ i ] = 24; + shiftTable[ i | 0x100 ] = 24; + + // small number (denorm) + + } else if ( e < - 14 ) { + + baseTable[ i ] = 0x0400 >> ( - e - 14 ); + baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000; + shiftTable[ i ] = - e - 1; + shiftTable[ i | 0x100 ] = - e - 1; + + // normal number + + } else if ( e <= 15 ) { + + baseTable[ i ] = ( e + 15 ) << 10; + baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000; + shiftTable[ i ] = 13; + shiftTable[ i | 0x100 ] = 13; + + // large number (Infinity, -Infinity) + + } else if ( e < 128 ) { + + baseTable[ i ] = 0x7c00; + baseTable[ i | 0x100 ] = 0xfc00; + shiftTable[ i ] = 24; + shiftTable[ i | 0x100 ] = 24; + + // stay (NaN, Infinity, -Infinity) + + } else { + + baseTable[ i ] = 0x7c00; + baseTable[ i | 0x100 ] = 0xfc00; + shiftTable[ i ] = 13; + shiftTable[ i | 0x100 ] = 13; + + } + + } + + // float16 to float32 helpers + + const mantissaTable = new Uint32Array( 2048 ); + const exponentTable = new Uint32Array( 64 ); + const offsetTable = new Uint32Array( 64 ); + + for ( let i = 1; i < 1024; ++ i ) { + + let m = i << 13; // zero pad mantissa bits + let e = 0; // zero exponent + + // normalized + while ( ( m & 0x00800000 ) === 0 ) { + + m <<= 1; + e -= 0x00800000; // decrement exponent + + } + + m &= ~ 0x00800000; // clear leading 1 bit + e += 0x38800000; // adjust bias + + mantissaTable[ i ] = m | e; + + } + + for ( let i = 1024; i < 2048; ++ i ) { + + mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 ); + + } + + for ( let i = 1; i < 31; ++ i ) { + + exponentTable[ i ] = i << 23; + + } + + exponentTable[ 31 ] = 0x47800000; + exponentTable[ 32 ] = 0x80000000; + + for ( let i = 33; i < 63; ++ i ) { + + exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 ); + + } + + exponentTable[ 63 ] = 0xc7800000; + + for ( let i = 1; i < 64; ++ i ) { + + if ( i !== 32 ) { + + offsetTable[ i ] = 1024; + + } + + } + + return { + floatView: floatView, + uint32View: uint32View, + baseTable: baseTable, + shiftTable: shiftTable, + mantissaTable: mantissaTable, + exponentTable: exponentTable, + offsetTable: offsetTable + }; + + } + + // float32 to float16 + + function toHalfFloat( val ) { + + if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); + + val = clamp( val, - 65504, 65504 ); + + _tables.floatView[ 0 ] = val; + const f = _tables.uint32View[ 0 ]; + const e = ( f >> 23 ) & 0x1ff; + return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); + + } + + // float16 to float32 + + function fromHalfFloat( val ) { + + const m = val >> 10; + _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; + return _tables.floatView[ 0 ]; + + } + + var DataUtils = /*#__PURE__*/Object.freeze({ + __proto__: null, + toHalfFloat: toHalfFloat, + fromHalfFloat: fromHalfFloat + }); + + // r134, d65e0af06644fe5a84a6fc0e372f4318f95a04c0 + + function ImmediateRenderObject() { + + console.error( 'THREE.ImmediateRenderObject has been removed.' ); + + } + + // r138, 48b05d3500acc084df50be9b4c90781ad9b8cb17 + + class WebGLMultisampleRenderTarget extends WebGLRenderTarget { + + constructor( width, height, options ) { + + console.error( 'THREE.WebGLMultisampleRenderTarget has been removed. Use a normal render target and set the "samples" property to greater 0 to enable multisampling.' ); + super( width, height, options ); + this.samples = 4; + + } + + } + + // r138, f9cd9cab03b7b64244e304900a3a2eeaa3a588ce + + class DataTexture2DArray extends DataArrayTexture { + + constructor( data, width, height, depth ) { + + console.warn( 'THREE.DataTexture2DArray has been renamed to DataArrayTexture.' ); + super( data, width, height, depth ); + + } + + } + + // r138, f9cd9cab03b7b64244e304900a3a2eeaa3a588ce + + class DataTexture3D extends Data3DTexture { + + constructor( data, width, height, depth ) { + + console.warn( 'THREE.DataTexture3D has been renamed to Data3DTexture.' ); + super( data, width, height, depth ); + + } + + } + + // r144 + + class BoxBufferGeometry extends BoxGeometry { + + constructor( width, height, depth, widthSegments, heightSegments, depthSegments ) { + + console.warn( 'THREE.BoxBufferGeometry has been renamed to THREE.BoxGeometry.' ); + super( width, height, depth, widthSegments, heightSegments, depthSegments ); + + + } + + } + + // r144 + + class CapsuleBufferGeometry extends CapsuleGeometry { + + constructor( radius, length, capSegments, radialSegments ) { + + console.warn( 'THREE.CapsuleBufferGeometry has been renamed to THREE.CapsuleGeometry.' ); + super( radius, length, capSegments, radialSegments ); + + } + + } + + // r144 + + class CircleBufferGeometry extends CircleGeometry { + + constructor( radius, segments, thetaStart, thetaLength ) { + + console.warn( 'THREE.CircleBufferGeometry has been renamed to THREE.CircleGeometry.' ); + super( radius, segments, thetaStart, thetaLength ); + + } + + } + + // r144 + + class ConeBufferGeometry extends ConeGeometry { + + constructor( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + + console.warn( 'THREE.ConeBufferGeometry has been renamed to THREE.ConeGeometry.' ); + super( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + + } + + } + + // r144 + + class CylinderBufferGeometry extends CylinderGeometry { + + constructor( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + + console.warn( 'THREE.CylinderBufferGeometry has been renamed to THREE.CylinderGeometry.' ); + super( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + + } + + } + + // r144 + + class DodecahedronBufferGeometry extends DodecahedronGeometry { + + constructor( radius, detail ) { + + console.warn( 'THREE.DodecahedronBufferGeometry has been renamed to THREE.DodecahedronGeometry.' ); + super( radius, detail ); + + } + + } + + // r144 + + class ExtrudeBufferGeometry extends ExtrudeGeometry { + + constructor( shapes, options ) { + + console.warn( 'THREE.ExtrudeBufferGeometry has been renamed to THREE.ExtrudeGeometry.' ); + super( shapes, options ); + + } + + } + + // r144 + + class IcosahedronBufferGeometry extends IcosahedronGeometry { + + constructor( radius, detail ) { + + console.warn( 'THREE.IcosahedronBufferGeometry has been renamed to THREE.IcosahedronGeometry.' ); + super( radius, detail ); + + } + + } + + // r144 + + class LatheBufferGeometry extends LatheGeometry { + + constructor( points, segments, phiStart, phiLength ) { + + console.warn( 'THREE.LatheBufferGeometry has been renamed to THREE.LatheGeometry.' ); + super( points, segments, phiStart, phiLength ); + + } + + } + + // r144 + + class OctahedronBufferGeometry extends OctahedronGeometry { + + constructor( radius, detail ) { + + console.warn( 'THREE.OctahedronBufferGeometry has been renamed to THREE.OctahedronGeometry.' ); + super( radius, detail ); + + } + + } + + // r144 + + class PlaneBufferGeometry extends PlaneGeometry { + + constructor( width, height, widthSegments, heightSegments ) { + + console.warn( 'THREE.PlaneBufferGeometry has been renamed to THREE.PlaneGeometry.' ); + super( width, height, widthSegments, heightSegments ); + + } + + } + + // r144 + + class PolyhedronBufferGeometry extends PolyhedronGeometry { + + constructor( vertices, indices, radius, detail ) { + + console.warn( 'THREE.PolyhedronBufferGeometry has been renamed to THREE.PolyhedronGeometry.' ); + super( vertices, indices, radius, detail ); + + } + + } + + // r144 + + class RingBufferGeometry extends RingGeometry { + + constructor( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + + console.warn( 'THREE.RingBufferGeometry has been renamed to THREE.RingGeometry.' ); + super( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ); + + } + + } + + // r144 + + class ShapeBufferGeometry extends ShapeGeometry { + + constructor( shapes, curveSegments ) { + + console.warn( 'THREE.ShapeBufferGeometry has been renamed to THREE.ShapeGeometry.' ); + super( shapes, curveSegments ); + + } + + } + + // r144 + + class SphereBufferGeometry extends SphereGeometry { + + constructor( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + + console.warn( 'THREE.SphereBufferGeometry has been renamed to THREE.SphereGeometry.' ); + super( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ); + + } + + } + + // r144 + + class TetrahedronBufferGeometry extends TetrahedronGeometry { + + constructor( radius, detail ) { + + console.warn( 'THREE.TetrahedronBufferGeometry has been renamed to THREE.TetrahedronGeometry.' ); + super( radius, detail ); + + } + + } + + // r144 + + class TorusBufferGeometry extends TorusGeometry { + + constructor( radius, tube, radialSegments, tubularSegments, arc ) { + + console.warn( 'THREE.TorusBufferGeometry has been renamed to THREE.TorusGeometry.' ); + super( radius, tube, radialSegments, tubularSegments, arc ); + + } + + } + + // r144 + + class TorusKnotBufferGeometry extends TorusKnotGeometry { + + constructor( radius, tube, tubularSegments, radialSegments, p, q ) { + + console.warn( 'THREE.TorusKnotBufferGeometry has been renamed to THREE.TorusKnotGeometry.' ); + super( radius, tube, tubularSegments, radialSegments, p, q ); + + } + + } + + // r144 + + class TubeBufferGeometry extends TubeGeometry { + + constructor( path, tubularSegments, radius, radialSegments, closed ) { + + console.warn( 'THREE.TubeBufferGeometry has been renamed to THREE.TubeGeometry.' ); + super( path, tubularSegments, radius, radialSegments, closed ); + + } + + } + + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { + revision: REVISION, + } } ) ); + + } + + if ( typeof window !== 'undefined' ) { + + if ( window.__THREE__ ) { + + console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); + + } else { + + window.__THREE__ = REVISION; + + } + + } + + var THREE = /*#__PURE__*/Object.freeze({ + __proto__: null, + ACESFilmicToneMapping: ACESFilmicToneMapping, + AddEquation: AddEquation, + AddOperation: AddOperation, + AdditiveAnimationBlendMode: AdditiveAnimationBlendMode, + AdditiveBlending: AdditiveBlending, + AlphaFormat: AlphaFormat, + AlwaysDepth: AlwaysDepth, + AlwaysStencilFunc: AlwaysStencilFunc, + AmbientLight: AmbientLight, + AmbientLightProbe: AmbientLightProbe, + AnimationClip: AnimationClip, + AnimationLoader: AnimationLoader, + AnimationMixer: AnimationMixer, + AnimationObjectGroup: AnimationObjectGroup, + AnimationUtils: AnimationUtils, + ArcCurve: ArcCurve, + ArrayCamera: ArrayCamera, + ArrowHelper: ArrowHelper, + Audio: Audio, + AudioAnalyser: AudioAnalyser, + AudioContext: AudioContext, + AudioListener: AudioListener, + AudioLoader: AudioLoader, + AxesHelper: AxesHelper, + BackSide: BackSide, + BasicDepthPacking: BasicDepthPacking, + BasicShadowMap: BasicShadowMap, + Bone: Bone, + BooleanKeyframeTrack: BooleanKeyframeTrack, + Box2: Box2, + Box3: Box3, + Box3Helper: Box3Helper, + BoxBufferGeometry: BoxBufferGeometry, + BoxGeometry: BoxGeometry, + BoxHelper: BoxHelper, + BufferAttribute: BufferAttribute, + BufferGeometry: BufferGeometry, + BufferGeometryLoader: BufferGeometryLoader, + ByteType: ByteType, + Cache: Cache, + Camera: Camera, + CameraHelper: CameraHelper, + CanvasTexture: CanvasTexture, + CapsuleBufferGeometry: CapsuleBufferGeometry, + CapsuleGeometry: CapsuleGeometry, + CatmullRomCurve3: CatmullRomCurve3, + CineonToneMapping: CineonToneMapping, + CircleBufferGeometry: CircleBufferGeometry, + CircleGeometry: CircleGeometry, + ClampToEdgeWrapping: ClampToEdgeWrapping, + Clock: Clock, + Color: Color, + ColorKeyframeTrack: ColorKeyframeTrack, + ColorManagement: ColorManagement, + CompressedTexture: CompressedTexture, + CompressedTextureLoader: CompressedTextureLoader, + ConeBufferGeometry: ConeBufferGeometry, + ConeGeometry: ConeGeometry, + CubeCamera: CubeCamera, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + CubeTexture: CubeTexture, + CubeTextureLoader: CubeTextureLoader, + CubeUVReflectionMapping: CubeUVReflectionMapping, + CubicBezierCurve: CubicBezierCurve, + CubicBezierCurve3: CubicBezierCurve3, + CubicInterpolant: CubicInterpolant, + CullFaceBack: CullFaceBack, + CullFaceFront: CullFaceFront, + CullFaceFrontBack: CullFaceFrontBack, + CullFaceNone: CullFaceNone, + Curve: Curve, + CurvePath: CurvePath, + CustomBlending: CustomBlending, + CustomToneMapping: CustomToneMapping, + CylinderBufferGeometry: CylinderBufferGeometry, + CylinderGeometry: CylinderGeometry, + Cylindrical: Cylindrical, + Data3DTexture: Data3DTexture, + DataArrayTexture: DataArrayTexture, + DataTexture: DataTexture, + DataTexture2DArray: DataTexture2DArray, + DataTexture3D: DataTexture3D, + DataTextureLoader: DataTextureLoader, + DataUtils: DataUtils, + DecrementStencilOp: DecrementStencilOp, + DecrementWrapStencilOp: DecrementWrapStencilOp, + DefaultLoadingManager: DefaultLoadingManager, + DepthFormat: DepthFormat, + DepthStencilFormat: DepthStencilFormat, + DepthTexture: DepthTexture, + DirectionalLight: DirectionalLight, + DirectionalLightHelper: DirectionalLightHelper, + DiscreteInterpolant: DiscreteInterpolant, + DodecahedronBufferGeometry: DodecahedronBufferGeometry, + DodecahedronGeometry: DodecahedronGeometry, + DoubleSide: DoubleSide, + DstAlphaFactor: DstAlphaFactor, + DstColorFactor: DstColorFactor, + DynamicCopyUsage: DynamicCopyUsage, + DynamicDrawUsage: DynamicDrawUsage, + DynamicReadUsage: DynamicReadUsage, + EdgesGeometry: EdgesGeometry, + EllipseCurve: EllipseCurve, + EqualDepth: EqualDepth, + EqualStencilFunc: EqualStencilFunc, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + Euler: Euler, + EventDispatcher: EventDispatcher, + ExtrudeBufferGeometry: ExtrudeBufferGeometry, + ExtrudeGeometry: ExtrudeGeometry, + FileLoader: FileLoader, + Float16BufferAttribute: Float16BufferAttribute, + Float32BufferAttribute: Float32BufferAttribute, + Float64BufferAttribute: Float64BufferAttribute, + FloatType: FloatType, + Fog: Fog, + FogExp2: FogExp2, + FramebufferTexture: FramebufferTexture, + FrontSide: FrontSide, + Frustum: Frustum, + GLBufferAttribute: GLBufferAttribute, + GLSL1: GLSL1, + GLSL3: GLSL3, + GreaterDepth: GreaterDepth, + GreaterEqualDepth: GreaterEqualDepth, + GreaterEqualStencilFunc: GreaterEqualStencilFunc, + GreaterStencilFunc: GreaterStencilFunc, + GridHelper: GridHelper, + Group: Group, + HalfFloatType: HalfFloatType, + HemisphereLight: HemisphereLight, + HemisphereLightHelper: HemisphereLightHelper, + HemisphereLightProbe: HemisphereLightProbe, + IcosahedronBufferGeometry: IcosahedronBufferGeometry, + IcosahedronGeometry: IcosahedronGeometry, + ImageBitmapLoader: ImageBitmapLoader, + ImageLoader: ImageLoader, + ImageUtils: ImageUtils, + ImmediateRenderObject: ImmediateRenderObject, + IncrementStencilOp: IncrementStencilOp, + IncrementWrapStencilOp: IncrementWrapStencilOp, + InstancedBufferAttribute: InstancedBufferAttribute, + InstancedBufferGeometry: InstancedBufferGeometry, + InstancedInterleavedBuffer: InstancedInterleavedBuffer, + InstancedMesh: InstancedMesh, + Int16BufferAttribute: Int16BufferAttribute, + Int32BufferAttribute: Int32BufferAttribute, + Int8BufferAttribute: Int8BufferAttribute, + IntType: IntType, + InterleavedBuffer: InterleavedBuffer, + InterleavedBufferAttribute: InterleavedBufferAttribute, + Interpolant: Interpolant, + InterpolateDiscrete: InterpolateDiscrete, + InterpolateLinear: InterpolateLinear, + InterpolateSmooth: InterpolateSmooth, + InvertStencilOp: InvertStencilOp, + KeepStencilOp: KeepStencilOp, + KeyframeTrack: KeyframeTrack, + LOD: LOD, + LatheBufferGeometry: LatheBufferGeometry, + LatheGeometry: LatheGeometry, + Layers: Layers, + LessDepth: LessDepth, + LessEqualDepth: LessEqualDepth, + LessEqualStencilFunc: LessEqualStencilFunc, + LessStencilFunc: LessStencilFunc, + Light: Light, + LightProbe: LightProbe, + Line: Line, + Line3: Line3, + LineBasicMaterial: LineBasicMaterial, + LineCurve: LineCurve, + LineCurve3: LineCurve3, + LineDashedMaterial: LineDashedMaterial, + LineLoop: LineLoop, + LineSegments: LineSegments, + LinearEncoding: LinearEncoding, + LinearFilter: LinearFilter, + LinearInterpolant: LinearInterpolant, + LinearMipMapLinearFilter: LinearMipMapLinearFilter, + LinearMipMapNearestFilter: LinearMipMapNearestFilter, + LinearMipmapLinearFilter: LinearMipmapLinearFilter, + LinearMipmapNearestFilter: LinearMipmapNearestFilter, + LinearSRGBColorSpace: LinearSRGBColorSpace, + LinearToneMapping: LinearToneMapping, + Loader: Loader, + LoaderUtils: LoaderUtils, + LoadingManager: LoadingManager, + LoopOnce: LoopOnce, + LoopPingPong: LoopPingPong, + LoopRepeat: LoopRepeat, + LuminanceAlphaFormat: LuminanceAlphaFormat, + LuminanceFormat: LuminanceFormat, + MOUSE: MOUSE, + Material: Material, + MaterialLoader: MaterialLoader, + MathUtils: MathUtils, + Matrix3: Matrix3, + Matrix4: Matrix4, + MaxEquation: MaxEquation, + Mesh: Mesh, + MeshBasicMaterial: MeshBasicMaterial, + MeshDepthMaterial: MeshDepthMaterial, + MeshDistanceMaterial: MeshDistanceMaterial, + MeshLambertMaterial: MeshLambertMaterial, + MeshMatcapMaterial: MeshMatcapMaterial, + MeshNormalMaterial: MeshNormalMaterial, + MeshPhongMaterial: MeshPhongMaterial, + MeshPhysicalMaterial: MeshPhysicalMaterial, + MeshStandardMaterial: MeshStandardMaterial, + MeshToonMaterial: MeshToonMaterial, + MinEquation: MinEquation, + MirroredRepeatWrapping: MirroredRepeatWrapping, + MixOperation: MixOperation, + MultiplyBlending: MultiplyBlending, + MultiplyOperation: MultiplyOperation, + NearestFilter: NearestFilter, + NearestMipMapLinearFilter: NearestMipMapLinearFilter, + NearestMipMapNearestFilter: NearestMipMapNearestFilter, + NearestMipmapLinearFilter: NearestMipmapLinearFilter, + NearestMipmapNearestFilter: NearestMipmapNearestFilter, + NeverDepth: NeverDepth, + NeverStencilFunc: NeverStencilFunc, + NoBlending: NoBlending, + NoColorSpace: NoColorSpace, + NoToneMapping: NoToneMapping, + NormalAnimationBlendMode: NormalAnimationBlendMode, + NormalBlending: NormalBlending, + NotEqualDepth: NotEqualDepth, + NotEqualStencilFunc: NotEqualStencilFunc, + NumberKeyframeTrack: NumberKeyframeTrack, + Object3D: Object3D, + ObjectLoader: ObjectLoader, + ObjectSpaceNormalMap: ObjectSpaceNormalMap, + OctahedronBufferGeometry: OctahedronBufferGeometry, + OctahedronGeometry: OctahedronGeometry, + OneFactor: OneFactor, + OneMinusDstAlphaFactor: OneMinusDstAlphaFactor, + OneMinusDstColorFactor: OneMinusDstColorFactor, + OneMinusSrcAlphaFactor: OneMinusSrcAlphaFactor, + OneMinusSrcColorFactor: OneMinusSrcColorFactor, + OrthographicCamera: OrthographicCamera, + PCFShadowMap: PCFShadowMap, + PCFSoftShadowMap: PCFSoftShadowMap, + PMREMGenerator: PMREMGenerator, + Path: Path, + PerspectiveCamera: PerspectiveCamera, + Plane: Plane, + PlaneBufferGeometry: PlaneBufferGeometry, + PlaneGeometry: PlaneGeometry, + PlaneHelper: PlaneHelper, + PointLight: PointLight, + PointLightHelper: PointLightHelper, + Points: Points, + PointsMaterial: PointsMaterial, + PolarGridHelper: PolarGridHelper, + PolyhedronBufferGeometry: PolyhedronBufferGeometry, + PolyhedronGeometry: PolyhedronGeometry, + PositionalAudio: PositionalAudio, + PropertyBinding: PropertyBinding, + PropertyMixer: PropertyMixer, + QuadraticBezierCurve: QuadraticBezierCurve, + QuadraticBezierCurve3: QuadraticBezierCurve3, + Quaternion: Quaternion, + QuaternionKeyframeTrack: QuaternionKeyframeTrack, + QuaternionLinearInterpolant: QuaternionLinearInterpolant, + REVISION: REVISION, + RGBADepthPacking: RGBADepthPacking, + RGBAFormat: RGBAFormat, + RGBAIntegerFormat: RGBAIntegerFormat, + RGBA_ASTC_10x10_Format: RGBA_ASTC_10x10_Format, + RGBA_ASTC_10x5_Format: RGBA_ASTC_10x5_Format, + RGBA_ASTC_10x6_Format: RGBA_ASTC_10x6_Format, + RGBA_ASTC_10x8_Format: RGBA_ASTC_10x8_Format, + RGBA_ASTC_12x10_Format: RGBA_ASTC_12x10_Format, + RGBA_ASTC_12x12_Format: RGBA_ASTC_12x12_Format, + RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, + RGBA_ASTC_5x4_Format: RGBA_ASTC_5x4_Format, + RGBA_ASTC_5x5_Format: RGBA_ASTC_5x5_Format, + RGBA_ASTC_6x5_Format: RGBA_ASTC_6x5_Format, + RGBA_ASTC_6x6_Format: RGBA_ASTC_6x6_Format, + RGBA_ASTC_8x5_Format: RGBA_ASTC_8x5_Format, + RGBA_ASTC_8x6_Format: RGBA_ASTC_8x6_Format, + RGBA_ASTC_8x8_Format: RGBA_ASTC_8x8_Format, + RGBA_BPTC_Format: RGBA_BPTC_Format, + RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, + RGBA_PVRTC_2BPPV1_Format: RGBA_PVRTC_2BPPV1_Format, + RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, + RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format, + RGBA_S3TC_DXT3_Format: RGBA_S3TC_DXT3_Format, + RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, + RGBFormat: RGBFormat, + RGB_ETC1_Format: RGB_ETC1_Format, + RGB_ETC2_Format: RGB_ETC2_Format, + RGB_PVRTC_2BPPV1_Format: RGB_PVRTC_2BPPV1_Format, + RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, + RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format, + RGFormat: RGFormat, + RGIntegerFormat: RGIntegerFormat, + RawShaderMaterial: RawShaderMaterial, + Ray: Ray, + Raycaster: Raycaster, + RectAreaLight: RectAreaLight, + RedFormat: RedFormat, + RedIntegerFormat: RedIntegerFormat, + ReinhardToneMapping: ReinhardToneMapping, + RepeatWrapping: RepeatWrapping, + ReplaceStencilOp: ReplaceStencilOp, + ReverseSubtractEquation: ReverseSubtractEquation, + RingBufferGeometry: RingBufferGeometry, + RingGeometry: RingGeometry, + SRGBColorSpace: SRGBColorSpace, + Scene: Scene, + ShaderChunk: ShaderChunk, + ShaderLib: ShaderLib, + ShaderMaterial: ShaderMaterial, + ShadowMaterial: ShadowMaterial, + Shape: Shape, + ShapeBufferGeometry: ShapeBufferGeometry, + ShapeGeometry: ShapeGeometry, + ShapePath: ShapePath, + ShapeUtils: ShapeUtils, + ShortType: ShortType, + Skeleton: Skeleton, + SkeletonHelper: SkeletonHelper, + SkinnedMesh: SkinnedMesh, + Source: Source, + Sphere: Sphere, + SphereBufferGeometry: SphereBufferGeometry, + SphereGeometry: SphereGeometry, + Spherical: Spherical, + SphericalHarmonics3: SphericalHarmonics3, + SplineCurve: SplineCurve, + SpotLight: SpotLight, + SpotLightHelper: SpotLightHelper, + Sprite: Sprite, + SpriteMaterial: SpriteMaterial, + SrcAlphaFactor: SrcAlphaFactor, + SrcAlphaSaturateFactor: SrcAlphaSaturateFactor, + SrcColorFactor: SrcColorFactor, + StaticCopyUsage: StaticCopyUsage, + StaticDrawUsage: StaticDrawUsage, + StaticReadUsage: StaticReadUsage, + StereoCamera: StereoCamera, + StreamCopyUsage: StreamCopyUsage, + StreamDrawUsage: StreamDrawUsage, + StreamReadUsage: StreamReadUsage, + StringKeyframeTrack: StringKeyframeTrack, + SubtractEquation: SubtractEquation, + SubtractiveBlending: SubtractiveBlending, + TOUCH: TOUCH, + TangentSpaceNormalMap: TangentSpaceNormalMap, + TetrahedronBufferGeometry: TetrahedronBufferGeometry, + TetrahedronGeometry: TetrahedronGeometry, + Texture: Texture, + TextureLoader: TextureLoader, + TorusBufferGeometry: TorusBufferGeometry, + TorusGeometry: TorusGeometry, + TorusKnotBufferGeometry: TorusKnotBufferGeometry, + TorusKnotGeometry: TorusKnotGeometry, + Triangle: Triangle, + TriangleFanDrawMode: TriangleFanDrawMode, + TriangleStripDrawMode: TriangleStripDrawMode, + TrianglesDrawMode: TrianglesDrawMode, + TubeBufferGeometry: TubeBufferGeometry, + TubeGeometry: TubeGeometry, + UVMapping: UVMapping, + Uint16BufferAttribute: Uint16BufferAttribute, + Uint32BufferAttribute: Uint32BufferAttribute, + Uint8BufferAttribute: Uint8BufferAttribute, + Uint8ClampedBufferAttribute: Uint8ClampedBufferAttribute, + Uniform: Uniform, + UniformsGroup: UniformsGroup, + UniformsLib: UniformsLib, + UniformsUtils: UniformsUtils, + UnsignedByteType: UnsignedByteType, + UnsignedInt248Type: UnsignedInt248Type, + UnsignedIntType: UnsignedIntType, + UnsignedShort4444Type: UnsignedShort4444Type, + UnsignedShort5551Type: UnsignedShort5551Type, + UnsignedShortType: UnsignedShortType, + VSMShadowMap: VSMShadowMap, + Vector2: Vector2, + Vector3: Vector3, + Vector4: Vector4, + VectorKeyframeTrack: VectorKeyframeTrack, + VideoTexture: VideoTexture, + WebGL1Renderer: WebGL1Renderer, + WebGL3DRenderTarget: WebGL3DRenderTarget, + WebGLArrayRenderTarget: WebGLArrayRenderTarget, + WebGLCubeRenderTarget: WebGLCubeRenderTarget, + WebGLMultipleRenderTargets: WebGLMultipleRenderTargets, + WebGLMultisampleRenderTarget: WebGLMultisampleRenderTarget, + WebGLRenderTarget: WebGLRenderTarget, + WebGLRenderer: WebGLRenderer, + WebGLUtils: WebGLUtils, + WireframeGeometry: WireframeGeometry, + WrapAroundEnding: WrapAroundEnding, + ZeroCurvatureEnding: ZeroCurvatureEnding, + ZeroFactor: ZeroFactor, + ZeroSlopeEnding: ZeroSlopeEnding, + ZeroStencilOp: ZeroStencilOp, + _SRGBAFormat: _SRGBAFormat, + sRGBEncoding: sRGBEncoding + }); + + /* src\MovingDotSpaceModalBrainstorm.svelte generated by Svelte v3.59.2 */ + const file$h = "src\\MovingDotSpaceModalBrainstorm.svelte"; + + function create_fragment$h(ctx) { + let div; + + const block = { + c: function create() { + div = element$1("div"); + attr_dev(div, "class", "svelte-1kuj9kb"); + add_location(div, file$h, 95, 0, 3254); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + /*div_binding*/ ctx[1](div); + }, + p: noop$2, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + /*div_binding*/ ctx[1](null); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$h.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$h($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('MovingDotSpaceModalBrainstorm', slots, []); + let container; + let scene, camera, renderer, geometry, material, mesh; + + onMount(() => { + init(); + animate(); + }); + + function init() { + // Create scene + scene = new Scene(); + + // Create camera + camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); + + camera.position.z = 5; + + // Create renderer + renderer = new WebGLRenderer({ antialias: true }); + + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + // Create geometry + geometry = new TorusKnotGeometry(1, 0.3, 100, 20); + + // Create material + material = new MeshBasicMaterial({ color: 0x00ff00, wireframe: true }); + + // Create mesh + mesh = new Mesh(geometry, material); + + scene.add(mesh); + } + + function animate() { + requestAnimationFrame(animate); + mesh.rotation.x += 0.01; + mesh.rotation.y += 0.02; + renderer.render(scene, camera); + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + function div_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + container = $$value; + $$invalidate(0, container); + }); + } + + $$self.$capture_state = () => ({ + onMount, + THREE, + container, + scene, + camera, + renderer, + geometry, + material, + mesh, + init, + animate + }); + + $$self.$inject_state = $$props => { + if ('container' in $$props) $$invalidate(0, container = $$props.container); + if ('scene' in $$props) scene = $$props.scene; + if ('camera' in $$props) camera = $$props.camera; + if ('renderer' in $$props) renderer = $$props.renderer; + if ('geometry' in $$props) geometry = $$props.geometry; + if ('material' in $$props) material = $$props.material; + if ('mesh' in $$props) mesh = $$props.mesh; + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [container, div_binding]; + } + + class MovingDotSpaceModalBrainstorm extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$h, create_fragment$h, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "MovingDotSpaceModalBrainstorm", + options, + id: create_fragment$h.name + }); + } + } + + /* src\MovingDotSpaceGameFind.svelte generated by Svelte v3.59.2 */ + + const file$g = "src\\MovingDotSpaceGameFind.svelte"; + + function get_each_context$d(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[9] = list[i]; + child_ctx[11] = i; + return child_ctx; + } + + function get_each_context_1$7(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[12] = list[i]; + child_ctx[14] = i; + return child_ctx; + } + + // (63:4) {:else} + function create_else_block$2(ctx) { + let p; + + const block = { + c: function create() { + p = element$1("p"); + p.textContent = "Game over. Try again!"; + add_location(p, file$g, 63, 6, 1832); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_else_block$2.name, + type: "else", + source: "(63:4) {:else}", + ctx + }); + + return block; + } + + // (61:34) + function create_if_block_1$5(ctx) { + let p; + + const block = { + c: function create() { + p = element$1("p"); + p.textContent = "You won! 🎉"; + add_location(p, file$g, 61, 6, 1793); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_1$5.name, + type: "if", + source: "(61:34) ", + ctx + }); + + return block; + } + + // (59:4) {#if gameState === 'playing'} + function create_if_block$8(ctx) { + let p; + let t0; + let t1; + + const block = { + c: function create() { + p = element$1("p"); + t0 = text("Presses Remaining: "); + t1 = text(/*pressesRemaining*/ ctx[0]); + add_location(p, file$g, 59, 6, 1705); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + append_dev(p, t0); + append_dev(p, t1); + }, + p: function update(ctx, dirty) { + if (dirty & /*pressesRemaining*/ 1) set_data_dev(t1, /*pressesRemaining*/ ctx[0]); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block$8.name, + type: "if", + source: "(59:4) {#if gameState === 'playing'}", + ctx + }); + + return block; + } + + // (71:6) {#each row as cell, colIndex} + function create_each_block_1$7(ctx) { + let button; + + let t0_value = (/*cell*/ ctx[12].pressed + ? /*rowIndex*/ ctx[11] === /*correctItem*/ ctx[1].row && /*colIndex*/ ctx[14] === /*correctItem*/ ctx[1].col + ? '✅' + : '❌' + : '') + ""; + + let t0; + let t1; + let button_disabled_value; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[6](/*rowIndex*/ ctx[11], /*colIndex*/ ctx[14]); + } + + const block = { + c: function create() { + button = element$1("button"); + t0 = text(t0_value); + t1 = space(); + button.disabled = button_disabled_value = /*gameState*/ ctx[2] !== 'playing'; + attr_dev(button, "class", "svelte-p3ubim"); + toggle_class(button, "pressed", /*cell*/ ctx[12].pressed); + add_location(button, file$g, 71, 8, 2045); + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); + append_dev(button, t0); + append_dev(button, t1); + + if (!mounted) { + dispose = listen_dev(button, "click", click_handler, false, false, false, false); + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + + if (dirty & /*grid, correctItem*/ 10 && t0_value !== (t0_value = (/*cell*/ ctx[12].pressed + ? /*rowIndex*/ ctx[11] === /*correctItem*/ ctx[1].row && /*colIndex*/ ctx[14] === /*correctItem*/ ctx[1].col + ? '✅' + : '❌' + : '') + "")) set_data_dev(t0, t0_value); + + if (dirty & /*gameState*/ 4 && button_disabled_value !== (button_disabled_value = /*gameState*/ ctx[2] !== 'playing')) { + prop_dev(button, "disabled", button_disabled_value); + } + + if (dirty & /*grid*/ 8) { + toggle_class(button, "pressed", /*cell*/ ctx[12].pressed); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_1$7.name, + type: "each", + source: "(71:6) {#each row as cell, colIndex}", + ctx + }); + + return block; + } + + // (70:4) {#each grid as row, rowIndex} + function create_each_block$d(ctx) { + let each_1_anchor; + let each_value_1 = /*row*/ ctx[9]; + validate_each_argument(each_value_1); + let each_blocks = []; + + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks[i] = create_each_block_1$7(get_each_context_1$7(ctx, each_value_1, i)); + } + + const block = { + c: function create() { + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + each_1_anchor = empty(); + }, + m: function mount(target, anchor) { + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(target, anchor); + } + } + + insert_dev(target, each_1_anchor, anchor); + }, + p: function update(ctx, dirty) { + if (dirty & /*gameState, grid, pressButton, correctItem*/ 30) { + each_value_1 = /*row*/ ctx[9]; + validate_each_argument(each_value_1); + let i; + + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1$7(ctx, each_value_1, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block_1$7(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value_1.length; + } + }, + d: function destroy(detaching) { + destroy_each(each_blocks, detaching); + if (detaching) detach_dev(each_1_anchor); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$d.name, + type: "each", + source: "(70:4) {#each grid as row, rowIndex}", + ctx + }); + + return block; + } + + function create_fragment$g(ctx) { + let div0; + let t0; + let button; + let t2; + let div1; + let mounted; + let dispose; + + function select_block_type(ctx, dirty) { + if (/*gameState*/ ctx[2] === 'playing') return create_if_block$8; + if (/*gameState*/ ctx[2] === 'won') return create_if_block_1$5; + return create_else_block$2; + } + + let current_block_type = select_block_type(ctx); + let if_block = current_block_type(ctx); + let each_value = /*grid*/ ctx[3]; + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$d(get_each_context$d(ctx, each_value, i)); + } + + const block = { + c: function create() { + div0 = element$1("div"); + if_block.c(); + t0 = space(); + button = element$1("button"); + button.textContent = "Restart Game"; + t2 = space(); + div1 = element$1("div"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + attr_dev(button, "class", "svelte-p3ubim"); + add_location(button, file$g, 65, 4, 1877); + add_location(div0, file$g, 57, 2, 1657); + attr_dev(div1, "class", "grid svelte-p3ubim"); + add_location(div1, file$g, 68, 2, 1945); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div0, anchor); + if_block.m(div0, null); + append_dev(div0, t0); + append_dev(div0, button); + insert_dev(target, t2, anchor); + insert_dev(target, div1, anchor); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div1, null); + } + } + + if (!mounted) { + dispose = listen_dev(button, "click", /*resetGame*/ ctx[5], false, false, false, false); + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block) { + if_block.p(ctx, dirty); + } else { + if_block.d(1); + if_block = current_block_type(ctx); + + if (if_block) { + if_block.c(); + if_block.m(div0, t0); + } + } + + if (dirty & /*grid, gameState, pressButton, correctItem*/ 30) { + each_value = /*grid*/ ctx[3]; + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$d(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$d(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div1, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div0); + if_block.d(); + if (detaching) detach_dev(t2); + if (detaching) detach_dev(div1); + destroy_each(each_blocks, detaching); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$g.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$g($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('MovingDotSpaceGameFind', slots, []); + let gridSize = 10; + let maxPresses = 20; // Maximum number of presses allowed + let pressesRemaining = maxPresses; + + let correctItem = { + row: Math.floor(Math.random() * gridSize), + col: Math.floor(Math.random() * gridSize) + }; + + let gameState = "playing"; // Can be "playing", "won", or "lost" + + // Generate initial grid state + let grid = Array(gridSize).fill().map(() => Array(gridSize).fill().map(() => ({ pressed: false }))); + + function pressButton(row, col) { + if (grid[row][col].pressed || pressesRemaining === 0 || gameState !== "playing") { + return; // Ignore if already pressed or no presses left or game not in playing state + } + + $$invalidate(3, grid[row][col].pressed = true, grid); + $$invalidate(0, pressesRemaining -= 1); + + // Check for win condition + if (row === correctItem.row && col === correctItem.col) { + $$invalidate(2, gameState = "won"); + } else if (pressesRemaining === 0) { + $$invalidate(2, gameState = "lost"); + } + } + + function resetGame() { + $$invalidate(0, pressesRemaining = maxPresses); + + $$invalidate(1, correctItem = { + row: Math.floor(Math.random() * gridSize), + col: Math.floor(Math.random() * gridSize) + }); + + $$invalidate(3, grid = Array(gridSize).fill().map(() => Array(gridSize).fill().map(() => ({ pressed: false })))); + $$invalidate(2, gameState = "playing"); + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + const click_handler = (rowIndex, colIndex) => pressButton(rowIndex, colIndex); + + $$self.$capture_state = () => ({ + gridSize, + maxPresses, + pressesRemaining, + correctItem, + gameState, + grid, + pressButton, + resetGame + }); + + $$self.$inject_state = $$props => { + if ('gridSize' in $$props) gridSize = $$props.gridSize; + if ('maxPresses' in $$props) maxPresses = $$props.maxPresses; + if ('pressesRemaining' in $$props) $$invalidate(0, pressesRemaining = $$props.pressesRemaining); + if ('correctItem' in $$props) $$invalidate(1, correctItem = $$props.correctItem); + if ('gameState' in $$props) $$invalidate(2, gameState = $$props.gameState); + if ('grid' in $$props) $$invalidate(3, grid = $$props.grid); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + pressesRemaining, + correctItem, + gameState, + grid, + pressButton, + resetGame, + click_handler + ]; + } + + class MovingDotSpaceGameFind extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$g, create_fragment$g, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "MovingDotSpaceGameFind", + options, + id: create_fragment$g.name + }); + } + } + + /* src\MovingDotSpaceGameOrder.svelte generated by Svelte v3.59.2 */ + + const file$f = "src\\MovingDotSpaceGameOrder.svelte"; + + function get_each_context$c(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[10] = list[i]; + child_ctx[12] = i; + return child_ctx; + } + + // (72:39) + function create_if_block_2$2(ctx) { + let p; + + const block = { + c: function create() { + p = element$1("p"); + p.textContent = "Incorrect order. Try again!"; + add_location(p, file$f, 72, 4, 2206); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_2$2.name, + type: "if", + source: "(72:39) ", + ctx + }); + + return block; + } + + // (70:2) {#if gameStatus === "correct"} + function create_if_block_1$4(ctx) { + let p; + + const block = { + c: function create() { + p = element$1("p"); + p.textContent = "You guessed the correct order! 🎉"; + add_location(p, file$f, 70, 4, 2119); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_1$4.name, + type: "if", + source: "(70:2) {#if gameStatus === \\\"correct\\\"}", + ctx + }); + + return block; + } + + // (79:4) {#each Array(gridSize) as _, i} + function create_each_block$c(ctx) { + let button; + let t0_value = /*i*/ ctx[12] + 1 + ""; + let t0; + let t1; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[8](/*i*/ ctx[12]); + } + + const block = { + c: function create() { + button = element$1("button"); + t0 = text(t0_value); + t1 = space(); + attr_dev(button, "data-number", /*i*/ ctx[12] + 1); + attr_dev(button, "class", "svelte-7k1yf9"); + toggle_class(button, "pressed", /*userOrder*/ ctx[0].includes(/*i*/ ctx[12] + 1)); + add_location(button, file$f, 79, 6, 2378); + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); + append_dev(button, t0); + append_dev(button, t1); + + if (!mounted) { + dispose = listen_dev(button, "click", click_handler, false, false, false, false); + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + + if (dirty & /*userOrder*/ 1) { + toggle_class(button, "pressed", /*userOrder*/ ctx[0].includes(/*i*/ ctx[12] + 1)); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$c.name, + type: "each", + source: "(79:4) {#each Array(gridSize) as _, i}", + ctx + }); + + return block; + } + + // (86:2) {#if !checkOnEveryPress && gameStatus === ""} + function create_if_block$7(ctx) { + let button; + let t; + let button_disabled_value; + let mounted; + let dispose; + + const block = { + c: function create() { + button = element$1("button"); + t = text("Check Order"); + button.disabled = button_disabled_value = /*userOrder*/ ctx[0].length !== /*gridSize*/ ctx[3]; + attr_dev(button, "class", "svelte-7k1yf9"); + add_location(button, file$f, 86, 4, 2600); + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); + append_dev(button, t); + + if (!mounted) { + dispose = listen_dev(button, "click", /*checkOrder*/ ctx[5], false, false, false, false); + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty & /*userOrder*/ 1 && button_disabled_value !== (button_disabled_value = /*userOrder*/ ctx[0].length !== /*gridSize*/ ctx[3])) { + prop_dev(button, "disabled", button_disabled_value); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block$7.name, + type: "if", + source: "(86:2) {#if !checkOnEveryPress && gameStatus === \\\"\\\"}", + ctx + }); + + return block; + } + + function create_fragment$f(ctx) { + let div0; + let input; + let t0; + let label; + let t2; + let t3; + let button; + let t5; + let div1; + let t6; + let if_block1_anchor; + let mounted; + let dispose; + + function select_block_type(ctx, dirty) { + if (/*gameStatus*/ ctx[2] === "correct") return create_if_block_1$4; + if (/*gameStatus*/ ctx[2] === "incorrect") return create_if_block_2$2; + } + + let current_block_type = select_block_type(ctx); + let if_block0 = current_block_type && current_block_type(ctx); + let each_value = Array(/*gridSize*/ ctx[3]); + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$c(get_each_context$c(ctx, each_value, i)); + } + + let if_block1 = !/*checkOnEveryPress*/ ctx[1] && /*gameStatus*/ ctx[2] === "" && create_if_block$7(ctx); + + const block = { + c: function create() { + div0 = element$1("div"); + input = element$1("input"); + t0 = space(); + label = element$1("label"); + label.textContent = "Check order on every press"; + t2 = space(); + if (if_block0) if_block0.c(); + t3 = space(); + button = element$1("button"); + button.textContent = "Restart Game"; + t5 = space(); + div1 = element$1("div"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t6 = space(); + if (if_block1) if_block1.c(); + if_block1_anchor = empty(); + attr_dev(input, "type", "checkbox"); + add_location(input, file$f, 65, 4, 1962); + add_location(label, file$f, 66, 4, 2024); + attr_dev(div0, "class", "controls svelte-7k1yf9"); + add_location(div0, file$f, 64, 2, 1934); + attr_dev(button, "class", "svelte-7k1yf9"); + add_location(button, file$f, 75, 2, 2257); + attr_dev(div1, "class", "grid svelte-7k1yf9"); + add_location(div1, file$f, 77, 2, 2315); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div0, anchor); + append_dev(div0, input); + input.checked = /*checkOnEveryPress*/ ctx[1]; + append_dev(div0, t0); + append_dev(div0, label); + insert_dev(target, t2, anchor); + if (if_block0) if_block0.m(target, anchor); + insert_dev(target, t3, anchor); + insert_dev(target, button, anchor); + insert_dev(target, t5, anchor); + insert_dev(target, div1, anchor); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div1, null); + } + } + + insert_dev(target, t6, anchor); + if (if_block1) if_block1.m(target, anchor); + insert_dev(target, if_block1_anchor, anchor); + + if (!mounted) { + dispose = [ + listen_dev(input, "change", /*input_change_handler*/ ctx[7]), + listen_dev(button, "click", /*resetGame*/ ctx[6], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*checkOnEveryPress*/ 2) { + input.checked = /*checkOnEveryPress*/ ctx[1]; + } + + if (current_block_type !== (current_block_type = select_block_type(ctx))) { + if (if_block0) if_block0.d(1); + if_block0 = current_block_type && current_block_type(ctx); + + if (if_block0) { + if_block0.c(); + if_block0.m(t3.parentNode, t3); + } + } + + if (dirty & /*userOrder, handlePress*/ 17) { + each_value = Array(/*gridSize*/ ctx[3]); + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$c(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$c(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div1, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + + if (!/*checkOnEveryPress*/ ctx[1] && /*gameStatus*/ ctx[2] === "") { + if (if_block1) { + if_block1.p(ctx, dirty); + } else { + if_block1 = create_if_block$7(ctx); + if_block1.c(); + if_block1.m(if_block1_anchor.parentNode, if_block1_anchor); + } + } else if (if_block1) { + if_block1.d(1); + if_block1 = null; + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div0); + if (detaching) detach_dev(t2); + + if (if_block0) { + if_block0.d(detaching); + } + + if (detaching) detach_dev(t3); + if (detaching) detach_dev(button); + if (detaching) detach_dev(t5); + if (detaching) detach_dev(div1); + destroy_each(each_blocks, detaching); + if (detaching) detach_dev(t6); + if (if_block1) if_block1.d(detaching); + if (detaching) detach_dev(if_block1_anchor); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$f.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$f($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('MovingDotSpaceGameOrder', slots, []); + let gridSize = 4; // Grid size for simplicity + let correctOrder = Array.from({ length: gridSize }, (_, i) => i + 1).sort(() => 0.5 - Math.random()); // Randomized correct order + let userOrder = []; // User's order + let checkOnEveryPress = false; // Start with manual check + let gameStatus = ""; // "", "correct", or "incorrect" + + function handlePress(number) { + if (userOrder.includes(number) || gameStatus) return; // Ignore if already pressed or game has ended + userOrder.push(number); + + if (!checkOnEveryPress) { + // Add the "pressed" class to the pressed button + const pressedButton = document.querySelector(`button[data-number="${number}"]`); + + pressedButton.classList.add("pressed"); + } else { + checkOrder(); + } + } + + function checkOrder() { + for (let i = 0; i < userOrder.length; i++) { + if (userOrder[i] !== correctOrder[i]) { + $$invalidate(2, gameStatus = "incorrect"); + return; + } + } + + if (userOrder.length === correctOrder.length) { + $$invalidate(2, gameStatus = "correct"); + } + } + + function resetGame() { + $$invalidate(0, userOrder = []); + $$invalidate(2, gameStatus = ""); + correctOrder.sort(() => 0.5 - Math.random()); // Shuffle for a new game + + // Remove the "pressed" class from all buttons + const pressedButtons = document.querySelectorAll(".pressed"); + + pressedButtons.forEach(button => button.classList.remove("pressed")); + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + function input_change_handler() { + checkOnEveryPress = this.checked; + $$invalidate(1, checkOnEveryPress); + } + + const click_handler = i => handlePress(i + 1); + + $$self.$capture_state = () => ({ + gridSize, + correctOrder, + userOrder, + checkOnEveryPress, + gameStatus, + handlePress, + checkOrder, + resetGame + }); + + $$self.$inject_state = $$props => { + if ('gridSize' in $$props) $$invalidate(3, gridSize = $$props.gridSize); + if ('correctOrder' in $$props) correctOrder = $$props.correctOrder; + if ('userOrder' in $$props) $$invalidate(0, userOrder = $$props.userOrder); + if ('checkOnEveryPress' in $$props) $$invalidate(1, checkOnEveryPress = $$props.checkOnEveryPress); + if ('gameStatus' in $$props) $$invalidate(2, gameStatus = $$props.gameStatus); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + userOrder, + checkOnEveryPress, + gameStatus, + gridSize, + handlePress, + checkOrder, + resetGame, + input_change_handler, + click_handler + ]; + } + + class MovingDotSpaceGameOrder extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$f, create_fragment$f, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "MovingDotSpaceGameOrder", + options, + id: create_fragment$f.name + }); + } + } + + // themeConfig.js + + const themes = { + 'User Custom - Template': { + background: '/AutoGameBackgrounds/theme_background.png', + inventory: [ + { type: "weapon", name: "Random waepon", description: "A powerful weapon." }, + // ... more space items + ], + skills: [ + { branch: "Skill Group 1", name: "Skill One", learned: false }, + // ... more space skills + ], + persistentTargets: [ + { name: "Background Target 1", x: 500, y: 500, collisionType: "alert", collisiontext: "First Test"}, + ], + // ... and so on for targets + story: [ + { + part: 0, + objectives: [ + { id: 1, + name: "Mission Details", + complete: false, + progress: 0, + inventoryRequired: [], }, + ], + targets: [ + { name: "Target 1", x: 150, y: 150, collisionType: "alert", collisiontext: "First Test"}, + ], }, { part: 1, @@ -61076,6 +96257,7 @@ var app = (function () { 'Default': { background: '/AutoGameBackgrounds/1stGameLoc123.png', inventory: [ + { type: "book", name: "My Memories", description: "Currently I dont remember the when I start this journey...." }, { type: "weapon", name: "Sword", description: "A sharp blade." }, { type: "armor", name: "Shield", description: "Protects against attacks." }, { type: "consumable", name: "Health Potion", description: "Restores health." }, @@ -61117,6 +96299,7 @@ var app = (function () { { label: "Buy an Axe", action: "buyAxe" } ], consequences: [], + modalimg: '/AutoGameBackgrounds/1stGameLoc123.png', }, guidance: { title: "Entrance - Guidance", @@ -61159,7 +96342,7 @@ var app = (function () { //{ name: "Dragon's Lair", x: 1600, y: 200, collisionType: "incrementScore", incrementValue: 50 }, //{ name: "Abandoned Shipwreck", x: 1300, y: 500, collisionType: "shrinkDot" }, - { name: "Switch Test 1", x: 700, y: 700, collisionType: "storypartchange", collisiontext: "First Test", newStage: 1}, + { name: "Switch Test 1", x: 700, y: 700, collisionType: "storypartchange", collisiontext: "First Test", transitionToPart: 1}, ], }, { @@ -61167,7 +96350,7 @@ var app = (function () { objectives: [], targets: [ { name: "Target 1", x: 50, y: 50, collisionType: "alert", collisiontext: "First Test"}, - { name: "Switch Back Test 1", x: 600, y: 400, collisionType: "storypartchange", collisiontext: "First Test", newStage: 0}, + { name: "Switch Back Test 1", x: 600, y: 400, collisionType: "storypartchange", collisiontext: "First Test", transitionToPart: 0}, ], }, ], @@ -61188,10 +96371,13 @@ var app = (function () { background: '/AutoGameBackgrounds/SpaceOdysseyGameLoc.png', inventory: [ { type: "weapon", name: "Laser Gun", description: "A powerful laser weapon." }, + { type: "tool", name: "Repair Kit", description: "A kit for repairing various equipment." }, + { type: "tool", name: "Mining Laser", description: "A tool for extracting minerals from asteroids." }, // ... more space items ], skills: [ { branch: "Piloting", name: "Astro Navigation", learned: false }, + { branch: "Engineering", name: "Repair Mastery", learned: false }, // ... more space skills ], persistentTargets: [ @@ -61262,6 +96448,57 @@ var app = (function () { { name: "To Alien Homeworld", x: 1100, y: 200, collisionType: "storypartchange", transitionToPart: 2, collisiontext: "After successful communication, the aliens invite you to their homeworld to discuss a potential peace treaty." }, ], }, + { + part: 2, + objectives: [ + { + id: 4, + name: "Negotiate Peace with the Aliens", + complete: false, + progress: 0, + inventoryRequired: [], + }, + { + id: 5, + name: "Gather Alien Artifacts", + complete: false, + progress: 0, + inventoryRequired: ["Artifact Scanner"], + }, + ], + targets: [ + { + name: "Alien Council Chamber", + x: 600, + y: 250, + collisionType: "modal", + modalConfig: { + title: "Alien Council Chamber", + content: "You are in the presence of the Alien Council. Present your case for peace and negotiate terms.", + actions: [ + { label: "Present Peace Offer", action: "presentPeaceOffer" }, + { label: "Listen to Alien Concerns", action: "listenConcerns" }, + ], + } + }, + { + name: "Alien Ruins", + x: 750, + y: 400, + collisionType: "alert", + collisiontext: "You have discovered ancient alien ruins. Use your Artifact Scanner to gather important artifacts." + }, + { + name: "Return to Human Colony", + x: 800, + y: 150, + collisionType: "storypartchange", + transitionToPart: 3, + collisiontext: "Having successfully negotiated peace and gathered artifacts, return to the Human Colony to share your findings." + }, + ], + } + // ... more story parts ], actions: { @@ -61277,6 +96514,16 @@ var app = (function () { purchaseUpgrades() { // Logic to purchase ship upgrades }, + presentPeaceOffer() { + // Logic to present a peace offer to the Alien Council + console.log("Presenting peace offer..."); + // Additional logic for negotiation success or failure + }, + listenConcerns() { + // Logic to listen to the concerns of the Alien Council + console.log("Listening to alien concerns..."); + // Additional logic to address concerns and build trust + }, // ... add more space-specific actions }, }, @@ -62009,1192 +97256,9662 @@ var app = (function () { ] } ] - } + }, + 'Test for graph format': { + background: '/AutoGameBackgrounds/theme_background.png', + inventory: [ + { type: "weapon", name: "Random waepon", description: "A powerful weapon." }, + // ... more space items + ], + skills: [ + { branch: "Skill Group 1", name: "Skill One", learned: false }, + // ... more space skills + ], + persistentTargets: [ + { name: "Background Target 1", x: 500, y: 500, collisionType: "alert", collisiontext: "First Test"}, + ], + // ... and so on for targets + story: [ + { + part: 0, + objectives: [ + { id: 1, + name: "Mission Details", + complete: false, + progress: 0, + inventoryRequired: [], }, + ], + targets: [ + { name: "Target 1", x: 150, y: 150, collisionType: "alert", collisiontext: "First Test"}, + { name: "Switch to Target 2", x: 600, y: 400, collisionType: "storypartchange", collisiontext: "Test", transitionToPart: 1}, + ], + }, + { + part: 1, + objectives: [ + { id: 2, + name: "Mission Details", + complete: false, + progress: 0, + inventoryRequired: [], }, + ], + targets: [ + { name: "Target 2", x: 250, y: 250, collisionType: "alert", collisiontext: "First Test"}, + { + name: "substory1", + x: 600, + y: 600, + collisionType: "smmodal", + modalStates: { + A: { + title: "Event 1", + content: "You are at Event 1. What would you like to do next?", + items: [ + { + label: "To Event 3", + action: "C" + }, + { + label: "To Event 5", + action: "E" + }, + { + label: "To Event 7", + action: "G" + }, + { + label: "Next: Event 2", + action: "B" + } + ], + consequences: [ + + ] + }, + B: { + title: "Event 2", + content: "You are at Event 2. What would you like to do next?", + items: [ + { + label: "To Event 5", + action: "E" + }, + { + label: "To Event 3", + action: "C" + }, + { + label: "To Event 5", + action: "E" + }, + { + label: "To Event 7", + action: "G" + }, + { + label: "Next: Event 3", + action: "C" + } + ], + consequences: [ + + ] + }, + C: { + title: "Event 3", + content: "You are at Event 3. What would you like to do next?", + items: [ + { + label: "Next: Event 4", + action: "D" + } + ], + consequences: [ + + ] + }, + D: { + title: "Event 4", + content: "You are at Event 4. What would you like to do next?", + items: [ + { + label: "To Event 6", + action: "F" + }, + { + label: "Next: Event 5", + action: "E" + } + ], + consequences: [ + + ] + }, + E: { + title: "Event 5", + content: "You are at Event 5. What would you like to do next?", + items: [ + { + label: "Next: Event 6", + action: "F" + } + ], + consequences: [ + + ] + }, + F: { + title: "Event 6", + content: "You are at Event 6. What would you like to do next?", + items: [ + { + label: "To Event 4", + action: "D" + }, + { + label: "To Event 1", + action: "A" + }, + { + label: "Next: Event 7", + action: "G" + } + ], + consequences: [ + + ] + }, + G: { + title: "Event 7", + content: "You are at Event 7. What would you like to do next?", + items: [ + + ], + consequences: [ + + ] + } + } + }, + { + name: "substory3", + x: 650, + y: 800, + collisionType: "smmodal", + modalStates: { + A: { + title: "Event 1", + content: "You are at Event 1. What would you like to do next?", + items: [{label:"Next: Event 2",action:"B"}], + consequences: [], + }, + B: { + title: "Event 2", + content: "You are at Event 2. What would you like to do next?", + items: [{"label":"Next: Event 3","action":"C"}], + consequences: [], + }, + C: { + title: "Event 3", + content: "You are at Event 3. What would you like to do next?", + items: [{"label":"Next: Event 4","action":"D"}], + consequences: [], + }, + D: { + title: "Event 4", + content: "You are at Event 4. What would you like to do next?", + items: [{"label":"To Event 2","action":"B"},{"label":"To Event 2","action":"B"},{"label":"To Event 7","action":"G"},{"label":"Next: Event 5","action":"E"}], + consequences: [], + }, + E: { + title: "Event 5", + content: "You are at Event 5. What would you like to do next?", + items: [{"label":"To Event 7","action":"G"},{"label":"To Event 2","action":"B"},{"label":"To Event 3","action":"C"},{"label":"Next: Event 6","action":"F"}], + consequences: [], + }, + F: { + title: "Event 6", + content: "You are at Event 6. What would you like to do next?", + items: [{"label":"To Event 1","action":"A"},{"label":"Next: Event 7","action":"G"}], + consequences: [], + }, + G: { + title: "Event 7", + content: "You are at Event 7. What would you like to do next?", + items: [{"label":"To Event 3","action":"C"},{"label":"To Event 6","action":"F"},{"label":"To Event 5","action":"E"}], + consequences: [], + } + } + }, + { + "name": "Story made 310524", + "x": 500, + "y": 100, + "collisionType": "smmodal", + "modalStates": { + "A": { + "title": "Explore Location", + "content": "Aria, an adventurous young woman, sets out to explore the ancient ruins of Eldoria. What would you like to do next?", + "items": [ + { + "label": "Discover Clue", + "action": "B" + }, + { + "label": "Next: Discover Clue", + "action": "B" + } + ], + "consequences": [] + }, + "B": { + "title": "Discover Clue", + "content": "Inside the ruins, Aria finds a faded mural depicting a secret chamber hidden deep within the labyrinth. What would you like to do next?", + "items": [ + { + "label": "Meet Character", + "action": "C" + }, + { + "label": "Next: Meet Character", + "action": "C" + } + ], + "consequences": [] + }, + "C": { + "title": "Meet Character", + "content": "Aria meets Eamon, a seasoned explorer who has been searching for the relic for years. What would you like to do next?", + "items": [ + { + "label": "Solve Riddle", + "action": "D" + }, + { + "label": "Next: Solve Riddle", + "action": "D" + } + ], + "consequences": [] + }, + "D": { + "title": "Solve Riddle", + "content": "Together, they decipher an ancient riddle inscribed on the mural. What would you like to do next?", + "items": [ + { + "label": "Find Item", + "action": "E" + }, + { + "label": "Next: Find Item", + "action": "E" + } + ], + "consequences": [] + }, + "E": { + "title": "Find Item", + "content": "In a hidden alcove, they discover an old, ornate key. What would you like to do next?", + "items": [ + { + "label": "Face Challenge", + "action": "F" + }, + { + "label": "Next: Face Challenge", + "action": "F" + } + ], + "consequences": [] + }, + "F": { + "title": "Face Challenge", + "content": "They encounter various challenges, including traps and puzzles. What would you like to do next?", + "items": [ + { + "label": "Make Decision", + "action": "G" + }, + { + "label": "Next: Make Decision", + "action": "G" + } + ], + "consequences": [] + }, + "G": { + "title": "Make Decision", + "content": "Aria and Eamon must decide whether to take a dangerous shortcut. What would you like to do next?", + "items": [ + { + "label": "Engage Battle", + "action": "H" + }, + { + "label": "Next: Engage Battle", + "action": "H" + } + ], + "consequences": [] + }, + "H": { + "title": "Engage Battle", + "content": "In the cavern, they face a fierce guardian beast. What would you like to do next?", + "items": [ + { + "label": "Unlock Ability", + "action": "I" + }, + { + "label": "Next: Unlock Ability", + "action": "I" + } + ], + "consequences": [] + }, + "I": { + "title": "Unlock Ability", + "content": "Eamon reveals a hidden talent for deciphering ancient texts. What would you like to do next?", + "items": [ + { + "label": "Learn Secret", + "action": "J" + }, + { + "label": "Next: Learn Secret", + "action": "J" + } + ], + "consequences": [] + }, + "J": { + "title": "Learn Secret", + "content": "They learn about the true nature of the relic. What would you like to do next?", + "items": [ + { + "label": "Complete Mission", + "action": "K" + }, + { + "label": "Next: Complete Mission", + "action": "K" + } + ], + "consequences": [] + }, + "K": { + "title": "Complete Mission", + "content": "Aria and Eamon finally reach the chamber and retrieve the relic. What would you like to do next?", + "items": [ + { + "label": "Experience Setback", + "action": "L" + }, + { + "label": "Next: Experience Setback", + "action": "L" + } + ], + "consequences": [] + }, + "L": { + "title": "Experience Setback", + "content": "As they exit the chamber, the ruins begin to collapse. What would you like to do next?", + "items": [ + { + "label": "Earn Reward", + "action": "M" + }, + { + "label": "Next: Earn Reward", + "action": "M" + } + ], + "consequences": [] + }, + "M": { + "title": "Earn Reward", + "content": "They find a hidden cache containing valuable treasures. What would you like to do next?", + "items": [ + { + "label": "Uncover Mystery", + "action": "N" + }, + { + "label": "Next: Uncover Mystery", + "action": "N" + } + ], + "consequences": [] + }, + "N": { + "title": "Uncover Mystery", + "content": "They discover a scroll revealing the existence of other relics. What would you like to do next?", + "items": [ + { + "label": "Form Alliance", + "action": "O" + }, + { + "label": "Next: Form Alliance", + "action": "O" + } + ], + "consequences": [] + }, + "O": { + "title": "Form Alliance", + "content": "Aria and Eamon pledge to work together to find the remaining relics. What would you like to do next?", + "items": [ + { + "label": "Face Betrayal", + "action": "P" + }, + { + "label": "Next: Face Betrayal", + "action": "P" + } + ], + "consequences": [] + }, + "P": { + "title": "Face Betrayal", + "content": "They encounter a former ally who betrays them. What would you like to do next?", + "items": [ + { + "label": "Confront Nemesis", + "action": "Q" + }, + { + "label": "Next: Confront Nemesis", + "action": "Q" + } + ], + "consequences": [] + }, + "Q": { + "title": "Confront Nemesis", + "content": "They confront the main antagonist, a powerful sorcerer. What would you like to do next?", + "items": [ + { + "label": "Make Discovery", + "action": "R" + }, + { + "label": "Next: Make Discovery", + "action": "R" + } + ], + "consequences": [] + }, + "R": { + "title": "Make Discovery", + "content": "They discover an ancient prophecy foretelling their quest. What would you like to do next?", + "items": [ + { + "label": "Overcome Loss", + "action": "S" + }, + { + "label": "Next: Overcome Loss", + "action": "S" + } + ], + "consequences": [] + }, + "S": { + "title": "Overcome Loss", + "content": "They mourn the loss of allies and friends who fell during their quest. What would you like to do next?", + "items": [ + { + "label": "Achieve Victory", + "action": "T" + }, + { + "label": "Next: Achieve Victory", + "action": "T" + } + ], + "consequences": [] + }, + "T": { + "title": "Achieve Victory", + "content": "With the sorcerer defeated and the relics secured, Aria and Eamon achieve a great victory. What would you like to do next?", + "items": [ + { + "label": "Continue the Adventure", + "action": "U" + }, + { + "label": "Next: Continue the Adventure", + "action": "U" + } + ], + "consequences": [] + }, + "U": { + "title": "Continue the Adventure", + "content": "Aria and Eamon continue their quest, knowing that their adventure is far from over.", + "items": [], + "consequences": [] + } + } + }, + { + name: "substory2", + x: 700, + y: 700, + collisionType: "smmodal", + modalStates: { + "A": { + "title": "Event 1", + "content": "You are at Event 1. What would you like to do next?", + "items": [ + { + "label": "To Event 2", + "action": "B" + }, + { + "label": "Next: Event 2", + "action": "B" + } + ], + "consequences": [] + }, + "B": { + "title": "Event 2", + "content": "You are at Event 2. What would you like to do next?", + "items": [ + { + "label": "To Event 7", + "action": "G" + }, + { + "label": "To Event 1", + "action": "A" + }, + { + "label": "To Event 6", + "action": "F" + }, + { + "label": "Next: Event 3", + "action": "C" + } + ], + "consequences": [] + }, + "C": { + "title": "Event 3", + "content": "You are at Event 3. What would you like to do next?", + "items": [ + { + "label": "To Event 4", + "action": "D" + }, + { + "label": "To Event 7", + "action": "G" + }, + { + "label": "Next: Event 4", + "action": "D" + } + ], + "consequences": [] + }, + "D": { + "title": "Event 4", + "content": "You are at Event 4. What would you like to do next?", + "items": [ + { + "label": "To Event 7", + "action": "G" + }, + { + "label": "To Event 6", + "action": "F" + }, + { + "label": "Next: Event 5", + "action": "E" + } + ], + "consequences": [] + }, + "E": { + "title": "Event 5", + "content": "You are at Event 5. What would you like to do next?", + "items": [ + { + "label": "To Event 6", + "action": "F" + }, + { + "label": "To Event 1", + "action": "A" + }, + { + "label": "Next: Event 6", + "action": "F" + } + ], + "consequences": [] + }, + "F": { + "title": "Event 6", + "content": "You are at Event 6. What would you like to do next?", + "items": [ + { + "label": "Next: Event 7", + "action": "G" + } + ], + "consequences": [] + }, + "G": { + "title": "Event 7", + "content": "You are at Event 7. What would you like to do next?", + "items": [], + "consequences": [] + } + } + }, + ], + }, + ], + actions: { + Buybook() { + // Logic to slay the dragon + }, + }, + stateobjects: { + // For location based story within a part + }, + }, + }; + + /* src\MovingDotSpacePortfromReact.svelte generated by Svelte v3.59.2 */ + + const { Object: Object_1$2, console: console_1$7 } = globals; + + const file$e = "src\\MovingDotSpacePortfromReact.svelte"; + + function get_each_context$b(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[31] = list[i]; + return child_ctx; + } + + function get_each_context_1$6(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[34] = list[i]; + return child_ctx; + } + + // (321:4) {#each themeKeys as key} + function create_each_block_1$6(ctx) { + let option; + let t_value = /*key*/ ctx[34] + ""; + let t; + + const block = { + c: function create() { + option = element$1("option"); + t = text(t_value); + option.__value = /*key*/ ctx[34]; + option.value = option.__value; + add_location(option, file$e, 321, 8, 13237); + }, + m: function mount(target, anchor) { + insert_dev(target, option, anchor); + append_dev(option, t); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(option); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_1$6.name, + type: "each", + source: "(321:4) {#each themeKeys as key}", + ctx + }); + + return block; + } + + // (334:4) {#each $targets as target (target.name)} + function create_each_block$b(key_1, ctx) { + let first; + let target; + let t0; + let span; + let t1_value = /*target*/ ctx[31].name + ""; + let t1; + let current; + + target = new MovingDotTargetPortfromReact({ + props: { position: /*target*/ ctx[31] }, + $$inline: true + }); + + const block = { + key: key_1, + first: null, + c: function create() { + first = empty(); + create_component(target.$$.fragment); + t0 = space(); + span = element$1("span"); + t1 = text(t1_value); + set_style(span, "position", "absolute"); + set_style(span, "left", /*target*/ ctx[31].x + "px"); + set_style(span, "top", /*target*/ ctx[31].y + "px"); + add_location(span, file$e, 335, 8, 14538); + this.first = first; + }, + m: function mount(target$1, anchor) { + insert_dev(target$1, first, anchor); + mount_component(target, target$1, anchor); + insert_dev(target$1, t0, anchor); + insert_dev(target$1, span, anchor); + append_dev(span, t1); + current = true; + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + const target_changes = {}; + if (dirty[0] & /*$targets*/ 4096) target_changes.position = /*target*/ ctx[31]; + target.$set(target_changes); + if ((!current || dirty[0] & /*$targets*/ 4096) && t1_value !== (t1_value = /*target*/ ctx[31].name + "")) set_data_dev(t1, t1_value); + + if (!current || dirty[0] & /*$targets*/ 4096) { + set_style(span, "left", /*target*/ ctx[31].x + "px"); + } + + if (!current || dirty[0] & /*$targets*/ 4096) { + set_style(span, "top", /*target*/ ctx[31].y + "px"); + } + }, + i: function intro(local) { + if (current) return; + transition_in(target.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(target.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + if (detaching) detach_dev(first); + destroy_component(target, detaching); + if (detaching) detach_dev(t0); + if (detaching) detach_dev(span); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$b.name, + type: "each", + source: "(334:4) {#each $targets as target (target.name)}", + ctx + }); + + return block; + } + + // (340:4) {#if isModalOpen} + function create_if_block_1$3(ctx) { + let modal; + let current; + + modal = new MovingDotSpaceSimpleModal({ + props: { + isOpen: /*isModalOpen*/ ctx[3], + onClose: /*handleModalClose*/ ctx[20], + title: /*currentcollisiontitletext*/ ctx[5], + content: /*currentcollisiontext*/ ctx[6], + items: /*currentcollisionitems*/ ctx[7], + currentTheme: /*currentTheme*/ ctx[10], + themeActions: themes[/*currentTheme*/ ctx[10]].actions + }, + $$inline: true + }); + + const block = { + c: function create() { + create_component(modal.$$.fragment); + }, + m: function mount(target, anchor) { + mount_component(modal, target, anchor); + current = true; + }, + p: function update(ctx, dirty) { + const modal_changes = {}; + if (dirty[0] & /*isModalOpen*/ 8) modal_changes.isOpen = /*isModalOpen*/ ctx[3]; + if (dirty[0] & /*currentcollisiontitletext*/ 32) modal_changes.title = /*currentcollisiontitletext*/ ctx[5]; + if (dirty[0] & /*currentcollisiontext*/ 64) modal_changes.content = /*currentcollisiontext*/ ctx[6]; + if (dirty[0] & /*currentcollisionitems*/ 128) modal_changes.items = /*currentcollisionitems*/ ctx[7]; + if (dirty[0] & /*currentTheme*/ 1024) modal_changes.currentTheme = /*currentTheme*/ ctx[10]; + if (dirty[0] & /*currentTheme*/ 1024) modal_changes.themeActions = themes[/*currentTheme*/ ctx[10]].actions; + modal.$set(modal_changes); + }, + i: function intro(local) { + if (current) return; + transition_in(modal.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(modal.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(modal, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_1$3.name, + type: "if", + source: "(340:4) {#if isModalOpen}", + ctx + }); + + return block; + } + + // (344:4) {#if isSMModalOpen} + function create_if_block$6(ctx) { + let smmodal; + let current; + + smmodal = new SimpleStateMachineModal({ + props: { + isOpen: /*isSMModalOpen*/ ctx[4], + onClose: /*handleModalClose*/ ctx[20], + modalStates: /*currentstatemodalstates*/ ctx[9] + }, + $$inline: true + }); + + const block = { + c: function create() { + create_component(smmodal.$$.fragment); + }, + m: function mount(target, anchor) { + mount_component(smmodal, target, anchor); + current = true; + }, + p: function update(ctx, dirty) { + const smmodal_changes = {}; + if (dirty[0] & /*isSMModalOpen*/ 16) smmodal_changes.isOpen = /*isSMModalOpen*/ ctx[4]; + if (dirty[0] & /*currentstatemodalstates*/ 512) smmodal_changes.modalStates = /*currentstatemodalstates*/ ctx[9]; + smmodal.$set(smmodal_changes); + }, + i: function intro(local) { + if (current) return; + transition_in(smmodal.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(smmodal.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(smmodal, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block$6.name, + type: "if", + source: "(344:4) {#if isSMModalOpen}", + ctx + }); + + return block; + } + + // (355:0) + function create_default_slot$1(ctx) { + let h10; + let t1; + let fighttest; + let t2; + let fightasalltest; + let t3; + let modaltest; + let t4; + let h11; + let t6; + let findtest; + let t7; + let h12; + let t9; + let ordertest; + let current; + fighttest = new MovingDotSpaceGameFight({ $$inline: true }); + fightasalltest = new MovingDotSpaceGameFightMultiTheme({ $$inline: true }); + modaltest = new MovingDotSpaceModalBrainstorm({ $$inline: true }); + findtest = new MovingDotSpaceGameFind({ $$inline: true }); + ordertest = new MovingDotSpaceGameOrder({ $$inline: true }); + + const block = { + c: function create() { + h10 = element$1("h1"); + h10.textContent = "Expand this to allow up to 100 fighters on each side"; + t1 = space(); + create_component(fighttest.$$.fragment); + t2 = space(); + create_component(fightasalltest.$$.fragment); + t3 = space(); + create_component(modaltest.$$.fragment); + t4 = space(); + h11 = element$1("h1"); + h11.textContent = "Find games are choices between similar looking items missing information with limited information (Luck = More Targets)"; + t6 = space(); + create_component(findtest.$$.fragment); + t7 = space(); + h12 = element$1("h1"); + h12.textContent = "Find out/ make sense / Resolve Conflict = order mixed up and"; + t9 = space(); + create_component(ordertest.$$.fragment); + add_location(h10, file$e, 355, 4, 15536); + add_location(h11, file$e, 359, 4, 15665); + add_location(h12, file$e, 361, 4, 15818); + }, + m: function mount(target, anchor) { + insert_dev(target, h10, anchor); + insert_dev(target, t1, anchor); + mount_component(fighttest, target, anchor); + insert_dev(target, t2, anchor); + mount_component(fightasalltest, target, anchor); + insert_dev(target, t3, anchor); + mount_component(modaltest, target, anchor); + insert_dev(target, t4, anchor); + insert_dev(target, h11, anchor); + insert_dev(target, t6, anchor); + mount_component(findtest, target, anchor); + insert_dev(target, t7, anchor); + insert_dev(target, h12, anchor); + insert_dev(target, t9, anchor); + mount_component(ordertest, target, anchor); + current = true; + }, + p: noop$2, + i: function intro(local) { + if (current) return; + transition_in(fighttest.$$.fragment, local); + transition_in(fightasalltest.$$.fragment, local); + transition_in(modaltest.$$.fragment, local); + transition_in(findtest.$$.fragment, local); + transition_in(ordertest.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(fighttest.$$.fragment, local); + transition_out(fightasalltest.$$.fragment, local); + transition_out(modaltest.$$.fragment, local); + transition_out(findtest.$$.fragment, local); + transition_out(ordertest.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + if (detaching) detach_dev(h10); + if (detaching) detach_dev(t1); + destroy_component(fighttest, detaching); + if (detaching) detach_dev(t2); + destroy_component(fightasalltest, detaching); + if (detaching) detach_dev(t3); + destroy_component(modaltest, detaching); + if (detaching) detach_dev(t4); + if (detaching) detach_dev(h11); + if (detaching) detach_dev(t6); + destroy_component(findtest, detaching); + if (detaching) detach_dev(t7); + if (detaching) detach_dev(h12); + if (detaching) detach_dev(t9); + destroy_component(ordertest, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot$1.name, + type: "slot", + source: "(355:0) ", + ctx + }); + + return block; + } + + function create_fragment$e(ctx) { + let t0; + let select; + let t1; + let button0; + let t3; + let button1; + let t5; + let dotgamethememanager; + let t6; + let div1; + let canvas_1; + let t7; + let movingdot; + let t8; + let div0; + let t9; + let t10_value = /*$dotPosition*/ ctx[0].x + ""; + let t10; + let t11; + let t12_value = /*$dotPosition*/ ctx[0].y + ""; + let t12; + let t13; + let t14; + let each_blocks = []; + let each1_lookup = new Map(); + let t15; + let t16; + let t17; + let h4; + let t19; + let movingdotstats; + let t20; + let h1; + let t22; + let hr; + let t23; + let simplecollapsible; + let current; + let mounted; + let dispose; + let each_value_1 = /*themeKeys*/ ctx[15]; + validate_each_argument(each_value_1); + let each_blocks_1 = []; + + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks_1[i] = create_each_block_1$6(get_each_context_1$6(ctx, each_value_1, i)); + } + + dotgamethememanager = new MovingDotSpaceThemeManager({ + props: { + ChangedContentPlaceholder: /*ChangedContentPlaceholdertoSend*/ ctx[1] + }, + $$inline: true + }); + + let movingdot_props = { + position: /*$dotPosition*/ ctx[0], + boundaries: /*boundaries*/ ctx[14] + }; + + movingdot = new MovingDotPortfromReact({ props: movingdot_props, $$inline: true }); + /*movingdot_binding*/ ctx[24](movingdot); + movingdot.$on("move", /*move_handler*/ ctx[25]); + let each_value = /*$targets*/ ctx[12]; + validate_each_argument(each_value); + const get_key = ctx => /*target*/ ctx[31].name; + validate_each_keys(ctx, each_value, get_each_context$b, get_key); + + for (let i = 0; i < each_value.length; i += 1) { + let child_ctx = get_each_context$b(ctx, each_value, i); + let key = get_key(child_ctx); + each1_lookup.set(key, each_blocks[i] = create_each_block$b(key, child_ctx)); + } + + let if_block0 = /*isModalOpen*/ ctx[3] && create_if_block_1$3(ctx); + let if_block1 = /*isSMModalOpen*/ ctx[4] && create_if_block$6(ctx); + movingdotstats = new MovingDotStatDisplay({ $$inline: true }); + + simplecollapsible = new SimpleCollapsible({ + props: { + title: "Some practice modal ideas - how to solve the import issue (have to import all modals all the time?)", + $$slots: { default: [create_default_slot$1] }, + $$scope: { ctx } + }, + $$inline: true + }); + + const block = { + c: function create() { + t0 = text("Game Selector\r\n"); + select = element$1("select"); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].c(); + } + + t1 = text("\r\n | \r\n"); + button0 = element$1("button"); + button0.textContent = "Test load for the auto gen config from streamlined JSON assist"; + t3 = space(); + button1 = element$1("button"); + button1.textContent = "Test load for the auto gen config from Graph data to JSON Conversion"; + t5 = space(); + create_component(dotgamethememanager.$$.fragment); + t6 = space(); + div1 = element$1("div"); + canvas_1 = element$1("canvas"); + t7 = space(); + create_component(movingdot.$$.fragment); + t8 = space(); + div0 = element$1("div"); + t9 = text("Minor Game Events Log for player ||| Position for Developer "); + t10 = text(t10_value); + t11 = space(); + t12 = text(t12_value); + t13 = text(" - TODO - Story Line / Avatars? / Clock System ||| For Job Experience focused Stats can be Emotions Stress Frustration Relief Tiredness Confidence (Percieved Skill) Experience (Actual Skill)"); + t14 = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t15 = space(); + if (if_block0) if_block0.c(); + t16 = space(); + if (if_block1) if_block1.c(); + t17 = space(); + h4 = element$1("h4"); + h4.textContent = "Gameplay Dependent:"; + t19 = space(); + create_component(movingdotstats.$$.fragment); + t20 = space(); + h1 = element$1("h1"); + h1.textContent = "Simple Game is normally just story with fighting and traversing mechanics repeated in between videos with as heavy customisation of any part of the game as possible"; + t22 = space(); + hr = element$1("hr"); + t23 = space(); + create_component(simplecollapsible.$$.fragment); + if (/*currentTheme*/ ctx[10] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[22].call(select)); + add_location(select, file$e, 319, 0, 13139); + add_location(button0, file$e, 325, 0, 13302); + add_location(button1, file$e, 326, 0, 13416); + set_style(canvas_1, "width", "100%"); + set_style(canvas_1, "height", "100%"); + attr_dev(canvas_1, "tabindex", "0"); + add_location(canvas_1, file$e, 330, 4, 13874); + attr_dev(div0, "id", "overlayText"); + attr_dev(div0, "class", "svelte-c2nwl9"); + add_location(div0, file$e, 332, 4, 14132); + attr_dev(div1, "id", "game-container"); + set_style(div1, "position", "relative"); + set_style(div1, "width", "100%"); + set_style(div1, "height", "100vh"); + set_style(div1, "border", "1px solid black"); + set_style(div1, "overflow", "hidden"); + set_style(div1, "background-image", "url('" + /*CurrentGameBackground*/ ctx[11] + "')"); + set_style(div1, "background-size", "cover"); + set_style(div1, "background-position", "center"); + add_location(div1, file$e, 329, 0, 13641); + add_location(h4, file$e, 349, 0, 15169); + add_location(h1, file$e, 351, 0, 15220); + add_location(hr, file$e, 352, 0, 15395); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, t0, anchor); + insert_dev(target, select, anchor); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + if (each_blocks_1[i]) { + each_blocks_1[i].m(select, null); + } + } + + select_option(select, /*currentTheme*/ ctx[10], true); + insert_dev(target, t1, anchor); + insert_dev(target, button0, anchor); + insert_dev(target, t3, anchor); + insert_dev(target, button1, anchor); + insert_dev(target, t5, anchor); + mount_component(dotgamethememanager, target, anchor); + insert_dev(target, t6, anchor); + insert_dev(target, div1, anchor); + append_dev(div1, canvas_1); + /*canvas_1_binding*/ ctx[23](canvas_1); + append_dev(div1, t7); + mount_component(movingdot, div1, null); + append_dev(div1, t8); + append_dev(div1, div0); + append_dev(div0, t9); + append_dev(div0, t10); + append_dev(div0, t11); + append_dev(div0, t12); + append_dev(div0, t13); + append_dev(div1, t14); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div1, null); + } + } + + append_dev(div1, t15); + if (if_block0) if_block0.m(div1, null); + append_dev(div1, t16); + if (if_block1) if_block1.m(div1, null); + insert_dev(target, t17, anchor); + insert_dev(target, h4, anchor); + insert_dev(target, t19, anchor); + mount_component(movingdotstats, target, anchor); + insert_dev(target, t20, anchor); + insert_dev(target, h1, anchor); + insert_dev(target, t22, anchor); + insert_dev(target, hr, anchor); + insert_dev(target, t23, anchor); + mount_component(simplecollapsible, target, anchor); + current = true; + + if (!mounted) { + dispose = [ + listen_dev(select, "change", /*select_change_handler*/ ctx[22]), + listen_dev(select, "change", /*changeTheme*/ ctx[16], false, false, false, false), + listen_dev(button0, "click", /*loadexperimentaltheme*/ ctx[17], false, false, false, false), + listen_dev(button1, "click", /*loadexperimentalthemefromgraphtoJSON*/ ctx[18], false, false, false, false), + listen_dev(canvas_1, "click", /*handleSpaceClick*/ ctx[19], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*themeKeys*/ 32768) { + each_value_1 = /*themeKeys*/ ctx[15]; + validate_each_argument(each_value_1); + let i; + + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1$6(ctx, each_value_1, i); + + if (each_blocks_1[i]) { + each_blocks_1[i].p(child_ctx, dirty); + } else { + each_blocks_1[i] = create_each_block_1$6(child_ctx); + each_blocks_1[i].c(); + each_blocks_1[i].m(select, null); + } + } + + for (; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].d(1); + } + + each_blocks_1.length = each_value_1.length; + } + + if (dirty[0] & /*currentTheme, themeKeys*/ 33792) { + select_option(select, /*currentTheme*/ ctx[10]); + } + + const dotgamethememanager_changes = {}; + if (dirty[0] & /*ChangedContentPlaceholdertoSend*/ 2) dotgamethememanager_changes.ChangedContentPlaceholder = /*ChangedContentPlaceholdertoSend*/ ctx[1]; + dotgamethememanager.$set(dotgamethememanager_changes); + const movingdot_changes = {}; + if (dirty[0] & /*$dotPosition*/ 1) movingdot_changes.position = /*$dotPosition*/ ctx[0]; + movingdot.$set(movingdot_changes); + if ((!current || dirty[0] & /*$dotPosition*/ 1) && t10_value !== (t10_value = /*$dotPosition*/ ctx[0].x + "")) set_data_dev(t10, t10_value); + if ((!current || dirty[0] & /*$dotPosition*/ 1) && t12_value !== (t12_value = /*$dotPosition*/ ctx[0].y + "")) set_data_dev(t12, t12_value); + + if (dirty[0] & /*$targets*/ 4096) { + each_value = /*$targets*/ ctx[12]; + validate_each_argument(each_value); + group_outros(); + validate_each_keys(ctx, each_value, get_each_context$b, get_key); + each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each1_lookup, div1, outro_and_destroy_block, create_each_block$b, t15, get_each_context$b); + check_outros(); + } + + if (/*isModalOpen*/ ctx[3]) { + if (if_block0) { + if_block0.p(ctx, dirty); + + if (dirty[0] & /*isModalOpen*/ 8) { + transition_in(if_block0, 1); + } + } else { + if_block0 = create_if_block_1$3(ctx); + if_block0.c(); + transition_in(if_block0, 1); + if_block0.m(div1, t16); + } + } else if (if_block0) { + group_outros(); + + transition_out(if_block0, 1, 1, () => { + if_block0 = null; + }); + + check_outros(); + } + + if (/*isSMModalOpen*/ ctx[4]) { + if (if_block1) { + if_block1.p(ctx, dirty); + + if (dirty[0] & /*isSMModalOpen*/ 16) { + transition_in(if_block1, 1); + } + } else { + if_block1 = create_if_block$6(ctx); + if_block1.c(); + transition_in(if_block1, 1); + if_block1.m(div1, null); + } + } else if (if_block1) { + group_outros(); + + transition_out(if_block1, 1, 1, () => { + if_block1 = null; + }); + + check_outros(); + } + + if (!current || dirty[0] & /*CurrentGameBackground*/ 2048) { + set_style(div1, "background-image", "url('" + /*CurrentGameBackground*/ ctx[11] + "')"); + } + + const simplecollapsible_changes = {}; + + if (dirty[1] & /*$$scope*/ 64) { + simplecollapsible_changes.$$scope = { dirty, ctx }; + } + + simplecollapsible.$set(simplecollapsible_changes); + }, + i: function intro(local) { + if (current) return; + transition_in(dotgamethememanager.$$.fragment, local); + transition_in(movingdot.$$.fragment, local); + + for (let i = 0; i < each_value.length; i += 1) { + transition_in(each_blocks[i]); + } + + transition_in(if_block0); + transition_in(if_block1); + transition_in(movingdotstats.$$.fragment, local); + transition_in(simplecollapsible.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(dotgamethememanager.$$.fragment, local); + transition_out(movingdot.$$.fragment, local); + + for (let i = 0; i < each_blocks.length; i += 1) { + transition_out(each_blocks[i]); + } + + transition_out(if_block0); + transition_out(if_block1); + transition_out(movingdotstats.$$.fragment, local); + transition_out(simplecollapsible.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + if (detaching) detach_dev(t0); + if (detaching) detach_dev(select); + destroy_each(each_blocks_1, detaching); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(button0); + if (detaching) detach_dev(t3); + if (detaching) detach_dev(button1); + if (detaching) detach_dev(t5); + destroy_component(dotgamethememanager, detaching); + if (detaching) detach_dev(t6); + if (detaching) detach_dev(div1); + /*canvas_1_binding*/ ctx[23](null); + /*movingdot_binding*/ ctx[24](null); + destroy_component(movingdot); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].d(); + } + + if (if_block0) if_block0.d(); + if (if_block1) if_block1.d(); + if (detaching) detach_dev(t17); + if (detaching) detach_dev(h4); + if (detaching) detach_dev(t19); + destroy_component(movingdotstats, detaching); + if (detaching) detach_dev(t20); + if (detaching) detach_dev(h1); + if (detaching) detach_dev(t22); + if (detaching) detach_dev(hr); + if (detaching) detach_dev(t23); + destroy_component(simplecollapsible, detaching); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$e.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$e($$self, $$props, $$invalidate) { + let $dotPosition; + let $targets; + let $autogenconfigtestsmmdoalfromgraph; + let $autogenconfigtest; + validate_store(targets, 'targets'); + component_subscribe($$self, targets, $$value => $$invalidate(12, $targets = $$value)); + validate_store(autogenconfigtestsmmdoalfromgraph, 'autogenconfigtestsmmdoalfromgraph'); + component_subscribe($$self, autogenconfigtestsmmdoalfromgraph, $$value => $$invalidate(27, $autogenconfigtestsmmdoalfromgraph = $$value)); + validate_store(autogenconfigtest, 'autogenconfigtest'); + component_subscribe($$self, autogenconfigtest, $$value => $$invalidate(28, $autogenconfigtest = $$value)); + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('MovingDotSpacePortfromReact', slots, []); + let ChangedContentPlaceholdertoSend = "No changes"; + let canvas; + let dotPosition = writable({ x: 900, y: 450 }); + validate_store(dotPosition, 'dotPosition'); + component_subscribe($$self, dotPosition, value => $$invalidate(0, $dotPosition = value)); + let boundaries = { maxX: 1835, maxY: 890, minX: 0, minY: 0 }; + let isModalOpen = false; + let isSMModalOpen = false; + let currentcollisiontitletext; + let currentcollisiontext; + let currentcollisionitems = []; + let movingDotElement; + let currentstatemodalstates; + let currentTheme = 'Default'; // default theme + let currentThemeStage = 0; + let themeKeys = Object.keys(themes); + let CurrentGameBackground = themes[currentTheme].background; //GameBackgrounds[0].url; + inventory.set(themes[currentTheme].inventory); + skills.set(themes[currentTheme].skills); + objectives.set(themes[currentTheme].story[0].objectives); + + targets.set([ + ...themes[currentTheme].persistentTargets, + ...themes[currentTheme].story[0].targets + ]); + + themeactions.set(themes[currentTheme].actions); + + //$: console.log($themeactions) + // objectives.set(themes[currentTheme].objectives); + // targets.set(themes[currentTheme].storyparttargets[0]) + // function changeTheme(event) { + // currentTheme = event.target.value; + // const theme = themes[currentTheme]; + // inventory.set(theme.inventory); + // skills.set(theme.skills); + // objectives.set(theme.objectives); + // currentThemeStage = 0; // Resetting currentThemeStage to 0 + // targets.set(theme.storyparttargets[0]); + // CurrentGameBackground = theme.background + // ChangedContentPlaceholdertoSend = "TODO is all other variables to change" + // } + function changeTheme(event) { + $$invalidate(10, currentTheme = event.target.value); + console.log(currentTheme); + const theme = themes[currentTheme]; + console.log(theme); + inventory.set(theme.inventory); + skills.set(theme.skills); + themeactions.set(themes.actions); + currentThemeStage = 0; + const initialStory = theme.story.find(part => part.part === 0); + + if (initialStory) { + objectives.set(initialStory.objectives); + + const uniqueTargets = [ + ...theme.persistentTargets, + ...initialStory.targets.filter(target => !theme.persistentTargets.some(persistentTarget => persistentTarget.name === target.name)) + ]; + + targets.set(uniqueTargets); + } else { + // Handle the case when no initial story part is found + objectives.set([]); + + targets.set([...theme.persistentTargets]); + } + + $$invalidate(11, CurrentGameBackground = theme.background); + $$invalidate(1, ChangedContentPlaceholdertoSend = "TODO is all other variables to change"); + } + + function loadexperimentaltheme() { + if ($autogenconfigtest.story) { + inventory.set($autogenconfigtest.inventory); + skills.set($autogenconfigtest.skills); + themeactions.set($autogenconfigtest.actions); + currentThemeStage = 0; + const initialStory = $autogenconfigtest.story.find(part => part.part === 0); + + if (initialStory) { + objectives.set(initialStory.objectives); + + const uniqueTargets = [ + ...$autogenconfigtest.persistentTargets, + ...initialStory.targets.filter(target => !$autogenconfigtest.persistentTargets.some(persistentTarget => persistentTarget.name === target.name)) + ]; + + targets.set(uniqueTargets); + } else { + // Handle the case when no initial story part is found + objectives.set([]); + + targets.set([...$autogenconfigtest.persistentTargets]); + } + + $$invalidate(11, CurrentGameBackground = $autogenconfigtest.background); + $$invalidate(1, ChangedContentPlaceholdertoSend = "TODO is all other variables to change"); + } else { + alert("Merge not performed"); + } + } + + function loadexperimentalthemefromgraphtoJSON() { + if ($autogenconfigtestsmmdoalfromgraph.story) { + inventory.set($autogenconfigtestsmmdoalfromgraph.inventory); + skills.set($autogenconfigtestsmmdoalfromgraph.skills); + themeactions.set($autogenconfigtestsmmdoalfromgraph.actions); + currentThemeStage = 0; + const initialStory = $autogenconfigtestsmmdoalfromgraph.story.find(part => part.part === 0); + + if (initialStory) { + objectives.set(initialStory.objectives); + + const uniqueTargets = [ + ...$autogenconfigtestsmmdoalfromgraph.persistentTargets, + ...initialStory.targets.filter(target => !$autogenconfigtestsmmdoalfromgraph.persistentTargets.some(persistentTarget => persistentTarget.name === target.name)) + ]; + + targets.set(uniqueTargets); + } else { + // Handle the case when no initial story part is found + objectives.set([]); + + targets.set([...$autogenconfigtestsmmdoalfromgraph.persistentTargets]); + } + + $$invalidate(11, CurrentGameBackground = $autogenconfigtestsmmdoalfromgraph.background); + $$invalidate(1, ChangedContentPlaceholdertoSend = "TODO is all other variables to change"); + } else { + alert("Merge not performed"); + } + } + + function handleSpaceClick() { + //console.log('Container clicked!', event); + movingDotElement.focusDot(); + } + + function handleModalClose() { + $$invalidate(3, isModalOpen = false); + $$invalidate(4, isSMModalOpen = false); + movingDotElement.focusDot(); + } + + function updateDotPosition(newX, newY) { + dotPosition.set({ x: newX, y: newY }); + } + + // Collision check function + const checkCollision = dotPos => { + $targets.forEach(target => { + if (dotPos.x < target.x + 10 && dotPos.x + 10 > target.x && dotPos.y < target.y + 10 && dotPos.y + 10 > target.y) { + handleCollision(target); + } + }); + }; + + // Handle collision based on the target object + const handleCollision = target => { + if (target.subtargets) { + alert("Subtargets found. Can be used as discovered locations or just splitting one target into a self contained set of targets. (variable logged in console)"); + console.log(target.subtargets); + } //eventually use to temporarily act as the all targets in the map which can each all have smmodals + + switch (target.collisionType) { + case "": + console.log("Nothing Happenedddd"); + break; + case "alert": + alert(target.collisiontext); + break; + case "decision": + if (confirm(target.collisiontext)) { + alert("You said yes"); + } else { + alert("You said no"); + } + break; + case "modal": + $$invalidate(3, isModalOpen = true); + $$invalidate(5, currentcollisiontitletext = target.modalConfig.title); + $$invalidate(6, currentcollisiontext = target.modalConfig.content); + $$invalidate(7, currentcollisionitems = target.modalConfig.actions); + break; + case "smmodal": + $$invalidate(4, isSMModalOpen = true); + console.log('smmodal'); + console.log(target.modalStates); + $$invalidate(9, currentstatemodalstates = target.modalStates); + //currentcollisiontitletext = target.modalConfig.title; + //currentcollisiontext = target.modalConfig.content; + //currentcollisionitems = target.modalConfig.actions; + break; + case "storypartchange": + currentThemeStage = target.transitionToPart; + const newStoryPart = themes[currentTheme].story.find(part => part.part === currentThemeStage); + if (newStoryPart) { + objectives.set(newStoryPart.objectives); + targets.set([...themes[currentTheme].persistentTargets, ...newStoryPart.targets]); + } + // currentThemeStage = target.newStage; + // targets.set(themes[currentTheme].storyparttargets[currentThemeStage]) + break; + case "requirementsgated": + const currentObjectives = themes[currentTheme].story[currentThemeStage].objectives; + const allObjectivesCompleted = currentObjectives.every(objective => objective.complete); + if (allObjectivesCompleted && target.requirements > 5) { + //if (target.requirements > 5){ + alert(target.collisiontext); + } else { + alert("You have not journeyed enough to explore this area yet (Stats required: and an inventory item)"); + } + break; + } // Handle other permanent UI elements here + }; // ... + //ChatGPT Suggested Options + // Change the background color of the canvas or a specific element. + // case "changeBackgroundColor": + + const writable_props = []; + + Object_1$2.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$7.warn(` was created with unknown prop '${key}'`); + }); + + function select_change_handler() { + currentTheme = select_value(this); + $$invalidate(10, currentTheme); + $$invalidate(15, themeKeys); + } + + function canvas_1_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + canvas = $$value; + $$invalidate(2, canvas); + }); + } + + function movingdot_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + movingDotElement = $$value; + $$invalidate(8, movingDotElement); + }); + } + + const move_handler = e => updateDotPosition(e.detail.x, e.detail.y); + + $$self.$capture_state = () => ({ + onMount, + writable, + MovingDot: MovingDotPortfromReact, + Target: MovingDotTargetPortfromReact, + Modal: MovingDotSpaceSimpleModal, + SMModal: SimpleStateMachineModal, + MovingDotStats: MovingDotStatDisplay, + DotGameThemeManager: MovingDotSpaceThemeManager, + FightTest: MovingDotSpaceGameFight, + FightasAllTest: MovingDotSpaceGameFightMultiTheme, + ModalTest: MovingDotSpaceModalBrainstorm, + FindTest: MovingDotSpaceGameFind, + OrderTest: MovingDotSpaceGameOrder, + SimpleCollapsible, + themes, + inventory, + skills, + objectives, + targets, + themeactions, + autogenconfigtest, + autogenconfigtestsmmdoalfromgraph, + ChangedContentPlaceholdertoSend, + canvas, + dotPosition, + boundaries, + isModalOpen, + isSMModalOpen, + currentcollisiontitletext, + currentcollisiontext, + currentcollisionitems, + movingDotElement, + currentstatemodalstates, + currentTheme, + currentThemeStage, + themeKeys, + CurrentGameBackground, + changeTheme, + loadexperimentaltheme, + loadexperimentalthemefromgraphtoJSON, + handleSpaceClick, + handleModalClose, + updateDotPosition, + checkCollision, + handleCollision, + $dotPosition, + $targets, + $autogenconfigtestsmmdoalfromgraph, + $autogenconfigtest + }); + + $$self.$inject_state = $$props => { + if ('ChangedContentPlaceholdertoSend' in $$props) $$invalidate(1, ChangedContentPlaceholdertoSend = $$props.ChangedContentPlaceholdertoSend); + if ('canvas' in $$props) $$invalidate(2, canvas = $$props.canvas); + if ('dotPosition' in $$props) $$invalidate(13, dotPosition = $$props.dotPosition); + if ('boundaries' in $$props) $$invalidate(14, boundaries = $$props.boundaries); + if ('isModalOpen' in $$props) $$invalidate(3, isModalOpen = $$props.isModalOpen); + if ('isSMModalOpen' in $$props) $$invalidate(4, isSMModalOpen = $$props.isSMModalOpen); + if ('currentcollisiontitletext' in $$props) $$invalidate(5, currentcollisiontitletext = $$props.currentcollisiontitletext); + if ('currentcollisiontext' in $$props) $$invalidate(6, currentcollisiontext = $$props.currentcollisiontext); + if ('currentcollisionitems' in $$props) $$invalidate(7, currentcollisionitems = $$props.currentcollisionitems); + if ('movingDotElement' in $$props) $$invalidate(8, movingDotElement = $$props.movingDotElement); + if ('currentstatemodalstates' in $$props) $$invalidate(9, currentstatemodalstates = $$props.currentstatemodalstates); + if ('currentTheme' in $$props) $$invalidate(10, currentTheme = $$props.currentTheme); + if ('currentThemeStage' in $$props) currentThemeStage = $$props.currentThemeStage; + if ('themeKeys' in $$props) $$invalidate(15, themeKeys = $$props.themeKeys); + if ('CurrentGameBackground' in $$props) $$invalidate(11, CurrentGameBackground = $$props.CurrentGameBackground); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + $$self.$$.update = () => { + if ($$self.$$.dirty[0] & /*$dotPosition*/ 1) { + // document.body.style.backgroundColor = target.color; + // break; + // Play a sound effect. You'll need to pre-load these sounds. + // case "playSound": + // new Audio(target.soundUrl).play(); + // break; + // Redirect the user to a different URL. + // case "redirect": + // window.location.href = target.url; + // break; + // Increase the size of the dot. + // case "enlargeDot": + // dotElement.style.transform = "scale(1.5)"; + // break; + // Decrease the size of the dot. + // case "shrinkDot": + // dotElement.style.transform = "scale(0.5)"; + // break; + // Apply a rotation to the dot. + // case "rotateDot": + // dotElement.style.transform = "rotate(45deg)"; + // break; + // Toggle the visibility of a specific element on the page. + // case "toggleVisibility": + // let elem = document.getElementById(target.elementId); + // elem.style.display = elem.style.display === 'none' ? 'block' : 'none'; + // break; + // Trigger a CSS animation on a specific element. + // case "startAnimation": + // let animElem = document.getElementById(target.elementId); + // animElem.classList.add(target.animationClass); + // break; + // Increase a score or counter displayed on the screen. + // case "incrementScore": + // score += target.incrementValue; + // updateScoreDisplay(); // Assuming you have a function to update the score display + // break; + // Change the color of the dot. + // case "changeDotColor": + // dotElement.style.backgroundColor = target.color; + // break; + // Reactive statement to check collision whenever dotPosition changes + $dotPosition && checkCollision($dotPosition); + } + }; + + return [ + $dotPosition, + ChangedContentPlaceholdertoSend, + canvas, + isModalOpen, + isSMModalOpen, + currentcollisiontitletext, + currentcollisiontext, + currentcollisionitems, + movingDotElement, + currentstatemodalstates, + currentTheme, + CurrentGameBackground, + $targets, + dotPosition, + boundaries, + themeKeys, + changeTheme, + loadexperimentaltheme, + loadexperimentalthemefromgraphtoJSON, + handleSpaceClick, + handleModalClose, + updateDotPosition, + select_change_handler, + canvas_1_binding, + movingdot_binding, + move_handler + ]; + } + + class MovingDotSpacePortfromReact extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$e, create_fragment$e, safe_not_equal, {}, null, [-1, -1]); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "MovingDotSpacePortfromReact", + options, + id: create_fragment$e.name + }); + } + } + + /* src\YoutubeIframeAPICustomInterface.svelte generated by Svelte v3.59.2 */ + + const { console: console_1$6 } = globals; + + const file$d = "src\\YoutubeIframeAPICustomInterface.svelte"; + + function get_each_context$a(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[76] = list[i]; + child_ctx[78] = i; + return child_ctx; + } + + // (518:8) {#each YTIDitems as item, index} + function create_each_block$a(ctx) { + let button; + let t0_value = /*item*/ ctx[76] + ""; + let t0; + let t1; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[43](/*index*/ ctx[78]); + } + + const block = { + c: function create() { + button = element$1("button"); + t0 = text(t0_value); + t1 = space(); + add_location(button, file$d, 518, 12, 18828); + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); + append_dev(button, t0); + append_dev(button, t1); + + if (!mounted) { + dispose = listen_dev(button, "click", click_handler, false, false, false, false); + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + if (dirty[0] & /*YTIDitems*/ 65536 && t0_value !== (t0_value = /*item*/ ctx[76] + "")) set_data_dev(t0, t0_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$a.name, + type: "each", + source: "(518:8) {#each YTIDitems as item, index}", + ctx + }); + + return block; + } + + function create_fragment$d(ctx) { + let h10; + let t1; + let h20; + let t3; + let h3; + let t4; + let b; + let t6; + let h11; + let t7; + let t8; + let t9; + let div1; + let label; + let br0; + let t11; + let input0; + let t12; + let button0; + let t14; + let button1; + let t16; + let br1; + let t17; + let textarea0; + let br2; + let t18; + let div0; + let t19; + let div2; + let input1; + let t20; + let input2; + let t21; + let textarea1; + let t22; + let button2; + let t24; + let pre; + let t25; + let t26; + let div7; + let div3; + let t27; + let div4; + let t28; + let t29_value = /*currentTime*/ ctx[4].toFixed(2) + ""; + let t29; + let t30; + let t31; + let div5; + let t32; + let t33; + let br3; + let t34; + let t35; + let t36; + let br4; + let t37; + let div6; + let t38; + let t39; + let t40; + let div8; + let t41; + let t42; + let t43; + let br5; + let t44; + let input3; + let t45; + let button3; + let t47; + let t48; + let t49; + let button4; + let t51; + let textarea2; + let t52; + let button5; + let t56; + let button6; + let t60; + let t61; + let t62; + let t63_value = /*timestamps*/ ctx[11].length + ""; + let t63; + let t64; + let br6; + let t65; + let button7; + let t67; + let button8; + let t68; + let button8_class_value; + let button8_disabled_value; + let t69; + let button9; + let t70; + let button9_class_value; + let button9_disabled_value; + let t71; + let button10; + let t72; + let button10_class_value; + let button10_disabled_value; + let t73; + let t74; + let t75; + let t76_value = /*userTimestamps*/ ctx[1].length + ""; + let t76; + let t77; + let br7; + let t78; + let t79; + let t80; + let t81_value = /*r2userTimestamps*/ ctx[12].length + ""; + let t81; + let t82; + let br8; + let t83; + let br9; + let t84; + let button11; + let t86; + let button12; + let t88; + let input4; + let t89; + let br10; + let t90; + let input5; + let t91; + let input6; + let t92; + let input7; + let t93; + let input8; + let t94; + let div9; + let h21; + let t96; + let h22; + let t98; + let hr; + let t99; + let div10; + let t100; + let br11; + let mounted; + let dispose; + let each_value = /*YTIDitems*/ ctx[16]; + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$a(get_each_context$a(ctx, each_value, i)); + } + + const block = { + c: function create() { + h10 = element$1("h1"); + h10.textContent = "Custom Youtube Player for learning Video and music"; + t1 = space(); + h20 = element$1("h2"); + h20.textContent = "Next Step for social media is to build in education blocks eg. App lets you watch next short uninterrupted if you get answer right, app forces you to see the correction as overlay if you get it wrong"; + t3 = space(); + h3 = element$1("h3"); + t4 = text("End Goal is special subtitles - Nouns Verbs and images of them in sync with video AND "); + b = element$1("b"); + b.textContent = "NB NB NB random repitition of items over video Reading as you watch any video NB NB NB"; + t6 = space(); + h11 = element$1("h1"); + t7 = text("Debug subs = "); + t8 = text(/*$ytsubcurrenttext*/ ctx[22]); + t9 = space(); + div1 = element$1("div"); + label = element$1("label"); + label.textContent = "Manage Multiple Videos"; + br0 = element$1("br"); + t11 = text("\r\n Import "); + input0 = element$1("input"); + t12 = space(); + button0 = element$1("button"); + button0.textContent = "Add Items"; + t14 = space(); + button1 = element$1("button"); + button1.textContent = "Download List as Text File"; + t16 = space(); + br1 = element$1("br"); + t17 = space(); + textarea0 = element$1("textarea"); + br2 = element$1("br"); + t18 = space(); + div0 = element$1("div"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t19 = space(); + div2 = element$1("div"); + input1 = element$1("input"); + t20 = text("\r\n Start/Stop Word Update (Dummy Transcript as default)\r\n "); + input2 = element$1("input"); + t21 = space(); + textarea1 = element$1("textarea"); + t22 = space(); + button2 = element$1("button"); + button2.textContent = "Convert YT Transcript to JSON Test"; + t24 = space(); + pre = element$1("pre"); + t25 = text(/*jsonOutput*/ ctx[6]); + t26 = space(); + div7 = element$1("div"); + div3 = element$1("div"); + t27 = space(); + div4 = element$1("div"); + t28 = text("Current Time: "); + t29 = text(t29_value); + t30 = text(" seconds"); + t31 = space(); + div5 = element$1("div"); + t32 = text(/*line*/ ctx[8]); + t33 = space(); + br3 = element$1("br"); + t34 = space(); + t35 = text(/*currentWord*/ ctx[7]); + t36 = space(); + br4 = element$1("br"); + t37 = space(); + div6 = element$1("div"); + t38 = text("Debug subs (Hide = '') = "); + t39 = text(/*$ytsubcurrenttext*/ ctx[22]); + t40 = space(); + div8 = element$1("div"); + t41 = text("Note Taking Section based on auto gen timestamp (currently "); + t42 = text(/*interval*/ ctx[23]); + t43 = text("s) (caution - all changes saved) --- "); + br5 = element$1("br"); + t44 = space(); + input3 = element$1("input"); + t45 = space(); + button3 = element$1("button"); + button3.textContent = "create note Segments"; + t47 = text(" | Current index of Note: "); + t48 = text(/*currentIndex*/ ctx[10]); + t49 = text(" | "); + button4 = element$1("button"); + button4.textContent = "Save Notes to File"; + t51 = text(" Overlay notes on screen check box | AI analysis generate button |\r\n "); + textarea2 = element$1("textarea"); + t52 = space(); + button5 = element$1("button"); + button5.textContent = `Previous Auto Timestamp - ${/*interval*/ ctx[23]}s`; + t56 = space(); + button6 = element$1("button"); + button6.textContent = `Next Auto Timestamp - ${/*interval*/ ctx[23]}s`; + t60 = text("\r\nAuto Timestamps: "); + t61 = text(/*currentIndex*/ ctx[10]); + t62 = text(" / "); + t63 = text(t63_value); + t64 = space(); + br6 = element$1("br"); + t65 = space(); + button7 = element$1("button"); + button7.textContent = "Add Timestamp"; + t67 = space(); + button8 = element$1("button"); + t68 = text("Current User Timestamp (incomplete)"); + t69 = space(); + button9 = element$1("button"); + t70 = text("Previous User Timestamp"); + t71 = space(); + button10 = element$1("button"); + t72 = text("Next User Timestamp"); + t73 = text("\r\nUser Timestamps: "); + t74 = text(/*currentuserIndex*/ ctx[0]); + t75 = text(" / "); + t76 = text(t76_value); + t77 = space(); + br7 = element$1("br"); + t78 = text(" Round 2 (/n) User Timestamps: "); + t79 = text(/*currentuserIndex*/ ctx[0]); + t80 = text(" / "); + t81 = text(t81_value); + t82 = space(); + br8 = element$1("br"); + t83 = text("A list of one messes up the logic for the counter in conjuction with the user timestamp button reactivity "); + br9 = element$1("br"); + t84 = space(); + button11 = element$1("button"); + button11.textContent = "Export Timestamps"; + t86 = space(); + button12 = element$1("button"); + button12.textContent = "Export Round 2 Timestamps"; + t88 = text(" Import Timestamps (Incomplete) "); + input4 = element$1("input"); + t89 = space(); + br10 = element$1("br"); + t90 = text(" Interval Repeat "); + input5 = element$1("input"); + t91 = text(" ||| Start "); + input6 = element$1("input"); + t92 = text(" End "); + input7 = element$1("input"); + t93 = text(" Reps "); + input8 = element$1("input"); + t94 = space(); + div9 = element$1("div"); + h21 = element$1("h2"); + h21.textContent = "Anticipation Training? -- Verbs in subtitle order known before interval repitition?"; + t96 = space(); + h22 = element$1("h2"); + h22.textContent = "Stateful Video - Reverse Interval Repeat aka parts of the video you know == Autoskip sections"; + t98 = space(); + hr = element$1("hr"); + t99 = space(); + div10 = element$1("div"); + t100 = text("Skip Interval Button sections\r\n "); + br11 = element$1("br"); + add_location(h10, file$d, 504, 0, 17783); + add_location(h20, file$d, 505, 0, 17844); + add_location(b, file$d, 506, 90, 18144); + add_location(h3, file$d, 506, 0, 18054); + add_location(h11, file$d, 508, 0, 18246); + attr_dev(label, "for", "ytid-input"); + add_location(label, file$d, 511, 4, 18304); + add_location(br0, file$d, 511, 58, 18358); + attr_dev(input0, "type", "file"); + attr_dev(input0, "id", "file-import"); + add_location(input0, file$d, 512, 11, 18375); + add_location(button0, file$d, 513, 4, 18452); + add_location(button1, file$d, 514, 4, 18508); + add_location(br1, file$d, 514, 76, 18580); + attr_dev(textarea0, "id", "ytid-input"); + attr_dev(textarea0, "rows", "4"); + set_style(textarea0, "width", "35%"); + attr_dev(textarea0, "placeholder", "Add multiple Youtube IDs separated by new lines to make buttons"); + add_location(textarea0, file$d, 515, 4, 18590); + add_location(br2, file$d, 515, 171, 18757); + add_location(div0, file$d, 516, 4, 18767); + add_location(div1, file$d, 510, 0, 18293); + attr_dev(input1, "type", "text"); + add_location(input1, file$d, 527, 4, 18974); + attr_dev(input2, "type", "checkbox"); + add_location(input2, file$d, 529, 4, 19086); + attr_dev(textarea1, "placeholder", "Enter transcript here..."); + add_location(textarea1, file$d, 534, 4, 19409); + add_location(button2, file$d, 535, 4, 19499); + attr_dev(pre, "class", "transcriptpre svelte-udvqea"); + add_location(pre, file$d, 536, 4, 19584); + add_location(div2, file$d, 526, 0, 18963); + attr_dev(div3, "id", "youtube-player"); + set_style(div3, "height", "90vh"); + set_style(div3, "width", "90%"); + add_location(div3, file$d, 540, 4, 19680); + set_style(div4, "position", "absolute"); + set_style(div4, "top", "0%"); + set_style(div4, "left", "40%"); + set_style(div4, "color", "white"); + set_style(div4, "background-color", "rgba(0, 0, 0, 0.5)"); + add_location(div4, file$d, 541, 4, 19750); + add_location(br3, file$d, 545, 15, 20070); + add_location(br4, file$d, 546, 22, 20098); + set_style(div5, "position", "absolute"); + set_style(div5, "top", "50%"); + set_style(div5, "left", "20%"); + set_style(div5, "color", "white"); + set_style(div5, "background-color", "rgba(0, 0, 0, 0.5)"); + set_style(div5, "font-size", "100px"); + add_location(div5, file$d, 544, 4, 19929); + set_style(div6, "position", "absolute"); + set_style(div6, "top", "25%"); + set_style(div6, "left", "30%"); + set_style(div6, "color", "white"); + set_style(div6, "background-color", "rgba(0, 0, 0, 0.5)"); + set_style(div6, "font-size", "100px"); + add_location(div6, file$d, 548, 4, 20120); + set_style(div7, "position", "relative"); + add_location(div7, file$d, 539, 0, 19641); + add_location(br5, file$d, 554, 110, 20442); + attr_dev(input3, "type", "file"); + add_location(input3, file$d, 555, 4, 20452); + add_location(button3, file$d, 555, 59, 20507); + add_location(button4, file$d, 555, 169, 20617); + attr_dev(textarea2, "name", "notesubtitles"); + attr_dev(textarea2, "id", "notestextarea"); + attr_dev(textarea2, "rows", "2"); + set_style(textarea2, "width", "100%"); + add_location(textarea2, file$d, 556, 4, 20759); + add_location(div8, file$d, 553, 0, 20325); + add_location(button5, file$d, 560, 0, 20986); + add_location(button6, file$d, 561, 0, 21079); + add_location(br6, file$d, 564, 0, 21221); + add_location(button7, file$d, 565, 0, 21227); + attr_dev(button8, "class", button8_class_value = "" + (null_to_empty(/*currentindexButtonClass*/ ctx[19]) + " svelte-udvqea")); + button8.disabled = button8_disabled_value = /*currentuserIndex*/ ctx[0] <= 0; + add_location(button8, file$d, 566, 0, 21287); + attr_dev(button9, "class", button9_class_value = "" + (null_to_empty(/*previousindexButtonClass*/ ctx[20]) + " svelte-udvqea")); + button9.disabled = button9_disabled_value = /*currentuserIndex*/ ctx[0] <= 0; + add_location(button9, file$d, 567, 0, 21442); + attr_dev(button10, "class", button10_class_value = "" + (null_to_empty(/*nextindexButtonClass*/ ctx[21]) + " svelte-udvqea")); + button10.disabled = button10_disabled_value = /*currentuserIndex*/ ctx[0] >= /*userTimestamps*/ ctx[1].length - 1; + add_location(button10, file$d, 568, 0, 21587); + add_location(br7, file$d, 571, 0, 21810); + add_location(br8, file$d, 571, 82, 21892); + add_location(br9, file$d, 571, 192, 22002); + add_location(button11, file$d, 572, 0, 22008); + add_location(button12, file$d, 572, 63, 22071); + attr_dev(input4, "type", "file"); + attr_dev(input4, "accept", ".json"); + add_location(input4, file$d, 572, 167, 22175); + add_location(br10, file$d, 573, 0, 22240); + attr_dev(input5, "type", "checkbox"); + add_location(input5, file$d, 573, 21, 22261); + attr_dev(input6, "type", "number"); + attr_dev(input6, "class", "numberinput svelte-udvqea"); + attr_dev(input6, "min", "0"); + add_location(input6, file$d, 573, 82, 22322); + attr_dev(input7, "type", "number"); + attr_dev(input7, "class", "numberinput svelte-udvqea"); + attr_dev(input7, "min", "0"); + add_location(input7, file$d, 573, 162, 22402); + attr_dev(input8, "type", "number"); + attr_dev(input8, "class", "numberinput svelte-udvqea"); + attr_dev(input8, "min", "0"); + add_location(input8, file$d, 573, 241, 22481); + add_location(h21, file$d, 577, 4, 22594); + add_location(h22, file$d, 578, 4, 22692); + attr_dev(div9, "class", "imagesubtitle svelte-udvqea"); + add_location(div9, file$d, 576, 0, 22561); + add_location(hr, file$d, 582, 0, 22808); + add_location(br11, file$d, 585, 4, 22860); + add_location(div10, file$d, 583, 0, 22814); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, h10, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, h20, anchor); + insert_dev(target, t3, anchor); + insert_dev(target, h3, anchor); + append_dev(h3, t4); + append_dev(h3, b); + insert_dev(target, t6, anchor); + insert_dev(target, h11, anchor); + append_dev(h11, t7); + append_dev(h11, t8); + insert_dev(target, t9, anchor); + insert_dev(target, div1, anchor); + append_dev(div1, label); + append_dev(div1, br0); + append_dev(div1, t11); + append_dev(div1, input0); + append_dev(div1, t12); + append_dev(div1, button0); + append_dev(div1, t14); + append_dev(div1, button1); + append_dev(div1, t16); + append_dev(div1, br1); + append_dev(div1, t17); + append_dev(div1, textarea0); + set_input_value(textarea0, /*YTIDinput*/ ctx[17]); + append_dev(div1, br2); + append_dev(div1, t18); + append_dev(div1, div0); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div0, null); + } + } + + insert_dev(target, t19, anchor); + insert_dev(target, div2, anchor); + append_dev(div2, input1); + set_input_value(input1, /*$ytsubcurrentID*/ ctx[3]); + append_dev(div2, t20); + append_dev(div2, input2); + input2.checked = /*isUpdating*/ ctx[9]; + append_dev(div2, t21); + append_dev(div2, textarea1); + set_input_value(textarea1, /*transcript*/ ctx[5]); + append_dev(div2, t22); + append_dev(div2, button2); + append_dev(div2, t24); + append_dev(div2, pre); + append_dev(pre, t25); + insert_dev(target, t26, anchor); + insert_dev(target, div7, anchor); + append_dev(div7, div3); + append_dev(div7, t27); + append_dev(div7, div4); + append_dev(div4, t28); + append_dev(div4, t29); + append_dev(div4, t30); + append_dev(div7, t31); + append_dev(div7, div5); + append_dev(div5, t32); + append_dev(div5, t33); + append_dev(div5, br3); + append_dev(div5, t34); + append_dev(div5, t35); + append_dev(div5, t36); + append_dev(div5, br4); + append_dev(div7, t37); + append_dev(div7, div6); + append_dev(div6, t38); + append_dev(div6, t39); + insert_dev(target, t40, anchor); + insert_dev(target, div8, anchor); + append_dev(div8, t41); + append_dev(div8, t42); + append_dev(div8, t43); + append_dev(div8, br5); + append_dev(div8, t44); + append_dev(div8, input3); + append_dev(div8, t45); + append_dev(div8, button3); + append_dev(div8, t47); + append_dev(div8, t48); + append_dev(div8, t49); + append_dev(div8, button4); + append_dev(div8, t51); + append_dev(div8, textarea2); + set_input_value(textarea2, /*notesegments*/ ctx[18][/*currentIndex*/ ctx[10]]['notes']); + insert_dev(target, t52, anchor); + insert_dev(target, button5, anchor); + insert_dev(target, t56, anchor); + insert_dev(target, button6, anchor); + insert_dev(target, t60, anchor); + insert_dev(target, t61, anchor); + insert_dev(target, t62, anchor); + insert_dev(target, t63, anchor); + insert_dev(target, t64, anchor); + insert_dev(target, br6, anchor); + insert_dev(target, t65, anchor); + insert_dev(target, button7, anchor); + insert_dev(target, t67, anchor); + insert_dev(target, button8, anchor); + append_dev(button8, t68); + insert_dev(target, t69, anchor); + insert_dev(target, button9, anchor); + append_dev(button9, t70); + insert_dev(target, t71, anchor); + insert_dev(target, button10, anchor); + append_dev(button10, t72); + insert_dev(target, t73, anchor); + insert_dev(target, t74, anchor); + insert_dev(target, t75, anchor); + insert_dev(target, t76, anchor); + insert_dev(target, t77, anchor); + insert_dev(target, br7, anchor); + insert_dev(target, t78, anchor); + insert_dev(target, t79, anchor); + insert_dev(target, t80, anchor); + insert_dev(target, t81, anchor); + insert_dev(target, t82, anchor); + insert_dev(target, br8, anchor); + insert_dev(target, t83, anchor); + insert_dev(target, br9, anchor); + insert_dev(target, t84, anchor); + insert_dev(target, button11, anchor); + insert_dev(target, t86, anchor); + insert_dev(target, button12, anchor); + insert_dev(target, t88, anchor); + insert_dev(target, input4, anchor); + insert_dev(target, t89, anchor); + insert_dev(target, br10, anchor); + insert_dev(target, t90, anchor); + insert_dev(target, input5, anchor); + input5.checked = /*isRepeating*/ ctx[2]; + insert_dev(target, t91, anchor); + insert_dev(target, input6, anchor); + set_input_value(input6, /*repstartTime*/ ctx[13]); + insert_dev(target, t92, anchor); + insert_dev(target, input7, anchor); + set_input_value(input7, /*rependTime*/ ctx[14]); + insert_dev(target, t93, anchor); + insert_dev(target, input8, anchor); + set_input_value(input8, /*repetitions*/ ctx[15]); + insert_dev(target, t94, anchor); + insert_dev(target, div9, anchor); + append_dev(div9, h21); + append_dev(div9, t96); + append_dev(div9, h22); + insert_dev(target, t98, anchor); + insert_dev(target, hr, anchor); + insert_dev(target, t99, anchor); + insert_dev(target, div10, anchor); + append_dev(div10, t100); + append_dev(div10, br11); + + if (!mounted) { + dispose = [ + listen_dev(input0, "change", /*YTIDhandleFileImport*/ ctx[39], false, false, false, false), + listen_dev(button0, "click", /*YTIDaddItems*/ ctx[36], false, false, false, false), + listen_dev(button1, "click", /*YTIDdownloadList*/ ctx[38], false, false, false, false), + listen_dev(textarea0, "input", /*textarea0_input_handler*/ ctx[42]), + listen_dev(input1, "input", /*input1_input_handler*/ ctx[44]), + listen_dev(input2, "change", /*input2_change_handler*/ ctx[45]), + listen_dev(input2, "click", /*toggleUpdate*/ ctx[25], false, false, false, false), + listen_dev(textarea1, "input", /*textarea1_input_handler*/ ctx[46]), + listen_dev(button2, "click", /*transcriptToJson*/ ctx[35], false, false, false, false), + listen_dev(input3, "change", /*loadnotesegmentstofile*/ ctx[41], false, false, false, false), + listen_dev(button3, "click", /*createNoteSegments*/ ctx[24], false, false, false, false), + listen_dev(button4, "click", /*savenoteSegmentstofile*/ ctx[40], false, false, false, false), + listen_dev(textarea2, "input", /*textarea2_input_handler*/ ctx[47]), + listen_dev(button5, "click", /*goToPreviousAutoTimestamp*/ ctx[27], false, false, false, false), + listen_dev(button6, "click", /*goToNextAutoTimestamp*/ ctx[26], false, false, false, false), + listen_dev(button7, "click", /*addUserTimestamp*/ ctx[28], false, false, false, false), + listen_dev(button8, "click", /*goToCurrentUserTimestamp*/ ctx[29], false, false, false, false), + listen_dev(button9, "click", /*goToPreviousUserTimestamp*/ ctx[31], false, false, false, false), + listen_dev(button10, "click", /*goToNextUserTimestamp*/ ctx[30], false, false, false, false), + listen_dev(button11, "click", /*exportTimestamps*/ ctx[32], false, false, false, false), + listen_dev(button12, "click", /*exportr2Timestamps*/ ctx[33], false, false, false, false), + listen_dev(input4, "change", /*importTimestamps*/ ctx[34], false, false, false, false), + listen_dev(input5, "change", /*input5_change_handler*/ ctx[48]), + listen_dev(input6, "input", /*input6_input_handler*/ ctx[49]), + listen_dev(input7, "input", /*input7_input_handler*/ ctx[50]), + listen_dev(input8, "input", /*input8_input_handler*/ ctx[51]) + ]; + + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*$ytsubcurrenttext*/ 4194304) set_data_dev(t8, /*$ytsubcurrenttext*/ ctx[22]); + + if (dirty[0] & /*YTIDinput*/ 131072) { + set_input_value(textarea0, /*YTIDinput*/ ctx[17]); + } + + if (dirty[0] & /*YTIDitems*/ 65536 | dirty[1] & /*YTIDupdateItem*/ 64) { + each_value = /*YTIDitems*/ ctx[16]; + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$a(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$a(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div0, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + + if (dirty[0] & /*$ytsubcurrentID*/ 8 && input1.value !== /*$ytsubcurrentID*/ ctx[3]) { + set_input_value(input1, /*$ytsubcurrentID*/ ctx[3]); + } + + if (dirty[0] & /*isUpdating*/ 512) { + input2.checked = /*isUpdating*/ ctx[9]; + } + + if (dirty[0] & /*transcript*/ 32) { + set_input_value(textarea1, /*transcript*/ ctx[5]); + } + + if (dirty[0] & /*jsonOutput*/ 64) set_data_dev(t25, /*jsonOutput*/ ctx[6]); + if (dirty[0] & /*currentTime*/ 16 && t29_value !== (t29_value = /*currentTime*/ ctx[4].toFixed(2) + "")) set_data_dev(t29, t29_value); + if (dirty[0] & /*line*/ 256) set_data_dev(t32, /*line*/ ctx[8]); + if (dirty[0] & /*currentWord*/ 128) set_data_dev(t35, /*currentWord*/ ctx[7]); + if (dirty[0] & /*$ytsubcurrenttext*/ 4194304) set_data_dev(t39, /*$ytsubcurrenttext*/ ctx[22]); + if (dirty[0] & /*currentIndex*/ 1024) set_data_dev(t48, /*currentIndex*/ ctx[10]); + + if (dirty[0] & /*notesegments, currentIndex*/ 263168) { + set_input_value(textarea2, /*notesegments*/ ctx[18][/*currentIndex*/ ctx[10]]['notes']); + } + + if (dirty[0] & /*currentIndex*/ 1024) set_data_dev(t61, /*currentIndex*/ ctx[10]); + if (dirty[0] & /*timestamps*/ 2048 && t63_value !== (t63_value = /*timestamps*/ ctx[11].length + "")) set_data_dev(t63, t63_value); + + if (dirty[0] & /*currentindexButtonClass*/ 524288 && button8_class_value !== (button8_class_value = "" + (null_to_empty(/*currentindexButtonClass*/ ctx[19]) + " svelte-udvqea"))) { + attr_dev(button8, "class", button8_class_value); + } + + if (dirty[0] & /*currentuserIndex*/ 1 && button8_disabled_value !== (button8_disabled_value = /*currentuserIndex*/ ctx[0] <= 0)) { + prop_dev(button8, "disabled", button8_disabled_value); + } + + if (dirty[0] & /*previousindexButtonClass*/ 1048576 && button9_class_value !== (button9_class_value = "" + (null_to_empty(/*previousindexButtonClass*/ ctx[20]) + " svelte-udvqea"))) { + attr_dev(button9, "class", button9_class_value); + } + + if (dirty[0] & /*currentuserIndex*/ 1 && button9_disabled_value !== (button9_disabled_value = /*currentuserIndex*/ ctx[0] <= 0)) { + prop_dev(button9, "disabled", button9_disabled_value); + } + + if (dirty[0] & /*nextindexButtonClass*/ 2097152 && button10_class_value !== (button10_class_value = "" + (null_to_empty(/*nextindexButtonClass*/ ctx[21]) + " svelte-udvqea"))) { + attr_dev(button10, "class", button10_class_value); + } + + if (dirty[0] & /*currentuserIndex, userTimestamps*/ 3 && button10_disabled_value !== (button10_disabled_value = /*currentuserIndex*/ ctx[0] >= /*userTimestamps*/ ctx[1].length - 1)) { + prop_dev(button10, "disabled", button10_disabled_value); + } + + if (dirty[0] & /*currentuserIndex*/ 1) set_data_dev(t74, /*currentuserIndex*/ ctx[0]); + if (dirty[0] & /*userTimestamps*/ 2 && t76_value !== (t76_value = /*userTimestamps*/ ctx[1].length + "")) set_data_dev(t76, t76_value); + if (dirty[0] & /*currentuserIndex*/ 1) set_data_dev(t79, /*currentuserIndex*/ ctx[0]); + if (dirty[0] & /*r2userTimestamps*/ 4096 && t81_value !== (t81_value = /*r2userTimestamps*/ ctx[12].length + "")) set_data_dev(t81, t81_value); + + if (dirty[0] & /*isRepeating*/ 4) { + input5.checked = /*isRepeating*/ ctx[2]; + } + + if (dirty[0] & /*repstartTime*/ 8192 && to_number(input6.value) !== /*repstartTime*/ ctx[13]) { + set_input_value(input6, /*repstartTime*/ ctx[13]); + } + + if (dirty[0] & /*rependTime*/ 16384 && to_number(input7.value) !== /*rependTime*/ ctx[14]) { + set_input_value(input7, /*rependTime*/ ctx[14]); + } + + if (dirty[0] & /*repetitions*/ 32768 && to_number(input8.value) !== /*repetitions*/ ctx[15]) { + set_input_value(input8, /*repetitions*/ ctx[15]); + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(h10); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(h20); + if (detaching) detach_dev(t3); + if (detaching) detach_dev(h3); + if (detaching) detach_dev(t6); + if (detaching) detach_dev(h11); + if (detaching) detach_dev(t9); + if (detaching) detach_dev(div1); + destroy_each(each_blocks, detaching); + if (detaching) detach_dev(t19); + if (detaching) detach_dev(div2); + if (detaching) detach_dev(t26); + if (detaching) detach_dev(div7); + if (detaching) detach_dev(t40); + if (detaching) detach_dev(div8); + if (detaching) detach_dev(t52); + if (detaching) detach_dev(button5); + if (detaching) detach_dev(t56); + if (detaching) detach_dev(button6); + if (detaching) detach_dev(t60); + if (detaching) detach_dev(t61); + if (detaching) detach_dev(t62); + if (detaching) detach_dev(t63); + if (detaching) detach_dev(t64); + if (detaching) detach_dev(br6); + if (detaching) detach_dev(t65); + if (detaching) detach_dev(button7); + if (detaching) detach_dev(t67); + if (detaching) detach_dev(button8); + if (detaching) detach_dev(t69); + if (detaching) detach_dev(button9); + if (detaching) detach_dev(t71); + if (detaching) detach_dev(button10); + if (detaching) detach_dev(t73); + if (detaching) detach_dev(t74); + if (detaching) detach_dev(t75); + if (detaching) detach_dev(t76); + if (detaching) detach_dev(t77); + if (detaching) detach_dev(br7); + if (detaching) detach_dev(t78); + if (detaching) detach_dev(t79); + if (detaching) detach_dev(t80); + if (detaching) detach_dev(t81); + if (detaching) detach_dev(t82); + if (detaching) detach_dev(br8); + if (detaching) detach_dev(t83); + if (detaching) detach_dev(br9); + if (detaching) detach_dev(t84); + if (detaching) detach_dev(button11); + if (detaching) detach_dev(t86); + if (detaching) detach_dev(button12); + if (detaching) detach_dev(t88); + if (detaching) detach_dev(input4); + if (detaching) detach_dev(t89); + if (detaching) detach_dev(br10); + if (detaching) detach_dev(t90); + if (detaching) detach_dev(input5); + if (detaching) detach_dev(t91); + if (detaching) detach_dev(input6); + if (detaching) detach_dev(t92); + if (detaching) detach_dev(input7); + if (detaching) detach_dev(t93); + if (detaching) detach_dev(input8); + if (detaching) detach_dev(t94); + if (detaching) detach_dev(div9); + if (detaching) detach_dev(t98); + if (detaching) detach_dev(hr); + if (detaching) detach_dev(t99); + if (detaching) detach_dev(div10); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$d.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function getRandomWord(line) { + let words = line.split(" "); + return words[Math.floor(Math.random() * words.length)]; + } + + function instance$d($$self, $$props, $$invalidate) { + let nextindexButtonClass; + let previousindexButtonClass; + let currentindexButtonClass; + let $ytsubcurrentID; + let $ytsubcurrenttext; + validate_store(ytsubcurrentID, 'ytsubcurrentID'); + component_subscribe($$self, ytsubcurrentID, $$value => $$invalidate(3, $ytsubcurrentID = $$value)); + validate_store(ytsubcurrenttext, 'ytsubcurrenttext'); + component_subscribe($$self, ytsubcurrenttext, $$value => $$invalidate(22, $ytsubcurrenttext = $$value)); + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('YoutubeIframeAPICustomInterface', slots, []); + let player; + let interval = 20; // Define your interval + let currentTime = 0; + let timeUpdateInterval; + + // Assuming 'transcript' contains your video transcript + let transcript = `Line 1 of the transcript. + Line 2 of the transcript. + Line 3 food + Line 4 foodest + Line 5 foods + Line 6 fooder + Line 7 foodz + Line 8 fooding + ...`; // Replace with your actual transcript + + let jsonOutput = ''; + let lines = transcript.split("\n"); + let currentWord = ""; + let line = ""; + let isUpdating = false; + let updateInterval; + let currentIndex = 0; // Assuming this is initialized appropriately + let currentuserIndex = 0; // Assuming this is initialized appropriately + let timestamps = []; // Array of timestamps + let userTimestamps = []; // Array of user timestamps + let r2userTimestamps = []; // Array of user timestamps + + //let currentvideoId = 'IVJkOHTBPn0'; + let youTubeApiLoaded = false; + + let currentvideoduration; + let regeneratedautotimestamps = false; + let repstartTime = 10; + let rependTime = 20; + let repetitions = 20; + let intervalId; + let isRepeating = false; + let YTIDitems = ['mwO6v4BlgZQ', 'IVJkOHTBPn0']; + let YTIDinput = ''; + let skipIntervals = []; + let intervalstartTime = 0; + let intervalendTime = 0; + + let notesegments = [ + { start: 0, end: 20, notes: 'Test' }, + { start: 21, end: 40, notes: 'For if' }, + { + start: 41, + end: 60, + notes: 'Correct text loads (Inititalise)' + } + ]; + + window.onYouTubeIframeAPIReady = function () { + youTubeApiLoaded = true; + initYouTubePlayer(); + }; + + // Function to initialize the YouTube player + function initYouTubePlayer() { + if (!youTubeApiLoaded) { + console.error("YouTube API is not ready yet."); + return; + } + + regeneratedautotimestamps = false; + + // Clear existing interval + clearInterval(timeUpdateInterval); + + // Reinitialize player with new video ID + if (player) { + player.loadVideoById($ytsubcurrentID); + } else { + player = new YT.Player('youtube-player', + { + height: '360', + width: '640', + videoId: $ytsubcurrentID, + events: { + 'onReady': onPlayerReady, + 'onStateChange': onPlayerStateChange + } + }); + } + + // Reset and start the interval to update current time + timeUpdateInterval = setInterval(updateCurrentTime, 1000); + } + + onMount(() => { + // Load the YouTube IFrame Player API + const tag = document.createElement('script'); + + tag.src = "https://www.youtube.com/iframe_api"; + const firstScriptTag = document.getElementsByTagName('script')[0]; + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + + // Update the current time every second + timeUpdateInterval = setInterval(updateCurrentTime, 1000); + }); + + function autogeneratedtimestamps() { + currentvideoduration = player.getDuration(); + + //console.log("Video Duration: ", currentvideoduration); + const generatedTimestamps = []; + + for (let i = interval; i < currentvideoduration; i += interval) { + generatedTimestamps.push(i); + } + + $$invalidate(11, timestamps = generatedTimestamps); + + // Do something with the timestamps + //console.log("Generated Timestamps: ", generatedTimestamps); + regeneratedautotimestamps = true; + } + + function createNoteSegments() { + // console.log("Video duration: " + currentvideoduration); + // console.log("Timestamps: " + timestamps); + $$invalidate(18, notesegments = []); // Clear existing segments + + let start = 0; + + timestamps.forEach((end, index) => { + if (index === 0) { + notesegments.push({ start: 0, end, notes: "" }); + } else { + start = timestamps[index - 1] + 1; + notesegments.push({ start, end, notes: "" }); + } + }); + + // Add a final segment if the last timestamp is less than the video duration + if (timestamps[timestamps.length - 1] < currentvideoduration) { + notesegments.push({ + start: timestamps[timestamps.length - 1] + 1, + end: currentvideoduration, + notes: "" + }); + } + } + + // Event handler for when the player is ready + function onPlayerReady(event) { + autogeneratedtimestamps(); + createNoteSegments(); + } + + function onPlayerStateChange(event) { + if (event.data === YT.PlayerState.PLAYING || event.data === YT.PlayerState.PAUSED) { + updateCurrentIndex(); + } + + // Check if the video has just started playing + if (event.data === YT.PlayerState.PLAYING && !regeneratedautotimestamps) { + autogeneratedtimestamps(); + createNoteSegments(); + } + } + + function updateCurrentIndex() { + const currentTime = player.getCurrentTime(); + + // Find the closest timestamp + let closest = timestamps.reduce((prev, curr) => Math.abs(curr - currentTime) < Math.abs(prev - currentTime) + ? curr + : prev); + + $$invalidate(10, currentIndex = timestamps.indexOf(closest)); + } + + function updateCurrentTime() { + if (player && player.getCurrentTime) { + $$invalidate(4, currentTime = player.getCurrentTime()); + } + } + + onDestroy(() => { + clearInterval(timeUpdateInterval); + }); + + function updateWord() { + if (isUpdating) { + $$invalidate(8, line = lines[Math.floor(Math.random() * lines.length)]); + $$invalidate(7, currentWord = getRandomWord(line)); + } + } + + function toggleUpdate() { + lines = transcript.split("\n"); + $$invalidate(9, isUpdating = !isUpdating); + + if (isUpdating) { + updateWord(); // Immediately update once + updateInterval = setInterval(updateWord, 3000); // Update every 3 seconds + } else { + clearInterval(updateInterval); + $$invalidate(8, line = ''); + $$invalidate(7, currentWord = ''); + } + } + + function goToNextAutoTimestamp() { + if (currentIndex < timestamps.length - 1) { + $$invalidate(10, currentIndex += 1); + player.seekTo(timestamps[currentIndex], true); + } + } + + function goToPreviousAutoTimestamp() { + if (currentIndex > 0) { + $$invalidate(10, currentIndex -= 1); + player.seekTo(timestamps[currentIndex], true); + } + } + + function addUserTimestamp() { + const currentTime = Math.floor(player.getCurrentTime()); + $$invalidate(1, userTimestamps = [...userTimestamps, currentTime].sort((a, b) => a - b)); + } + + function addr2UserTimestamp() { + const currentTime = Math.floor(player.getCurrentTime()); + $$invalidate(12, r2userTimestamps = [...r2userTimestamps, currentTime].sort((a, b) => a - b)); + } + + function goToCurrentUserTimestamp() { + if (currentuserIndex === 0 && currentIndex < 0) { + player.seekTo(userTimestamps[currentIndex], true); + } else if (currentuserIndex < 0) { + player.seekTo(userTimestamps[currentuserIndex], true); + } else { + // Handle the end of the list here + console.log("No selected user timestamp."); + } // You can also disable the "next" button or loop to the start if needed. + } + + function goToNextUserTimestamp() { + if (currentuserIndex < userTimestamps.length - 1) { + $$invalidate(0, currentuserIndex += 1); + player.seekTo(userTimestamps[currentuserIndex], true); + } else { + // Handle the end of the list here + console.log("Reached the end of user timestamps."); + } // You can also disable the "next" button or loop to the start if needed. + } + + function goToPreviousUserTimestamp() { + if (currentuserIndex > 0) { + $$invalidate(0, currentuserIndex -= 1); + player.seekTo(userTimestamps[currentuserIndex], true); + } else { + // Handle the beginning of the list here + console.log("Reached the start of user timestamps."); + } // You can also disable the "previous" button or loop to the end if needed. + } + + function exportTimestamps() { + const data = JSON.stringify({ + $ytsubcurrentID, + timestamps: userTimestamps + }); + + const blob = new Blob([data], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.style.display = 'none'; + const filename = `${$ytsubcurrentID}_timestamps.json`; + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + } + + function exportr2Timestamps() { + const data = JSON.stringify({ + $ytsubcurrentID, + timestamps: r2userTimestamps + }); + + const blob = new Blob([data], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.style.display = 'none'; + const filename = `${$ytsubcurrentID}_round2timestamps.json`; + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + } + + function importTimestamps(event) { + // Check if the file input is not empty + const file = event.target.files[0]; + + if (!event.target.files || event.target.files.length === 0) { + alert('No file selected.'); + return; + } + + // Check if the file is a Blob (File objects inherit from Blob) + if (!(file instanceof Blob)) { + alert('Selected item is not a file.'); + return; + } + + const reader = new FileReader(); + + reader.onload = e => { + try { + const data = JSON.parse(e.target.result); + + if (!Array.isArray(data.timestamps)) { + alert('Invalid file structure: timestamps should be an array.'); + return; + } + + set_store_value(ytsubcurrentID, $ytsubcurrentID = data.$ytsubcurrentID || '', $ytsubcurrentID); + $$invalidate(1, userTimestamps = data.timestamps); + } catch(error) { + alert('An error occurred while importing timestamps.'); //regeneratedautotimestamps = false; = true + } + }; + + reader.readAsText(file); + } + + function transcriptToJson() { + const lines = transcript.split('\n').filter(line => line.trim() !== ''); + const result = []; + + for (let i = 0; i < lines.length; i += 2) { + const timestampLine = lines[i]; + const textLine = lines[i + 1] || ''; // Ensure there's a line for text + const timestampParts = timestampLine.split(' '); + const timestamp = timestampParts.shift(); + const timeParts = timestamp.split(':'); + const seconds = parseInt(timeParts[0], 10) * 60 + parseInt(timeParts[1], 10); + result.push({ time: seconds, text: textLine.trim() }); + } + + $$invalidate(6, jsonOutput = JSON.stringify(result, null, 2)); + } + + function startRepetition() { + let count = 0; + player.seekTo(repstartTime, true); + player.playVideo(); + + intervalId = setInterval( + () => { + if (count < repetitions) { + player.seekTo(repstartTime, true); + count++; + } else { + stopRepetition(); + } + }, + (rependTime - repstartTime) * 1000 + ); + } + + function stopRepetition() { + clearInterval(intervalId); + } //player.pauseVideo(); + + // Function to handle button click for adding items + function YTIDaddItems() { + const newItems = YTIDinput.split('\n').filter(item => item.trim() !== ''); + YTIDitems.push(...newItems); + $$invalidate(17, YTIDinput = ''); // Clear textarea after adding + $$invalidate(16, YTIDitems = YTIDitems.slice()); + } + + function YTIDupdateItem(index) { + $$invalidate(16, YTIDitems[index] = `${YTIDitems[index]}`, YTIDitems); //(updated)`; + set_store_value(ytsubcurrentID, $ytsubcurrentID = YTIDitems[index], $ytsubcurrentID); + $$invalidate(16, YTIDitems = YTIDitems.slice()); + } + + function YTIDdownloadList() { + const blob = new Blob([YTIDitems.join('\n')], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'YTIDlist.txt'; // Name of the file to be downloaded + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } + + function YTIDhandleFileImport(event) { + const file = event.target.files[0]; + + if (file) { + const reader = new FileReader(); + + reader.onload = e => { + const fileContents = e.target.result; + $$invalidate(16, YTIDitems = fileContents.split('\n').filter(line => line.trim() !== '')); + }; + + reader.readAsText(file); + } + } + + function checkSkipIntervals() { + const currentTime = player.getCurrentTime(); + + for (const interval of skipIntervals) { + if (currentTime >= interval.start && currentTime < interval.end) { + player.seekTo(interval.end); + break; + } + } + } + + function addSkipInterval() { + skipIntervals.push({ + start: intervalstartTime, + end: intervalendTime + }); + + skipIntervals = skipIntervals; + intervalstartTime = 0; + intervalendTime = 0; + } + + function removeSkipInterval(index) { + skipIntervals.splice(index, 1); + skipIntervals = skipIntervals; + } + + // function createnoteSegments() { + // console.log(currentvideoduration) + // console.log(timestamps) + // notesegments = []; // Clear existing segments + // for (let start = 0; start < currentvideoduration; start += timestamps) { + // let end = start + timestamps - 1; + // if (end > currentvideoduration) end = currentvideoduration; // Adjust last segment to not exceed video duration + // notesegments.push({ start: start, end: end, notes: "" }); + // } + // console.log(notesegments) + // } + // function createNoteSegments() { + // console.log("Video duration: " + currentvideoduration); + // console.log("Timestamps: " + timestamps); + // notesegments = []; // Clear existing segments + // let start = 0; + // timestamps.forEach((end, index) => { + // if (index === 0) { + // notesegments.push({ start: 0, end: end, notes: "" }); + // } else { + // start = timestamps[index - 1] + 1; + // notesegments.push({ start: start, end: end, notes: "" }); + // } + // }); + // // Add a final segment if the last timestamp is less than the video duration + // if (timestamps[timestamps.length - 1] < currentvideoduration) { + // notesegments.push({ + // start: timestamps[timestamps.length - 1] + 1, + // end: currentvideoduration, + // notes: "" + // }); + // } + // console.log(notesegments); + // } + function savenoteSegmentstofile() { + const dataStr = JSON.stringify(notesegments); + const blob = new Blob([dataStr], { type: "application/json" }); + + // Getting current date and time for filename + const now = new Date(); + + const dateTimeStamp = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}-${now.getMinutes().toString().padStart(2, '0')}-${now.getSeconds().toString().padStart(2, '0')}`; + const filename = `noteSegments_${$ytsubcurrentID}_${dateTimeStamp}.json`; + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = filename; //"notesegments.json"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + } + + function loadnotesegmentstofile(event) { + const file = event.target.files[0]; + + if (file) { + const reader = new FileReader(); + + reader.onload = e => { + $$invalidate(18, notesegments = JSON.parse(e.target.result)); + console.log("Notes loaded:", notesegments); + }; + + reader.readAsText(file); + } + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$6.warn(` was created with unknown prop '${key}'`); + }); + + function textarea0_input_handler() { + YTIDinput = this.value; + $$invalidate(17, YTIDinput); + } + + const click_handler = index => YTIDupdateItem(index); + + function input1_input_handler() { + $ytsubcurrentID = this.value; + ytsubcurrentID.set($ytsubcurrentID); + } + + function input2_change_handler() { + isUpdating = this.checked; + $$invalidate(9, isUpdating); + } + + function textarea1_input_handler() { + transcript = this.value; + $$invalidate(5, transcript); + } + + function textarea2_input_handler() { + notesegments[currentIndex]['notes'] = this.value; + $$invalidate(18, notesegments); + } + + function input5_change_handler() { + isRepeating = this.checked; + $$invalidate(2, isRepeating); + } + + function input6_input_handler() { + repstartTime = to_number(this.value); + $$invalidate(13, repstartTime); + } + + function input7_input_handler() { + rependTime = to_number(this.value); + $$invalidate(14, rependTime); + } + + function input8_input_handler() { + repetitions = to_number(this.value); + $$invalidate(15, repetitions); + } + + $$self.$capture_state = () => ({ + onMount, + onDestroy, + ytsubcurrenttext, + ytsubcurrentID, + ytsubuse, + ytsubuseplayer, + player, + interval, + currentTime, + timeUpdateInterval, + transcript, + jsonOutput, + lines, + currentWord, + line, + isUpdating, + updateInterval, + currentIndex, + currentuserIndex, + timestamps, + userTimestamps, + r2userTimestamps, + youTubeApiLoaded, + currentvideoduration, + regeneratedautotimestamps, + repstartTime, + rependTime, + repetitions, + intervalId, + isRepeating, + YTIDitems, + YTIDinput, + skipIntervals, + intervalstartTime, + intervalendTime, + notesegments, + initYouTubePlayer, + autogeneratedtimestamps, + createNoteSegments, + onPlayerReady, + onPlayerStateChange, + updateCurrentIndex, + updateCurrentTime, + getRandomWord, + updateWord, + toggleUpdate, + goToNextAutoTimestamp, + goToPreviousAutoTimestamp, + addUserTimestamp, + addr2UserTimestamp, + goToCurrentUserTimestamp, + goToNextUserTimestamp, + goToPreviousUserTimestamp, + exportTimestamps, + exportr2Timestamps, + importTimestamps, + transcriptToJson, + startRepetition, + stopRepetition, + YTIDaddItems, + YTIDupdateItem, + YTIDdownloadList, + YTIDhandleFileImport, + checkSkipIntervals, + addSkipInterval, + removeSkipInterval, + savenoteSegmentstofile, + loadnotesegmentstofile, + currentindexButtonClass, + previousindexButtonClass, + nextindexButtonClass, + $ytsubcurrentID, + $ytsubcurrenttext + }); + + $$self.$inject_state = $$props => { + if ('player' in $$props) player = $$props.player; + if ('interval' in $$props) $$invalidate(23, interval = $$props.interval); + if ('currentTime' in $$props) $$invalidate(4, currentTime = $$props.currentTime); + if ('timeUpdateInterval' in $$props) timeUpdateInterval = $$props.timeUpdateInterval; + if ('transcript' in $$props) $$invalidate(5, transcript = $$props.transcript); + if ('jsonOutput' in $$props) $$invalidate(6, jsonOutput = $$props.jsonOutput); + if ('lines' in $$props) lines = $$props.lines; + if ('currentWord' in $$props) $$invalidate(7, currentWord = $$props.currentWord); + if ('line' in $$props) $$invalidate(8, line = $$props.line); + if ('isUpdating' in $$props) $$invalidate(9, isUpdating = $$props.isUpdating); + if ('updateInterval' in $$props) updateInterval = $$props.updateInterval; + if ('currentIndex' in $$props) $$invalidate(10, currentIndex = $$props.currentIndex); + if ('currentuserIndex' in $$props) $$invalidate(0, currentuserIndex = $$props.currentuserIndex); + if ('timestamps' in $$props) $$invalidate(11, timestamps = $$props.timestamps); + if ('userTimestamps' in $$props) $$invalidate(1, userTimestamps = $$props.userTimestamps); + if ('r2userTimestamps' in $$props) $$invalidate(12, r2userTimestamps = $$props.r2userTimestamps); + if ('youTubeApiLoaded' in $$props) youTubeApiLoaded = $$props.youTubeApiLoaded; + if ('currentvideoduration' in $$props) currentvideoduration = $$props.currentvideoduration; + if ('regeneratedautotimestamps' in $$props) regeneratedautotimestamps = $$props.regeneratedautotimestamps; + if ('repstartTime' in $$props) $$invalidate(13, repstartTime = $$props.repstartTime); + if ('rependTime' in $$props) $$invalidate(14, rependTime = $$props.rependTime); + if ('repetitions' in $$props) $$invalidate(15, repetitions = $$props.repetitions); + if ('intervalId' in $$props) intervalId = $$props.intervalId; + if ('isRepeating' in $$props) $$invalidate(2, isRepeating = $$props.isRepeating); + if ('YTIDitems' in $$props) $$invalidate(16, YTIDitems = $$props.YTIDitems); + if ('YTIDinput' in $$props) $$invalidate(17, YTIDinput = $$props.YTIDinput); + if ('skipIntervals' in $$props) skipIntervals = $$props.skipIntervals; + if ('intervalstartTime' in $$props) intervalstartTime = $$props.intervalstartTime; + if ('intervalendTime' in $$props) intervalendTime = $$props.intervalendTime; + if ('notesegments' in $$props) $$invalidate(18, notesegments = $$props.notesegments); + if ('currentindexButtonClass' in $$props) $$invalidate(19, currentindexButtonClass = $$props.currentindexButtonClass); + if ('previousindexButtonClass' in $$props) $$invalidate(20, previousindexButtonClass = $$props.previousindexButtonClass); + if ('nextindexButtonClass' in $$props) $$invalidate(21, nextindexButtonClass = $$props.nextindexButtonClass); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + $$self.$$.update = () => { + if ($$self.$$.dirty[0] & /*$ytsubcurrentID*/ 8) { + if ($ytsubcurrentID) { + initYouTubePlayer(); + } + } + + if ($$self.$$.dirty[0] & /*currentuserIndex, userTimestamps*/ 3) { + $$invalidate(21, nextindexButtonClass = currentuserIndex >= userTimestamps.length - 1 + ? 'button-at-end' + : 'button'); + } + + if ($$self.$$.dirty[0] & /*currentuserIndex*/ 1) { + $$invalidate(20, previousindexButtonClass = currentuserIndex <= 0 ? 'button-at-end' : 'button'); + } + + if ($$self.$$.dirty[0] & /*currentuserIndex*/ 1) { + $$invalidate(19, currentindexButtonClass = currentuserIndex <= 0 ? 'button-at-end' : 'button'); + } + + if ($$self.$$.dirty[0] & /*isRepeating*/ 4) { + if (isRepeating) { + startRepetition(); + } else { + stopRepetition(); + } + } + }; + + return [ + currentuserIndex, + userTimestamps, + isRepeating, + $ytsubcurrentID, + currentTime, + transcript, + jsonOutput, + currentWord, + line, + isUpdating, + currentIndex, + timestamps, + r2userTimestamps, + repstartTime, + rependTime, + repetitions, + YTIDitems, + YTIDinput, + notesegments, + currentindexButtonClass, + previousindexButtonClass, + nextindexButtonClass, + $ytsubcurrenttext, + interval, + createNoteSegments, + toggleUpdate, + goToNextAutoTimestamp, + goToPreviousAutoTimestamp, + addUserTimestamp, + goToCurrentUserTimestamp, + goToNextUserTimestamp, + goToPreviousUserTimestamp, + exportTimestamps, + exportr2Timestamps, + importTimestamps, + transcriptToJson, + YTIDaddItems, + YTIDupdateItem, + YTIDdownloadList, + YTIDhandleFileImport, + savenoteSegmentstofile, + loadnotesegmentstofile, + textarea0_input_handler, + click_handler, + input1_input_handler, + input2_change_handler, + textarea1_input_handler, + textarea2_input_handler, + input5_change_handler, + input6_input_handler, + input7_input_handler, + input8_input_handler + ]; + } + + class YoutubeIframeAPICustomInterface extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$d, create_fragment$d, safe_not_equal, {}, null, [-1, -1, -1]); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "YoutubeIframeAPICustomInterface", + options, + id: create_fragment$d.name + }); + } + } + + // Unique ID creation requires a high quality random # generator. In the browser we therefore + // require the crypto API and do not support built-in fallback to lower quality random number + // generators (like Math.random()). + let getRandomValues; + const rnds8 = new Uint8Array(16); + function rng() { + // lazy load so that environments that need to polyfill have a chance to do so + if (!getRandomValues) { + // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. + getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); + + if (!getRandomValues) { + throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); + } + } + + return getRandomValues(rnds8); + } + + /** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ + + const byteToHex = []; + + for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).slice(1)); + } + + function unsafeStringify(arr, offset = 0) { + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; + } + + const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); + var native = { + randomUUID }; - /* src\MovingDotSpacePortfromReact.svelte generated by Svelte v3.59.2 */ + function v4(options, buf, offset) { + if (native.randomUUID && !buf && !options) { + return native.randomUUID(); + } + + options = options || {}; + const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; + } + + return buf; + } + + return unsafeStringify(rnds); + } + + /* src\RecursiveNestedCommentsElement.svelte generated by Svelte v3.59.2 */ + + const { console: console_1$5 } = globals; + const file$c = "src\\RecursiveNestedCommentsElement.svelte"; + + function get_each_context$9(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[15] = list[i]; + child_ctx[16] = list; + child_ctx[17] = i; + return child_ctx; + } + + // (126:16) {#if showReplyInput[comment.id]} + function create_if_block$5(ctx) { + let div; + let input; + let t0; + let button; + let mounted; + let dispose; + + function input_input_handler() { + /*input_input_handler*/ ctx[12].call(input, /*comment*/ ctx[15]); + } + + function click_handler_1() { + return /*click_handler_1*/ ctx[13](/*comment*/ ctx[15]); + } + + const block = { + c: function create() { + div = element$1("div"); + input = element$1("input"); + t0 = space(); + button = element$1("button"); + button.textContent = "Post Reply"; + attr_dev(input, "placeholder", "Write a reply..."); + add_location(input, file$c, 127, 24, 5188); + add_location(button, file$c, 128, 24, 5289); + attr_dev(div, "class", "reply-input"); + add_location(div, file$c, 126, 20, 5137); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, input); + set_input_value(input, /*replyText*/ ctx[2][/*comment*/ ctx[15].id]); + append_dev(div, t0); + append_dev(div, button); + + if (!mounted) { + dispose = [ + listen_dev(input, "input", input_input_handler), + listen_dev(button, "click", click_handler_1, false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + + if (dirty & /*replyText, flattenedComments*/ 6 && input.value !== /*replyText*/ ctx[2][/*comment*/ ctx[15].id]) { + set_input_value(input, /*replyText*/ ctx[2][/*comment*/ ctx[15].id]); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block$5.name, + type: "if", + source: "(126:16) {#if showReplyInput[comment.id]}", + ctx + }); + + return block; + } + + // (122:8) {#each flattenedComments as comment} + function create_each_block$9(ctx) { + let div; + let span; + let t0_value = /*comment*/ ctx[15].title + ""; + let t0; + let t1; + let button; + let t3; + let t4; + let div_class_value; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[11](/*comment*/ ctx[15]); + } + + let if_block = /*showReplyInput*/ ctx[3][/*comment*/ ctx[15].id] && create_if_block$5(ctx); + + const block = { + c: function create() { + div = element$1("div"); + span = element$1("span"); + t0 = text(t0_value); + t1 = space(); + button = element$1("button"); + button.textContent = "Reply"; + t3 = space(); + if (if_block) if_block.c(); + t4 = space(); + add_location(span, file$c, 123, 16, 4951); + add_location(button, file$c, 124, 16, 4997); + + attr_dev(div, "class", div_class_value = "" + (null_to_empty(/*comment*/ ctx[15].level === 0 + ? 'top-level-comment' + : 'comment') + " svelte-bsj1sx")); + + set_style(div, "margin-left", /*comment*/ ctx[15].level * 20 + "px"); + add_location(div, file$c, 122, 12, 4821); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, span); + append_dev(span, t0); + append_dev(div, t1); + append_dev(div, button); + append_dev(div, t3); + if (if_block) if_block.m(div, null); + append_dev(div, t4); + + if (!mounted) { + dispose = listen_dev(button, "click", click_handler, false, false, false, false); + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + if (dirty & /*flattenedComments*/ 2 && t0_value !== (t0_value = /*comment*/ ctx[15].title + "")) set_data_dev(t0, t0_value); + + if (/*showReplyInput*/ ctx[3][/*comment*/ ctx[15].id]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block$5(ctx); + if_block.c(); + if_block.m(div, t4); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } + + if (dirty & /*flattenedComments*/ 2 && div_class_value !== (div_class_value = "" + (null_to_empty(/*comment*/ ctx[15].level === 0 + ? 'top-level-comment' + : 'comment') + " svelte-bsj1sx"))) { + attr_dev(div, "class", div_class_value); + } + + if (dirty & /*flattenedComments*/ 2) { + set_style(div, "margin-left", /*comment*/ ctx[15].level * 20 + "px"); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + if (if_block) if_block.d(); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$9.name, + type: "each", + source: "(122:8) {#each flattenedComments as comment}", + ctx + }); + + return block; + } + + function create_fragment$c(ctx) { + let h1; + let t1; + let h4; + let t3; + let simpleiframe; + let t4; + let div2; + let div0; + let button0; + let t6; + let input0; + let t7; + let input1; + let t8; + let button1; + let t10; + let br; + let t11; + let div1; + let current; + let mounted; + let dispose; + + simpleiframe = new SimpleIFrame({ + props: { webpages: /*LLMforassit*/ ctx[4] }, + $$inline: true + }); + + let each_value = /*flattenedComments*/ ctx[1]; + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$9(get_each_context$9(ctx, each_value, i)); + } + + const block = { + c: function create() { + h1 = element$1("h1"); + h1.textContent = "Reddit based Nested Comments Idea for LMM responses that need further branching responses"; + t1 = space(); + h4 = element$1("h4"); + h4.textContent = "Inspired by Vijay Bhati - https://github.com/vj98/Frontend-Machine-Coding/tree/main/nested-comments https://youtu.be/a4OA7QbHEho?list=PLBygUld3s6x8sI_H8UYROVMIVcuxUre1e"; + t3 = text("\r\nLLM: "); + create_component(simpleiframe.$$.fragment); + t4 = space(); + div2 = element$1("div"); + div0 = element$1("div"); + button0 = element$1("button"); + button0.textContent = "Export Comments"; + t6 = text("\r\n | Import Exported Comments \r\n "); + input0 = element$1("input"); + t7 = text("\r\n | \r\n "); + input1 = element$1("input"); + t8 = space(); + button1 = element$1("button"); + button1.textContent = "Post Comment"; + t10 = space(); + br = element$1("br"); + t11 = space(); + div1 = element$1("div"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + add_location(h1, file$c, 106, 0, 3964); + add_location(h4, file$c, 107, 0, 4066); + add_location(button0, file$c, 111, 8, 4395); + attr_dev(input0, "type", "file"); + add_location(input0, file$c, 113, 8, 4498); + attr_dev(input1, "placeholder", "Add a comment..."); + add_location(input1, file$c, 115, 8, 4570); + add_location(button1, file$c, 116, 8, 4644); + add_location(div0, file$c, 110, 4, 4380); + add_location(br, file$c, 119, 4, 4723); + attr_dev(div1, "id", "comment-container"); + add_location(div1, file$c, 120, 4, 4733); + attr_dev(div2, "class", "component-containter svelte-bsj1sx"); + set_style(div2, "border", "1px solid black"); + set_style(div2, "padding", "4px"); + add_location(div2, file$c, 109, 0, 4293); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, h1, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, h4, anchor); + insert_dev(target, t3, anchor); + mount_component(simpleiframe, target, anchor); + insert_dev(target, t4, anchor); + insert_dev(target, div2, anchor); + append_dev(div2, div0); + append_dev(div0, button0); + append_dev(div0, t6); + append_dev(div0, input0); + append_dev(div0, t7); + append_dev(div0, input1); + set_input_value(input1, /*newComment*/ ctx[0]); + append_dev(div0, t8); + append_dev(div0, button1); + append_dev(div2, t10); + append_dev(div2, br); + append_dev(div2, t11); + append_dev(div2, div1); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div1, null); + } + } + + current = true; + + if (!mounted) { + dispose = [ + listen_dev(button0, "click", /*exportToJson*/ ctx[8], false, false, false, false), + listen_dev(input0, "change", /*handleFileUpload*/ ctx[9], false, false, false, false), + listen_dev(input1, "input", /*input1_input_handler*/ ctx[10]), + listen_dev(button1, "click", /*addComment*/ ctx[5], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*newComment*/ 1 && input1.value !== /*newComment*/ ctx[0]) { + set_input_value(input1, /*newComment*/ ctx[0]); + } + + if (dirty & /*flattenedComments, addReply, replyText, toggleReplyInput, showReplyInput*/ 206) { + each_value = /*flattenedComments*/ ctx[1]; + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$9(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$9(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div1, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + }, + i: function intro(local) { + if (current) return; + transition_in(simpleiframe.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(simpleiframe.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + if (detaching) detach_dev(h1); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(h4); + if (detaching) detach_dev(t3); + destroy_component(simpleiframe, detaching); + if (detaching) detach_dev(t4); + if (detaching) detach_dev(div2); + destroy_each(each_blocks, detaching); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$c.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function flattenStructure(items, level = 0, parentId = null, processedIds = new Set()) { + let result = []; + + items.forEach(item => { + if (processedIds.has(item.id)) return; + result.push({ ...item, level, parentId }); + processedIds.add(item.id); + + if (item.items && Array.isArray(item.items)) { + const childItems = flattenStructure(item.items, level + 1, item.id, processedIds); + result = result.concat(childItems); + } + }); + + return result; + } + + function instance$c($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('RecursiveNestedCommentsElement', slots, []); + + let LLMforassit = [ + { + name: 'CohereForAI/c4ai-command-r-plus', + url: 'https://cohereforai-c4ai-command-r-plus.hf.space' + }, + { + name: 'ysharma/Chat_with_Meta_llama3_8b', + url: 'https://ysharma-chat-with-meta-llama3-8b.hf.space' + }, + { + name: 'Qwen/Qwen1.5-110B-Chat-demo', + url: 'https://qwen-qwen1-5-110b-chat-demo.hf.space' + } + ]; //List of models with system prompt available //{ name: '', url: '' }, + + let comments = []; + let newComment = ''; + let flattenedComments = []; + let replyText = {}; + let showReplyInput = {}; + + const addComment = () => { + comments = [ + ...comments, + { + id: v4(), + title: newComment, + items: [] + } + ]; + + $$invalidate(0, newComment = ''); + $$invalidate(1, flattenedComments = flattenStructure(comments)); + }; + + const addReply = (parentId, replyText) => { + const findAndAddReply = (items, id) => { + for (let item of items) { + if (item.id === id) { + item.items.push({ + id: v4(), + title: replyText, + items: [] + }); + + return true; + } + + if (item.items.length && findAndAddReply(item.items, id)) { + return true; + } + } + + return false; + }; + + findAndAddReply(comments, parentId); + $$invalidate(1, flattenedComments = flattenStructure(comments)); + }; + + // Function to toggle reply input + function toggleReplyInput(commentId) { + $$invalidate(3, showReplyInput[commentId] = !showReplyInput[commentId], showReplyInput); + } + + function exportToJson() { + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(comments)); + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", "comments.json"); + document.body.appendChild(downloadAnchorNode); + downloadAnchorNode.click(); + downloadAnchorNode.remove(); + } + + function handleFileUpload(event) { + const file = event.target.files[0]; + if (!file) return; + const reader = new FileReader(); + + reader.onload = e => { + const text = e.target.result; + + try { + comments = JSON.parse(text); + $$invalidate(1, flattenedComments = flattenStructure(comments)); + } catch(error) { + console.error("Error parsing JSON:", error); + } + }; + + reader.readAsText(file); + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$5.warn(` was created with unknown prop '${key}'`); + }); + + function input1_input_handler() { + newComment = this.value; + $$invalidate(0, newComment); + } + + const click_handler = comment => toggleReplyInput(comment.id); + + function input_input_handler(comment) { + replyText[comment.id] = this.value; + $$invalidate(2, replyText); + } + + const click_handler_1 = comment => { + addReply(comment.id, replyText[comment.id]); + toggleReplyInput(comment.id); + }; + + $$self.$capture_state = () => ({ + uuidv4: v4, + SimpleIFrame, + LLMforassit, + comments, + newComment, + flattenedComments, + replyText, + showReplyInput, + flattenStructure, + addComment, + addReply, + toggleReplyInput, + exportToJson, + handleFileUpload + }); + + $$self.$inject_state = $$props => { + if ('LLMforassit' in $$props) $$invalidate(4, LLMforassit = $$props.LLMforassit); + if ('comments' in $$props) comments = $$props.comments; + if ('newComment' in $$props) $$invalidate(0, newComment = $$props.newComment); + if ('flattenedComments' in $$props) $$invalidate(1, flattenedComments = $$props.flattenedComments); + if ('replyText' in $$props) $$invalidate(2, replyText = $$props.replyText); + if ('showReplyInput' in $$props) $$invalidate(3, showReplyInput = $$props.showReplyInput); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + newComment, + flattenedComments, + replyText, + showReplyInput, + LLMforassit, + addComment, + addReply, + toggleReplyInput, + exportToJson, + handleFileUpload, + input1_input_handler, + click_handler, + input_input_handler, + click_handler_1 + ]; + } + + class RecursiveNestedCommentsElement extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$c, create_fragment$c, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "RecursiveNestedCommentsElement", + options, + id: create_fragment$c.name + }); + } + } + + /* src\CopyandRemoveListComponent.svelte generated by Svelte v3.59.2 */ + + const { console: console_1$4 } = globals; + const file$b = "src\\CopyandRemoveListComponent.svelte"; + + function get_each_context$8(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[6] = list[i]; + return child_ctx; + } + + // (26:0) {:else} + function create_else_block$1(ctx) { + let each_blocks = []; + let each_1_lookup = new Map(); + let each_1_anchor; + let each_value = /*items*/ ctx[1]; + validate_each_argument(each_value); + const get_key = ctx => /*item*/ ctx[6].id; + validate_each_keys(ctx, each_value, get_each_context$8, get_key); + + for (let i = 0; i < each_value.length; i += 1) { + let child_ctx = get_each_context$8(ctx, each_value, i); + let key = get_key(child_ctx); + each_1_lookup.set(key, each_blocks[i] = create_each_block$8(key, child_ctx)); + } + + const block = { + c: function create() { + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + each_1_anchor = empty(); + }, + m: function mount(target, anchor) { + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(target, anchor); + } + } + + insert_dev(target, each_1_anchor, anchor); + }, + p: function update(ctx, dirty) { + if (dirty & /*copyAndRemoveItem, items*/ 10) { + each_value = /*items*/ ctx[1]; + validate_each_argument(each_value); + validate_each_keys(ctx, each_value, get_each_context$8, get_key); + each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, destroy_block, create_each_block$8, each_1_anchor, get_each_context$8); + } + }, + d: function destroy(detaching) { + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].d(detaching); + } + + if (detaching) detach_dev(each_1_anchor); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_else_block$1.name, + type: "else", + source: "(26:0) {:else}", + ctx + }); + + return block; + } + + // (24:0) {#if items.length === 0} + function create_if_block$4(ctx) { + let p; + + const block = { + c: function create() { + p = element$1("p"); + p.textContent = "All items have been copied! (or none entered yet)"; + add_location(p, file$b, 24, 4, 732); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block$4.name, + type: "if", + source: "(24:0) {#if items.length === 0}", + ctx + }); + + return block; + } + + // (27:4) {#each items as item (item.id)} + function create_each_block$8(key_1, ctx) { + let button; + let t0_value = /*item*/ ctx[6].text + ""; + let t0; + let t1; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[5](/*item*/ ctx[6]); + } + + const block = { + key: key_1, + first: null, + c: function create() { + button = element$1("button"); + t0 = text(t0_value); + t1 = space(); + attr_dev(button, "class", "item svelte-13m3fab"); + add_location(button, file$b, 27, 8, 844); + this.first = button; + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); + append_dev(button, t0); + append_dev(button, t1); + + if (!mounted) { + dispose = listen_dev(button, "click", click_handler, false, false, false, false); + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + if (dirty & /*items*/ 2 && t0_value !== (t0_value = /*item*/ ctx[6].text + "")) set_data_dev(t0, t0_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$8.name, + type: "each", + source: "(27:4) {#each items as item (item.id)}", + ctx + }); + + return block; + } + + function create_fragment$b(ctx) { + let h1; + let t1; + let textarea; + let t2; + let if_block_anchor; + let mounted; + let dispose; + + function select_block_type(ctx, dirty) { + if (/*items*/ ctx[1].length === 0) return create_if_block$4; + return create_else_block$1; + } + + let current_block_type = select_block_type(ctx); + let if_block = current_block_type(ctx); + + const block = { + c: function create() { + h1 = element$1("h1"); + h1.textContent = "Copy items for prompts by clicking buttons below"; + t1 = space(); + textarea = element$1("textarea"); + t2 = space(); + if_block.c(); + if_block_anchor = empty(); + add_location(h1, file$b, 19, 0, 537); + attr_dev(textarea, "placeholder", "Enter text here..."); + attr_dev(textarea, "class", "svelte-13m3fab"); + add_location(textarea, file$b, 21, 0, 598); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, h1, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, textarea, anchor); + set_input_value(textarea, /*textInput*/ ctx[0]); + insert_dev(target, t2, anchor); + if_block.m(target, anchor); + insert_dev(target, if_block_anchor, anchor); + + if (!mounted) { + dispose = [ + listen_dev(textarea, "input", /*textarea_input_handler*/ ctx[4]), + listen_dev(textarea, "input", /*updateItems*/ ctx[2], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*textInput*/ 1) { + set_input_value(textarea, /*textInput*/ ctx[0]); + } + + if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block) { + if_block.p(ctx, dirty); + } else { + if_block.d(1); + if_block = current_block_type(ctx); + + if (if_block) { + if_block.c(); + if_block.m(if_block_anchor.parentNode, if_block_anchor); + } + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(h1); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(textarea); + if (detaching) detach_dev(t2); + if_block.d(detaching); + if (detaching) detach_dev(if_block_anchor); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$b.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$b($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('CopyandRemoveListComponent', slots, []); + let textInput = ''; + let items = []; + + function updateItems() { + $$invalidate(1, items = textInput.split('\n').filter(line => line.trim() !== '').map((line, index) => ({ id: index + line, text: line }))); + } + + async function copyAndRemoveItem(item) { + try { + await navigator.clipboard.writeText(item.text); + $$invalidate(1, items = items.filter(i => i.id !== item.id)); + } catch(err) { + console.error('Failed to copy text: ', err); + } + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$4.warn(` was created with unknown prop '${key}'`); + }); + + function textarea_input_handler() { + textInput = this.value; + $$invalidate(0, textInput); + } + + const click_handler = item => copyAndRemoveItem(item); + + $$self.$capture_state = () => ({ + textInput, + items, + updateItems, + copyAndRemoveItem + }); + + $$self.$inject_state = $$props => { + if ('textInput' in $$props) $$invalidate(0, textInput = $$props.textInput); + if ('items' in $$props) $$invalidate(1, items = $$props.items); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + textInput, + items, + updateItems, + copyAndRemoveItem, + textarea_input_handler, + click_handler + ]; + } + + class CopyandRemoveListComponent extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$b, create_fragment$b, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "CopyandRemoveListComponent", + options, + id: create_fragment$b.name + }); + } + } + + /* src\ReadingStateCounter.svelte generated by Svelte v3.59.2 */ + + const file$a = "src\\ReadingStateCounter.svelte"; + + function get_each_context$7(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[8] = list[i]; + child_ctx[10] = i; + return child_ctx; + } + + // (67:4) {#each words as wordObj, index (index)} + function create_each_block$7(key_1, ctx) { + let button; + let t0_value = /*wordObj*/ ctx[8].word + ""; + let t0; + let t1; + let t2_value = /*wordObj*/ ctx[8].count + ""; + let t2; + let t3; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[7](/*index*/ ctx[10]); + } + + const block = { + key: key_1, + first: null, + c: function create() { + button = element$1("button"); + t0 = text(t0_value); + t1 = text(" ("); + t2 = text(t2_value); + t3 = text(")\r\n "); + attr_dev(button, "class", "word-button svelte-13vjncp"); + set_style(button, "background-color", getColor(/*wordObj*/ ctx[8].count)); + add_location(button, file$a, 67, 8, 1994); + this.first = button; + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); + append_dev(button, t0); + append_dev(button, t1); + append_dev(button, t2); + append_dev(button, t3); + + if (!mounted) { + dispose = listen_dev(button, "click", click_handler, false, false, false, false); + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + if (dirty & /*words*/ 2 && t0_value !== (t0_value = /*wordObj*/ ctx[8].word + "")) set_data_dev(t0, t0_value); + if (dirty & /*words*/ 2 && t2_value !== (t2_value = /*wordObj*/ ctx[8].count + "")) set_data_dev(t2, t2_value); + + if (dirty & /*words*/ 2) { + set_style(button, "background-color", getColor(/*wordObj*/ ctx[8].count)); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$7.name, + type: "each", + source: "(67:4) {#each words as wordObj, index (index)}", + ctx + }); + + return block; + } + + function create_fragment$a(ctx) { + let div0; + let h1; + let t1; + let input0; + let t2; + let button0; + let t4; + let button1; + let t6; + let input1; + let t7; + let div1; + let each_blocks = []; + let each_1_lookup = new Map(); + let mounted; + let dispose; + let each_value = /*words*/ ctx[1]; + validate_each_argument(each_value); + const get_key = ctx => /*index*/ ctx[10]; + validate_each_keys(ctx, each_value, get_each_context$7, get_key); + + for (let i = 0; i < each_value.length; i += 1) { + let child_ctx = get_each_context$7(ctx, each_value, i); + let key = get_key(child_ctx); + each_1_lookup.set(key, each_blocks[i] = create_each_block$7(key, child_ctx)); + } + + const block = { + c: function create() { + div0 = element$1("div"); + h1 = element$1("h1"); + h1.textContent = "Stateful Reader Brainstorm"; + t1 = space(); + input0 = element$1("input"); + t2 = space(); + button0 = element$1("button"); + button0.textContent = "Submit Text"; + t4 = space(); + button1 = element$1("button"); + button1.textContent = "Export to JSON"; + t6 = space(); + input1 = element$1("input"); + t7 = space(); + div1 = element$1("div"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + add_location(h1, file$a, 57, 4, 1576); + attr_dev(input0, "type", "text"); + attr_dev(input0, "placeholder", "Enter text here"); + attr_dev(input0, "class", "svelte-13vjncp"); + add_location(input0, file$a, 58, 4, 1617); + attr_dev(button0, "class", "svelte-13vjncp"); + add_location(button0, file$a, 59, 4, 1696); + attr_dev(button1, "class", "svelte-13vjncp"); + add_location(button1, file$a, 60, 4, 1752); + attr_dev(input1, "type", "file"); + attr_dev(input1, "class", "svelte-13vjncp"); + add_location(input1, file$a, 61, 4, 1813); + add_location(div0, file$a, 56, 0, 1565); + add_location(div1, file$a, 64, 0, 1873); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div0, anchor); + append_dev(div0, h1); + append_dev(div0, t1); + append_dev(div0, input0); + set_input_value(input0, /*inputText*/ ctx[0]); + append_dev(div0, t2); + append_dev(div0, button0); + append_dev(div0, t4); + append_dev(div0, button1); + append_dev(div0, t6); + append_dev(div0, input1); + insert_dev(target, t7, anchor); + insert_dev(target, div1, anchor); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div1, null); + } + } + + if (!mounted) { + dispose = [ + listen_dev(input0, "input", /*input0_input_handler*/ ctx[6]), + listen_dev(button0, "click", /*submitText*/ ctx[2], false, false, false, false), + listen_dev(button1, "click", /*exportToJson*/ ctx[4], false, false, false, false), + listen_dev(input1, "change", /*importFromJson*/ ctx[5], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*inputText*/ 1 && input0.value !== /*inputText*/ ctx[0]) { + set_input_value(input0, /*inputText*/ ctx[0]); + } + + if (dirty & /*getColor, words, handleClick*/ 10) { + each_value = /*words*/ ctx[1]; + validate_each_argument(each_value); + validate_each_keys(ctx, each_value, get_each_context$7, get_key); + each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, div1, destroy_block, create_each_block$7, null, get_each_context$7); + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div0); + if (detaching) detach_dev(t7); + if (detaching) detach_dev(div1); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].d(); + } + + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$a.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function getColor(count) { + const colors = [ + '#1a1a1a', + '#333333', + '#4d4d4d', + '#666666', + '#808080', + '#999999', + '#b3b3b3', + '#cccccc', + '#e6e6e6', + '#ffffff' + ]; + + return colors[Math.min(Math.floor(count / 10), 9)]; + } + + function instance$a($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('ReadingStateCounter', slots, []); + let inputText = ""; + let words = []; + + function submitText() { + $$invalidate(1, words = inputText.split(/\s+/).map(word => ({ word, count: 0 }))); + } + + function handleClick(index) { + $$invalidate(1, words[index].count += 1, words); + $$invalidate(1, words = [...words]); // Ensures Svelte detects the change + } + + // Function to export data to JSON + function exportToJson() { + const jsonData = JSON.stringify(words); + const blob = new Blob([jsonData], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'statefulwords.json'; + a.click(); + URL.revokeObjectURL(url); + } + + // Function to handle file import + function importFromJson(event) { + const file = event.target.files[0]; + + if (file) { + const reader = new FileReader(); + + reader.onload = e => { + const json = e.target.result; + $$invalidate(1, words = JSON.parse(json)); + }; + + reader.readAsText(file); + } + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + function input0_input_handler() { + inputText = this.value; + $$invalidate(0, inputText); + } + + const click_handler = index => handleClick(index); + + $$self.$capture_state = () => ({ + inputText, + words, + submitText, + handleClick, + getColor, + exportToJson, + importFromJson + }); + + $$self.$inject_state = $$props => { + if ('inputText' in $$props) $$invalidate(0, inputText = $$props.inputText); + if ('words' in $$props) $$invalidate(1, words = $$props.words); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + inputText, + words, + submitText, + handleClick, + exportToJson, + importFromJson, + input0_input_handler, + click_handler + ]; + } + + class ReadingStateCounter extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$a, create_fragment$a, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "ReadingStateCounter", + options, + id: create_fragment$a.name + }); + } + } + + /* src\DeliberateSubconciousRepititionPractice.svelte generated by Svelte v3.59.2 */ + + const { Object: Object_1$1, console: console_1$3 } = globals; + const file$9 = "src\\DeliberateSubconciousRepititionPractice.svelte"; + + // (156:0) {#if selectedItem} + function create_if_block_1$2(ctx) { + let div; + let strong0; + let t1; + let t2_value = /*selectedItem*/ ctx[1].text + ""; + let t2; + let t3; + let strong1; + let t5; + let t6_value = /*counts*/ ctx[2][/*selectedItem*/ ctx[1].id] + ""; + let t6; + + const block = { + c: function create() { + div = element$1("div"); + strong0 = element$1("strong"); + strong0.textContent = "Current Word:"; + t1 = space(); + t2 = text(t2_value); + t3 = space(); + strong1 = element$1("strong"); + strong1.textContent = "Count:"; + t5 = space(); + t6 = text(t6_value); + add_location(strong0, file$9, 157, 8, 5744); + add_location(strong1, file$9, 158, 8, 5805); + add_location(div, file$9, 156, 4, 5729); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, strong0); + append_dev(div, t1); + append_dev(div, t2); + append_dev(div, t3); + append_dev(div, strong1); + append_dev(div, t5); + append_dev(div, t6); + }, + p: function update(ctx, dirty) { + if (dirty & /*selectedItem*/ 2 && t2_value !== (t2_value = /*selectedItem*/ ctx[1].text + "")) set_data_dev(t2, t2_value); + if (dirty & /*counts, selectedItem*/ 6 && t6_value !== (t6_value = /*counts*/ ctx[2][/*selectedItem*/ ctx[1].id] + "")) set_data_dev(t6, t6_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_1$2.name, + type: "if", + source: "(156:0) {#if selectedItem}", + ctx + }); + + return block; + } + + // (163:0) {#if allWordsLimitReached} + function create_if_block$3(ctx) { + let div; + + const block = { + c: function create() { + div = element$1("div"); + div.textContent = "All words have reached the count limit."; + attr_dev(div, "class", "alert svelte-fb2ql8"); + add_location(div, file$9, 163, 4, 5910); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block$3.name, + type: "if", + source: "(163:0) {#if allWordsLimitReached}", + ctx + }); + + return block; + } + + function create_fragment$9(ctx) { + let h1; + let t1; + let input0; + let t2; + let button0; + let t4; + let br; + let t5; + let textarea0; + let t6; + let hr0; + let t7; + let div; + let label; + let t9; + let input1; + let t10; + let t11; + let t12; + let button1; + let t14; + let button2; + let t16; + let hr1; + let t17; + let button3; + let t19; + let textarea1; + let mounted; + let dispose; + let if_block0 = /*selectedItem*/ ctx[1] && create_if_block_1$2(ctx); + let if_block1 = /*allWordsLimitReached*/ ctx[4] && create_if_block$3(ctx); + + const block = { + c: function create() { + h1 = element$1("h1"); + h1.textContent = "Random Word till appearance count reached for TTS"; + t1 = space(); + input0 = element$1("input"); + t2 = space(); + button0 = element$1("button"); + button0.textContent = "Export Counts"; + t4 = space(); + br = element$1("br"); + t5 = space(); + textarea0 = element$1("textarea"); + t6 = space(); + hr0 = element$1("hr"); + t7 = space(); + div = element$1("div"); + label = element$1("label"); + label.textContent = "Total Count Limit:"; + t9 = space(); + input1 = element$1("input"); + t10 = space(); + if (if_block0) if_block0.c(); + t11 = space(); + if (if_block1) if_block1.c(); + t12 = space(); + button1 = element$1("button"); + button1.textContent = "Start"; + t14 = space(); + button2 = element$1("button"); + button2.textContent = "Stop"; + t16 = space(); + hr1 = element$1("hr"); + t17 = space(); + button3 = element$1("button"); + button3.textContent = "Simulate one hour or limit Counts"; + t19 = space(); + textarea1 = element$1("textarea"); + add_location(h1, file$9, 141, 0, 5255); + attr_dev(input0, "type", "file"); + add_location(input0, file$9, 143, 0, 5317); + add_location(button0, file$9, 144, 0, 5365); + add_location(br, file$9, 145, 0, 5421); + attr_dev(textarea0, "placeholder", "Enter text here..."); + add_location(textarea0, file$9, 146, 0, 5427); + add_location(hr0, file$9, 148, 0, 5531); + attr_dev(label, "for", "totalCountLimit"); + add_location(label, file$9, 151, 4, 5550); + attr_dev(input1, "type", "number"); + attr_dev(input1, "min", "1"); + attr_dev(input1, "id", "totalCountLimit"); + add_location(input1, file$9, 152, 4, 5612); + add_location(div, file$9, 150, 0, 5539); + add_location(button1, file$9, 168, 0, 6001); + add_location(button2, file$9, 169, 0, 6042); + add_location(hr1, file$9, 171, 0, 6083); + add_location(button3, file$9, 173, 0, 6091); + textarea1.readOnly = true; + attr_dev(textarea1, "placeholder", "Simulation result will be shown here..."); + add_location(textarea1, file$9, 174, 0, 6168); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, h1, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, input0, anchor); + insert_dev(target, t2, anchor); + insert_dev(target, button0, anchor); + insert_dev(target, t4, anchor); + insert_dev(target, br, anchor); + insert_dev(target, t5, anchor); + insert_dev(target, textarea0, anchor); + set_input_value(textarea0, /*textInput*/ ctx[0]); + insert_dev(target, t6, anchor); + insert_dev(target, hr0, anchor); + insert_dev(target, t7, anchor); + insert_dev(target, div, anchor); + append_dev(div, label); + append_dev(div, t9); + append_dev(div, input1); + set_input_value(input1, /*totalCountLimit*/ ctx[3]); + insert_dev(target, t10, anchor); + if (if_block0) if_block0.m(target, anchor); + insert_dev(target, t11, anchor); + if (if_block1) if_block1.m(target, anchor); + insert_dev(target, t12, anchor); + insert_dev(target, button1, anchor); + insert_dev(target, t14, anchor); + insert_dev(target, button2, anchor); + insert_dev(target, t16, anchor); + insert_dev(target, hr1, anchor); + insert_dev(target, t17, anchor); + insert_dev(target, button3, anchor); + insert_dev(target, t19, anchor); + insert_dev(target, textarea1, anchor); + set_input_value(textarea1, /*simulationResult*/ ctx[5]); + + if (!mounted) { + dispose = [ + listen_dev(input0, "change", /*importCounts*/ ctx[10], false, false, false, false), + listen_dev(button0, "click", /*exportCounts*/ ctx[9], false, false, false, false), + listen_dev(textarea0, "input", /*textarea0_input_handler*/ ctx[12]), + listen_dev(textarea0, "input", /*updateItems*/ ctx[6], false, false, false, false), + listen_dev(input1, "input", /*input1_input_handler*/ ctx[13]), + listen_dev(button1, "click", /*start*/ ctx[7], false, false, false, false), + listen_dev(button2, "click", /*stop*/ ctx[8], false, false, false, false), + listen_dev(button3, "click", /*simulateCount*/ ctx[11], false, false, false, false), + listen_dev(textarea1, "input", /*textarea1_input_handler*/ ctx[14]) + ]; + + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*textInput*/ 1) { + set_input_value(textarea0, /*textInput*/ ctx[0]); + } + + if (dirty & /*totalCountLimit*/ 8 && to_number(input1.value) !== /*totalCountLimit*/ ctx[3]) { + set_input_value(input1, /*totalCountLimit*/ ctx[3]); + } + + if (/*selectedItem*/ ctx[1]) { + if (if_block0) { + if_block0.p(ctx, dirty); + } else { + if_block0 = create_if_block_1$2(ctx); + if_block0.c(); + if_block0.m(t11.parentNode, t11); + } + } else if (if_block0) { + if_block0.d(1); + if_block0 = null; + } + + if (/*allWordsLimitReached*/ ctx[4]) { + if (if_block1) ; else { + if_block1 = create_if_block$3(ctx); + if_block1.c(); + if_block1.m(t12.parentNode, t12); + } + } else if (if_block1) { + if_block1.d(1); + if_block1 = null; + } + + if (dirty & /*simulationResult*/ 32) { + set_input_value(textarea1, /*simulationResult*/ ctx[5]); + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(h1); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(input0); + if (detaching) detach_dev(t2); + if (detaching) detach_dev(button0); + if (detaching) detach_dev(t4); + if (detaching) detach_dev(br); + if (detaching) detach_dev(t5); + if (detaching) detach_dev(textarea0); + if (detaching) detach_dev(t6); + if (detaching) detach_dev(hr0); + if (detaching) detach_dev(t7); + if (detaching) detach_dev(div); + if (detaching) detach_dev(t10); + if (if_block0) if_block0.d(detaching); + if (detaching) detach_dev(t11); + if (if_block1) if_block1.d(detaching); + if (detaching) detach_dev(t12); + if (detaching) detach_dev(button1); + if (detaching) detach_dev(t14); + if (detaching) detach_dev(button2); + if (detaching) detach_dev(t16); + if (detaching) detach_dev(hr1); + if (detaching) detach_dev(t17); + if (detaching) detach_dev(button3); + if (detaching) detach_dev(t19); + if (detaching) detach_dev(textarea1); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$9.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$9($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('DeliberateSubconciousRepititionPractice', slots, []); + let textInput = ''; + let items = []; + let running = false; + let selectedItem = null; + let intervalId = null; + let counts = {}; + let totalCountLimit = 10; // Default limit, can be changed by the user + let allWordsLimitReached = false; + let simulationResult = ''; // Variable to hold the result of the simulation + + function updateItems() { + items = textInput.split(/\W+/).filter(word => word.trim() !== '').map(word => ({ id: word, text: word })); // Use word itself as the ID + $$invalidate(2, counts = items.reduce((acc, item) => ({ ...acc, [item.id]: 0 }), {})); + } + + function start() { + if (!running && items.length > 0) { + running = true; + + intervalId = setInterval( + () => { + // Filter out items that have reached the totalCountLimit + const eligibleItems = items.filter(item => counts[item.id] < totalCountLimit); + + // If there are no eligible items left, stop the timer + if (eligibleItems.length === 0) { + stop(); + $$invalidate(4, allWordsLimitReached = true); // Set when all words reach the limit + return; + } + + // Select a random item from the eligible items + const randomIndex = Math.floor(Math.random() * eligibleItems.length); + + $$invalidate(1, selectedItem = eligibleItems[randomIndex]); + $$invalidate(2, counts[selectedItem.id]++, counts); + }, + 1000 + ); + } + } + + function stop() { + if (running) { + clearInterval(intervalId); + running = false; + intervalId = null; + } + } + + function exportCounts() { + const dataStr = JSON.stringify(counts); + const blob = new Blob([dataStr], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = "counts.json"; + link.href = url; + link.click(); + } + + function importCounts(event) { + const fileReader = new FileReader(); + + fileReader.onload = e => { + const data = JSON.parse(e.target.result); + $$invalidate(2, counts = { ...counts, ...data }); + + items = Object.keys(data).map((word, index) => ({ + id: word, // Use word itself as the ID + text: word + })); + + // Ensure existing items are updated if they are not in the imported data + items.forEach(item => { + if (!counts[item.id]) { + $$invalidate(2, counts[item.id] = 0, counts); + } + }); + }; + + fileReader.readAsText(event.target.files[0]); + } + + // ... (other variables and functions remain unchanged) + function simulateCount() { + let simulatedTime = 0; + let maxSimulatedSeconds = 3600; // 3600 seconds = 1 hour + let simulationOutput = ""; // Accumulate output here + + // Reset the allWordsLimitReached flag and simulationResult + $$invalidate(4, allWordsLimitReached = false); + + $$invalidate(5, simulationResult = ''); + + // Simulate until max time is reached or all words hit the limit + while (simulatedTime < maxSimulatedSeconds && !allWordsLimitReached) { + const eligibleItems = items.filter(item => counts[item.id] < totalCountLimit); + + if (eligibleItems.length === 0) { + $$invalidate(4, allWordsLimitReached = true); // Set when all words reach the limit + break; // Exit the loop if all words hit the limit + } + + // Select a random item and increment its count + const randomIndex = Math.floor(Math.random() * eligibleItems.length); + + $$invalidate(1, selectedItem = eligibleItems[randomIndex]); + $$invalidate(2, counts[selectedItem.id]++, counts); + simulationOutput += selectedItem.text + " "; // Append selected word to output + + // Increment simulated time (equivalent to the time between iterations in the real scenario) + simulatedTime++; + } + + // Update simulationResult with a message + if (allWordsLimitReached) { + $$invalidate(5, simulationResult = "All words have reached the count limit during simulation."); + } else { + $$invalidate(5, simulationResult = `Simulation finished after ${simulatedTime} seconds.`); + } + + // Export the simulation output to a text file + exportSimulationOutput(simulationOutput); + } + + function exportSimulationOutput(output) { + if (output) { + const blob = new Blob([output], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = "simulation_output.txt"; + link.href = url; + link.click(); + } else { + console.error("No simulation output to export."); + $$invalidate(5, simulationResult = "No simulation output to export."); + } + } + + onDestroy(() => { + if (intervalId) { + clearInterval(intervalId); + } + }); + + const writable_props = []; + + Object_1$1.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$3.warn(` was created with unknown prop '${key}'`); + }); + + function textarea0_input_handler() { + textInput = this.value; + $$invalidate(0, textInput); + } + + function input1_input_handler() { + totalCountLimit = to_number(this.value); + $$invalidate(3, totalCountLimit); + } + + function textarea1_input_handler() { + simulationResult = this.value; + $$invalidate(5, simulationResult); + } + + $$self.$capture_state = () => ({ + onDestroy, + textInput, + items, + running, + selectedItem, + intervalId, + counts, + totalCountLimit, + allWordsLimitReached, + simulationResult, + updateItems, + start, + stop, + exportCounts, + importCounts, + simulateCount, + exportSimulationOutput + }); + + $$self.$inject_state = $$props => { + if ('textInput' in $$props) $$invalidate(0, textInput = $$props.textInput); + if ('items' in $$props) items = $$props.items; + if ('running' in $$props) running = $$props.running; + if ('selectedItem' in $$props) $$invalidate(1, selectedItem = $$props.selectedItem); + if ('intervalId' in $$props) intervalId = $$props.intervalId; + if ('counts' in $$props) $$invalidate(2, counts = $$props.counts); + if ('totalCountLimit' in $$props) $$invalidate(3, totalCountLimit = $$props.totalCountLimit); + if ('allWordsLimitReached' in $$props) $$invalidate(4, allWordsLimitReached = $$props.allWordsLimitReached); + if ('simulationResult' in $$props) $$invalidate(5, simulationResult = $$props.simulationResult); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + textInput, + selectedItem, + counts, + totalCountLimit, + allWordsLimitReached, + simulationResult, + updateItems, + start, + stop, + exportCounts, + importCounts, + simulateCount, + textarea0_input_handler, + input1_input_handler, + textarea1_input_handler + ]; + } + + class DeliberateSubconciousRepititionPractice extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$9, create_fragment$9, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "DeliberateSubconciousRepititionPractice", + options, + id: create_fragment$9.name + }); + } + } + + /* src\LLMWorkflowTest.svelte generated by Svelte v3.59.2 */ + + const { Object: Object_1, console: console_1$2 } = globals; + const file$8 = "src\\LLMWorkflowTest.svelte"; + + function get_each_context$6(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[10] = list[i]; + child_ctx[11] = list; + child_ctx[12] = i; + return child_ctx; + } + + function get_each_context_1$5(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[13] = list[i]; + return child_ctx; + } + + // (87:4) {#each Object.keys(workflows) as workflow} + function create_each_block_1$5(ctx) { + let option; + let t_value = /*workflow*/ ctx[13] + ""; + let t; + + const block = { + c: function create() { + option = element$1("option"); + t = text(t_value); + option.__value = /*workflow*/ ctx[13]; + option.value = option.__value; + add_location(option, file$8, 87, 6, 2693); + }, + m: function mount(target, anchor) { + insert_dev(target, option, anchor); + append_dev(option, t); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(option); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_1$5.name, + type: "each", + source: "(87:4) {#each Object.keys(workflows) as workflow}", + ctx + }); + + return block; + } + + // (92:2) {#each placeholderInputs as placeholder} + function create_each_block$6(ctx) { + let div; + let label; + let t0; + let t1_value = /*placeholder*/ ctx[10] + ""; + let t1; + let t2; + let t3; + let input; + let mounted; + let dispose; + + function input_input_handler() { + /*input_input_handler*/ ctx[8].call(input, /*placeholder*/ ctx[10]); + } + + const block = { + c: function create() { + div = element$1("div"); + label = element$1("label"); + t0 = text("Enter word for <"); + t1 = text(t1_value); + t2 = text(">"); + t3 = space(); + input = element$1("input"); + add_location(label, file$8, 93, 6, 2828); + attr_dev(input, "type", "text"); + add_location(input, file$8, 94, 6, 2887); + add_location(div, file$8, 92, 4, 2815); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, label); + append_dev(label, t0); + append_dev(label, t1); + append_dev(label, t2); + append_dev(div, t3); + append_dev(div, input); + set_input_value(input, /*placeholderValues*/ ctx[1][/*placeholder*/ ctx[10]]); + + if (!mounted) { + dispose = [ + listen_dev(input, "input", input_input_handler), + listen_dev(input, "input", /*updateInputs*/ ctx[6], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + if (dirty & /*placeholderInputs*/ 4 && t1_value !== (t1_value = /*placeholder*/ ctx[10] + "")) set_data_dev(t1, t1_value); + + if (dirty & /*placeholderValues, placeholderInputs*/ 6 && input.value !== /*placeholderValues*/ ctx[1][/*placeholder*/ ctx[10]]) { + set_input_value(input, /*placeholderValues*/ ctx[1][/*placeholder*/ ctx[10]]); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$6.name, + type: "each", + source: "(92:2) {#each placeholderInputs as placeholder}", + ctx + }); + + return block; + } + + function create_fragment$8(ctx) { + let div1; + let h1; + let t1; + let select; + let t2; + let t3; + let div0; + let t4; + let button; + let mounted; + let dispose; + let each_value_1 = Object.keys(/*workflows*/ ctx[3]); + validate_each_argument(each_value_1); + let each_blocks_1 = []; + + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks_1[i] = create_each_block_1$5(get_each_context_1$5(ctx, each_value_1, i)); + } + + let each_value = /*placeholderInputs*/ ctx[2]; + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$6(get_each_context$6(ctx, each_value, i)); + } + + const block = { + c: function create() { + div1 = element$1("div"); + h1 = element$1("h1"); + h1.textContent = "Incompelete Workflow Interface"; + t1 = space(); + select = element$1("select"); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].c(); + } + + t2 = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t3 = space(); + div0 = element$1("div"); + t4 = space(); + button = element$1("button"); + button.textContent = "Submit"; + add_location(h1, file$8, 84, 2, 2523); + if (/*selectedWorkflow*/ ctx[0] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[7].call(select)); + add_location(select, file$8, 85, 2, 2566); + attr_dev(div0, "id", "input-group"); + add_location(div0, file$8, 102, 2, 3039); + add_location(button, file$8, 104, 2, 3073); + add_location(div1, file$8, 83, 0, 2514); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div1, anchor); + append_dev(div1, h1); + append_dev(div1, t1); + append_dev(div1, select); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + if (each_blocks_1[i]) { + each_blocks_1[i].m(select, null); + } + } + + select_option(select, /*selectedWorkflow*/ ctx[0], true); + append_dev(div1, t2); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div1, null); + } + } + + append_dev(div1, t3); + append_dev(div1, div0); + append_dev(div1, t4); + append_dev(div1, button); + + if (!mounted) { + dispose = [ + listen_dev(select, "change", /*select_change_handler*/ ctx[7]), + listen_dev(select, "change", /*handleWorkflowChange*/ ctx[4], false, false, false, false), + listen_dev(button, "click", /*processInputs*/ ctx[5], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*Object, workflows*/ 8) { + each_value_1 = Object.keys(/*workflows*/ ctx[3]); + validate_each_argument(each_value_1); + let i; + + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1$5(ctx, each_value_1, i); + + if (each_blocks_1[i]) { + each_blocks_1[i].p(child_ctx, dirty); + } else { + each_blocks_1[i] = create_each_block_1$5(child_ctx); + each_blocks_1[i].c(); + each_blocks_1[i].m(select, null); + } + } + + for (; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].d(1); + } + + each_blocks_1.length = each_value_1.length; + } + + if (dirty & /*selectedWorkflow, Object, workflows*/ 9) { + select_option(select, /*selectedWorkflow*/ ctx[0]); + } + + if (dirty & /*placeholderValues, placeholderInputs, updateInputs*/ 70) { + each_value = /*placeholderInputs*/ ctx[2]; + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$6(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$6(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div1, t3); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div1); + destroy_each(each_blocks_1, detaching); + destroy_each(each_blocks, detaching); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$8.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$8($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('LLMWorkflowTest', slots, []); + + let workflows = { + "Merged Spelling": { + steps: [ + "Please make an image description the meaning of the word ", + "next please find english words close in spelling to ", + "great, next make an image description using those words", + "Thanks lets now merge the two seperate image descriptions together" + ], + placeholders: { "": "much", "": "henduo" }, + timeline: [[], 1, [1], [0, 2]] + }, + "Another Workflow": { + steps: [ + "Do something with ", + "Then do something else with " + ], + placeholders: { + "": "value1", + "": "value2" + }, + timeline: [[], 1] + } + }; + + let selectedWorkflow = "Merged Spelling"; + let placeholderValues = workflows[selectedWorkflow].placeholders; + let placeholderInputs = Object.keys(placeholderValues); + let timeline = workflows[selectedWorkflow].timeline; + + function handleWorkflowChange() { + $$invalidate(1, placeholderValues = workflows[selectedWorkflow].placeholders); + $$invalidate(2, placeholderInputs = Object.keys(placeholderValues)); + timeline = workflows[selectedWorkflow].timeline; + updateInputs(); + } + + function processInputs() { + const inputs = document.querySelectorAll('input[type="text"]'); + console.log(`Workflow: ${selectedWorkflow}`); + + inputs.forEach((input, i) => { + console.log(`Step ${i + 1}: ${input.value}`); + }); + } + + onMount(() => { + handleWorkflowChange(); + updateInputs(); + }); + + function updateInputs() { + const inputGroup = document.getElementById('input-group'); + inputGroup.innerHTML = ''; + const steps = workflows[selectedWorkflow].steps; + + steps.forEach((step, i) => { + const label = placeholderInputs.reduce((updatedStep, placeholder) => updatedStep.replace(new RegExp(placeholder, 'g'), placeholderValues[placeholder]), step); + + const dependencyText = Array.isArray(timeline[i]) + ? timeline[i].join(', ') + : timeline[i]; + + const inputBox = ` +
+ + + ${timeline[i].length > 0 + ? `Output depends on: ${dependencyText}` + : ''} +
+ `; + + inputGroup.innerHTML += inputBox; + }); + } + + const writable_props = []; + + Object_1.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$2.warn(` was created with unknown prop '${key}'`); + }); + + function select_change_handler() { + selectedWorkflow = select_value(this); + $$invalidate(0, selectedWorkflow); + $$invalidate(3, workflows); + } + + function input_input_handler(placeholder) { + placeholderValues[placeholder] = this.value; + $$invalidate(1, placeholderValues); + } + + $$self.$capture_state = () => ({ + onMount, + workflows, + selectedWorkflow, + placeholderValues, + placeholderInputs, + timeline, + handleWorkflowChange, + processInputs, + updateInputs + }); + + $$self.$inject_state = $$props => { + if ('workflows' in $$props) $$invalidate(3, workflows = $$props.workflows); + if ('selectedWorkflow' in $$props) $$invalidate(0, selectedWorkflow = $$props.selectedWorkflow); + if ('placeholderValues' in $$props) $$invalidate(1, placeholderValues = $$props.placeholderValues); + if ('placeholderInputs' in $$props) $$invalidate(2, placeholderInputs = $$props.placeholderInputs); + if ('timeline' in $$props) timeline = $$props.timeline; + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + selectedWorkflow, + placeholderValues, + placeholderInputs, + workflows, + handleWorkflowChange, + processInputs, + updateInputs, + select_change_handler, + input_input_handler + ]; + } + + class LLMWorkflowTest extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$8, create_fragment$8, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "LLMWorkflowTest", + options, + id: create_fragment$8.name + }); + } + } + + /* src\PictureSubtitlesbasedonYTTranscript.svelte generated by Svelte v3.59.2 */ + + const { console: console_1$1 } = globals; + + const file$7 = "src\\PictureSubtitlesbasedonYTTranscript.svelte"; + + function get_each_context$5(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[25] = list[i]; + return child_ctx; + } + + function get_each_context_1$4(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[28] = list[i]; + return child_ctx; + } + + // (168:6) {#each subtitleData.images as image} + function create_each_block_1$4(ctx) { + let img; + let img_src_value; + + const block = { + c: function create() { + img = element$1("img"); + if (!src_url_equal(img.src, img_src_value = /*image*/ ctx[28])) attr_dev(img, "src", img_src_value); + attr_dev(img, "alt", "Subtitle Image"); + add_location(img, file$7, 168, 8, 5640); + }, + m: function mount(target, anchor) { + insert_dev(target, img, anchor); + }, + p: function update(ctx, dirty) { + if (dirty & /*subtitlesOutput*/ 2 && !src_url_equal(img.src, img_src_value = /*image*/ ctx[28])) { + attr_dev(img, "src", img_src_value); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(img); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_1$4.name, + type: "each", + source: "(168:6) {#each subtitleData.images as image}", + ctx + }); + + return block; + } + + // (165:2) {#each subtitlesOutput as subtitleData} + function create_each_block$5(ctx) { + let div; + let p; + let t0_value = /*subtitleData*/ ctx[25].text + ""; + let t0; + let t1; + let t2; + let each_value_1 = /*subtitleData*/ ctx[25].images; + validate_each_argument(each_value_1); + let each_blocks = []; + + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks[i] = create_each_block_1$4(get_each_context_1$4(ctx, each_value_1, i)); + } + + const block = { + c: function create() { + div = element$1("div"); + p = element$1("p"); + t0 = text(t0_value); + t1 = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t2 = space(); + add_location(p, file$7, 166, 6, 5560); + add_location(div, file$7, 165, 4, 5547); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, p); + append_dev(p, t0); + append_dev(div, t1); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div, null); + } + } + + append_dev(div, t2); + }, + p: function update(ctx, dirty) { + if (dirty & /*subtitlesOutput*/ 2 && t0_value !== (t0_value = /*subtitleData*/ ctx[25].text + "")) set_data_dev(t0, t0_value); + + if (dirty & /*subtitlesOutput*/ 2) { + each_value_1 = /*subtitleData*/ ctx[25].images; + validate_each_argument(each_value_1); + let i; + + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1$4(ctx, each_value_1, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block_1$4(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div, t2); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value_1.length; + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + destroy_each(each_blocks, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$5.name, + type: "each", + source: "(165:2) {#each subtitlesOutput as subtitleData}", + ctx + }); + + return block; + } + + function create_fragment$7(ctx) { + let div; + let p; + let t1; + let label0; + let input0; + let t2; + let br0; + let t3; + let input1; + let t4; + let button0; + let t6; + let progress_1; + let t7; + let span; + let t8_value = Math.round(/*progress*/ ctx[2]) + ""; + let t8; + let t9; + let t10; + let t11; + let t12; + let button1; + let t13_value = (/*$paused*/ ctx[8] ? 'Resume' : 'Pause') + ""; + let t13; + let t14; + let button2; + let t16; + let label1; + let input2; + let t17; + let t18; + let t19; + let t20; + let t21; + let t22; + let br1; + let t23; + let t24; + let t25; + let mounted; + let dispose; + let each_value = /*subtitlesOutput*/ ctx[1]; + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$5(get_each_context$5(ctx, each_value, i)); + } + + const block = { + c: function create() { + div = element$1("div"); + p = element$1("p"); + p.textContent = "Picture + Formatted Subtitles ||| Figure out how to use ella to make collages"; + t1 = space(); + label0 = element$1("label"); + input0 = element$1("input"); + t2 = text("\r\n Load and play video in Youtube player (tick before load subtitles)\r\n "); + br0 = element$1("br"); + t3 = space(); + input1 = element$1("input"); + t4 = space(); + button0 = element$1("button"); + button0.textContent = "Load Subtitles"; + t6 = space(); + progress_1 = element$1("progress"); + t7 = space(); + span = element$1("span"); + t8 = text(t8_value); + t9 = text("%"); + t10 = text("\r\n | "); + t11 = text(/*totalDuration*/ ctx[3]); + t12 = space(); + button1 = element$1("button"); + t13 = text(t13_value); + t14 = space(); + button2 = element$1("button"); + button2.textContent = "Restart"; + t16 = space(); + label1 = element$1("label"); + input2 = element$1("input"); + t17 = text("\r\n Show only current subtitle"); + t18 = text("\r\n Title: "); + t19 = text(/*subtitleVideoTitle*/ ctx[6]); + t20 = text(" Video Time: "); + t21 = text(/*uiTimeStatus*/ ctx[5]); + t22 = space(); + br1 = element$1("br"); + t23 = text(" | "); + t24 = text(/*uistatusupdate*/ ctx[4]); + t25 = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + add_location(p, file$7, 146, 2, 4674); + attr_dev(input0, "type", "checkbox"); + add_location(input0, file$7, 148, 4, 4775); + add_location(label0, file$7, 147, 2, 4762); + add_location(br0, file$7, 150, 10, 4915); + attr_dev(input1, "type", "file"); + attr_dev(input1, "accept", ".zip"); + add_location(input1, file$7, 151, 2, 4923); + add_location(button0, file$7, 152, 2, 5007); + progress_1.value = /*progress*/ ctx[2]; + attr_dev(progress_1, "max", "100"); + add_location(progress_1, file$7, 153, 2, 5070); + add_location(span, file$7, 154, 2, 5122); + add_location(button1, file$7, 156, 2, 5183); + add_location(button2, file$7, 157, 2, 5251); + attr_dev(input2, "type", "checkbox"); + add_location(input2, file$7, 159, 4, 5309); + add_location(label1, file$7, 158, 2, 5296); + add_location(br1, file$7, 162, 57, 5473); + attr_dev(div, "class", "borderdiv svelte-gwzbee"); + add_location(div, file$7, 145, 0, 4647); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, p); + append_dev(div, t1); + append_dev(div, label0); + append_dev(label0, input0); + input0.checked = /*$ytsubuseplayer*/ ctx[9]; + append_dev(label0, t2); + append_dev(div, br0); + append_dev(div, t3); + append_dev(div, input1); + append_dev(div, t4); + append_dev(div, button0); + append_dev(div, t6); + append_dev(div, progress_1); + append_dev(div, t7); + append_dev(div, span); + append_dev(span, t8); + append_dev(span, t9); + append_dev(div, t10); + append_dev(div, t11); + append_dev(div, t12); + append_dev(div, button1); + append_dev(button1, t13); + append_dev(div, t14); + append_dev(div, button2); + append_dev(div, t16); + append_dev(div, label1); + append_dev(label1, input2); + input2.checked = /*$onlyCurrentSubtitle*/ ctx[7]; + append_dev(label1, t17); + append_dev(div, t18); + append_dev(div, t19); + append_dev(div, t20); + append_dev(div, t21); + append_dev(div, t22); + append_dev(div, br1); + append_dev(div, t23); + append_dev(div, t24); + append_dev(div, t25); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div, null); + } + } + + if (!mounted) { + dispose = [ + listen_dev(input0, "change", /*input0_change_handler*/ ctx[16]), + listen_dev(input1, "change", /*change_handler*/ ctx[17], false, false, false, false), + listen_dev(button0, "click", /*handleFileUpload*/ ctx[13], false, false, false, false), + listen_dev(button1, "click", /*pause*/ ctx[14], false, false, false, false), + listen_dev(button2, "click", /*reset*/ ctx[15], false, false, false, false), + listen_dev(input2, "change", /*input2_change_handler*/ ctx[18]) + ]; + + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*$ytsubuseplayer*/ 512) { + input0.checked = /*$ytsubuseplayer*/ ctx[9]; + } + + if (dirty & /*progress*/ 4) { + prop_dev(progress_1, "value", /*progress*/ ctx[2]); + } + + if (dirty & /*progress*/ 4 && t8_value !== (t8_value = Math.round(/*progress*/ ctx[2]) + "")) set_data_dev(t8, t8_value); + if (dirty & /*totalDuration*/ 8) set_data_dev(t11, /*totalDuration*/ ctx[3]); + if (dirty & /*$paused*/ 256 && t13_value !== (t13_value = (/*$paused*/ ctx[8] ? 'Resume' : 'Pause') + "")) set_data_dev(t13, t13_value); + + if (dirty & /*$onlyCurrentSubtitle*/ 128) { + input2.checked = /*$onlyCurrentSubtitle*/ ctx[7]; + } + + if (dirty & /*subtitleVideoTitle*/ 64) set_data_dev(t19, /*subtitleVideoTitle*/ ctx[6]); + if (dirty & /*uiTimeStatus*/ 32) set_data_dev(t21, /*uiTimeStatus*/ ctx[5]); + if (dirty & /*uistatusupdate*/ 16) set_data_dev(t24, /*uistatusupdate*/ ctx[4]); + + if (dirty & /*subtitlesOutput*/ 2) { + each_value = /*subtitlesOutput*/ ctx[1]; + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$5(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$5(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + destroy_each(each_blocks, detaching); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$7.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$7($$self, $$props, $$invalidate) { + let $onlyCurrentSubtitle; + let $restart; + let $paused; + let $ytsubcurrenttext; + let $ytsubcurrentID; + let $ytsubuseplayer; + validate_store(ytsubcurrenttext, 'ytsubcurrenttext'); + component_subscribe($$self, ytsubcurrenttext, $$value => $$invalidate(21, $ytsubcurrenttext = $$value)); + validate_store(ytsubcurrentID, 'ytsubcurrentID'); + component_subscribe($$self, ytsubcurrentID, $$value => $$invalidate(22, $ytsubcurrentID = $$value)); + validate_store(ytsubuseplayer, 'ytsubuseplayer'); + component_subscribe($$self, ytsubuseplayer, $$value => $$invalidate(9, $ytsubuseplayer = $$value)); + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('PictureSubtitlesbasedonYTTranscript', slots, []); + let zipFile; + let subtitlesOutput = []; //writable([]); + let currentTime = writable(0); // Track current time + let paused = writable(false); // Control pause state + validate_store(paused, 'paused'); + component_subscribe($$self, paused, value => $$invalidate(8, $paused = value)); + let restart = writable(false); // Signal to restart + validate_store(restart, 'restart'); + component_subscribe($$self, restart, value => $$invalidate(20, $restart = value)); + let onlyCurrentSubtitle = writable(false); // Control subtitle display mode + validate_store(onlyCurrentSubtitle, 'onlyCurrentSubtitle'); + component_subscribe($$self, onlyCurrentSubtitle, value => $$invalidate(7, $onlyCurrentSubtitle = value)); + let progress = 0; + let totalDuration = 0; + + //let useYTPlayer = writable(false); + let uistatusupdate = null; + + let uiTimeStatus = 0; + let subtitleVideoDetailsFileData = null; + let subtitleVideoTitle = null; + + async function handleFileUpload() { + // Reset the component state + $$invalidate(1, subtitlesOutput = []); + + currentTime.set(0); + paused.set(false); + restart.set(false); + onlyCurrentSubtitle.set(false); + $$invalidate(2, progress = 0); + $$invalidate(3, totalDuration = 0); + + if (!zipFile) { + console.log('No zip file selected'); + return; + } + + const zip = new JSZip(); + const contents = await zip.loadAsync(zipFile); + console.log('Zip file loaded'); + const subtitlesFile = await contents.file('preprocessed_subtitles.json').async('text'); + const subtitlesVideoDetailsFile = await contents.file('YTTVideoInfo.txt'); + + if (subtitlesVideoDetailsFile) { + const textContent = await subtitlesVideoDetailsFile.async('text'); + + try { + subtitleVideoDetailsFileData = JSON.parse(textContent); + console.log(subtitleVideoDetailsFileData["video_id"]); + + if ($ytsubuseplayer) { + set_store_value(ytsubcurrentID, $ytsubcurrentID = subtitleVideoDetailsFileData["video_id"], $ytsubcurrentID); + } + + $$invalidate(6, subtitleVideoTitle = subtitleVideoDetailsFileData["title"]); + } catch(error) { + console.error('Error parsing JSON:', error); + } + } else { + console.error('Text file not found in the ZIP file.'); + } + + const preprocessedSubtitles = JSON.parse(subtitlesFile); + preprocessedSubtitles.sort((a, b) => a.start - b.start); + console.log('Subtitles parsed and sorted'); + $$invalidate(4, uistatusupdate = 'Subtitles parsed and sorted - Syncing to time has started'); + let localTime = 0; + let i = 0; + + const displayNextSubtitle = async () => { + console.log('Starting displayNextSubtitle'); + $$invalidate(3, totalDuration = preprocessedSubtitles.reduce((total, subtitle) => total + subtitle.duration, 0)); + + while (i < preprocessedSubtitles.length) { + const subtitle = preprocessedSubtitles[i]; + console.log('Current subtitle:', subtitle); + set_store_value(ytsubcurrenttext, $ytsubcurrenttext = subtitle.text, $ytsubcurrenttext); + + if (localTime < subtitle.start) { + await new Promise(resolve => setTimeout(resolve, (subtitle.start - localTime) * 1000)); + console.log('Waited for subtitle start time'); + } + + if ($paused) { + await new Promise(resolve => paused.subscribe(value => !value && resolve())); + console.log('Resumed from pause'); + } + + if ($restart) { + localTime = 0; + i = 0; + $$invalidate(1, subtitlesOutput = []); + restart.set(false); + console.log('Restarted subtitles'); + continue; + } + + const images = await Promise.all(subtitle.image_paths.map(async path => URL.createObjectURL(await contents.file(path).async('blob')))); + + if ($onlyCurrentSubtitle) { + $$invalidate(1, subtitlesOutput = [{ text: subtitle.text, images }]); + } else { + $$invalidate(1, subtitlesOutput = [...subtitlesOutput, { text: subtitle.text, images }]); + } + + $$invalidate(2, progress = localTime / totalDuration * 100); + await tick(); + console.log('Subtitle added to output:', subtitlesOutput); + await new Promise(resolve => setTimeout(resolve, subtitle.duration * 1000)); + console.log('Waited for subtitle duration'); + ($$invalidate(4, uistatusupdate = 'Waited for subtitle duration')); + $$invalidate(5, uiTimeStatus = localTime); + localTime += subtitle.duration; + i++; + } + + console.log('Finished displaying subtitles'); + }; + + await displayNextSubtitle(); + console.log('Finished handleFileUpload'); + } + + function pause() { + paused.update(value => !value); + } + + function reset() { + restart.set(true); + } + + function toggleSubtitleMode() { + onlyCurrentSubtitle.update(value => !value); + } + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$1.warn(` was created with unknown prop '${key}'`); + }); + + function input0_change_handler() { + $ytsubuseplayer = this.checked; + ytsubuseplayer.set($ytsubuseplayer); + } + + const change_handler = e => $$invalidate(0, zipFile = e.target.files[0]); + + function input2_change_handler() { + $onlyCurrentSubtitle = this.checked; + onlyCurrentSubtitle.set($onlyCurrentSubtitle); + } + + $$self.$capture_state = () => ({ + onMount, + tick, + writable, + JSZip, + ytsubcurrenttext, + ytsubcurrentID, + ytsubuseplayer, + ytsubuse, + zipFile, + subtitlesOutput, + currentTime, + paused, + restart, + onlyCurrentSubtitle, + progress, + totalDuration, + uistatusupdate, + uiTimeStatus, + subtitleVideoDetailsFileData, + subtitleVideoTitle, + handleFileUpload, + pause, + reset, + toggleSubtitleMode, + $onlyCurrentSubtitle, + $restart, + $paused, + $ytsubcurrenttext, + $ytsubcurrentID, + $ytsubuseplayer + }); + + $$self.$inject_state = $$props => { + if ('zipFile' in $$props) $$invalidate(0, zipFile = $$props.zipFile); + if ('subtitlesOutput' in $$props) $$invalidate(1, subtitlesOutput = $$props.subtitlesOutput); + if ('currentTime' in $$props) currentTime = $$props.currentTime; + if ('paused' in $$props) $$invalidate(10, paused = $$props.paused); + if ('restart' in $$props) $$invalidate(11, restart = $$props.restart); + if ('onlyCurrentSubtitle' in $$props) $$invalidate(12, onlyCurrentSubtitle = $$props.onlyCurrentSubtitle); + if ('progress' in $$props) $$invalidate(2, progress = $$props.progress); + if ('totalDuration' in $$props) $$invalidate(3, totalDuration = $$props.totalDuration); + if ('uistatusupdate' in $$props) $$invalidate(4, uistatusupdate = $$props.uistatusupdate); + if ('uiTimeStatus' in $$props) $$invalidate(5, uiTimeStatus = $$props.uiTimeStatus); + if ('subtitleVideoDetailsFileData' in $$props) subtitleVideoDetailsFileData = $$props.subtitleVideoDetailsFileData; + if ('subtitleVideoTitle' in $$props) $$invalidate(6, subtitleVideoTitle = $$props.subtitleVideoTitle); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + zipFile, + subtitlesOutput, + progress, + totalDuration, + uistatusupdate, + uiTimeStatus, + subtitleVideoTitle, + $onlyCurrentSubtitle, + $paused, + $ytsubuseplayer, + paused, + restart, + onlyCurrentSubtitle, + handleFileUpload, + pause, + reset, + input0_change_handler, + change_handler, + input2_change_handler + ]; + } + + class PictureSubtitlesbasedonYTTranscript extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$7, create_fragment$7, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "PictureSubtitlesbasedonYTTranscript", + options, + id: create_fragment$7.name + }); + } + } + + /* src\PSWSasspellingpractice.svelte generated by Svelte v3.59.2 */ + + const file$6 = "src\\PSWSasspellingpractice.svelte"; + + function get_each_context$4(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[3] = list[i]; + child_ctx[5] = i; + return child_ctx; + } + + function get_each_context_1$3(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[6] = list[i]; + return child_ctx; + } + + function get_each_context_2$3(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[9] = list[i]; + return child_ctx; + } + + // (25:8) {#if sentence} + function create_if_block$2(ctx) { + let h4; + let t1; + let div; + let table; + let each_value_1 = extractLetters(/*sentence*/ ctx[3]); + validate_each_argument(each_value_1); + let each_blocks = []; + + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks[i] = create_each_block_1$3(get_each_context_1$3(ctx, each_value_1, i)); + } + + const block = { + c: function create() { + h4 = element$1("h4"); + h4.textContent = "Extracted Letters:"; + t1 = space(); + div = element$1("div"); + table = element$1("table"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + add_location(h4, file$6, 25, 10, 918); + add_location(table, file$6, 27, 12, 1058); + set_style(div, "max-height", "275px"); + set_style(div, "max-width", "97%"); + set_style(div, "overflow", "auto"); + set_style(div, "display", "inline-block"); + add_location(div, file$6, 26, 10, 957); + }, + m: function mount(target, anchor) { + insert_dev(target, h4, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, div, anchor); + append_dev(div, table); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(table, null); + } + } + }, + p: function update(ctx, dirty) { + if (dirty & /*extractLetters, sentences*/ 2) { + each_value_1 = extractLetters(/*sentence*/ ctx[3]); + validate_each_argument(each_value_1); + let i; + + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1$3(ctx, each_value_1, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block_1$3(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(table, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value_1.length; + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(h4); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(div); + destroy_each(each_blocks, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block$2.name, + type: "if", + source: "(25:8) {#if sentence}", + ctx + }); + + return block; + } + + // (31:18) {#each row as cell} + function create_each_block_2$3(ctx) { + let td; + let t_value = /*cell*/ ctx[9] + ""; + let t; + + const block = { + c: function create() { + td = element$1("td"); + t = text(t_value); + add_location(td, file$6, 31, 20, 1203); + }, + m: function mount(target, anchor) { + insert_dev(target, td, anchor); + append_dev(td, t); + }, + p: function update(ctx, dirty) { + if (dirty & /*sentences*/ 2 && t_value !== (t_value = /*cell*/ ctx[9] + "")) set_data_dev(t, t_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(td); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_2$3.name, + type: "each", + source: "(31:18) {#each row as cell}", + ctx + }); + + return block; + } + + // (29:14) {#each extractLetters(sentence) as row} + function create_each_block_1$3(ctx) { + let tr; + let each_value_2 = /*row*/ ctx[6]; + validate_each_argument(each_value_2); + let each_blocks = []; + + for (let i = 0; i < each_value_2.length; i += 1) { + each_blocks[i] = create_each_block_2$3(get_each_context_2$3(ctx, each_value_2, i)); + } + + const block = { + c: function create() { + tr = element$1("tr"); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + add_location(tr, file$6, 29, 16, 1138); + }, + m: function mount(target, anchor) { + insert_dev(target, tr, anchor); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(tr, null); + } + } + }, + p: function update(ctx, dirty) { + if (dirty & /*extractLetters, sentences*/ 2) { + each_value_2 = /*row*/ ctx[6]; + validate_each_argument(each_value_2); + let i; + + for (i = 0; i < each_value_2.length; i += 1) { + const child_ctx = get_each_context_2$3(ctx, each_value_2, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block_2$3(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(tr, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value_2.length; + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(tr); + destroy_each(each_blocks, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_1$3.name, + type: "each", + source: "(29:14) {#each extractLetters(sentence) as row}", + ctx + }); + + return block; + } + + // (21:4) {#each sentences as sentence, index} + function create_each_block$4(ctx) { + let div; + let h3; + let t0; + let t1_value = /*index*/ ctx[5] + 1 + ""; + let t1; + let t2; + let t3; + let p; + let t4_value = /*sentence*/ ctx[3] + ""; + let t4; + let t5; + let if_block = /*sentence*/ ctx[3] && create_if_block$2(ctx); + + const block = { + c: function create() { + div = element$1("div"); + h3 = element$1("h3"); + t0 = text("Sentence "); + t1 = text(t1_value); + t2 = text(":"); + t3 = space(); + p = element$1("p"); + t4 = text(t4_value); + t5 = space(); + if (if_block) if_block.c(); + add_location(h3, file$6, 22, 8, 825); + add_location(p, file$6, 23, 8, 865); + add_location(div, file$6, 21, 6, 810); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, h3); + append_dev(h3, t0); + append_dev(h3, t1); + append_dev(h3, t2); + append_dev(div, t3); + append_dev(div, p); + append_dev(p, t4); + append_dev(div, t5); + if (if_block) if_block.m(div, null); + }, + p: function update(ctx, dirty) { + if (dirty & /*sentences*/ 2 && t4_value !== (t4_value = /*sentence*/ ctx[3] + "")) set_data_dev(t4, t4_value); + + if (/*sentence*/ ctx[3]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block$2(ctx); + if_block.c(); + if_block.m(div, null); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + if (if_block) if_block.d(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$4.name, + type: "each", + source: "(21:4) {#each sentences as sentence, index}", + ctx + }); + + return block; + } + + function create_fragment$6(ctx) { + let div; + let h2; + let t1; + let textarea; + let t2; + let t3; + let p; + let mounted; + let dispose; + let each_value = /*sentences*/ ctx[1]; + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$4(get_each_context$4(ctx, each_value, i)); + } + + const block = { + c: function create() { + div = element$1("div"); + h2 = element$1("h2"); + h2.textContent = "Sentence Letter Extractor"; + t1 = space(); + textarea = element$1("textarea"); + t2 = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t3 = space(); + p = element$1("p"); + p.textContent = "Example rough prompt to claude/gpt 4 to generate image prompt - The output of a random sentence brought R b N C I f L r t n f b r, please try and make a sentence where each letter is used to make a sentence with as many nouns adjectives in it while using as few words as possible"; + add_location(h2, file$6, 18, 4, 541); + set_style(textarea, "width", "95%"); + set_style(textarea, "height", "100px"); + attr_dev(textarea, "placeholder", "Enter sentences separated by full stops, question marks, exclamation marks, or colons"); + add_location(textarea, file$6, 19, 4, 581); + add_location(p, file$6, 40, 4, 1379); + add_location(div, file$6, 17, 2, 530); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, h2); + append_dev(div, t1); + append_dev(div, textarea); + set_input_value(textarea, /*inputText*/ ctx[0]); + append_dev(div, t2); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div, null); + } + } + + append_dev(div, t3); + append_dev(div, p); + + if (!mounted) { + dispose = listen_dev(textarea, "input", /*textarea_input_handler*/ ctx[2]); + mounted = true; + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*inputText*/ 1) { + set_input_value(textarea, /*inputText*/ ctx[0]); + } + + if (dirty & /*extractLetters, sentences*/ 2) { + each_value = /*sentences*/ ctx[1]; + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$4(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$4(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div, t3); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + destroy_each(each_blocks, detaching); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$6.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function extractLetters(sentence) { + const words = sentence.split(' '); + const maxLength = Math.max(...words.map(word => word.length)); + const result = []; + + for (let i = 0; i < maxLength; i++) { + const letters = words.map(word => word[i] || ''); + result.push(letters); + } + + return result; + } + + function instance$6($$self, $$props, $$invalidate) { + let sentences; + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('PSWSasspellingpractice', slots, []); + let inputText = ''; + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + function textarea_input_handler() { + inputText = this.value; + $$invalidate(0, inputText); + } + + $$self.$capture_state = () => ({ inputText, extractLetters, sentences }); + + $$self.$inject_state = $$props => { + if ('inputText' in $$props) $$invalidate(0, inputText = $$props.inputText); + if ('sentences' in $$props) $$invalidate(1, sentences = $$props.sentences); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + $$self.$$.update = () => { + if ($$self.$$.dirty & /*inputText*/ 1) { + $$invalidate(1, sentences = inputText.split(/[.?!:]/).map(sentence => sentence.trim()).filter(sentence => sentence !== '')); + } + }; + + return [inputText, sentences, textarea_input_handler]; + } + + class PSWSasspellingpractice extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$6, create_fragment$6, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "PSWSasspellingpractice", + options, + id: create_fragment$6.name + }); + } + } + + /* src\ListeningPracticeandSyllableStudy.svelte generated by Svelte v3.59.2 */ + + const file$5 = "src\\ListeningPracticeandSyllableStudy.svelte"; + + function get_each_context$3(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[6] = list[i]; + child_ctx[8] = i; + return child_ctx; + } + + // (25:4) {#each syllableLists as syllables, index (index)} + function create_each_block$3(key_1, ctx) { + let button; + let t0_value = /*displayTexts*/ ctx[1][/*index*/ ctx[8]] + ""; + let t0; + let t1; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[3](/*index*/ ctx[8]); + } + + const block = { + key: key_1, + first: null, + c: function create() { + button = element$1("button"); + t0 = text(t0_value); + t1 = space(); + set_style(button, "cursor", "pointer"); + add_location(button, file$5, 25, 8, 874); + this.first = button; + }, + m: function mount(target, anchor) { + insert_dev(target, button, anchor); + append_dev(button, t0); + append_dev(button, t1); + + if (!mounted) { + dispose = listen_dev(button, "click", click_handler, false, false, false, false); + mounted = true; + } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; + if (dirty & /*displayTexts, syllableLists*/ 3 && t0_value !== (t0_value = /*displayTexts*/ ctx[1][/*index*/ ctx[8]] + "")) set_data_dev(t0, t0_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(button); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$3.name, + type: "each", + source: "(25:4) {#each syllableLists as syllables, index (index)}", + ctx + }); + + return block; + } + + function create_fragment$5(ctx) { + let main; + let div; + let t1; + let each_blocks = []; + let each_1_lookup = new Map(); + let each_value = /*syllableLists*/ ctx[0]; + validate_each_argument(each_value); + const get_key = ctx => /*index*/ ctx[8]; + validate_each_keys(ctx, each_value, get_each_context$3, get_key); + + for (let i = 0; i < each_value.length; i += 1) { + let child_ctx = get_each_context$3(ctx, each_value, i); + let key = get_key(child_ctx); + each_1_lookup.set(key, each_blocks[i] = create_each_block$3(key, child_ctx)); + } + + const block = { + c: function create() { + main = element$1("main"); + div = element$1("div"); + div.textContent = "On click will Show Next Syllable"; + t1 = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + attr_dev(div, "class", "svelte-18he4oy"); + add_location(div, file$5, 23, 4, 766); + add_location(main, file$5, 22, 0, 754); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, main, anchor); + append_dev(main, div); + append_dev(main, t1); + + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(main, null); + } + } + }, + p: function update(ctx, [dirty]) { + if (dirty & /*nextSyllable, syllableLists, displayTexts*/ 7) { + each_value = /*syllableLists*/ ctx[0]; + validate_each_argument(each_value); + validate_each_keys(ctx, each_value, get_each_context$3, get_key); + each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, main, destroy_block, create_each_block$3, null, get_each_context$3); + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(main); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].d(); + } + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$5.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$5($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('ListeningPracticeandSyllableStudy', slots, []); + let { syllableLists = [] } = $$props; + let currentSyllableIndices = Array(syllableLists.length).fill(0); + let displayTexts = syllableLists.map((list, index) => list[0]); + + function nextSyllable(wordIndex) { + if (currentSyllableIndices[wordIndex] < syllableLists[wordIndex].length - 1) { + currentSyllableIndices[wordIndex]++; + } else { + currentSyllableIndices[wordIndex] = 0; + } + + updateDisplayText(wordIndex); + } + + function updateDisplayText(wordIndex) { + $$invalidate(1, displayTexts[wordIndex] = syllableLists[wordIndex].slice(0, currentSyllableIndices[wordIndex] + 1).join(''), displayTexts); + } + + const writable_props = ['syllableLists']; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + const click_handler = index => nextSyllable(index); + + $$self.$$set = $$props => { + if ('syllableLists' in $$props) $$invalidate(0, syllableLists = $$props.syllableLists); + }; + + $$self.$capture_state = () => ({ + syllableLists, + currentSyllableIndices, + displayTexts, + nextSyllable, + updateDisplayText + }); + + $$self.$inject_state = $$props => { + if ('syllableLists' in $$props) $$invalidate(0, syllableLists = $$props.syllableLists); + if ('currentSyllableIndices' in $$props) currentSyllableIndices = $$props.currentSyllableIndices; + if ('displayTexts' in $$props) $$invalidate(1, displayTexts = $$props.displayTexts); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [syllableLists, displayTexts, nextSyllable, click_handler]; + } + + class ListeningPracticeandSyllableStudy extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$5, create_fragment$5, safe_not_equal, { syllableLists: 0 }); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "ListeningPracticeandSyllableStudy", + options, + id: create_fragment$5.name + }); + } + + get syllableLists() { + throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); + } + + set syllableLists(value) { + throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); + } + } + + /* src\Testspace.svelte generated by Svelte v3.59.2 */ + + function create_fragment$4(ctx) { + let t; + + const block = { + c: function create() { + t = text("Audio Repitition Creation tool options - Kaggle script?"); + }, + l: function claim(nodes) { + throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + }, + m: function mount(target, anchor) { + insert_dev(target, t, anchor); + }, + p: noop$2, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(t); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$4.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function instance$4($$self, $$props) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('Testspace', slots, []); + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + return []; + } + + class Testspace extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$4, create_fragment$4, safe_not_equal, {}); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "Testspace", + options, + id: create_fragment$4.name + }); + } + } - const { Object: Object_1$2, console: console_1$6 } = globals; + /** + * @license + * Copyright (c) 2023, Jeff Hlywa (jhlywa@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + const WHITE = 'w'; + const BLACK = 'b'; + const PAWN = 'p'; + const KNIGHT = 'n'; + const BISHOP = 'b'; + const ROOK = 'r'; + const QUEEN = 'q'; + const KING = 'k'; + const DEFAULT_POSITION = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'; + const EMPTY = -1; + const FLAGS = { + NORMAL: 'n', + CAPTURE: 'c', + BIG_PAWN: 'b', + EP_CAPTURE: 'e', + PROMOTION: 'p', + KSIDE_CASTLE: 'k', + QSIDE_CASTLE: 'q', + }; + const BITS = { + NORMAL: 1, + CAPTURE: 2, + BIG_PAWN: 4, + EP_CAPTURE: 8, + PROMOTION: 16, + KSIDE_CASTLE: 32, + QSIDE_CASTLE: 64, + }; + /* + * NOTES ABOUT 0x88 MOVE GENERATION ALGORITHM + * ---------------------------------------------------------------------------- + * From https://github.com/jhlywa/chess.js/issues/230 + * + * A lot of people are confused when they first see the internal representation + * of chess.js. It uses the 0x88 Move Generation Algorithm which internally + * stores the board as an 8x16 array. This is purely for efficiency but has a + * couple of interesting benefits: + * + * 1. 0x88 offers a very inexpensive "off the board" check. Bitwise AND (&) any + * square with 0x88, if the result is non-zero then the square is off the + * board. For example, assuming a knight square A8 (0 in 0x88 notation), + * there are 8 possible directions in which the knight can move. These + * directions are relative to the 8x16 board and are stored in the + * PIECE_OFFSETS map. One possible move is A8 - 18 (up one square, and two + * squares to the left - which is off the board). 0 - 18 = -18 & 0x88 = 0x88 + * (because of two-complement representation of -18). The non-zero result + * means the square is off the board and the move is illegal. Take the + * opposite move (from A8 to C7), 0 + 18 = 18 & 0x88 = 0. A result of zero + * means the square is on the board. + * + * 2. The relative distance (or difference) between two squares on a 8x16 board + * is unique and can be used to inexpensively determine if a piece on a + * square can attack any other arbitrary square. For example, let's see if a + * pawn on E7 can attack E2. The difference between E7 (20) - E2 (100) is + * -80. We add 119 to make the ATTACKS array index non-negative (because the + * worst case difference is A8 - H1 = -119). The ATTACKS array contains a + * bitmask of pieces that can attack from that distance and direction. + * ATTACKS[-80 + 119=39] gives us 24 or 0b11000 in binary. Look at the + * PIECE_MASKS map to determine the mask for a given piece type. In our pawn + * example, we would check to see if 24 & 0x1 is non-zero, which it is + * not. So, naturally, a pawn on E7 can't attack a piece on E2. However, a + * rook can since 24 & 0x8 is non-zero. The only thing left to check is that + * there are no blocking pieces between E7 and E2. That's where the RAYS + * array comes in. It provides an offset (in this case 16) to add to E7 (20) + * to check for blocking pieces. E7 (20) + 16 = E6 (36) + 16 = E5 (52) etc. + */ + // prettier-ignore + // eslint-disable-next-line + const Ox88 = { + a8: 0, b8: 1, c8: 2, d8: 3, e8: 4, f8: 5, g8: 6, h8: 7, + a7: 16, b7: 17, c7: 18, d7: 19, e7: 20, f7: 21, g7: 22, h7: 23, + a6: 32, b6: 33, c6: 34, d6: 35, e6: 36, f6: 37, g6: 38, h6: 39, + a5: 48, b5: 49, c5: 50, d5: 51, e5: 52, f5: 53, g5: 54, h5: 55, + a4: 64, b4: 65, c4: 66, d4: 67, e4: 68, f4: 69, g4: 70, h4: 71, + a3: 80, b3: 81, c3: 82, d3: 83, e3: 84, f3: 85, g3: 86, h3: 87, + a2: 96, b2: 97, c2: 98, d2: 99, e2: 100, f2: 101, g2: 102, h2: 103, + a1: 112, b1: 113, c1: 114, d1: 115, e1: 116, f1: 117, g1: 118, h1: 119 + }; + const PAWN_OFFSETS = { + b: [16, 32, 17, 15], + w: [-16, -32, -17, -15], + }; + const PIECE_OFFSETS = { + n: [-18, -33, -31, -14, 18, 33, 31, 14], + b: [-17, -15, 17, 15], + r: [-16, 1, 16, -1], + q: [-17, -16, -15, 1, 17, 16, 15, -1], + k: [-17, -16, -15, 1, 17, 16, 15, -1], + }; + // prettier-ignore + const ATTACKS = [ + 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 20, 0, + 0, 20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 20, 0, 0, + 0, 0, 20, 0, 0, 0, 0, 24, 0, 0, 0, 0, 20, 0, 0, 0, + 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 24, 0, 0, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 2, 24, 2, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 53, 56, 53, 2, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 56, 0, 56, 24, 24, 24, 24, 24, 24, 0, + 0, 0, 0, 0, 0, 2, 53, 56, 53, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 2, 24, 2, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 24, 0, 0, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 20, 0, 0, 0, 0, + 0, 0, 20, 0, 0, 0, 0, 24, 0, 0, 0, 0, 20, 0, 0, 0, + 0, 20, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 20, 0, 0, + 20, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 20 + ]; + // prettier-ignore + const RAYS = [ + 17, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 15, 0, + 0, 17, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 15, 0, 0, + 0, 0, 17, 0, 0, 0, 0, 16, 0, 0, 0, 0, 15, 0, 0, 0, + 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 15, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 16, 0, 15, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 16, 15, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, 0, + 0, 0, 0, 0, 0, 0, -15, -16, -17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -15, 0, -16, 0, -17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -15, 0, 0, -16, 0, 0, -17, 0, 0, 0, 0, 0, + 0, 0, 0, -15, 0, 0, 0, -16, 0, 0, 0, -17, 0, 0, 0, 0, + 0, 0, -15, 0, 0, 0, 0, -16, 0, 0, 0, 0, -17, 0, 0, 0, + 0, -15, 0, 0, 0, 0, 0, -16, 0, 0, 0, 0, 0, -17, 0, 0, + -15, 0, 0, 0, 0, 0, 0, -16, 0, 0, 0, 0, 0, 0, -17 + ]; + const PIECE_MASKS = { p: 0x1, n: 0x2, b: 0x4, r: 0x8, q: 0x10, k: 0x20 }; + const SYMBOLS = 'pnbrqkPNBRQK'; + const PROMOTIONS = [KNIGHT, BISHOP, ROOK, QUEEN]; + const RANK_1 = 7; + const RANK_2 = 6; + /* + * const RANK_3 = 5 + * const RANK_4 = 4 + * const RANK_5 = 3 + * const RANK_6 = 2 + */ + const RANK_7 = 1; + const RANK_8 = 0; + const SIDES = { + [KING]: BITS.KSIDE_CASTLE, + [QUEEN]: BITS.QSIDE_CASTLE, + }; + const ROOKS = { + w: [ + { square: Ox88.a1, flag: BITS.QSIDE_CASTLE }, + { square: Ox88.h1, flag: BITS.KSIDE_CASTLE }, + ], + b: [ + { square: Ox88.a8, flag: BITS.QSIDE_CASTLE }, + { square: Ox88.h8, flag: BITS.KSIDE_CASTLE }, + ], + }; + const SECOND_RANK = { b: RANK_7, w: RANK_2 }; + const TERMINATION_MARKERS = ['1-0', '0-1', '1/2-1/2', '*']; + // Extracts the zero-based rank of an 0x88 square. + function rank(square) { + return square >> 4; + } + // Extracts the zero-based file of an 0x88 square. + function file$4(square) { + return square & 0xf; + } + function isDigit(c) { + return '0123456789'.indexOf(c) !== -1; + } + // Converts a 0x88 square to algebraic notation. + function algebraic(square) { + const f = file$4(square); + const r = rank(square); + return ('abcdefgh'.substring(f, f + 1) + + '87654321'.substring(r, r + 1)); + } + function swapColor(color) { + return color === WHITE ? BLACK : WHITE; + } + function validateFen(fen) { + // 1st criterion: 6 space-seperated fields? + const tokens = fen.split(/\s+/); + if (tokens.length !== 6) { + return { + ok: false, + error: 'Invalid FEN: must contain six space-delimited fields', + }; + } + // 2nd criterion: move number field is a integer value > 0? + const moveNumber = parseInt(tokens[5], 10); + if (isNaN(moveNumber) || moveNumber <= 0) { + return { + ok: false, + error: 'Invalid FEN: move number must be a positive integer', + }; + } + // 3rd criterion: half move counter is an integer >= 0? + const halfMoves = parseInt(tokens[4], 10); + if (isNaN(halfMoves) || halfMoves < 0) { + return { + ok: false, + error: 'Invalid FEN: half move counter number must be a non-negative integer', + }; + } + // 4th criterion: 4th field is a valid e.p.-string? + if (!/^(-|[abcdefgh][36])$/.test(tokens[3])) { + return { ok: false, error: 'Invalid FEN: en-passant square is invalid' }; + } + // 5th criterion: 3th field is a valid castle-string? + if (/[^kKqQ-]/.test(tokens[2])) { + return { ok: false, error: 'Invalid FEN: castling availability is invalid' }; + } + // 6th criterion: 2nd field is "w" (white) or "b" (black)? + if (!/^(w|b)$/.test(tokens[1])) { + return { ok: false, error: 'Invalid FEN: side-to-move is invalid' }; + } + // 7th criterion: 1st field contains 8 rows? + const rows = tokens[0].split('/'); + if (rows.length !== 8) { + return { + ok: false, + error: "Invalid FEN: piece data does not contain 8 '/'-delimited rows", + }; + } + // 8th criterion: every row is valid? + for (let i = 0; i < rows.length; i++) { + // check for right sum of fields AND not two numbers in succession + let sumFields = 0; + let previousWasNumber = false; + for (let k = 0; k < rows[i].length; k++) { + if (isDigit(rows[i][k])) { + if (previousWasNumber) { + return { + ok: false, + error: 'Invalid FEN: piece data is invalid (consecutive number)', + }; + } + sumFields += parseInt(rows[i][k], 10); + previousWasNumber = true; + } + else { + if (!/^[prnbqkPRNBQK]$/.test(rows[i][k])) { + return { + ok: false, + error: 'Invalid FEN: piece data is invalid (invalid piece)', + }; + } + sumFields += 1; + previousWasNumber = false; + } + } + if (sumFields !== 8) { + return { + ok: false, + error: 'Invalid FEN: piece data is invalid (too many squares in rank)', + }; + } + } + // 9th criterion: is en-passant square legal? + if ((tokens[3][1] == '3' && tokens[1] == 'w') || + (tokens[3][1] == '6' && tokens[1] == 'b')) { + return { ok: false, error: 'Invalid FEN: illegal en-passant square' }; + } + // 10th criterion: does chess position contain exact two kings? + const kings = [ + { color: 'white', regex: /K/g }, + { color: 'black', regex: /k/g }, + ]; + for (const { color, regex } of kings) { + if (!regex.test(tokens[0])) { + return { ok: false, error: `Invalid FEN: missing ${color} king` }; + } + if ((tokens[0].match(regex) || []).length > 1) { + return { ok: false, error: `Invalid FEN: too many ${color} kings` }; + } + } + // 11th criterion: are any pawns on the first or eighth rows? + if (Array.from(rows[0] + rows[7]).some((char) => char.toUpperCase() === 'P')) { + return { + ok: false, + error: 'Invalid FEN: some pawns are on the edge rows', + }; + } + return { ok: true }; + } + // this function is used to uniquely identify ambiguous moves + function getDisambiguator(move, moves) { + const from = move.from; + const to = move.to; + const piece = move.piece; + let ambiguities = 0; + let sameRank = 0; + let sameFile = 0; + for (let i = 0, len = moves.length; i < len; i++) { + const ambigFrom = moves[i].from; + const ambigTo = moves[i].to; + const ambigPiece = moves[i].piece; + /* + * if a move of the same piece type ends on the same to square, we'll need + * to add a disambiguator to the algebraic notation + */ + if (piece === ambigPiece && from !== ambigFrom && to === ambigTo) { + ambiguities++; + if (rank(from) === rank(ambigFrom)) { + sameRank++; + } + if (file$4(from) === file$4(ambigFrom)) { + sameFile++; + } + } + } + if (ambiguities > 0) { + if (sameRank > 0 && sameFile > 0) { + /* + * if there exists a similar moving piece on the same rank and file as + * the move in question, use the square as the disambiguator + */ + return algebraic(from); + } + else if (sameFile > 0) { + /* + * if the moving piece rests on the same file, use the rank symbol as the + * disambiguator + */ + return algebraic(from).charAt(1); + } + else { + // else use the file symbol + return algebraic(from).charAt(0); + } + } + return ''; + } + function addMove(moves, color, from, to, piece, captured = undefined, flags = BITS.NORMAL) { + const r = rank(to); + if (piece === PAWN && (r === RANK_1 || r === RANK_8)) { + for (let i = 0; i < PROMOTIONS.length; i++) { + const promotion = PROMOTIONS[i]; + moves.push({ + color, + from, + to, + piece, + captured, + promotion, + flags: flags | BITS.PROMOTION, + }); + } + } + else { + moves.push({ + color, + from, + to, + piece, + captured, + flags, + }); + } + } + function inferPieceType(san) { + let pieceType = san.charAt(0); + if (pieceType >= 'a' && pieceType <= 'h') { + const matches = san.match(/[a-h]\d.*[a-h]\d/); + if (matches) { + return undefined; + } + return PAWN; + } + pieceType = pieceType.toLowerCase(); + if (pieceType === 'o') { + return KING; + } + return pieceType; + } + // parses all of the decorators out of a SAN string + function strippedSan(move) { + return move.replace(/=/, '').replace(/[+#]?[?!]*$/, ''); + } + function trimFen(fen) { + /* + * remove last two fields in FEN string as they're not needed when checking + * for repetition + */ + return fen.split(' ').slice(0, 4).join(' '); + } + class Chess { + _board = new Array(128); + _turn = WHITE; + _header = {}; + _kings = { w: EMPTY, b: EMPTY }; + _epSquare = -1; + _halfMoves = 0; + _moveNumber = 0; + _history = []; + _comments = {}; + _castling = { w: 0, b: 0 }; + // tracks number of times a position has been seen for repetition checking + _positionCount = {}; + constructor(fen = DEFAULT_POSITION) { + this.load(fen); + } + clear({ preserveHeaders = false } = {}) { + this._board = new Array(128); + this._kings = { w: EMPTY, b: EMPTY }; + this._turn = WHITE; + this._castling = { w: 0, b: 0 }; + this._epSquare = EMPTY; + this._halfMoves = 0; + this._moveNumber = 1; + this._history = []; + this._comments = {}; + this._header = preserveHeaders ? this._header : {}; + this._positionCount = {}; + /* + * Delete the SetUp and FEN headers (if preserved), the board is empty and + * these headers don't make sense in this state. They'll get added later + * via .load() or .put() + */ + delete this._header['SetUp']; + delete this._header['FEN']; + } + removeHeader(key) { + if (key in this._header) { + delete this._header[key]; + } + } + load(fen, { skipValidation = false, preserveHeaders = false } = {}) { + let tokens = fen.split(/\s+/); + // append commonly omitted fen tokens + if (tokens.length >= 2 && tokens.length < 6) { + const adjustments = ['-', '-', '0', '1']; + fen = tokens.concat(adjustments.slice(-(6 - tokens.length))).join(' '); + } + tokens = fen.split(/\s+/); + if (!skipValidation) { + const { ok, error } = validateFen(fen); + if (!ok) { + throw new Error(error); + } + } + const position = tokens[0]; + let square = 0; + this.clear({ preserveHeaders }); + for (let i = 0; i < position.length; i++) { + const piece = position.charAt(i); + if (piece === '/') { + square += 8; + } + else if (isDigit(piece)) { + square += parseInt(piece, 10); + } + else { + const color = piece < 'a' ? WHITE : BLACK; + this._put({ type: piece.toLowerCase(), color }, algebraic(square)); + square++; + } + } + this._turn = tokens[1]; + if (tokens[2].indexOf('K') > -1) { + this._castling.w |= BITS.KSIDE_CASTLE; + } + if (tokens[2].indexOf('Q') > -1) { + this._castling.w |= BITS.QSIDE_CASTLE; + } + if (tokens[2].indexOf('k') > -1) { + this._castling.b |= BITS.KSIDE_CASTLE; + } + if (tokens[2].indexOf('q') > -1) { + this._castling.b |= BITS.QSIDE_CASTLE; + } + this._epSquare = tokens[3] === '-' ? EMPTY : Ox88[tokens[3]]; + this._halfMoves = parseInt(tokens[4], 10); + this._moveNumber = parseInt(tokens[5], 10); + this._updateSetup(fen); + this._incPositionCount(fen); + } + fen() { + let empty = 0; + let fen = ''; + for (let i = Ox88.a8; i <= Ox88.h1; i++) { + if (this._board[i]) { + if (empty > 0) { + fen += empty; + empty = 0; + } + const { color, type: piece } = this._board[i]; + fen += color === WHITE ? piece.toUpperCase() : piece.toLowerCase(); + } + else { + empty++; + } + if ((i + 1) & 0x88) { + if (empty > 0) { + fen += empty; + } + if (i !== Ox88.h1) { + fen += '/'; + } + empty = 0; + i += 8; + } + } + let castling = ''; + if (this._castling[WHITE] & BITS.KSIDE_CASTLE) { + castling += 'K'; + } + if (this._castling[WHITE] & BITS.QSIDE_CASTLE) { + castling += 'Q'; + } + if (this._castling[BLACK] & BITS.KSIDE_CASTLE) { + castling += 'k'; + } + if (this._castling[BLACK] & BITS.QSIDE_CASTLE) { + castling += 'q'; + } + // do we have an empty castling flag? + castling = castling || '-'; + let epSquare = '-'; + /* + * only print the ep square if en passant is a valid move (pawn is present + * and ep capture is not pinned) + */ + if (this._epSquare !== EMPTY) { + const bigPawnSquare = this._epSquare + (this._turn === WHITE ? 16 : -16); + const squares = [bigPawnSquare + 1, bigPawnSquare - 1]; + for (const square of squares) { + // is the square off the board? + if (square & 0x88) { + continue; + } + const color = this._turn; + // is there a pawn that can capture the epSquare? + if (this._board[square]?.color === color && + this._board[square]?.type === PAWN) { + // if the pawn makes an ep capture, does it leave it's king in check? + this._makeMove({ + color, + from: square, + to: this._epSquare, + piece: PAWN, + captured: PAWN, + flags: BITS.EP_CAPTURE, + }); + const isLegal = !this._isKingAttacked(color); + this._undoMove(); + // if ep is legal, break and set the ep square in the FEN output + if (isLegal) { + epSquare = algebraic(this._epSquare); + break; + } + } + } + } + return [ + fen, + this._turn, + castling, + epSquare, + this._halfMoves, + this._moveNumber, + ].join(' '); + } + /* + * Called when the initial board setup is changed with put() or remove(). + * modifies the SetUp and FEN properties of the header object. If the FEN + * is equal to the default position, the SetUp and FEN are deleted the setup + * is only updated if history.length is zero, ie moves haven't been made. + */ + _updateSetup(fen) { + if (this._history.length > 0) + return; + if (fen !== DEFAULT_POSITION) { + this._header['SetUp'] = '1'; + this._header['FEN'] = fen; + } + else { + delete this._header['SetUp']; + delete this._header['FEN']; + } + } + reset() { + this.load(DEFAULT_POSITION); + } + get(square) { + return this._board[Ox88[square]] || false; + } + put({ type, color }, square) { + if (this._put({ type, color }, square)) { + this._updateCastlingRights(); + this._updateEnPassantSquare(); + this._updateSetup(this.fen()); + return true; + } + return false; + } + _put({ type, color }, square) { + // check for piece + if (SYMBOLS.indexOf(type.toLowerCase()) === -1) { + return false; + } + // check for valid square + if (!(square in Ox88)) { + return false; + } + const sq = Ox88[square]; + // don't let the user place more than one king + if (type == KING && + !(this._kings[color] == EMPTY || this._kings[color] == sq)) { + return false; + } + const currentPieceOnSquare = this._board[sq]; + // if one of the kings will be replaced by the piece from args, set the `_kings` respective entry to `EMPTY` + if (currentPieceOnSquare && currentPieceOnSquare.type === KING) { + this._kings[currentPieceOnSquare.color] = EMPTY; + } + this._board[sq] = { type: type, color: color }; + if (type === KING) { + this._kings[color] = sq; + } + return true; + } + remove(square) { + const piece = this.get(square); + delete this._board[Ox88[square]]; + if (piece && piece.type === KING) { + this._kings[piece.color] = EMPTY; + } + this._updateCastlingRights(); + this._updateEnPassantSquare(); + this._updateSetup(this.fen()); + return piece; + } + _updateCastlingRights() { + const whiteKingInPlace = this._board[Ox88.e1]?.type === KING && + this._board[Ox88.e1]?.color === WHITE; + const blackKingInPlace = this._board[Ox88.e8]?.type === KING && + this._board[Ox88.e8]?.color === BLACK; + if (!whiteKingInPlace || + this._board[Ox88.a1]?.type !== ROOK || + this._board[Ox88.a1]?.color !== WHITE) { + this._castling.w &= ~BITS.QSIDE_CASTLE; + } + if (!whiteKingInPlace || + this._board[Ox88.h1]?.type !== ROOK || + this._board[Ox88.h1]?.color !== WHITE) { + this._castling.w &= ~BITS.KSIDE_CASTLE; + } + if (!blackKingInPlace || + this._board[Ox88.a8]?.type !== ROOK || + this._board[Ox88.a8]?.color !== BLACK) { + this._castling.b &= ~BITS.QSIDE_CASTLE; + } + if (!blackKingInPlace || + this._board[Ox88.h8]?.type !== ROOK || + this._board[Ox88.h8]?.color !== BLACK) { + this._castling.b &= ~BITS.KSIDE_CASTLE; + } + } + _updateEnPassantSquare() { + if (this._epSquare === EMPTY) { + return; + } + const startSquare = this._epSquare + (this._turn === WHITE ? -16 : 16); + const currentSquare = this._epSquare + (this._turn === WHITE ? 16 : -16); + const attackers = [currentSquare + 1, currentSquare - 1]; + if (this._board[startSquare] !== null || + this._board[this._epSquare] !== null || + this._board[currentSquare]?.color !== swapColor(this._turn) || + this._board[currentSquare]?.type !== PAWN) { + this._epSquare = EMPTY; + return; + } + const canCapture = (square) => !(square & 0x88) && + this._board[square]?.color === this._turn && + this._board[square]?.type === PAWN; + if (!attackers.some(canCapture)) { + this._epSquare = EMPTY; + } + } + _attacked(color, square) { + for (let i = Ox88.a8; i <= Ox88.h1; i++) { + // did we run off the end of the board + if (i & 0x88) { + i += 7; + continue; + } + // if empty square or wrong color + if (this._board[i] === undefined || this._board[i].color !== color) { + continue; + } + const piece = this._board[i]; + const difference = i - square; + // skip - to/from square are the same + if (difference === 0) { + continue; + } + const index = difference + 119; + if (ATTACKS[index] & PIECE_MASKS[piece.type]) { + if (piece.type === PAWN) { + if (difference > 0) { + if (piece.color === WHITE) + return true; + } + else { + if (piece.color === BLACK) + return true; + } + continue; + } + // if the piece is a knight or a king + if (piece.type === 'n' || piece.type === 'k') + return true; + const offset = RAYS[index]; + let j = i + offset; + let blocked = false; + while (j !== square) { + if (this._board[j] != null) { + blocked = true; + break; + } + j += offset; + } + if (!blocked) + return true; + } + } + return false; + } + _isKingAttacked(color) { + const square = this._kings[color]; + return square === -1 ? false : this._attacked(swapColor(color), square); + } + isAttacked(square, attackedBy) { + return this._attacked(attackedBy, Ox88[square]); + } + isCheck() { + return this._isKingAttacked(this._turn); + } + inCheck() { + return this.isCheck(); + } + isCheckmate() { + return this.isCheck() && this._moves().length === 0; + } + isStalemate() { + return !this.isCheck() && this._moves().length === 0; + } + isInsufficientMaterial() { + /* + * k.b. vs k.b. (of opposite colors) with mate in 1: + * 8/8/8/8/1b6/8/B1k5/K7 b - - 0 1 + * + * k.b. vs k.n. with mate in 1: + * 8/8/8/8/1n6/8/B7/K1k5 b - - 2 1 + */ + const pieces = { + b: 0, + n: 0, + r: 0, + q: 0, + k: 0, + p: 0, + }; + const bishops = []; + let numPieces = 0; + let squareColor = 0; + for (let i = Ox88.a8; i <= Ox88.h1; i++) { + squareColor = (squareColor + 1) % 2; + if (i & 0x88) { + i += 7; + continue; + } + const piece = this._board[i]; + if (piece) { + pieces[piece.type] = piece.type in pieces ? pieces[piece.type] + 1 : 1; + if (piece.type === BISHOP) { + bishops.push(squareColor); + } + numPieces++; + } + } + // k vs. k + if (numPieces === 2) { + return true; + } + else if ( + // k vs. kn .... or .... k vs. kb + numPieces === 3 && + (pieces[BISHOP] === 1 || pieces[KNIGHT] === 1)) { + return true; + } + else if (numPieces === pieces[BISHOP] + 2) { + // kb vs. kb where any number of bishops are all on the same color + let sum = 0; + const len = bishops.length; + for (let i = 0; i < len; i++) { + sum += bishops[i]; + } + if (sum === 0 || sum === len) { + return true; + } + } + return false; + } + isThreefoldRepetition() { + return this._getPositionCount(this.fen()) >= 3; + } + isDraw() { + return (this._halfMoves >= 100 || // 50 moves per side = 100 half moves + this.isStalemate() || + this.isInsufficientMaterial() || + this.isThreefoldRepetition()); + } + isGameOver() { + return this.isCheckmate() || this.isStalemate() || this.isDraw(); + } + moves({ verbose = false, square = undefined, piece = undefined, } = {}) { + const moves = this._moves({ square, piece }); + if (verbose) { + return moves.map((move) => this._makePretty(move)); + } + else { + return moves.map((move) => this._moveToSan(move, moves)); + } + } + _moves({ legal = true, piece = undefined, square = undefined, } = {}) { + const forSquare = square ? square.toLowerCase() : undefined; + const forPiece = piece?.toLowerCase(); + const moves = []; + const us = this._turn; + const them = swapColor(us); + let firstSquare = Ox88.a8; + let lastSquare = Ox88.h1; + let singleSquare = false; + // are we generating moves for a single square? + if (forSquare) { + // illegal square, return empty moves + if (!(forSquare in Ox88)) { + return []; + } + else { + firstSquare = lastSquare = Ox88[forSquare]; + singleSquare = true; + } + } + for (let from = firstSquare; from <= lastSquare; from++) { + // did we run off the end of the board + if (from & 0x88) { + from += 7; + continue; + } + // empty square or opponent, skip + if (!this._board[from] || this._board[from].color === them) { + continue; + } + const { type } = this._board[from]; + let to; + if (type === PAWN) { + if (forPiece && forPiece !== type) + continue; + // single square, non-capturing + to = from + PAWN_OFFSETS[us][0]; + if (!this._board[to]) { + addMove(moves, us, from, to, PAWN); + // double square + to = from + PAWN_OFFSETS[us][1]; + if (SECOND_RANK[us] === rank(from) && !this._board[to]) { + addMove(moves, us, from, to, PAWN, undefined, BITS.BIG_PAWN); + } + } + // pawn captures + for (let j = 2; j < 4; j++) { + to = from + PAWN_OFFSETS[us][j]; + if (to & 0x88) + continue; + if (this._board[to]?.color === them) { + addMove(moves, us, from, to, PAWN, this._board[to].type, BITS.CAPTURE); + } + else if (to === this._epSquare) { + addMove(moves, us, from, to, PAWN, PAWN, BITS.EP_CAPTURE); + } + } + } + else { + if (forPiece && forPiece !== type) + continue; + for (let j = 0, len = PIECE_OFFSETS[type].length; j < len; j++) { + const offset = PIECE_OFFSETS[type][j]; + to = from; + while (true) { + to += offset; + if (to & 0x88) + break; + if (!this._board[to]) { + addMove(moves, us, from, to, type); + } + else { + // own color, stop loop + if (this._board[to].color === us) + break; + addMove(moves, us, from, to, type, this._board[to].type, BITS.CAPTURE); + break; + } + /* break, if knight or king */ + if (type === KNIGHT || type === KING) + break; + } + } + } + } + /* + * check for castling if we're: + * a) generating all moves, or + * b) doing single square move generation on the king's square + */ + if (forPiece === undefined || forPiece === KING) { + if (!singleSquare || lastSquare === this._kings[us]) { + // king-side castling + if (this._castling[us] & BITS.KSIDE_CASTLE) { + const castlingFrom = this._kings[us]; + const castlingTo = castlingFrom + 2; + if (!this._board[castlingFrom + 1] && + !this._board[castlingTo] && + !this._attacked(them, this._kings[us]) && + !this._attacked(them, castlingFrom + 1) && + !this._attacked(them, castlingTo)) { + addMove(moves, us, this._kings[us], castlingTo, KING, undefined, BITS.KSIDE_CASTLE); + } + } + // queen-side castling + if (this._castling[us] & BITS.QSIDE_CASTLE) { + const castlingFrom = this._kings[us]; + const castlingTo = castlingFrom - 2; + if (!this._board[castlingFrom - 1] && + !this._board[castlingFrom - 2] && + !this._board[castlingFrom - 3] && + !this._attacked(them, this._kings[us]) && + !this._attacked(them, castlingFrom - 1) && + !this._attacked(them, castlingTo)) { + addMove(moves, us, this._kings[us], castlingTo, KING, undefined, BITS.QSIDE_CASTLE); + } + } + } + } + /* + * return all pseudo-legal moves (this includes moves that allow the king + * to be captured) + */ + if (!legal || this._kings[us] === -1) { + return moves; + } + // filter out illegal moves + const legalMoves = []; + for (let i = 0, len = moves.length; i < len; i++) { + this._makeMove(moves[i]); + if (!this._isKingAttacked(us)) { + legalMoves.push(moves[i]); + } + this._undoMove(); + } + return legalMoves; + } + move(move, { strict = false } = {}) { + /* + * The move function can be called with in the following parameters: + * + * .move('Nxb7') <- argument is a case-sensitive SAN string + * + * .move({ from: 'h7', <- argument is a move object + * to :'h8', + * promotion: 'q' }) + * + * + * An optional strict argument may be supplied to tell chess.js to + * strictly follow the SAN specification. + */ + let moveObj = null; + if (typeof move === 'string') { + moveObj = this._moveFromSan(move, strict); + } + else if (typeof move === 'object') { + const moves = this._moves(); + // convert the pretty move object to an ugly move object + for (let i = 0, len = moves.length; i < len; i++) { + if (move.from === algebraic(moves[i].from) && + move.to === algebraic(moves[i].to) && + (!('promotion' in moves[i]) || move.promotion === moves[i].promotion)) { + moveObj = moves[i]; + break; + } + } + } + // failed to find move + if (!moveObj) { + if (typeof move === 'string') { + throw new Error(`Invalid move: ${move}`); + } + else { + throw new Error(`Invalid move: ${JSON.stringify(move)}`); + } + } + /* + * need to make a copy of move because we can't generate SAN after the move + * is made + */ + const prettyMove = this._makePretty(moveObj); + this._makeMove(moveObj); + this._incPositionCount(prettyMove.after); + return prettyMove; + } + _push(move) { + this._history.push({ + move, + kings: { b: this._kings.b, w: this._kings.w }, + turn: this._turn, + castling: { b: this._castling.b, w: this._castling.w }, + epSquare: this._epSquare, + halfMoves: this._halfMoves, + moveNumber: this._moveNumber, + }); + } + _makeMove(move) { + const us = this._turn; + const them = swapColor(us); + this._push(move); + this._board[move.to] = this._board[move.from]; + delete this._board[move.from]; + // if ep capture, remove the captured pawn + if (move.flags & BITS.EP_CAPTURE) { + if (this._turn === BLACK) { + delete this._board[move.to - 16]; + } + else { + delete this._board[move.to + 16]; + } + } + // if pawn promotion, replace with new piece + if (move.promotion) { + this._board[move.to] = { type: move.promotion, color: us }; + } + // if we moved the king + if (this._board[move.to].type === KING) { + this._kings[us] = move.to; + // if we castled, move the rook next to the king + if (move.flags & BITS.KSIDE_CASTLE) { + const castlingTo = move.to - 1; + const castlingFrom = move.to + 1; + this._board[castlingTo] = this._board[castlingFrom]; + delete this._board[castlingFrom]; + } + else if (move.flags & BITS.QSIDE_CASTLE) { + const castlingTo = move.to + 1; + const castlingFrom = move.to - 2; + this._board[castlingTo] = this._board[castlingFrom]; + delete this._board[castlingFrom]; + } + // turn off castling + this._castling[us] = 0; + } + // turn off castling if we move a rook + if (this._castling[us]) { + for (let i = 0, len = ROOKS[us].length; i < len; i++) { + if (move.from === ROOKS[us][i].square && + this._castling[us] & ROOKS[us][i].flag) { + this._castling[us] ^= ROOKS[us][i].flag; + break; + } + } + } + // turn off castling if we capture a rook + if (this._castling[them]) { + for (let i = 0, len = ROOKS[them].length; i < len; i++) { + if (move.to === ROOKS[them][i].square && + this._castling[them] & ROOKS[them][i].flag) { + this._castling[them] ^= ROOKS[them][i].flag; + break; + } + } + } + // if big pawn move, update the en passant square + if (move.flags & BITS.BIG_PAWN) { + if (us === BLACK) { + this._epSquare = move.to - 16; + } + else { + this._epSquare = move.to + 16; + } + } + else { + this._epSquare = EMPTY; + } + // reset the 50 move counter if a pawn is moved or a piece is captured + if (move.piece === PAWN) { + this._halfMoves = 0; + } + else if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) { + this._halfMoves = 0; + } + else { + this._halfMoves++; + } + if (us === BLACK) { + this._moveNumber++; + } + this._turn = them; + } + undo() { + const move = this._undoMove(); + if (move) { + const prettyMove = this._makePretty(move); + this._decPositionCount(prettyMove.after); + return prettyMove; + } + return null; + } + _undoMove() { + const old = this._history.pop(); + if (old === undefined) { + return null; + } + const move = old.move; + this._kings = old.kings; + this._turn = old.turn; + this._castling = old.castling; + this._epSquare = old.epSquare; + this._halfMoves = old.halfMoves; + this._moveNumber = old.moveNumber; + const us = this._turn; + const them = swapColor(us); + this._board[move.from] = this._board[move.to]; + this._board[move.from].type = move.piece; // to undo any promotions + delete this._board[move.to]; + if (move.captured) { + if (move.flags & BITS.EP_CAPTURE) { + // en passant capture + let index; + if (us === BLACK) { + index = move.to - 16; + } + else { + index = move.to + 16; + } + this._board[index] = { type: PAWN, color: them }; + } + else { + // regular capture + this._board[move.to] = { type: move.captured, color: them }; + } + } + if (move.flags & (BITS.KSIDE_CASTLE | BITS.QSIDE_CASTLE)) { + let castlingTo, castlingFrom; + if (move.flags & BITS.KSIDE_CASTLE) { + castlingTo = move.to + 1; + castlingFrom = move.to - 1; + } + else { + castlingTo = move.to - 2; + castlingFrom = move.to + 1; + } + this._board[castlingTo] = this._board[castlingFrom]; + delete this._board[castlingFrom]; + } + return move; + } + pgn({ newline = '\n', maxWidth = 0, } = {}) { + /* + * using the specification from http://www.chessclub.com/help/PGN-spec + * example for html usage: .pgn({ max_width: 72, newline_char: "
" }) + */ + const result = []; + let headerExists = false; + /* add the PGN header information */ + for (const i in this._header) { + /* + * TODO: order of enumerated properties in header object is not + * guaranteed, see ECMA-262 spec (section 12.6.4) + */ + result.push('[' + i + ' "' + this._header[i] + '"]' + newline); + headerExists = true; + } + if (headerExists && this._history.length) { + result.push(newline); + } + const appendComment = (moveString) => { + const comment = this._comments[this.fen()]; + if (typeof comment !== 'undefined') { + const delimiter = moveString.length > 0 ? ' ' : ''; + moveString = `${moveString}${delimiter}{${comment}}`; + } + return moveString; + }; + // pop all of history onto reversed_history + const reversedHistory = []; + while (this._history.length > 0) { + reversedHistory.push(this._undoMove()); + } + const moves = []; + let moveString = ''; + // special case of a commented starting position with no moves + if (reversedHistory.length === 0) { + moves.push(appendComment('')); + } + // build the list of moves. a move_string looks like: "3. e3 e6" + while (reversedHistory.length > 0) { + moveString = appendComment(moveString); + const move = reversedHistory.pop(); + // make TypeScript stop complaining about move being undefined + if (!move) { + break; + } + // if the position started with black to move, start PGN with #. ... + if (!this._history.length && move.color === 'b') { + const prefix = `${this._moveNumber}. ...`; + // is there a comment preceding the first move? + moveString = moveString ? `${moveString} ${prefix}` : prefix; + } + else if (move.color === 'w') { + // store the previous generated move_string if we have one + if (moveString.length) { + moves.push(moveString); + } + moveString = this._moveNumber + '.'; + } + moveString = + moveString + ' ' + this._moveToSan(move, this._moves({ legal: true })); + this._makeMove(move); + } + // are there any other leftover moves? + if (moveString.length) { + moves.push(appendComment(moveString)); + } + // is there a result? + if (typeof this._header.Result !== 'undefined') { + moves.push(this._header.Result); + } + /* + * history should be back to what it was before we started generating PGN, + * so join together moves + */ + if (maxWidth === 0) { + return result.join('') + moves.join(' '); + } + // TODO (jah): huh? + const strip = function () { + if (result.length > 0 && result[result.length - 1] === ' ') { + result.pop(); + return true; + } + return false; + }; + // NB: this does not preserve comment whitespace. + const wrapComment = function (width, move) { + for (const token of move.split(' ')) { + if (!token) { + continue; + } + if (width + token.length > maxWidth) { + while (strip()) { + width--; + } + result.push(newline); + width = 0; + } + result.push(token); + width += token.length; + result.push(' '); + width++; + } + if (strip()) { + width--; + } + return width; + }; + // wrap the PGN output at max_width + let currentWidth = 0; + for (let i = 0; i < moves.length; i++) { + if (currentWidth + moves[i].length > maxWidth) { + if (moves[i].includes('{')) { + currentWidth = wrapComment(currentWidth, moves[i]); + continue; + } + } + // if the current move will push past max_width + if (currentWidth + moves[i].length > maxWidth && i !== 0) { + // don't end the line with whitespace + if (result[result.length - 1] === ' ') { + result.pop(); + } + result.push(newline); + currentWidth = 0; + } + else if (i !== 0) { + result.push(' '); + currentWidth++; + } + result.push(moves[i]); + currentWidth += moves[i].length; + } + return result.join(''); + } + header(...args) { + for (let i = 0; i < args.length; i += 2) { + if (typeof args[i] === 'string' && typeof args[i + 1] === 'string') { + this._header[args[i]] = args[i + 1]; + } + } + return this._header; + } + loadPgn(pgn, { strict = false, newlineChar = '\r?\n', } = {}) { + function mask(str) { + return str.replace(/\\/g, '\\'); + } + function parsePgnHeader(header) { + const headerObj = {}; + const headers = header.split(new RegExp(mask(newlineChar))); + let key = ''; + let value = ''; + for (let i = 0; i < headers.length; i++) { + const regex = /^\s*\[\s*([A-Za-z]+)\s*"(.*)"\s*\]\s*$/; + key = headers[i].replace(regex, '$1'); + value = headers[i].replace(regex, '$2'); + if (key.trim().length > 0) { + headerObj[key] = value; + } + } + return headerObj; + } + // strip whitespace from head/tail of PGN block + pgn = pgn.trim(); + /* + * RegExp to split header. Takes advantage of the fact that header and movetext + * will always have a blank line between them (ie, two newline_char's). Handles + * case where movetext is empty by matching newlineChar until end of string is + * matched - effectively trimming from the end extra newlineChar. + * + * With default newline_char, will equal: + * /^(\[((?:\r?\n)|.)*\])((?:\s*\r?\n){2}|(?:\s*\r?\n)*$)/ + */ + const headerRegex = new RegExp('^(\\[((?:' + + mask(newlineChar) + + ')|.)*\\])' + + '((?:\\s*' + + mask(newlineChar) + + '){2}|(?:\\s*' + + mask(newlineChar) + + ')*$)'); + // If no header given, begin with moves. + const headerRegexResults = headerRegex.exec(pgn); + const headerString = headerRegexResults + ? headerRegexResults.length >= 2 + ? headerRegexResults[1] + : '' + : ''; + // Put the board in the starting position + this.reset(); + // parse PGN header + const headers = parsePgnHeader(headerString); + let fen = ''; + for (const key in headers) { + // check to see user is including fen (possibly with wrong tag case) + if (key.toLowerCase() === 'fen') { + fen = headers[key]; + } + this.header(key, headers[key]); + } + /* + * the permissive parser should attempt to load a fen tag, even if it's the + * wrong case and doesn't include a corresponding [SetUp "1"] tag + */ + if (!strict) { + if (fen) { + this.load(fen, { preserveHeaders: true }); + } + } + else { + /* + * strict parser - load the starting position indicated by [Setup '1'] + * and [FEN position] + */ + if (headers['SetUp'] === '1') { + if (!('FEN' in headers)) { + throw new Error('Invalid PGN: FEN tag must be supplied with SetUp tag'); + } + // don't clear the headers when loading + this.load(headers['FEN'], { preserveHeaders: true }); + } + } + /* + * NB: the regexes below that delete move numbers, recursive annotations, + * and numeric annotation glyphs may also match text in comments. To + * prevent this, we transform comments by hex-encoding them in place and + * decoding them again after the other tokens have been deleted. + * + * While the spec states that PGN files should be ASCII encoded, we use + * {en,de}codeURIComponent here to support arbitrary UTF8 as a convenience + * for modern users + */ + function toHex(s) { + return Array.from(s) + .map(function (c) { + /* + * encodeURI doesn't transform most ASCII characters, so we handle + * these ourselves + */ + return c.charCodeAt(0) < 128 + ? c.charCodeAt(0).toString(16) + : encodeURIComponent(c).replace(/%/g, '').toLowerCase(); + }) + .join(''); + } + function fromHex(s) { + return s.length == 0 + ? '' + : decodeURIComponent('%' + (s.match(/.{1,2}/g) || []).join('%')); + } + const encodeComment = function (s) { + s = s.replace(new RegExp(mask(newlineChar), 'g'), ' '); + return `{${toHex(s.slice(1, s.length - 1))}}`; + }; + const decodeComment = function (s) { + if (s.startsWith('{') && s.endsWith('}')) { + return fromHex(s.slice(1, s.length - 1)); + } + }; + // delete header to get the moves + let ms = pgn + .replace(headerString, '') + .replace( + // encode comments so they don't get deleted below + new RegExp(`({[^}]*})+?|;([^${mask(newlineChar)}]*)`, 'g'), function (_match, bracket, semicolon) { + return bracket !== undefined + ? encodeComment(bracket) + : ' ' + encodeComment(`{${semicolon.slice(1)}}`); + }) + .replace(new RegExp(mask(newlineChar), 'g'), ' '); + // delete recursive annotation variations + const ravRegex = /(\([^()]+\))+?/g; + while (ravRegex.test(ms)) { + ms = ms.replace(ravRegex, ''); + } + // delete move numbers + ms = ms.replace(/\d+\.(\.\.)?/g, ''); + // delete ... indicating black to move + ms = ms.replace(/\.\.\./g, ''); + /* delete numeric annotation glyphs */ + ms = ms.replace(/\$\d+/g, ''); + // trim and get array of moves + let moves = ms.trim().split(new RegExp(/\s+/)); + // delete empty entries + moves = moves.filter((move) => move !== ''); + let result = ''; + for (let halfMove = 0; halfMove < moves.length; halfMove++) { + const comment = decodeComment(moves[halfMove]); + if (comment !== undefined) { + this._comments[this.fen()] = comment; + continue; + } + const move = this._moveFromSan(moves[halfMove], strict); + // invalid move + if (move == null) { + // was the move an end of game marker + if (TERMINATION_MARKERS.indexOf(moves[halfMove]) > -1) { + result = moves[halfMove]; + } + else { + throw new Error(`Invalid move in PGN: ${moves[halfMove]}`); + } + } + else { + // reset the end of game marker if making a valid move + result = ''; + this._makeMove(move); + this._incPositionCount(this.fen()); + } + } + /* + * Per section 8.2.6 of the PGN spec, the Result tag pair must match match + * the termination marker. Only do this when headers are present, but the + * result tag is missing + */ + if (result && Object.keys(this._header).length && !this._header['Result']) { + this.header('Result', result); + } + } + /* + * Convert a move from 0x88 coordinates to Standard Algebraic Notation + * (SAN) + * + * @param {boolean} strict Use the strict SAN parser. It will throw errors + * on overly disambiguated moves (see below): + * + * r1bqkbnr/ppp2ppp/2n5/1B1pP3/4P3/8/PPPP2PP/RNBQK1NR b KQkq - 2 4 + * 4. ... Nge7 is overly disambiguated because the knight on c6 is pinned + * 4. ... Ne7 is technically the valid SAN + */ + _moveToSan(move, moves) { + let output = ''; + if (move.flags & BITS.KSIDE_CASTLE) { + output = 'O-O'; + } + else if (move.flags & BITS.QSIDE_CASTLE) { + output = 'O-O-O'; + } + else { + if (move.piece !== PAWN) { + const disambiguator = getDisambiguator(move, moves); + output += move.piece.toUpperCase() + disambiguator; + } + if (move.flags & (BITS.CAPTURE | BITS.EP_CAPTURE)) { + if (move.piece === PAWN) { + output += algebraic(move.from)[0]; + } + output += 'x'; + } + output += algebraic(move.to); + if (move.promotion) { + output += '=' + move.promotion.toUpperCase(); + } + } + this._makeMove(move); + if (this.isCheck()) { + if (this.isCheckmate()) { + output += '#'; + } + else { + output += '+'; + } + } + this._undoMove(); + return output; + } + // convert a move from Standard Algebraic Notation (SAN) to 0x88 coordinates + _moveFromSan(move, strict = false) { + // strip off any move decorations: e.g Nf3+?! becomes Nf3 + const cleanMove = strippedSan(move); + let pieceType = inferPieceType(cleanMove); + let moves = this._moves({ legal: true, piece: pieceType }); + // strict parser + for (let i = 0, len = moves.length; i < len; i++) { + if (cleanMove === strippedSan(this._moveToSan(moves[i], moves))) { + return moves[i]; + } + } + // the strict parser failed + if (strict) { + return null; + } + let piece = undefined; + let matches = undefined; + let from = undefined; + let to = undefined; + let promotion = undefined; + /* + * The default permissive (non-strict) parser allows the user to parse + * non-standard chess notations. This parser is only run after the strict + * Standard Algebraic Notation (SAN) parser has failed. + * + * When running the permissive parser, we'll run a regex to grab the piece, the + * to/from square, and an optional promotion piece. This regex will + * parse common non-standard notation like: Pe2-e4, Rc1c4, Qf3xf7, + * f7f8q, b1c3 + * + * NOTE: Some positions and moves may be ambiguous when using the permissive + * parser. For example, in this position: 6k1/8/8/B7/8/8/8/BN4K1 w - - 0 1, + * the move b1c3 may be interpreted as Nc3 or B1c3 (a disambiguated bishop + * move). In these cases, the permissive parser will default to the most + * basic interpretation (which is b1c3 parsing to Nc3). + */ + let overlyDisambiguated = false; + matches = cleanMove.match(/([pnbrqkPNBRQK])?([a-h][1-8])x?-?([a-h][1-8])([qrbnQRBN])?/); + if (matches) { + piece = matches[1]; + from = matches[2]; + to = matches[3]; + promotion = matches[4]; + if (from.length == 1) { + overlyDisambiguated = true; + } + } + else { + /* + * The [a-h]?[1-8]? portion of the regex below handles moves that may be + * overly disambiguated (e.g. Nge7 is unnecessary and non-standard when + * there is one legal knight move to e7). In this case, the value of + * 'from' variable will be a rank or file, not a square. + */ + matches = cleanMove.match(/([pnbrqkPNBRQK])?([a-h]?[1-8]?)x?-?([a-h][1-8])([qrbnQRBN])?/); + if (matches) { + piece = matches[1]; + from = matches[2]; + to = matches[3]; + promotion = matches[4]; + if (from.length == 1) { + overlyDisambiguated = true; + } + } + } + pieceType = inferPieceType(cleanMove); + moves = this._moves({ + legal: true, + piece: piece ? piece : pieceType, + }); + if (!to) { + return null; + } + for (let i = 0, len = moves.length; i < len; i++) { + if (!from) { + // if there is no from square, it could be just 'x' missing from a capture + if (cleanMove === + strippedSan(this._moveToSan(moves[i], moves)).replace('x', '')) { + return moves[i]; + } + // hand-compare move properties with the results from our permissive regex + } + else if ((!piece || piece.toLowerCase() == moves[i].piece) && + Ox88[from] == moves[i].from && + Ox88[to] == moves[i].to && + (!promotion || promotion.toLowerCase() == moves[i].promotion)) { + return moves[i]; + } + else if (overlyDisambiguated) { + /* + * SPECIAL CASE: we parsed a move string that may have an unneeded + * rank/file disambiguator (e.g. Nge7). The 'from' variable will + */ + const square = algebraic(moves[i].from); + if ((!piece || piece.toLowerCase() == moves[i].piece) && + Ox88[to] == moves[i].to && + (from == square[0] || from == square[1]) && + (!promotion || promotion.toLowerCase() == moves[i].promotion)) { + return moves[i]; + } + } + } + return null; + } + ascii() { + let s = ' +------------------------+\n'; + for (let i = Ox88.a8; i <= Ox88.h1; i++) { + // display the rank + if (file$4(i) === 0) { + s += ' ' + '87654321'[rank(i)] + ' |'; + } + if (this._board[i]) { + const piece = this._board[i].type; + const color = this._board[i].color; + const symbol = color === WHITE ? piece.toUpperCase() : piece.toLowerCase(); + s += ' ' + symbol + ' '; + } + else { + s += ' . '; + } + if ((i + 1) & 0x88) { + s += '|\n'; + i += 8; + } + } + s += ' +------------------------+\n'; + s += ' a b c d e f g h'; + return s; + } + perft(depth) { + const moves = this._moves({ legal: false }); + let nodes = 0; + const color = this._turn; + for (let i = 0, len = moves.length; i < len; i++) { + this._makeMove(moves[i]); + if (!this._isKingAttacked(color)) { + if (depth - 1 > 0) { + nodes += this.perft(depth - 1); + } + else { + nodes++; + } + } + this._undoMove(); + } + return nodes; + } + // pretty = external move object + _makePretty(uglyMove) { + const { color, piece, from, to, flags, captured, promotion } = uglyMove; + let prettyFlags = ''; + for (const flag in BITS) { + if (BITS[flag] & flags) { + prettyFlags += FLAGS[flag]; + } + } + const fromAlgebraic = algebraic(from); + const toAlgebraic = algebraic(to); + const move = { + color, + piece, + from: fromAlgebraic, + to: toAlgebraic, + san: this._moveToSan(uglyMove, this._moves({ legal: true })), + flags: prettyFlags, + lan: fromAlgebraic + toAlgebraic, + before: this.fen(), + after: '', + }; + // generate the FEN for the 'after' key + this._makeMove(uglyMove); + move.after = this.fen(); + this._undoMove(); + if (captured) { + move.captured = captured; + } + if (promotion) { + move.promotion = promotion; + move.lan += promotion; + } + return move; + } + turn() { + return this._turn; + } + board() { + const output = []; + let row = []; + for (let i = Ox88.a8; i <= Ox88.h1; i++) { + if (this._board[i] == null) { + row.push(null); + } + else { + row.push({ + square: algebraic(i), + type: this._board[i].type, + color: this._board[i].color, + }); + } + if ((i + 1) & 0x88) { + output.push(row); + row = []; + i += 8; + } + } + return output; + } + squareColor(square) { + if (square in Ox88) { + const sq = Ox88[square]; + return (rank(sq) + file$4(sq)) % 2 === 0 ? 'light' : 'dark'; + } + return null; + } + history({ verbose = false } = {}) { + const reversedHistory = []; + const moveHistory = []; + while (this._history.length > 0) { + reversedHistory.push(this._undoMove()); + } + while (true) { + const move = reversedHistory.pop(); + if (!move) { + break; + } + if (verbose) { + moveHistory.push(this._makePretty(move)); + } + else { + moveHistory.push(this._moveToSan(move, this._moves())); + } + this._makeMove(move); + } + return moveHistory; + } + /* + * Keeps track of position occurrence counts for the purpose of repetition + * checking. All three methods (`_inc`, `_dec`, and `_get`) trim the + * irrelevent information from the fen, initialising new positions, and + * removing old positions from the record if their counts are reduced to 0. + */ + _getPositionCount(fen) { + const trimmedFen = trimFen(fen); + return this._positionCount[trimmedFen] || 0; + } + _incPositionCount(fen) { + const trimmedFen = trimFen(fen); + if (this._positionCount[trimmedFen] === undefined) { + this._positionCount[trimmedFen] = 0; + } + this._positionCount[trimmedFen] += 1; + } + _decPositionCount(fen) { + const trimmedFen = trimFen(fen); + if (this._positionCount[trimmedFen] === 1) { + delete this._positionCount[trimmedFen]; + } + else { + this._positionCount[trimmedFen] -= 1; + } + } + _pruneComments() { + const reversedHistory = []; + const currentComments = {}; + const copyComment = (fen) => { + if (fen in this._comments) { + currentComments[fen] = this._comments[fen]; + } + }; + while (this._history.length > 0) { + reversedHistory.push(this._undoMove()); + } + copyComment(this.fen()); + while (true) { + const move = reversedHistory.pop(); + if (!move) { + break; + } + this._makeMove(move); + copyComment(this.fen()); + } + this._comments = currentComments; + } + getComment() { + return this._comments[this.fen()]; + } + setComment(comment) { + this._comments[this.fen()] = comment.replace('{', '[').replace('}', ']'); + } + deleteComment() { + const comment = this._comments[this.fen()]; + delete this._comments[this.fen()]; + return comment; + } + getComments() { + this._pruneComments(); + return Object.keys(this._comments).map((fen) => { + return { fen: fen, comment: this._comments[fen] }; + }); + } + deleteComments() { + this._pruneComments(); + return Object.keys(this._comments).map((fen) => { + const comment = this._comments[fen]; + delete this._comments[fen]; + return { fen: fen, comment: comment }; + }); + } + setCastlingRights(color, rights) { + for (const side of [KING, QUEEN]) { + if (rights[side] !== undefined) { + if (rights[side]) { + this._castling[color] |= SIDES[side]; + } + else { + this._castling[color] &= ~SIDES[side]; + } + } + } + this._updateCastlingRights(); + const result = this.getCastlingRights(color); + return ((rights[KING] === undefined || rights[KING] === result[KING]) && + (rights[QUEEN] === undefined || rights[QUEEN] === result[QUEEN])); + } + getCastlingRights(color) { + return { + [KING]: (this._castling[color] & SIDES[KING]) !== 0, + [QUEEN]: (this._castling[color] & SIDES[QUEEN]) !== 0, + }; + } + moveNumber() { + return this._moveNumber; + } + } - const file$b = "src\\MovingDotSpacePortfromReact.svelte"; + /* src\ChessStudyTool.svelte generated by Svelte v3.59.2 */ + const file$3 = "src\\ChessStudyTool.svelte"; - function get_each_context$8(ctx, list, i) { + function get_each_context$2(ctx, list, i) { const child_ctx = ctx.slice(); - child_ctx[29] = list[i]; + child_ctx[31] = list[i]; return child_ctx; } - function get_each_context_1$3(ctx, list, i) { + function get_each_context_1$2(ctx, list, i) { const child_ctx = ctx.slice(); - child_ctx[32] = list[i]; + child_ctx[34] = list[i]; + child_ctx[36] = i; return child_ctx; } - // (286:4) {#each themeKeys as key} - function create_each_block_1$3(ctx) { - let option; - let t_value = /*key*/ ctx[32] + ""; - let t; - - const block = { - c: function create() { - option = element("option"); - t = text(t_value); - option.__value = /*key*/ ctx[32]; - option.value = option.__value; - add_location(option, file$b, 286, 8, 11619); - }, - m: function mount(target, anchor) { - insert_dev(target, option, anchor); - append_dev(option, t); - }, - p: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(option); - } - }; - - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block_1$3.name, - type: "each", - source: "(286:4) {#each themeKeys as key}", - ctx - }); - - return block; + function get_each_context_2$2(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[37] = list[i]; + child_ctx[39] = i; + return child_ctx; } - // (298:4) {#each $targets as target (target.name)} - function create_each_block$8(key_1, ctx) { - let first; - let target; - let t0; - let span; - let t1_value = /*target*/ ctx[29].name + ""; - let t1; - let current; - - target = new MovingDotTargetPortfromReact({ - props: { position: /*target*/ ctx[29] }, - $$inline: true - }); - - const block = { - key: key_1, - first: null, - c: function create() { - first = empty(); - create_component(target.$$.fragment); - t0 = space(); - span = element("span"); - t1 = text(t1_value); - set_style(span, "position", "absolute"); - set_style(span, "left", /*target*/ ctx[29].x + "px"); - set_style(span, "top", /*target*/ ctx[29].y + "px"); - add_location(span, file$b, 299, 8, 12755); - this.first = first; - }, - m: function mount(target$1, anchor) { - insert_dev(target$1, first, anchor); - mount_component(target, target$1, anchor); - insert_dev(target$1, t0, anchor); - insert_dev(target$1, span, anchor); - append_dev(span, t1); - current = true; - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; - const target_changes = {}; - if (dirty[0] & /*$targets*/ 4096) target_changes.position = /*target*/ ctx[29]; - target.$set(target_changes); - if ((!current || dirty[0] & /*$targets*/ 4096) && t1_value !== (t1_value = /*target*/ ctx[29].name + "")) set_data_dev(t1, t1_value); - - if (!current || dirty[0] & /*$targets*/ 4096) { - set_style(span, "left", /*target*/ ctx[29].x + "px"); - } - - if (!current || dirty[0] & /*$targets*/ 4096) { - set_style(span, "top", /*target*/ ctx[29].y + "px"); - } - }, - i: function intro(local) { - if (current) return; - transition_in(target.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(target.$$.fragment, local); - current = false; - }, - d: function destroy(detaching) { - if (detaching) detach_dev(first); - destroy_component(target, detaching); - if (detaching) detach_dev(t0); - if (detaching) detach_dev(span); - } - }; - - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block$8.name, - type: "each", - source: "(298:4) {#each $targets as target (target.name)}", - ctx - }); - - return block; + function get_each_context_3(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[40] = list[i]; + child_ctx[42] = i; + return child_ctx; } - // (304:4) {#if isModalOpen} - function create_if_block_1$1(ctx) { - let modal; - let current; - - modal = new MovingDotSpaceSimpleModal({ - props: { - isOpen: /*isModalOpen*/ ctx[3], - onClose: /*handleModalClose*/ ctx[19], - title: /*currentcollisiontitletext*/ ctx[5], - content: /*currentcollisiontext*/ ctx[6], - items: /*currentcollisionitems*/ ctx[7], - currentTheme: /*currentTheme*/ ctx[10], - themeActions: themes[/*currentTheme*/ ctx[10]].actions - }, - $$inline: true - }); + // (174:22) {#if piece} + function create_if_block_3$1(ctx) { + let img; + let img_src_value; + let img_alt_value; const block = { c: function create() { - create_component(modal.$$.fragment); + img = element$1("img"); + if (!src_url_equal(img.src, img_src_value = getPieceImage(/*piece*/ ctx[40]))) attr_dev(img, "src", img_src_value); + attr_dev(img, "alt", img_alt_value = /*piece*/ ctx[40].type); + attr_dev(img, "class", "svelte-7r6gh4"); + add_location(img, file$3, 174, 26, 6485); }, m: function mount(target, anchor) { - mount_component(modal, target, anchor); - current = true; + insert_dev(target, img, anchor); }, p: function update(ctx, dirty) { - const modal_changes = {}; - if (dirty[0] & /*isModalOpen*/ 8) modal_changes.isOpen = /*isModalOpen*/ ctx[3]; - if (dirty[0] & /*currentcollisiontitletext*/ 32) modal_changes.title = /*currentcollisiontitletext*/ ctx[5]; - if (dirty[0] & /*currentcollisiontext*/ 64) modal_changes.content = /*currentcollisiontext*/ ctx[6]; - if (dirty[0] & /*currentcollisionitems*/ 128) modal_changes.items = /*currentcollisionitems*/ ctx[7]; - if (dirty[0] & /*currentTheme*/ 1024) modal_changes.currentTheme = /*currentTheme*/ ctx[10]; - if (dirty[0] & /*currentTheme*/ 1024) modal_changes.themeActions = themes[/*currentTheme*/ ctx[10]].actions; - modal.$set(modal_changes); - }, - i: function intro(local) { - if (current) return; - transition_in(modal.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(modal.$$.fragment, local); - current = false; + if (dirty[0] & /*board*/ 1 && !src_url_equal(img.src, img_src_value = getPieceImage(/*piece*/ ctx[40]))) { + attr_dev(img, "src", img_src_value); + } + + if (dirty[0] & /*board*/ 1 && img_alt_value !== (img_alt_value = /*piece*/ ctx[40].type)) { + attr_dev(img, "alt", img_alt_value); + } }, d: function destroy(detaching) { - destroy_component(modal, detaching); + if (detaching) detach_dev(img); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block_1$1.name, + id: create_if_block_3$1.name, type: "if", - source: "(304:4) {#if isModalOpen}", + source: "(174:22) {#if piece}", ctx }); return block; } - // (308:4) {#if isSMModalOpen} - function create_if_block$4(ctx) { - let smmodal; - let current; - - smmodal = new SimpleStateMachineModal({ - props: { - isOpen: /*isSMModalOpen*/ ctx[4], - onClose: /*handleModalClose*/ ctx[19], - modalStates: /*currentstatemodalstates*/ ctx[9] - }, - $$inline: true - }); + // (177:22) {#if squareText[rowIndex * 8 + colIndex]} + function create_if_block_2$1(ctx) { + let span; + let t_value = /*squareText*/ ctx[5][/*rowIndex*/ ctx[39] * 8 + /*colIndex*/ ctx[42]] + ""; + let t; const block = { c: function create() { - create_component(smmodal.$$.fragment); + span = element$1("span"); + t = text(t_value); + attr_dev(span, "class", "square-text svelte-7r6gh4"); + add_location(span, file$3, 177, 26, 6660); }, m: function mount(target, anchor) { - mount_component(smmodal, target, anchor); - current = true; + insert_dev(target, span, anchor); + append_dev(span, t); }, p: function update(ctx, dirty) { - const smmodal_changes = {}; - if (dirty[0] & /*isSMModalOpen*/ 16) smmodal_changes.isOpen = /*isSMModalOpen*/ ctx[4]; - if (dirty[0] & /*currentstatemodalstates*/ 512) smmodal_changes.modalStates = /*currentstatemodalstates*/ ctx[9]; - smmodal.$set(smmodal_changes); - }, - i: function intro(local) { - if (current) return; - transition_in(smmodal.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(smmodal.$$.fragment, local); - current = false; + if (dirty[0] & /*squareText*/ 32 && t_value !== (t_value = /*squareText*/ ctx[5][/*rowIndex*/ ctx[39] * 8 + /*colIndex*/ ctx[42]] + "")) set_data_dev(t, t_value); }, d: function destroy(detaching) { - destroy_component(smmodal, detaching); + if (detaching) detach_dev(span); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block$4.name, + id: create_if_block_2$1.name, type: "if", - source: "(308:4) {#if isSMModalOpen}", - ctx - }); - - return block; - } - - // (318:0) - function create_default_slot$1(ctx) { - let h10; - let t1; - let fighttest; - let t2; - let modaltest; - let t3; - let h11; - let t5; - let findtest; - let t6; - let h12; - let t8; - let ordertest; - let current; - fighttest = new MovingDotSpaceGameFight({ $$inline: true }); - modaltest = new MovingDotSpaceModalBrainstorm({ $$inline: true }); - findtest = new MovingDotSpaceGameFind({ $$inline: true }); - ordertest = new MovingDotSpaceGameOrder({ $$inline: true }); - - const block = { - c: function create() { - h10 = element("h1"); - h10.textContent = "Expand this to allow up to 100 fighters on each side"; - t1 = space(); - create_component(fighttest.$$.fragment); - t2 = space(); - create_component(modaltest.$$.fragment); - t3 = space(); - h11 = element("h1"); - h11.textContent = "Find games are choices between similar looking items missing information with limited information (Luck = More Targets)"; - t5 = space(); - create_component(findtest.$$.fragment); - t6 = space(); - h12 = element("h1"); - h12.textContent = "Find out/ make sense / Resolve Conflict = order mixed up and"; - t8 = space(); - create_component(ordertest.$$.fragment); - add_location(h10, file$b, 318, 4, 13722); - add_location(h11, file$b, 321, 4, 13827); - add_location(h12, file$b, 323, 4, 13980); - }, - m: function mount(target, anchor) { - insert_dev(target, h10, anchor); - insert_dev(target, t1, anchor); - mount_component(fighttest, target, anchor); - insert_dev(target, t2, anchor); - mount_component(modaltest, target, anchor); - insert_dev(target, t3, anchor); - insert_dev(target, h11, anchor); - insert_dev(target, t5, anchor); - mount_component(findtest, target, anchor); - insert_dev(target, t6, anchor); - insert_dev(target, h12, anchor); - insert_dev(target, t8, anchor); - mount_component(ordertest, target, anchor); - current = true; - }, - p: noop, - i: function intro(local) { - if (current) return; - transition_in(fighttest.$$.fragment, local); - transition_in(modaltest.$$.fragment, local); - transition_in(findtest.$$.fragment, local); - transition_in(ordertest.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(fighttest.$$.fragment, local); - transition_out(modaltest.$$.fragment, local); - transition_out(findtest.$$.fragment, local); - transition_out(ordertest.$$.fragment, local); - current = false; - }, - d: function destroy(detaching) { - if (detaching) detach_dev(h10); - if (detaching) detach_dev(t1); - destroy_component(fighttest, detaching); - if (detaching) detach_dev(t2); - destroy_component(modaltest, detaching); - if (detaching) detach_dev(t3); - if (detaching) detach_dev(h11); - if (detaching) detach_dev(t5); - destroy_component(findtest, detaching); - if (detaching) detach_dev(t6); - if (detaching) detach_dev(h12); - if (detaching) detach_dev(t8); - destroy_component(ordertest, detaching); - } - }; - - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_default_slot$1.name, - type: "slot", - source: "(318:0) ", + source: "(177:22) {#if squareText[rowIndex * 8 + colIndex]}", ctx }); return block; } - function create_fragment$b(ctx) { - let t0; - let select; - let t1; - let button; - let t3; - let dotgamethememanager; - let t4; - let div1; - let canvas_1; - let t5; - let movingdot; - let t6; - let div0; - let t7; - let t8_value = /*$dotPosition*/ ctx[0].x + ""; - let t8; - let t9; - let t10_value = /*$dotPosition*/ ctx[0].y + ""; - let t10; - let t11; - let t12; - let each_blocks = []; - let each1_lookup = new Map(); - let t13; - let t14; - let t15; - let movingdotstats; - let t16; - let h1; - let t18; - let hr; - let t19; - let simplecollapsible; - let current; + // (169:14) {#each row as piece, colIndex} + function create_each_block_3(ctx) { + let div; + let t; let mounted; let dispose; - let each_value_1 = /*themeKeys*/ ctx[15]; - validate_each_argument(each_value_1); - let each_blocks_1 = []; - - for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks_1[i] = create_each_block_1$3(get_each_context_1$3(ctx, each_value_1, i)); - } - - dotgamethememanager = new MovingDotSpaceThemeManager({ - props: { - ChangedContentPlaceholder: /*ChangedContentPlaceholdertoSend*/ ctx[1] - }, - $$inline: true - }); - - let movingdot_props = { - position: /*$dotPosition*/ ctx[0], - boundaries: /*boundaries*/ ctx[14] - }; - - movingdot = new MovingDotPortfromReact({ props: movingdot_props, $$inline: true }); - /*movingdot_binding*/ ctx[23](movingdot); - movingdot.$on("move", /*move_handler*/ ctx[24]); - let each_value = /*$targets*/ ctx[12]; - validate_each_argument(each_value); - const get_key = ctx => /*target*/ ctx[29].name; - validate_each_keys(ctx, each_value, get_each_context$8, get_key); + let if_block0 = /*piece*/ ctx[40] && create_if_block_3$1(ctx); + let if_block1 = /*squareText*/ ctx[5][/*rowIndex*/ ctx[39] * 8 + /*colIndex*/ ctx[42]] && create_if_block_2$1(ctx); - for (let i = 0; i < each_value.length; i += 1) { - let child_ctx = get_each_context$8(ctx, each_value, i); - let key = get_key(child_ctx); - each1_lookup.set(key, each_blocks[i] = create_each_block$8(key, child_ctx)); + function click_handler() { + return /*click_handler*/ ctx[20](/*rowIndex*/ ctx[39], /*colIndex*/ ctx[42]); } - let if_block0 = /*isModalOpen*/ ctx[3] && create_if_block_1$1(ctx); - let if_block1 = /*isSMModalOpen*/ ctx[4] && create_if_block$4(ctx); - movingdotstats = new MovingDotStatDisplay({ $$inline: true }); - - simplecollapsible = new SimpleCollapsible({ - props: { - title: "Some practice modal ideas - how to solve the import issue (have to import all modals all the time?)", - $$slots: { default: [create_default_slot$1] }, - $$scope: { ctx } - }, - $$inline: true - }); - const block = { c: function create() { - t0 = text("Game Selector\r\n"); - select = element("select"); - - for (let i = 0; i < each_blocks_1.length; i += 1) { - each_blocks_1[i].c(); - } - - t1 = text("\r\n | \r\n"); - button = element("button"); - button.textContent = "Test load for the auto gen config"; - t3 = space(); - create_component(dotgamethememanager.$$.fragment); - t4 = space(); - div1 = element("div"); - canvas_1 = element("canvas"); - t5 = space(); - create_component(movingdot.$$.fragment); - t6 = space(); - div0 = element("div"); - t7 = text("Minor Game Events Log for player ||| Position for Developer "); - t8 = text(t8_value); - t9 = space(); - t10 = text(t10_value); - t11 = text(" - TODO - Story Line / Avatars? / Clock System ||| For Job Experience focused Stats can be Emotions Stress Frustration Relief Tiredness Confidence (Percieved Skill) Experience (Actual Skill)"); - t12 = space(); - - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } - - t13 = space(); + div = element$1("div"); if (if_block0) if_block0.c(); - t14 = space(); + t = space(); if (if_block1) if_block1.c(); - t15 = space(); - create_component(movingdotstats.$$.fragment); - t16 = space(); - h1 = element("h1"); - h1.textContent = "Simple Game is normally just story with fighting and traversing mechanics repeated in between videos with as heavy customisation of any part of the game as possible"; - t18 = space(); - hr = element("hr"); - t19 = space(); - create_component(simplecollapsible.$$.fragment); - if (/*currentTheme*/ ctx[10] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[21].call(select)); - add_location(select, file$b, 284, 0, 11521); - add_location(button, file$b, 290, 0, 11684); - set_style(canvas_1, "width", "100%"); - set_style(canvas_1, "height", "100%"); - attr_dev(canvas_1, "tabindex", "0"); - add_location(canvas_1, file$b, 294, 4, 12091); - attr_dev(div0, "id", "overlayText"); - attr_dev(div0, "class", "svelte-c2nwl9"); - add_location(div0, file$b, 296, 4, 12349); - attr_dev(div1, "id", "game-container"); - set_style(div1, "position", "relative"); - set_style(div1, "width", "100%"); - set_style(div1, "height", "100vh"); - set_style(div1, "border", "1px solid black"); - set_style(div1, "overflow", "hidden"); - set_style(div1, "background-image", "url('" + /*CurrentGameBackground*/ ctx[11] + "')"); - set_style(div1, "background-size", "cover"); - set_style(div1, "background-position", "center"); - add_location(div1, file$b, 293, 0, 11858); - add_location(h1, file$b, 314, 0, 13406); - add_location(hr, file$b, 315, 0, 13581); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, t0, anchor); - insert_dev(target, select, anchor); - - for (let i = 0; i < each_blocks_1.length; i += 1) { - if (each_blocks_1[i]) { - each_blocks_1[i].m(select, null); - } - } - - select_option(select, /*currentTheme*/ ctx[10], true); - insert_dev(target, t1, anchor); - insert_dev(target, button, anchor); - insert_dev(target, t3, anchor); - mount_component(dotgamethememanager, target, anchor); - insert_dev(target, t4, anchor); - insert_dev(target, div1, anchor); - append_dev(div1, canvas_1); - /*canvas_1_binding*/ ctx[22](canvas_1); - append_dev(div1, t5); - mount_component(movingdot, div1, null); - append_dev(div1, t6); - append_dev(div1, div0); - append_dev(div0, t7); - append_dev(div0, t8); - append_dev(div0, t9); - append_dev(div0, t10); - append_dev(div0, t11); - append_dev(div1, t12); - - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(div1, null); - } - } - - append_dev(div1, t13); - if (if_block0) if_block0.m(div1, null); - append_dev(div1, t14); - if (if_block1) if_block1.m(div1, null); - insert_dev(target, t15, anchor); - mount_component(movingdotstats, target, anchor); - insert_dev(target, t16, anchor); - insert_dev(target, h1, anchor); - insert_dev(target, t18, anchor); - insert_dev(target, hr, anchor); - insert_dev(target, t19, anchor); - mount_component(simplecollapsible, target, anchor); - current = true; - - if (!mounted) { - dispose = [ - listen_dev(select, "change", /*select_change_handler*/ ctx[21]), - listen_dev(select, "change", /*changeTheme*/ ctx[16], false, false, false, false), - listen_dev(button, "click", /*loadexperimentaltheme*/ ctx[17], false, false, false, false), - listen_dev(canvas_1, "click", /*handleSpaceClick*/ ctx[18], false, false, false, false) - ]; - - mounted = true; - } + attr_dev(div, "class", "square " + getSquareColor(/*rowIndex*/ ctx[39] * 8 + /*colIndex*/ ctx[42]) + " svelte-7r6gh4"); + add_location(div, file$3, 169, 18, 6234); }, - p: function update(ctx, dirty) { - if (dirty[0] & /*themeKeys*/ 32768) { - each_value_1 = /*themeKeys*/ ctx[15]; - validate_each_argument(each_value_1); - let i; - - for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$3(ctx, each_value_1, i); - - if (each_blocks_1[i]) { - each_blocks_1[i].p(child_ctx, dirty); - } else { - each_blocks_1[i] = create_each_block_1$3(child_ctx); - each_blocks_1[i].c(); - each_blocks_1[i].m(select, null); - } - } - - for (; i < each_blocks_1.length; i += 1) { - each_blocks_1[i].d(1); - } - - each_blocks_1.length = each_value_1.length; - } - - if (dirty[0] & /*currentTheme, themeKeys*/ 33792) { - select_option(select, /*currentTheme*/ ctx[10]); - } - - const dotgamethememanager_changes = {}; - if (dirty[0] & /*ChangedContentPlaceholdertoSend*/ 2) dotgamethememanager_changes.ChangedContentPlaceholder = /*ChangedContentPlaceholdertoSend*/ ctx[1]; - dotgamethememanager.$set(dotgamethememanager_changes); - const movingdot_changes = {}; - if (dirty[0] & /*$dotPosition*/ 1) movingdot_changes.position = /*$dotPosition*/ ctx[0]; - movingdot.$set(movingdot_changes); - if ((!current || dirty[0] & /*$dotPosition*/ 1) && t8_value !== (t8_value = /*$dotPosition*/ ctx[0].x + "")) set_data_dev(t8, t8_value); - if ((!current || dirty[0] & /*$dotPosition*/ 1) && t10_value !== (t10_value = /*$dotPosition*/ ctx[0].y + "")) set_data_dev(t10, t10_value); + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + if (if_block0) if_block0.m(div, null); + append_dev(div, t); + if (if_block1) if_block1.m(div, null); - if (dirty[0] & /*$targets*/ 4096) { - each_value = /*$targets*/ ctx[12]; - validate_each_argument(each_value); - group_outros(); - validate_each_keys(ctx, each_value, get_each_context$8, get_key); - each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each1_lookup, div1, outro_and_destroy_block, create_each_block$8, t13, get_each_context$8); - check_outros(); + if (!mounted) { + dispose = listen_dev(div, "click", click_handler, false, false, false, false); + mounted = true; } + }, + p: function update(new_ctx, dirty) { + ctx = new_ctx; - if (/*isModalOpen*/ ctx[3]) { + if (/*piece*/ ctx[40]) { if (if_block0) { if_block0.p(ctx, dirty); - - if (dirty[0] & /*isModalOpen*/ 8) { - transition_in(if_block0, 1); - } } else { - if_block0 = create_if_block_1$1(ctx); + if_block0 = create_if_block_3$1(ctx); if_block0.c(); - transition_in(if_block0, 1); - if_block0.m(div1, t14); + if_block0.m(div, t); } } else if (if_block0) { - group_outros(); - - transition_out(if_block0, 1, 1, () => { - if_block0 = null; - }); - - check_outros(); + if_block0.d(1); + if_block0 = null; } - if (/*isSMModalOpen*/ ctx[4]) { + if (/*squareText*/ ctx[5][/*rowIndex*/ ctx[39] * 8 + /*colIndex*/ ctx[42]]) { if (if_block1) { if_block1.p(ctx, dirty); - - if (dirty[0] & /*isSMModalOpen*/ 16) { - transition_in(if_block1, 1); - } } else { - if_block1 = create_if_block$4(ctx); + if_block1 = create_if_block_2$1(ctx); if_block1.c(); - transition_in(if_block1, 1); - if_block1.m(div1, null); + if_block1.m(div, null); } } else if (if_block1) { - group_outros(); - - transition_out(if_block1, 1, 1, () => { - if_block1 = null; - }); - - check_outros(); - } - - if (!current || dirty[0] & /*CurrentGameBackground*/ 2048) { - set_style(div1, "background-image", "url('" + /*CurrentGameBackground*/ ctx[11] + "')"); - } - - const simplecollapsible_changes = {}; - - if (dirty[1] & /*$$scope*/ 16) { - simplecollapsible_changes.$$scope = { dirty, ctx }; - } - - simplecollapsible.$set(simplecollapsible_changes); - }, - i: function intro(local) { - if (current) return; - transition_in(dotgamethememanager.$$.fragment, local); - transition_in(movingdot.$$.fragment, local); - - for (let i = 0; i < each_value.length; i += 1) { - transition_in(each_blocks[i]); - } - - transition_in(if_block0); - transition_in(if_block1); - transition_in(movingdotstats.$$.fragment, local); - transition_in(simplecollapsible.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(dotgamethememanager.$$.fragment, local); - transition_out(movingdot.$$.fragment, local); - - for (let i = 0; i < each_blocks.length; i += 1) { - transition_out(each_blocks[i]); + if_block1.d(1); + if_block1 = null; } - - transition_out(if_block0); - transition_out(if_block1); - transition_out(movingdotstats.$$.fragment, local); - transition_out(simplecollapsible.$$.fragment, local); - current = false; }, d: function destroy(detaching) { - if (detaching) detach_dev(t0); - if (detaching) detach_dev(select); - destroy_each(each_blocks_1, detaching); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(button); - if (detaching) detach_dev(t3); - destroy_component(dotgamethememanager, detaching); - if (detaching) detach_dev(t4); - if (detaching) detach_dev(div1); - /*canvas_1_binding*/ ctx[22](null); - /*movingdot_binding*/ ctx[23](null); - destroy_component(movingdot); - - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].d(); - } - + if (detaching) detach_dev(div); if (if_block0) if_block0.d(); if (if_block1) if_block1.d(); - if (detaching) detach_dev(t15); - destroy_component(movingdotstats, detaching); - if (detaching) detach_dev(t16); - if (detaching) detach_dev(h1); - if (detaching) detach_dev(t18); - if (detaching) detach_dev(hr); - if (detaching) detach_dev(t19); - destroy_component(simplecollapsible, detaching); mounted = false; - run_all(dispose); + dispose(); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$b.name, - type: "component", - source: "", + id: create_each_block_3.name, + type: "each", + source: "(169:14) {#each row as piece, colIndex}", ctx }); return block; } - function instance$b($$self, $$props, $$invalidate) { - let $dotPosition; - let $targets; - let $autogenconfigtest; - validate_store(targets, 'targets'); - component_subscribe($$self, targets, $$value => $$invalidate(12, $targets = $$value)); - validate_store(autogenconfigtest, 'autogenconfigtest'); - component_subscribe($$self, autogenconfigtest, $$value => $$invalidate(26, $autogenconfigtest = $$value)); - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('MovingDotSpacePortfromReact', slots, []); - let ChangedContentPlaceholdertoSend = "No changes"; - let canvas; - let dotPosition = writable({ x: 900, y: 450 }); - validate_store(dotPosition, 'dotPosition'); - component_subscribe($$self, dotPosition, value => $$invalidate(0, $dotPosition = value)); - let boundaries = { maxX: 1835, maxY: 890, minX: 0, minY: 0 }; - let isModalOpen = false; - let isSMModalOpen = false; - let currentcollisiontitletext; - let currentcollisiontext; - let currentcollisionitems = []; - let movingDotElement; - let currentstatemodalstates; - let currentTheme = 'Default'; // default theme - let currentThemeStage = 0; - let themeKeys = Object.keys(themes); - let CurrentGameBackground = themes[currentTheme].background; //GameBackgrounds[0].url; - inventory.set(themes[currentTheme].inventory); - skills.set(themes[currentTheme].skills); - objectives.set(themes[currentTheme].story[0].objectives); - - targets.set([ - ...themes[currentTheme].persistentTargets, - ...themes[currentTheme].story[0].targets - ]); - - themeactions.set(themes[currentTheme].actions); - - //$: console.log($themeactions) - // objectives.set(themes[currentTheme].objectives); - // targets.set(themes[currentTheme].storyparttargets[0]) - // function changeTheme(event) { - // currentTheme = event.target.value; - // const theme = themes[currentTheme]; - // inventory.set(theme.inventory); - // skills.set(theme.skills); - // objectives.set(theme.objectives); - // currentThemeStage = 0; // Resetting currentThemeStage to 0 - // targets.set(theme.storyparttargets[0]); - // CurrentGameBackground = theme.background - // ChangedContentPlaceholdertoSend = "TODO is all other variables to change" - // } - function changeTheme(event) { - $$invalidate(10, currentTheme = event.target.value); - console.log(currentTheme); - const theme = themes[currentTheme]; - console.log(theme); - inventory.set(theme.inventory); - skills.set(theme.skills); - themeactions.set(themes.actions); - currentThemeStage = 0; - const initialStory = theme.story.find(part => part.part === 0); - - if (initialStory) { - objectives.set(initialStory.objectives); - - const uniqueTargets = [ - ...theme.persistentTargets, - ...initialStory.targets.filter(target => !theme.persistentTargets.some(persistentTarget => persistentTarget.name === target.name)) - ]; - - targets.set(uniqueTargets); - } else { - // Handle the case when no initial story part is found - objectives.set([]); - - targets.set([...theme.persistentTargets]); - } + // (167:6) {#each board as row, rowIndex} + function create_each_block_2$2(ctx) { + let div; + let t; + let each_value_3 = /*row*/ ctx[37]; + validate_each_argument(each_value_3); + let each_blocks = []; - $$invalidate(11, CurrentGameBackground = theme.background); - $$invalidate(1, ChangedContentPlaceholdertoSend = "TODO is all other variables to change"); + for (let i = 0; i < each_value_3.length; i += 1) { + each_blocks[i] = create_each_block_3(get_each_context_3(ctx, each_value_3, i)); } - function loadexperimentaltheme() { - if ($autogenconfigtest.story) { - inventory.set($autogenconfigtest.inventory); - skills.set($autogenconfigtest.skills); - themeactions.set($autogenconfigtest.actions); - currentThemeStage = 0; - const initialStory = $autogenconfigtest.story.find(part => part.part === 0); - - if (initialStory) { - objectives.set(initialStory.objectives); + const block = { + c: function create() { + div = element$1("div"); - const uniqueTargets = [ - ...$autogenconfigtest.persistentTargets, - ...initialStory.targets.filter(target => !$autogenconfigtest.persistentTargets.some(persistentTarget => persistentTarget.name === target.name)) - ]; + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } - targets.set(uniqueTargets); - } else { - // Handle the case when no initial story part is found - objectives.set([]); + t = space(); + attr_dev(div, "class", "row svelte-7r6gh4"); + add_location(div, file$3, 167, 10, 6151); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); - targets.set([...$autogenconfigtest.persistentTargets]); + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(div, null); + } } - $$invalidate(11, CurrentGameBackground = $autogenconfigtest.background); - $$invalidate(1, ChangedContentPlaceholdertoSend = "TODO is all other variables to change"); - } else { - alert("Merge not performed"); - } - } + append_dev(div, t); + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*handleSquareClick, squareText, board*/ 545) { + each_value_3 = /*row*/ ctx[37]; + validate_each_argument(each_value_3); + let i; - function handleSpaceClick() { - //console.log('Container clicked!', event); - movingDotElement.focusDot(); - } + for (i = 0; i < each_value_3.length; i += 1) { + const child_ctx = get_each_context_3(ctx, each_value_3, i); - function handleModalClose() { - $$invalidate(3, isModalOpen = false); - $$invalidate(4, isSMModalOpen = false); - movingDotElement.focusDot(); - } + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block_3(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(div, t); + } + } - function updateDotPosition(newX, newY) { - dotPosition.set({ x: newX, y: newY }); - } + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } - // Collision check function - const checkCollision = dotPos => { - $targets.forEach(target => { - if (dotPos.x < target.x + 10 && dotPos.x + 10 > target.x && dotPos.y < target.y + 10 && dotPos.y + 10 > target.y) { - handleCollision(target); + each_blocks.length = each_value_3.length; } - }); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + destroy_each(each_blocks, detaching); + } }; - // Handle collision based on the target object - const handleCollision = target => { - if (target.subtargets) { - alert("Subtargets found. Can be used as discovered locations or just splitting one target into a self contained set of targets. (variable logged in console)"); - console.log(target.subtargets); - } //eventually use to temporarily act as the all targets in the map which can each all have smmodals - - switch (target.collisionType) { - case "": - console.log("Nothing Happenedddd"); - break; - case "alert": - alert(target.collisiontext); - break; - case "decision": - if (confirm(target.collisiontext)) { - alert("You said yes"); - } else { - alert("You said no"); - } - break; - case "modal": - $$invalidate(3, isModalOpen = true); - $$invalidate(5, currentcollisiontitletext = target.modalConfig.title); - $$invalidate(6, currentcollisiontext = target.modalConfig.content); - $$invalidate(7, currentcollisionitems = target.modalConfig.actions); - break; - case "smmodal": - $$invalidate(4, isSMModalOpen = true); - console.log('smmodal'); - console.log(target.modalStates); - $$invalidate(9, currentstatemodalstates = target.modalStates); - //currentcollisiontitletext = target.modalConfig.title; - //currentcollisiontext = target.modalConfig.content; - //currentcollisionitems = target.modalConfig.actions; - break; - case "storypartchange": - currentThemeStage = target.transitionToPart; - const newStoryPart = themes[currentTheme].story.find(part => part.part === currentThemeStage); - if (newStoryPart) { - objectives.set(newStoryPart.objectives); - targets.set([...themes[currentTheme].persistentTargets, ...newStoryPart.targets]); - } - // currentThemeStage = target.newStage; - // targets.set(themes[currentTheme].storyparttargets[currentThemeStage]) - break; - case "requirementsgated": - const currentObjectives = themes[currentTheme].story[currentThemeStage].objectives; - const allObjectivesCompleted = currentObjectives.every(objective => objective.complete); - if (allObjectivesCompleted && target.requirements > 5) { - //if (target.requirements > 5){ - alert(target.collisiontext); - } else { - alert("You have not journeyed enough to explore this area yet (Stats required: and an inventory item)"); - } - break; - } // Handle other permanent UI elements here - }; // ... - //ChatGPT Suggested Options - // Change the background color of the canvas or a specific element. - // case "changeBackgroundColor": - - const writable_props = []; - - Object_1$2.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$6.warn(` was created with unknown prop '${key}'`); + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_2$2.name, + type: "each", + source: "(167:6) {#each board as row, rowIndex}", + ctx }); - function select_change_handler() { - currentTheme = select_value(this); - $$invalidate(10, currentTheme); - $$invalidate(15, themeKeys); - } + return block; + } - function canvas_1_binding($$value) { - binding_callbacks[$$value ? 'unshift' : 'push'](() => { - canvas = $$value; - $$invalidate(2, canvas); - }); - } + // (194:6) {#if games.length > 0} + function create_if_block_1$1(ctx) { + let div; + let h3; + let t1; + let select; + let t2; + let button; + let mounted; + let dispose; + let each_value_1 = /*games*/ ctx[2]; + validate_each_argument(each_value_1); + let each_blocks = []; - function movingdot_binding($$value) { - binding_callbacks[$$value ? 'unshift' : 'push'](() => { - movingDotElement = $$value; - $$invalidate(8, movingDotElement); - }); + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks[i] = create_each_block_1$2(get_each_context_1$2(ctx, each_value_1, i)); } - const move_handler = e => updateDotPosition(e.detail.x, e.detail.y); + const block = { + c: function create() { + div = element$1("div"); + h3 = element$1("h3"); + h3.textContent = "Select a Game"; + t1 = space(); + select = element$1("select"); - $$self.$capture_state = () => ({ - onMount, - writable, - MovingDot: MovingDotPortfromReact, - Target: MovingDotTargetPortfromReact, - Modal: MovingDotSpaceSimpleModal, - SMModal: SimpleStateMachineModal, - MovingDotStats: MovingDotStatDisplay, - DotGameThemeManager: MovingDotSpaceThemeManager, - FightTest: MovingDotSpaceGameFight, - ModalTest: MovingDotSpaceModalBrainstorm, - FindTest: MovingDotSpaceGameFind, - OrderTest: MovingDotSpaceGameOrder, - SimpleCollapsible, - themes, - inventory, - skills, - objectives, - targets, - themeactions, - autogenconfigtest, - ChangedContentPlaceholdertoSend, - canvas, - dotPosition, - boundaries, - isModalOpen, - isSMModalOpen, - currentcollisiontitletext, - currentcollisiontext, - currentcollisionitems, - movingDotElement, - currentstatemodalstates, - currentTheme, - currentThemeStage, - themeKeys, - CurrentGameBackground, - changeTheme, - loadexperimentaltheme, - handleSpaceClick, - handleModalClose, - updateDotPosition, - checkCollision, - handleCollision, - $dotPosition, - $targets, - $autogenconfigtest - }); + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } - $$self.$inject_state = $$props => { - if ('ChangedContentPlaceholdertoSend' in $$props) $$invalidate(1, ChangedContentPlaceholdertoSend = $$props.ChangedContentPlaceholdertoSend); - if ('canvas' in $$props) $$invalidate(2, canvas = $$props.canvas); - if ('dotPosition' in $$props) $$invalidate(13, dotPosition = $$props.dotPosition); - if ('boundaries' in $$props) $$invalidate(14, boundaries = $$props.boundaries); - if ('isModalOpen' in $$props) $$invalidate(3, isModalOpen = $$props.isModalOpen); - if ('isSMModalOpen' in $$props) $$invalidate(4, isSMModalOpen = $$props.isSMModalOpen); - if ('currentcollisiontitletext' in $$props) $$invalidate(5, currentcollisiontitletext = $$props.currentcollisiontitletext); - if ('currentcollisiontext' in $$props) $$invalidate(6, currentcollisiontext = $$props.currentcollisiontext); - if ('currentcollisionitems' in $$props) $$invalidate(7, currentcollisionitems = $$props.currentcollisionitems); - if ('movingDotElement' in $$props) $$invalidate(8, movingDotElement = $$props.movingDotElement); - if ('currentstatemodalstates' in $$props) $$invalidate(9, currentstatemodalstates = $$props.currentstatemodalstates); - if ('currentTheme' in $$props) $$invalidate(10, currentTheme = $$props.currentTheme); - if ('currentThemeStage' in $$props) currentThemeStage = $$props.currentThemeStage; - if ('themeKeys' in $$props) $$invalidate(15, themeKeys = $$props.themeKeys); - if ('CurrentGameBackground' in $$props) $$invalidate(11, CurrentGameBackground = $$props.CurrentGameBackground); - }; + t2 = space(); + button = element$1("button"); + button.textContent = "Load Selected Game"; + add_location(h3, file$3, 195, 14, 7367); + attr_dev(select, "class", "svelte-7r6gh4"); + add_location(select, file$3, 196, 14, 7405); + attr_dev(button, "class", "svelte-7r6gh4"); + add_location(button, file$3, 203, 14, 7765); + attr_dev(div, "class", "game-selector svelte-7r6gh4"); + add_location(div, file$3, 194, 10, 7324); + }, + m: function mount(target, anchor) { + insert_dev(target, div, anchor); + append_dev(div, h3); + append_dev(div, t1); + append_dev(div, select); - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + for (let i = 0; i < each_blocks.length; i += 1) { + if (each_blocks[i]) { + each_blocks[i].m(select, null); + } + } - $$self.$$.update = () => { - if ($$self.$$.dirty[0] & /*$dotPosition*/ 1) { - // document.body.style.backgroundColor = target.color; - // break; - // Play a sound effect. You'll need to pre-load these sounds. - // case "playSound": - // new Audio(target.soundUrl).play(); - // break; - // Redirect the user to a different URL. - // case "redirect": - // window.location.href = target.url; - // break; - // Increase the size of the dot. - // case "enlargeDot": - // dotElement.style.transform = "scale(1.5)"; - // break; - // Decrease the size of the dot. - // case "shrinkDot": - // dotElement.style.transform = "scale(0.5)"; - // break; - // Apply a rotation to the dot. - // case "rotateDot": - // dotElement.style.transform = "rotate(45deg)"; - // break; - // Toggle the visibility of a specific element on the page. - // case "toggleVisibility": - // let elem = document.getElementById(target.elementId); - // elem.style.display = elem.style.display === 'none' ? 'block' : 'none'; - // break; - // Trigger a CSS animation on a specific element. - // case "startAnimation": - // let animElem = document.getElementById(target.elementId); - // animElem.classList.add(target.animationClass); - // break; - // Increase a score or counter displayed on the screen. - // case "incrementScore": - // score += target.incrementValue; - // updateScoreDisplay(); // Assuming you have a function to update the score display - // break; - // Change the color of the dot. - // case "changeDotColor": - // dotElement.style.backgroundColor = target.color; - // break; - // Reactive statement to check collision whenever dotPosition changes - $dotPosition && checkCollision($dotPosition); + append_dev(div, t2); + append_dev(div, button); + + if (!mounted) { + dispose = [ + listen_dev(select, "change", /*change_handler*/ ctx[21], false, false, false, false), + listen_dev(button, "click", /*loadSelectedGame*/ ctx[14], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*games*/ 4) { + each_value_1 = /*games*/ ctx[2]; + validate_each_argument(each_value_1); + let i; + + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1$2(ctx, each_value_1, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block_1$2(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(select, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value_1.length; + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(div); + destroy_each(each_blocks, detaching); + mounted = false; + run_all(dispose); } }; - return [ - $dotPosition, - ChangedContentPlaceholdertoSend, - canvas, - isModalOpen, - isSMModalOpen, - currentcollisiontitletext, - currentcollisiontext, - currentcollisionitems, - movingDotElement, - currentstatemodalstates, - currentTheme, - CurrentGameBackground, - $targets, - dotPosition, - boundaries, - themeKeys, - changeTheme, - loadexperimentaltheme, - handleSpaceClick, - handleModalClose, - updateDotPosition, - select_change_handler, - canvas_1_binding, - movingdot_binding, - move_handler - ]; - } - - class MovingDotSpacePortfromReact extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$b, create_fragment$b, safe_not_equal, {}, null, [-1, -1]); + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_1$1.name, + type: "if", + source: "(194:6) {#if games.length > 0}", + ctx + }); - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "MovingDotSpacePortfromReact", - options, - id: create_fragment$b.name - }); - } + return block; } - /* src\YoutubeIframeAPICustomInterface.svelte generated by Svelte v3.59.2 */ + // (198:18) {#each games as game, index} + function create_each_block_1$2(ctx) { + let option; + let t0_value = /*game*/ ctx[34].metadata.Event + ""; + let t0; + let t1; + let t2_value = /*game*/ ctx[34].metadata.White + ""; + let t2; + let t3; + let t4_value = /*game*/ ctx[34].metadata.Black + ""; + let t4; + let t5; - const { console: console_1$5 } = globals; + const block = { + c: function create() { + option = element$1("option"); + t0 = text(t0_value); + t1 = text(" - "); + t2 = text(t2_value); + t3 = text(" vs "); + t4 = text(t4_value); + t5 = space(); + option.__value = /*index*/ ctx[36]; + option.value = option.__value; + add_location(option, file$3, 198, 22, 7544); + }, + m: function mount(target, anchor) { + insert_dev(target, option, anchor); + append_dev(option, t0); + append_dev(option, t1); + append_dev(option, t2); + append_dev(option, t3); + append_dev(option, t4); + append_dev(option, t5); + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*games*/ 4 && t0_value !== (t0_value = /*game*/ ctx[34].metadata.Event + "")) set_data_dev(t0, t0_value); + if (dirty[0] & /*games*/ 4 && t2_value !== (t2_value = /*game*/ ctx[34].metadata.White + "")) set_data_dev(t2, t2_value); + if (dirty[0] & /*games*/ 4 && t4_value !== (t4_value = /*game*/ ctx[34].metadata.Black + "")) set_data_dev(t4, t4_value); + }, + d: function destroy(detaching) { + if (detaching) detach_dev(option); + } + }; - const file$a = "src\\YoutubeIframeAPICustomInterface.svelte"; + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block_1$2.name, + type: "each", + source: "(198:18) {#each games as game, index}", + ctx + }); - function get_each_context$7(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[76] = list[i]; - child_ctx[78] = i; - return child_ctx; + return block; } - // (518:8) {#each YTIDitems as item, index} - function create_each_block$7(ctx) { - let button; - let t0_value = /*item*/ ctx[76] + ""; - let t0; + // (208:6) {#if previewText} + function create_if_block$1(ctx) { + let div; + let h3; let t1; + let textarea; + let t2; + let button; let mounted; let dispose; - function click_handler() { - return /*click_handler*/ ctx[43](/*index*/ ctx[78]); - } - const block = { c: function create() { - button = element("button"); - t0 = text(t0_value); + div = element$1("div"); + h3 = element$1("h3"); + h3.textContent = "Game Preview"; t1 = space(); - add_location(button, file$a, 518, 12, 18828); + textarea = element$1("textarea"); + t2 = space(); + button = element$1("button"); + button.textContent = "Copy to Clipboard"; + add_location(h3, file$3, 209, 14, 7935); + textarea.readOnly = true; + attr_dev(textarea, "rows", "10"); + attr_dev(textarea, "cols", "50"); + textarea.value = /*previewText*/ ctx[4]; + attr_dev(textarea, "class", "svelte-7r6gh4"); + add_location(textarea, file$3, 210, 14, 7972); + add_location(button, file$3, 211, 14, 8051); + attr_dev(div, "class", "preview svelte-7r6gh4"); + add_location(div, file$3, 208, 10, 7898); }, m: function mount(target, anchor) { - insert_dev(target, button, anchor); - append_dev(button, t0); - append_dev(button, t1); + insert_dev(target, div, anchor); + append_dev(div, h3); + append_dev(div, t1); + append_dev(div, textarea); + append_dev(div, t2); + append_dev(div, button); if (!mounted) { - dispose = listen_dev(button, "click", click_handler, false, false, false, false); + dispose = listen_dev(button, "click", /*copyToClipboard*/ ctx[15], false, false, false, false); mounted = true; } }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; - if (dirty[0] & /*YTIDitems*/ 65536 && t0_value !== (t0_value = /*item*/ ctx[76] + "")) set_data_dev(t0, t0_value); + p: function update(ctx, dirty) { + if (dirty[0] & /*previewText*/ 16) { + prop_dev(textarea, "value", /*previewText*/ ctx[4]); + } }, d: function destroy(detaching) { - if (detaching) detach_dev(button); + if (detaching) detach_dev(div); mounted = false; dispose(); } @@ -63202,3986 +106919,4581 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$7.name, + id: create_if_block$1.name, + type: "if", + source: "(208:6) {#if previewText}", + ctx + }); + + return block; + } + + // (219:14) {#each squareOptions as option} + function create_each_block$2(ctx) { + let option; + let t_value = /*option*/ ctx[31].label + ""; + let t; + + const block = { + c: function create() { + option = element$1("option"); + t = text(t_value); + option.__value = /*option*/ ctx[31].value; + option.value = option.__value; + add_location(option, file$3, 219, 18, 8358); + }, + m: function mount(target, anchor) { + insert_dev(target, option, anchor); + append_dev(option, t); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(option); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_each_block$2.name, type: "each", - source: "(518:8) {#each YTIDitems as item, index}", + source: "(219:14) {#each squareOptions as option}", ctx }); return block; } - function create_fragment$a(ctx) { - let h10; + function create_fragment$3(ctx) { + let div4; + let div0; + let t0; + let div3; + let textarea0; let t1; - let h20; + let button0; let t3; - let h3; + let hr; let t4; - let b; - let t6; - let h11; + let input0; + let t5; + let button1; let t7; - let t8; + let button2; let t9; - let div1; - let label; - let br0; + let t10; let t11; - let input0; - let t12; - let button0; + let div1; + let select; + let option; + let t13; + let input1; let t14; - let button1; + let button3; let t16; - let br1; - let t17; - let textarea0; - let br2; - let t18; - let div0; - let t19; let div2; - let input1; + let h3; + let t18; + let button4; let t20; - let input2; - let t21; let textarea1; - let t22; - let button2; - let t24; - let pre; - let t25; - let t26; - let div7; - let div3; - let t27; - let div4; - let t28; - let t29_value = /*currentTime*/ ctx[4].toFixed(2) + ""; - let t29; - let t30; - let t31; - let div5; - let t32; - let t33; - let br3; - let t34; - let t35; - let t36; - let br4; - let t37; - let div6; - let t38; - let t39; - let t40; - let div8; - let t41; - let t42; - let t43; - let br5; - let t44; - let input3; - let t45; - let button3; - let t47; - let t48; - let t49; - let button4; - let t51; - let textarea2; - let t52; + let t21; let button5; - let t56; - let button6; - let t60; - let t61; - let t62; - let t63_value = /*timestamps*/ ctx[11].length + ""; - let t63; - let t64; - let br6; - let t65; - let button7; - let t67; - let button8; - let t68; - let button8_class_value; - let button8_disabled_value; - let t69; - let button9; - let t70; - let button9_class_value; - let button9_disabled_value; - let t71; - let button10; - let t72; - let button10_class_value; - let button10_disabled_value; - let t73; - let t74; - let t75; - let t76_value = /*userTimestamps*/ ctx[1].length + ""; - let t76; - let t77; - let br7; - let t78; - let t79; - let t80; - let t81_value = /*r2userTimestamps*/ ctx[12].length + ""; - let t81; - let t82; - let br8; - let t83; - let br9; - let t84; - let button11; - let t86; - let button12; - let t88; - let input4; - let t89; - let br10; - let t90; - let input5; - let t91; - let input6; - let t92; - let input7; - let t93; - let input8; - let t94; - let div9; - let h21; - let t96; - let h22; - let t98; - let hr; - let t99; - let div10; - let t100; - let br11; let mounted; let dispose; - let each_value = /*YTIDitems*/ ctx[16]; - validate_each_argument(each_value); - let each_blocks = []; - - for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$7(get_each_context$7(ctx, each_value, i)); - } - - const block = { - c: function create() { - h10 = element("h1"); - h10.textContent = "Custom Youtube Player for learning Video and music"; - t1 = space(); - h20 = element("h2"); - h20.textContent = "Next Step for social media is to build in education blocks eg. App lets you watch next short uninterrupted if you get answer right, app forces you to see the correction as overlay if you get it wrong"; - t3 = space(); - h3 = element("h3"); - t4 = text("End Goal is special subtitles - Nouns Verbs and images of them in sync with video AND "); - b = element("b"); - b.textContent = "NB NB NB random repitition of items over video Reading as you watch any video NB NB NB"; - t6 = space(); - h11 = element("h1"); - t7 = text("Debug subs = "); - t8 = text(/*$ytsubcurrenttext*/ ctx[22]); - t9 = space(); - div1 = element("div"); - label = element("label"); - label.textContent = "Manage Multiple Videos"; - br0 = element("br"); - t11 = text("\r\n Import "); - input0 = element("input"); - t12 = space(); - button0 = element("button"); - button0.textContent = "Add Items"; - t14 = space(); - button1 = element("button"); - button1.textContent = "Download List as Text File"; - t16 = space(); - br1 = element("br"); - t17 = space(); - textarea0 = element("textarea"); - br2 = element("br"); - t18 = space(); - div0 = element("div"); - - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + let each_value_2 = /*board*/ ctx[0]; + validate_each_argument(each_value_2); + let each_blocks_1 = []; - t19 = space(); - div2 = element("div"); - input1 = element("input"); - t20 = text("\r\n Start/Stop Word Update (Dummy Transcript as default)\r\n "); - input2 = element("input"); - t21 = space(); - textarea1 = element("textarea"); - t22 = space(); - button2 = element("button"); - button2.textContent = "Convert YT Transcript to JSON Test"; - t24 = space(); - pre = element("pre"); - t25 = text(/*jsonOutput*/ ctx[6]); - t26 = space(); - div7 = element("div"); - div3 = element("div"); - t27 = space(); - div4 = element("div"); - t28 = text("Current Time: "); - t29 = text(t29_value); - t30 = text(" seconds"); - t31 = space(); - div5 = element("div"); - t32 = text(/*line*/ ctx[8]); - t33 = space(); - br3 = element("br"); - t34 = space(); - t35 = text(/*currentWord*/ ctx[7]); - t36 = space(); - br4 = element("br"); - t37 = space(); - div6 = element("div"); - t38 = text("Debug subs (Hide = '') = "); - t39 = text(/*$ytsubcurrenttext*/ ctx[22]); - t40 = space(); - div8 = element("div"); - t41 = text("Note Taking Section based on auto gen timestamp (currently "); - t42 = text(/*interval*/ ctx[23]); - t43 = text("s) (caution - all changes saved) --- "); - br5 = element("br"); - t44 = space(); - input3 = element("input"); - t45 = space(); - button3 = element("button"); - button3.textContent = "create note Segments"; - t47 = text(" | Current index of Note: "); - t48 = text(/*currentIndex*/ ctx[10]); - t49 = text(" | "); - button4 = element("button"); - button4.textContent = "Save Notes to File"; - t51 = text(" Overlay notes on screen check box | AI analysis generate button |\r\n "); - textarea2 = element("textarea"); - t52 = space(); - button5 = element("button"); - button5.textContent = `Previous Auto Timestamp - ${/*interval*/ ctx[23]}s`; - t56 = space(); - button6 = element("button"); - button6.textContent = `Next Auto Timestamp - ${/*interval*/ ctx[23]}s`; - t60 = text("\r\nAuto Timestamps: "); - t61 = text(/*currentIndex*/ ctx[10]); - t62 = text(" / "); - t63 = text(t63_value); - t64 = space(); - br6 = element("br"); - t65 = space(); - button7 = element("button"); - button7.textContent = "Add Timestamp"; - t67 = space(); - button8 = element("button"); - t68 = text("Current User Timestamp (incomplete)"); - t69 = space(); - button9 = element("button"); - t70 = text("Previous User Timestamp"); - t71 = space(); - button10 = element("button"); - t72 = text("Next User Timestamp"); - t73 = text("\r\nUser Timestamps: "); - t74 = text(/*currentuserIndex*/ ctx[0]); - t75 = text(" / "); - t76 = text(t76_value); - t77 = space(); - br7 = element("br"); - t78 = text(" Round 2 (/n) User Timestamps: "); - t79 = text(/*currentuserIndex*/ ctx[0]); - t80 = text(" / "); - t81 = text(t81_value); - t82 = space(); - br8 = element("br"); - t83 = text("A list of one messes up the logic for the counter in conjuction with the user timestamp button reactivity "); - br9 = element("br"); - t84 = space(); - button11 = element("button"); - button11.textContent = "Export Timestamps"; - t86 = space(); - button12 = element("button"); - button12.textContent = "Export Round 2 Timestamps"; - t88 = text(" Import Timestamps (Incomplete) "); - input4 = element("input"); - t89 = space(); - br10 = element("br"); - t90 = text(" Interval Repeat "); - input5 = element("input"); - t91 = text(" ||| Start "); - input6 = element("input"); - t92 = text(" End "); - input7 = element("input"); - t93 = text(" Reps "); - input8 = element("input"); - t94 = space(); - div9 = element("div"); - h21 = element("h2"); - h21.textContent = "Anticipation Training? -- Verbs in subtitle order known before interval repitition?"; - t96 = space(); - h22 = element("h2"); - h22.textContent = "Stateful Video - Reverse Interval Repeat aka parts of the video you know == Autoskip sections"; - t98 = space(); - hr = element("hr"); - t99 = space(); - div10 = element("div"); - t100 = text("Skip Interval Button sections\r\n "); - br11 = element("br"); - add_location(h10, file$a, 504, 0, 17783); - add_location(h20, file$a, 505, 0, 17844); - add_location(b, file$a, 506, 90, 18144); - add_location(h3, file$a, 506, 0, 18054); - add_location(h11, file$a, 508, 0, 18246); - attr_dev(label, "for", "ytid-input"); - add_location(label, file$a, 511, 4, 18304); - add_location(br0, file$a, 511, 58, 18358); - attr_dev(input0, "type", "file"); - attr_dev(input0, "id", "file-import"); - add_location(input0, file$a, 512, 11, 18375); - add_location(button0, file$a, 513, 4, 18452); - add_location(button1, file$a, 514, 4, 18508); - add_location(br1, file$a, 514, 76, 18580); - attr_dev(textarea0, "id", "ytid-input"); - attr_dev(textarea0, "rows", "4"); - set_style(textarea0, "width", "35%"); - attr_dev(textarea0, "placeholder", "Add multiple Youtube IDs separated by new lines to make buttons"); - add_location(textarea0, file$a, 515, 4, 18590); - add_location(br2, file$a, 515, 171, 18757); - add_location(div0, file$a, 516, 4, 18767); - add_location(div1, file$a, 510, 0, 18293); - attr_dev(input1, "type", "text"); - add_location(input1, file$a, 527, 4, 18974); - attr_dev(input2, "type", "checkbox"); - add_location(input2, file$a, 529, 4, 19086); - attr_dev(textarea1, "placeholder", "Enter transcript here..."); - add_location(textarea1, file$a, 534, 4, 19409); - add_location(button2, file$a, 535, 4, 19499); - attr_dev(pre, "class", "transcriptpre svelte-udvqea"); - add_location(pre, file$a, 536, 4, 19584); - add_location(div2, file$a, 526, 0, 18963); - attr_dev(div3, "id", "youtube-player"); - set_style(div3, "height", "90vh"); - set_style(div3, "width", "90%"); - add_location(div3, file$a, 540, 4, 19680); - set_style(div4, "position", "absolute"); - set_style(div4, "top", "0%"); - set_style(div4, "left", "40%"); - set_style(div4, "color", "white"); - set_style(div4, "background-color", "rgba(0, 0, 0, 0.5)"); - add_location(div4, file$a, 541, 4, 19750); - add_location(br3, file$a, 545, 15, 20070); - add_location(br4, file$a, 546, 22, 20098); - set_style(div5, "position", "absolute"); - set_style(div5, "top", "50%"); - set_style(div5, "left", "20%"); - set_style(div5, "color", "white"); - set_style(div5, "background-color", "rgba(0, 0, 0, 0.5)"); - set_style(div5, "font-size", "100px"); - add_location(div5, file$a, 544, 4, 19929); - set_style(div6, "position", "absolute"); - set_style(div6, "top", "25%"); - set_style(div6, "left", "30%"); - set_style(div6, "color", "white"); - set_style(div6, "background-color", "rgba(0, 0, 0, 0.5)"); - set_style(div6, "font-size", "100px"); - add_location(div6, file$a, 548, 4, 20120); - set_style(div7, "position", "relative"); - add_location(div7, file$a, 539, 0, 19641); - add_location(br5, file$a, 554, 110, 20442); - attr_dev(input3, "type", "file"); - add_location(input3, file$a, 555, 4, 20452); - add_location(button3, file$a, 555, 59, 20507); - add_location(button4, file$a, 555, 169, 20617); - attr_dev(textarea2, "name", "notesubtitles"); - attr_dev(textarea2, "id", "notestextarea"); - attr_dev(textarea2, "rows", "2"); - set_style(textarea2, "width", "100%"); - add_location(textarea2, file$a, 556, 4, 20759); - add_location(div8, file$a, 553, 0, 20325); - add_location(button5, file$a, 560, 0, 20986); - add_location(button6, file$a, 561, 0, 21079); - add_location(br6, file$a, 564, 0, 21221); - add_location(button7, file$a, 565, 0, 21227); - attr_dev(button8, "class", button8_class_value = "" + (null_to_empty(/*currentindexButtonClass*/ ctx[19]) + " svelte-udvqea")); - button8.disabled = button8_disabled_value = /*currentuserIndex*/ ctx[0] <= 0; - add_location(button8, file$a, 566, 0, 21287); - attr_dev(button9, "class", button9_class_value = "" + (null_to_empty(/*previousindexButtonClass*/ ctx[20]) + " svelte-udvqea")); - button9.disabled = button9_disabled_value = /*currentuserIndex*/ ctx[0] <= 0; - add_location(button9, file$a, 567, 0, 21442); - attr_dev(button10, "class", button10_class_value = "" + (null_to_empty(/*nextindexButtonClass*/ ctx[21]) + " svelte-udvqea")); - button10.disabled = button10_disabled_value = /*currentuserIndex*/ ctx[0] >= /*userTimestamps*/ ctx[1].length - 1; - add_location(button10, file$a, 568, 0, 21587); - add_location(br7, file$a, 571, 0, 21810); - add_location(br8, file$a, 571, 82, 21892); - add_location(br9, file$a, 571, 192, 22002); - add_location(button11, file$a, 572, 0, 22008); - add_location(button12, file$a, 572, 63, 22071); - attr_dev(input4, "type", "file"); - attr_dev(input4, "accept", ".json"); - add_location(input4, file$a, 572, 167, 22175); - add_location(br10, file$a, 573, 0, 22240); - attr_dev(input5, "type", "checkbox"); - add_location(input5, file$a, 573, 21, 22261); - attr_dev(input6, "type", "number"); - attr_dev(input6, "class", "numberinput svelte-udvqea"); - attr_dev(input6, "min", "0"); - add_location(input6, file$a, 573, 82, 22322); - attr_dev(input7, "type", "number"); - attr_dev(input7, "class", "numberinput svelte-udvqea"); - attr_dev(input7, "min", "0"); - add_location(input7, file$a, 573, 162, 22402); - attr_dev(input8, "type", "number"); - attr_dev(input8, "class", "numberinput svelte-udvqea"); - attr_dev(input8, "min", "0"); - add_location(input8, file$a, 573, 241, 22481); - add_location(h21, file$a, 577, 4, 22594); - add_location(h22, file$a, 578, 4, 22692); - attr_dev(div9, "class", "imagesubtitle svelte-udvqea"); - add_location(div9, file$a, 576, 0, 22561); - add_location(hr, file$a, 582, 0, 22808); - add_location(br11, file$a, 585, 4, 22860); - add_location(div10, file$a, 583, 0, 22814); + for (let i = 0; i < each_value_2.length; i += 1) { + each_blocks_1[i] = create_each_block_2$2(get_each_context_2$2(ctx, each_value_2, i)); + } + + let if_block0 = /*games*/ ctx[2].length > 0 && create_if_block_1$1(ctx); + let if_block1 = /*previewText*/ ctx[4] && create_if_block$1(ctx); + let each_value = /*squareOptions*/ ctx[8]; + validate_each_argument(each_value); + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block$2(get_each_context$2(ctx, each_value, i)); + } + + const block = { + c: function create() { + div4 = element$1("div"); + div0 = element$1("div"); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].c(); + } + + t0 = space(); + div3 = element$1("div"); + textarea0 = element$1("textarea"); + t1 = space(); + button0 = element$1("button"); + button0.textContent = "Load from Text"; + t3 = space(); + hr = element$1("hr"); + t4 = space(); + input0 = element$1("input"); + t5 = space(); + button1 = element$1("button"); + button1.textContent = "Load Starting Position"; + t7 = space(); + button2 = element$1("button"); + button2.textContent = "Next Move"; + t9 = space(); + if (if_block0) if_block0.c(); + t10 = space(); + if (if_block1) if_block1.c(); + t11 = space(); + div1 = element$1("div"); + select = element$1("select"); + option = element$1("option"); + option.textContent = "Select a square"; + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + t13 = space(); + input1 = element$1("input"); + t14 = space(); + button3 = element$1("button"); + button3.textContent = "Add Text to Square"; + t16 = space(); + div2 = element$1("div"); + h3 = element$1("h3"); + h3.textContent = "Save and Load Position"; + t18 = space(); + button4 = element$1("button"); + button4.textContent = "Save Current Position"; + t20 = space(); + textarea1 = element$1("textarea"); + t21 = space(); + button5 = element$1("button"); + button5.textContent = "Load Saved Position"; + attr_dev(div0, "class", "board svelte-7r6gh4"); + add_location(div0, file$3, 165, 2, 6082); + attr_dev(textarea0, "id", "notationTextarea"); + attr_dev(textarea0, "placeholder", "Enter notation here..."); + attr_dev(textarea0, "rows", "5"); + attr_dev(textarea0, "cols", "50"); + add_location(textarea0, file$3, 186, 6, 6870); + add_location(button0, file$3, 187, 6, 7008); + add_location(hr, file$3, 188, 6, 7071); + attr_dev(input0, "type", "file"); + attr_dev(input0, "accept", ".pgn"); + add_location(input0, file$3, 189, 6, 7083); + add_location(button1, file$3, 190, 6, 7155); + add_location(button2, file$3, 191, 6, 7234); + option.__value = ""; + option.value = option.__value; + option.disabled = true; + add_location(option, file$3, 217, 14, 8241); + attr_dev(select, "class", "svelte-7r6gh4"); + if (/*selectedSquare*/ ctx[1] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[22].call(select)); + add_location(select, file$3, 216, 10, 8189); + attr_dev(input1, "type", "text"); + attr_dev(input1, "placeholder", "Enter text for selected square"); + attr_dev(input1, "class", "svelte-7r6gh4"); + add_location(input1, file$3, 222, 10, 8466); + attr_dev(button3, "class", "svelte-7r6gh4"); + add_location(button3, file$3, 223, 10, 8567); + attr_dev(div1, "class", "text-input svelte-7r6gh4"); + add_location(div1, file$3, 215, 6, 8153); + add_location(h3, file$3, 227, 10, 8688); + attr_dev(button4, "class", "svelte-7r6gh4"); + add_location(button4, file$3, 228, 10, 8731); + attr_dev(textarea1, "placeholder", "Paste saved position data here..."); + attr_dev(textarea1, "rows", "5"); + attr_dev(textarea1, "cols", "50"); + attr_dev(textarea1, "class", "svelte-7r6gh4"); + add_location(textarea1, file$3, 229, 10, 8805); + attr_dev(button5, "class", "svelte-7r6gh4"); + add_location(button5, file$3, 230, 10, 8927); + attr_dev(div2, "class", "save-load svelte-7r6gh4"); + add_location(div2, file$3, 226, 6, 8653); + add_location(div3, file$3, 185, 2, 6857); + attr_dev(div4, "class", "boardandextra svelte-7r6gh4"); + add_location(div4, file$3, 164, 0, 6051); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, m: function mount(target, anchor) { - insert_dev(target, h10, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, h20, anchor); - insert_dev(target, t3, anchor); - insert_dev(target, h3, anchor); - append_dev(h3, t4); - append_dev(h3, b); - insert_dev(target, t6, anchor); - insert_dev(target, h11, anchor); - append_dev(h11, t7); - append_dev(h11, t8); - insert_dev(target, t9, anchor); - insert_dev(target, div1, anchor); - append_dev(div1, label); - append_dev(div1, br0); - append_dev(div1, t11); - append_dev(div1, input0); - append_dev(div1, t12); - append_dev(div1, button0); - append_dev(div1, t14); - append_dev(div1, button1); - append_dev(div1, t16); - append_dev(div1, br1); - append_dev(div1, t17); - append_dev(div1, textarea0); - set_input_value(textarea0, /*YTIDinput*/ ctx[17]); - append_dev(div1, br2); - append_dev(div1, t18); - append_dev(div1, div0); + insert_dev(target, div4, anchor); + append_dev(div4, div0); + + for (let i = 0; i < each_blocks_1.length; i += 1) { + if (each_blocks_1[i]) { + each_blocks_1[i].m(div0, null); + } + } + + append_dev(div4, t0); + append_dev(div4, div3); + append_dev(div3, textarea0); + append_dev(div3, t1); + append_dev(div3, button0); + append_dev(div3, t3); + append_dev(div3, hr); + append_dev(div3, t4); + append_dev(div3, input0); + append_dev(div3, t5); + append_dev(div3, button1); + append_dev(div3, t7); + append_dev(div3, button2); + append_dev(div3, t9); + if (if_block0) if_block0.m(div3, null); + append_dev(div3, t10); + if (if_block1) if_block1.m(div3, null); + append_dev(div3, t11); + append_dev(div3, div1); + append_dev(div1, select); + append_dev(select, option); for (let i = 0; i < each_blocks.length; i += 1) { if (each_blocks[i]) { - each_blocks[i].m(div0, null); + each_blocks[i].m(select, null); } } - insert_dev(target, t19, anchor); - insert_dev(target, div2, anchor); - append_dev(div2, input1); - set_input_value(input1, /*$ytsubcurrentID*/ ctx[3]); + select_option(select, /*selectedSquare*/ ctx[1], true); + append_dev(div1, t13); + append_dev(div1, input1); + set_input_value(input1, /*textInput*/ ctx[6]); + append_dev(div1, t14); + append_dev(div1, button3); + append_dev(div3, t16); + append_dev(div3, div2); + append_dev(div2, h3); + append_dev(div2, t18); + append_dev(div2, button4); append_dev(div2, t20); - append_dev(div2, input2); - input2.checked = /*isUpdating*/ ctx[9]; - append_dev(div2, t21); append_dev(div2, textarea1); - set_input_value(textarea1, /*transcript*/ ctx[5]); - append_dev(div2, t22); - append_dev(div2, button2); - append_dev(div2, t24); - append_dev(div2, pre); - append_dev(pre, t25); - insert_dev(target, t26, anchor); - insert_dev(target, div7, anchor); - append_dev(div7, div3); - append_dev(div7, t27); - append_dev(div7, div4); - append_dev(div4, t28); - append_dev(div4, t29); - append_dev(div4, t30); - append_dev(div7, t31); - append_dev(div7, div5); - append_dev(div5, t32); - append_dev(div5, t33); - append_dev(div5, br3); - append_dev(div5, t34); - append_dev(div5, t35); - append_dev(div5, t36); - append_dev(div5, br4); - append_dev(div7, t37); - append_dev(div7, div6); - append_dev(div6, t38); - append_dev(div6, t39); - insert_dev(target, t40, anchor); - insert_dev(target, div8, anchor); - append_dev(div8, t41); - append_dev(div8, t42); - append_dev(div8, t43); - append_dev(div8, br5); - append_dev(div8, t44); - append_dev(div8, input3); - append_dev(div8, t45); - append_dev(div8, button3); - append_dev(div8, t47); - append_dev(div8, t48); - append_dev(div8, t49); - append_dev(div8, button4); - append_dev(div8, t51); - append_dev(div8, textarea2); - set_input_value(textarea2, /*notesegments*/ ctx[18][/*currentIndex*/ ctx[10]]['notes']); - insert_dev(target, t52, anchor); - insert_dev(target, button5, anchor); - insert_dev(target, t56, anchor); - insert_dev(target, button6, anchor); - insert_dev(target, t60, anchor); - insert_dev(target, t61, anchor); - insert_dev(target, t62, anchor); - insert_dev(target, t63, anchor); - insert_dev(target, t64, anchor); - insert_dev(target, br6, anchor); - insert_dev(target, t65, anchor); - insert_dev(target, button7, anchor); - insert_dev(target, t67, anchor); - insert_dev(target, button8, anchor); - append_dev(button8, t68); - insert_dev(target, t69, anchor); - insert_dev(target, button9, anchor); - append_dev(button9, t70); - insert_dev(target, t71, anchor); - insert_dev(target, button10, anchor); - append_dev(button10, t72); - insert_dev(target, t73, anchor); - insert_dev(target, t74, anchor); - insert_dev(target, t75, anchor); - insert_dev(target, t76, anchor); - insert_dev(target, t77, anchor); - insert_dev(target, br7, anchor); - insert_dev(target, t78, anchor); - insert_dev(target, t79, anchor); - insert_dev(target, t80, anchor); - insert_dev(target, t81, anchor); - insert_dev(target, t82, anchor); - insert_dev(target, br8, anchor); - insert_dev(target, t83, anchor); - insert_dev(target, br9, anchor); - insert_dev(target, t84, anchor); - insert_dev(target, button11, anchor); - insert_dev(target, t86, anchor); - insert_dev(target, button12, anchor); - insert_dev(target, t88, anchor); - insert_dev(target, input4, anchor); - insert_dev(target, t89, anchor); - insert_dev(target, br10, anchor); - insert_dev(target, t90, anchor); - insert_dev(target, input5, anchor); - input5.checked = /*isRepeating*/ ctx[2]; - insert_dev(target, t91, anchor); - insert_dev(target, input6, anchor); - set_input_value(input6, /*repstartTime*/ ctx[13]); - insert_dev(target, t92, anchor); - insert_dev(target, input7, anchor); - set_input_value(input7, /*rependTime*/ ctx[14]); - insert_dev(target, t93, anchor); - insert_dev(target, input8, anchor); - set_input_value(input8, /*repetitions*/ ctx[15]); - insert_dev(target, t94, anchor); - insert_dev(target, div9, anchor); - append_dev(div9, h21); - append_dev(div9, t96); - append_dev(div9, h22); - insert_dev(target, t98, anchor); - insert_dev(target, hr, anchor); - insert_dev(target, t99, anchor); - insert_dev(target, div10, anchor); - append_dev(div10, t100); - append_dev(div10, br11); + set_input_value(textarea1, /*saveData*/ ctx[7]); + append_dev(div2, t21); + append_dev(div2, button5); + + if (!mounted) { + dispose = [ + listen_dev(textarea0, "input", /*handleTextareaInput*/ ctx[16], false, false, false, false), + listen_dev(button0, "click", /*loadFromText*/ ctx[17], false, false, false, false), + listen_dev(input0, "change", /*handleFileUpload*/ ctx[13], false, false, false, false), + listen_dev(button1, "click", /*loadStartingPosition*/ ctx[11], false, false, false, false), + listen_dev(button2, "click", /*nextMove*/ ctx[12], false, false, false, false), + listen_dev(select, "change", /*select_change_handler*/ ctx[22]), + listen_dev(input1, "input", /*input1_input_handler*/ ctx[23]), + listen_dev(button3, "click", /*addTextToSquare*/ ctx[10], false, false, false, false), + listen_dev(button4, "click", /*savePosition*/ ctx[18], false, false, false, false), + listen_dev(textarea1, "input", /*textarea1_input_handler*/ ctx[24]), + listen_dev(button5, "click", /*loadSavedPosition*/ ctx[19], false, false, false, false) + ]; + + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*board, handleSquareClick, squareText*/ 545) { + each_value_2 = /*board*/ ctx[0]; + validate_each_argument(each_value_2); + let i; + + for (i = 0; i < each_value_2.length; i += 1) { + const child_ctx = get_each_context_2$2(ctx, each_value_2, i); + + if (each_blocks_1[i]) { + each_blocks_1[i].p(child_ctx, dirty); + } else { + each_blocks_1[i] = create_each_block_2$2(child_ctx); + each_blocks_1[i].c(); + each_blocks_1[i].m(div0, null); + } + } + + for (; i < each_blocks_1.length; i += 1) { + each_blocks_1[i].d(1); + } + + each_blocks_1.length = each_value_2.length; + } + + if (/*games*/ ctx[2].length > 0) { + if (if_block0) { + if_block0.p(ctx, dirty); + } else { + if_block0 = create_if_block_1$1(ctx); + if_block0.c(); + if_block0.m(div3, t10); + } + } else if (if_block0) { + if_block0.d(1); + if_block0 = null; + } + + if (/*previewText*/ ctx[4]) { + if (if_block1) { + if_block1.p(ctx, dirty); + } else { + if_block1 = create_if_block$1(ctx); + if_block1.c(); + if_block1.m(div3, t11); + } + } else if (if_block1) { + if_block1.d(1); + if_block1 = null; + } + + if (dirty[0] & /*squareOptions*/ 256) { + each_value = /*squareOptions*/ ctx[8]; + validate_each_argument(each_value); + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context$2(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + } else { + each_blocks[i] = create_each_block$2(child_ctx); + each_blocks[i].c(); + each_blocks[i].m(select, null); + } + } + + for (; i < each_blocks.length; i += 1) { + each_blocks[i].d(1); + } + + each_blocks.length = each_value.length; + } + + if (dirty[0] & /*selectedSquare, squareOptions*/ 258) { + select_option(select, /*selectedSquare*/ ctx[1]); + } + + if (dirty[0] & /*textInput*/ 64 && input1.value !== /*textInput*/ ctx[6]) { + set_input_value(input1, /*textInput*/ ctx[6]); + } + + if (dirty[0] & /*saveData*/ 128) { + set_input_value(textarea1, /*saveData*/ ctx[7]); + } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div4); + destroy_each(each_blocks_1, detaching); + if (if_block0) if_block0.d(); + if (if_block1) if_block1.d(); + destroy_each(each_blocks, detaching); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_fragment$3.name, + type: "component", + source: "", + ctx + }); + + return block; + } + + function getSquareColor(square) { + const row = 8 - Math.floor(square / 8); + const col = square % 8 + 1; + return (row + col) % 2 === 0 ? 'light' : 'dark'; + } + + function getPieceImage(piece) { + if (!piece) return ''; + const pieceType = piece.type; + const pieceColor = piece.color === 'w' ? 'white' : 'black'; + return `/Chess/${pieceColor}_${pieceType}.png`; // Ensure these images are available in the /images directory + } + + function instance$3($$self, $$props, $$invalidate) { + let { $$slots: slots = {}, $$scope } = $$props; + validate_slots('ChessStudyTool', slots, []); + let chess = new Chess(); + let board = chess.board(); + let selectedSquare = null; + let moves = []; + let currentMoveIndex = 0; + let pgnContent = ''; + let games = []; + let selectedGameIndex = -1; + let previewText = ''; + let squareText = {}; // Object to store text for each square + let textInput = ''; + let saveData = ''; // Text area content to save/load position + + let squareOptions = [ + { value: 0, label: 'a8' }, + { value: 1, label: 'b8' }, + { value: 2, label: 'c8' }, + { value: 3, label: 'd8' }, + { value: 4, label: 'e8' }, + { value: 5, label: 'f8' }, + { value: 6, label: 'g8' }, + { value: 7, label: 'h8' }, + { value: 8, label: 'a7' }, + { value: 9, label: 'b7' }, + { value: 10, label: 'c7' }, + { value: 11, label: 'd7' }, + { value: 12, label: 'e7' }, + { value: 13, label: 'f7' }, + { value: 14, label: 'g7' }, + { value: 15, label: 'h7' }, + { value: 16, label: 'a6' }, + { value: 17, label: 'b6' }, + { value: 18, label: 'c6' }, + { value: 19, label: 'd6' }, + { value: 20, label: 'e6' }, + { value: 21, label: 'f6' }, + { value: 22, label: 'g6' }, + { value: 23, label: 'h6' }, + { value: 24, label: 'a5' }, + { value: 25, label: 'b5' }, + { value: 26, label: 'c5' }, + { value: 27, label: 'd5' }, + { value: 28, label: 'e5' }, + { value: 29, label: 'f5' }, + { value: 30, label: 'g5' }, + { value: 31, label: 'h5' }, + { value: 32, label: 'a4' }, + { value: 33, label: 'b4' }, + { value: 34, label: 'c4' }, + { value: 35, label: 'd4' }, + { value: 36, label: 'e4' }, + { value: 37, label: 'f4' }, + { value: 38, label: 'g4' }, + { value: 39, label: 'h4' }, + { value: 40, label: 'a3' }, + { value: 41, label: 'b3' }, + { value: 42, label: 'c3' }, + { value: 43, label: 'd3' }, + { value: 44, label: 'e3' }, + { value: 45, label: 'f3' }, + { value: 46, label: 'g3' }, + { value: 47, label: 'h3' }, + { value: 48, label: 'a2' }, + { value: 49, label: 'b2' }, + { value: 50, label: 'c2' }, + { value: 51, label: 'd2' }, + { value: 52, label: 'e2' }, + { value: 53, label: 'f2' }, + { value: 54, label: 'g2' }, + { value: 55, label: 'h2' }, + { value: 56, label: 'a1' }, + { value: 57, label: 'b1' }, + { value: 58, label: 'c1' }, + { value: 59, label: 'd1' }, + { value: 60, label: 'e1' }, + { value: 61, label: 'f1' }, + { value: 62, label: 'g1' }, + { value: 63, label: 'h1' } + ]; + + function handleSquareClick(square) { + $$invalidate(1, selectedSquare = square); + } + + function addTextToSquare() { + if (selectedSquare !== null && textInput.trim() !== '') { + $$invalidate(5, squareText[selectedSquare] = textInput, squareText); + $$invalidate(6, textInput = ''); + $$invalidate(1, selectedSquare = null); + } + } + + function loadStartingPosition() { + chess.reset(); + $$invalidate(0, board = chess.board()); + $$invalidate(1, selectedSquare = null); + moves = []; + currentMoveIndex = 0; + $$invalidate(5, squareText = {}); // Clear all square text + } + + function loadNotation(notation) { + chess.reset(); + moves = notation.split(/\d+\.\s*/).filter(Boolean).flatMap(movePair => movePair.trim().split(/\s+/)); + currentMoveIndex = 0; + $$invalidate(0, board = chess.board()); + } + + function nextMove() { + if (currentMoveIndex < moves.length) { + chess.move(moves[currentMoveIndex]); + $$invalidate(0, board = chess.board()); + currentMoveIndex++; + } + } + + function handleFileUpload(event) { + const file = event.target.files[0]; + + if (file) { + const reader = new FileReader(); + + reader.onload = function (e) { + pgnContent = e.target.result; + parsePgn(pgnContent); + }; + + reader.readAsText(file); + } + } + + function parsePgn(content) { + const gameSections = content.split(/\r?\n\r?\n(?=\[Event)/); + + $$invalidate(2, games = gameSections.map(section => { + const metadata = {}; + const moves = []; + const lines = section.split(/\r?\n/); + + lines.forEach(line => { + if (line.startsWith('[')) { + const match = line.match(/\[(\w+)\s+"(.+)"\]/); + + if (match) { + metadata[match[1]] = match[2]; + } + } else if (line.trim()) { + moves.push(line.trim()); + } + }); + + return { metadata, moves }; + })); + } + + function loadSelectedGame() { + if (selectedGameIndex >= 0) { + const selectedGame = games[selectedGameIndex]; + loadNotation(selectedGame.moves.join(' ')); + $$invalidate(4, previewText = selectedGame.moves.join(' ').slice(0, 2000)); + } + } + + function copyToClipboard() { + navigator.clipboard.writeText(previewText).then(() => { + alert('Text copied to clipboard!'); + }); + } + + function handleTextareaInput(event) { + const text = event.target.value; + loadNotation(text); + } + + function loadFromText() { + loadNotation(document.getElementById('notationTextarea').value); + } + + function savePosition() { + const positionData = { fen: chess.fen(), squareText }; + $$invalidate(7, saveData = JSON.stringify(positionData)); + } + + function loadSavedPosition() { + if (saveData.trim() !== '') { + const positionData = JSON.parse(saveData); + chess.load(positionData.fen); + $$invalidate(0, board = chess.board()); + $$invalidate(5, squareText = positionData.squareText); + } + } + + onMount(() => { + loadStartingPosition(); + }); + + const writable_props = []; + + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); + + const click_handler = (rowIndex, colIndex) => handleSquareClick(rowIndex * 8 + colIndex); + + const change_handler = e => { + $$invalidate(3, selectedGameIndex = e.target.value); + }; + + function select_change_handler() { + selectedSquare = select_value(this); + $$invalidate(1, selectedSquare); + $$invalidate(8, squareOptions); + } + + function input1_input_handler() { + textInput = this.value; + $$invalidate(6, textInput); + } + + function textarea1_input_handler() { + saveData = this.value; + $$invalidate(7, saveData); + } + + $$self.$capture_state = () => ({ + Chess, + onMount, + chess, + board, + selectedSquare, + moves, + currentMoveIndex, + pgnContent, + games, + selectedGameIndex, + previewText, + squareText, + textInput, + saveData, + squareOptions, + getSquareColor, + handleSquareClick, + addTextToSquare, + loadStartingPosition, + loadNotation, + nextMove, + handleFileUpload, + parsePgn, + loadSelectedGame, + copyToClipboard, + getPieceImage, + handleTextareaInput, + loadFromText, + savePosition, + loadSavedPosition + }); + + $$self.$inject_state = $$props => { + if ('chess' in $$props) chess = $$props.chess; + if ('board' in $$props) $$invalidate(0, board = $$props.board); + if ('selectedSquare' in $$props) $$invalidate(1, selectedSquare = $$props.selectedSquare); + if ('moves' in $$props) moves = $$props.moves; + if ('currentMoveIndex' in $$props) currentMoveIndex = $$props.currentMoveIndex; + if ('pgnContent' in $$props) pgnContent = $$props.pgnContent; + if ('games' in $$props) $$invalidate(2, games = $$props.games); + if ('selectedGameIndex' in $$props) $$invalidate(3, selectedGameIndex = $$props.selectedGameIndex); + if ('previewText' in $$props) $$invalidate(4, previewText = $$props.previewText); + if ('squareText' in $$props) $$invalidate(5, squareText = $$props.squareText); + if ('textInput' in $$props) $$invalidate(6, textInput = $$props.textInput); + if ('saveData' in $$props) $$invalidate(7, saveData = $$props.saveData); + if ('squareOptions' in $$props) $$invalidate(8, squareOptions = $$props.squareOptions); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + board, + selectedSquare, + games, + selectedGameIndex, + previewText, + squareText, + textInput, + saveData, + squareOptions, + handleSquareClick, + addTextToSquare, + loadStartingPosition, + nextMove, + handleFileUpload, + loadSelectedGame, + copyToClipboard, + handleTextareaInput, + loadFromText, + savePosition, + loadSavedPosition, + click_handler, + change_handler, + select_change_handler, + input1_input_handler, + textarea1_input_handler + ]; + } + + class ChessStudyTool extends SvelteComponentDev { + constructor(options) { + super(options); + init(this, options, instance$3, create_fragment$3, safe_not_equal, {}, null, [-1, -1]); + + dispatch_dev("SvelteRegisterComponent", { + component: this, + tagName: "ChessStudyTool", + options, + id: create_fragment$3.name + }); + } + } + + /*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */ + function isNothing(subject) { + return (typeof subject === 'undefined') || (subject === null); + } + + + function isObject(subject) { + return (typeof subject === 'object') && (subject !== null); + } + + + function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; + else if (isNothing(sequence)) return []; + + return [ sequence ]; + } + + + function extend(target, source) { + var index, length, key, sourceKeys; + + if (source) { + sourceKeys = Object.keys(source); + + for (index = 0, length = sourceKeys.length; index < length; index += 1) { + key = sourceKeys[index]; + target[key] = source[key]; + } + } + + return target; + } + + + function repeat(string, count) { + var result = '', cycle; + + for (cycle = 0; cycle < count; cycle += 1) { + result += string; + } + + return result; + } + + + function isNegativeZero(number) { + return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number); + } + + + var isNothing_1 = isNothing; + var isObject_1 = isObject; + var toArray_1 = toArray; + var repeat_1 = repeat; + var isNegativeZero_1 = isNegativeZero; + var extend_1 = extend; + + var common = { + isNothing: isNothing_1, + isObject: isObject_1, + toArray: toArray_1, + repeat: repeat_1, + isNegativeZero: isNegativeZero_1, + extend: extend_1 + }; + + // YAML error class. http://stackoverflow.com/questions/8458984 + + + function formatError(exception, compact) { + var where = '', message = exception.reason || '(unknown reason)'; + + if (!exception.mark) return message; + + if (exception.mark.name) { + where += 'in "' + exception.mark.name + '" '; + } + + where += '(' + (exception.mark.line + 1) + ':' + (exception.mark.column + 1) + ')'; + + if (!compact && exception.mark.snippet) { + where += '\n\n' + exception.mark.snippet; + } + + return message + ' ' + where; + } + + + function YAMLException$1(reason, mark) { + // Super constructor + Error.call(this); + + this.name = 'YAMLException'; + this.reason = reason; + this.mark = mark; + this.message = formatError(this, false); + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor); + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || ''; + } + } + + + // Inherit from Error + YAMLException$1.prototype = Object.create(Error.prototype); + YAMLException$1.prototype.constructor = YAMLException$1; + + + YAMLException$1.prototype.toString = function toString(compact) { + return this.name + ': ' + formatError(this, compact); + }; + + + var exception = YAMLException$1; + + // get snippet for a single line, respecting maxLength + function getLine(buffer, lineStart, lineEnd, position, maxLineLength) { + var head = ''; + var tail = ''; + var maxHalfLength = Math.floor(maxLineLength / 2) - 1; + + if (position - lineStart > maxHalfLength) { + head = ' ... '; + lineStart = position - maxHalfLength + head.length; + } + + if (lineEnd - position > maxHalfLength) { + tail = ' ...'; + lineEnd = position + maxHalfLength - tail.length; + } + + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, '→') + tail, + pos: position - lineStart + head.length // relative position + }; + } + + + function padStart(string, max) { + return common.repeat(' ', max - string.length) + string; + } + + + function makeSnippet(mark, options) { + options = Object.create(options || null); + + if (!mark.buffer) return null; + + if (!options.maxLength) options.maxLength = 79; + if (typeof options.indent !== 'number') options.indent = 1; + if (typeof options.linesBefore !== 'number') options.linesBefore = 3; + if (typeof options.linesAfter !== 'number') options.linesAfter = 2; + + var re = /\r?\n|\r|\0/g; + var lineStarts = [ 0 ]; + var lineEnds = []; + var match; + var foundLineNo = -1; + + while ((match = re.exec(mark.buffer))) { + lineEnds.push(match.index); + lineStarts.push(match.index + match[0].length); + + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2; + } + } + + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1; + + var result = '', i, line; + var lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length; + var maxLineLength = options.maxLength - (options.indent + lineNoLength + 3); + + for (i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo - i], + lineEnds[foundLineNo - i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), + maxLineLength + ); + result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + result; + } + + line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength); + result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\n'; + + for (i = 1; i <= options.linesAfter; i++) { + if (foundLineNo + i >= lineEnds.length) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo + i], + lineEnds[foundLineNo + i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]), + maxLineLength + ); + result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + } + + return result.replace(/\n$/, ''); + } + + + var snippet = makeSnippet; + + var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'multi', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'representName', + 'defaultStyle', + 'styleAliases' + ]; + + var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' + ]; - if (!mounted) { - dispose = [ - listen_dev(input0, "change", /*YTIDhandleFileImport*/ ctx[39], false, false, false, false), - listen_dev(button0, "click", /*YTIDaddItems*/ ctx[36], false, false, false, false), - listen_dev(button1, "click", /*YTIDdownloadList*/ ctx[38], false, false, false, false), - listen_dev(textarea0, "input", /*textarea0_input_handler*/ ctx[42]), - listen_dev(input1, "input", /*input1_input_handler*/ ctx[44]), - listen_dev(input2, "change", /*input2_change_handler*/ ctx[45]), - listen_dev(input2, "click", /*toggleUpdate*/ ctx[25], false, false, false, false), - listen_dev(textarea1, "input", /*textarea1_input_handler*/ ctx[46]), - listen_dev(button2, "click", /*transcriptToJson*/ ctx[35], false, false, false, false), - listen_dev(input3, "change", /*loadnotesegmentstofile*/ ctx[41], false, false, false, false), - listen_dev(button3, "click", /*createNoteSegments*/ ctx[24], false, false, false, false), - listen_dev(button4, "click", /*savenoteSegmentstofile*/ ctx[40], false, false, false, false), - listen_dev(textarea2, "input", /*textarea2_input_handler*/ ctx[47]), - listen_dev(button5, "click", /*goToPreviousAutoTimestamp*/ ctx[27], false, false, false, false), - listen_dev(button6, "click", /*goToNextAutoTimestamp*/ ctx[26], false, false, false, false), - listen_dev(button7, "click", /*addUserTimestamp*/ ctx[28], false, false, false, false), - listen_dev(button8, "click", /*goToCurrentUserTimestamp*/ ctx[29], false, false, false, false), - listen_dev(button9, "click", /*goToPreviousUserTimestamp*/ ctx[31], false, false, false, false), - listen_dev(button10, "click", /*goToNextUserTimestamp*/ ctx[30], false, false, false, false), - listen_dev(button11, "click", /*exportTimestamps*/ ctx[32], false, false, false, false), - listen_dev(button12, "click", /*exportr2Timestamps*/ ctx[33], false, false, false, false), - listen_dev(input4, "change", /*importTimestamps*/ ctx[34], false, false, false, false), - listen_dev(input5, "change", /*input5_change_handler*/ ctx[48]), - listen_dev(input6, "input", /*input6_input_handler*/ ctx[49]), - listen_dev(input7, "input", /*input7_input_handler*/ ctx[50]), - listen_dev(input8, "input", /*input8_input_handler*/ ctx[51]) - ]; + function compileStyleAliases(map) { + var result = {}; - mounted = true; - } - }, - p: function update(ctx, dirty) { - if (dirty[0] & /*$ytsubcurrenttext*/ 4194304) set_data_dev(t8, /*$ytsubcurrenttext*/ ctx[22]); + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } - if (dirty[0] & /*YTIDinput*/ 131072) { - set_input_value(textarea0, /*YTIDinput*/ ctx[17]); - } + return result; + } - if (dirty[0] & /*YTIDitems*/ 65536 | dirty[1] & /*YTIDupdateItem*/ 64) { - each_value = /*YTIDitems*/ ctx[16]; - validate_each_argument(each_value); - let i; + function Type$1(tag, options) { + options = options || {}; - for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$7(ctx, each_value, i); + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new exception('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.options = options; // keep original options in case user wants to extend this type later + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.representName = options['representName'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.multi = options['multi'] || false; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new exception('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } + } - if (each_blocks[i]) { - each_blocks[i].p(child_ctx, dirty); - } else { - each_blocks[i] = create_each_block$7(child_ctx); - each_blocks[i].c(); - each_blocks[i].m(div0, null); - } - } + var type = Type$1; - for (; i < each_blocks.length; i += 1) { - each_blocks[i].d(1); - } + /*eslint-disable max-len*/ - each_blocks.length = each_value.length; - } - if (dirty[0] & /*$ytsubcurrentID*/ 8 && input1.value !== /*$ytsubcurrentID*/ ctx[3]) { - set_input_value(input1, /*$ytsubcurrentID*/ ctx[3]); - } - if (dirty[0] & /*isUpdating*/ 512) { - input2.checked = /*isUpdating*/ ctx[9]; - } - if (dirty[0] & /*transcript*/ 32) { - set_input_value(textarea1, /*transcript*/ ctx[5]); - } - if (dirty[0] & /*jsonOutput*/ 64) set_data_dev(t25, /*jsonOutput*/ ctx[6]); - if (dirty[0] & /*currentTime*/ 16 && t29_value !== (t29_value = /*currentTime*/ ctx[4].toFixed(2) + "")) set_data_dev(t29, t29_value); - if (dirty[0] & /*line*/ 256) set_data_dev(t32, /*line*/ ctx[8]); - if (dirty[0] & /*currentWord*/ 128) set_data_dev(t35, /*currentWord*/ ctx[7]); - if (dirty[0] & /*$ytsubcurrenttext*/ 4194304) set_data_dev(t39, /*$ytsubcurrenttext*/ ctx[22]); - if (dirty[0] & /*currentIndex*/ 1024) set_data_dev(t48, /*currentIndex*/ ctx[10]); + function compileList(schema, name) { + var result = []; - if (dirty[0] & /*notesegments, currentIndex*/ 263168) { - set_input_value(textarea2, /*notesegments*/ ctx[18][/*currentIndex*/ ctx[10]]['notes']); - } + schema[name].forEach(function (currentType) { + var newIndex = result.length; - if (dirty[0] & /*currentIndex*/ 1024) set_data_dev(t61, /*currentIndex*/ ctx[10]); - if (dirty[0] & /*timestamps*/ 2048 && t63_value !== (t63_value = /*timestamps*/ ctx[11].length + "")) set_data_dev(t63, t63_value); + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && + previousType.kind === currentType.kind && + previousType.multi === currentType.multi) { - if (dirty[0] & /*currentindexButtonClass*/ 524288 && button8_class_value !== (button8_class_value = "" + (null_to_empty(/*currentindexButtonClass*/ ctx[19]) + " svelte-udvqea"))) { - attr_dev(button8, "class", button8_class_value); - } + newIndex = previousIndex; + } + }); - if (dirty[0] & /*currentuserIndex*/ 1 && button8_disabled_value !== (button8_disabled_value = /*currentuserIndex*/ ctx[0] <= 0)) { - prop_dev(button8, "disabled", button8_disabled_value); - } + result[newIndex] = currentType; + }); - if (dirty[0] & /*previousindexButtonClass*/ 1048576 && button9_class_value !== (button9_class_value = "" + (null_to_empty(/*previousindexButtonClass*/ ctx[20]) + " svelte-udvqea"))) { - attr_dev(button9, "class", button9_class_value); - } + return result; + } - if (dirty[0] & /*currentuserIndex*/ 1 && button9_disabled_value !== (button9_disabled_value = /*currentuserIndex*/ ctx[0] <= 0)) { - prop_dev(button9, "disabled", button9_disabled_value); - } - if (dirty[0] & /*nextindexButtonClass*/ 2097152 && button10_class_value !== (button10_class_value = "" + (null_to_empty(/*nextindexButtonClass*/ ctx[21]) + " svelte-udvqea"))) { - attr_dev(button10, "class", button10_class_value); - } + function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + }, index, length; + + function collectType(type) { + if (type.multi) { + result.multi[type.kind].push(type); + result.multi['fallback'].push(type); + } else { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + } - if (dirty[0] & /*currentuserIndex, userTimestamps*/ 3 && button10_disabled_value !== (button10_disabled_value = /*currentuserIndex*/ ctx[0] >= /*userTimestamps*/ ctx[1].length - 1)) { - prop_dev(button10, "disabled", button10_disabled_value); - } + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; + } - if (dirty[0] & /*currentuserIndex*/ 1) set_data_dev(t74, /*currentuserIndex*/ ctx[0]); - if (dirty[0] & /*userTimestamps*/ 2 && t76_value !== (t76_value = /*userTimestamps*/ ctx[1].length + "")) set_data_dev(t76, t76_value); - if (dirty[0] & /*currentuserIndex*/ 1) set_data_dev(t79, /*currentuserIndex*/ ctx[0]); - if (dirty[0] & /*r2userTimestamps*/ 4096 && t81_value !== (t81_value = /*r2userTimestamps*/ ctx[12].length + "")) set_data_dev(t81, t81_value); - if (dirty[0] & /*isRepeating*/ 4) { - input5.checked = /*isRepeating*/ ctx[2]; - } + function Schema$1(definition) { + return this.extend(definition); + } - if (dirty[0] & /*repstartTime*/ 8192 && to_number(input6.value) !== /*repstartTime*/ ctx[13]) { - set_input_value(input6, /*repstartTime*/ ctx[13]); - } - if (dirty[0] & /*rependTime*/ 16384 && to_number(input7.value) !== /*rependTime*/ ctx[14]) { - set_input_value(input7, /*rependTime*/ ctx[14]); - } + Schema$1.prototype.extend = function extend(definition) { + var implicit = []; + var explicit = []; - if (dirty[0] & /*repetitions*/ 32768 && to_number(input8.value) !== /*repetitions*/ ctx[15]) { - set_input_value(input8, /*repetitions*/ ctx[15]); - } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(h10); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(h20); - if (detaching) detach_dev(t3); - if (detaching) detach_dev(h3); - if (detaching) detach_dev(t6); - if (detaching) detach_dev(h11); - if (detaching) detach_dev(t9); - if (detaching) detach_dev(div1); - destroy_each(each_blocks, detaching); - if (detaching) detach_dev(t19); - if (detaching) detach_dev(div2); - if (detaching) detach_dev(t26); - if (detaching) detach_dev(div7); - if (detaching) detach_dev(t40); - if (detaching) detach_dev(div8); - if (detaching) detach_dev(t52); - if (detaching) detach_dev(button5); - if (detaching) detach_dev(t56); - if (detaching) detach_dev(button6); - if (detaching) detach_dev(t60); - if (detaching) detach_dev(t61); - if (detaching) detach_dev(t62); - if (detaching) detach_dev(t63); - if (detaching) detach_dev(t64); - if (detaching) detach_dev(br6); - if (detaching) detach_dev(t65); - if (detaching) detach_dev(button7); - if (detaching) detach_dev(t67); - if (detaching) detach_dev(button8); - if (detaching) detach_dev(t69); - if (detaching) detach_dev(button9); - if (detaching) detach_dev(t71); - if (detaching) detach_dev(button10); - if (detaching) detach_dev(t73); - if (detaching) detach_dev(t74); - if (detaching) detach_dev(t75); - if (detaching) detach_dev(t76); - if (detaching) detach_dev(t77); - if (detaching) detach_dev(br7); - if (detaching) detach_dev(t78); - if (detaching) detach_dev(t79); - if (detaching) detach_dev(t80); - if (detaching) detach_dev(t81); - if (detaching) detach_dev(t82); - if (detaching) detach_dev(br8); - if (detaching) detach_dev(t83); - if (detaching) detach_dev(br9); - if (detaching) detach_dev(t84); - if (detaching) detach_dev(button11); - if (detaching) detach_dev(t86); - if (detaching) detach_dev(button12); - if (detaching) detach_dev(t88); - if (detaching) detach_dev(input4); - if (detaching) detach_dev(t89); - if (detaching) detach_dev(br10); - if (detaching) detach_dev(t90); - if (detaching) detach_dev(input5); - if (detaching) detach_dev(t91); - if (detaching) detach_dev(input6); - if (detaching) detach_dev(t92); - if (detaching) detach_dev(input7); - if (detaching) detach_dev(t93); - if (detaching) detach_dev(input8); - if (detaching) detach_dev(t94); - if (detaching) detach_dev(div9); - if (detaching) detach_dev(t98); - if (detaching) detach_dev(hr); - if (detaching) detach_dev(t99); - if (detaching) detach_dev(div10); - mounted = false; - run_all(dispose); - } - }; + if (definition instanceof type) { + // Schema.extend(type) + explicit.push(definition); - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$a.name, - type: "component", - source: "", - ctx - }); + } else if (Array.isArray(definition)) { + // Schema.extend([ type1, type2, ... ]) + explicit = explicit.concat(definition); - return block; + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] }) + if (definition.implicit) implicit = implicit.concat(definition.implicit); + if (definition.explicit) explicit = explicit.concat(definition.explicit); + + } else { + throw new exception('Schema.extend argument should be a Type, [ Type ], ' + + 'or a schema definition ({ implicit: [...], explicit: [...] })'); + } + + implicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + if (type$1.loadKind && type$1.loadKind !== 'scalar') { + throw new exception('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + + if (type$1.multi) { + throw new exception('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.'); + } + }); + + explicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + }); + + var result = Object.create(Schema$1.prototype); + + result.implicit = (this.implicit || []).concat(implicit); + result.explicit = (this.explicit || []).concat(explicit); + + result.compiledImplicit = compileList(result, 'implicit'); + result.compiledExplicit = compileList(result, 'explicit'); + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit); + + return result; + }; + + + var schema = Schema$1; + + var str = new type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } + }); + + var seq = new type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } + }); + + var map = new type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } + }); + + var failsafe = new schema({ + explicit: [ + str, + seq, + map + ] + }); + + function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); } - function getRandomWord(line) { - let words = line.split(" "); - return words[Math.floor(Math.random() * words.length)]; + function constructYamlNull() { + return null; } - function instance$a($$self, $$props, $$invalidate) { - let nextindexButtonClass; - let previousindexButtonClass; - let currentindexButtonClass; - let $ytsubcurrentID; - let $ytsubcurrenttext; - validate_store(ytsubcurrentID, 'ytsubcurrentID'); - component_subscribe($$self, ytsubcurrentID, $$value => $$invalidate(3, $ytsubcurrentID = $$value)); - validate_store(ytsubcurrenttext, 'ytsubcurrenttext'); - component_subscribe($$self, ytsubcurrenttext, $$value => $$invalidate(22, $ytsubcurrenttext = $$value)); - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('YoutubeIframeAPICustomInterface', slots, []); - let player; - let interval = 20; // Define your interval - let currentTime = 0; - let timeUpdateInterval; + function isNull(object) { + return object === null; + } - // Assuming 'transcript' contains your video transcript - let transcript = `Line 1 of the transcript. - Line 2 of the transcript. - Line 3 food - Line 4 foodest - Line 5 foods - Line 6 fooder - Line 7 foodz - Line 8 fooding - ...`; // Replace with your actual transcript + var _null = new type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; }, + empty: function () { return ''; } + }, + defaultStyle: 'lowercase' + }); - let jsonOutput = ''; - let lines = transcript.split("\n"); - let currentWord = ""; - let line = ""; - let isUpdating = false; - let updateInterval; - let currentIndex = 0; // Assuming this is initialized appropriately - let currentuserIndex = 0; // Assuming this is initialized appropriately - let timestamps = []; // Array of timestamps - let userTimestamps = []; // Array of user timestamps - let r2userTimestamps = []; // Array of user timestamps + function resolveYamlBoolean(data) { + if (data === null) return false; - //let currentvideoId = 'IVJkOHTBPn0'; - let youTubeApiLoaded = false; + var max = data.length; - let currentvideoduration; - let regeneratedautotimestamps = false; - let repstartTime = 10; - let rependTime = 20; - let repetitions = 20; - let intervalId; - let isRepeating = false; - let YTIDitems = ['mwO6v4BlgZQ', 'IVJkOHTBPn0']; - let YTIDinput = ''; - let skipIntervals = []; - let intervalstartTime = 0; - let intervalendTime = 0; + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); + } - let notesegments = [ - { start: 0, end: 20, notes: 'Test' }, - { start: 21, end: 40, notes: 'For if' }, - { - start: 41, - end: 60, - notes: 'Correct text loads (Inititalise)' - } - ]; + function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; + } - window.onYouTubeIframeAPIReady = function () { - youTubeApiLoaded = true; - initYouTubePlayer(); - }; + function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; + } - // Function to initialize the YouTube player - function initYouTubePlayer() { - if (!youTubeApiLoaded) { - console.error("YouTube API is not ready yet."); - return; - } + var bool = new type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' + }); - regeneratedautotimestamps = false; + function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); + } - // Clear existing interval - clearInterval(timeUpdateInterval); + function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); + } - // Reinitialize player with new video ID - if (player) { - player.loadVideoById($ytsubcurrentID); - } else { - player = new YT.Player('youtube-player', - { - height: '360', - width: '640', - videoId: $ytsubcurrentID, - events: { - 'onReady': onPlayerReady, - 'onStateChange': onPlayerStateChange - } - }); - } + function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); + } - // Reset and start the interval to update current time - timeUpdateInterval = setInterval(updateCurrentTime, 1000); - } + function resolveYamlInteger(data) { + if (data === null) return false; - onMount(() => { - // Load the YouTube IFrame Player API - const tag = document.createElement('script'); + var max = data.length, + index = 0, + hasDigits = false, + ch; - tag.src = "https://www.youtube.com/iframe_api"; - const firstScriptTag = document.getElementsByTagName('script')[0]; - firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + if (!max) return false; - // Update the current time every second - timeUpdateInterval = setInterval(updateCurrentTime, 1000); - }); + ch = data[index]; - function autogeneratedtimestamps() { - currentvideoduration = player.getDuration(); + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } - //console.log("Video Duration: ", currentvideoduration); - const generatedTimestamps = []; + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; - for (let i = interval; i < currentvideoduration; i += interval) { - generatedTimestamps.push(i); - } + // base 2, base 8, base 16 - $$invalidate(11, timestamps = generatedTimestamps); + if (ch === 'b') { + // base 2 + index++; - // Do something with the timestamps - //console.log("Generated Timestamps: ", generatedTimestamps); - regeneratedautotimestamps = true; - } + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } - function createNoteSegments() { - // console.log("Video duration: " + currentvideoduration); - // console.log("Timestamps: " + timestamps); - $$invalidate(18, notesegments = []); // Clear existing segments - let start = 0; + if (ch === 'x') { + // base 16 + index++; - timestamps.forEach((end, index) => { - if (index === 0) { - notesegments.push({ start: 0, end, notes: "" }); - } else { - start = timestamps[index - 1] + 1; - notesegments.push({ start, end, notes: "" }); - } - }); + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } - // Add a final segment if the last timestamp is less than the video duration - if (timestamps[timestamps.length - 1] < currentvideoduration) { - notesegments.push({ - start: timestamps[timestamps.length - 1] + 1, - end: currentvideoduration, - notes: "" - }); - } - } - // Event handler for when the player is ready - function onPlayerReady(event) { - autogeneratedtimestamps(); - createNoteSegments(); - } + if (ch === 'o') { + // base 8 + index++; - function onPlayerStateChange(event) { - if (event.data === YT.PlayerState.PLAYING || event.data === YT.PlayerState.PAUSED) { - updateCurrentIndex(); - } + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + } - // Check if the video has just started playing - if (event.data === YT.PlayerState.PLAYING && !regeneratedautotimestamps) { - autogeneratedtimestamps(); - createNoteSegments(); - } - } + // base 10 (except 0) - function updateCurrentIndex() { - const currentTime = player.getCurrentTime(); + // value should not start with `_`; + if (ch === '_') return false; - // Find the closest timestamp - let closest = timestamps.reduce((prev, curr) => Math.abs(curr - currentTime) < Math.abs(prev - currentTime) - ? curr - : prev); + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } - $$invalidate(10, currentIndex = timestamps.indexOf(closest)); - } + // Should have digits and should not end with `_` + if (!hasDigits || ch === '_') return false; - function updateCurrentTime() { - if (player && player.getCurrentTime) { - $$invalidate(4, currentTime = player.getCurrentTime()); - } - } + return true; + } - onDestroy(() => { - clearInterval(timeUpdateInterval); - }); + function constructYamlInteger(data) { + var value = data, sign = 1, ch; - function updateWord() { - if (isUpdating) { - $$invalidate(8, line = lines[Math.floor(Math.random() * lines.length)]); - $$invalidate(7, currentWord = getRandomWord(line)); - } - } + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } - function toggleUpdate() { - lines = transcript.split("\n"); - $$invalidate(9, isUpdating = !isUpdating); + ch = value[0]; - if (isUpdating) { - updateWord(); // Immediately update once - updateInterval = setInterval(updateWord, 3000); // Update every 3 seconds - } else { - clearInterval(updateInterval); - $$invalidate(8, line = ''); - $$invalidate(7, currentWord = ''); - } - } + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } - function goToNextAutoTimestamp() { - if (currentIndex < timestamps.length - 1) { - $$invalidate(10, currentIndex += 1); - player.seekTo(timestamps[currentIndex], true); - } - } + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value.slice(2), 16); + if (value[1] === 'o') return sign * parseInt(value.slice(2), 8); + } + + return sign * parseInt(value, 10); + } + + function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); + } + + var int = new type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); }, + octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1); }, + decimal: function (obj) { return obj.toString(10); }, + /* eslint-disable max-len */ + hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } + }); + + var YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + '^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + + // .2e4, .2 + // special case, seems not from spec + '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + + // .inf + '|[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$'); + + function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data) || + // Quick hack to not allow integers end with `_` + // Probably should update regexp & check speed + data[data.length - 1] === '_') { + return false; + } + + return true; + } + + function constructYamlFloat(data) { + var value, sign; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + } + return sign * parseFloat(value, 10); + } + + + var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + + function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; + } + + function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); + } + + var float = new type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' + }); + + var json = failsafe.extend({ + implicit: [ + _null, + bool, + int, + float + ] + }); + + var core = json; + + var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + + var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + + function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; + } + + function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; + } + + function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); + } + + var timestamp = new type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp + }); + + function resolveYamlMerge(data) { + return data === '<<' || data === null; + } - function goToPreviousAutoTimestamp() { - if (currentIndex > 0) { - $$invalidate(10, currentIndex -= 1); - player.seekTo(timestamps[currentIndex], true); - } - } + var merge = new type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge + }); - function addUserTimestamp() { - const currentTime = Math.floor(player.getCurrentTime()); - $$invalidate(1, userTimestamps = [...userTimestamps, currentTime].sort((a, b) => a - b)); - } + /*eslint-disable no-bitwise*/ - function addr2UserTimestamp() { - const currentTime = Math.floor(player.getCurrentTime()); - $$invalidate(12, r2userTimestamps = [...r2userTimestamps, currentTime].sort((a, b) => a - b)); - } - function goToCurrentUserTimestamp() { - if (currentuserIndex === 0 && currentIndex < 0) { - player.seekTo(userTimestamps[currentIndex], true); - } else if (currentuserIndex < 0) { - player.seekTo(userTimestamps[currentuserIndex], true); - } else { - // Handle the end of the list here - console.log("No selected user timestamp."); - } // You can also disable the "next" button or loop to the start if needed. - } - function goToNextUserTimestamp() { - if (currentuserIndex < userTimestamps.length - 1) { - $$invalidate(0, currentuserIndex += 1); - player.seekTo(userTimestamps[currentuserIndex], true); - } else { - // Handle the end of the list here - console.log("Reached the end of user timestamps."); - } // You can also disable the "next" button or loop to the start if needed. - } - function goToPreviousUserTimestamp() { - if (currentuserIndex > 0) { - $$invalidate(0, currentuserIndex -= 1); - player.seekTo(userTimestamps[currentuserIndex], true); - } else { - // Handle the beginning of the list here - console.log("Reached the start of user timestamps."); - } // You can also disable the "previous" button or loop to the end if needed. - } - function exportTimestamps() { - const data = JSON.stringify({ - $ytsubcurrentID, - timestamps: userTimestamps - }); + // [ 64, 65, 66 ] -> [ padding, CR, LF ] + var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; - const blob = new Blob([data], { type: 'application/json' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.style.display = 'none'; - const filename = `${$ytsubcurrentID}_timestamps.json`; - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - window.URL.revokeObjectURL(url); - } - function exportr2Timestamps() { - const data = JSON.stringify({ - $ytsubcurrentID, - timestamps: r2userTimestamps - }); + function resolveYamlBinary(data) { + if (data === null) return false; - const blob = new Blob([data], { type: 'application/json' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.style.display = 'none'; - const filename = `${$ytsubcurrentID}_round2timestamps.json`; - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - window.URL.revokeObjectURL(url); - } + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; - function importTimestamps(event) { - // Check if the file input is not empty - const file = event.target.files[0]; + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); - if (!event.target.files || event.target.files.length === 0) { - alert('No file selected.'); - return; - } + // Skip CR/LF + if (code > 64) continue; - // Check if the file is a Blob (File objects inherit from Blob) - if (!(file instanceof Blob)) { - alert('Selected item is not a file.'); - return; - } + // Fail on illegal characters + if (code < 0) return false; - const reader = new FileReader(); + bitlen += 6; + } - reader.onload = e => { - try { - const data = JSON.parse(e.target.result); + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; + } - if (!Array.isArray(data.timestamps)) { - alert('Invalid file structure: timestamps should be an array.'); - return; - } + function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; - set_store_value(ytsubcurrentID, $ytsubcurrentID = data.$ytsubcurrentID || '', $ytsubcurrentID); - $$invalidate(1, userTimestamps = data.timestamps); - } catch(error) { - alert('An error occurred while importing timestamps.'); //regeneratedautotimestamps = false; = true - } - }; + // Collect by 6*4 bits (3 bytes) - reader.readAsText(file); - } + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } - function transcriptToJson() { - const lines = transcript.split('\n').filter(line => line.trim() !== ''); - const result = []; + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } - for (let i = 0; i < lines.length; i += 2) { - const timestampLine = lines[i]; - const textLine = lines[i + 1] || ''; // Ensure there's a line for text - const timestampParts = timestampLine.split(' '); - const timestamp = timestampParts.shift(); - const timeParts = timestamp.split(':'); - const seconds = parseInt(timeParts[0], 10) * 60 + parseInt(timeParts[1], 10); - result.push({ time: seconds, text: textLine.trim() }); - } + // Dump tail - $$invalidate(6, jsonOutput = JSON.stringify(result, null, 2)); - } + tailbits = (max % 4) * 6; - function startRepetition() { - let count = 0; - player.seekTo(repstartTime, true); - player.playVideo(); + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } - intervalId = setInterval( - () => { - if (count < repetitions) { - player.seekTo(repstartTime, true); - count++; - } else { - stopRepetition(); - } - }, - (rependTime - repstartTime) * 1000 - ); - } + return new Uint8Array(result); + } - function stopRepetition() { - clearInterval(intervalId); - } //player.pauseVideo(); + function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; - // Function to handle button click for adding items - function YTIDaddItems() { - const newItems = YTIDinput.split('\n').filter(item => item.trim() !== ''); - YTIDitems.push(...newItems); - $$invalidate(17, YTIDinput = ''); // Clear textarea after adding - $$invalidate(16, YTIDitems = YTIDitems.slice()); - } + // Convert every three bytes to 4 ASCII characters. - function YTIDupdateItem(index) { - $$invalidate(16, YTIDitems[index] = `${YTIDitems[index]}`, YTIDitems); //(updated)`; - set_store_value(ytsubcurrentID, $ytsubcurrentID = YTIDitems[index], $ytsubcurrentID); - $$invalidate(16, YTIDitems = YTIDitems.slice()); - } + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } - function YTIDdownloadList() { - const blob = new Blob([YTIDitems.join('\n')], { type: 'text/plain' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = 'YTIDlist.txt'; // Name of the file to be downloaded - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - } + bits = (bits << 8) + object[idx]; + } - function YTIDhandleFileImport(event) { - const file = event.target.files[0]; + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } - if (file) { - const reader = new FileReader(); + return result; + } - reader.onload = e => { - const fileContents = e.target.result; - $$invalidate(16, YTIDitems = fileContents.split('\n').filter(line => line.trim() !== '')); - }; + function isBinary(obj) { + return Object.prototype.toString.call(obj) === '[object Uint8Array]'; + } - reader.readAsText(file); - } - } + var binary = new type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary + }); - function checkSkipIntervals() { - const currentTime = player.getCurrentTime(); + var _hasOwnProperty$3 = Object.prototype.hasOwnProperty; + var _toString$2 = Object.prototype.toString; - for (const interval of skipIntervals) { - if (currentTime >= interval.start && currentTime < interval.end) { - player.seekTo(interval.end); - break; - } - } - } + function resolveYamlOmap(data) { + if (data === null) return true; - function addSkipInterval() { - skipIntervals.push({ - start: intervalstartTime, - end: intervalendTime - }); + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; - skipIntervals = skipIntervals; - intervalstartTime = 0; - intervalendTime = 0; - } + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; - function removeSkipInterval(index) { - skipIntervals.splice(index, 1); - skipIntervals = skipIntervals; - } + if (_toString$2.call(pair) !== '[object Object]') return false; - // function createnoteSegments() { - // console.log(currentvideoduration) - // console.log(timestamps) - // notesegments = []; // Clear existing segments - // for (let start = 0; start < currentvideoduration; start += timestamps) { - // let end = start + timestamps - 1; - // if (end > currentvideoduration) end = currentvideoduration; // Adjust last segment to not exceed video duration - // notesegments.push({ start: start, end: end, notes: "" }); - // } - // console.log(notesegments) - // } - // function createNoteSegments() { - // console.log("Video duration: " + currentvideoduration); - // console.log("Timestamps: " + timestamps); - // notesegments = []; // Clear existing segments - // let start = 0; - // timestamps.forEach((end, index) => { - // if (index === 0) { - // notesegments.push({ start: 0, end: end, notes: "" }); - // } else { - // start = timestamps[index - 1] + 1; - // notesegments.push({ start: start, end: end, notes: "" }); - // } - // }); - // // Add a final segment if the last timestamp is less than the video duration - // if (timestamps[timestamps.length - 1] < currentvideoduration) { - // notesegments.push({ - // start: timestamps[timestamps.length - 1] + 1, - // end: currentvideoduration, - // notes: "" - // }); - // } - // console.log(notesegments); - // } - function savenoteSegmentstofile() { - const dataStr = JSON.stringify(notesegments); - const blob = new Blob([dataStr], { type: "application/json" }); + for (pairKey in pair) { + if (_hasOwnProperty$3.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } - // Getting current date and time for filename - const now = new Date(); + if (!pairHasKey) return false; - const dateTimeStamp = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}-${now.getMinutes().toString().padStart(2, '0')}-${now.getSeconds().toString().padStart(2, '0')}`; - const filename = `noteSegments_${$ytsubcurrentID}_${dateTimeStamp}.json`; - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = filename; //"notesegments.json"; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(url); - } + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } - function loadnotesegmentstofile(event) { - const file = event.target.files[0]; + return true; + } - if (file) { - const reader = new FileReader(); + function constructYamlOmap(data) { + return data !== null ? data : []; + } - reader.onload = e => { - $$invalidate(18, notesegments = JSON.parse(e.target.result)); - console.log("Notes loaded:", notesegments); - }; + var omap = new type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap + }); - reader.readAsText(file); - } - } + var _toString$1 = Object.prototype.toString; - const writable_props = []; + function resolveYamlPairs(data) { + if (data === null) return true; - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$5.warn(` was created with unknown prop '${key}'`); - }); + var index, length, pair, keys, result, + object = data; - function textarea0_input_handler() { - YTIDinput = this.value; - $$invalidate(17, YTIDinput); - } + result = new Array(object.length); - const click_handler = index => YTIDupdateItem(index); + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; - function input1_input_handler() { - $ytsubcurrentID = this.value; - ytsubcurrentID.set($ytsubcurrentID); - } + if (_toString$1.call(pair) !== '[object Object]') return false; - function input2_change_handler() { - isUpdating = this.checked; - $$invalidate(9, isUpdating); - } + keys = Object.keys(pair); - function textarea1_input_handler() { - transcript = this.value; - $$invalidate(5, transcript); - } + if (keys.length !== 1) return false; - function textarea2_input_handler() { - notesegments[currentIndex]['notes'] = this.value; - $$invalidate(18, notesegments); - } + result[index] = [ keys[0], pair[keys[0]] ]; + } - function input5_change_handler() { - isRepeating = this.checked; - $$invalidate(2, isRepeating); - } + return true; + } - function input6_input_handler() { - repstartTime = to_number(this.value); - $$invalidate(13, repstartTime); - } + function constructYamlPairs(data) { + if (data === null) return []; - function input7_input_handler() { - rependTime = to_number(this.value); - $$invalidate(14, rependTime); - } + var index, length, pair, keys, result, + object = data; - function input8_input_handler() { - repetitions = to_number(this.value); - $$invalidate(15, repetitions); - } + result = new Array(object.length); - $$self.$capture_state = () => ({ - onMount, - onDestroy, - ytsubcurrenttext, - ytsubcurrentID, - ytsubuse, - ytsubuseplayer, - player, - interval, - currentTime, - timeUpdateInterval, - transcript, - jsonOutput, - lines, - currentWord, - line, - isUpdating, - updateInterval, - currentIndex, - currentuserIndex, - timestamps, - userTimestamps, - r2userTimestamps, - youTubeApiLoaded, - currentvideoduration, - regeneratedautotimestamps, - repstartTime, - rependTime, - repetitions, - intervalId, - isRepeating, - YTIDitems, - YTIDinput, - skipIntervals, - intervalstartTime, - intervalendTime, - notesegments, - initYouTubePlayer, - autogeneratedtimestamps, - createNoteSegments, - onPlayerReady, - onPlayerStateChange, - updateCurrentIndex, - updateCurrentTime, - getRandomWord, - updateWord, - toggleUpdate, - goToNextAutoTimestamp, - goToPreviousAutoTimestamp, - addUserTimestamp, - addr2UserTimestamp, - goToCurrentUserTimestamp, - goToNextUserTimestamp, - goToPreviousUserTimestamp, - exportTimestamps, - exportr2Timestamps, - importTimestamps, - transcriptToJson, - startRepetition, - stopRepetition, - YTIDaddItems, - YTIDupdateItem, - YTIDdownloadList, - YTIDhandleFileImport, - checkSkipIntervals, - addSkipInterval, - removeSkipInterval, - savenoteSegmentstofile, - loadnotesegmentstofile, - currentindexButtonClass, - previousindexButtonClass, - nextindexButtonClass, - $ytsubcurrentID, - $ytsubcurrenttext - }); + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; - $$self.$inject_state = $$props => { - if ('player' in $$props) player = $$props.player; - if ('interval' in $$props) $$invalidate(23, interval = $$props.interval); - if ('currentTime' in $$props) $$invalidate(4, currentTime = $$props.currentTime); - if ('timeUpdateInterval' in $$props) timeUpdateInterval = $$props.timeUpdateInterval; - if ('transcript' in $$props) $$invalidate(5, transcript = $$props.transcript); - if ('jsonOutput' in $$props) $$invalidate(6, jsonOutput = $$props.jsonOutput); - if ('lines' in $$props) lines = $$props.lines; - if ('currentWord' in $$props) $$invalidate(7, currentWord = $$props.currentWord); - if ('line' in $$props) $$invalidate(8, line = $$props.line); - if ('isUpdating' in $$props) $$invalidate(9, isUpdating = $$props.isUpdating); - if ('updateInterval' in $$props) updateInterval = $$props.updateInterval; - if ('currentIndex' in $$props) $$invalidate(10, currentIndex = $$props.currentIndex); - if ('currentuserIndex' in $$props) $$invalidate(0, currentuserIndex = $$props.currentuserIndex); - if ('timestamps' in $$props) $$invalidate(11, timestamps = $$props.timestamps); - if ('userTimestamps' in $$props) $$invalidate(1, userTimestamps = $$props.userTimestamps); - if ('r2userTimestamps' in $$props) $$invalidate(12, r2userTimestamps = $$props.r2userTimestamps); - if ('youTubeApiLoaded' in $$props) youTubeApiLoaded = $$props.youTubeApiLoaded; - if ('currentvideoduration' in $$props) currentvideoduration = $$props.currentvideoduration; - if ('regeneratedautotimestamps' in $$props) regeneratedautotimestamps = $$props.regeneratedautotimestamps; - if ('repstartTime' in $$props) $$invalidate(13, repstartTime = $$props.repstartTime); - if ('rependTime' in $$props) $$invalidate(14, rependTime = $$props.rependTime); - if ('repetitions' in $$props) $$invalidate(15, repetitions = $$props.repetitions); - if ('intervalId' in $$props) intervalId = $$props.intervalId; - if ('isRepeating' in $$props) $$invalidate(2, isRepeating = $$props.isRepeating); - if ('YTIDitems' in $$props) $$invalidate(16, YTIDitems = $$props.YTIDitems); - if ('YTIDinput' in $$props) $$invalidate(17, YTIDinput = $$props.YTIDinput); - if ('skipIntervals' in $$props) skipIntervals = $$props.skipIntervals; - if ('intervalstartTime' in $$props) intervalstartTime = $$props.intervalstartTime; - if ('intervalendTime' in $$props) intervalendTime = $$props.intervalendTime; - if ('notesegments' in $$props) $$invalidate(18, notesegments = $$props.notesegments); - if ('currentindexButtonClass' in $$props) $$invalidate(19, currentindexButtonClass = $$props.currentindexButtonClass); - if ('previousindexButtonClass' in $$props) $$invalidate(20, previousindexButtonClass = $$props.previousindexButtonClass); - if ('nextindexButtonClass' in $$props) $$invalidate(21, nextindexButtonClass = $$props.nextindexButtonClass); - }; + keys = Object.keys(pair); - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + result[index] = [ keys[0], pair[keys[0]] ]; + } - $$self.$$.update = () => { - if ($$self.$$.dirty[0] & /*$ytsubcurrentID*/ 8) { - if ($ytsubcurrentID) { - initYouTubePlayer(); - } - } + return result; + } - if ($$self.$$.dirty[0] & /*currentuserIndex, userTimestamps*/ 3) { - $$invalidate(21, nextindexButtonClass = currentuserIndex >= userTimestamps.length - 1 - ? 'button-at-end' - : 'button'); - } + var pairs = new type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs + }); - if ($$self.$$.dirty[0] & /*currentuserIndex*/ 1) { - $$invalidate(20, previousindexButtonClass = currentuserIndex <= 0 ? 'button-at-end' : 'button'); - } + var _hasOwnProperty$2 = Object.prototype.hasOwnProperty; - if ($$self.$$.dirty[0] & /*currentuserIndex*/ 1) { - $$invalidate(19, currentindexButtonClass = currentuserIndex <= 0 ? 'button-at-end' : 'button'); - } + function resolveYamlSet(data) { + if (data === null) return true; - if ($$self.$$.dirty[0] & /*isRepeating*/ 4) { - if (isRepeating) { - startRepetition(); - } else { - stopRepetition(); - } - } - }; + var key, object = data; - return [ - currentuserIndex, - userTimestamps, - isRepeating, - $ytsubcurrentID, - currentTime, - transcript, - jsonOutput, - currentWord, - line, - isUpdating, - currentIndex, - timestamps, - r2userTimestamps, - repstartTime, - rependTime, - repetitions, - YTIDitems, - YTIDinput, - notesegments, - currentindexButtonClass, - previousindexButtonClass, - nextindexButtonClass, - $ytsubcurrenttext, - interval, - createNoteSegments, - toggleUpdate, - goToNextAutoTimestamp, - goToPreviousAutoTimestamp, - addUserTimestamp, - goToCurrentUserTimestamp, - goToNextUserTimestamp, - goToPreviousUserTimestamp, - exportTimestamps, - exportr2Timestamps, - importTimestamps, - transcriptToJson, - YTIDaddItems, - YTIDupdateItem, - YTIDdownloadList, - YTIDhandleFileImport, - savenoteSegmentstofile, - loadnotesegmentstofile, - textarea0_input_handler, - click_handler, - input1_input_handler, - input2_change_handler, - textarea1_input_handler, - textarea2_input_handler, - input5_change_handler, - input6_input_handler, - input7_input_handler, - input8_input_handler - ]; + for (key in object) { + if (_hasOwnProperty$2.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; + } + + function constructYamlSet(data) { + return data !== null ? data : {}; } - class YoutubeIframeAPICustomInterface extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$a, create_fragment$a, safe_not_equal, {}, null, [-1, -1, -1]); + var set = new type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet + }); - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "YoutubeIframeAPICustomInterface", - options, - id: create_fragment$a.name - }); - } + var _default = core.extend({ + implicit: [ + timestamp, + merge + ], + explicit: [ + binary, + omap, + pairs, + set + ] + }); + + /*eslint-disable max-len,no-use-before-define*/ + + + + + + + + var _hasOwnProperty$1 = Object.prototype.hasOwnProperty; + + + var CONTEXT_FLOW_IN = 1; + var CONTEXT_FLOW_OUT = 2; + var CONTEXT_BLOCK_IN = 3; + var CONTEXT_BLOCK_OUT = 4; + + + var CHOMPING_CLIP = 1; + var CHOMPING_STRIP = 2; + var CHOMPING_KEEP = 3; + + + var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; + var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; + var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; + var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; + var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + + function _class(obj) { return Object.prototype.toString.call(obj); } + + function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); } - // Unique ID creation requires a high quality random # generator. In the browser we therefore - // require the crypto API and do not support built-in fallback to lower quality random number - // generators (like Math.random()). - let getRandomValues; - const rnds8 = new Uint8Array(16); - function rng() { - // lazy load so that environments that need to polyfill have a chance to do so - if (!getRandomValues) { - // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. - getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); + function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); + } - if (!getRandomValues) { - throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); - } + function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); + } + + function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; + } + + function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; } - return getRandomValues(rnds8); + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; } - /** - * Convert array of 16 byte values to UUID string format of the form: - * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX - */ + function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; + } - const byteToHex = []; + function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } - for (let i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).slice(1)); + return -1; + } + + function simpleEscapeSequence(c) { + /* eslint-disable indent */ + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; + } + + function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode( + ((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00 + ); } - function unsafeStringify(arr, offset = 0) { - // Note: Be careful editing this code! It's been tuned for performance - // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 - return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; + var simpleEscapeCheck = new Array(256); // integer, for fast access + var simpleEscapeMap = new Array(256); + for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); } - const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); - var native = { - randomUUID - }; - function v4(options, buf, offset) { - if (native.randomUUID && !buf && !options) { - return native.randomUUID(); + function State$1(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || _default; + this.onWarning = options['onWarning'] || null; + // (Hidden) Remove? makes the loader to expect YAML 1.1 documents + // if such documents have no explicit %YAML directive + this.legacy = options['legacy'] || false; + + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + // position of first leading tab in the current line, + // used to make sure there are no tabs in the indentation + this.firstTabInLine = -1; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + + } + + + function generateError(state, message) { + var mark = { + name: state.filename, + buffer: state.input.slice(0, -1), // omit trailing \0 + position: state.position, + line: state.line, + column: state.position - state.lineStart + }; + + mark.snippet = snippet(mark); + + return new exception(message, mark); + } + + function throwError(state, message) { + throw generateError(state, message); + } + + function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); } + } - options = options || {}; - const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` - rnds[6] = rnds[6] & 0x0f | 0x40; - rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + var directiveHandlers = { - if (buf) { - offset = offset || 0; + YAML: function handleYamlDirective(state, name, args) { - for (let i = 0; i < 16; ++i) { - buf[offset + i] = rnds[i]; + var match, major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); } - return buf; + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } + + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty$1.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + try { + prefix = decodeURIComponent(prefix); + } catch (err) { + throwError(state, 'tag prefix is malformed: ' + prefix); + } + + state.tagMap[handle] = prefix; } + }; - return unsafeStringify(rnds); + + function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; _position < _length; _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } } - /* src\RecursiveNestedCommentsElement.svelte generated by Svelte v3.59.2 */ + function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; - const { console: console_1$4 } = globals; - const file$9 = "src\\RecursiveNestedCommentsElement.svelte"; + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } - function get_each_context$6(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[15] = list[i]; - child_ctx[16] = list; - child_ctx[17] = i; - return child_ctx; + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty$1.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } } - // (126:16) {#if showReplyInput[comment.id]} - function create_if_block$3(ctx) { - let div; - let input; - let t0; - let button; - let mounted; - let dispose; + function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, + startLine, startLineStart, startPos) { - function input_input_handler() { - /*input_input_handler*/ ctx[12].call(input, /*comment*/ ctx[15]); - } + var index, quantity; - function click_handler_1() { - return /*click_handler_1*/ ctx[13](/*comment*/ ctx[15]); - } + // The output is a plain object here, so keys can only be strings. + // We need to convert keyNode to a string, but doing so can hang the process + // (deeply nested arrays that explode exponentially using aliases). + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); - const block = { - c: function create() { - div = element("div"); - input = element("input"); - t0 = space(); - button = element("button"); - button.textContent = "Post Reply"; - attr_dev(input, "placeholder", "Write a reply..."); - add_location(input, file$9, 127, 24, 5188); - add_location(button, file$9, 128, 24, 5289); - attr_dev(div, "class", "reply-input"); - add_location(div, file$9, 126, 20, 5137); - }, - m: function mount(target, anchor) { - insert_dev(target, div, anchor); - append_dev(div, input); - set_input_value(input, /*replyText*/ ctx[2][/*comment*/ ctx[15].id]); - append_dev(div, t0); - append_dev(div, button); + for (index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, 'nested arrays are not supported inside keys'); + } - if (!mounted) { - dispose = [ - listen_dev(input, "input", input_input_handler), - listen_dev(button, "click", click_handler_1, false, false, false, false) - ]; + if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { + keyNode[index] = '[object Object]'; + } + } + } - mounted = true; - } - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; + // Avoid code execution in load() via toString property + // (still use its own toString for arrays, timestamps, + // and whatever user schema extensions happen to have @@toStringTag) + if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { + keyNode = '[object Object]'; + } - if (dirty & /*replyText, flattenedComments*/ 6 && input.value !== /*replyText*/ ctx[2][/*comment*/ ctx[15].id]) { - set_input_value(input, /*replyText*/ ctx[2][/*comment*/ ctx[15].id]); - } - }, - d: function destroy(detaching) { - if (detaching) detach_dev(div); - mounted = false; - run_all(dispose); - } - }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block$3.name, - type: "if", - source: "(126:16) {#if showReplyInput[comment.id]}", - ctx - }); + keyNode = String(keyNode); - return block; + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty$1.call(overridableKeys, keyNode) && + _hasOwnProperty$1.call(_result, keyNode)) { + state.line = startLine || state.line; + state.lineStart = startLineStart || state.lineStart; + state.position = startPos || state.position; + throwError(state, 'duplicated mapping key'); + } + + // used for this specific key only because Object.defineProperty is slow + if (keyNode === '__proto__') { + Object.defineProperty(_result, keyNode, { + configurable: true, + enumerable: true, + writable: true, + value: valueNode + }); + } else { + _result[keyNode] = valueNode; + } + delete overridableKeys[keyNode]; + } + + return _result; } - // (122:8) {#each flattenedComments as comment} - function create_each_block$6(ctx) { - let div; - let span; - let t0_value = /*comment*/ ctx[15].title + ""; - let t0; - let t1; - let button; - let t3; - let t4; - let div_class_value; - let mounted; - let dispose; + function readLineBreak(state) { + var ch; - function click_handler() { - return /*click_handler*/ ctx[11](/*comment*/ ctx[15]); - } + ch = state.input.charCodeAt(state.position); - let if_block = /*showReplyInput*/ ctx[3][/*comment*/ ctx[15].id] && create_if_block$3(ctx); + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } - const block = { - c: function create() { - div = element("div"); - span = element("span"); - t0 = text(t0_value); - t1 = space(); - button = element("button"); - button.textContent = "Reply"; - t3 = space(); - if (if_block) if_block.c(); - t4 = space(); - add_location(span, file$9, 123, 16, 4951); - add_location(button, file$9, 124, 16, 4997); + state.line += 1; + state.lineStart = state.position; + state.firstTabInLine = -1; + } - attr_dev(div, "class", div_class_value = "" + (null_to_empty(/*comment*/ ctx[15].level === 0 - ? 'top-level-comment' - : 'comment') + " svelte-bsj1sx")); + function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); - set_style(div, "margin-left", /*comment*/ ctx[15].level * 20 + "px"); - add_location(div, file$9, 122, 12, 4821); - }, - m: function mount(target, anchor) { - insert_dev(target, div, anchor); - append_dev(div, span); - append_dev(span, t0); - append_dev(div, t1); - append_dev(div, button); - append_dev(div, t3); - if (if_block) if_block.m(div, null); - append_dev(div, t4); + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) { + state.firstTabInLine = state.position; + } + ch = state.input.charCodeAt(++state.position); + } - if (!mounted) { - dispose = listen_dev(button, "click", click_handler, false, false, false, false); - mounted = true; - } - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; - if (dirty & /*flattenedComments*/ 2 && t0_value !== (t0_value = /*comment*/ ctx[15].title + "")) set_data_dev(t0, t0_value); + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } - if (/*showReplyInput*/ ctx[3][/*comment*/ ctx[15].id]) { - if (if_block) { - if_block.p(ctx, dirty); - } else { - if_block = create_if_block$3(ctx); - if_block.c(); - if_block.m(div, t4); - } - } else if (if_block) { - if_block.d(1); - if_block = null; - } + if (is_EOL(ch)) { + readLineBreak(state); - if (dirty & /*flattenedComments*/ 2 && div_class_value !== (div_class_value = "" + (null_to_empty(/*comment*/ ctx[15].level === 0 - ? 'top-level-comment' - : 'comment') + " svelte-bsj1sx"))) { - attr_dev(div, "class", div_class_value); - } + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; - if (dirty & /*flattenedComments*/ 2) { - set_style(div, "margin-left", /*comment*/ ctx[15].level * 20 + "px"); - } - }, - d: function destroy(detaching) { - if (detaching) detach_dev(div); - if (if_block) if_block.d(); - mounted = false; - dispose(); - } - }; + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block$6.name, - type: "each", - source: "(122:8) {#each flattenedComments as comment}", - ctx - }); + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } - return block; + return lineBreaks; } - function create_fragment$9(ctx) { - let h1; - let t1; - let h4; - let t3; - let simpleiframe; - let t4; - let div2; - let div0; - let button0; - let t6; - let input0; - let t7; - let input1; - let t8; - let button1; - let t10; - let br; - let t11; - let div1; - let current; - let mounted; - let dispose; + function testDocumentSeparator(state) { + var _position = state.position, + ch; - simpleiframe = new SimpleIFrame({ - props: { webpages: /*LLMforassit*/ ctx[4] }, - $$inline: true - }); + ch = state.input.charCodeAt(_position); - let each_value = /*flattenedComments*/ ctx[1]; - validate_each_argument(each_value); - let each_blocks = []; + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { - for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$6(get_each_context$6(ctx, each_value, i)); - } + _position += 3; - const block = { - c: function create() { - h1 = element("h1"); - h1.textContent = "Reddit based Nested Comments Idea for LMM responses that need further branching responses"; - t1 = space(); - h4 = element("h4"); - h4.textContent = "Inspired by Vijay Bhati - https://github.com/vj98/Frontend-Machine-Coding/tree/main/nested-comments https://youtu.be/a4OA7QbHEho?list=PLBygUld3s6x8sI_H8UYROVMIVcuxUre1e"; - t3 = text("\r\nLLM: "); - create_component(simpleiframe.$$.fragment); - t4 = space(); - div2 = element("div"); - div0 = element("div"); - button0 = element("button"); - button0.textContent = "Export Comments"; - t6 = text("\r\n | Import Exported Comments \r\n "); - input0 = element("input"); - t7 = text("\r\n | \r\n "); - input1 = element("input"); - t8 = space(); - button1 = element("button"); - button1.textContent = "Post Comment"; - t10 = space(); - br = element("br"); - t11 = space(); - div1 = element("div"); + ch = state.input.charCodeAt(_position); - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } - add_location(h1, file$9, 106, 0, 3964); - add_location(h4, file$9, 107, 0, 4066); - add_location(button0, file$9, 111, 8, 4395); - attr_dev(input0, "type", "file"); - add_location(input0, file$9, 113, 8, 4498); - attr_dev(input1, "placeholder", "Add a comment..."); - add_location(input1, file$9, 115, 8, 4570); - add_location(button1, file$9, 116, 8, 4644); - add_location(div0, file$9, 110, 4, 4380); - add_location(br, file$9, 119, 4, 4723); - attr_dev(div1, "id", "comment-container"); - add_location(div1, file$9, 120, 4, 4733); - attr_dev(div2, "class", "component-containter svelte-bsj1sx"); - set_style(div2, "border", "1px solid black"); - set_style(div2, "padding", "4px"); - add_location(div2, file$9, 109, 0, 4293); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, h1, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, h4, anchor); - insert_dev(target, t3, anchor); - mount_component(simpleiframe, target, anchor); - insert_dev(target, t4, anchor); - insert_dev(target, div2, anchor); - append_dev(div2, div0); - append_dev(div0, button0); - append_dev(div0, t6); - append_dev(div0, input0); - append_dev(div0, t7); - append_dev(div0, input1); - set_input_value(input1, /*newComment*/ ctx[0]); - append_dev(div0, t8); - append_dev(div0, button1); - append_dev(div2, t10); - append_dev(div2, br); - append_dev(div2, t11); - append_dev(div2, div1); + return false; + } - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(div1, null); - } - } + function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } + } - current = true; - if (!mounted) { - dispose = [ - listen_dev(button0, "click", /*exportToJson*/ ctx[8], false, false, false, false), - listen_dev(input0, "change", /*handleFileUpload*/ ctx[9], false, false, false, false), - listen_dev(input1, "input", /*input1_input_handler*/ ctx[10]), - listen_dev(button1, "click", /*addComment*/ ctx[5], false, false, false, false) - ]; + function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } - mounted = true; - } - }, - p: function update(ctx, [dirty]) { - if (dirty & /*newComment*/ 1 && input1.value !== /*newComment*/ ctx[0]) { - set_input_value(input1, /*newComment*/ ctx[0]); - } + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); - if (dirty & /*flattenedComments, addReply, replyText, toggleReplyInput, showReplyInput*/ 206) { - each_value = /*flattenedComments*/ ctx[1]; - validate_each_argument(each_value); - let i; + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } - for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$6(ctx, each_value, i); + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } - if (each_blocks[i]) { - each_blocks[i].p(child_ctx, dirty); - } else { - each_blocks[i] = create_each_block$6(child_ctx); - each_blocks[i].c(); - each_blocks[i].m(div1, null); - } - } + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } - for (; i < each_blocks.length; i += 1) { - each_blocks[i].d(1); - } + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } - each_blocks.length = each_value.length; - } - }, - i: function intro(local) { - if (current) return; - transition_in(simpleiframe.$$.fragment, local); - current = true; - }, - o: function outro(local) { - transition_out(simpleiframe.$$.fragment, local); - current = false; - }, - d: function destroy(detaching) { - if (detaching) detach_dev(h1); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(h4); - if (detaching) detach_dev(t3); - destroy_component(simpleiframe, detaching); - if (detaching) detach_dev(t4); - if (detaching) detach_dev(div2); - destroy_each(each_blocks, detaching); - mounted = false; - run_all(dispose); - } - }; + ch = state.input.charCodeAt(++state.position); + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$9.name, - type: "component", - source: "", - ctx - }); + captureSegment(state, captureStart, captureEnd, false); - return block; + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; } - function flattenStructure(items, level = 0, parentId = null, processedIds = new Set()) { - let result = []; + function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; - items.forEach(item => { - if (processedIds.has(item.id)) return; - result.push({ ...item, level, parentId }); - processedIds.add(item.id); + ch = state.input.charCodeAt(state.position); - if (item.items && Array.isArray(item.items)) { - const childItems = flattenStructure(item.items, level + 1, item.id, processedIds); - result = result.concat(childItems); - } - }); + if (ch !== 0x27/* ' */) { + return false; + } - return result; + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); } - function instance$9($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('RecursiveNestedCommentsElement', slots, []); + function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; - let LLMforassit = [ - { - name: 'CohereForAI/c4ai-command-r-plus', - url: 'https://cohereforai-c4ai-command-r-plus.hf.space' - }, - { - name: 'ysharma/Chat_with_Meta_llama3_8b', - url: 'https://ysharma-chat-with-meta-llama3-8b.hf.space' - }, - { - name: 'Qwen/Qwen1.5-110B-Chat-demo', - url: 'https://qwen-qwen1-5-110b-chat-demo.hf.space' - } - ]; //List of models with system prompt available //{ name: '', url: '' }, + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; - let comments = []; - let newComment = ''; - let flattenedComments = []; - let replyText = {}; - let showReplyInput = {}; + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; - const addComment = () => { - comments = [ - ...comments, - { - id: v4(), - title: newComment, - items: [] - } - ]; + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); - $$invalidate(0, newComment = ''); - $$invalidate(1, flattenedComments = flattenStructure(comments)); - }; + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; - const addReply = (parentId, replyText) => { - const findAndAddReply = (items, id) => { - for (let item of items) { - if (item.id === id) { - item.items.push({ - id: v4(), - title: replyText, - items: [] - }); + } else { + throwError(state, 'expected hexadecimal character'); + } + } - return true; - } + state.result += charFromCodepoint(hexResult); - if (item.items.length && findAndAddReply(item.items, id)) { - return true; - } - } + state.position++; - return false; - }; + } else { + throwError(state, 'unknown escape sequence'); + } - findAndAddReply(comments, parentId); - $$invalidate(1, flattenedComments = flattenStructure(comments)); - }; + captureStart = captureEnd = state.position; - // Function to toggle reply input - function toggleReplyInput(commentId) { - $$invalidate(3, showReplyInput[commentId] = !showReplyInput[commentId], showReplyInput); - } + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; - function exportToJson() { - const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(comments)); - const downloadAnchorNode = document.createElement('a'); - downloadAnchorNode.setAttribute("href", dataStr); - downloadAnchorNode.setAttribute("download", "comments.json"); - document.body.appendChild(downloadAnchorNode); - downloadAnchorNode.click(); - downloadAnchorNode.remove(); - } + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); - function handleFileUpload(event) { - const file = event.target.files[0]; - if (!file) return; - const reader = new FileReader(); + } else { + state.position++; + captureEnd = state.position; + } + } - reader.onload = e => { - const text = e.target.result; + throwError(state, 'unexpected end of the stream within a double quoted scalar'); + } + + function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _lineStart, + _pos, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = Object.create(null), + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } - try { - comments = JSON.parse(text); - $$invalidate(1, flattenedComments = flattenStructure(comments)); - } catch(error) { - console.error("Error parsing JSON:", error); - } - }; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } - reader.readAsText(file); - } + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } else if (ch === 0x2C/* , */) { + // "flow collection entries can never be completely empty", as per YAML 1.2, section 7.4 + throwError(state, "expected the node content, but found ','"); + } - const writable_props = []; + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$4.warn(` was created with unknown prop '${key}'`); - }); + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); - function input1_input_handler() { - newComment = this.value; - $$invalidate(0, newComment); - } + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } - const click_handler = comment => toggleReplyInput(comment.id); + _line = state.line; // Save the current line. + _lineStart = state.lineStart; + _pos = state.position; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } - function input_input_handler(comment) { - replyText[comment.id] = this.value; - $$invalidate(2, replyText); - } + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)); + } else { + _result.push(keyNode); + } - const click_handler_1 = comment => { - addReply(comment.id, replyText[comment.id]); - toggleReplyInput(comment.id); - }; + skipSeparationSpace(state, true, nodeIndent); - $$self.$capture_state = () => ({ - uuidv4: v4, - SimpleIFrame, - LLMforassit, - comments, - newComment, - flattenedComments, - replyText, - showReplyInput, - flattenStructure, - addComment, - addReply, - toggleReplyInput, - exportToJson, - handleFileUpload - }); + ch = state.input.charCodeAt(state.position); - $$self.$inject_state = $$props => { - if ('LLMforassit' in $$props) $$invalidate(4, LLMforassit = $$props.LLMforassit); - if ('comments' in $$props) comments = $$props.comments; - if ('newComment' in $$props) $$invalidate(0, newComment = $$props.newComment); - if ('flattenedComments' in $$props) $$invalidate(1, flattenedComments = $$props.flattenedComments); - if ('replyText' in $$props) $$invalidate(2, replyText = $$props.replyText); - if ('showReplyInput' in $$props) $$invalidate(3, showReplyInput = $$props.showReplyInput); - }; + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + throwError(state, 'unexpected end of the stream within a flow collection'); + } + + function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } - return [ - newComment, - flattenedComments, - replyText, - showReplyInput, - LLMforassit, - addComment, - addReply, - toggleReplyInput, - exportToJson, - handleFileUpload, - input1_input_handler, - click_handler, - input_input_handler, - click_handler_1 - ]; - } + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } - class RecursiveNestedCommentsElement extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$9, create_fragment$9, safe_not_equal, {}); + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "RecursiveNestedCommentsElement", - options, - id: create_fragment$9.name - }); - } - } + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } - /* src\CopyandRemoveListComponent.svelte generated by Svelte v3.59.2 */ + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; - const { console: console_1$3 } = globals; - const file$8 = "src\\CopyandRemoveListComponent.svelte"; + ch = state.input.charCodeAt(state.position); - function get_each_context$5(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[6] = list[i]; - return child_ctx; - } + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } - // (26:0) {:else} - function create_else_block(ctx) { - let each_blocks = []; - let each_1_lookup = new Map(); - let each_1_anchor; - let each_value = /*items*/ ctx[1]; - validate_each_argument(each_value); - const get_key = ctx => /*item*/ ctx[6].id; - validate_each_keys(ctx, each_value, get_each_context$5, get_key); + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } - for (let i = 0; i < each_value.length; i += 1) { - let child_ctx = get_each_context$5(ctx, each_value, i); - let key = get_key(child_ctx); - each_1_lookup.set(key, each_blocks[i] = create_each_block$5(key, child_ctx)); - } + if (is_EOL(ch)) { + emptyLines++; + continue; + } - const block = { - c: function create() { - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + // End of the scalar. + if (state.lineIndent < textIndent) { - each_1_anchor = empty(); - }, - m: function mount(target, anchor) { - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(target, anchor); - } - } + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } - insert_dev(target, each_1_anchor, anchor); - }, - p: function update(ctx, dirty) { - if (dirty & /*copyAndRemoveItem, items*/ 10) { - each_value = /*items*/ ctx[1]; - validate_each_argument(each_value); - validate_each_keys(ctx, each_value, get_each_context$5, get_key); - each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, each_1_anchor.parentNode, destroy_block, create_each_block$5, each_1_anchor, get_each_context$5); - } - }, - d: function destroy(detaching) { - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].d(detaching); - } + // Break this `while` cycle and go to the funciton's epilogue. + break; + } - if (detaching) detach_dev(each_1_anchor); - } - }; + // Folded style: use fancy rules to handle line breaks. + if (folding) { - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_else_block.name, - type: "else", - source: "(26:0) {:else}", - ctx - }); + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); - return block; - } + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); - // (24:0) {#if items.length === 0} - function create_if_block$2(ctx) { - let p; + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } - const block = { - c: function create() { - p = element("p"); - p.textContent = "All items have been copied! (or none entered yet)"; - add_location(p, file$8, 24, 4, 732); - }, - m: function mount(target, anchor) { - insert_dev(target, p, anchor); - }, - p: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(p); - } - }; + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block$2.name, - type: "if", - source: "(24:0) {#if items.length === 0}", - ctx - }); + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } - return block; + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; } - // (27:4) {#each items as item (item.id)} - function create_each_block$5(key_1, ctx) { - let button; - let t0_value = /*item*/ ctx[6].text + ""; - let t0; - let t1; - let mounted; - let dispose; + function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; - function click_handler() { - return /*click_handler*/ ctx[5](/*item*/ ctx[6]); - } + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; - const block = { - key: key_1, - first: null, - c: function create() { - button = element("button"); - t0 = text(t0_value); - t1 = space(); - attr_dev(button, "class", "item svelte-13m3fab"); - add_location(button, file$8, 27, 8, 844); - this.first = button; - }, - m: function mount(target, anchor) { - insert_dev(target, button, anchor); - append_dev(button, t0); - append_dev(button, t1); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } - if (!mounted) { - dispose = listen_dev(button, "click", click_handler, false, false, false, false); - mounted = true; - } - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; - if (dirty & /*items*/ 2 && t0_value !== (t0_value = /*item*/ ctx[6].text + "")) set_data_dev(t0, t0_value); - }, - d: function destroy(detaching) { - if (detaching) detach_dev(button); - mounted = false; - dispose(); - } - }; + ch = state.input.charCodeAt(state.position); - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block$5.name, - type: "each", - source: "(27:4) {#each items as item (item.id)}", - ctx - }); + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } - return block; - } + if (ch !== 0x2D/* - */) { + break; + } - function create_fragment$8(ctx) { - let h1; - let t1; - let textarea; - let t2; - let if_block_anchor; - let mounted; - let dispose; + following = state.input.charCodeAt(state.position + 1); - function select_block_type(ctx, dirty) { - if (/*items*/ ctx[1].length === 0) return create_if_block$2; - return create_else_block; - } + if (!is_WS_OR_EOL(following)) { + break; + } - let current_block_type = select_block_type(ctx); - let if_block = current_block_type(ctx); + detected = true; + state.position++; - const block = { - c: function create() { - h1 = element("h1"); - h1.textContent = "Copy items for prompts by clicking buttons below"; - t1 = space(); - textarea = element("textarea"); - t2 = space(); - if_block.c(); - if_block_anchor = empty(); - add_location(h1, file$8, 19, 0, 537); - attr_dev(textarea, "placeholder", "Enter text here..."); - attr_dev(textarea, "class", "svelte-13m3fab"); - add_location(textarea, file$8, 21, 0, 598); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, h1, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, textarea, anchor); - set_input_value(textarea, /*textInput*/ ctx[0]); - insert_dev(target, t2, anchor); - if_block.m(target, anchor); - insert_dev(target, if_block_anchor, anchor); + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } - if (!mounted) { - dispose = [ - listen_dev(textarea, "input", /*textarea_input_handler*/ ctx[4]), - listen_dev(textarea, "input", /*updateItems*/ ctx[2], false, false, false, false) - ]; + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); - mounted = true; - } - }, - p: function update(ctx, [dirty]) { - if (dirty & /*textInput*/ 1) { - set_input_value(textarea, /*textInput*/ ctx[0]); - } + ch = state.input.charCodeAt(state.position); - if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block) { - if_block.p(ctx, dirty); - } else { - if_block.d(1); - if_block = current_block_type(ctx); + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } - if (if_block) { - if_block.c(); - if_block.m(if_block_anchor.parentNode, if_block_anchor); - } - } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(h1); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(textarea); - if (detaching) detach_dev(t2); - if_block.d(detaching); - if (detaching) detach_dev(if_block_anchor); - mounted = false; - run_all(dispose); - } - }; + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; + } + + function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _keyLine, + _keyLineStart, + _keyPos, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = Object.create(null), + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$8.name, - type: "component", - source: "", - ctx - }); + ch = state.input.charCodeAt(state.position); - return block; - } + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } - function instance$8($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('CopyandRemoveListComponent', slots, []); - let textInput = ''; - let items = []; + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. - function updateItems() { - $$invalidate(1, items = textInput.split('\n').filter(line => line.trim() !== '').map((line, index) => ({ id: index + line, text: line }))); - } + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { - async function copyAndRemoveItem(item) { - try { - await navigator.clipboard.writeText(item.text); - $$invalidate(1, items = items.filter(i => i.id !== item.id)); - } catch(err) { - console.error('Failed to copy text: ', err); - } - } + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } - const writable_props = []; + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + // Neither implicit nor explicit notation. + // Reading is done. Go to the epilogue. + break; + } + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$3.warn(` was created with unknown prop '${key}'`); - }); + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); - function textarea_input_handler() { - textInput = this.value; - $$invalidate(0, textInput); - } + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } - const click_handler = item => copyAndRemoveItem(item); + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } - $$self.$capture_state = () => ({ - textInput, - items, - updateItems, - copyAndRemoveItem - }); + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; - $$self.$inject_state = $$props => { - if ('textInput' in $$props) $$invalidate(0, textInput = $$props.textInput); - if ('items' in $$props) $$invalidate(1, items = $$props.items); - }; + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } - return [ - textInput, - items, - updateItems, - copyAndRemoveItem, - textarea_input_handler, - click_handler - ]; - } + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); - class CopyandRemoveListComponent extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$8, create_fragment$8, safe_not_equal, {}); + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + } - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "CopyandRemoveListComponent", - options, - id: create_fragment$8.name - }); - } - } + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + } + + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } - /* src\ReadingStateCounter.svelte generated by Svelte v3.59.2 */ + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } - const file$7 = "src\\ReadingStateCounter.svelte"; + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } - function get_each_context$4(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[8] = list[i]; - child_ctx[10] = i; - return child_ctx; + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; } - // (67:4) {#each words as wordObj, index (index)} - function create_each_block$4(key_1, ctx) { - let button; - let t0_value = /*wordObj*/ ctx[8].word + ""; - let t0; - let t1; - let t2_value = /*wordObj*/ ctx[8].count + ""; - let t2; - let t3; - let mounted; - let dispose; + function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; - function click_handler() { - return /*click_handler*/ ctx[7](/*index*/ ctx[10]); - } + ch = state.input.charCodeAt(state.position); - const block = { - key: key_1, - first: null, - c: function create() { - button = element("button"); - t0 = text(t0_value); - t1 = text(" ("); - t2 = text(t2_value); - t3 = text(")\r\n "); - attr_dev(button, "class", "word-button svelte-13vjncp"); - set_style(button, "background-color", getColor(/*wordObj*/ ctx[8].count)); - add_location(button, file$7, 67, 8, 1994); - this.first = button; - }, - m: function mount(target, anchor) { - insert_dev(target, button, anchor); - append_dev(button, t0); - append_dev(button, t1); - append_dev(button, t2); - append_dev(button, t3); + if (ch !== 0x21/* ! */) return false; - if (!mounted) { - dispose = listen_dev(button, "click", click_handler, false, false, false, false); - mounted = true; - } - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; - if (dirty & /*words*/ 2 && t0_value !== (t0_value = /*wordObj*/ ctx[8].word + "")) set_data_dev(t0, t0_value); - if (dirty & /*words*/ 2 && t2_value !== (t2_value = /*wordObj*/ ctx[8].count + "")) set_data_dev(t2, t2_value); + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } - if (dirty & /*words*/ 2) { - set_style(button, "background-color", getColor(/*wordObj*/ ctx[8].count)); - } - }, - d: function destroy(detaching) { - if (detaching) detach_dev(button); - mounted = false; - dispose(); - } - }; + ch = state.input.charCodeAt(++state.position); - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block$4.name, - type: "each", - source: "(67:4) {#each words as wordObj, index (index)}", - ctx - }); + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); - return block; - } + } else { + tagHandle = '!'; + } - function create_fragment$7(ctx) { - let div0; - let h1; - let t1; - let input0; - let t2; - let button0; - let t4; - let button1; - let t6; - let input1; - let t7; - let div1; - let each_blocks = []; - let each_1_lookup = new Map(); - let mounted; - let dispose; - let each_value = /*words*/ ctx[1]; - validate_each_argument(each_value); - const get_key = ctx => /*index*/ ctx[10]; - validate_each_keys(ctx, each_value, get_each_context$4, get_key); + _position = state.position; - for (let i = 0; i < each_value.length; i += 1) { - let child_ctx = get_each_context$4(ctx, each_value, i); - let key = get_key(child_ctx); - each_1_lookup.set(key, each_blocks[i] = create_each_block$4(key, child_ctx)); - } + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); - const block = { - c: function create() { - div0 = element("div"); - h1 = element("h1"); - h1.textContent = "Stateful Reader Brainstorm"; - t1 = space(); - input0 = element("input"); - t2 = space(); - button0 = element("button"); - button0.textContent = "Submit Text"; - t4 = space(); - button1 = element("button"); - button1.textContent = "Export to JSON"; - t6 = space(); - input1 = element("input"); - t7 = space(); - div1 = element("div"); + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); - add_location(h1, file$7, 57, 4, 1576); - attr_dev(input0, "type", "text"); - attr_dev(input0, "placeholder", "Enter text here"); - attr_dev(input0, "class", "svelte-13vjncp"); - add_location(input0, file$7, 58, 4, 1617); - attr_dev(button0, "class", "svelte-13vjncp"); - add_location(button0, file$7, 59, 4, 1696); - attr_dev(button1, "class", "svelte-13vjncp"); - add_location(button1, file$7, 60, 4, 1752); - attr_dev(input1, "type", "file"); - attr_dev(input1, "class", "svelte-13vjncp"); - add_location(input1, file$7, 61, 4, 1813); - add_location(div0, file$7, 56, 0, 1565); - add_location(div1, file$7, 64, 0, 1873); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, div0, anchor); - append_dev(div0, h1); - append_dev(div0, t1); - append_dev(div0, input0); - set_input_value(input0, /*inputText*/ ctx[0]); - append_dev(div0, t2); - append_dev(div0, button0); - append_dev(div0, t4); - append_dev(div0, button1); - append_dev(div0, t6); - append_dev(div0, input1); - insert_dev(target, t7, anchor); - insert_dev(target, div1, anchor); + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(div1, null); - } - } + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } - if (!mounted) { - dispose = [ - listen_dev(input0, "input", /*input0_input_handler*/ ctx[6]), - listen_dev(button0, "click", /*submitText*/ ctx[2], false, false, false, false), - listen_dev(button1, "click", /*exportToJson*/ ctx[4], false, false, false, false), - listen_dev(input1, "change", /*importFromJson*/ ctx[5], false, false, false, false) - ]; + ch = state.input.charCodeAt(++state.position); + } - mounted = true; - } - }, - p: function update(ctx, [dirty]) { - if (dirty & /*inputText*/ 1 && input0.value !== /*inputText*/ ctx[0]) { - set_input_value(input0, /*inputText*/ ctx[0]); - } + tagName = state.input.slice(_position, state.position); - if (dirty & /*getColor, words, handleClick*/ 10) { - each_value = /*words*/ ctx[1]; - validate_each_argument(each_value); - validate_each_keys(ctx, each_value, get_each_context$4, get_key); - each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, div1, destroy_block, create_each_block$4, null, get_each_context$4); - } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(div0); - if (detaching) detach_dev(t7); - if (detaching) detach_dev(div1); + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].d(); - } + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } - mounted = false; - run_all(dispose); - } - }; + try { + tagName = decodeURIComponent(tagName); + } catch (err) { + throwError(state, 'tag name is malformed: ' + tagName); + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$7.name, - type: "component", - source: "", - ctx - }); + if (isVerbatim) { + state.tag = tagName; - return block; - } + } else if (_hasOwnProperty$1.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; - function getColor(count) { - const colors = [ - '#1a1a1a', - '#333333', - '#4d4d4d', - '#666666', - '#808080', - '#999999', - '#b3b3b3', - '#cccccc', - '#e6e6e6', - '#ffffff' - ]; + } else if (tagHandle === '!') { + state.tag = '!' + tagName; - return colors[Math.min(Math.floor(count / 10), 9)]; + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; } - function instance$7($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('ReadingStateCounter', slots, []); - let inputText = ""; - let words = []; + function readAnchorProperty(state) { + var _position, + ch; - function submitText() { - $$invalidate(1, words = inputText.split(/\s+/).map(word => ({ word, count: 0 }))); - } + ch = state.input.charCodeAt(state.position); - function handleClick(index) { - $$invalidate(1, words[index].count += 1, words); - $$invalidate(1, words = [...words]); // Ensures Svelte detects the change - } + if (ch !== 0x26/* & */) return false; - // Function to export data to JSON - function exportToJson() { - const jsonData = JSON.stringify(words); - const blob = new Blob([jsonData], { type: "application/json" }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = 'statefulwords.json'; - a.click(); - URL.revokeObjectURL(url); - } + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } - // Function to handle file import - function importFromJson(event) { - const file = event.target.files[0]; + ch = state.input.charCodeAt(++state.position); + _position = state.position; - if (file) { - const reader = new FileReader(); + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } - reader.onload = e => { - const json = e.target.result; - $$invalidate(1, words = JSON.parse(json)); - }; + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } - reader.readAsText(file); - } - } + state.anchor = state.input.slice(_position, state.position); + return true; + } - const writable_props = []; + function readAlias(state) { + var _position, alias, + ch; - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); + ch = state.input.charCodeAt(state.position); - function input0_input_handler() { - inputText = this.value; - $$invalidate(0, inputText); - } + if (ch !== 0x2A/* * */) return false; - const click_handler = index => handleClick(index); + ch = state.input.charCodeAt(++state.position); + _position = state.position; - $$self.$capture_state = () => ({ - inputText, - words, - submitText, - handleClick, - getColor, - exportToJson, - importFromJson - }); + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } - $$self.$inject_state = $$props => { - if ('inputText' in $$props) $$invalidate(0, inputText = $$props.inputText); - if ('words' in $$props) $$invalidate(1, words = $$props.words); - }; + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + alias = state.input.slice(_position, state.position); - return [ - inputText, - words, - submitText, - handleClick, - exportToJson, - importFromJson, - input0_input_handler, - click_handler - ]; - } + if (!_hasOwnProperty$1.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } - class ReadingStateCounter extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$7, create_fragment$7, safe_not_equal, {}); + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; + } + + function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } - /* src\DeliberateSubconciousRepititionPractice.svelte generated by Svelte v3.59.2 */ + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } - const { Object: Object_1$1, console: console_1$2 } = globals; - const file$6 = "src\\DeliberateSubconciousRepititionPractice.svelte"; + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } - // (156:0) {#if selectedItem} - function create_if_block_1(ctx) { - let div; - let strong0; - let t1; - let t2_value = /*selectedItem*/ ctx[1].text + ""; - let t2; - let t3; - let strong1; - let t5; - let t6_value = /*counts*/ ctx[2][/*selectedItem*/ ctx[1].id] + ""; - let t6; + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } - const block = { - c: function create() { - div = element("div"); - strong0 = element("strong"); - strong0.textContent = "Current Word:"; - t1 = space(); - t2 = text(t2_value); - t3 = space(); - strong1 = element("strong"); - strong1.textContent = "Count:"; - t5 = space(); - t6 = text(t6_value); - add_location(strong0, file$6, 157, 8, 5744); - add_location(strong1, file$6, 158, 8, 5805); - add_location(div, file$6, 156, 4, 5729); - }, - m: function mount(target, anchor) { - insert_dev(target, div, anchor); - append_dev(div, strong0); - append_dev(div, t1); - append_dev(div, t2); - append_dev(div, t3); - append_dev(div, strong1); - append_dev(div, t5); - append_dev(div, t6); - }, - p: function update(ctx, dirty) { - if (dirty & /*selectedItem*/ 2 && t2_value !== (t2_value = /*selectedItem*/ ctx[1].text + "")) set_data_dev(t2, t2_value); - if (dirty & /*counts, selectedItem*/ 6 && t6_value !== (t6_value = /*counts*/ ctx[2][/*selectedItem*/ ctx[1].id] + "")) set_data_dev(t6, t6_value); - }, - d: function destroy(detaching) { - if (detaching) detach_dev(div); - } - }; + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block_1.name, - type: "if", - source: "(156:0) {#if selectedItem}", - ctx - }); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } - return block; - } + if (state.tag === null) { + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } - // (163:0) {#if allWordsLimitReached} - function create_if_block$1(ctx) { - let div; + } else if (state.tag === '?') { + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only automatically assigned to plain scalars. + // + // We only need to check kind conformity in case user explicitly assigns '?' + // tag, for example like this: "! [0]" + // + if (state.result !== null && state.kind !== 'scalar') { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } - const block = { - c: function create() { - div = element("div"); - div.textContent = "All words have reached the count limit."; - attr_dev(div, "class", "alert svelte-fb2ql8"); - add_location(div, file$6, 163, 4, 5910); - }, - m: function mount(target, anchor) { - insert_dev(target, div, anchor); - }, - d: function destroy(detaching) { - if (detaching) detach_dev(div); - } - }; + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type = state.implicitTypes[typeIndex]; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_if_block$1.name, - type: "if", - source: "(163:0) {#if allWordsLimitReached}", - ctx - }); + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (state.tag !== '!') { + if (_hasOwnProperty$1.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + } else { + // looking for multi type + type = null; + typeList = state.typeMap.multi[state.kind || 'fallback']; + + for (typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) { + if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) { + type = typeList[typeIndex]; + break; + } + } + } - return block; + if (!type) { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result, state.tag); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; } - function create_fragment$6(ctx) { - let h1; - let t1; - let input0; - let t2; - let button0; - let t4; - let br; - let t5; - let textarea0; - let t6; - let hr0; - let t7; - let div; - let label; - let t9; - let input1; - let t10; - let t11; - let t12; - let button1; - let t14; - let button2; - let t16; - let hr1; - let t17; - let button3; - let t19; - let textarea1; - let mounted; - let dispose; - let if_block0 = /*selectedItem*/ ctx[1] && create_if_block_1(ctx); - let if_block1 = /*allWordsLimitReached*/ ctx[4] && create_if_block$1(ctx); + function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; - const block = { - c: function create() { - h1 = element("h1"); - h1.textContent = "Random Word till appearance count reached for TTS"; - t1 = space(); - input0 = element("input"); - t2 = space(); - button0 = element("button"); - button0.textContent = "Export Counts"; - t4 = space(); - br = element("br"); - t5 = space(); - textarea0 = element("textarea"); - t6 = space(); - hr0 = element("hr"); - t7 = space(); - div = element("div"); - label = element("label"); - label.textContent = "Total Count Limit:"; - t9 = space(); - input1 = element("input"); - t10 = space(); - if (if_block0) if_block0.c(); - t11 = space(); - if (if_block1) if_block1.c(); - t12 = space(); - button1 = element("button"); - button1.textContent = "Start"; - t14 = space(); - button2 = element("button"); - button2.textContent = "Stop"; - t16 = space(); - hr1 = element("hr"); - t17 = space(); - button3 = element("button"); - button3.textContent = "Simulate one hour or limit Counts"; - t19 = space(); - textarea1 = element("textarea"); - add_location(h1, file$6, 141, 0, 5255); - attr_dev(input0, "type", "file"); - add_location(input0, file$6, 143, 0, 5317); - add_location(button0, file$6, 144, 0, 5365); - add_location(br, file$6, 145, 0, 5421); - attr_dev(textarea0, "placeholder", "Enter text here..."); - add_location(textarea0, file$6, 146, 0, 5427); - add_location(hr0, file$6, 148, 0, 5531); - attr_dev(label, "for", "totalCountLimit"); - add_location(label, file$6, 151, 4, 5550); - attr_dev(input1, "type", "number"); - attr_dev(input1, "min", "1"); - attr_dev(input1, "id", "totalCountLimit"); - add_location(input1, file$6, 152, 4, 5612); - add_location(div, file$6, 150, 0, 5539); - add_location(button1, file$6, 168, 0, 6001); - add_location(button2, file$6, 169, 0, 6042); - add_location(hr1, file$6, 171, 0, 6083); - add_location(button3, file$6, 173, 0, 6091); - textarea1.readOnly = true; - attr_dev(textarea1, "placeholder", "Simulation result will be shown here..."); - add_location(textarea1, file$6, 174, 0, 6168); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, h1, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, input0, anchor); - insert_dev(target, t2, anchor); - insert_dev(target, button0, anchor); - insert_dev(target, t4, anchor); - insert_dev(target, br, anchor); - insert_dev(target, t5, anchor); - insert_dev(target, textarea0, anchor); - set_input_value(textarea0, /*textInput*/ ctx[0]); - insert_dev(target, t6, anchor); - insert_dev(target, hr0, anchor); - insert_dev(target, t7, anchor); - insert_dev(target, div, anchor); - append_dev(div, label); - append_dev(div, t9); - append_dev(div, input1); - set_input_value(input1, /*totalCountLimit*/ ctx[3]); - insert_dev(target, t10, anchor); - if (if_block0) if_block0.m(target, anchor); - insert_dev(target, t11, anchor); - if (if_block1) if_block1.m(target, anchor); - insert_dev(target, t12, anchor); - insert_dev(target, button1, anchor); - insert_dev(target, t14, anchor); - insert_dev(target, button2, anchor); - insert_dev(target, t16, anchor); - insert_dev(target, hr1, anchor); - insert_dev(target, t17, anchor); - insert_dev(target, button3, anchor); - insert_dev(target, t19, anchor); - insert_dev(target, textarea1, anchor); - set_input_value(textarea1, /*simulationResult*/ ctx[5]); + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = Object.create(null); + state.anchorMap = Object.create(null); - if (!mounted) { - dispose = [ - listen_dev(input0, "change", /*importCounts*/ ctx[10], false, false, false, false), - listen_dev(button0, "click", /*exportCounts*/ ctx[9], false, false, false, false), - listen_dev(textarea0, "input", /*textarea0_input_handler*/ ctx[12]), - listen_dev(textarea0, "input", /*updateItems*/ ctx[6], false, false, false, false), - listen_dev(input1, "input", /*input1_input_handler*/ ctx[13]), - listen_dev(button1, "click", /*start*/ ctx[7], false, false, false, false), - listen_dev(button2, "click", /*stop*/ ctx[8], false, false, false, false), - listen_dev(button3, "click", /*simulateCount*/ ctx[11], false, false, false, false), - listen_dev(textarea1, "input", /*textarea1_input_handler*/ ctx[14]) - ]; + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); - mounted = true; - } - }, - p: function update(ctx, [dirty]) { - if (dirty & /*textInput*/ 1) { - set_input_value(textarea0, /*textInput*/ ctx[0]); - } + ch = state.input.charCodeAt(state.position); - if (dirty & /*totalCountLimit*/ 8 && to_number(input1.value) !== /*totalCountLimit*/ ctx[3]) { - set_input_value(input1, /*totalCountLimit*/ ctx[3]); - } + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } - if (/*selectedItem*/ ctx[1]) { - if (if_block0) { - if_block0.p(ctx, dirty); - } else { - if_block0 = create_if_block_1(ctx); - if_block0.c(); - if_block0.m(t11.parentNode, t11); - } - } else if (if_block0) { - if_block0.d(1); - if_block0 = null; - } + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; - if (/*allWordsLimitReached*/ ctx[4]) { - if (if_block1) ; else { - if_block1 = create_if_block$1(ctx); - if_block1.c(); - if_block1.m(t12.parentNode, t12); - } - } else if (if_block1) { - if_block1.d(1); - if_block1 = null; - } + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } - if (dirty & /*simulationResult*/ 32) { - set_input_value(textarea1, /*simulationResult*/ ctx[5]); - } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(h1); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(input0); - if (detaching) detach_dev(t2); - if (detaching) detach_dev(button0); - if (detaching) detach_dev(t4); - if (detaching) detach_dev(br); - if (detaching) detach_dev(t5); - if (detaching) detach_dev(textarea0); - if (detaching) detach_dev(t6); - if (detaching) detach_dev(hr0); - if (detaching) detach_dev(t7); - if (detaching) detach_dev(div); - if (detaching) detach_dev(t10); - if (if_block0) if_block0.d(detaching); - if (detaching) detach_dev(t11); - if (if_block1) if_block1.d(detaching); - if (detaching) detach_dev(t12); - if (detaching) detach_dev(button1); - if (detaching) detach_dev(t14); - if (detaching) detach_dev(button2); - if (detaching) detach_dev(t16); - if (detaching) detach_dev(hr1); - if (detaching) detach_dev(t17); - if (detaching) detach_dev(button3); - if (detaching) detach_dev(t19); - if (detaching) detach_dev(textarea1); - mounted = false; - run_all(dispose); - } - }; + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$6.name, - type: "component", - source: "", - ctx - }); + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } - return block; - } + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } - function instance$6($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('DeliberateSubconciousRepititionPractice', slots, []); - let textInput = ''; - let items = []; - let running = false; - let selectedItem = null; - let intervalId = null; - let counts = {}; - let totalCountLimit = 10; // Default limit, can be changed by the user - let allWordsLimitReached = false; - let simulationResult = ''; // Variable to hold the result of the simulation + if (is_EOL(ch)) break; - function updateItems() { - items = textInput.split(/\W+/).filter(word => word.trim() !== '').map(word => ({ id: word, text: word })); // Use word itself as the ID - $$invalidate(2, counts = items.reduce((acc, item) => ({ ...acc, [item.id]: 0 }), {})); - } + _position = state.position; - function start() { - if (!running && items.length > 0) { - running = true; + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } - intervalId = setInterval( - () => { - // Filter out items that have reached the totalCountLimit - const eligibleItems = items.filter(item => counts[item.id] < totalCountLimit); + directiveArgs.push(state.input.slice(_position, state.position)); + } - // If there are no eligible items left, stop the timer - if (eligibleItems.length === 0) { - stop(); - $$invalidate(4, allWordsLimitReached = true); // Set when all words reach the limit - return; - } + if (ch !== 0) readLineBreak(state); - // Select a random item from the eligible items - const randomIndex = Math.floor(Math.random() * eligibleItems.length); + if (_hasOwnProperty$1.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } - $$invalidate(1, selectedItem = eligibleItems[randomIndex]); - $$invalidate(2, counts[selectedItem.id]++, counts); - }, - 1000 - ); - } - } + skipSeparationSpace(state, true, -1); - function stop() { - if (running) { - clearInterval(intervalId); - running = false; - intervalId = null; - } - } + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); - function exportCounts() { - const dataStr = JSON.stringify(counts); - const blob = new Blob([dataStr], { type: "application/json" }); - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.download = "counts.json"; - link.href = url; - link.click(); - } + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } - function importCounts(event) { - const fileReader = new FileReader(); + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); - fileReader.onload = e => { - const data = JSON.parse(e.target.result); - $$invalidate(2, counts = { ...counts, ...data }); + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } - items = Object.keys(data).map((word, index) => ({ - id: word, // Use word itself as the ID - text: word - })); + state.documents.push(state.result); - // Ensure existing items are updated if they are not in the imported data - items.forEach(item => { - if (!counts[item.id]) { - $$invalidate(2, counts[item.id] = 0, counts); - } - }); - }; + if (state.position === state.lineStart && testDocumentSeparator(state)) { - fileReader.readAsText(event.target.files[0]); - } + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } - // ... (other variables and functions remain unchanged) - function simulateCount() { - let simulatedTime = 0; - let maxSimulatedSeconds = 3600; // 3600 seconds = 1 hour - let simulationOutput = ""; // Accumulate output here + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } + } - // Reset the allWordsLimitReached flag and simulationResult - $$invalidate(4, allWordsLimitReached = false); - $$invalidate(5, simulationResult = ''); + function loadDocuments(input, options) { + input = String(input); + options = options || {}; - // Simulate until max time is reached or all words hit the limit - while (simulatedTime < maxSimulatedSeconds && !allWordsLimitReached) { - const eligibleItems = items.filter(item => counts[item.id] < totalCountLimit); + if (input.length !== 0) { - if (eligibleItems.length === 0) { - $$invalidate(4, allWordsLimitReached = true); // Set when all words reach the limit - break; // Exit the loop if all words hit the limit - } + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } - // Select a random item and increment its count - const randomIndex = Math.floor(Math.random() * eligibleItems.length); + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } - $$invalidate(1, selectedItem = eligibleItems[randomIndex]); - $$invalidate(2, counts[selectedItem.id]++, counts); - simulationOutput += selectedItem.text + " "; // Append selected word to output + var state = new State$1(input, options); - // Increment simulated time (equivalent to the time between iterations in the real scenario) - simulatedTime++; - } + var nullpos = input.indexOf('\0'); - // Update simulationResult with a message - if (allWordsLimitReached) { - $$invalidate(5, simulationResult = "All words have reached the count limit during simulation."); - } else { - $$invalidate(5, simulationResult = `Simulation finished after ${simulatedTime} seconds.`); - } + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, 'null byte is not allowed in input'); + } - // Export the simulation output to a text file - exportSimulationOutput(simulationOutput); - } + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; - function exportSimulationOutput(output) { - if (output) { - const blob = new Blob([output], { type: "text/plain" }); - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.download = "simulation_output.txt"; - link.href = url; - link.click(); - } else { - console.error("No simulation output to export."); - $$invalidate(5, simulationResult = "No simulation output to export."); - } - } + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } - onDestroy(() => { - if (intervalId) { - clearInterval(intervalId); - } - }); + while (state.position < (state.length - 1)) { + readDocument(state); + } - const writable_props = []; + return state.documents; + } - Object_1$1.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$2.warn(` was created with unknown prop '${key}'`); - }); - function textarea0_input_handler() { - textInput = this.value; - $$invalidate(0, textInput); - } + function loadAll$1(input, iterator, options) { + if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { + options = iterator; + iterator = null; + } - function input1_input_handler() { - totalCountLimit = to_number(this.value); - $$invalidate(3, totalCountLimit); - } + var documents = loadDocuments(input, options); - function textarea1_input_handler() { - simulationResult = this.value; - $$invalidate(5, simulationResult); - } + if (typeof iterator !== 'function') { + return documents; + } - $$self.$capture_state = () => ({ - onDestroy, - textInput, - items, - running, - selectedItem, - intervalId, - counts, - totalCountLimit, - allWordsLimitReached, - simulationResult, - updateItems, - start, - stop, - exportCounts, - importCounts, - simulateCount, - exportSimulationOutput - }); + for (var index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } + } - $$self.$inject_state = $$props => { - if ('textInput' in $$props) $$invalidate(0, textInput = $$props.textInput); - if ('items' in $$props) items = $$props.items; - if ('running' in $$props) running = $$props.running; - if ('selectedItem' in $$props) $$invalidate(1, selectedItem = $$props.selectedItem); - if ('intervalId' in $$props) intervalId = $$props.intervalId; - if ('counts' in $$props) $$invalidate(2, counts = $$props.counts); - if ('totalCountLimit' in $$props) $$invalidate(3, totalCountLimit = $$props.totalCountLimit); - if ('allWordsLimitReached' in $$props) $$invalidate(4, allWordsLimitReached = $$props.allWordsLimitReached); - if ('simulationResult' in $$props) $$invalidate(5, simulationResult = $$props.simulationResult); - }; - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + function load$1(input, options) { + var documents = loadDocuments(input, options); - return [ - textInput, - selectedItem, - counts, - totalCountLimit, - allWordsLimitReached, - simulationResult, - updateItems, - start, - stop, - exportCounts, - importCounts, - simulateCount, - textarea0_input_handler, - input1_input_handler, - textarea1_input_handler - ]; + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new exception('expected a single document in the stream, but found more'); } - class DeliberateSubconciousRepititionPractice extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$6, create_fragment$6, safe_not_equal, {}); - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "DeliberateSubconciousRepititionPractice", - options, - id: create_fragment$6.name - }); - } + var loadAll_1 = loadAll$1; + var load_1 = load$1; + + var loader = { + loadAll: loadAll_1, + load: load_1 + }; + + /*eslint-disable no-use-before-define*/ + + + + + + var _toString = Object.prototype.toString; + var _hasOwnProperty = Object.prototype.hasOwnProperty; + + var CHAR_BOM = 0xFEFF; + var CHAR_TAB = 0x09; /* Tab */ + var CHAR_LINE_FEED = 0x0A; /* LF */ + var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ + var CHAR_SPACE = 0x20; /* Space */ + var CHAR_EXCLAMATION = 0x21; /* ! */ + var CHAR_DOUBLE_QUOTE = 0x22; /* " */ + var CHAR_SHARP = 0x23; /* # */ + var CHAR_PERCENT = 0x25; /* % */ + var CHAR_AMPERSAND = 0x26; /* & */ + var CHAR_SINGLE_QUOTE = 0x27; /* ' */ + var CHAR_ASTERISK = 0x2A; /* * */ + var CHAR_COMMA = 0x2C; /* , */ + var CHAR_MINUS = 0x2D; /* - */ + var CHAR_COLON = 0x3A; /* : */ + var CHAR_EQUALS = 0x3D; /* = */ + var CHAR_GREATER_THAN = 0x3E; /* > */ + var CHAR_QUESTION = 0x3F; /* ? */ + var CHAR_COMMERCIAL_AT = 0x40; /* @ */ + var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ + var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ + var CHAR_GRAVE_ACCENT = 0x60; /* ` */ + var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ + var CHAR_VERTICAL_LINE = 0x7C; /* | */ + var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + + var ESCAPE_SEQUENCES = {}; + + ESCAPE_SEQUENCES[0x00] = '\\0'; + ESCAPE_SEQUENCES[0x07] = '\\a'; + ESCAPE_SEQUENCES[0x08] = '\\b'; + ESCAPE_SEQUENCES[0x09] = '\\t'; + ESCAPE_SEQUENCES[0x0A] = '\\n'; + ESCAPE_SEQUENCES[0x0B] = '\\v'; + ESCAPE_SEQUENCES[0x0C] = '\\f'; + ESCAPE_SEQUENCES[0x0D] = '\\r'; + ESCAPE_SEQUENCES[0x1B] = '\\e'; + ESCAPE_SEQUENCES[0x22] = '\\"'; + ESCAPE_SEQUENCES[0x5C] = '\\\\'; + ESCAPE_SEQUENCES[0x85] = '\\N'; + ESCAPE_SEQUENCES[0xA0] = '\\_'; + ESCAPE_SEQUENCES[0x2028] = '\\L'; + ESCAPE_SEQUENCES[0x2029] = '\\P'; + + var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' + ]; + + var DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + + function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; } - /* src\LLMWorkflowTest.svelte generated by Svelte v3.59.2 */ + function encodeHex(character) { + var string, handle, length; - const { Object: Object_1, console: console_1$1 } = globals; - const file$5 = "src\\LLMWorkflowTest.svelte"; + string = character.toString(16).toUpperCase(); - function get_each_context$3(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[10] = list[i]; - child_ctx[11] = list; - child_ctx[12] = i; - return child_ctx; + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new exception('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; + } + + + var QUOTING_TYPE_SINGLE = 1, + QUOTING_TYPE_DOUBLE = 2; + + function State(options) { + this.schema = options['schema'] || _default; + this.indent = Math.max(1, (options['indent'] || 2)); + this.noArrayIndent = options['noArrayIndent'] || false; + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + this.condenseFlow = options['condenseFlow'] || false; + this.quotingType = options['quotingType'] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE; + this.forceQuotes = options['forceQuotes'] || false; + this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; + } + + // Indents every line in a string. Empty lines (\n only) are not indented. + function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; } - function get_each_context_1$2(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[13] = list[i]; - return child_ctx; + function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); } - // (87:4) {#each Object.keys(workflows) as workflow} - function create_each_block_1$2(ctx) { - let option; - let t_value = /*workflow*/ ctx[13] + ""; - let t; + function testImplicitResolving(state, str) { + var index, length, type; - const block = { - c: function create() { - option = element("option"); - t = text(t_value); - option.__value = /*workflow*/ ctx[13]; - option.value = option.__value; - add_location(option, file$5, 87, 6, 2693); - }, - m: function mount(target, anchor) { - insert_dev(target, option, anchor); - append_dev(option, t); - }, - p: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(option); - } - }; + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block_1$2.name, - type: "each", - source: "(87:4) {#each Object.keys(workflows) as workflow}", - ctx - }); + if (type.resolve(str)) { + return true; + } + } - return block; + return false; + } + + // [33] s-white ::= s-space | s-tab + function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; + } + + // Returns true if the character can be printed without escaping. + // From YAML 1.2: "any allowed characters known to be non-printable + // should also be escaped. [However,] This isn’t mandatory" + // Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. + function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== CHAR_BOM) + || (0x10000 <= c && c <= 0x10FFFF); + } + + // [34] ns-char ::= nb-char - s-white + // [27] nb-char ::= c-printable - b-char - c-byte-order-mark + // [26] b-char ::= b-line-feed | b-carriage-return + // Including s-white (for some reason, examples doesn't match specs in this aspect) + // ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark + function isNsCharOrWhitespace(c) { + return isPrintable(c) + && c !== CHAR_BOM + // - b-char + && c !== CHAR_CARRIAGE_RETURN + && c !== CHAR_LINE_FEED; + } + + // [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out + // c = flow-in ⇒ ns-plain-safe-in + // c = block-key ⇒ ns-plain-safe-out + // c = flow-key ⇒ ns-plain-safe-in + // [128] ns-plain-safe-out ::= ns-char + // [129] ns-plain-safe-in ::= ns-char - c-flow-indicator + // [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” ) + // | ( /* An ns-char preceding */ “#” ) + // | ( “:” /* Followed by an ns-plain-safe(c) */ ) + function isPlainSafe(c, prev, inblock) { + var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return ( + // ns-plain-safe + inblock ? // c = flow-in + cIsNsCharOrWhitespace + : cIsNsCharOrWhitespace + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + ) + // ns-plain-char + && c !== CHAR_SHARP // false on '#' + && !(prev === CHAR_COLON && !cIsNsChar) // false on ': ' + || (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) // change to true on '[^ ]#' + || (prev === CHAR_COLON && cIsNsChar); // change to true on ':[^ ]' + } + + // Simplified test for values allowed as the first character in plain style. + function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part + return isPrintable(c) && c !== CHAR_BOM + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_EQUALS + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; + } + + // Simplified test for values allowed as the last character in plain style. + function isPlainSafeLast(c) { + // just not whitespace or colon, it will be checked to be plain character later + return !isWhitespace(c) && c !== CHAR_COLON; + } + + // Same as 'string'.codePointAt(pos), but works in older browsers. + function codePointAt(string, pos) { + var first = string.charCodeAt(pos), second; + if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; + } + + // Determines whether block indentation indicator is required. + function needIndentIndicator(string) { + var leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); + } + + var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + + // Determines which scalar styles are possible and returns the preferred style. + // lineWidth = -1 => no limit. + // Pre-conditions: str.length > 0. + // Post-conditions: + // STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. + // STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). + // STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). + function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, + testAmbiguousType, quotingType, forceQuotes, inblock) { + + var i; + var char = 0; + var prevChar = null; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(codePointAt(string, 0)) + && isPlainSafeLast(codePointAt(string, string.length - 1)); + + if (singleLineOnly || forceQuotes) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + + // Note: line breaking/folding is implemented for only the folded style. + // NB. We drop the last trailing newline (if any) of a returned block scalar + // since the dumper adds its own newline. This always works: + // • No ending newline => unaffected; already using strip "-" chomping. + // • Ending newline => removed then restored. + // Importantly, this keeps the "+" chomp indicator from gaining an extra line. + function writeScalar(state, string, level, iskey, inblock) { + state.dump = (function () { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? ('"' + string + '"') : ("'" + string + "'"); + } + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, + testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) { + + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string) + '"'; + default: + throw new exception('impossible error: invalid scalar style'); + } + }()); + } + + // Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. + function blockHeader(string, indentPerLevel) { + var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; + } + + // (See the note for writeScalar.) + function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; + } + + // Note: a long line without a suitable break point will exceed the width limit. + // Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. + function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; + } + + // Greedy line breaking. + // Picks the longest line under the limit each time, + // otherwise settles for the shortest line over the limit. + // NB. More-indented lines *cannot* be folded, as that would add an extra \n. + function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner } - // (92:2) {#each placeholderInputs as placeholder} - function create_each_block$3(ctx) { - let div; - let label; - let t0; - let t1_value = /*placeholder*/ ctx[10] + ""; - let t1; - let t2; - let t3; - let input; - let mounted; - let dispose; + // Escapes a double-quoted string. + function escapeString(string) { + var result = ''; + var char = 0; + var escapeSeq; - function input_input_handler() { - /*input_input_handler*/ ctx[8].call(input, /*placeholder*/ ctx[10]); - } + for (var i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + escapeSeq = ESCAPE_SEQUENCES[char]; - const block = { - c: function create() { - div = element("div"); - label = element("label"); - t0 = text("Enter word for <"); - t1 = text(t1_value); - t2 = text(">"); - t3 = space(); - input = element("input"); - add_location(label, file$5, 93, 6, 2828); - attr_dev(input, "type", "text"); - add_location(input, file$5, 94, 6, 2887); - add_location(div, file$5, 92, 4, 2815); - }, - m: function mount(target, anchor) { - insert_dev(target, div, anchor); - append_dev(div, label); - append_dev(label, t0); - append_dev(label, t1); - append_dev(label, t2); - append_dev(div, t3); - append_dev(div, input); - set_input_value(input, /*placeholderValues*/ ctx[1][/*placeholder*/ ctx[10]]); + if (!escapeSeq && isPrintable(char)) { + result += string[i]; + if (char >= 0x10000) result += string[i + 1]; + } else { + result += escapeSeq || encodeHex(char); + } + } - if (!mounted) { - dispose = [ - listen_dev(input, "input", input_input_handler), - listen_dev(input, "input", /*updateInputs*/ ctx[6], false, false, false, false) - ]; + return result; + } - mounted = true; - } - }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; - if (dirty & /*placeholderInputs*/ 4 && t1_value !== (t1_value = /*placeholder*/ ctx[10] + "")) set_data_dev(t1, t1_value); + function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length, + value; - if (dirty & /*placeholderValues, placeholderInputs*/ 6 && input.value !== /*placeholderValues*/ ctx[1][/*placeholder*/ ctx[10]]) { - set_input_value(input, /*placeholderValues*/ ctx[1][/*placeholder*/ ctx[10]]); - } - }, - d: function destroy(detaching) { - if (detaching) detach_dev(div); - mounted = false; - run_all(dispose); - } - }; + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_each_block$3.name, - type: "each", - source: "(92:2) {#each placeholderInputs as placeholder}", - ctx - }); + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } - return block; + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level, value, false, false) || + (typeof value === 'undefined' && + writeNode(state, level, null, false, false))) { + + if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : ''); + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; } - function create_fragment$5(ctx) { - let div1; - let h1; - let t1; - let select; - let t2; - let t3; - let div0; - let t4; - let button; - let mounted; - let dispose; - let each_value_1 = Object.keys(/*workflows*/ ctx[3]); - validate_each_argument(each_value_1); - let each_blocks_1 = []; + function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length, + value; - for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks_1[i] = create_each_block_1$2(get_each_context_1$2(ctx, each_value_1, i)); - } + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; - let each_value = /*placeholderInputs*/ ctx[2]; - validate_each_argument(each_value); - let each_blocks = []; + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } - for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$3(get_each_context$3(ctx, each_value, i)); - } + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level + 1, value, true, true, false, true) || + (typeof value === 'undefined' && + writeNode(state, level + 1, null, true, true, false, true))) { - const block = { - c: function create() { - div1 = element("div"); - h1 = element("h1"); - h1.textContent = "Incompelete Workflow Interface"; - t1 = space(); - select = element("select"); + if (!compact || _result !== '') { + _result += generateNextLine(state, level); + } - for (let i = 0; i < each_blocks_1.length; i += 1) { - each_blocks_1[i].c(); - } + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += '-'; + } else { + _result += '- '; + } - t2 = space(); + _result += state.dump; + } + } - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. + } - t3 = space(); - div0 = element("div"); - t4 = space(); - button = element("button"); - button.textContent = "Submit"; - add_location(h1, file$5, 84, 2, 2523); - if (/*selectedWorkflow*/ ctx[0] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[7].call(select)); - add_location(select, file$5, 85, 2, 2566); - attr_dev(div0, "id", "input-group"); - add_location(div0, file$5, 102, 2, 3039); - add_location(button, file$5, 104, 2, 3073); - add_location(div1, file$5, 83, 0, 2514); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, div1, anchor); - append_dev(div1, h1); - append_dev(div1, t1); - append_dev(div1, select); + function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; - for (let i = 0; i < each_blocks_1.length; i += 1) { - if (each_blocks_1[i]) { - each_blocks_1[i].m(select, null); - } - } + for (index = 0, length = objectKeyList.length; index < length; index += 1) { - select_option(select, /*selectedWorkflow*/ ctx[0], true); - append_dev(div1, t2); + pairBuffer = ''; + if (_result !== '') pairBuffer += ', '; - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(div1, null); - } - } + if (state.condenseFlow) pairBuffer += '"'; - append_dev(div1, t3); - append_dev(div1, div0); - append_dev(div1, t4); - append_dev(div1, button); + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; - if (!mounted) { - dispose = [ - listen_dev(select, "change", /*select_change_handler*/ ctx[7]), - listen_dev(select, "change", /*handleWorkflowChange*/ ctx[4], false, false, false, false), - listen_dev(button, "click", /*processInputs*/ ctx[5], false, false, false, false) - ]; + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } - mounted = true; - } - }, - p: function update(ctx, [dirty]) { - if (dirty & /*Object, workflows*/ 8) { - each_value_1 = Object.keys(/*workflows*/ ctx[3]); - validate_each_argument(each_value_1); - let i; + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } - for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1$2(ctx, each_value_1, i); + if (state.dump.length > 1024) pairBuffer += '? '; - if (each_blocks_1[i]) { - each_blocks_1[i].p(child_ctx, dirty); - } else { - each_blocks_1[i] = create_each_block_1$2(child_ctx); - each_blocks_1[i].c(); - each_blocks_1[i].m(select, null); - } - } + pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' '); - for (; i < each_blocks_1.length; i += 1) { - each_blocks_1[i].d(1); - } + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } - each_blocks_1.length = each_value_1.length; - } + pairBuffer += state.dump; - if (dirty & /*selectedWorkflow, Object, workflows*/ 9) { - select_option(select, /*selectedWorkflow*/ ctx[0]); - } + // Both key and value are valid. + _result += pairBuffer; + } - if (dirty & /*placeholderValues, placeholderInputs, updateInputs*/ 70) { - each_value = /*placeholderInputs*/ ctx[2]; - validate_each_argument(each_value); - let i; + state.tag = _tag; + state.dump = '{' + _result + '}'; + } + + function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new exception('sortKeys must be a boolean or a function'); + } - for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$3(ctx, each_value, i); + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; - if (each_blocks[i]) { - each_blocks[i].p(child_ctx, dirty); - } else { - each_blocks[i] = create_each_block$3(child_ctx); - each_blocks[i].c(); - each_blocks[i].m(div1, t3); - } - } + if (!compact || _result !== '') { + pairBuffer += generateNextLine(state, level); + } - for (; i < each_blocks.length; i += 1) { - each_blocks[i].d(1); - } + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; - each_blocks.length = each_value.length; - } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(div1); - destroy_each(each_blocks_1, detaching); - destroy_each(each_blocks, detaching); - mounted = false; - run_all(dispose); - } - }; + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$5.name, - type: "component", - source: "", - ctx - }); + pairBuffer += state.dump; - return block; - } + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } - function instance$5($$self, $$props, $$invalidate) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('LLMWorkflowTest', slots, []); + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } - let workflows = { - "Merged Spelling": { - steps: [ - "Please make an image description the meaning of the word ", - "next please find english words close in spelling to ", - "great, next make an image description using those words", - "Thanks lets now merge the two seperate image descriptions together" - ], - placeholders: { "": "much", "": "henduo" }, - timeline: [[], 1, [1], [0, 2]] - }, - "Another Workflow": { - steps: [ - "Do something with ", - "Then do something else with " - ], - placeholders: { - "": "value1", - "": "value2" - }, - timeline: [[], 1] - } - }; + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } - let selectedWorkflow = "Merged Spelling"; - let placeholderValues = workflows[selectedWorkflow].placeholders; - let placeholderInputs = Object.keys(placeholderValues); - let timeline = workflows[selectedWorkflow].timeline; + pairBuffer += state.dump; - function handleWorkflowChange() { - $$invalidate(1, placeholderValues = workflows[selectedWorkflow].placeholders); - $$invalidate(2, placeholderInputs = Object.keys(placeholderValues)); - timeline = workflows[selectedWorkflow].timeline; - updateInputs(); - } + // Both key and value are valid. + _result += pairBuffer; + } - function processInputs() { - const inputs = document.querySelectorAll('input[type="text"]'); - console.log(`Workflow: ${selectedWorkflow}`); + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. + } - inputs.forEach((input, i) => { - console.log(`Step ${i + 1}: ${input.value}`); - }); - } + function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; - onMount(() => { - handleWorkflowChange(); - updateInputs(); - }); + typeList = explicit ? state.explicitTypes : state.implicitTypes; - function updateInputs() { - const inputGroup = document.getElementById('input-group'); - inputGroup.innerHTML = ''; - const steps = workflows[selectedWorkflow].steps; + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; - steps.forEach((step, i) => { - const label = placeholderInputs.reduce((updatedStep, placeholder) => updatedStep.replace(new RegExp(placeholder, 'g'), placeholderValues[placeholder]), step); + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { - const dependencyText = Array.isArray(timeline[i]) - ? timeline[i].join(', ') - : timeline[i]; + if (explicit) { + if (type.multi && type.representName) { + state.tag = type.representName(object); + } else { + state.tag = type.tag; + } + } else { + state.tag = '?'; + } + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new exception('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } - const inputBox = ` -
- - - ${timeline[i].length > 0 - ? `Output depends on: ${dependencyText}` - : ''} -
- `; + state.dump = _result; + } - inputGroup.innerHTML += inputBox; - }); - } + return true; + } + } - const writable_props = []; + return false; + } - Object_1.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1$1.warn(` was created with unknown prop '${key}'`); - }); + // Serializes `object` and writes it to global `result`. + // Returns true on success, or false on invalid object. + // + function writeNode(state, level, object, block, compact, iskey, isblockseq) { + state.tag = null; + state.dump = object; - function select_change_handler() { - selectedWorkflow = select_value(this); - $$invalidate(0, selectedWorkflow); - $$invalidate(3, workflows); - } + if (!detectType(state, object, false)) { + detectType(state, object, true); + } - function input_input_handler(placeholder) { - placeholderValues[placeholder] = this.value; - $$invalidate(1, placeholderValues); - } + var type = _toString.call(state.dump); + var inblock = block; + var tagStr; - $$self.$capture_state = () => ({ - onMount, - workflows, - selectedWorkflow, - placeholderValues, - placeholderInputs, - timeline, - handleWorkflowChange, - processInputs, - updateInputs - }); + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } - $$self.$inject_state = $$props => { - if ('workflows' in $$props) $$invalidate(3, workflows = $$props.workflows); - if ('selectedWorkflow' in $$props) $$invalidate(0, selectedWorkflow = $$props.selectedWorkflow); - if ('placeholderValues' in $$props) $$invalidate(1, placeholderValues = $$props.placeholderValues); - if ('placeholderInputs' in $$props) $$invalidate(2, placeholderInputs = $$props.placeholderInputs); - if ('timeline' in $$props) timeline = $$props.timeline; - }; + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } - return [ - selectedWorkflow, - placeholderValues, - placeholderInputs, - workflows, - handleWorkflowChange, - processInputs, - updateInputs, - select_change_handler, - input_input_handler - ]; - } + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } - class LLMWorkflowTest extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$5, create_fragment$5, safe_not_equal, {}); + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact); + } else { + writeBlockSequence(state, level, state.dump, compact); + } + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey, inblock); + } + } else if (type === '[object Undefined]') { + return false; + } else { + if (state.skipInvalid) return false; + throw new exception('unacceptable kind of an object to dump ' + type); + } - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "LLMWorkflowTest", - options, - id: create_fragment$5.name - }); - } + if (state.tag !== null && state.tag !== '?') { + // Need to encode all characters except those allowed by the spec: + // + // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */ + // [36] ns-hex-digit ::= ns-dec-digit + // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */ + // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */ + // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-” + // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#” + // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,” + // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]” + // + // Also need to encode '!' because it has special meaning (end of tag prefix). + // + tagStr = encodeURI( + state.tag[0] === '!' ? state.tag.slice(1) : state.tag + ).replace(/!/g, '%21'); + + if (state.tag[0] === '!') { + tagStr = '!' + tagStr; + } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') { + tagStr = '!!' + tagStr.slice(18); + } else { + tagStr = '!<' + tagStr + '>'; + } + + state.dump = tagStr + ' ' + state.dump; + } + } + + return true; } - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; - function getDefaultExportFromCjs (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; - } + inspectNode(object, objects, duplicatesIndexes); - function commonjsRequire(path) { - throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); + } + + function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } } - var jszip_min = {exports: {}}; + function dump$1(input, options) { + options = options || {}; - /*! + var state = new State(options); - JSZip v3.10.1 - A JavaScript class for generating and reading zip files - + if (!state.noRefs) getDuplicateReferences(input, state); - (c) 2009-2016 Stuart Knightley - Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown. + var value = input; - JSZip uses the library pako released under the MIT license : - https://github.com/nodeca/pako/blob/main/LICENSE - */ + if (state.replacer) { + value = state.replacer.call({ '': value }, '', value); + } - (function (module, exports) { - !function(e){module.exports=e();}(function(){return function s(a,o,h){function u(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof commonjsRequire&&commonjsRequire;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return u(t||e)},i,i.exports,s,a,o,h);}return o[r].exports}for(var l="function"==typeof commonjsRequire&&commonjsRequire,e=0;e>2,s=(3&t)<<4|r>>4,a=1>6:64,o=2>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),l[h++]=t,64!==s&&(l[h++]=r),64!==a&&(l[h++]=n);return l};},{"./support":30,"./utils":32}],2:[function(e,t,r){var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i;}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o;},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate");},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){var n=e("./utils");var o=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e;}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return -1^e}(0|t,e,e.length,0):function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t.charCodeAt(a))];return -1^e}(0|t,e,e.length,0):0};},{"./utils":32}],5:[function(e,t,r){r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null;},{}],6:[function(e,t,r){var n=null;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n};},{lie:37}],7:[function(e,t,r){var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function h(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={};}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1);},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0);},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null;},h.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta});};},r.compressWorker=function(e){return new h("Deflate",e)},r.uncompressWorker=function(){return new h("Inflate",{})};},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,r){function A(e,t){var r,n="";for(r=0;r>>=8;return n}function n(e,t,r,n,i,s){var a,o,h=e.file,u=e.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),c=I.transformTo("string",O.utf8encode(h.name)),d=h.comment,p=I.transformTo("string",s(d)),m=I.transformTo("string",O.utf8encode(d)),_=c.length!==h.name.length,g=m.length!==d.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};t&&!r||(x.crc32=e.crc32,x.compressedSize=e.compressedSize,x.uncompressedSize=e.uncompressedSize);var S=0;t&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===i?(C=798,z|=function(e,t){var r=e;return e||(r=t?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(e){return 63&(e||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+c,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(n,4)+f+b+p}}var I=e("../utils"),i=e("../stream/GenericWorker"),O=e("../utf8"),B=e("../crc32"),R=e("../signature");function s(e,t,r,n){i.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=t,this.zipPlatform=r,this.encodeFileName=n,this.streamFiles=e,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[];}I.inherits(s,i),s.prototype.push=function(e){var t=e.meta.percent||0,r=this.entriesCount,n=this._sources.length;this.accumulate?this.contentBuffer.push(e):(this.bytesWritten+=e.data.length,i.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:r?(t+100*(r-n-1))/r:100}}));},s.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten,this.currentFile=e.file.name;var t=this.streamFiles&&!e.file.dir;if(t){var r=n(e,t,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}});}else this.accumulate=!0;},s.prototype.closedSource=function(e){this.accumulate=!1;var t=this.streamFiles&&!e.file.dir,r=n(e,t,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),t)this.push({data:function(e){return R.DATA_DESCRIPTOR+A(e.crc32,4)+A(e.compressedSize,4)+A(e.uncompressedSize,4)}(e),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null;},s.prototype.flush=function(){for(var e=this.bytesWritten,t=0;t=this.index;t--)r=(r<<8)+this.byteAt(t);return this.index+=e,r},readString:function(e){return n.transformTo("string",this.readData(e))},readData:function(){},lastIndexOfSignature:function(){},readAndCheckSignature:function(){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC(1980+(e>>25&127),(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(31&e)<<1))}},t.exports=i;},{"../utils":32}],19:[function(e,t,r){var n=e("./Uint8ArrayReader");function i(e){n.call(this,e);}e("../utils").inherits(i,n),i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i;},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){var n=e("./DataReader");function i(e){n.call(this,e);}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i;},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){var n=e("./ArrayReader");function i(e){n.call(this,e);}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i;},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),h=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new h(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)};},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b";},{}],24:[function(e,t,r){var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e;}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta});},t.exports=s;},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0);}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e);},t.exports=s;},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0);}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length;}i.prototype.processChunk.call(this,e);},t.exports=s;},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat();},function(e){t.error(e);});}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null;},s.prototype.resume=function(){return !!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0));},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return !1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t);}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s;},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null;}n.prototype={push:function(e){this.emit("data",e);},end:function(){if(this.isFinished)return !1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0;}catch(e){this.emit("error",e);}return !0},error:function(e){return !this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[];},emit:function(e,t){if(this._listeners[e])for(var r=0;r "+e:e}},t.exports=n;},{}],29:[function(e,t,r){var h=e("../utils"),i=e("./ConvertWorker"),s=e("./GenericWorker"),u=e("../base64"),n=e("../support"),a=e("../external"),o=null;if(n.nodestream)try{o=e("../nodejs/NodejsStreamOutputAdapter");}catch(e){}function l(e,o){return new a.Promise(function(t,r){var n=[],i=e._internalType,s=e._outputType,a=e._mimeType;e.on("data",function(e,t){n.push(e),o&&o(t);}).on("error",function(e){n=[],r(e);}).on("end",function(){try{var e=function(e,t,r){switch(e){case"blob":return h.newBlob(h.transformTo("arraybuffer",t),r);case"base64":return u.encode(t);default:return h.transformTo(e,t)}}(s,function(e,t){var r,n=0,i=null,s=0;for(r=0;r>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t}(e)},s.utf8decode=function(e){return h.nodebuffer?o.transformTo("nodebuffer",e).toString("utf-8"):function(e){var t,r,n,i,s=e.length,a=new Array(2*s);for(t=r=0;t>10&1023,a[r++]=56320|1023&n);}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(h.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length);}else t=this.leftOver.concat(t);this.leftOver=null;}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}(t),i=t;n!==t.length&&(h.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta});},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null);},s.Utf8DecodeWorker=a,o.inherits(l,n),l.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta});},s.Utf8EncodeWorker=l;},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,a){var o=e("./support"),h=e("./base64"),r=e("./nodejsUtils"),u=e("./external");function n(e){return e}function l(e,t){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0);},parseZIP64ExtraField:function(){if(this.extraFields[1]){var e=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4));}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t},r.buf2binstring=function(e){return l(e,e.length)},r.binstring2buf=function(e){for(var t=new h.Buf8(e.length),r=0,n=t.length;r>10&1023,o[n++]=56320|1023&i);}return l(o,n)},r.utf8border=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t};},{"./common":41}],43:[function(e,t,r){t.exports=function(e,t,r,n){for(var i=65535&e|0,s=e>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:e>>>1;t[r]=e;}return t}();t.exports=function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return -1^e};},{}],46:[function(e,t,r){var h,c=e("../utils/common"),u=e("./trees"),d=e("./adler32"),p=e("./crc32"),n=e("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,i=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(e,t){return e.msg=n[t],t}function T(e){return (e<<1)-(4e.avail_out&&(r=e.avail_out),0!==r&&(c.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0));}function N(e,t){u._tr_flush_block(e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,F(e.strm);}function U(e,t){e.pending_buf[e.pending++]=t;}function P(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t;}function L(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,h=e.strstart>e.w_size-z?e.strstart-(e.w_size-z):0,u=e.window,l=e.w_mask,f=e.prev,c=e.strstart+S,d=u[s+a-1],p=u[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(u[(r=t)+a]===p&&u[r+a-1]===d&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--i);return a<=e.lookahead?a:e.lookahead}function j(e){var t,r,n,i,s,a,o,h,u,l,f=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-z)){for(c.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;n=e.head[--t],e.head[t]=f<=n?n-f:0,--r;);for(t=r=f;n=e.prev[--t],e.prev[t]=f<=n?n-f:0,--r;);i+=f;}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,h=e.strstart+e.lookahead,u=i,l=void 0,l=a.avail_in,u=x)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x)if(n=u._tr_tally(e,e.strstart-e.match_start,e.match_length-x),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=x){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-x,n=u._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-x),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(j(e),0===e.lookahead&&t===l)return A;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+r;if((0===e.strstart||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,N(e,!1),0===e.strm.avail_out))return A;if(e.strstart-e.block_start>=e.w_size-z&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):(e.strstart>e.block_start&&(N(e,!1),e.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(e,t){return Y(e,t,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?_:(e.state.gzhead=t,m):_},r.deflate=function(e,t){var r,n,i,s;if(!e||!e.state||5>8&255),U(n,n.gzhead.time>>16&255),U(n,n.gzhead.time>>24&255),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(U(n,255&n.gzhead.extra.length),U(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=p(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(U(n,0),U(n,0),U(n,0),U(n,0),U(n,0),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,3),n.status=E);else {var a=v+(n.w_bits-8<<4)<<8;a|=(2<=n.strategy||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(a|=32),a+=31-a%31,n.status=E,P(n,a),0!==n.strstart&&(P(n,e.adler>>>16),P(n,65535&e.adler)),e.adler=1;}if(69===n.status)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending!==n.pending_buf_size));)U(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73);}else n.status=73;if(73===n.status)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.gzindex=0,n.status=91);}else n.status=91;if(91===n.status)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103);}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&F(e),n.pending+2<=n.pending_buf_size&&(U(n,255&e.adler),U(n,e.adler>>8&255),e.adler=0,n.status=E)):n.status=E),0!==n.pending){if(F(e),0===e.avail_out)return n.last_flush=-1,m}else if(0===e.avail_in&&T(t)<=T(r)&&t!==f)return R(e,-5);if(666===n.status&&0!==e.avail_in)return R(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==l&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(j(e),0===e.lookahead)){if(t===l)return A;break}if(e.match_length=0,r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=S){if(j(e),e.lookahead<=S&&t===l)return A;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=x&&0e.lookahead&&(e.match_length=e.lookahead);}if(e.match_length>=x?(r=u._tr_tally(e,1,e.match_length-x),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):h[n.level].func(n,t);if(o!==O&&o!==B||(n.status=666),o===A||o===O)return 0===e.avail_out&&(n.last_flush=-1),m;if(o===I&&(1===t?u._tr_align(n):5!==t&&(u._tr_stored_block(n,0,0,!1),3===t&&(D(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),F(e),0===e.avail_out))return n.last_flush=-1,m}return t!==f?m:n.wrap<=0?1:(2===n.wrap?(U(n,255&e.adler),U(n,e.adler>>8&255),U(n,e.adler>>16&255),U(n,e.adler>>24&255),U(n,255&e.total_in),U(n,e.total_in>>8&255),U(n,e.total_in>>16&255),U(n,e.total_in>>24&255)):(P(n,e.adler>>>16),P(n,65535&e.adler)),F(e),0=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new c.Buf8(r.w_size),c.arraySet(u,t,l-r.w_size,r.w_size,0),t=u,l=r.w_size),a=e.avail_in,o=e.next_in,h=e.input,e.avail_in=l,e.next_in=0,e.input=t,j(r);r.lookahead>=x;){for(n=r.strstart,i=r.lookahead-(x-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else {if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(d&(1<>>=y,p-=y),p<15&&(d+=z[n++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(d&(1<>>=y,p-=y,(y=s-a)>3,d&=(1<<(p-=w<<3))-1,e.next_in=n,e.next_out=s,e.avail_in=n>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0;}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=P,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new I.Buf32(n),t.distcode=t.distdyn=new I.Buf32(i),t.sane=1,t.back=-1,N):U}function o(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,a(e)):U}function h(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||15=s.wsize?(I.arraySet(s.window,t,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(n<(i=s.wsize-s.wnext)&&(i=n),I.arraySet(s.window,t,r-n,i,s.wnext),(n-=i)?(I.arraySet(s.window,t,r-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=i,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){e.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0;}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(d=r.length)&&(d=o),d&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,n,s,d,k)),512&r.flags&&(r.check=B(r.check,n,d,s)),o-=d,s+=d,r.length-=d),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(d=0;k=n[s+d++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&d>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break e;o--,u+=n[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;u>>>=2,l-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30;}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break e;o--,u+=n[s++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(d=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3;}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=_,l-=_,r.lens[r.have++]=b;else {if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],d=3+(3&u),u>>>=2,l-=2;}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3;}else {for(z=_+7;l>>=_)),u>>>=7,l-=7;}if(r.have+d>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;d--;)r.lens[r.have++]=k;}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=h){e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,R(e,c),a=e.next_out,i=e.output,h=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v;}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra;}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v;}if(u>>>=_,l-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra;}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break e;if(d=c-h,r.offset>d){if((d=r.offset-d)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}p=d>r.wnext?(d-=r.wnext,r.wsize-d):r.wnext-d,d>r.length&&(d=r.length),m=r.window;}else m=i,p=a-r.offset,d=r.length;for(hd?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=t[r+a[v]];}if(k>>7)]}function U(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255;}function P(e,t,r){e.bi_valid>d-r?(e.bi_buf|=t<>d-e.bi_valid,e.bi_valid+=r-d):(e.bi_buf|=t<>>=1,r<<=1,0<--t;);return r>>>1}function Z(e,t,r){var n,i,s=new Array(g+1),a=0;for(n=1;n<=g;n++)s[n]=a=a+r[n-1]<<1;for(i=0;i<=t;i++){var o=e[2*i+1];0!==o&&(e[2*i]=j(s[o]++,o));}}function W(e){var t;for(t=0;t>1;1<=r;r--)G(e,s,r);for(i=h;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],G(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,G(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,h=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,f=t.stat_desc.has_stree,c=t.stat_desc.extra_bits,d=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=g;s++)e.bl_count[s]=0;for(h[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<_;r++)p<(s=h[2*h[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),h[2*n+1]=s,u>=7;n>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return o;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return h;for(t=32;t>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?J(e,t,r,n):4===e.strategy||s===i?(P(e,2+(n?1:0),3),K(e,z,C)):(P(e,4+(n?1:0),3),function(e,t,r,n){var i;for(P(e,t-257,5),P(e,r-1,5),P(e,n-4,4),i=0;i>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(A[r]+u+1)]++,e.dyn_dtree[2*N(t)]++),e.last_lit===e.lit_bufsize-1},r._tr_align=function(e){P(e,2,3),L(e,m,z),function(e){16===e.bi_valid?(U(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):8<=e.bi_valid&&(e.pending_buf[e.pending++]=255&e.bi_buf,e.bi_buf>>=8,e.bi_valid-=8);}(e);};},{"../utils/common":41}],53:[function(e,t,r){t.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0;};},{}],54:[function(e,t,r){(function(e){!function(r,n){if(!r.setImmediate){var i,s,t,a,o=1,h={},u=!1,l=r.document,e=Object.getPrototypeOf&&Object.getPrototypeOf(r);e=e&&e.setTimeout?e:r,i="[object process]"==={}.toString.call(r.process)?function(e){process.nextTick(function(){c(e);});}:function(){if(r.postMessage&&!r.importScripts){var e=!0,t=r.onmessage;return r.onmessage=function(){e=!1;},r.postMessage("","*"),r.onmessage=t,e}}()?(a="setImmediate$"+Math.random()+"$",r.addEventListener?r.addEventListener("message",d,!1):r.attachEvent("onmessage",d),function(e){r.postMessage(a+e,"*");}):r.MessageChannel?((t=new MessageChannel).port1.onmessage=function(e){c(e.data);},function(e){t.port2.postMessage(e);}):l&&"onreadystatechange"in l.createElement("script")?(s=l.documentElement,function(e){var t=l.createElement("script");t.onreadystatechange=function(){c(e),t.onreadystatechange=null,s.removeChild(t),t=null;},s.appendChild(t);}):function(e){setTimeout(c,0,e);},e.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),r=0;r $$invalidate(21, $ytsubcurrenttext = $$value)); - validate_store(ytsubcurrentID, 'ytsubcurrentID'); - component_subscribe($$self, ytsubcurrentID, $$value => $$invalidate(22, $ytsubcurrentID = $$value)); - validate_store(ytsubuseplayer, 'ytsubuseplayer'); - component_subscribe($$self, ytsubuseplayer, $$value => $$invalidate(9, $ytsubuseplayer = $$value)); + function instance$2($$self, $$props, $$invalidate) { + let $accumulatedDifferences; + let $changes; let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('PictureSubtitlesbasedonYTTranscript', slots, []); - let zipFile; - let subtitlesOutput = []; //writable([]); - let currentTime = writable(0); // Track current time - let paused = writable(false); // Control pause state - validate_store(paused, 'paused'); - component_subscribe($$self, paused, value => $$invalidate(8, $paused = value)); - let restart = writable(false); // Signal to restart - validate_store(restart, 'restart'); - component_subscribe($$self, restart, value => $$invalidate(20, $restart = value)); - let onlyCurrentSubtitle = writable(false); // Control subtitle display mode - validate_store(onlyCurrentSubtitle, 'onlyCurrentSubtitle'); - component_subscribe($$self, onlyCurrentSubtitle, value => $$invalidate(7, $onlyCurrentSubtitle = value)); - let progress = 0; - let totalDuration = 0; + validate_slots('CodeComparionToolinGraph', slots, []); + let cy1, cy2; + let container1, container2; + let customScenario1 = ""; // Textarea input for custom scenarios for Graph 1 + let customScenario2 = ""; // Textarea input for custom scenarios for Graph 2 + const changes = writable([]); + validate_store(changes, 'changes'); + component_subscribe($$self, changes, value => $$invalidate(5, $changes = value)); + let accumulatedDifferences = writable([]); // To accumulate all differences + validate_store(accumulatedDifferences, 'accumulatedDifferences'); + component_subscribe($$self, accumulatedDifferences, value => $$invalidate(4, $accumulatedDifferences = value)); + + let dummyData1 = [ + { + file: 'ComponentA', + symbols: [ + { id: 'function1', type: 'function' }, + { id: 'variable1', type: 'variable' } + ], + edges: [{ source: 'variable1', target: 'function1' }] + }, + { + file: 'ComponentB', + symbols: [ + { id: 'function2', type: 'function' }, + { id: 'variable2', type: 'variable' } + ], + edges: [{ source: 'variable2', target: 'function2' }] + } + ]; - //let useYTPlayer = writable(false); - let uistatusupdate = null; + let dummyData2 = [ + { + file: 'ComponentC', + symbols: [ + { id: 'function3', type: 'function' }, + { id: 'variable3', type: 'variable' } + ], + edges: [{ source: 'variable3', target: 'function3' }] + }, + { + file: 'ComponentD', + symbols: [ + { id: 'function4', type: 'function' }, + { id: 'variable4', type: 'variable' } + ], + edges: [{ source: 'variable4', target: 'function4' }] + } + ]; - let uiTimeStatus = 0; - let subtitleVideoDetailsFileData = null; - let subtitleVideoTitle = null; + const createGraphElements = data => { + const elements = []; - async function handleFileUpload() { - // Reset the component state - $$invalidate(1, subtitlesOutput = []); + data.forEach(file => { + file.symbols.forEach(symbol => { + elements.push({ + data: { + id: symbol.id, + label: `${symbol.id} (${symbol.type})`, + type: symbol.type + } + }); + }); - currentTime.set(0); - paused.set(false); - restart.set(false); - onlyCurrentSubtitle.set(false); - $$invalidate(2, progress = 0); - $$invalidate(3, totalDuration = 0); + file.edges.forEach(edge => { + elements.push({ + data: { + source: edge.source, + target: edge.target, + type: edge.type + } + }); + }); + }); - if (!zipFile) { - console.log('No zip file selected'); - return; - } + return elements; + }; - const zip = new JSZip(); - const contents = await zip.loadAsync(zipFile); - console.log('Zip file loaded'); - const subtitlesFile = await contents.file('preprocessed_subtitles.json').async('text'); - const subtitlesVideoDetailsFile = await contents.file('YTTVideoInfo.txt'); + const findDifferences = () => { + const nodesGraph1 = new Set(dummyData1.flatMap(file => file.symbols.map(symbol => symbol.id))); + const nodesGraph2 = new Set(dummyData2.flatMap(file => file.symbols.map(symbol => symbol.id))); + const edgesGraph1 = new Set(dummyData1.flatMap(file => file.edges.map(edge => `${edge.source}-${edge.target}`))); + const edgesGraph2 = new Set(dummyData2.flatMap(file => file.edges.map(edge => `${edge.source}-${edge.target}`))); - if (subtitlesVideoDetailsFile) { - const textContent = await subtitlesVideoDetailsFile.async('text'); + const nodeDiffs = [ + ...[...nodesGraph1].filter(x => !nodesGraph2.has(x)).map(id => ({ type: 'missing in graph2', id })), + ...[...nodesGraph2].filter(x => !nodesGraph1.has(x)).map(id => ({ type: 'missing in graph1', id })) + ]; - try { - subtitleVideoDetailsFileData = JSON.parse(textContent); - console.log(subtitleVideoDetailsFileData["video_id"]); + const edgeDiffs = [ + ...[...edgesGraph1].filter(x => !edgesGraph2.has(x)).map(id => ({ type: 'missing in graph2', id })), + ...[...edgesGraph2].filter(x => !edgesGraph1.has(x)).map(id => ({ type: 'missing in graph1', id })) + ]; - if ($ytsubuseplayer) { - set_store_value(ytsubcurrentID, $ytsubcurrentID = subtitleVideoDetailsFileData["video_id"], $ytsubcurrentID); - } + const currentDifferences = [...nodeDiffs, ...edgeDiffs]; + changes.set(currentDifferences); + const timestamp = new Date().toLocaleString(); - $$invalidate(6, subtitleVideoTitle = subtitleVideoDetailsFileData["title"]); - } catch(error) { - console.error('Error parsing JSON:', error); + accumulatedDifferences.update(prev => [ + ...prev, + { + timestamp, + differences: currentDifferences } - } else { - console.error('Text file not found in the ZIP file.'); - } + ]); + }; - const preprocessedSubtitles = JSON.parse(subtitlesFile); - preprocessedSubtitles.sort((a, b) => a.start - b.start); - console.log('Subtitles parsed and sorted'); - $$invalidate(4, uistatusupdate = 'Subtitles parsed and sorted - Syncing to time has started'); - let localTime = 0; - let i = 0; + const loadFromInputArea = graph => { + try { + const customData = jsYaml.load(graph === 1 ? customScenario1 : customScenario2); + const customElements = createGraphElements(customData); + + if (graph === 1) { + dummyData1 = customData; + cy1.elements().remove(); + cy1.add(customElements); + cy1.layout({ name: 'cose', animate: true }).run(); + } else { + dummyData2 = customData; + cy2.elements().remove(); + cy2.add(customElements); + cy2.layout({ name: 'cose', animate: true }).run(); + } - const displayNextSubtitle = async () => { - console.log('Starting displayNextSubtitle'); - $$invalidate(3, totalDuration = preprocessedSubtitles.reduce((total, subtitle) => total + subtitle.duration, 0)); + findDifferences(); + } catch(e) { + alert('Invalid YAML'); + } + }; - while (i < preprocessedSubtitles.length) { - const subtitle = preprocessedSubtitles[i]; - console.log('Current subtitle:', subtitle); - set_store_value(ytsubcurrenttext, $ytsubcurrenttext = subtitle.text, $ytsubcurrenttext); + const fitGraph = graph => { + if (graph === 1) { + cy1.fit(); + } else { + cy2.fit(); + } + }; - if (localTime < subtitle.start) { - await new Promise(resolve => setTimeout(resolve, (subtitle.start - localTime) * 1000)); - console.log('Waited for subtitle start time'); - } + const saveDifferences = () => { + const textToSave = $accumulatedDifferences.map(diffSet => `${diffSet.timestamp}\n${diffSet.differences.map(diff => `${diff.type}: ${diff.id}`).join('\n')}`).join('\n\n'); + const blob = new Blob([textToSave], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'differences.txt'; + a.click(); + URL.revokeObjectURL(url); + }; - if ($paused) { - await new Promise(resolve => paused.subscribe(value => !value && resolve())); - console.log('Resumed from pause'); + onMount(() => { + cy1 = cytoscape({ + container: container1, + elements: createGraphElements(dummyData1), + style: [ + { + selector: 'node', + style: { + 'label': 'data(label)', + 'background-color': '#61bffc', + 'text-valign': 'center', + 'text-halign': 'left' + } + }, + { + selector: 'edge', + style: { + 'line-color': '#61bffc', + 'target-arrow-color': '#61bffc', + 'target-arrow-shape': 'triangle' + } } + ], + layout: { name: 'cose', animate: true } + }); - if ($restart) { - localTime = 0; - i = 0; - $$invalidate(1, subtitlesOutput = []); - restart.set(false); - console.log('Restarted subtitles'); - continue; + cy2 = cytoscape({ + container: container2, + elements: createGraphElements(dummyData2), + style: [ + { + selector: 'node', + style: { + 'label': 'data(label)', + 'background-color': '#ff5733', + 'text-valign': 'center', + 'text-halign': 'left' + } + }, + { + selector: 'edge', + style: { + 'line-color': '#ff5733', + 'target-arrow-color': '#ff5733', + 'target-arrow-shape': 'triangle' + } } + ], + layout: { name: 'cose', animate: true } + }); - const images = await Promise.all(subtitle.image_paths.map(async path => URL.createObjectURL(await contents.file(path).async('blob')))); - - if ($onlyCurrentSubtitle) { - $$invalidate(1, subtitlesOutput = [{ text: subtitle.text, images }]); - } else { - $$invalidate(1, subtitlesOutput = [...subtitlesOutput, { text: subtitle.text, images }]); - } + findDifferences(); + }); - $$invalidate(2, progress = localTime / totalDuration * 100); - await tick(); - console.log('Subtitle added to output:', subtitlesOutput); - await new Promise(resolve => setTimeout(resolve, subtitle.duration * 1000)); - console.log('Waited for subtitle duration'); - ($$invalidate(4, uistatusupdate = 'Waited for subtitle duration')); - $$invalidate(5, uiTimeStatus = localTime); - localTime += subtitle.duration; - i++; - } + onDestroy(() => { + if (cy1) cy1.destroy(); + if (cy2) cy2.destroy(); + }); - console.log('Finished displaying subtitles'); - }; + const writable_props = []; - await displayNextSubtitle(); - console.log('Finished handleFileUpload'); - } + Object.keys($$props).forEach(key => { + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + }); - function pause() { - paused.update(value => !value); + function div0_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + container1 = $$value; + $$invalidate(0, container1); + }); } - function reset() { - restart.set(true); - } + const click_handler = () => fitGraph(1); - function toggleSubtitleMode() { - onlyCurrentSubtitle.update(value => !value); + function div2_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + container2 = $$value; + $$invalidate(1, container2); + }); } - const writable_props = []; - - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1.warn(` was created with unknown prop '${key}'`); - }); + const click_handler_1 = () => fitGraph(2); - function input0_change_handler() { - $ytsubuseplayer = this.checked; - ytsubuseplayer.set($ytsubuseplayer); + function textarea0_input_handler() { + customScenario1 = this.value; + $$invalidate(2, customScenario1); } - const change_handler = e => $$invalidate(0, zipFile = e.target.files[0]); + const click_handler_2 = () => loadFromInputArea(1); - function input2_change_handler() { - $onlyCurrentSubtitle = this.checked; - onlyCurrentSubtitle.set($onlyCurrentSubtitle); + function textarea1_input_handler() { + customScenario2 = this.value; + $$invalidate(3, customScenario2); } + const click_handler_3 = () => loadFromInputArea(2); + $$self.$capture_state = () => ({ onMount, - tick, + onDestroy, + cytoscape, + yaml: jsYaml, writable, - JSZip, - ytsubcurrenttext, - ytsubcurrentID, - ytsubuseplayer, - ytsubuse, - zipFile, - subtitlesOutput, - currentTime, - paused, - restart, - onlyCurrentSubtitle, - progress, - totalDuration, - uistatusupdate, - uiTimeStatus, - subtitleVideoDetailsFileData, - subtitleVideoTitle, - handleFileUpload, - pause, - reset, - toggleSubtitleMode, - $onlyCurrentSubtitle, - $restart, - $paused, - $ytsubcurrenttext, - $ytsubcurrentID, - $ytsubuseplayer + cy1, + cy2, + container1, + container2, + customScenario1, + customScenario2, + changes, + accumulatedDifferences, + dummyData1, + dummyData2, + createGraphElements, + findDifferences, + loadFromInputArea, + fitGraph, + saveDifferences, + $accumulatedDifferences, + $changes }); $$self.$inject_state = $$props => { - if ('zipFile' in $$props) $$invalidate(0, zipFile = $$props.zipFile); - if ('subtitlesOutput' in $$props) $$invalidate(1, subtitlesOutput = $$props.subtitlesOutput); - if ('currentTime' in $$props) currentTime = $$props.currentTime; - if ('paused' in $$props) $$invalidate(10, paused = $$props.paused); - if ('restart' in $$props) $$invalidate(11, restart = $$props.restart); - if ('onlyCurrentSubtitle' in $$props) $$invalidate(12, onlyCurrentSubtitle = $$props.onlyCurrentSubtitle); - if ('progress' in $$props) $$invalidate(2, progress = $$props.progress); - if ('totalDuration' in $$props) $$invalidate(3, totalDuration = $$props.totalDuration); - if ('uistatusupdate' in $$props) $$invalidate(4, uistatusupdate = $$props.uistatusupdate); - if ('uiTimeStatus' in $$props) $$invalidate(5, uiTimeStatus = $$props.uiTimeStatus); - if ('subtitleVideoDetailsFileData' in $$props) subtitleVideoDetailsFileData = $$props.subtitleVideoDetailsFileData; - if ('subtitleVideoTitle' in $$props) $$invalidate(6, subtitleVideoTitle = $$props.subtitleVideoTitle); + if ('cy1' in $$props) cy1 = $$props.cy1; + if ('cy2' in $$props) cy2 = $$props.cy2; + if ('container1' in $$props) $$invalidate(0, container1 = $$props.container1); + if ('container2' in $$props) $$invalidate(1, container2 = $$props.container2); + if ('customScenario1' in $$props) $$invalidate(2, customScenario1 = $$props.customScenario1); + if ('customScenario2' in $$props) $$invalidate(3, customScenario2 = $$props.customScenario2); + if ('accumulatedDifferences' in $$props) $$invalidate(7, accumulatedDifferences = $$props.accumulatedDifferences); + if ('dummyData1' in $$props) dummyData1 = $$props.dummyData1; + if ('dummyData2' in $$props) dummyData2 = $$props.dummyData2; }; if ($$props && "$$inject" in $$props) { @@ -67788,126 +112295,348 @@ var app = (function () { } return [ - zipFile, - subtitlesOutput, - progress, - totalDuration, - uistatusupdate, - uiTimeStatus, - subtitleVideoTitle, - $onlyCurrentSubtitle, - $paused, - $ytsubuseplayer, - paused, - restart, - onlyCurrentSubtitle, - handleFileUpload, - pause, - reset, - input0_change_handler, - change_handler, - input2_change_handler + container1, + container2, + customScenario1, + customScenario2, + $accumulatedDifferences, + $changes, + changes, + accumulatedDifferences, + loadFromInputArea, + fitGraph, + saveDifferences, + div0_binding, + click_handler, + div2_binding, + click_handler_1, + textarea0_input_handler, + click_handler_2, + textarea1_input_handler, + click_handler_3 ]; } - class PictureSubtitlesbasedonYTTranscript extends SvelteComponentDev { + class CodeComparionToolinGraph extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$4, create_fragment$4, safe_not_equal, {}); + init(this, options, instance$2, create_fragment$2, safe_not_equal, {}, null, [-1, -1]); dispatch_dev("SvelteRegisterComponent", { component: this, - tagName: "PictureSubtitlesbasedonYTTranscript", + tagName: "CodeComparionToolinGraph", options, - id: create_fragment$4.name + id: create_fragment$2.name }); } } - /* src\PSWSasspellingpractice.svelte generated by Svelte v3.59.2 */ + /* src\GraphEditLoadTool.svelte generated by Svelte v3.59.2 */ - const file$3 = "src\\PSWSasspellingpractice.svelte"; + const { console: console_1 } = globals; + const file$1 = "src\\GraphEditLoadTool.svelte"; - function get_each_context$1(ctx, list, i) { + function get_each_context(ctx, list, i) { const child_ctx = ctx.slice(); - child_ctx[3] = list[i]; - child_ctx[5] = i; + child_ctx[42] = list[i]; return child_ctx; } function get_each_context_1(ctx, list, i) { const child_ctx = ctx.slice(); - child_ctx[6] = list[i]; + child_ctx[45] = list[i]; return child_ctx; } function get_each_context_2(ctx, list, i) { const child_ctx = ctx.slice(); - child_ctx[9] = list[i]; + child_ctx[45] = list[i]; return child_ctx; } - // (25:8) {#if sentence} - function create_if_block(ctx) { - let h4; + // (383:8) {:else} + function create_else_block_3(ctx) { + let p; + + const block = { + c: function create() { + p = element$1("p"); + p.textContent = "Click on a node to see its data."; + add_location(p, file$1, 383, 10, 11916); + }, + m: function mount(target, anchor) { + insert_dev(target, p, anchor); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(p); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_else_block_3.name, + type: "else", + source: "(383:8) {:else}", + ctx + }); + + return block; + } + + // (362:8) {#if $selectedNodeData} + function create_if_block_3(ctx) { + let pre; + let t0_value = JSON.stringify(/*$selectedNodeData*/ ctx[9], null, 2) + ""; + let t0; let t1; - let div; - let table; - let each_value_1 = extractLetters(/*sentence*/ ctx[3]); - validate_each_argument(each_value_1); + let div0; + let label0; + let t2; + let input0; + let t3; + let label1; + let t4; + let input1; + let t5; + let button0; + let t7; + let div1; + let button1; + let t9; + let button2; + let t11; + let label2; + let t12; + let input2; + let mounted; + let dispose; + + const block = { + c: function create() { + pre = element$1("pre"); + t0 = text(t0_value); + t1 = space(); + div0 = element$1("div"); + label0 = element$1("label"); + t2 = text("Label:\r\n "); + input0 = element$1("input"); + t3 = space(); + label1 = element$1("label"); + t4 = text("Type:\r\n "); + input1 = element$1("input"); + t5 = space(); + button0 = element$1("button"); + button0.textContent = "Update Node"; + t7 = space(); + div1 = element$1("div"); + button1 = element$1("button"); + button1.textContent = "Delete Node"; + t9 = space(); + button2 = element$1("button"); + button2.textContent = "Add Nodes"; + t11 = space(); + label2 = element$1("label"); + t12 = text("Number of nodes to add:\r\n "); + input2 = element$1("input"); + add_location(pre, file$1, 362, 10, 11091); + attr_dev(input0, "type", "text"); + add_location(input0, file$1, 366, 14, 11236); + attr_dev(label0, "class", "label svelte-y6fsmu"); + add_location(label0, file$1, 364, 12, 11177); + attr_dev(input1, "type", "text"); + add_location(input1, file$1, 370, 14, 11377); + attr_dev(label1, "class", "label svelte-y6fsmu"); + add_location(label1, file$1, 368, 12, 11319); + add_location(button0, file$1, 372, 12, 11459); + add_location(div0, file$1, 363, 10, 11158); + add_location(button1, file$1, 375, 12, 11576); + add_location(button2, file$1, 376, 12, 11642); + attr_dev(input2, "type", "number"); + attr_dev(input2, "min", "1"); + add_location(input2, file$1, 379, 14, 11784); + attr_dev(label2, "class", "label svelte-y6fsmu"); + add_location(label2, file$1, 377, 12, 11708); + attr_dev(div1, "class", "buttons svelte-y6fsmu"); + add_location(div1, file$1, 374, 10, 11541); + }, + m: function mount(target, anchor) { + insert_dev(target, pre, anchor); + append_dev(pre, t0); + insert_dev(target, t1, anchor); + insert_dev(target, div0, anchor); + append_dev(div0, label0); + append_dev(label0, t2); + append_dev(label0, input0); + set_input_value(input0, /*updatedLabel*/ ctx[1]); + append_dev(div0, t3); + append_dev(div0, label1); + append_dev(label1, t4); + append_dev(label1, input1); + set_input_value(input1, /*updatedType*/ ctx[2]); + append_dev(div0, t5); + append_dev(div0, button0); + insert_dev(target, t7, anchor); + insert_dev(target, div1, anchor); + append_dev(div1, button1); + append_dev(div1, t9); + append_dev(div1, button2); + append_dev(div1, t11); + append_dev(div1, label2); + append_dev(label2, t12); + append_dev(label2, input2); + set_input_value(input2, /*numberOfNodesToAdd*/ ctx[3]); + + if (!mounted) { + dispose = [ + listen_dev(input0, "input", /*input0_input_handler*/ ctx[30]), + listen_dev(input1, "input", /*input1_input_handler*/ ctx[31]), + listen_dev(button0, "click", /*handleUpdate*/ ctx[20], false, false, false, false), + listen_dev(button1, "click", /*handleDelete*/ ctx[21], false, false, false, false), + listen_dev(button2, "click", /*handleAddNodes*/ ctx[22], false, false, false, false), + listen_dev(input2, "input", /*input2_input_handler*/ ctx[32]) + ]; + + mounted = true; + } + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*$selectedNodeData*/ 512 && t0_value !== (t0_value = JSON.stringify(/*$selectedNodeData*/ ctx[9], null, 2) + "")) set_data_dev(t0, t0_value); + + if (dirty[0] & /*updatedLabel*/ 2 && input0.value !== /*updatedLabel*/ ctx[1]) { + set_input_value(input0, /*updatedLabel*/ ctx[1]); + } + + if (dirty[0] & /*updatedType*/ 4 && input1.value !== /*updatedType*/ ctx[2]) { + set_input_value(input1, /*updatedType*/ ctx[2]); + } + + if (dirty[0] & /*numberOfNodesToAdd*/ 8 && to_number(input2.value) !== /*numberOfNodesToAdd*/ ctx[3]) { + set_input_value(input2, /*numberOfNodesToAdd*/ ctx[3]); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(pre); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(div0); + if (detaching) detach_dev(t7); + if (detaching) detach_dev(div1); + mounted = false; + run_all(dispose); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_3.name, + type: "if", + source: "(362:8) {#if $selectedNodeData}", + ctx + }); + + return block; + } + + // (399:12) {:else} + function create_else_block_2(ctx) { + let select; + let option; + + const block = { + c: function create() { + select = element$1("select"); + option = element$1("option"); + option.textContent = "Loading nodes..."; + option.__value = "Loading nodes..."; + option.value = option.__value; + add_location(option, file$1, 400, 16, 12561); + select.disabled = true; + add_location(select, file$1, 399, 14, 12526); + }, + m: function mount(target, anchor) { + insert_dev(target, select, anchor); + append_dev(select, option); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(select); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_else_block_2.name, + type: "else", + source: "(399:12) {:else}", + ctx + }); + + return block; + } + + // (392:12) {#if $cyReady} + function create_if_block_2(ctx) { + let select; + let option; + let mounted; + let dispose; + let each_value_2 = /*$nodeIds*/ ctx[11]; + validate_each_argument(each_value_2); let each_blocks = []; - for (let i = 0; i < each_value_1.length; i += 1) { - each_blocks[i] = create_each_block_1(get_each_context_1(ctx, each_value_1, i)); + for (let i = 0; i < each_value_2.length; i += 1) { + each_blocks[i] = create_each_block_2(get_each_context_2(ctx, each_value_2, i)); } const block = { c: function create() { - h4 = element("h4"); - h4.textContent = "Extracted Letters:"; - t1 = space(); - div = element("div"); - table = element("table"); + select = element$1("select"); + option = element$1("option"); + option.textContent = "Select source node"; for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(h4, file$3, 25, 10, 918); - add_location(table, file$3, 27, 12, 1058); - set_style(div, "max-height", "275px"); - set_style(div, "max-width", "97%"); - set_style(div, "overflow", "auto"); - set_style(div, "display", "inline-block"); - add_location(div, file$3, 26, 10, 957); + option.__value = ""; + option.value = option.__value; + option.disabled = true; + add_location(option, file$1, 393, 16, 12294); + if (/*sourceNodeId*/ ctx[4] === void 0) add_render_callback(() => /*select_change_handler*/ ctx[33].call(select)); + add_location(select, file$1, 392, 14, 12242); }, m: function mount(target, anchor) { - insert_dev(target, h4, anchor); - insert_dev(target, t1, anchor); - insert_dev(target, div, anchor); - append_dev(div, table); + insert_dev(target, select, anchor); + append_dev(select, option); for (let i = 0; i < each_blocks.length; i += 1) { if (each_blocks[i]) { - each_blocks[i].m(table, null); + each_blocks[i].m(select, null); } } + + select_option(select, /*sourceNodeId*/ ctx[4], true); + + if (!mounted) { + dispose = listen_dev(select, "change", /*select_change_handler*/ ctx[33]); + mounted = true; + } }, p: function update(ctx, dirty) { - if (dirty & /*extractLetters, sentences*/ 2) { - each_value_1 = extractLetters(/*sentence*/ ctx[3]); - validate_each_argument(each_value_1); + if (dirty[0] & /*$nodeIds*/ 2048) { + each_value_2 = /*$nodeIds*/ ctx[11]; + validate_each_argument(each_value_2); let i; - for (i = 0; i < each_value_1.length; i += 1) { - const child_ctx = get_each_context_1(ctx, each_value_1, i); + for (i = 0; i < each_value_2.length; i += 1) { + const child_ctx = get_each_context_2(ctx, each_value_2, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block_1(child_ctx); + each_blocks[i] = create_each_block_2(child_ctx); each_blocks[i].c(); - each_blocks[i].m(table, null); + each_blocks[i].m(select, null); } } @@ -67915,108 +112644,175 @@ var app = (function () { each_blocks[i].d(1); } - each_blocks.length = each_value_1.length; + each_blocks.length = each_value_2.length; + } + + if (dirty[0] & /*sourceNodeId, $nodeIds*/ 2064) { + select_option(select, /*sourceNodeId*/ ctx[4]); + } + }, + d: function destroy(detaching) { + if (detaching) detach_dev(select); + destroy_each(each_blocks, detaching); + mounted = false; + dispose(); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_if_block_2.name, + type: "if", + source: "(392:12) {#if $cyReady}", + ctx + }); + + return block; + } + + // (395:16) {#each $nodeIds as id} + function create_each_block_2(ctx) { + let option; + let t_value = /*id*/ ctx[45] + ""; + let t; + let option_value_value; + + const block = { + c: function create() { + option = element$1("option"); + t = text(t_value); + option.__value = option_value_value = /*id*/ ctx[45]; + option.value = option.__value; + add_location(option, file$1, 395, 18, 12407); + }, + m: function mount(target, anchor) { + insert_dev(target, option, anchor); + append_dev(option, t); + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*$nodeIds*/ 2048 && t_value !== (t_value = /*id*/ ctx[45] + "")) set_data_dev(t, t_value); + + if (dirty[0] & /*$nodeIds*/ 2048 && option_value_value !== (option_value_value = /*id*/ ctx[45])) { + prop_dev(option, "__value", option_value_value); + option.value = option.__value; } }, d: function destroy(detaching) { - if (detaching) detach_dev(h4); - if (detaching) detach_dev(t1); - if (detaching) detach_dev(div); - destroy_each(each_blocks, detaching); + if (detaching) detach_dev(option); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_if_block.name, - type: "if", - source: "(25:8) {#if sentence}", + id: create_each_block_2.name, + type: "each", + source: "(395:16) {#each $nodeIds as id}", ctx }); return block; } - // (31:18) {#each row as cell} - function create_each_block_2(ctx) { - let td; - let t_value = /*cell*/ ctx[9] + ""; - let t; + // (414:12) {:else} + function create_else_block_1(ctx) { + let select; + let option; const block = { c: function create() { - td = element("td"); - t = text(t_value); - add_location(td, file$3, 31, 20, 1203); + select = element$1("select"); + option = element$1("option"); + option.textContent = "Loading nodes..."; + option.__value = "Loading nodes..."; + option.value = option.__value; + add_location(option, file$1, 415, 16, 13083); + select.disabled = true; + add_location(select, file$1, 414, 14, 13048); }, m: function mount(target, anchor) { - insert_dev(target, td, anchor); - append_dev(td, t); - }, - p: function update(ctx, dirty) { - if (dirty & /*sentences*/ 2 && t_value !== (t_value = /*cell*/ ctx[9] + "")) set_data_dev(t, t_value); + insert_dev(target, select, anchor); + append_dev(select, option); }, + p: noop$2, d: function destroy(detaching) { - if (detaching) detach_dev(td); + if (detaching) detach_dev(select); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_2.name, - type: "each", - source: "(31:18) {#each row as cell}", + id: create_else_block_1.name, + type: "else", + source: "(414:12) {:else}", ctx }); return block; } - // (29:14) {#each extractLetters(sentence) as row} - function create_each_block_1(ctx) { - let tr; - let each_value_2 = /*row*/ ctx[6]; - validate_each_argument(each_value_2); + // (407:12) {#if $cyReady} + function create_if_block_1(ctx) { + let select; + let option; + let mounted; + let dispose; + let each_value_1 = /*$nodeIds*/ ctx[11]; + validate_each_argument(each_value_1); let each_blocks = []; - for (let i = 0; i < each_value_2.length; i += 1) { - each_blocks[i] = create_each_block_2(get_each_context_2(ctx, each_value_2, i)); + for (let i = 0; i < each_value_1.length; i += 1) { + each_blocks[i] = create_each_block_1(get_each_context_1(ctx, each_value_1, i)); } const block = { c: function create() { - tr = element("tr"); + select = element$1("select"); + option = element$1("option"); + option.textContent = "Select target node"; for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - add_location(tr, file$3, 29, 16, 1138); + option.__value = ""; + option.value = option.__value; + option.disabled = true; + add_location(option, file$1, 408, 16, 12816); + if (/*targetNodeId*/ ctx[5] === void 0) add_render_callback(() => /*select_change_handler_1*/ ctx[34].call(select)); + add_location(select, file$1, 407, 14, 12764); }, m: function mount(target, anchor) { - insert_dev(target, tr, anchor); + insert_dev(target, select, anchor); + append_dev(select, option); for (let i = 0; i < each_blocks.length; i += 1) { if (each_blocks[i]) { - each_blocks[i].m(tr, null); + each_blocks[i].m(select, null); } } + + select_option(select, /*targetNodeId*/ ctx[5], true); + + if (!mounted) { + dispose = listen_dev(select, "change", /*select_change_handler_1*/ ctx[34]); + mounted = true; + } }, p: function update(ctx, dirty) { - if (dirty & /*extractLetters, sentences*/ 2) { - each_value_2 = /*row*/ ctx[6]; - validate_each_argument(each_value_2); + if (dirty[0] & /*$nodeIds*/ 2048) { + each_value_1 = /*$nodeIds*/ ctx[11]; + validate_each_argument(each_value_1); let i; - for (i = 0; i < each_value_2.length; i += 1) { - const child_ctx = get_each_context_2(ctx, each_value_2, i); + for (i = 0; i < each_value_1.length; i += 1) { + const child_ctx = get_each_context_1(ctx, each_value_1, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block_2(child_ctx); + each_blocks[i] = create_each_block_1(child_ctx); each_blocks[i].c(); - each_blocks[i].m(tr, null); + each_blocks[i].m(select, null); } } @@ -68024,188 +112820,175 @@ var app = (function () { each_blocks[i].d(1); } - each_blocks.length = each_value_2.length; + each_blocks.length = each_value_1.length; + } + + if (dirty[0] & /*targetNodeId, $nodeIds*/ 2080) { + select_option(select, /*targetNodeId*/ ctx[5]); } }, d: function destroy(detaching) { - if (detaching) detach_dev(tr); + if (detaching) detach_dev(select); destroy_each(each_blocks, detaching); + mounted = false; + dispose(); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block_1.name, - type: "each", - source: "(29:14) {#each extractLetters(sentence) as row}", + id: create_if_block_1.name, + type: "if", + source: "(407:12) {#if $cyReady}", ctx }); return block; } - // (21:4) {#each sentences as sentence, index} - function create_each_block$1(ctx) { - let div; - let h3; - let t0; - let t1_value = /*index*/ ctx[5] + 1 + ""; - let t1; - let t2; - let t3; - let p; - let t4_value = /*sentence*/ ctx[3] + ""; - let t4; - let t5; - let if_block = /*sentence*/ ctx[3] && create_if_block(ctx); + // (410:16) {#each $nodeIds as id} + function create_each_block_1(ctx) { + let option; + let t_value = /*id*/ ctx[45] + ""; + let t; + let option_value_value; const block = { c: function create() { - div = element("div"); - h3 = element("h3"); - t0 = text("Sentence "); - t1 = text(t1_value); - t2 = text(":"); - t3 = space(); - p = element("p"); - t4 = text(t4_value); - t5 = space(); - if (if_block) if_block.c(); - add_location(h3, file$3, 22, 8, 825); - add_location(p, file$3, 23, 8, 865); - add_location(div, file$3, 21, 6, 810); + option = element$1("option"); + t = text(t_value); + option.__value = option_value_value = /*id*/ ctx[45]; + option.value = option.__value; + add_location(option, file$1, 410, 18, 12929); }, m: function mount(target, anchor) { - insert_dev(target, div, anchor); - append_dev(div, h3); - append_dev(h3, t0); - append_dev(h3, t1); - append_dev(h3, t2); - append_dev(div, t3); - append_dev(div, p); - append_dev(p, t4); - append_dev(div, t5); - if (if_block) if_block.m(div, null); + insert_dev(target, option, anchor); + append_dev(option, t); }, p: function update(ctx, dirty) { - if (dirty & /*sentences*/ 2 && t4_value !== (t4_value = /*sentence*/ ctx[3] + "")) set_data_dev(t4, t4_value); + if (dirty[0] & /*$nodeIds*/ 2048 && t_value !== (t_value = /*id*/ ctx[45] + "")) set_data_dev(t, t_value); - if (/*sentence*/ ctx[3]) { - if (if_block) { - if_block.p(ctx, dirty); - } else { - if_block = create_if_block(ctx); - if_block.c(); - if_block.m(div, null); - } - } else if (if_block) { - if_block.d(1); - if_block = null; + if (dirty[0] & /*$nodeIds*/ 2048 && option_value_value !== (option_value_value = /*id*/ ctx[45])) { + prop_dev(option, "__value", option_value_value); + option.value = option.__value; } }, d: function destroy(detaching) { - if (detaching) detach_dev(div); - if (if_block) if_block.d(); + if (detaching) detach_dev(option); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_each_block$1.name, + id: create_each_block_1.name, type: "each", - source: "(21:4) {#each sentences as sentence, index}", + source: "(410:16) {#each $nodeIds as id}", ctx }); return block; } - function create_fragment$3(ctx) { - let div; - let h2; - let t1; - let textarea; - let t2; - let t3; - let p; + // (432:12) {:else} + function create_else_block(ctx) { + let select; + let option; + + const block = { + c: function create() { + select = element$1("select"); + option = element$1("option"); + option.textContent = "Loading edges..."; + option.__value = "Loading edges..."; + option.value = option.__value; + add_location(option, file$1, 433, 16, 13720); + select.disabled = true; + add_location(select, file$1, 432, 14, 13685); + }, + m: function mount(target, anchor) { + insert_dev(target, select, anchor); + append_dev(select, option); + }, + p: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(select); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_else_block.name, + type: "else", + source: "(432:12) {:else}", + ctx + }); + + return block; + } + + // (425:12) {#if $cyReady} + function create_if_block(ctx) { + let select; + let option; let mounted; let dispose; - let each_value = /*sentences*/ ctx[1]; + let each_value = /*$edgeIds*/ ctx[12]; validate_each_argument(each_value); let each_blocks = []; for (let i = 0; i < each_value.length; i += 1) { - each_blocks[i] = create_each_block$1(get_each_context$1(ctx, each_value, i)); + each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i)); } const block = { c: function create() { - div = element("div"); - h2 = element("h2"); - h2.textContent = "Sentence Letter Extractor"; - t1 = space(); - textarea = element("textarea"); - t2 = space(); + select = element$1("select"); + option = element$1("option"); + option.textContent = "Select edge to delete"; for (let i = 0; i < each_blocks.length; i += 1) { each_blocks[i].c(); } - t3 = space(); - p = element("p"); - p.textContent = "Example rough prompt to claude/gpt 4 to generate image prompt - The output of a random sentence brought R b N C I f L r t n f b r, please try and make a sentence where each letter is used to make a sentence with as many nouns adjectives in it while using as few words as possible"; - add_location(h2, file$3, 18, 4, 541); - set_style(textarea, "width", "95%"); - set_style(textarea, "height", "100px"); - attr_dev(textarea, "placeholder", "Enter sentences separated by full stops, question marks, exclamation marks, or colons"); - add_location(textarea, file$3, 19, 4, 581); - add_location(p, file$3, 40, 4, 1379); - add_location(div, file$3, 17, 2, 530); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); + option.__value = ""; + option.value = option.__value; + option.disabled = true; + add_location(option, file$1, 426, 16, 13444); + if (/*selectedEdge*/ ctx[6] === void 0) add_render_callback(() => /*select_change_handler_2*/ ctx[35].call(select)); + add_location(select, file$1, 425, 14, 13392); }, m: function mount(target, anchor) { - insert_dev(target, div, anchor); - append_dev(div, h2); - append_dev(div, t1); - append_dev(div, textarea); - set_input_value(textarea, /*inputText*/ ctx[0]); - append_dev(div, t2); + insert_dev(target, select, anchor); + append_dev(select, option); for (let i = 0; i < each_blocks.length; i += 1) { if (each_blocks[i]) { - each_blocks[i].m(div, null); + each_blocks[i].m(select, null); } } - append_dev(div, t3); - append_dev(div, p); + select_option(select, /*selectedEdge*/ ctx[6], true); if (!mounted) { - dispose = listen_dev(textarea, "input", /*textarea_input_handler*/ ctx[2]); + dispose = listen_dev(select, "change", /*select_change_handler_2*/ ctx[35]); mounted = true; } }, - p: function update(ctx, [dirty]) { - if (dirty & /*inputText*/ 1) { - set_input_value(textarea, /*inputText*/ ctx[0]); - } - - if (dirty & /*extractLetters, sentences*/ 2) { - each_value = /*sentences*/ ctx[1]; + p: function update(ctx, dirty) { + if (dirty[0] & /*$edgeIds*/ 4096) { + each_value = /*$edgeIds*/ ctx[12]; validate_each_argument(each_value); let i; for (i = 0; i < each_value.length; i += 1) { - const child_ctx = get_each_context$1(ctx, each_value, i); + const child_ctx = get_each_context(ctx, each_value, i); if (each_blocks[i]) { each_blocks[i].p(child_ctx, dirty); } else { - each_blocks[i] = create_each_block$1(child_ctx); + each_blocks[i] = create_each_block(child_ctx); each_blocks[i].c(); - each_blocks[i].m(div, t3); + each_blocks[i].m(select, null); } } @@ -68215,11 +112998,13 @@ var app = (function () { each_blocks.length = each_value.length; } + + if (dirty[0] & /*selectedEdge, $edgeIds*/ 4160) { + select_option(select, /*selectedEdge*/ ctx[6]); + } }, - i: noop, - o: noop, d: function destroy(detaching) { - if (detaching) detach_dev(div); + if (detaching) detach_dev(select); destroy_each(each_blocks, detaching); mounted = false; dispose(); @@ -68228,131 +113013,44 @@ var app = (function () { dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$3.name, - type: "component", - source: "", + id: create_if_block.name, + type: "if", + source: "(425:12) {#if $cyReady}", ctx }); return block; } - function extractLetters(sentence) { - const words = sentence.split(' '); - const maxLength = Math.max(...words.map(word => word.length)); - const result = []; - - for (let i = 0; i < maxLength; i++) { - const letters = words.map(word => word[i] || ''); - result.push(letters); - } - - return result; - } - - function instance$3($$self, $$props, $$invalidate) { - let sentences; - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('PSWSasspellingpractice', slots, []); - let inputText = ''; - const writable_props = []; - - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); - - function textarea_input_handler() { - inputText = this.value; - $$invalidate(0, inputText); - } - - $$self.$capture_state = () => ({ inputText, extractLetters, sentences }); - - $$self.$inject_state = $$props => { - if ('inputText' in $$props) $$invalidate(0, inputText = $$props.inputText); - if ('sentences' in $$props) $$invalidate(1, sentences = $$props.sentences); - }; - - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } - - $$self.$$.update = () => { - if ($$self.$$.dirty & /*inputText*/ 1) { - $$invalidate(1, sentences = inputText.split(/[.?!:]/).map(sentence => sentence.trim()).filter(sentence => sentence !== '')); - } - }; - - return [inputText, sentences, textarea_input_handler]; - } - - class PSWSasspellingpractice extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$3, create_fragment$3, safe_not_equal, {}); - - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "PSWSasspellingpractice", - options, - id: create_fragment$3.name - }); - } - } - - /* src\ListeningPracticeandSyllableStudy.svelte generated by Svelte v3.59.2 */ - - const file$2 = "src\\ListeningPracticeandSyllableStudy.svelte"; - - function get_each_context(ctx, list, i) { - const child_ctx = ctx.slice(); - child_ctx[6] = list[i]; - child_ctx[8] = i; - return child_ctx; - } - - // (25:4) {#each syllableLists as syllables, index (index)} - function create_each_block(key_1, ctx) { - let button; - let t0_value = /*displayTexts*/ ctx[1][/*index*/ ctx[8]] + ""; - let t0; - let t1; - let mounted; - let dispose; - - function click_handler() { - return /*click_handler*/ ctx[3](/*index*/ ctx[8]); - } + // (428:16) {#each $edgeIds as edge} + function create_each_block(ctx) { + let option; + let t_value = /*edge*/ ctx[42] + ""; + let t; + let option_value_value; const block = { - key: key_1, - first: null, c: function create() { - button = element("button"); - t0 = text(t0_value); - t1 = space(); - set_style(button, "cursor", "pointer"); - add_location(button, file$2, 25, 8, 874); - this.first = button; + option = element$1("option"); + t = text(t_value); + option.__value = option_value_value = /*edge*/ ctx[42]; + option.value = option.__value; + add_location(option, file$1, 428, 18, 13562); }, m: function mount(target, anchor) { - insert_dev(target, button, anchor); - append_dev(button, t0); - append_dev(button, t1); + insert_dev(target, option, anchor); + append_dev(option, t); + }, + p: function update(ctx, dirty) { + if (dirty[0] & /*$edgeIds*/ 4096 && t_value !== (t_value = /*edge*/ ctx[42] + "")) set_data_dev(t, t_value); - if (!mounted) { - dispose = listen_dev(button, "click", click_handler, false, false, false, false); - mounted = true; + if (dirty[0] & /*$edgeIds*/ 4096 && option_value_value !== (option_value_value = /*edge*/ ctx[42])) { + prop_dev(option, "__value", option_value_value); + option.value = option.__value; } }, - p: function update(new_ctx, dirty) { - ctx = new_ctx; - if (dirty & /*displayTexts, syllableLists*/ 3 && t0_value !== (t0_value = /*displayTexts*/ ctx[1][/*index*/ ctx[8]] + "")) set_data_dev(t0, t0_value); - }, d: function destroy(detaching) { - if (detaching) detach_dev(button); - mounted = false; - dispose(); + if (detaching) detach_dev(option); } }; @@ -68360,81 +113058,397 @@ var app = (function () { block, id: create_each_block.name, type: "each", - source: "(25:4) {#each syllableLists as syllables, index (index)}", + source: "(428:16) {#each $edgeIds as edge}", ctx }); return block; } - function create_fragment$2(ctx) { - let main; - let div; + function create_fragment$1(ctx) { + let div11; + let h1; let t1; - let each_blocks = []; - let each_1_lookup = new Map(); - let each_value = /*syllableLists*/ ctx[0]; - validate_each_argument(each_value); - const get_key = ctx => /*index*/ ctx[8]; - validate_each_keys(ctx, each_value, get_each_context, get_key); + let div5; + let div0; + let t2; + let div4; + let h3; + let t4; + let t5; + let div1; + let button0; + let t7; + let div2; + let label0; + let t8; + let t9; + let label1; + let t10; + let t11; + let button1; + let t13; + let div3; + let label2; + let t14; + let t15; + let button2; + let t17; + let div10; + let button3; + let t19; + let button4; + let t21; + let button5; + let t23; + let button6; + let t25; + let button7; + let t27; + let button8; + let t29; + let div9; + let div6; + let label3; + let t31; + let textarea0; + let t32; + let div7; + let label4; + let t34; + let textarea1; + let t35; + let div8; + let p; + let t37; + let pre; + let mounted; + let dispose; - for (let i = 0; i < each_value.length; i += 1) { - let child_ctx = get_each_context(ctx, each_value, i); - let key = get_key(child_ctx); - each_1_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx)); + function select_block_type(ctx, dirty) { + if (/*$selectedNodeData*/ ctx[9]) return create_if_block_3; + return create_else_block_3; + } + + let current_block_type = select_block_type(ctx); + let if_block0 = current_block_type(ctx); + + function select_block_type_1(ctx, dirty) { + if (/*$cyReady*/ ctx[10]) return create_if_block_2; + return create_else_block_2; + } + + let current_block_type_1 = select_block_type_1(ctx); + let if_block1 = current_block_type_1(ctx); + + function select_block_type_2(ctx, dirty) { + if (/*$cyReady*/ ctx[10]) return create_if_block_1; + return create_else_block_1; + } + + let current_block_type_2 = select_block_type_2(ctx); + let if_block2 = current_block_type_2(ctx); + + function select_block_type_3(ctx, dirty) { + if (/*$cyReady*/ ctx[10]) return create_if_block; + return create_else_block; } + let current_block_type_3 = select_block_type_3(ctx); + let if_block3 = current_block_type_3(ctx); + const block = { c: function create() { - main = element("main"); - div = element("div"); - div.textContent = "On click will Show Next Syllable"; + div11 = element$1("div"); + h1 = element$1("h1"); + h1.textContent = "Code Outline Graph"; t1 = space(); - - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].c(); - } - - attr_dev(div, "class", "svelte-18he4oy"); - add_location(div, file$2, 23, 4, 766); - add_location(main, file$2, 22, 0, 754); + div5 = element$1("div"); + div0 = element$1("div"); + t2 = space(); + div4 = element$1("div"); + h3 = element$1("h3"); + h3.textContent = "Node Data"; + t4 = space(); + if_block0.c(); + t5 = space(); + div1 = element$1("div"); + button0 = element$1("button"); + button0.textContent = "Add Node Without Edges"; + t7 = space(); + div2 = element$1("div"); + label0 = element$1("label"); + t8 = text("Source Node ID:\r\n "); + if_block1.c(); + t9 = space(); + label1 = element$1("label"); + t10 = text("Target Node ID:\r\n "); + if_block2.c(); + t11 = space(); + button1 = element$1("button"); + button1.textContent = "Add Edge"; + t13 = space(); + div3 = element$1("div"); + label2 = element$1("label"); + t14 = text("Select Edge:\r\n "); + if_block3.c(); + t15 = space(); + button2 = element$1("button"); + button2.textContent = "Delete Edge"; + t17 = space(); + div10 = element$1("div"); + button3 = element$1("button"); + button3.textContent = "Fit Graph"; + t19 = space(); + button4 = element$1("button"); + button4.textContent = "Load Dummy Scenario"; + t21 = space(); + button5 = element$1("button"); + button5.textContent = "Space Out Nodes"; + t23 = space(); + button6 = element$1("button"); + button6.textContent = "Load from Input Area"; + t25 = space(); + button7 = element$1("button"); + button7.textContent = "Edit Graph Data"; + t27 = space(); + button8 = element$1("button"); + button8.textContent = "Add Empty Lines"; + t29 = space(); + div9 = element$1("div"); + div6 = element$1("div"); + label3 = element$1("label"); + label3.textContent = "Current Graph Data (readonly)"; + t31 = space(); + textarea0 = element$1("textarea"); + t32 = space(); + div7 = element$1("div"); + label4 = element$1("label"); + label4.textContent = "Custom Scenario (editable)"; + t34 = space(); + textarea1 = element$1("textarea"); + t35 = space(); + div8 = element$1("div"); + p = element$1("p"); + p.textContent = "YAML Format: (to prompt with)"; + t37 = space(); + pre = element$1("pre"); + pre.textContent = " - file: CustomScenario\r\n symbols:\r\n - id: functionA\r\n type: function\r\n - id: variableX\r\n type: variable\r\n - id: functionB\r\n type: function\r\n - id: variableY\r\n type: variable\r\n edges:\r\n - source: functionA\r\n target: variableX\r\n type: function-to-variable\r\n - source: variableX\r\n target: functionB\r\n type: variable-to-function\r\n - source: functionB\r\n target: variableY\r\n type: function-to-variable\r\n "; + add_location(h1, file$1, 356, 4, 10882); + attr_dev(div0, "id", "cy"); + attr_dev(div0, "class", "svelte-y6fsmu"); + add_location(div0, file$1, 358, 6, 10950); + add_location(h3, file$1, 360, 8, 11028); + add_location(button0, file$1, 386, 10, 12013); + attr_dev(div1, "class", "buttons svelte-y6fsmu"); + add_location(div1, file$1, 385, 8, 11980); + attr_dev(label0, "class", "label svelte-y6fsmu"); + add_location(label0, file$1, 389, 10, 12148); + attr_dev(label1, "class", "label svelte-y6fsmu"); + add_location(label1, file$1, 404, 10, 12670); + add_location(button1, file$1, 419, 10, 13192); + attr_dev(div2, "class", "buttons svelte-y6fsmu"); + add_location(div2, file$1, 388, 8, 12115); + attr_dev(label2, "class", "label svelte-y6fsmu"); + add_location(label2, file$1, 422, 10, 13301); + add_location(button2, file$1, 437, 10, 13829); + attr_dev(div3, "class", "buttons svelte-y6fsmu"); + add_location(div3, file$1, 421, 8, 13268); + attr_dev(div4, "id", "nodeData"); + attr_dev(div4, "class", "svelte-y6fsmu"); + add_location(div4, file$1, 359, 6, 10999); + attr_dev(div5, "class", "cyandnodedata svelte-y6fsmu"); + add_location(div5, file$1, 357, 4, 10915); + add_location(button3, file$1, 443, 6, 13966); + add_location(button4, file$1, 444, 6, 14020); + add_location(button5, file$1, 445, 6, 14094); + add_location(button6, file$1, 446, 6, 14159); + add_location(button7, file$1, 447, 6, 14233); + add_location(button8, file$1, 448, 6, 14302); + attr_dev(label3, "class", "label svelte-y6fsmu"); + add_location(label3, file$1, 451, 10, 14426); + textarea0.readOnly = true; + attr_dev(textarea0, "placeholder", "Current graph data (readonly)"); + attr_dev(textarea0, "class", "svelte-y6fsmu"); + add_location(textarea0, file$1, 452, 10, 14496); + add_location(div6, file$1, 450, 8, 14409); + attr_dev(label4, "class", "label svelte-y6fsmu"); + add_location(label4, file$1, 455, 10, 14643); + attr_dev(textarea1, "placeholder", "Enter custom scenario in YAML format"); + attr_dev(textarea1, "class", "svelte-y6fsmu"); + add_location(textarea1, file$1, 456, 10, 14710); + add_location(div7, file$1, 454, 8, 14626); + add_location(p, file$1, 459, 10, 14875); + add_location(pre, file$1, 460, 10, 14923); + attr_dev(div8, "class", "guidance-text svelte-y6fsmu"); + add_location(div8, file$1, 458, 8, 14836); + attr_dev(div9, "class", "textarea-container svelte-y6fsmu"); + add_location(div9, file$1, 449, 6, 14367); + attr_dev(div10, "id", "controls"); + attr_dev(div10, "class", "svelte-y6fsmu"); + add_location(div10, file$1, 442, 4, 13939); + add_location(div11, file$1, 355, 2, 10871); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); }, m: function mount(target, anchor) { - insert_dev(target, main, anchor); - append_dev(main, div); - append_dev(main, t1); + insert_dev(target, div11, anchor); + append_dev(div11, h1); + append_dev(div11, t1); + append_dev(div11, div5); + append_dev(div5, div0); + /*div0_binding*/ ctx[29](div0); + append_dev(div5, t2); + append_dev(div5, div4); + append_dev(div4, h3); + append_dev(div4, t4); + if_block0.m(div4, null); + append_dev(div4, t5); + append_dev(div4, div1); + append_dev(div1, button0); + append_dev(div4, t7); + append_dev(div4, div2); + append_dev(div2, label0); + append_dev(label0, t8); + if_block1.m(label0, null); + append_dev(div2, t9); + append_dev(div2, label1); + append_dev(label1, t10); + if_block2.m(label1, null); + append_dev(div2, t11); + append_dev(div2, button1); + append_dev(div4, t13); + append_dev(div4, div3); + append_dev(div3, label2); + append_dev(label2, t14); + if_block3.m(label2, null); + append_dev(div3, t15); + append_dev(div3, button2); + append_dev(div11, t17); + append_dev(div11, div10); + append_dev(div10, button3); + append_dev(div10, t19); + append_dev(div10, button4); + append_dev(div10, t21); + append_dev(div10, button5); + append_dev(div10, t23); + append_dev(div10, button6); + append_dev(div10, t25); + append_dev(div10, button7); + append_dev(div10, t27); + append_dev(div10, button8); + append_dev(div10, t29); + append_dev(div10, div9); + append_dev(div9, div6); + append_dev(div6, label3); + append_dev(div6, t31); + append_dev(div6, textarea0); + set_input_value(textarea0, /*currentGraphData*/ ctx[8]); + append_dev(div9, t32); + append_dev(div9, div7); + append_dev(div7, label4); + append_dev(div7, t34); + append_dev(div7, textarea1); + set_input_value(textarea1, /*customScenario*/ ctx[7]); + append_dev(div9, t35); + append_dev(div9, div8); + append_dev(div8, p); + append_dev(div8, t37); + append_dev(div8, pre); - for (let i = 0; i < each_blocks.length; i += 1) { - if (each_blocks[i]) { - each_blocks[i].m(main, null); - } + if (!mounted) { + dispose = [ + listen_dev(button0, "click", /*handleAddNodeWithoutEdges*/ ctx[23], false, false, false, false), + listen_dev(button1, "click", /*handleAddEdge*/ ctx[24], false, false, false, false), + listen_dev(button2, "click", /*handleDeleteEdge*/ ctx[25], false, false, false, false), + listen_dev(button3, "click", /*fitGraph*/ ctx[27], false, false, false, false), + listen_dev(button4, "click", /*initializeScenario*/ ctx[17], false, false, false, false), + listen_dev(button5, "click", /*spaceOutNodes*/ ctx[26], false, false, false, false), + listen_dev(button6, "click", /*loadFromInputArea*/ ctx[18], false, false, false, false), + listen_dev(button7, "click", /*loadFromGraphData*/ ctx[19], false, false, false, false), + listen_dev(button8, "click", /*addEmptyLines*/ ctx[28], false, false, false, false), + listen_dev(textarea0, "input", /*textarea0_input_handler*/ ctx[36]), + listen_dev(textarea1, "input", /*textarea1_input_handler*/ ctx[37]) + ]; + + mounted = true; } }, - p: function update(ctx, [dirty]) { - if (dirty & /*nextSyllable, syllableLists, displayTexts*/ 7) { - each_value = /*syllableLists*/ ctx[0]; - validate_each_argument(each_value); - validate_each_keys(ctx, each_value, get_each_context, get_key); - each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx, each_value, each_1_lookup, main, destroy_block, create_each_block, null, get_each_context); + p: function update(ctx, dirty) { + if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block0) { + if_block0.p(ctx, dirty); + } else { + if_block0.d(1); + if_block0 = current_block_type(ctx); + + if (if_block0) { + if_block0.c(); + if_block0.m(div4, t5); + } + } + + if (current_block_type_1 === (current_block_type_1 = select_block_type_1(ctx)) && if_block1) { + if_block1.p(ctx, dirty); + } else { + if_block1.d(1); + if_block1 = current_block_type_1(ctx); + + if (if_block1) { + if_block1.c(); + if_block1.m(label0, null); + } + } + + if (current_block_type_2 === (current_block_type_2 = select_block_type_2(ctx)) && if_block2) { + if_block2.p(ctx, dirty); + } else { + if_block2.d(1); + if_block2 = current_block_type_2(ctx); + + if (if_block2) { + if_block2.c(); + if_block2.m(label1, null); + } + } + + if (current_block_type_3 === (current_block_type_3 = select_block_type_3(ctx)) && if_block3) { + if_block3.p(ctx, dirty); + } else { + if_block3.d(1); + if_block3 = current_block_type_3(ctx); + + if (if_block3) { + if_block3.c(); + if_block3.m(label2, null); + } + } + + if (dirty[0] & /*currentGraphData*/ 256) { + set_input_value(textarea0, /*currentGraphData*/ ctx[8]); } - }, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(main); - for (let i = 0; i < each_blocks.length; i += 1) { - each_blocks[i].d(); + if (dirty[0] & /*customScenario*/ 128) { + set_input_value(textarea1, /*customScenario*/ ctx[7]); } + }, + i: noop$2, + o: noop$2, + d: function destroy(detaching) { + if (detaching) detach_dev(div11); + /*div0_binding*/ ctx[29](null); + if_block0.d(); + if_block1.d(); + if_block2.d(); + if_block3.d(); + mounted = false; + run_all(dispose); } }; dispatch_dev("SvelteRegisterBlock", { block, - id: create_fragment$2.name, + id: create_fragment$1.name, type: "component", source: "", ctx @@ -68443,139 +113457,569 @@ var app = (function () { return block; } - function instance$2($$self, $$props, $$invalidate) { + function instance$1($$self, $$props, $$invalidate) { + let $selectedNodeData; + let $cyReady; + let $nodeIds; + let $edgeIds; let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('ListeningPracticeandSyllableStudy', slots, []); - let { syllableLists = [] } = $$props; - let currentSyllableIndices = Array(syllableLists.length).fill(0); - let displayTexts = syllableLists.map((list, index) => list[0]); - - function nextSyllable(wordIndex) { - if (currentSyllableIndices[wordIndex] < syllableLists[wordIndex].length - 1) { - currentSyllableIndices[wordIndex]++; - } else { - currentSyllableIndices[wordIndex] = 0; + validate_slots('GraphEditLoadTool', slots, []); + let cy; + let container; + let selectedNodeData = writable(null); + validate_store(selectedNodeData, 'selectedNodeData'); + component_subscribe($$self, selectedNodeData, value => $$invalidate(9, $selectedNodeData = value)); + let updatedLabel = ""; + let updatedType = ""; + let numberOfNodesToAdd = 1; + let sourceNodeId = ""; + let targetNodeId = ""; + let selectedEdge = ""; + let customScenario = ""; // Textarea input for custom scenarios + let currentGraphData = ""; // Textarea for displaying current graph data + const cyReady = writable(false); // Store to track if Cytoscape instance is ready + validate_store(cyReady, 'cyReady'); + component_subscribe($$self, cyReady, value => $$invalidate(10, $cyReady = value)); + const nodeIds = writable([]); // Store to track the list of node IDs + validate_store(nodeIds, 'nodeIds'); + component_subscribe($$self, nodeIds, value => $$invalidate(11, $nodeIds = value)); + const edgeIds = writable([]); // Store to track the list of edges + validate_store(edgeIds, 'edgeIds'); + component_subscribe($$self, edgeIds, value => $$invalidate(12, $edgeIds = value)); + + const dummyData = [ + { + file: 'ComponentA', + symbols: [ + { id: 'function1', type: 'function' }, + { id: 'variable1', type: 'variable' } + ], + edges: [{ source: 'variable1', target: 'function1' }] + }, + { + file: 'ComponentB', + symbols: [ + { id: 'function2', type: 'function' }, + { id: 'variable2', type: 'variable' } + ], + edges: [{ source: 'variable2', target: 'function2' }] } + ]; - updateDisplayText(wordIndex); - } + const createGraphElements = data => { + const elements = []; - function updateDisplayText(wordIndex) { - $$invalidate(1, displayTexts[wordIndex] = syllableLists[wordIndex].slice(0, currentSyllableIndices[wordIndex] + 1).join(''), displayTexts); - } + data.forEach(file => { + file.symbols.forEach(symbol => { + elements.push({ + data: { + id: symbol.id, + label: `${symbol.id} (${symbol.type})`, + type: symbol.type + } + }); + }); - const writable_props = ['syllableLists']; + file.edges.forEach(edge => { + if (edge.source && edge.target && edge.type) { + elements.push({ + data: { + source: edge.source, + target: edge.target, + type: edge.type + } + }); + } else { + console.error('Invalid edge format:', edge); + } + }); + }); - Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); - }); + return elements; + }; - const click_handler = index => nextSyllable(index); + const initializeScenario = () => { + const scenarioElements = [ + { + data: { + id: 'function1', + label: 'Function 1', + type: 'function' + } + }, + { + data: { + id: 'variable1', + label: 'Variable 1', + type: 'variable' + } + }, + { + data: { + id: 'function2', + label: 'Function 2', + type: 'function' + } + }, + { + data: { + id: 'variable2', + label: 'Variable 2', + type: 'variable' + } + }, + { + data: { + id: 'function3', + label: 'Function 3', + type: 'function' + } + }, + { + data: { + id: 'variable3', + label: 'Variable 3', + type: 'variable' + } + }, + { + data: { + source: 'function1', + target: 'variable1', + type: 'function-to-variable' + } + }, + { + data: { + source: 'variable1', + target: 'function2', + type: 'variable-to-function' + } + }, + { + data: { + source: 'function2', + target: 'variable2', + type: 'function-to-variable' + } + }, + { + data: { + source: 'function2', + target: 'function3', + type: 'function-to-function' + } + }, + { + data: { + source: 'function3', + target: 'variable3', + type: 'function-to-variable' + } + } + ]; - $$self.$$set = $$props => { - if ('syllableLists' in $$props) $$invalidate(0, syllableLists = $$props.syllableLists); + cy.add(scenarioElements); + cy.layout({ name: 'cose', animate: true }).run(); + updateNodeAndEdgeIds(); }; - $$self.$capture_state = () => ({ - syllableLists, - currentSyllableIndices, - displayTexts, - nextSyllable, - updateDisplayText - }); + const loadFromInputArea = () => { + try { + const customData = jsYaml.load(customScenario); + const customElements = createGraphElements(customData); + cy.elements().remove(); + cy.add(customElements); + cy.layout({ name: 'cose', animate: true }).run(); + updateNodeAndEdgeIds(); + } catch(e) { + alert('Invalid YAML'); + } + }; - $$self.$inject_state = $$props => { - if ('syllableLists' in $$props) $$invalidate(0, syllableLists = $$props.syllableLists); - if ('currentSyllableIndices' in $$props) currentSyllableIndices = $$props.currentSyllableIndices; - if ('displayTexts' in $$props) $$invalidate(1, displayTexts = $$props.displayTexts); + const loadFromGraphData = () => { + const symbols = cy.nodes().map(node => ({ + id: node.data('id'), + type: node.data('type') + })); + + const edges = cy.edges().map(edge => ({ + source: edge.data('source'), + target: edge.data('target'), + type: edge.data('type') + })); + + const graphData = [{ file: "CustomScenario", symbols, edges }]; + $$invalidate(8, currentGraphData = jsYaml.dump(graphData)); + $$invalidate(7, customScenario = currentGraphData); // Load data into the textarea as well }; - if ($$props && "$$inject" in $$props) { - $$self.$inject_state($$props.$$inject); - } + const handleUpdate = () => { + selectedNodeData.update(data => { + const newData = { + ...data, + label: updatedLabel, + type: updatedType + }; - return [syllableLists, displayTexts, nextSyllable, click_handler]; - } + updateNodeData(data.id, newData); + return newData; + }); + }; - class ListeningPracticeandSyllableStudy extends SvelteComponentDev { - constructor(options) { - super(options); - init(this, options, instance$2, create_fragment$2, safe_not_equal, { syllableLists: 0 }); + const handleDelete = () => { + if (confirm("Are you sure you want to delete this node?")) { + selectedNodeData.update(data => { + const node = cy.getElementById(data.id); - dispatch_dev("SvelteRegisterComponent", { - component: this, - tagName: "ListeningPracticeandSyllableStudy", - options, - id: create_fragment$2.name + if (node) { + node.remove(); + selectedNodeData.set(null); + updateNodeAndEdgeIds(); + } + + return null; + }); + } + }; + + const handleAddNodes = () => { + selectedNodeData.update(data => { + for (let i = 0; i < numberOfNodesToAdd; i++) { + const newId = `node${cy.nodes().length + 1}`; + + const newNode = { + data: { id: newId, label: newId, type: 'new' } + }; + + cy.add(newNode); + + cy.add({ + data: { + source: data.id, + target: newId, + type: 'function-to-variable' + } + }); + } + + cy.layout({ name: 'cose', animate: true }).run(); + updateNodeAndEdgeIds(); + return data; }); - } + }; - get syllableLists() { - throw new Error(": Props cannot be read directly from the component instance unless compiling with 'accessors: true' or ''"); - } + const handleAddNodeWithoutEdges = () => { + const newId = `node${cy.nodes().length + 1}`; - set syllableLists(value) { - throw new Error(": Props cannot be set directly on the component instance unless compiling with 'accessors: true' or ''"); - } - } + const newNode = { + data: { id: newId, label: newId, type: 'new' } + }; - /* src\Testspace.svelte generated by Svelte v3.59.2 */ + cy.add(newNode); + cy.layout({ name: 'cose', animate: true }).run(); + updateNodeAndEdgeIds(); + }; - const file$1 = "src\\Testspace.svelte"; + const handleAddEdge = () => { + if (sourceNodeId && targetNodeId && sourceNodeId !== targetNodeId) { + const sourceNode = cy.getElementById(sourceNodeId); + const targetNode = cy.getElementById(targetNodeId); + let edgeType = 'unknown'; - function create_fragment$1(ctx) { - let div; + if (sourceNode.data('type') === 'variable' && targetNode.data('type') === 'function') { + edgeType = 'variable-to-function'; + } else if (sourceNode.data('type') === 'function' && targetNode.data('type') === 'variable') { + edgeType = 'function-to-variable'; + } - const block = { - c: function create() { - div = element("div"); - add_location(div, file$1, 0, 0, 0); - }, - l: function claim(nodes) { - throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); - }, - m: function mount(target, anchor) { - insert_dev(target, div, anchor); - }, - p: noop, - i: noop, - o: noop, - d: function destroy(detaching) { - if (detaching) detach_dev(div); + cy.add({ + data: { + source: sourceNodeId, + target: targetNodeId, + type: edgeType + } + }); + + cy.layout({ name: 'cose', animate: true }).run(); + updateNodeAndEdgeIds(); } }; - dispatch_dev("SvelteRegisterBlock", { - block, - id: create_fragment$1.name, - type: "component", - source: "", - ctx + const handleDeleteEdge = () => { + if (selectedEdge) { + const [source, target] = selectedEdge.split(' -> '); + const edge = cy.edges(`[source="${source}"][target="${target}"]`); + + if (edge) { + edge.remove(); + cy.layout({ name: 'cose', animate: true }).run(); + updateNodeAndEdgeIds(); + } + } + }; + + const updateNodeAndEdgeIds = () => { + const ids = cy.nodes().map(node => node.id()); + nodeIds.set(ids); + const edges = cy.edges().map(edge => `${edge.data('source')} -> ${edge.data('target')}`); + edgeIds.set(edges); + }; + + const spaceOutNodes = () => { + cy.layout({ + name: 'grid', + padding: 10, + avoidOverlap: true, + avoidOverlapPadding: 20 + }).run(); + }; + + onMount(() => { + const elements = createGraphElements(dummyData); + + cy = cytoscape({ + container, + elements, + style: [ + { + selector: 'node', + style: { + 'label': 'data(label)', + 'text-valign': 'center', + 'text-halign': 'center', + 'background-color': '#61bffc', + 'color': '#fff', + 'text-outline-width': 2, + 'text-outline-color': '#888' + } + }, + { + selector: 'edge', + style: { + 'width': 3, + 'line-color'(ele) { + return ele.data('type') === 'variable-to-function' + ? '#33FF57' + : ele.data('type') === 'function-to-variable' + ? '#FF5733' + : '#ccc'; + }, + 'target-arrow-color'(ele) { + return ele.data('type') === 'variable-to-function' + ? '#33FF57' + : ele.data('type') === 'function-to-variable' + ? '#FF5733' + : '#ccc'; + }, + 'target-arrow-shape': 'triangle' + } + } + ], + layout: { name: 'cose', animate: true } + }); + + cy.on('tap', 'node', function (event) { + const node = event.target; + selectedNodeData.set(node.data()); + $$invalidate(1, updatedLabel = node.data().label); + $$invalidate(2, updatedType = node.data().type); + }); + + cyReady.set(true); // Set cyReady to true once Cytoscape is initialized + updateNodeAndEdgeIds(); // Initialize node and edge IDs }); - return block; - } + onDestroy(() => { + if (cy) { + cy.destroy(); + } + }); + + const fitGraph = () => { + if (cy) { + cy.fit(); + } + }; + + const addEmptyLines = () => { + const currentLines = currentGraphData.split('\n'); + const customLines = customScenario.split('\n'); + const maxLength = Math.max(currentLines.length, customLines.length); + const newCurrentGraphData = []; + const newCustomScenario = []; + + for (let i = 0; i < maxLength; i++) { + newCurrentGraphData.push(currentLines[i] || ''); + newCustomScenario.push(customLines[i] || ''); + } + + $$invalidate(8, currentGraphData = newCurrentGraphData.join('\n')); + $$invalidate(7, customScenario = newCustomScenario.join('\n')); + }; - function instance$1($$self, $$props) { - let { $$slots: slots = {}, $$scope } = $$props; - validate_slots('Testspace', slots, []); const writable_props = []; Object.keys($$props).forEach(key => { - if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console.warn(` was created with unknown prop '${key}'`); + if (!~writable_props.indexOf(key) && key.slice(0, 2) !== '$$' && key !== 'slot') console_1.warn(` was created with unknown prop '${key}'`); }); - return []; + function div0_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + container = $$value; + $$invalidate(0, container); + }); + } + + function input0_input_handler() { + updatedLabel = this.value; + $$invalidate(1, updatedLabel); + } + + function input1_input_handler() { + updatedType = this.value; + $$invalidate(2, updatedType); + } + + function input2_input_handler() { + numberOfNodesToAdd = to_number(this.value); + $$invalidate(3, numberOfNodesToAdd); + } + + function select_change_handler() { + sourceNodeId = select_value(this); + $$invalidate(4, sourceNodeId); + } + + function select_change_handler_1() { + targetNodeId = select_value(this); + $$invalidate(5, targetNodeId); + } + + function select_change_handler_2() { + selectedEdge = select_value(this); + $$invalidate(6, selectedEdge); + } + + function textarea0_input_handler() { + currentGraphData = this.value; + $$invalidate(8, currentGraphData); + } + + function textarea1_input_handler() { + customScenario = this.value; + $$invalidate(7, customScenario); + } + + $$self.$capture_state = () => ({ + onMount, + onDestroy, + cytoscape, + yaml: jsYaml, + writable, + cy, + container, + selectedNodeData, + updatedLabel, + updatedType, + numberOfNodesToAdd, + sourceNodeId, + targetNodeId, + selectedEdge, + customScenario, + currentGraphData, + cyReady, + nodeIds, + edgeIds, + dummyData, + createGraphElements, + initializeScenario, + loadFromInputArea, + loadFromGraphData, + handleUpdate, + handleDelete, + handleAddNodes, + handleAddNodeWithoutEdges, + handleAddEdge, + handleDeleteEdge, + updateNodeAndEdgeIds, + spaceOutNodes, + fitGraph, + addEmptyLines, + $selectedNodeData, + $cyReady, + $nodeIds, + $edgeIds + }); + + $$self.$inject_state = $$props => { + if ('cy' in $$props) cy = $$props.cy; + if ('container' in $$props) $$invalidate(0, container = $$props.container); + if ('selectedNodeData' in $$props) $$invalidate(13, selectedNodeData = $$props.selectedNodeData); + if ('updatedLabel' in $$props) $$invalidate(1, updatedLabel = $$props.updatedLabel); + if ('updatedType' in $$props) $$invalidate(2, updatedType = $$props.updatedType); + if ('numberOfNodesToAdd' in $$props) $$invalidate(3, numberOfNodesToAdd = $$props.numberOfNodesToAdd); + if ('sourceNodeId' in $$props) $$invalidate(4, sourceNodeId = $$props.sourceNodeId); + if ('targetNodeId' in $$props) $$invalidate(5, targetNodeId = $$props.targetNodeId); + if ('selectedEdge' in $$props) $$invalidate(6, selectedEdge = $$props.selectedEdge); + if ('customScenario' in $$props) $$invalidate(7, customScenario = $$props.customScenario); + if ('currentGraphData' in $$props) $$invalidate(8, currentGraphData = $$props.currentGraphData); + }; + + if ($$props && "$$inject" in $$props) { + $$self.$inject_state($$props.$$inject); + } + + return [ + container, + updatedLabel, + updatedType, + numberOfNodesToAdd, + sourceNodeId, + targetNodeId, + selectedEdge, + customScenario, + currentGraphData, + $selectedNodeData, + $cyReady, + $nodeIds, + $edgeIds, + selectedNodeData, + cyReady, + nodeIds, + edgeIds, + initializeScenario, + loadFromInputArea, + loadFromGraphData, + handleUpdate, + handleDelete, + handleAddNodes, + handleAddNodeWithoutEdges, + handleAddEdge, + handleDeleteEdge, + spaceOutNodes, + fitGraph, + addEmptyLines, + div0_binding, + input0_input_handler, + input1_input_handler, + input2_input_handler, + select_change_handler, + select_change_handler_1, + select_change_handler_2, + textarea0_input_handler, + textarea1_input_handler + ]; } - class Testspace extends SvelteComponentDev { + class GraphEditLoadTool extends SvelteComponentDev { constructor(options) { super(options); - init(this, options, instance$1, create_fragment$1, safe_not_equal, {}); + init(this, options, instance$1, create_fragment$1, safe_not_equal, {}, null, [-1, -1]); dispatch_dev("SvelteRegisterComponent", { component: this, - tagName: "Testspace", + tagName: "GraphEditLoadTool", options, id: create_fragment$1.name }); @@ -68585,8 +114029,8 @@ var app = (function () { /* src\App.svelte generated by Svelte v3.59.2 */ const file = "src\\App.svelte"; - // (46:1) - function create_default_slot(ctx) { + // (56:1) + function create_default_slot_4(ctx) { let h3; let t1; let div6; @@ -68624,46 +114068,46 @@ var app = (function () { const block = { c: function create() { - h3 = element("h3"); + h3 = element$1("h3"); h3.textContent = "(Through Gradio and Custom Components)"; t1 = space(); - div6 = element("div"); - div0 = element("div"); + div6 = element$1("div"); + div0 = element$1("div"); create_component(copyremove.$$.fragment); t2 = space(); - div1 = element("div"); + div1 = element$1("div"); create_component(llmwf.$$.fragment); t3 = space(); - div2 = element("div"); + div2 = element$1("div"); create_component(subrepprac.$$.fragment); t4 = space(); - div3 = element("div"); + div3 = element$1("div"); create_component(readingstatecounter.$$.fragment); t5 = space(); - div4 = element("div"); + div4 = element$1("div"); t6 = text("Works well with this prompt + gemini: (Please seperate the words into a list and have the roman and english in brackets next to each word:) "); - br = element("br"); + br = element$1("br"); t7 = text(" Current Practice flow plan User steps: 1) get lyrics (youtube/genius/whisper/other) 2) send to gemini with prompt 3)Enter into new component which starts with scramble spelling with dropdowns then scramble spelling using typing then moves to \n\t\t\t\t"); create_component(orderaspractice.$$.fragment); t8 = space(); - div5 = element("div"); + div5 = element$1("div"); create_component(firstsyllable.$$.fragment); - add_location(h3, file, 46, 2, 1835); + add_location(h3, file, 56, 2, 2563); attr_dev(div0, "class", "componentborder svelte-192gzri"); - add_location(div0, file, 49, 3, 1934); + add_location(div0, file, 59, 3, 2662); attr_dev(div1, "class", "componentborder svelte-192gzri"); - add_location(div1, file, 50, 3, 1987); + add_location(div1, file, 60, 3, 2715); attr_dev(div2, "class", "componentborder svelte-192gzri"); - add_location(div2, file, 51, 3, 2035); + add_location(div2, file, 61, 3, 2763); attr_dev(div3, "class", "componentborder svelte-192gzri"); - add_location(div3, file, 52, 3, 2088); - add_location(br, file, 54, 144, 2324); + add_location(div3, file, 62, 3, 2816); + add_location(br, file, 64, 144, 3052); attr_dev(div4, "class", "componentborder svelte-192gzri"); - add_location(div4, file, 53, 3, 2150); + add_location(div4, file, 63, 3, 2878); attr_dev(div5, "class", "componentborder svelte-192gzri"); - add_location(div5, file, 57, 3, 2611); + add_location(div5, file, 67, 3, 3339); attr_dev(div6, "class", "grid-MultiComponentContainer svelte-192gzri"); - add_location(div6, file, 48, 2, 1888); + add_location(div6, file, 58, 2, 2616); }, m: function mount(target, anchor) { insert_dev(target, h3, anchor); @@ -68691,7 +114135,7 @@ var app = (function () { mount_component(firstsyllable, div5, null); current = true; }, - p: noop, + p: noop$2, i: function intro(local) { if (current) return; transition_in(copyremove.$$.fragment, local); @@ -68724,11 +114168,211 @@ var app = (function () { } }; + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_4.name, + type: "slot", + source: "(56:1) ", + ctx + }); + + return block; + } + + // (74:1) + function create_default_slot_3(ctx) { + let nestedcommentssvelte; + let current; + nestedcommentssvelte = new RecursiveNestedCommentsElement({ $$inline: true }); + + const block = { + c: function create() { + create_component(nestedcommentssvelte.$$.fragment); + }, + m: function mount(target, anchor) { + mount_component(nestedcommentssvelte, target, anchor); + current = true; + }, + i: function intro(local) { + if (current) return; + transition_in(nestedcommentssvelte.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(nestedcommentssvelte.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(nestedcommentssvelte, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_3.name, + type: "slot", + source: "(74:1) ", + ctx + }); + + return block; + } + + // (78:1) + function create_default_slot_2(ctx) { + let myyoutube; + let t; + let ytpicsubs; + let current; + myyoutube = new YoutubeIframeAPICustomInterface({ $$inline: true }); + ytpicsubs = new PictureSubtitlesbasedonYTTranscript({ $$inline: true }); + + const block = { + c: function create() { + create_component(myyoutube.$$.fragment); + t = space(); + create_component(ytpicsubs.$$.fragment); + }, + m: function mount(target, anchor) { + mount_component(myyoutube, target, anchor); + insert_dev(target, t, anchor); + mount_component(ytpicsubs, target, anchor); + current = true; + }, + i: function intro(local) { + if (current) return; + transition_in(myyoutube.$$.fragment, local); + transition_in(ytpicsubs.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(myyoutube.$$.fragment, local); + transition_out(ytpicsubs.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(myyoutube, detaching); + if (detaching) detach_dev(t); + destroy_component(ytpicsubs, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_2.name, + type: "slot", + source: "(78:1) ", + ctx + }); + + return block; + } + + // (83:1) + function create_default_slot_1(ctx) { + let chessstudytool; + let current; + chessstudytool = new ChessStudyTool({ $$inline: true }); + + const block = { + c: function create() { + create_component(chessstudytool.$$.fragment); + }, + m: function mount(target, anchor) { + mount_component(chessstudytool, target, anchor); + current = true; + }, + i: function intro(local) { + if (current) return; + transition_in(chessstudytool.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(chessstudytool.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(chessstudytool, detaching); + } + }; + + dispatch_dev("SvelteRegisterBlock", { + block, + id: create_default_slot_1.name, + type: "slot", + source: "(83:1) ", + ctx + }); + + return block; + } + + // (87:1) + function create_default_slot(ctx) { + let grapheditloadtool; + let t0; + let codecompariontoolingraph; + let t1; + let h1; + let t2; + let b; + let t4; + let current; + grapheditloadtool = new GraphEditLoadTool({ $$inline: true }); + codecompariontoolingraph = new CodeComparionToolinGraph({ $$inline: true }); + + const block = { + c: function create() { + create_component(grapheditloadtool.$$.fragment); + t0 = space(); + create_component(codecompariontoolingraph.$$.fragment); + t1 = space(); + h1 = element$1("h1"); + t2 = text("Placeholder for: table of just input output pairs to plan intermediary nodes on the path to the solution ("); + b = element$1("b"); + b.textContent = "which should allow some flattened input and output for an llm to use"; + t4 = text(")"); + add_location(b, file, 89, 112, 4070); + attr_dev(h1, "class", "svelte-192gzri"); + add_location(h1, file, 89, 2, 3960); + }, + m: function mount(target, anchor) { + mount_component(grapheditloadtool, target, anchor); + insert_dev(target, t0, anchor); + mount_component(codecompariontoolingraph, target, anchor); + insert_dev(target, t1, anchor); + insert_dev(target, h1, anchor); + append_dev(h1, t2); + append_dev(h1, b); + append_dev(h1, t4); + current = true; + }, + p: noop$2, + i: function intro(local) { + if (current) return; + transition_in(grapheditloadtool.$$.fragment, local); + transition_in(codecompariontoolingraph.$$.fragment, local); + current = true; + }, + o: function outro(local) { + transition_out(grapheditloadtool.$$.fragment, local); + transition_out(codecompariontoolingraph.$$.fragment, local); + current = false; + }, + d: function destroy(detaching) { + destroy_component(grapheditloadtool, detaching); + if (detaching) detach_dev(t0); + destroy_component(codecompariontoolingraph, detaching); + if (detaching) detach_dev(t1); + if (detaching) detach_dev(h1); + } + }; + dispatch_dev("SvelteRegisterBlock", { block, id: create_default_slot.name, type: "slot", - source: "(46:1) ", + source: "(87:1) ", ctx }); @@ -68753,86 +114397,139 @@ var app = (function () { let t10; let h11; let t12; - let simplecollapsible; - let t13; - let nestedcommentssvelte; + let div; + let h21; let t14; - let myyoutube; + let br; let t15; - let ytpicsubs; let t16; - let h12; + let simplecollapsible0; + let t17; + let simplecollapsible1; let t18; - let h21; + let simplecollapsible2; + let t19; + let simplecollapsible3; let t20; + let simplecollapsible4; + let t21; + let h12; + let t23; + let h22; + let t25; let dotgame; let current; testspace = new Testspace({ $$inline: true }); - simplecollapsible = new SimpleCollapsible({ + simplecollapsible0 = new SimpleCollapsible({ props: { title: "Random Text Idea Tests", + $$slots: { default: [create_default_slot_4] }, + $$scope: { ctx } + }, + $$inline: true + }); + + simplecollapsible1 = new SimpleCollapsible({ + props: { + title: "Nested Comments Idea", + $$slots: { default: [create_default_slot_3] }, + $$scope: { ctx } + }, + $$inline: true + }); + + simplecollapsible2 = new SimpleCollapsible({ + props: { + title: "YT Player Idea", + $$slots: { default: [create_default_slot_2] }, + $$scope: { ctx } + }, + $$inline: true + }); + + simplecollapsible3 = new SimpleCollapsible({ + props: { + title: "Chess Loader as a glossary/vocab repitition Tool", + $$slots: { default: [create_default_slot_1] }, + $$scope: { ctx } + }, + $$inline: true + }); + + simplecollapsible4 = new SimpleCollapsible({ + props: { + title: "Text/Code to YAML to Graph Ideas for Visual structure", $$slots: { default: [create_default_slot] }, $$scope: { ctx } }, $$inline: true }); - nestedcommentssvelte = new RecursiveNestedCommentsElement({ $$inline: true }); - myyoutube = new YoutubeIframeAPICustomInterface({ $$inline: true }); - ytpicsubs = new PictureSubtitlesbasedonYTTranscript({ $$inline: true }); dotgame = new MovingDotSpacePortfromReact({ $$inline: true }); const block = { c: function create() { - main = element("main"); + main = element$1("main"); create_component(testspace.$$.fragment); t0 = space(); - h10 = element("h1"); + h10 = element$1("h1"); t1 = text("LLM Assisted Hello "); t2 = text(/*name*/ ctx[0]); t3 = text("!"); t4 = space(); - h20 = element("h2"); + h20 = element$1("h2"); h20.textContent = "(I forgot to log how many prompts to make the whole page. As most of code is from llms, a planning LLM could have made this in 1 day. Prompts to app should be a benchmark)"; t6 = space(); - p = element("p"); + p = element$1("p"); t7 = text("Visit the "); - a = element("a"); + a = element$1("a"); a.textContent = "Svelte tutorial"; t9 = text(" to learn how to build Svelte apps. (or ask Claude / GPT4 for help)"); t10 = space(); - h11 = element("h1"); - h11.textContent = "Brainstorm for Educational Interfaces to add LLM and other models into"; + h11 = element$1("h1"); + h11.textContent = "Brainstorm for Educational Interfaces to add LLM and other models into (Which gradio 3 couldnt do at the time)"; t12 = space(); - create_component(simplecollapsible.$$.fragment); - t13 = space(); - create_component(nestedcommentssvelte.$$.fragment); - t14 = space(); - create_component(myyoutube.$$.fragment); - t15 = space(); - create_component(ytpicsubs.$$.fragment); + div = element$1("div"); + h21 = element$1("h2"); + h21.textContent = "Random Idea"; + t14 = text("\n\t\tLearning through analogies - comprehension of abstract things is easiest with things you can see (shapes and structures) so to learn quick you have to keep giving an llm a pair of contrasting items in your mind you think are closest to the concept and it will gradually help you move towards the 'most effiecient shape' for the idea you are learning\n\t\t"); + br = element$1("br"); + t15 = text(" eg. embedding space is closer to a cup with air or a plastic bag with randomly shaped item inside."); t16 = space(); - h12 = element("h1"); - h12.textContent = "Themeable Game Brainstorm - Image + Lists - Game as Universal Translator for any subject"; + create_component(simplecollapsible0.$$.fragment); + t17 = space(); + create_component(simplecollapsible1.$$.fragment); t18 = space(); - h21 = element("h2"); - h21.textContent = "Also bridge to testing on low pc before auto refactor pipeline to unreal engine = truly multiplatform game"; + create_component(simplecollapsible2.$$.fragment); + t19 = space(); + create_component(simplecollapsible3.$$.fragment); t20 = space(); + create_component(simplecollapsible4.$$.fragment); + t21 = space(); + h12 = element$1("h1"); + h12.textContent = "Themeable Game Brainstorm - Image + Lists - Game as Universal Translator for any subject - Textbook to Realwork Demonstation / Mockup of Digital Twin / Custom Game playing"; + t23 = space(); + h22 = element$1("h2"); + h22.textContent = "Also bridge to testing on low pc before auto refactor pipeline to playcanvas and then to unreal engine = truly multiplatform game"; + t25 = space(); create_component(dotgame.$$.fragment); attr_dev(h10, "class", "svelte-192gzri"); - add_location(h10, file, 38, 1, 1213); - add_location(h20, file, 39, 1, 1250); + add_location(h10, file, 42, 1, 1405); + add_location(h20, file, 43, 1, 1442); attr_dev(a, "href", "https://svelte.dev/tutorial"); - add_location(a, file, 40, 14, 1445); - add_location(p, file, 40, 1, 1432); + add_location(a, file, 44, 14, 1637); + add_location(p, file, 44, 1, 1624); attr_dev(h11, "class", "svelte-192gzri"); - add_location(h11, file, 44, 1, 1699); + add_location(h11, file, 48, 1, 1891); + add_location(h21, file, 50, 2, 2021); + add_location(br, file, 52, 2, 2396); + add_location(div, file, 49, 1, 2013); attr_dev(h12, "class", "svelte-192gzri"); - add_location(h12, file, 67, 1, 2829); - add_location(h21, file, 68, 1, 2930); + add_location(h12, file, 92, 1, 4177); + add_location(h22, file, 93, 1, 4361); attr_dev(main, "class", "svelte-192gzri"); - add_location(main, file, 36, 0, 1190); + add_location(main, file, 39, 0, 1381); }, l: function claim(nodes) { throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option"); @@ -68855,57 +114552,96 @@ var app = (function () { append_dev(main, t10); append_dev(main, h11); append_dev(main, t12); - mount_component(simplecollapsible, main, null); - append_dev(main, t13); - mount_component(nestedcommentssvelte, main, null); - append_dev(main, t14); - mount_component(myyoutube, main, null); - append_dev(main, t15); - mount_component(ytpicsubs, main, null); + append_dev(main, div); + append_dev(div, h21); + append_dev(div, t14); + append_dev(div, br); + append_dev(div, t15); append_dev(main, t16); - append_dev(main, h12); + mount_component(simplecollapsible0, main, null); + append_dev(main, t17); + mount_component(simplecollapsible1, main, null); append_dev(main, t18); - append_dev(main, h21); + mount_component(simplecollapsible2, main, null); + append_dev(main, t19); + mount_component(simplecollapsible3, main, null); append_dev(main, t20); + mount_component(simplecollapsible4, main, null); + append_dev(main, t21); + append_dev(main, h12); + append_dev(main, t23); + append_dev(main, h22); + append_dev(main, t25); mount_component(dotgame, main, null); current = true; }, p: function update(ctx, [dirty]) { if (!current || dirty & /*name*/ 1) set_data_dev(t2, /*name*/ ctx[0]); - const simplecollapsible_changes = {}; + const simplecollapsible0_changes = {}; if (dirty & /*$$scope*/ 64) { - simplecollapsible_changes.$$scope = { dirty, ctx }; + simplecollapsible0_changes.$$scope = { dirty, ctx }; } - simplecollapsible.$set(simplecollapsible_changes); + simplecollapsible0.$set(simplecollapsible0_changes); + const simplecollapsible1_changes = {}; + + if (dirty & /*$$scope*/ 64) { + simplecollapsible1_changes.$$scope = { dirty, ctx }; + } + + simplecollapsible1.$set(simplecollapsible1_changes); + const simplecollapsible2_changes = {}; + + if (dirty & /*$$scope*/ 64) { + simplecollapsible2_changes.$$scope = { dirty, ctx }; + } + + simplecollapsible2.$set(simplecollapsible2_changes); + const simplecollapsible3_changes = {}; + + if (dirty & /*$$scope*/ 64) { + simplecollapsible3_changes.$$scope = { dirty, ctx }; + } + + simplecollapsible3.$set(simplecollapsible3_changes); + const simplecollapsible4_changes = {}; + + if (dirty & /*$$scope*/ 64) { + simplecollapsible4_changes.$$scope = { dirty, ctx }; + } + + simplecollapsible4.$set(simplecollapsible4_changes); }, i: function intro(local) { if (current) return; transition_in(testspace.$$.fragment, local); - transition_in(simplecollapsible.$$.fragment, local); - transition_in(nestedcommentssvelte.$$.fragment, local); - transition_in(myyoutube.$$.fragment, local); - transition_in(ytpicsubs.$$.fragment, local); + transition_in(simplecollapsible0.$$.fragment, local); + transition_in(simplecollapsible1.$$.fragment, local); + transition_in(simplecollapsible2.$$.fragment, local); + transition_in(simplecollapsible3.$$.fragment, local); + transition_in(simplecollapsible4.$$.fragment, local); transition_in(dotgame.$$.fragment, local); current = true; }, o: function outro(local) { transition_out(testspace.$$.fragment, local); - transition_out(simplecollapsible.$$.fragment, local); - transition_out(nestedcommentssvelte.$$.fragment, local); - transition_out(myyoutube.$$.fragment, local); - transition_out(ytpicsubs.$$.fragment, local); + transition_out(simplecollapsible0.$$.fragment, local); + transition_out(simplecollapsible1.$$.fragment, local); + transition_out(simplecollapsible2.$$.fragment, local); + transition_out(simplecollapsible3.$$.fragment, local); + transition_out(simplecollapsible4.$$.fragment, local); transition_out(dotgame.$$.fragment, local); current = false; }, d: function destroy(detaching) { if (detaching) detach_dev(main); destroy_component(testspace); - destroy_component(simplecollapsible); - destroy_component(nestedcommentssvelte); - destroy_component(myyoutube); - destroy_component(ytpicsubs); + destroy_component(simplecollapsible0); + destroy_component(simplecollapsible1); + destroy_component(simplecollapsible2); + destroy_component(simplecollapsible3); + destroy_component(simplecollapsible4); destroy_component(dotgame); } }; @@ -68974,6 +114710,9 @@ var app = (function () { FirstSyllable: ListeningPracticeandSyllableStudy, Testspace, SimpleCollapsible, + ChessStudyTool, + CodeComparionToolinGraph, + GraphEditLoadTool, showModal, openModal, closeModal,