// LittleJS Engine - MIT License - Copyright 2021 Frank Force // https://github.com/KilledByAPixel/LittleJS const engineName="LittleJS",engineVersion="1.27.2",frameRate=60;let timeDelta=1/frameRate,engineObjects=[],engineObjectsCollide=[],engineObjectsCollideStaticLast=[],frame=0,time=0,timeReal=0,paused=!1;function getPaused(){return paused}function setPaused(a=!0){paused=a}let averageFPS=0,frameTimeLastMS=0,frameTimeBufferMS=0;const frameDeltaHistory=[];let frameIntervalMS=1e3/60,frameDeltaCarryMS=0,frameDeltaCarryAverageMS=0,frameDeltaSmoothing=!0;function engineSmoothDelta(a){if(!(0a){frameDeltaHistory.push(a);64g-h);const[c,d]=engineFrameFit(frameIntervalMS),[e,f]=engineFrameFit(b[b.length>>2]);frameIntervalMS=d<=f?c:e;frameDeltaSmoothing=min(d,f)<(frameDeltaSmoothing?.2:.12)}if(!frameDeltaSmoothing)return a+=frameDeltaCarryMS,frameDeltaCarryMS=min(a,0),frameDeltaCarryAverageMS=0,max(a,0);b=frameDeltaCarryAverageMS/32;frameDeltaCarryMS+=a;a=round((frameDeltaCarryMS-b)/frameIntervalMS);if(1>a)return 0;a=a*frameIntervalMS+b;frameDeltaCarryMS-=a;frameDeltaCarryAverageMS+=(frameDeltaCarryMS-frameDeltaCarryAverageMS)/32;return a}function engineFrameFit(a){var b=0;let c=0,d=0,e=0,f=0,g=0,h=0;const k=frameDeltaHistory.length;for(const l of frameDeltaHistory){const m=max(1,round(l/a));b+=l;c+=m;d+=abs(l-m*a);e+=c;f+=b;g+=c*c;h+=c*b}b=k*g-e*e;return[b?(k*h-e*f)/b:a,d/k/a]}let timeFixedStart=0,frameFixedStart=0,windowWidthLast=0,windowHeightLast=0,windowPixelRatioLast=0,engineUpdateInternal,engineFrameScheduled=!1,engineFrameErrorLast;const engineObjectsCollidePairs=new Map;function engineObjectsCollidePairAnswer(a,b){return engineObjectsCollidePairs.get(a)?.get(b)}function engineObjectsCollidePairAdd(a,b,c=!1){let d=engineObjectsCollidePairs.get(a);d||engineObjectsCollidePairs.set(a,d=new Map);d.set(b,c)}let engineCollideGridMin=64,engineCollideGrid,engineObjectsOneWayStart;function engineCollideGridBuild(a){let b=0;for(const e of a)b+=min(max(abs(e.size.x),abs(e.size.y)),16)||0;const c=new Map,d={size:max(2*b/a.length,.5),cells:new Map,at:new Map,index:c,big:new Set,seen:new Map,stamp:0,byIndex:(e,f)=>c.get(e)-c.get(f)};a.forEach((e,f)=>{c.set(e,f);engineCollideGridPlace(d,e)});return d}const engineCollideGridBox=[0,0,0,0];function engineCollideGridCells(a,b){a=a.size;const c=abs(b.size.x)/2,d=abs(b.size.y)/2,e=engineCollideGridBox;e[0]=floor((b.pos.x-c)/a);e[1]=floor((b.pos.y-d)/a);e[2]=floor((b.pos.x+c)/a);e[3]=floor((b.pos.y+d)/a);return e}const engineCollideGridFits=(a,b,c,d)=>1024>=(c-a+1)*(d-b+1)&&abs(a)<2**31&&abs(b)<2**31&&abs(c)<2**31&&abs(d)<2**31;function engineCollideGridPlace(a,b){if(a.index.has(b)){var[c,d,e,f]=engineCollideGridCells(a,b),g=!engineCollideGridFits(c,d,e,f),h=a.at.get(b);if(!h||h[0]!==c||h[1]!==d||h[2]!==e||h[3]!==f||h[4]!==g){if(h&&!h[4])for(var k=h[0];k<=h[2];++k)for(var l=h[1];l<=h[3];++l){var m=a.cells.get(1048576*k+l);m.splice(m.indexOf(b),1)}a.big.delete(b);if(g)a.big.add(b);else for(h=c;h<=e;++h)for(k=d;k<=f;++k)l=1048576*h+k,(m=a.cells.get(l))?m.push(b):a.cells.set(l,[b]);a.at.set(b,[c,d,e,f,g])}}}function engineCollideGridNear(a,b,c,d){const[e,f,g,h]=engineCollideGridCells(a,b);b=++a.stamp;d.length=0;for(var k of a.big)engineCollideGridAdd(a,k,c,b,d);if(engineCollideGridFits(e,f,g,h))for(k=e;k<=g;++k)for(var l=f;l<=h;++l){const m=a.cells.get(1048576*k+l);if(m)for(const n of m)engineCollideGridAdd(a,n,c,b,d)}else for(l of a.index.keys())engineCollideGridAdd(a,l,c,b,d);d.sort(a.byIndex)}function engineCollideGridAdd(a,b,c,d,e){a.seen.get(b)!==d&&(a.seen.set(b,d),a.index.get(b)>c&&e.push(b))}function*engineCollideGridWalk(a){var b;const c=(b=engineCollideGrid).built||(b.built=engineCollideGridBuild(engineCollideGrid.list));b=-1;let d,e,f,g,h=0;const k=[];for(;;){if(a.pos.x!==d||a.pos.y!==e||a.size.x!==f||a.size.y!==g)d=a.pos.x,e=a.pos.y,f=a.size.x,g=a.size.y,engineCollideGridNear(c,a,b,k),h=0;if(h>=k.length)break;const l=k[h++];b=c.index.get(l);yield l}}let engineInitialized=!1,engineInitDone,engineLoads,engineLoadsDone=0,engineObjectsUpdateCount=0;const engineChildStack=[];let showEngineVersion=!0;const pluginList=[];class EnginePlugin{constructor(a,b,c,d,e){this.update=a;this.render=b;this.glContextLost=c;this.glContextRestored=d;this.preRender=e}}function engineAddPlugin(a,b,c,d,e){a=new EnginePlugin(a,b,c,d,e);pluginList.push(a)}function engineAddLoad(a){if(engineLoads){engineLoads.push(a);const b=()=>{++engineLoadsDone};a.then(b,b)}return a}async function engineWaitForLoads(){let a=!0;const b=performance.now(),c=()=>{a&&(engineLoadingScreenDraw((performance.now()-b)/1e3),setTimeout(c,16))};headlessMode||c();try{for(let d;d!==engineLoads.length;)d=engineLoads.length,await Promise.allSettled(engineLoads)}finally{a=!1}}function engineLoadingScreenDraw(a){headlessMode||!loadingScreen||.5>a||(inputClear(),engineUpdateCanvas(),loadingScreen(engineLoadsDone/engineLoads.length))}async function engineInit(a,b,c,d,e,f=[],g){function h(){editorPreRender();mainContext.imageSmoothingEnabled=!tilesPixelated;glPreRender();setShader();pluginList.forEach(n=>n.preRender?.())}function k(n=0){function r(x){y=!0;engineUpdateCanvas();inputUpdate();x||b();pluginList.forEach(w=>w.update?.());if(x){for(const w of engineObjects)w.parent||w.updateTransforms();engineObjects.some(w=>w.destroyed)&&(engineObjects=engineObjects.filter(w=>!w.destroyed))}else engineObjectsUpdate();debugUpdate();c();inputUpdatePost()}function q(){if(!headlessMode){y||engineUpdateCanvas();h();d();engineObjectsSort();for(const x of engineObjects)x.destroyed||(setShader(x.shader),x.render());setShader();e();setShader();setAdditiveBlendMode(!1);pluginList.forEach(x=>x.render?.());inputRender();debugRender();glFlush();primitiveCount=drawCount=0}}var p=engineManualStep,t=n-frameTimeLastMS;frameTimeLastMS||(t=0);frameTimeLastMS=n;t&&1e3>t&&(averageFPS=averageFPS?lerp(averageFPS,1e3/t,.05):1e3/t);p||(t=engineSmoothDelta(t));audioUpdateVolume();var u=debug&&(debugOverlay||debugKeysAlways);n=u&&keyIsDown("Equal");u=u&&keyIsDown("Minus");n=n?10:u?.1:1;u=t;timeReal+=t*n/1e3;const v=timeScale*n;t*=v;let y=!1;if(engineVariableStep){if(0frameTimeBufferMS&&-9{await Promise.all(n);await a()})();engineAddLoad(r);await engineWaitForLoads();engineLoads=void 0;await r;engineUpdateInternal=k;if(!engineManualStep){if(debug)return k();try{k()}catch(q){engineFrameFailed(q)}}}if(engineInitialized)return engineInitDone;engineInitialized=!0;showEngineVersion&&console.log(`${engineName} Engine v${engineVersion}`);engineLoads=[];engineLoadsDone=0;"string"===typeof f&&(f=[f]);a||=()=>{};b||=()=>{};c||=()=>{};d||=()=>{};e||=()=>{};if(headlessMode)return engineInitDone=l([]);document.body||document.documentElement.appendChild(document.createElement("body"));g||=document.body;glInit(g);let m="margin:0;overflow:hidden;background:#000;user-select:none;-webkit-user-select:none;touch-action:none;-webkit-touch-callout:none;";g!==document.body&&g.clientHeight&&"static"===getComputedStyle(g).position&&(m+="position:relative;");g.style.cssText=m+g.style.cssText;mainCanvas=g.appendChild(document.createElement("canvas"));drawContext=mainContext=mainCanvas.getContext("2d");inputInit();audioInit();debugInit();mainCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";glCanvas&&(glCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)");setCanvasPixelated(canvasPixelated);engineUpdateCanvas();glPreRender();workContext=createCanvasContext(64);workCanvas=workContext.canvas;workReadContext=createCanvasContext(64,64,!0);workReadCanvas=workReadContext.canvas;g=f.map((n,r)=>loadTexture(r,n));f.length||g.push(loadTexture(0));g.push(imageFontInit());showSplashScreen&&(f=new Promise(n=>{function r(){inputClear();drawEngineLogo(q+=.01);1canvasMaxAspect?mainCanvasSize.x=min(mainCanvasSize.y*canvasMaxAspect|0,canvasMaxSize.x):c{engineFrameScheduled=!1;if(!engineManualStep){if(debug)return engineUpdateInternal(b);try{engineUpdateInternal(b)}catch(c){engineFrameFailed(c)}}};"function"===typeof requestAnimationFrame?requestAnimationFrame(a):setTimeout(()=>a(performance.now()),1e3/frameRate)}}const engineStepMaxFrames=36e3;function engineStep(a=1){if(engineManualStep&&engineUpdateInternal)for(a=min(a,engineStepMaxFrames);0=engineCollideGridMin&&(engineCollideGrid={list:engineObjectsCollideStaticLast,built:void 0});engineObjectsCollide.some(e=>e.oneWay)&&(engineObjectsOneWayStart=new Map(engineObjectsCollide.map(e=>[e,e.pos.copy()])));try{if(engineObjectsOneWayStart)for(const e of engineObjects)e.parent||e.destroyed||!e.oneWay||e.mass||(e.updatePhysics(),engineCollideGrid?.built&&engineCollideGridPlace(engineCollideGrid.built,e));for(const e of engineObjects)e.parent||e.destroyed||engineObjectsOneWayStart&&e.oneWay&&!e.mass||(e.updatePhysics(),engineCollideGrid?.built&&engineCollideGridPlace(engineCollideGrid.built,e))}finally{engineCollideGrid&&=void 0,engineObjectsOneWayStart&&=void 0}const d=engineObjectsUpdateCount;for(const e of engineObjects)b(e);for(const e of engineObjects)b(e);engineObjects.some(e=>e.destroyed)&&(engineObjects=engineObjects.filter(e=>!e.destroyed))}function engineObjectsSort(){for(let a=engineObjects.length;0<--a;)if(engineObjects[a].renderOrderb.renderOrder-c.renderOrder)}function engineObjectsDestroy(a=!0){for(const b of engineObjects)b.parent||b.persistent||b.destroy(a);engineObjects=engineObjects.filter(b=>!b.destroyed)}function engineObjectsCollect(a,b,c=engineObjects,d=!1){const e=[];if(a)if(!b||b instanceof Vector2){var f=b instanceof Vector2?b:vec2();for(var g of c)g.destroyed||(d?isOverlapping(a,f,g.pos):g.isOverlapping(a,f))&&e.push(g)}else{g=(b/2)**2;for(f of c)f.destroyed||(c=d?a.x-f.pos.x:max(abs(a.x-f.pos.x)-f.size.x/2,0),b=d?a.y-f.pos.y:max(abs(a.y-f.pos.y)-f.size.y/2,0),c*c+b*bMath.sign(a),hypot=Math.hypot,log2=a=>Math.log2(a),sin=Math.sin,cos=Math.cos,tan=Math.tan,atan2=Math.atan2;function mod(a,b=1){return(a%b+b)%b}function clamp(a,b=0,c=1){return ac?c:a}function percent(a,b,c){return(c-=b)?clamp((a-b)/c):0}function lerp(a,b,c){return a+clamp(c)*(b-a)}function percentLerp(a,b,c,d,e){return lerp(d,e,percent(a,b,c))}function distanceWrap(a,b,c=1){a=(a-b)%c;return 2*a%c-a}function lerpWrap(a,b,c,d=1){return a+clamp(c)*distanceWrap(b,a,d)}function distanceAngle(a,b){return distanceWrap(a,b,2*PI)}function lerpAngle(a,b,c){return lerpWrap(a,b,c,2*PI)}function smoothStep(a){a=clamp(a);return a*a*(3-2*a)}function isPowerOfTwo(a){return 0a[e]){if(f>d)return!1;c=max(f,c)}else{if(fb[e])return!1;return!0}function collideCircleCircle(a,b,c,d){a=a.subtract(c);b+=d;d=a.length();if(!(d>=b))return a.normalize(b-d)}function collideCircleBox(a,b,c,d){d=d.scale(.5);var e=vec2(clamp(a.x,c.x-d.x,c.x+d.x),clamp(a.y,c.y-d.y,c.y+d.y));e=a.subtract(e);const f=e.lengthSquared();if(f)return f>=b*b?void 0:e.normalize(b-f**.5);a=a.subtract(c);return pushOutAxis(a,d.x-abs(a.x),d.y-abs(a.y),b)}function collideBoxBox(a,b,c,d){a=a.subtract(c);c=(b.x+d.x)/2-abs(a.x);b=(b.y+d.y)/2-abs(a.y);if(!(0>=c||0>=b))return pushOutAxis(a,c,b)}function pushOutAxis(a,b,c,d=0){return b<=c?vec2((0<=a.x?1:-1)*(b+d),0):vec2(0,(0<=a.y?1:-1)*(c+d))}function oscillate(a=1,b=1,c=time,d=0,e=0){a=mod(d+c*a,1);e=1===e?1-2*abs(2*a-1):2===e?.5>a?-1:1:3===e?2*a-1:-cos(2*a*PI);return b/2*(e+1)}function isNumber(a){return"number"===typeof a&&a===a}function isStringLike(a){return null!=a&&"function"===typeof a.toString&&"string"===typeof a.toString()}function isArray(a){return Array.isArray(a)}function lineTest(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;const g=(e*e+f*f)**.5;if(g){b=a.floor();0>e&&b.x===a.x&&--b.x;0>f&&b.y===a.y&&--b.y;var h=e/g,k=f/g;e=sign(h);f=sign(k);var l=h?abs(1/h):Infinity,m=k?abs(1/k):Infinity,n=0b.x&&(a.x=b.x+1-1e-9),c.yb.y&&(a.y=b.y+1-1e-9),d&&(r?d.set(-e,0):d.set(0,-f)),a;(r=n=a)return new Vector2;b=clamp(b/a);return randVec2(a*rand(b*b,1)**.5)}function randColor(a=new Color,b=new Color(0,0,0,1),c=!1){return c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a))}class RandomGenerator{constructor(a=123456789){this.seed=a}float(a=1,b=0){this.seed=this.seed|0||123456789;this.seed^=this.seed<<13;this.seed^=this.seed>>>17;this.seed^=this.seed<<5;return b+(a-b)*noiseHash(this.seed)}int(a,b=0){return floor(this.float(a,b))}bool(a=.5){return this.float()a?this.scale(a/b):this.copy()}dot(a){return this.x*a.x+this.y*a.y}cross(a){return this.x*a.y-this.y*a.x}reflect(a,b=1){return this.subtract(a.scale((1+b)*this.dot(a)))}angle(){return atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*sin(a);this.y=b*cos(a);return this}rotate(a){const b=cos(-a);a=sin(-a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}setDirection(a,b=1){a=mod(a,4);this.x=a%2?a-1?-b:b:0;this.y=a%2?0:a?-b:b;return this}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}abs(){return new Vector2(abs(this.x),abs(this.y))}floor(){return new Vector2(floor(this.x),floor(this.y))}round(){return new Vector2(round(this.x),round(this.y))}snap(a){return new Vector2(floor(this.x*a)/a,floor(this.y*a)/a)}mod(a=1){return new Vector2(mod(this.x,a),mod(this.y,a))}area(){return abs(this.x*this.y)}lerp(a,b){b=clamp(b);return new Vector2(a.x*b+this.x*(1-b),a.y*b+this.y*(1-b))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.xthis.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`:`(${this.x}, ${this.y})`}isValid(){return isNumber(this.x)&&isNumber(this.y)}}function rgb(a,b,c,d){debug&&(2c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,g,h)=>1>6*(h=mod(h,1))?f+6*(g-f)*h:1>2*h?g:2>3*h?f+(g-f)*(4-6*h):f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}HSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=max(a,b,c),f=min(a,b,c),g=(e+f)/2;let h=0,k=0;if(e!==f){let l=e-f;k=.5(16>(c=round(255*clamp(c)))?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){6>a.length?(this.r=clamp(parseInt(a[1],16)/15),this.g=clamp(parseInt(a[2],16)/15),this.b=clamp(parseInt(a[3],16)/15),this.a=5===a.length?clamp(parseInt(a[4],16)/15):1):(this.r=clamp(parseInt(a.slice(1,3),16)/255),this.g=clamp(parseInt(a.slice(3,5),16)/255),this.b=clamp(parseInt(a.slice(5,7),16)/255),this.a=9===a.length?clamp(parseInt(a.slice(7,9),16)/255):1);return this}rgbaInt(){const a=255*clamp(this.r)+.5|0,b=255*clamp(this.g)+.5<<8,c=255*clamp(this.b)+.5<<16,d=255*clamp(this.a)+.5<<24;return a+b+c+d}isValid(){return isNumber(this.r)&&isNumber(this.g)&&isNumber(this.b)&&isNumber(this.a)}}const WHITE=debugProtectConstant(rgb()),CLEAR_WHITE=debugProtectConstant(rgb(1,1,1,0)),BLACK=debugProtectConstant(rgb(0,0,0)),CLEAR_BLACK=debugProtectConstant(rgb(0,0,0,0)),GRAY=debugProtectConstant(rgb(.5,.5,.5)),RED=debugProtectConstant(rgb(1,0,0)),ORANGE=debugProtectConstant(rgb(1,.5,0)),YELLOW=debugProtectConstant(rgb(1,1,0)),GREEN=debugProtectConstant(rgb(0,1,0)),CYAN=debugProtectConstant(rgb(0,1,1)),BLUE=debugProtectConstant(rgb(0,0,1)),PURPLE=debugProtectConstant(rgb(.5,0,1)),MAGENTA=debugProtectConstant(rgb(1,0,1));class Timer{constructor(a,b=!1){this.useRealTime=b;b=this.getGlobalTime();this.time=void 0===a?void 0:b+a;this.setTime=a}set(a=0){this.time=this.getGlobalTime()+a;this.setTime=a}setUseRealTime(a=!0){this.useRealTime=a}unset(){this.time=void 0}isSet(){return void 0!==this.time}active(){return this.getGlobalTime()=this.time}get(){return this.isSet()?this.getGlobalTime()-this.time:0}getPercent(){return this.isSet()?0this.get()?"before":"after"):"unset"}valueOf(){return this.get()}}function formatTime(a){const b=-1>=a?"-":"";a=abs(a)|0;return b+(a/60|0)+":"+(10>a%60?"0":"")+a%60}async function fetchJSON(a){var b=await loadFetch(a,"fetchJSON");if(!b.ok)throw Error(`fetchJSON: could not load ${a}, HTTP ${b.status} ${b.statusText}`);b=await b.text();let c;try{c=JSON.parse(b)}catch(d){throw Error(`fetchJSON: ${a} is not JSON`+(loadIsWebPage(b)?", it is a web page, so the path may be wrong":": "+d.message))}editorJSONFetched(a,c);return c}const loadIsWebPage=a=>/^\s*URL.revokeObjectURL(a),c)}function shareURL(a,b,c){navigator.share?.({title:a,url:b}).then(()=>c?.(),()=>{})}function readSaveData(a,b){let c={};try{const d=localStorage.getItem(a);if(d){try{c=JSON.parse(d)}catch{console.warn("readSaveData: the save "+a+" can not be read, using the defaults")}if(!c||"object"!==typeof c||isArray(c))c={}}}catch{}return{...b,...c}}function writeSaveData(a,b){let c;try{c=JSON.stringify(b)}catch(d){return console.warn("writeSaveData: the save "+a+" can not be written as JSON, "+d.message),!1}if(void 0===c)return console.warn("writeSaveData: the save "+a+" is nothing as JSON, it is not written"),!1;try{return localStorage.setItem(a,c),!0}catch{return console.warn("writeSaveData: the save "+a+" could not be written, storage is full or off"),!1}}function noiseHash(a){a=(a|0)^2654435769;a=Math.imul(a^a>>>16,2246822507);a=Math.imul(a^a>>>13,3266489909);return((a^a>>>16)>>>0)/2**32}function noise1D(a){const b=floor(a);return lerp(noiseHash(b),noiseHash(b+1),smoothStep(a-b))}function noise2D(a,b){const c=floor(a),d=floor(b);a=smoothStep(a-c);b=smoothStep(b-d);return lerp(lerp(noiseHash(c+Math.imul(d,374761393)),noiseHash(c+1+Math.imul(d,374761393)),a),lerp(noiseHash(c+Math.imul(d+1,374761393)),noiseHash(c+1+Math.imul(d+1,374761393)),a),b)}let cameraPos=vec2(),cameraAngle=0,cameraScale=32,timeScale=1,canvasColorTiles=!0,canvasClearColor=CLEAR_BLACK,canvasMaxSize=vec2(3840,2160),canvasMinAspect=0,canvasMaxAspect=0,canvasFixedSize=vec2(),canvasPixelated=!1,tilesPixelated=!0,canvasPixelRatio=1,fontDefault="arial",showSplashScreen=!1,loadingScreen=drawLoadingScreen,headlessMode=!1,engineManualStep=!1,engineVariableStep=!1,glEnable=!0,drawScreenSpace=!1,glCircleSides=32,tileDefaultSize=vec2(16),tileDefaultPadding=0,tileDefaultBleed=0,enablePhysicsSolver=!0,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultRestitution=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=vec2(),particleEmitRateScale=1,gamepadsEnable=!0,gamepadDirectionEmulateStick=!0,gamepadAxisFilterEnable=!0,inputWASDEmulateDirection=!0,touchInputEnable=!0,touchGamepadEnable=!1,touchGamepadPassthrough=!1,touchPinchWheel=!0,touchGamepadCenterButtonSize=0,touchGamepadButtonCount=4,touchGamepadLeftStick=!0,touchGamepadLeftButtonCount=0,touchGamepadRightStick=!1,touchGamepadAnalog=!0,touchGamepadFloating=!1,touchGamepadSize=100,touchGamepadAlpha=.3,touchGamepadDisplayTime=3,touchGamepadVibration=0,vibrateEnable=!0,soundEnable=!0,soundIgnoreSilentSwitch=!1,soundVolume=.3,soundDefaultRange=40,soundDefaultTaper=.7,soundPauseWhenHidden=!0;function setCameraPos(a){cameraPos=a.copy()}function setCameraAngle(a){cameraAngle=a}function setCameraScale(a){cameraScale=a}function setTimeScale(a){timeScale=max(0,a)}function setCanvasColorTiles(a){canvasColorTiles=a}function setCanvasClearColor(a){canvasClearColor=a.copy()}function setCanvasMaxSize(a){canvasMaxSize=a.copy()}function setCanvasMinAspect(a){canvasMinAspect=a}function setCanvasMaxAspect(a){canvasMaxAspect=a}function setCanvasFixedSize(a){canvasFixedSize=a.copy()}function setCanvasPixelated(a){canvasPixelated=a;mainCanvas&&(mainCanvas.style.imageRendering=a?"pixelated":"");glCanvas&&(glCanvas.style.imageRendering=a?"pixelated":"")}function setTilesPixelated(a){tilesPixelated=a}function setCanvasPixelRatio(a){canvasPixelRatio=a}function getCanvasPixelRatio(){return canvasPixelRatio??(devicePixelRatio||1)}function setFontDefault(a){fontDefault=a}function setShowSplashScreen(a){showSplashScreen=a}function setLoadingScreen(a){loadingScreen=a}function setHeadlessMode(a){headlessMode=a}function setEngineManualStep(a=!0){const b=engineManualStep&&!a;a&&!engineManualStep&&(frameTimeBufferMS=-500/frameRate);engineManualStep=a;b&&engineUpdateInternal&&(frameTimeLastMS=performance.now(),engineScheduleFrame())}function setEngineVariableStep(a=!0){engineVariableStep&&!a&&(timeFixedStart=frame?time+1/frameRate:time,frameFixedStart=frame,timeDelta=1/frameRate,frameTimeBufferMS=engineManualStep?-500/frameRate:0);engineVariableStep=a}function setDrawScreenSpace(a){drawScreenSpace=a}function setGLEnable(a){a&&!glCanBeEnabled?console.warn("Can not enable WebGL if it was disabled on start."):(glEnable=a,glCanvas&&(glCanvas.style.display=a?"":"none"))}function setGLCircleSides(a){glCircleSides=a}function setTileDefaultSize(a){tileDefaultSize=a.copy()}function setTileDefaultPadding(a){tileDefaultPadding=a}function setTileDefaultBleed(a){tileDefaultBleed=a}function setEnablePhysicsSolver(a){enablePhysicsSolver=a}function setObjectDefaultMass(a){objectDefaultMass=a}function setObjectDefaultDamping(a){objectDefaultDamping=a}function setObjectDefaultAngleDamping(a){objectDefaultAngleDamping=a}function setObjectDefaultRestitution(a){objectDefaultRestitution=a}function setObjectDefaultFriction(a){objectDefaultFriction=a}function setObjectMaxSpeed(a){objectMaxSpeed=a}function setGravity(a){gravity=a.copy()}function setParticleEmitRateScale(a){particleEmitRateScale=a}function setGamepadsEnable(a){gamepadsEnable=a}function setGamepadDirectionEmulateStick(a){gamepadDirectionEmulateStick=a}function setGamepadAxisFilterEnable(a){gamepadAxisFilterEnable=a}function setInputWASDEmulateDirection(a){inputWASDEmulateDirection=a}function setTouchInputEnable(a){touchInputEnable=a}function setTouchGamepadEnable(a){touchGamepadEnable=a}function setTouchPinchWheel(a){touchPinchWheel=a}function setTouchGamepadPassthrough(a){touchGamepadPassthrough=a}function setTouchGamepadCenterButtonSize(a){touchGamepadCenterButtonSize=a}function setTouchGamepadButtonCount(a){touchGamepadButtonCount=a;0e.x?c.x+d.x/2>b.x-a.x/2+.001:.5b.y-a.y/2+.001}function engineObjectRayEntry(a,b,c){const d=b.x-a.x;b=b.y-a.y;const e=d?min((c.x-a.x)/d,(c.x+1-a.x)/d):-Infinity;c=b?min((c.y-a.y)/b,(c.y+1-a.y)/b):-Infinity;const f=clamp(max(e,c));return{pos:vec2(a.x+d*f,a.y+b*f),side:e>=c}}function engineObjectBulletSweep(a,b,c){const d=c.subtract(b);var e=d.length();if(e){e=b.subtract(d.scale(1e-6/e));var f=floor(e.x),g=floor(e.y),h;e=r=>{if(r.x===f&&r.y===g||a.destroyed)return!1;for(const t of tileCollisionLayers){if(!t.isSolid)continue;var q=r.x-t.pos.x,p=r.y-t.pos.y;if(0>q||0>p||q>=t.size.x||p>=t.size.y)continue;const u=t.collisionData[p*t.size.x+q];if(u&&!tileCollisionOneWayPass(t,q,p,b.x,b.y)){p=vec2(r.x,r.y);q=engineObjectRayEntry(b,c,p);a.pos=q.pos;if(a.collideWithTile(u,p,!0))return r=q.side?vec2(-sign(d.x),0):vec2(0,-sign(d.y)),h={pos:q.pos,normal:r,layer:t},!0;if(a.destroyed)break}}return!1};var k=[];for(var l of tileCollisionLayers)if(l.isSolid){tileCollisionAssertWhole(l);var m=0,n=1;for(const[r,q,p,t]of[[b.x,d.x,l.pos.x-1,l.pos.x+l.size.x+1],[b.y,d.y,l.pos.y-1,l.pos.y+l.size.y+1]]){if(!q){if(rt)m=2;continue}const u=(p-r)/q,v=(t-r)/q;m=max(m,min(u,v));n=min(n,max(u,v))}mr[0]-q[0]);for(l=0;l=m?b:1<=m?c:b.add(d.scale(m)),0>=n?b:1<=n?c:b.add(d.scale(n)),e)}return h}}function engineObjectStartPos(a){return engineObjectsOneWayStart?.get(a)||a.pos}const engineObjectChildPlacedAt=new WeakMap;let engineObjectChildWarned=!1;function engineObjectChildPlaced(a){const b=engineObjectChildPlacedAt.get(a);b?(b[0]=a.pos.x,b[1]=a.pos.y,b[2]=a.angle):engineObjectChildPlacedAt.set(a,[a.pos.x,a.pos.y,a.angle])}function engineObjectChildCheck(a){var b=engineObjectChildPlacedAt.get(a);if(b&&!engineObjectChildWarned){var c=a.pos.x!==b[0]||a.pos.y!==b[1];b=a.angle!==b[2];if(c||b)engineObjectChildWarned=!0,console.warn(`a child object's ${c?"pos":"angle"} was set, but its parent places it each frame: `+`set its ${c?"localPos":"localAngle"} instead, which is relative to the parent`,a)}}class EngineObject{constructor(a=vec2(),b=vec2(1),c,d=0,e=WHITE,f=0){this.pos=a.copy();this.size=b.copy();this.drawSize=void 0;this.tileInfo=c;this.angle=d;this.color=e.copy();this.shader=this.additiveColor=void 0;this.castShadow=!0;this.castBackgroundShadow=!1;this.emissive=0;this.destroyed=this.mirror=!1;this.updatePass=0;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.restitution=objectDefaultRestitution;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=f;this.velocity=vec2();this.angleVelocity=0;this.spawnTime=time;this.children=[];this.clampSpeed=!0;this.isBullet=!1;this.localPos=this.parent=this.oneWay=this.groundObject=void 0;this.localAngle=0;this.persistent=this.collideRaycast=this.isSolid=this.collideSolidObjects=this.collideLevel=!1;engineObjects.push(this)}updateTransforms(a=!0){var b=this.parent;if(b){debug&&engineObjectChildCheck(this);const d=b.getMirrorSign();var c=this.localPos;const e=b.pos,f=c.x*d;c=c.y;if(b=b.angle){const g=cos(-b),h=sin(-b);this.pos.set(f*g-c*h+e.x,f*h+c*g+e.y)}else this.pos.set(f+e.x,c+e.y);this.angle=d*this.localAngle+b;debug&&engineObjectChildPlaced(this)}if(a)for(const d of this.children)d.updateTransforms()}updatePhysics(){if(!this.destroyed){var a=enablePhysicsSolver&&this.mass,b=a&&(this.collideSolidObjects||this.collideLevel)?this.pos.copy():void 0;this.velocity.x*=this.damping;this.velocity.y*=this.damping;this.mass&&(this.velocity.x+=gravity.x*this.gravityScale,this.velocity.y+=gravity.y*this.gravityScale);this.clampSpeed&&enablePhysicsSolver&&(this.collideSolidObjects&&this.size.x&&this.size.y||this.collideLevel&&this.mass&&!this.isBullet)&&(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed));this.pos.x+=this.velocity.x;this.pos.y+=this.velocity.y;this.angle+=this.angleVelocity*=this.angleDamping;if(a){a=0>this.gravityScale?-gravity.y:gravity.y;var c=0>this.velocity.y&&0>a||0h*e.x&&(this.velocity.x=g.velocity.x-h*f)}else h=this.velocity.y-g.velocity.y,0>h*e.y&&(this.velocity.y=g.velocity.y-h*f),0>e.y*a&&(this.groundObject=g);engineObjectsCollidePairAdd(this,g);debugPhysics&&debugOverlap(this.pos,this.size,g.pos,g.size,"#f00",void 0,!1);continue}if(e){e=b.subtract(g.pos);f=e.length();e=.001>f?vec2(0,.001):e.scale(.001/f);this.velocity=this.velocity.add(e);g.mass&&(g.velocity=g.velocity.subtract(e));engineObjectsCollidePairAdd(this,g);debugPhysics&&debugOverlap(this.pos,this.size,g.pos,g.size,"#f00",void 0,!1);continue}f=this.size.add(g.size);h=2*(0f.y-abs(a);const l=2*abs(b.y-g.pos.y)a;++a){var f=engineObjectBulletSweep(this,d,e);if(!f){this.pos=e;break}const{normal:h,layer:k}=f;var g=max(this.restitution,k.restitution);d=f.pos.add(h.scale(.002));const l=this.velocity.dot(h);0>l&&(this.velocity=this.velocity.subtract(h.scale(l*(1+g))));0>h.y*b&&c&&(this.groundObject=k);this.pos=d;e=e.subtract(f.pos);f=e.dot(h);g=d.add(0>f?e.subtract(h.scale(f*(1+g))):e);if(this.destroyed||1e-12>g.distanceSquared(d))break;e=g}debugPhysics&&debugPoint(this.pos,"#f00",void 0,void 0,!1)}updatePhysicsTiles(a,b,c){tileCollisionHitObject=this;const d=tileCollisionTest(this.pos,this.size,this);tileCollisionHitObject=void 0;if(d&&!tileCollisionTest(a,this.size,this)){var e=tileCollisionTest(vec2(this.pos.x,a.y),this.size,this),f=tileCollisionTest(vec2(a.x,this.pos.y),this.size,this);const h=max(this.restitution,d.restitution);if(e){b=0abs(b-this.pos.y)&&!tileCollisionTest(vec2(this.pos.x,b),this.size,this)){this.pos.y=b;debugPhysics&&debugRect(this.pos,this.size,"#ff0",0,0,!1,!1);return}var g=d.pos.x;const k=this.size.x/2+1e-4;b=this.pos.xb||(this.children.splice(b,1),a.parent=a.localPos=void 0)}isOverlappingObject(a){return this.isOverlapping(a.pos,a.size)}isOverlapping(a,b=vec2()){return isOverlapping(this.pos,this.size,a,b)}setCollision(a=!0,b=!0,c=!0,d=!0){this.collideSolidObjects=a;this.isSolid=b;this.collideLevel=c;this.collideRaycast=d}toString(){let a="type = "+this.constructor.name;if(this.pos.x||this.pos.y)a+="\npos = "+this.pos;if(this.velocity.x||this.velocity.y)a+="\nvelocity = "+this.velocity;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.angle&&(a+="\nangle = "+this.angle.toFixed(3));return a+="\ncolor = "+this.color}renderDebugInfo(){if(debug){var a=this.collideLevel||this.collideSolidObjects||this.isSolid;if(a||this.parent){var b=vec2(max(this.size.x,.2),max(this.size.y,.2)),c=rgb(this.collideLevel?1:0,this.collideSolidObjects?1:0,this.isSolid?1:0,.5);debugRect(this.pos,b,c,0,a?0:this.angle,a,!1);this.parent&&debugRect(this.pos,b.scale(.8),rgb(1,1,1,.5),0,this.angle,!1,!1);this.parent&&debugLine(this.pos,this.parent.pos,rgb(1,1,1,.5),.5,0,!1)}}}}let mainCanvas,mainContext,drawContext,workCanvas,workContext,workReadCanvas,workReadContext,backgroundCanvas,mainCanvasSize=vec2(),textureInfos=[],drawCount=0,primitiveCount=0;function isWhite(a){return 1<=a.r&&1<=a.g&&1<=a.b}function isBlack(a){return 0>=a.r&&0>=a.g&&0>=a.b&&0>=a.a}function tile(a=0,b=tileDefaultSize,c=0,d=tileDefaultPadding,e=tileDefaultBleed){"number"===typeof b&&(b=new Vector2(b,b));c="number"===typeof c?textureInfos[c]:c;if(!c?.size.x)return new TileInfo(new Vector2,headlessMode?b.copy():new Vector2,c,d,e);const f=b.x+2*d,g=b.y+2*d;let h;if("number"===typeof a){const k=c.size.x/f|0;h=a%k;a=a/k|0}else h=a.x,a=a.y;a=new Vector2(h*f+d,a*g+d);return new TileInfo(a,b,c,d,e)}class TileInfo{constructor(a=vec2(),b=tileDefaultSize,c=textureInfos[0],d=tileDefaultPadding,e=tileDefaultBleed,f=0){this.pos=a.copy();this.size=b.copy();this.padding=d;this.textureInfo=c;this.tiles=void 0;this.bleed=e;this.columns=f}offset(a){return new TileInfo(this.pos.add(a),this.size,this.textureInfo,this.padding,this.bleed,this.columns)}frame(a){return this.offset(new Vector2((this.columns?a%this.columns:a)*(this.size.x+2*this.padding),(this.columns?a/this.columns|0:0)*(this.size.y+2*this.padding)))}setColumns(a=0){this.columns=a;return this}index(a){return tile(a,this.size,this.textureInfo,this.padding,this.bleed).setColumns(this.columns)}setFullImage(a=this.textureInfo){this.textureInfo=a;this.pos=new Vector2;this.size=a.size.copy();this.bleed=this.padding=this.columns=0;return this}}class TextureInfo{constructor(a,b=!0,c=!1,d){this.size=(this.image=a)?vec2(a.width,a.height):vec2();this.sizeInverse=a?vec2(1/a.width,1/a.height):vec2();this.glTexture=void 0;this.wrap=c;this.pixelated=d;b&&this.createWebGLTexture()}createWebGLTexture(){const a=this.image;a?.width&&(this.size=vec2(a.width,a.height),this.sizeInverse=vec2(1/a.width,1/a.height));glRegisterTextureInfo(this)}destroyWebGLTexture(){glUnregisterTextureInfo(this)}hasWebGL(){return!!this.glTexture}setWrap(a=!0){this.wrap=a;glSetTextureWrap(this.glTexture,a)}setPixelated(a){this.pixelated=a;this.glTexture&&(this.destroyWebGLTexture(),this.createWebGLTexture())}}class SpriteAnimation{constructor(a,b,c=.1){this.firstTile=a;this.frameCount=b;this.frameTime=c;this.speed=1;this.mode="loop";this.startTime=time;this.onEnd=this.heldFrame=void 0}loop(){return this.restart("loop")}play(a){this.restart("once");this.onEnd=a;return this}pingPong(){return this.restart("pingPong")}stop(){this.heldFrame=this.frame;return this}restart(a=this.mode){this.mode=a;this.startTime=time;this.onEnd=this.heldFrame=void 0;return this}get elapsedFrames(){return(time-this.startTime)*this.speed/this.frameTime}get frame(){this.isDone;if(void 0!==this.heldFrame)return this.heldFrame;const a=this.frameCount;var b=floor(this.elapsedFrames);if("once"==this.mode)return clamp(0>this.speed?a-1+ceil(this.elapsedFrames):b,0,a-1);if("loop"==this.mode)return mod(b,a);const c=max(2*a-2,1);b=mod(b,c);return b=this.frameCount;if(a&&this.onEnd){const b=this.onEnd;this.onEnd=void 0;b()}return a}}class SpriteAnimator{constructor(a){const b=Object.keys(a);this.clips=a;this.name=b[0]}set(a,b){if(a==this.name&&!this.clip.isDone)return this;this.name=a;this.clip.restart();this.clip.onEnd=b;return this}get clip(){return this.clips[this.name]}get settledClip(){for(let a=4,b;a--&&b!==this.clip;)(b=this.clip).isDone;return this.clip}get tileInfo(){return this.settledClip.tileInfo}get frame(){return this.settledClip.frame}get isDone(){return this.settledClip.isDone}}class Shader{constructor(a){this.fragmentCode=String(a);this.program3D=this.program=void 0;glShaderObjects.push(this)}dispose(){glShaderDispose(this)}}function drawTile(a,b=vec2(1),c,d=WHITE,e=0,f,g,h=glEnable,k=drawScreenSpace,l){if(!headlessMode||l){var m=c?.textureInfo;if(!m||c.size.x&&c.size.y&&m.size.x){var n=c?.bleed??0;if(h&&glEnable){if(k){if(glSkipScreenSpace)return;[a,b,e]=screenToWorldTransform(a,b,e)}if(m){var r=m.sizeInverse;h=c.pos.x*r.x;k=c.pos.y*r.y;l=c.size.x*r.x;const q=c.size.y*r.y;glSetTexture(m.glTexture);if(n){const p=r.x*n;r=r.y*n;glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+p,k+r,h-p+l,k-r+q,d.rgbaInt(),g&&g.rgbaInt())}else glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h,k,h+l,k+q,d.rgbaInt(),g&&g.rgbaInt())}else f=g?d.add(g):d,glDrawUntextured(a.x,a.y,b.x,b.y,e,f.rgbaInt())}else++drawCount,++primitiveCount,drawCanvas2D(a,b,e,f,q=>{if(m)q.scale(1,-1),void 0===m.pixelated||(q.imageSmoothingEnabled=!m.pixelated),drawImageColor(q,m.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1,d,g,n);else{const p=g?d.add(g):d;q.fillStyle=p.toString();q.fillRect(-.5,-.5,1,1)}},k,l)}}}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,!1,void 0,e,f,g)}function drawRectGradient(a,b=vec2(1),c=WHITE,d=CLEAR_WHITE,e=0,f=glEnable,g=drawScreenSpace,h){if(!headlessMode||h)if(f&&glEnable){if(g){if(glSkipScreenSpace)return;[a,b,e]=screenToWorldTransform(a,b,e)}f=[];g=[];h=b.x/2;b=b.y/2;const k=c.rgbaInt(),l=d.rgbaInt(),m=cos(-e);e=sin(-e);for(let n=4;n--;){const r=n&1?h:-h,q=n&2?b:-b,p=n&2?k:l;f.push(vec2(a.x+(r*m-q*e),a.y+(r*e+q*m)));g.push(p)}glDrawColoredPoints(f,g)}else++drawCount,++primitiveCount,drawCanvas2D(a,b,e,!1,k=>{const l=k.createLinearGradient(0,.5,0,-.5);l.addColorStop(0,c.toString());l.addColorStop(1,d.toString());k.fillStyle=l;k.fillRect(-.5,-.5,1,1)},g,h)}function drawTextureWrapped(a,b,c,d=0,e=WHITE,f=0,g,h=glEnable,k=drawScreenSpace,l){if(!headlessMode||l)if(d="number"===typeof d?textureInfos[d]:d,h&&glEnable){if(k){if(glSkipScreenSpace)return;[a,b,f]=screenToWorldTransform(a,b,f)}glSetTexture(d.glTexture);glDraw(a.x,a.y,b.x,b.y,f,0,0,c.x,c.y,e.rgbaInt(),g&&g.rgbaInt())}else{++drawCount;++primitiveCount;k||(a=worldToScreen(a),b=b.scale(cameraScale),f-=cameraAngle);var m=!canvasColorTiles||isWhite(e)&&(!g||isBlack(g));k=!m&&g&&!isBlack(g);h=d.image;if(!m){m=e.r+","+e.g+","+e.b+","+e.a+(g?","+g.r+","+g.g+","+g.b+","+g.a:"");var n=drawTextureWrappedBakes.get(h);if(n?.key!==m||"getContext"in h)n=n?.context,n=n?.canvas.width===(h.width|0)&&n?.canvas.height===(h.height|0)?n:createCanvasContext(h.width|0,h.height|0,!0),bakeTintedImage(h,e,g,n),drawTextureWrappedBakes.set(h,n={key:m,context:n});h=n.context.canvas}l=l||drawContext;l.save();void 0===d.pixelated||(l.imageSmoothingEnabled=!d.pixelated);l.translate(a.x+.5,a.y+.5);l.rotate(f);l.globalAlpha=k?1:e.a;a=l.createPattern(h,"repeat");c=(new DOMMatrix).translate(-b.x/2,-b.y/2).scale(b.x/(c.x*h.width),b.y/(c.y*h.height));a.setTransform(c);l.fillStyle=a;l.fillRect(-b.x/2,-b.y/2,b.x,b.y);l.globalAlpha=1;l.restore()}}function drawLineList(a,b=.1,c=WHITE,d=!1,e=vec2(),f=0,g=glEnable,h=drawScreenSpace,k){if(!headlessMode||k)if(g&&glEnable){k=g=1;if(h){if(glSkipScreenSpace)return;[e,h,f]=screenToWorldTransform(e,vec2(1),f);g=h.x;k=h.y}glDrawOutlineTransform(a,c.rgbaInt(),b,e.x,e.y,g,k,f,d)}else++drawCount,++primitiveCount,drawCanvas2D(e,vec2(1),f,!1,l=>{if(b){l.strokeStyle=c.toString();l.lineWidth=abs(b);l.beginPath();for(let m=0;m{l.fillStyle=b.toString();l.beginPath();for(const m of a)l.lineTo(m.x,m.y);l.closePath();l.fill();0{l.fillStyle=c.toString();l.beginPath();l.ellipse(0,0,abs(b.x)/2,abs(b.y)/2,0,0,9);l.fill();0{const t=sin(p)*k;p=cos(p)*l;return vec2(a.x+t*m-p*n,a.y+t*n+p*m)};const r=[e(h%f/f*PI*2)],q=[g];for(let p=f;0{const l=k.createRadialGradient(0,0,0,0,0,.5);l.addColorStop(0,c.toString());l.addColorStop(1,d.toString());k.fillStyle=l;k.beginPath();k.ellipse(0,0,.5,.5,0,0,9);k.fill()},g,h)}function drawCircleGradient(a,b=1,c=WHITE,d=CLEAR_WHITE,e=glEnable,f=drawScreenSpace,g){drawEllipseGradient(a,vec2(b),c,d,0,e,f,g)}function drawCanvas2D(a,b,c=0,d=!1,e,f=drawScreenSpace,g=drawContext){if(!headlessMode||g)f||(a=worldToScreen(a),b=b.scale(cameraScale),c-=cameraAngle),g.save(),g.translate(a.x+.5,a.y+.5),g.rotate(c),g.scale(d?-b.x:b.x,-b.y),e(g),g.restore()}function drawText(a,b,c=1,d=WHITE,e=0,f=BLACK,g="center",h=fontDefault,k="",l,m=0,n=drawContext){b=worldToScreen(b);c*=cameraScale;e*=cameraScale;void 0!==l&&(l*=cameraScale);m-=cameraAngle;drawTextScreen(a,b,c,d,e,f,g,h,k,l,m,n)}const drawFontsChecked=new Set;function drawFontCheck(a,b,c,d){d=d+"|"+c;drawFontsChecked.has(d)||(drawFontsChecked.add(d),a.font="1px littlejs-font-check",a.font=b,"1px littlejs-font-check"===a.font&&console.warn(`the canvas does not take the font ${c}, so text draws as 10px sans-serif; `+"a family name with spaces or digits goes in quotes, as \"'Press Start 2P'\""))}const textLines=a=>(a+="").includes("\r")?a.split(/\r?\n/):a.split("\n");function textLineCount(a){let b=1;for(let c=-1;0<=(c=a.indexOf("\n",c+1));)++b;return b}const textIntl=globalThis.Intl,textSegmenter=textIntl?.Segmenter&&new textIntl.Segmenter,textJoins=/[\p{M}\u200c\u200d\u0600-\u0605\u06dd\u070f\u0890\u0891\u08e2\u0d4e\u0e33\u0eb3\u1100-\u11ff\ua960-\ua97c\ud7b0-\ud7fb\uff9e\uff9f\u{10000}-\u{10ffff}]/u;function textCharacters(a){return textJoins.test(a)?textSegmenter?Array.from(textSegmenter.segment(a),b=>b.segment.codePointAt(0)):Array.from(a,b=>b.codePointAt(0)).filter(b=>8205!==b&&65039!==b&&!(768<=b&&880>b)):a}const textGraphemes=a=>textJoins.test(a)?textSegmenter?Array.from(textSegmenter.segment(a),b=>b.segment):[...a]:a.split(""),textCharacterCode=(a,b)=>textBaseLetter("string"==typeof a?a.charCodeAt(b):a[b]),textBaseLetters=new Map;function textBaseLetter(a){if(192>a||592<=a)return a;let b=textBaseLetters.get(a);void 0===b&&textBaseLetters.set(a,b=String.fromCharCode(a).normalize("NFD").charCodeAt(0));return b}function drawTextScreen(a,b,c,d=WHITE,e=0,f=BLACK,g="center",h=fontDefault,k="",l,m=0,n=drawContext){if(!headlessMode||n){a=textLines(a);n.save();n.fillStyle=d.toString();n.strokeStyle=f.toString();n.lineWidth=e;n.textAlign=g;d=k+" "+c+"px "+h;debug&&drawFontCheck(n,d,h,k);n.font=d;n.textBaseline="middle";n.translate(b.x+.5,b.y+.5);n.rotate(m);var r=-(a.length-1)*c/2;a.forEach(q=>{e&&n.strokeText(q,0,r,l);n.fillText(q,0,r,l);r+=c});n.restore()}}async function loadTexture(a,b){textureInfos[a]?.destroyWebGLTexture();const c=new Image;b&&await engineAddLoad(new Promise(d=>{c.onload=d;c.onerror=()=>{console.warn("failed to load image: "+b);d()};c.crossOrigin="anonymous";c.src=b}));return textureInfos[a]=new TextureInfo(c)}function screenToWorld(a){let b=(a.x-mainCanvasSize.x/2+.5)/cameraScale;a=(a.y-mainCanvasSize.y/2+.5)/-cameraScale;if(cameraAngle){const c=cos(-cameraAngle),d=sin(-cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b+cameraPos.x,a+cameraPos.y)}function worldToScreen(a){let b=a.x-cameraPos.x;a=a.y-cameraPos.y;if(cameraAngle){const c=cos(cameraAngle),d=sin(cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b*cameraScale+mainCanvasSize.x/2-.5,a*-cameraScale+mainCanvasSize.y/2-.5)}function screenToWorldDelta(a){let b=a.x/cameraScale;a=a.y/-cameraScale;if(cameraAngle){const c=cos(-cameraAngle),d=sin(-cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b,a)}function worldToScreenDelta(a){let b=a.x;a=a.y;if(cameraAngle){const c=cos(cameraAngle),d=sin(cameraAngle),e=b*d+a*c;b=b*c-a*d;a=e}return new Vector2(b*cameraScale,a*-cameraScale)}function screenToWorldTransform(a,b,c=0){return[screenToWorld(a),b.scale(1/cameraScale),c+cameraAngle]}function getCameraSize(){return mainCanvasSize.scale(1/cameraScale)}function cameraFit(a,b,c,d){function e(n){if(void 0===n||isNumber(n))n=vec2(n);return isVector2(n)?{top:n.y,right:n.x,bottom:n.y,left:n.x}:{top:n.top||0,right:n.right||0,bottom:n.bottom||0,left:n.left||0}}var f=e(c);d=e(d);var g=b.x+f.left+f.right;const h=b.y+f.top+f.bottom,k=mainCanvasSize.x-d.left-d.right,l=mainCanvasSize.y-d.top-d.bottom;if(!(0-d&&c-b-e&&a-b{}):a.requestFullscreen&&a.requestFullscreen()?.catch?.(()=>{})}function setCursor(a="auto"){mainCanvas.parentElement.style.cursor=a}let engineImageFont;class ImageFont{constructor(a){this.tileInfo=a}drawText(a,b,c=1,d,e,f,g){"number"===typeof c?(c*=cameraScale,c=new Vector2(c,c)):c=c.scale(cameraScale);const h=glSkipScreenSpace;glSkipScreenSpace=!1;this.drawTextScreen(a,worldToScreen(b),c,d,e,f,g);glSkipScreenSpace=h}drawTextScreen(a,b,c,d=!0,e=WHITE,f=glEnable,g){const h="number"===typeof c?new Vector2(c,c):c,k=new Vector2,l=this.tileInfo.frame(0);a=textLines(a);const m=d?(a.length-1)*h.y/2:0;a.forEach((n,r)=>{n=textCharacters(n);const q=d?(n.length-1)*h.x/2:0;for(let p=n.length;p--;){const t=textCharacterCode(n,p);this.getGlyphPos(32>t||127=d;++d)c.addColorStop(d/16,"rgba(255,255,255,"+engineGlowAlpha(d/16,a).toFixed(4)+")");b.fillStyle=c;b.fillRect(0,0,64,64);engineGlowTextures.set(a,b=new TextureInfo(b.canvas,!0,!1,!1));return b}async function imageFontInit(){const a=new Image;await new Promise(e=>{a.onerror=a.onload=e;a.crossOrigin="anonymous";a.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAAAeAQMAAABnrVXaAAAABlBMVEUAAAD///+l2Z/dAAAAAXRSTlMAQObYZgAAAjpJREFUOMu9kzFu2zAUhn+CAROgqrk+B2l0BWYxMjlXeYaAtFtbdA1sGgHqRQfI0CNkSG5AwYB0BQ8d5Bsomwah6CPVeGg6tEPzAxLwyI+P78cP4u9lNO9OoMKnLMOobG5020/yaj/MrRcCGh1gBbyiLTPJEYaIiom5KM9Jq7KgynMGtb6L4GL4MF2H4LQKCXTvDVw2I4MsgZT7QLExdiutH+D08VOP3INXRrWX1/mmpbkNgAPYRVANb4xpcegYvhiNbIXauQICEjBuYLfMakaakWQeXxiZ0VDtuJCKs3ztMV59QtsHJNcRxDzfdL21ty3PrfIcXTN+E+GFAv6T5nbT9jd50/WFxb5ksdAv49qS6ouymG66ji08UMT6moykYLAo+V0j23GN4m829ZySAD5K7QsBfQTvOG8eE+gTeGYRAmnNAubN3hf5Zv9tJWDHp/VTuaSm7SN4fyINQqaNO3RMVxvpSPXnOChnRNvFcGY0gnwiPswYwTKVPE0zVtX3mTEIOoFzaqLrGuJaV+Uqumb71fVk/VoOH3cdLNQP/FHi8hV0CQNoqBZsUPlLPMsdCJro9QAaQQ0woDy9BJm0eTxCFnO9srcYlhNVlfR2EyTrph1uUtbUtAJifwRgrKuYdXVHeb0YI3QpawohQHkloI3J5FuVwI5ORxC9k2Tuz9Ir1IjgeIPGMHYkAZe2RuYkmWFmt3gGbTPOmBUWVTmRmHtGrfpzG/yuQNOKa6gBB/WA9khitPgl6/GP+gl2Af6tCbvaygAAAABJRU5ErkJggg=="});var b=vec2();const c=vec2(8),d=new TextureInfo(a);b=new TileInfo(b,c,d,1,0);engineImageFont=new ImageFont(b)}let mousePos=vec2(),mousePosScreen=vec2(),mouseDelta=vec2(),mouseDeltaScreen=vec2(),mouseWheel=0,touchPinch=0,mouseInWindow=!0,isUsingGamepad=!1,lastInputDevice="mouse",inputMouseMoveThreshold=6,inputPreventDefault=!0,gamepadPrimary=0;const isTouchDevice=!headlessMode&&"undefined"!=typeof window&&void 0!==window.ontouchstart;function setInputPreventDefault(a=!0){inputPreventDefault=a}function setInputMouseMoveThreshold(a){inputMouseMoveThreshold=a}function usingMouseInput(){return"mouse"===lastInputDevice}function usingKeyboardInput(){return"keyboard"===lastInputDevice}function usingGamepadInput(){return"gamepad"===lastInputDevice}function inputClearKey(a,b=0,c=!0,d=!0,e=!0){inputData[b]&&(inputData[b][a]&=~((c?1:0)|(d?2:0)|(e?4:0)))}const inputWASDToArrow={KeyW:"ArrowUp",KeyS:"ArrowDown",KeyA:"ArrowLeft",KeyD:"ArrowRight"},inputArrowToWASD={ArrowUp:"KeyW",ArrowDown:"KeyS",ArrowLeft:"KeyA",ArrowRight:"KeyD"},inputKeysHeld=new Set;let inputPinch,inputWasTouching=0,inputTouchIdentifier,inputLastTouchTime=-1e9;function inputIsTouchMouseEvent(a){return a.sourceCapabilities?.firesTouchEvents||500>performance.now()-inputLastTouchTime}function inputRealGamepadUsed(){for(const a of inputGetGamepads())if(a){for(const b of a.buttons)if(b.pressed)return!0;if("standard"===a.mapping)for(let b=0;4>b&&b{})}function gamepadVibrateStop(a=gamepadPrimary){vibrateEnable&&!headlessMode&&inputGetGamepads()[a]?.vibrationActuator?.reset?.()}function inputGetGamepads(){return navigator?.getGamepads?.()||[]}function vibrate(a=100){vibrateEnable&&!headlessMode&&navigator?.vibrate?.(a)}function vibrateStop(){vibrate(0)}function pointerLockRequest(){try{mainCanvas.requestPointerLock?.()?.catch?.(()=>{})}catch{}}function pointerLockExit(){inputLockExit();document.exitPointerLock?.()}function pointerLockIsActive(){return document.pointerLockElement===mainCanvas}const inputData=[[]],gamepadStickData=[],gamepadDpadData=[],gamepadHadInput=[],gamepadButtonsLast=[],gamepadAxisCentered=[],gamepadAxisCenteredFrames=15,touchGamepadTimer=new Timer(void 0,!0),touchGamepadButtons=[],touchGamepadSticks=[],touchGamepadButtonsPressed=[],touchGamepadStickAnchors=[],touchGamepadStickPointerId=[],touchGamepadPointerRole=new Map;let touchGamepadOverlay,touchGamepadStage,touchGamepadSvg,touchGamepadSvgEls,touchGamepadSideZones=[],touchGamepadZoneC,touchGamepadNeedRelayout=!0,touchGamepadLastLayout;function inputInit(){function a(g){return!!g.target?.closest?.("input,textarea,select,button,a,label,[contenteditable]")}function b(g){const h=g?.tagName;return"INPUT"===h?!"button checkbox color file image radio range reset submit".split(" ").includes(g.type):!!g?.isContentEditable||"TEXTAREA"===h||"SELECT"===h}function c(g){inputKeysHeld.delete(g.code);const h=inputWASDToArrow[g.code]||g.code;for(const k of h===g.code?[g.code]:[g.code,h])inputKeysHeld.has(k)||inputWASDEmulateDirection&&inputKeysHeld.has(inputArrowToWASD[k])||inputData[0][k]&1&&(inputData[0][k]=inputData[0][k]&2|4);if("Meta"===g.key)for(const k of[...inputKeysHeld])c({code:k})}function d(){function g(h){soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioResume();if(touchInputEnable){inputLastTouchTime=performance.now();if(!touchGamepadEnable||touchGamepadPassthrough){const m=n=>touchGamepadSideZones.includes(n.target)||n.target===touchGamepadZoneC;var k=[];for(var l of h.touches)m(l)||k.push(l);if(l=k.length){const n=!inputWasTouching&&"touchstart"==h.type&&[...h.changedTouches].find(t=>!m(t)),r=n||k[0];let q=vec2(r.clientX,r.clientY);const p=1g(h),{passive:!1});document.addEventListener("touchmove",h=>g(h),{passive:!1});document.addEventListener("touchend",h=>g(h),{passive:!1});document.addEventListener("touchcancel",h=>g(h),{passive:!1})}function e(g,h){const k=mainCanvas.getBoundingClientRect();return g>=k.left&&g<=k.right&&h>=k.top&&h<=k.bottom}function f(g){const h=mainCanvas.getBoundingClientRect(),k=percent(g.x,h.left,h.right);g=percent(g.y,h.top,h.bottom);return vec2(k*mainCanvasSize.x,g*mainCanvasSize.y)}headlessMode||(document.addEventListener("keydown",function(g){soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioResume();var h=b(g.target)||b(document.activeElement);if(!(g.repeat||h||inputKeysHeld.has(g.code)&&!g.metaKey)){inputKeysHeld.add(g.code);inputWASDEmulateDirection&&inputKeysHeld.has(inputArrowToWASD[g.code])&&inputData[0][g.code]&1||(inputData[0][g.code]=3|inputData[0][g.code]&4);var k=g.code;k=inputWASDEmulateDirection&&inputWASDToArrow[k]||k;k===g.code||inputData[0][k]&1||(inputData[0][k]=3|inputData[0][k]&4)}inputPreventDefault&&g.cancelable&&document.hasFocus()&&!(g.ctrlKey||g.metaKey||g.altKey||h)&&(h="string"===typeof g.key&&1===g.key.length,("ArrowUp ArrowDown ArrowLeft ArrowRight Space Tab Backspace".split(" ").includes(g.code)||h)&&g.preventDefault())}),document.addEventListener("keyup",c),document.addEventListener("mousedown",function(g){if(!touchInputEnable||!inputIsTouchMouseEvent(g))if(soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioResume(),pointerLockIsActive()||e(g.x,g.y)){inputData[0][g.button]=3|inputData[0][g.button]&4;var h=mousePosScreen;mousePosScreen=f(vec2(g.x,g.y));mouseDeltaScreen=mouseDeltaScreen.add(mousePosScreen.subtract(h));inputPreventDefault&&g.cancelable&&document.hasFocus()&&!a(g)&&(h=document.activeElement,b(h)&&!h.contains(g.target)&&h.blur(),g.preventDefault())}}),document.addEventListener("mouseup",function(g){touchInputEnable&&inputIsTouchMouseEvent(g)||(inputData[0][g.button]&1&&(inputData[0][g.button]=inputData[0][g.button]&2|4),inputPreventDefault&&g.cancelable&&(3===g.button||4===g.button)&&g.preventDefault())}),document.addEventListener("mousemove",function(g){mouseInWindow=!0;var h=mousePosScreen;mousePosScreen=f(vec2(g.x,g.y));pointerLockIsActive()?(h=mainCanvas.getBoundingClientRect(),g=vec2(g.movementX*mainCanvasSize.x/h.width,g.movementY*mainCanvasSize.y/h.height)):g=mousePosScreen.subtract(h);mouseDeltaScreen=mouseDeltaScreen.add(g)}),document.addEventListener("mouseleave",function(){mouseInWindow=!1}),document.addEventListener("wheel",function(g){g.target?.closest?.("input,textarea,select,[contenteditable]")||(g.ctrlKey||(mouseWheel+=sign(g.deltaY)),inputPreventDefault&&g.cancelable&&document.hasFocus()&&g.preventDefault())},{passive:!1}),document.addEventListener("contextmenu",function(g){const h=g.target;!inputPreventDefault||b(h)||h?.closest?.("a[href]")||g.preventDefault()}),addEventListener("blur",function(){inputClear()}),isTouchDevice&&d())}function inputUpdate(){inputCaptureMouse();headlessMode||(touchInputEnable&&isTouchDevice||document.hasFocus()||inputClear(),mousePos=screenToWorld(mousePosScreen),mouseDelta=screenToWorldDelta(mouseDeltaScreen),touchGamepadInit(),function(){var a=l=>{const m=n=>.3n?-percent(-n,.3,.8):0;return vec2(m(l.x),m(-l.y)).clampLength()};touchGamepadEnable&&isTouchDevice&&touchGamepadTimer.isSet()&&gamepadsEnable&&inputRealGamepadUsed()&&touchGamepadTimer.unset();if(touchGamepadEnable&&isTouchDevice&&touchGamepadTimer.isSet()){gamepadPrimary=0;var b=gamepadStickData[0]??(gamepadStickData[0]=[]),c=gamepadDpadData[0]??(gamepadDpadData[0]=vec2());b.length=0;c.set();for(var d=0;2>d;d++)if(touchGamepadSideStick(d)){var e=touchGamepadStickOut(d);b[e]=vec2();var f=touchGamepadSticks[d]??vec2();if(touchGamepadAnalog)b[e]=a(f);else if(.3c;++c){const l=b[c];if(!l){inputData[c+1]=void 0;gamepadStickData[c]=void 0;gamepadDpadData[c]=void 0;gamepadHadInput[c]=void 0;gamepadAxisCentered[c]=void 0;gamepadButtonsLast[c]=void 0;continue}d=inputData[c+1]??(inputData[c+1]=[]);e=gamepadButtonsLast[c]??(gamepadButtonsLast[c]=[]);g=gamepadStickData[c]??(gamepadStickData[c]=[]);f=gamepadDpadData[c]??(gamepadDpadData[c]=vec2());const m="standard"===l.mapping,n=gamepadAxisCentered[c]??(gamepadAxisCentered[c]=[]);var h=r=>{const q=isFinite(l.axes[r])?l.axes[r]:0;if(m&&4>r||!gamepadAxisFilterEnable)return q;const p=n[r]|0;if(p>gamepadAxisCenteredFrames)return q;n[r]=.3>abs(q)?p+1:0;return 0};for(var k=0;k>1]=a(vec2(h(k),h(k+1)));h=g.some(r=>.25>1;h&&(gamepadHadInput[c]=!0,gamepadHadInput[gamepadPrimary]||(gamepadPrimary=c));"standard"===l.mapping&&f.set((gamepadIsDown(15,c)&&1)-(gamepadIsDown(14,c)&&1),(gamepadIsDown(12,c)&&1)-(gamepadIsDown(13,c)&&1));gamepadDirectionEmulateStick&&(f.x||f.y)?g[0]=f.clampLength():gamepadDirectionEmulateStick&&!g.length&&(g[0]=vec2())}touchGamepadEnable&&isUsingGamepad&&touchGamepadTimer.unset()}}(),function(){const a=mouseIsDown(0)||mouseIsDown(1)||mouseIsDown(2)||mouseDeltaScreen.length()>inputMouseMoveThreshold;let b=!1;for(var c=gamepadStickCount();c--&&!b;)b=.2{const d=document.createElement("div");d.style.cssText="position:absolute;pointer-events:auto;touch-action:none";d.addEventListener("pointerdown",e=>touchGamepadPointerDown(e,d));d.addEventListener("pointermove",e=>touchGamepadPointerMove(e));d.addEventListener("pointerup",e=>touchGamepadPointerUp(e));d.addEventListener("pointercancel",e=>touchGamepadPointerUp(e));b.appendChild(d);return d};touchGamepadSideZones[0]=c();touchGamepadSideZones[1]=c();touchGamepadZoneC=c();addEventListener("resize",()=>touchGamepadNeedRelayout=!0);document.body.appendChild(a);touchGamepadNeedRelayout=!0}}function touchGamepadStageRect(){return touchGamepadStage.getBoundingClientRect()}function touchGamepadSideStick(a){return a?touchGamepadRightStick:touchGamepadLeftStick}function touchGamepadSideButtonCount(a){return a?touchGamepadButtonCount:touchGamepadLeftButtonCount}function touchGamepadSideButtonBase(a){return a?0:4}function touchGamepadStickOut(a){return a&&touchGamepadLeftStick?1:0}function touchGamepadStickButton(a){return touchGamepadStickOut(a)?11:10}function touchGamepadFaceIndex(a){return 3===a?2:2===a?3:a}function touchGamepadSideHasControl(a){return touchGamepadSideStick(a)||0b;b++){const c=touchGamepadSideButtonBase(b);if(!touchGamepadSideStick(b)&&a>=c&&af.style.cssText="position:absolute;pointer-events:auto;touch-action:none;"+g;if(paused){for(var e of touchGamepadSideZones)e.style.display="none";touchGamepadCenterButtonSize?(d(touchGamepadZoneC,"inset:0"),touchGamepadZoneC.style.display=""):touchGamepadZoneC.style.display="none"}else{for(e=0;2>e;e++){const f=touchGamepadSideZones[e],g=e?"right":"left";f.style.display=touchGamepadSideHasControl(e)?"":"none";if(touchGamepadFloating&&touchGamepadSideStick(e)){const h=touchGamepadSideHasControl(e?0:1)?"50%":"100%";d(f,`${g}:0;bottom:0;width:${h};height:60%`)}else d(f,`${g}:0;bottom:0;width:${3*c}px;height:${3*c}px`)}touchGamepadZoneC.style.display=touchGamepadCenterButtonSize?"":"none";c=touchGamepadCenterButtonSize;d(touchGamepadZoneC,`left:50%;top:50%;width:${2*c}px;height:${2*c}px;transform:translate(-50%,-50%)`)}touchGamepadBuildSvg(b,a);touchGamepadNeedRelayout=!1}}function touchGamepadBuildSvg(a,b){const c=touchGamepadSvg;for(;c.firstChild;)c.removeChild(c.firstChild);const d=touchGamepadSvgEls={face:[],thumb:[]},e=touchGamepadSize,f=(k,l,m,n)=>{const r=document.createElementNS(touchGamepadSvgNS,"circle");r.setAttribute("cx",k);r.setAttribute("cy",l);r.setAttribute("r",m);n&&r.setAttribute("fill",n);c.appendChild(r);return r},g=k=>{const l=.18*e,m=.5*e,n=k.x;k=k.y;const r=document.createElementNS(touchGamepadSvgNS,"path");r.setAttribute("d",`M ${n-l} ${k-m} H ${n+l} V ${k-l} H ${n+m} V ${k+l} H ${n+l} `+`V ${k+m} H ${n-l} V ${k+l} H ${n-m} V ${k-l} H ${n-l} Z`);c.appendChild(r)};for(let k=0;2>k;k++){const l=touchGamepadSideButtonCount(k),m=touchGamepadSideButtonBase(k),n=touchGamepadSideCenter(k,a,b);if(touchGamepadSideStick(k))touchGamepadAnalog?f(n.x,n.y,e/2):g(n),d.thumb[k]=f(n.x,n.y,e/4,"#fff");else if(1===l)d.face[m]=f(n.x,n.y,e/2,"#000");else for(let r=0;r{h=document.createElementNS(touchGamepadSvgNS,h);for(const m in k)h.setAttribute(m,k[m]);h.setAttribute("stroke",l);h.setAttribute("stroke-width",2);h.setAttribute("fill","none");d.appendChild(h)},f=(h,k,l)=>e("circle",{cx:h.x,cy:h.y,r:k},l);e("line",{x1:a/2,y1:0,x2:a/2,y2:b},"#0f0");for(var g=0;2>g;g++)if(touchGamepadSideStick(g))if(touchGamepadFloating){const h=.4*b,k=!touchGamepadSideHasControl(g?0:1);e("rect",{x:k?0:g?a/2:0,y:h,width:k?a:a/2,height:b-h},"#0ff")}else f(touchGamepadSideCenter(g,a,b),2*c,"#0ff");else 1<=touchGamepadSideButtonCount(g)&&f(touchGamepadSideCenter(g,a,b),c,"#0ff");if(touchGamepadCenterButtonSize)for(f(vec2(a/2,b/2),touchGamepadCenterButtonSize,"#ff0"),g=0;2>g;g++)touchGamepadStartBlockSide(g)&&f(touchGamepadSideCenter(g,a,b),2*c,"#f0f")}function touchGamepadRender(){if(touchGamepadOverlay&&!headlessMode)if(touchGamepadEnable&&isTouchDevice){touchGamepadOverlay.style.display="";var a=debug&&debugGamepads,b=[touchGamepadButtonCount,touchGamepadLeftButtonCount,touchGamepadLeftStick,touchGamepadRightStick,touchGamepadAnalog,touchGamepadSize,touchGamepadFloating,touchGamepadCenterButtonSize,paused,a].join();b!==touchGamepadLastLayout&&(touchGamepadLastLayout=b,touchGamepadNeedRelayout=!0);touchGamepadNeedRelayout&&touchGamepadRelayout();b=touchGamepadDisplayTime&&!touchGamepadPointerRole.size?percent(touchGamepadTimer.get(),touchGamepadDisplayTime+1,touchGamepadDisplayTime):1;var c=a||touchGamepadTimer.isSet()&&0e;e++)if(touchGamepadSideStick(e)&&b.thumb[e]){const f=touchGamepadSideCenter(e,a,c).add((touchGamepadSticks[e]??vec2()).scale(d/2));b.thumb[e].setAttribute("cx",f.x);b.thumb[e].setAttribute("cy",f.y)}for(a=0;a=touchGamepadSize)return-1;if(1===e)return f;b=c.subtract(b);a||(b.x*=-1);a=2===e?b.xh;h++){var g=h?!e:e;if(touchGamepadSideStick(h)){const k=touchGamepadSideHasControl(h?0:1);if(touchGamepadFloating?(!k||g)&&a.y>f:g&&touchGamepadSideCenter(h,b,c).distance(a)<2*d)return{role:"stick",side:h}}else if(1<=touchGamepadSideButtonCount(h)&&(g=touchGamepadFaceButtonAt(h,a,b,c),0<=g))return{role:"face",btn:g}}}function touchGamepadStartBlockedAt(a,b,c){for(let d=0;2>d;d++)if(touchGamepadStartBlockSide(d)&&touchGamepadSideCenter(d,b,c).distance(a)<2*touchGamepadSize)return!0;return!1}function touchGamepadStartBlockSide(a){return touchGamepadSideHasControl(a)&&!(touchGamepadFloating&&touchGamepadSideStick(a))}function touchGamepadPointerDown(a,b){if(touchGamepadEnable&&"mouse"!==a.pointerType)if(a.preventDefault(),b.setPointerCapture(a.pointerId),touchGamepadTimer.set(),soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioResume(),paused)touchGamepadCenterButtonSize&&!touchGamepadButtons[9]&&(touchGamepadButtons[9]=touchGamepadButtonsPressed[9]=1,touchGamepadPointerRole.set(a.pointerId,"start"));else{var c=touchGamepadStageRect();b=c.width;var d=c.height;c=vec2(a.clientX-c.left,a.clientY-c.top);var e=touchGamepadControlAt(c,b,d);e&&("stick"===e.role?(e=e.side,void 0===touchGamepadStickPointerId[e]&&(touchGamepadStickAnchors[e]=touchGamepadFloating?c:touchGamepadSideCenter(e,b,d),touchGamepadStickPointerId[e]=a.pointerId,touchGamepadPointerRole.set(a.pointerId,"stick"+e),touchGamepadNeedRelayout=!0,touchGamepadApplyStick(e,c),touchGamepadButtonsPressed[touchGamepadStickButton(e)]=1)):"face"===e.role?touchGamepadButtons[e.btn]||(touchGamepadButtons[e.btn]=touchGamepadButtonsPressed[e.btn]=1,touchGamepadPointerRole.set(a.pointerId,"face"+e.btn)):touchGamepadButtons[9]||(touchGamepadButtons[9]=touchGamepadButtonsPressed[9]=1,touchGamepadPointerRole.set(a.pointerId,"start")))}}function touchGamepadPointerMove(a){const b=touchGamepadPointerRole.get(a.pointerId);b&&(a.preventDefault(),a=touchGamepadEventPos(a),"stick0"!==b&&"stick1"!==b||touchGamepadApplyStick("stick1"===b?1:0,a))}function touchGamepadPointerUp(a){const b=touchGamepadPointerRole.get(a.pointerId);b&&(touchGamepadPointerRole.delete(a.pointerId),"stick0"===b||"stick1"===b?(a="stick1"===b?1:0,touchGamepadStickPointerId[a]=void 0,touchGamepadSticks[a]=vec2(),delete touchGamepadButtons[touchGamepadStickButton(a)]):"start"===b?delete touchGamepadButtons[9]:delete touchGamepadButtons[+b.slice(4)],touchGamepadTimer.set())}let audioContext="undefined"==typeof AudioContext?void 0:new AudioContext;function audioResume(){audioContext?.resume()?.catch?.(()=>{})}let audioMasterGain=audioContext?.createGain(),audioMasterVolume;audioMasterGain&&(audioMasterGain.connect(audioContext.destination),audioMasterGain.gain.value=audioMasterVolume=soundVolume,audioContext.addEventListener?.("statechange",audioStateChange));function audioUpdateVolume(){audioMasterGain&&soundVolume!==audioMasterVolume&&isFinite(soundVolume)&&(audioMasterGain.gain.value=audioMasterVolume=soundVolume)}let audioMasterEffectInput,audioMasterEffectOutput,audioMasterEffectOutputIsEffect;const audioDefaultSampleRate=44100;function audioIsRunning(){return"running"===audioContext?.state}function audioInit(){soundEnable&&!headlessMode&&(audioSetSession(),document.addEventListener("visibilitychange",audioVisibilityChange))}function audioSetSession(){const a="undefined"!=typeof navigator&&navigator.audioSession;a&&(a.type=soundIgnoreSilentSwitch?"playback":"auto")}let audioSuspendedWhenHidden=!1;function audioVisibilityChange(){audioContext&&(document.hidden?soundPauseWhenHidden&&"running"==audioContext.state&&(audioSuspendedWhenHidden=!0,audioContext.suspend()):audioSuspendedWhenHidden&&(audioSuspendedWhenHidden=!1,audioResume()))}const audioWaitingInstances=new Map;function audioWaitingPrune(a=performance.now()){for(const[b,c]of audioWaitingInstances){const d=(b.getDuration()-b.pausedTime)/b.rate;!b.loop&&a-c>1e3*d&&audioWaitingInstances.delete(b)}}function audioStateChange(){if(audioIsRunning()){audioWaitingPrune();var a=[...audioWaitingInstances.keys()];audioWaitingInstances.clear();for(const b of a)b.resume()}}function setAudioMasterEffect(a,b){var c=b||a;c=!!c&&"input"in c;b=audioEffectNode(b,"output")||audioEffectNode(a,"output");a=audioEffectNode(a,"input");if(audioMasterGain){audioMasterGain.disconnect(audioMasterEffectInput||audioContext.destination);if(audioMasterEffectOutput){let d=!0;try{audioMasterEffectOutput.disconnect(audioContext.destination)}catch{d=!1}audioMasterEffectOutputIsEffect&&d&&audioMasterEffectOutput.connect(audioMasterGain)}audioMasterEffectInput=a;audioMasterEffectOutput=b;audioMasterEffectOutputIsEffect=c;a?(audioMasterGain.connect(a),b.disconnect(),b.connect(audioContext.destination)):audioMasterGain.connect(audioContext.destination)}}function audioEffectNode(a,b){return a&&"input"in a?a[b]:a}const audioFinite=(a,b)=>isFinite(a)?a:b;function audioParamRamp(a,b,c=0){b=audioFinite(b,0);c=audioFinite(c,0);const d=audioContext.currentTime;a.cancelScheduledValues(d);c?(a.setValueAtTime(a.value,d),a.linearRampToValueAtTime(b,d+c)):a.value=b;return d+c}class Sound{constructor(a,b,c,d=soundDefaultTaper,e){if(soundEnable&&!headlessMode&&audioContext){var f=void 0===c;f&&(c=soundDefaultRange);this.range=c;this.rangeIsDefault=f;this.taper=d;this.randomness=b??0;this.sampleRate=audioDefaultSampleRate;this.sampleLength=0;this._sampleChannels=this.sampleBuffer=void 0;this.loadedPercent=0;this.onloadCallback=e;this.output=void 0;if(isArray(a))a=a.slice(),this.randomness=b??clamp(a[1]??.05),a[1]=0,this.sampleChannels=[zzfxG(...a)],this.buildSampleBuffer(),this.loadedPercent=1,e?.(this);else if(a){const g=a+"";engineAddLoad(this.loadSound(g).catch(h=>{console.warn("Sound load failed for",g,"-",h?.message??h);try{1===this.loadedPercent||this.onloadCallback?.(this)}catch(k){console.warn("Sound onloadCallback failed for",g,"-",k)}}))}}else this.loadedPercent=1,e?.(this)}get range(){return this.rangeValue}set range(a){this.rangeValue=a;this.rangeIsDefault=!1}get sampleChannels(){const a=this.sampleBuffer;if(!this._sampleChannels&&a){const b=[];for(let c=0;c=g*g)return;h**=.5;const k=g*this.taper;h>k&&(b*=percent(h,g,k))}g=2*worldToScreen(a).x/mainCanvasSize.x-1}c+=c*this.randomness*d*rand(-1,1);e=new SoundInstance(this,b,c,g,e,f);debug&&debugSound&&a&&(debugCircle(a,.5,"#0ff",.5,!0,!1),this.range&&(debugCircle(a,2*this.range,"#0ff",.5,!1,!1),debugCircle(a,2*this.range*this.taper,"#0ff",.5,!1,!1)),debugText("vol "+b.toFixed(2)+" pitch "+c.toFixed(2),a,.5,"#0ff",.5,0,"monospace",!1));return e}}playLoop(a,b=1,c=1,d=1,e=!1){return this.play(a,b,c,d,!0,e)}playMusic(a=1,b=!0,c=!1){return this.play(void 0,a,1,0,b,c)}playNote(a=0,b,c){a=getNoteFrequency(a,1);return this.play(b,c,a,0)}getDuration(){return this.sampleLength/this.sampleRate||0}isLoaded(){return 1===this.loadedPercent}async loadSound(a){const b=await loadFetch(a,"loadSound");if(!b.ok)throw Error(`loadSound: could not load ${a}, HTTP ${b.status} ${b.statusText}`);a=await b.arrayBuffer();a=await audioContext.decodeAudioData(a);this.sampleRate=a.sampleRate;this.sampleLength=a.length;this.sampleBuffer=a;this._sampleChannels=void 0;this.loadedPercent=1;this.onloadCallback?.(this)}}class SoundInstance{constructor(a,b=1,c=1,d=0,e=!1,f=!1){this.sound=a;this.volume=audioFinite(b,0);this.rate=audioFinite(c,1);this.pan=audioFinite(d,0);this.loop=e;this.pausedTime=0;this.startTime=void 0;this.startOffset=0;this.source=this.pannerNode=this.gainNode=void 0;this.output=a.output;this.onendedCallback=void 0;this.sourceEnded=g=>{g===this.source&&(this.startTime=this.source=this.gainNode=this.pannerNode=void 0,this.pausedTime=0,this.onendedCallback?.(g))};f||this.start()}start(a=0){this.isPlaying()&&this.stop();this.gainNode=audioContext.createGain();this.pannerNode=new StereoPannerNode(audioContext,{pan:clamp(this.pan,-1,1)});this.sound.buildSampleBuffer();this.source=this.sound.sampleBuffer?playAudioBuffer(this.sound.sampleBuffer,this.volume,this.rate,this.pan,this.loop,this.gainNode,a,this.sourceEnded,this.output,this.pannerNode):playSamples(this.sound.sampleChannels,this.volume,this.rate,this.pan,this.loop,this.sound.sampleRate,this.gainNode,a,this.sourceEnded,this.output,this.pannerNode);audioWaitingInstances.delete(this);if(this.source)this.startTime=audioContext.currentTime,this.startOffset=a,this.pausedTime=void 0;else if(this.startTime=this.gainNode=this.pannerNode=void 0,this.pausedTime=a,!audioIsRunning()){audioWaitingPrune();for(const b of audioWaitingInstances.keys())b.sound===this.sound&&audioWaitingInstances.delete(b);audioWaitingInstances.set(this,performance.now())}}setVolume(a,b=0){this.volume=a=audioFinite(a,0);this.gainNode&&audioParamRamp(this.gainNode.gain,a,b)}setPan(a){this.pan=a=audioFinite(a,0);this.pannerNode&&(this.pannerNode.pan.value=clamp(a,-1,1))}setRate(a){this.isPlaying()&&(this.startOffset=this.getCurrentTime(),this.startTime=audioContext.currentTime);this.rate=a=audioFinite(a,1);this.source&&(this.source.playbackRate.value=a)}stop(a=0){audioWaitingInstances.delete(this);this.isPlaying()&&(a?this.source.stop(audioParamRamp(this.gainNode.gain,0,a)):this.source.stop());this.pausedTime=0;this.pannerNode=this.gainNode=this.startTime=this.source=void 0}pause(){audioWaitingInstances.delete(this);this.isPaused()||(this.pausedTime=this.getCurrentTime(),this.source.stop(),this.pannerNode=this.gainNode=this.startTime=this.source=void 0)}resume(){this.isPaused()&&this.start(this.pausedTime)}isPlaying(){return!!this.source}isPaused(){return!this.isPlaying()}getCurrentTime(){if(!this.isPlaying())return this.pausedTime;const a=this.getDuration(),b=this.startOffset+(audioContext.currentTime-this.startTime)*this.rate;return a?this.loop?mod(b,a):min(b,a):0}getDuration(){return this.sound.getDuration()}getSource(){return this.source}}function speak(a,b=1,c=1,d=1,e=""){if(soundEnable&&!headlessMode&&"undefined"!==typeof speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=e,a.volume=clamp(b*soundVolume),a.rate=c,a.pitch=d,speechSynthesis.speak(a),a}function speakStop(){"undefined"!==typeof speechSynthesis&&speechSynthesis.cancel()}function getNoteFrequency(a,b=220){return b*2**(a/12)}function playSamples(a,b=1,c=1,d=0,e=!1,f=audioDefaultSampleRate,g,h=0,k,l,m){if(soundEnable&&!headlessMode){if(audioIsRunning())return a=createAudioBuffer(a,f),playAudioBuffer(a,b,c,d,e,g,h,k,l,m);audioSuspendedWhenHidden||audioResume()}}function createAudioBuffer(a,b=audioDefaultSampleRate){const c=audioContext.createBuffer(a.length,a[0].length,b);a.forEach((d,e)=>c.getChannelData(e).set(d));return c}function playAudioBuffer(a,b=1,c=1,d=0,e=!1,f,g=0,h,k,l){if(soundEnable&&!headlessMode){if(audioIsRunning()){b=audioFinite(b,0);c=audioFinite(c,1);d=audioFinite(d,0);var m=audioContext.createBufferSource();m.buffer=a;m.playbackRate.value=c;m.loop=e;f=f||audioContext.createGain();f.gain.value=b;a=audioEffectNode(k,"input")||audioMasterGain;f.connect(a);var n=l||new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)});m.connect(n).connect(f);m.addEventListener("ended",()=>{f.disconnect();n.disconnect();h&&h(m)});m.start(0,g);return m}audioSuspendedWhenHidden||audioResume()}}function zzfx(...a){return playSamples([zzfxG(...a)])}function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,k=0,l=0,m=0,n=0,r=0,q=0,p=0,t=0,u=0,v=1,y=0,x=0,w=0){var z=audioDefaultSampleRate;let A=2*PI,C=k*=500*A/z/z;b=c*=(1+rand(b,-b))*A/z;let D=0,B=0,E=0,F=1,G,H=0,J=0,M=0,L;var I=A*min(abs(w),z/4-1)*2/z,K=cos(I),N=sin(I)/2/2,O=1+N;I=-2*K/O;N=(1-N)/O;let P=(1+sign(w)*K)/2/O;K=-(sign(w)+K)/O;let Q=O=0,R=0,S=0;d=d*z||9;y*=z;e*=z;f*=z;u*=z;l*=500*A/z**3;p*=A/z;m*=A/z;n*=z;r=r*z|0;z=d+y+e+f+u|0;for(G=new Float32Array(0J?0:(Jn&&(c+=m,b+=m,F=0),!r||++B%r||(c=b,k=C,F||=1);return G}const tileCollisionLayers=[];function tileCollisionAssertWhole(a){}let tileCollisionFromObject,tileCollisionFromPos,tileCollisionHitObject;function tileCollisionOneWayPass(a,b,c,d,e,f=0,g=0){var h=a.oneWayTiles;if(!h.size)return!1;var k=a.data[c*a.size.x+b],l=k&&h.get(k.tile);if(!l)return!1;h=k.mirror?-l.x:l.x;l=l.y;for(k=k.direction&3;k--;)[h,l]=[l,-h];b=a.pos.x+b;a=a.pos.y+c;return.5h?d+f/2>b+.001:.5a+.001}let tileCollisionDataLayer;function tileCollisionGetDataFrom(a,b,c){let d=0;tileCollisionDataLayer=void 0;for(const f of tileCollisionLayers)if(f.isSolid){const g=a.x-f.pos.x,h=a.y-f.pos.y;var e=f.size;if(0<=g&&0<=h&&ga(b,c):(b,c)=>a.collideWithTile(b,c,a===tileCollisionHitObject):b=>0a.textureInfo.size.y))return a.frame(b)}}function tileLayersLoad(a,b=tileLayerDefaultTile(),c=0,d,e=!0){a||={width:50,height:50,layers:[{data:Array(2500).fill(0)}]};a=editorMapRestore(a);const{width:f,height:g}=a;if(!(Number.isInteger(f)&&Number.isInteger(g)&&0{for(const x of t){if((t=x.type)&&"tilelayer"!==t&&"group"!==t){r.push({dataLayer:x});continue}var y=x.tintcolor;y=y?tileLayersColor(y):(x.color||WHITE).copy();y.a*=x.opacity??1;const w=v&&!1!==x.visible;"group"===t?q(x.layers||[],u.multiply(y),w):r.push({dataLayer:x,color:u.multiply(y),visible:w})}};q(a.layers,WHITE,!0);if("string"===typeof d){const t=d;d=r.findIndex(u=>u.color&&u.dataLayer.name===t);0>d&&console.error("tileLayersLoad: no tile layer is named "+t+", none is solid")}k=[];l=vec2(a.width,a.height);m=r.length;for(const[t,{dataLayer:u,color:v}]of r.entries())if(h=u.data,v&&(!isArray(h)&&!ArrayBuffer.isView(h)||u.data.length!==l.area()))throw Error(`tileLayersLoad: layer ${u.name??t} has ${u.data?.length} tiles for a map of `+`${l.area()}; infinite maps and compressed layers are not read`);for(h=m;h--;){const{dataLayer:t,color:u,visible:v}=r[h];if(u){n=c-(m-1-h);n=new TileCollisionLayer(vec2(),l,b,n);n.isSolid=h===d;k[h]=n;v||(n.render=()=>{});for(let y=0;y>>29];p=new TileLayerData((p&268435455)-1,z,!!A,u);n.setData(w,p);h===d&&n.setCollisionData(w,1)}}e&&v&&n.redraw()}}editorMapLoaded(a,k,r);return k}function tileLayersColor(a){return(new Color).setHex(9===a.length?"#"+a.slice(3)+a.slice(1,3):a)}const tileLayersLDtkTypes={Int:"int",Float:"float",Bool:"bool",String:"string",Multilines:"string",Color:"color",FilePath:"file"};function tileLayersFromLDtk(a,b=0){var c=a?.levels?.length?a.levels:(a?.worlds||[]).flatMap(t=>t.levels||[]),d="string"===typeof b?c.find(t=>t.identifier===b):c[b];if(!d)throw Error("tileLayersFromLDtk: no level "+b);if(!isArray(d.layerInstances))throw Error("tileLayersFromLDtk: level "+d.identifier+" has no layers, levels saved as separate files are not read");c=d.layerInstances;const e=t=>"Entities"!==t.__type,f=c.find(t=>e(t)&&void 0!=t.__tilesetDefUid)||c.find(e)||c[0],g=f?.__gridSize||16,h=f?.__cWid||ceil(d.pxWid/g),k=f?.__cHei||ceil(d.pxHei/g);if(!(0=h*k))throw Error("tileLayersFromLDtk: level "+d.identifier+" is "+h+" by "+k+" cells");const l={width:h,height:k,tilewidth:g,tileheight:g,orientation:"orthogonal",renderorder:"right-down",infinite:!1,layers:[],nextlayerid:1,nextobjectid:1};if(a=(a?.defs?.tilesets||[]).find(t=>t.uid===f?.__tilesetDefUid))l.tilesets=[{firstgid:1,name:String(a.relPath||"").replace(/^.*[\\/]/,"").replace(/\.\w+$/,""),image:a.relPath,imagewidth:a.pxWid,imageheight:a.pxHei,tilewidth:a.tileGridSize,tileheight:a.tileGridSize,margin:a.padding||0,spacing:a.spacing||0,columns:a.__cWid,tilecount:a.__cWid*a.__cHei}];for(d=c.length;d--;){var m=c[d],n=m.__identifier;const t=l.nextlayerid++;if(!e(m)){var r=(m.entityInstances||[]).filter(x=>isArray(x.px)).map(x=>{const[w=0,z=0]=x.__pivot||[],A=x.width||0,C=x.height||0,D=[];for(const B of x.fieldInstances||[]){const E=tileLayersLDtkTypes[B.__type]||/^(Local|Extern)Enum\./.test(B.__type)&&"string";E&&void 0!=B.__value&&D.push({name:B.__identifier,type:E,value:B.__value})}return{id:l.nextobjectid++,name:"",type:x.__identifier,x:x.px[0]+(.5-w)*A,y:x.px[1]+(.5-z)*C,width:A,height:C,rotation:0,visible:!0,properties:D}});l.layers.push({id:t,name:n,type:"objectgroup",objects:r,opacity:1,visible:!0,x:0,y:0});continue}if(m.__gridSize!==g||m.__cWid!==h||m.__cHei!==k){console.warn(`tileLayersFromLDtk: layer ${n} has another grid, left out`);continue}r=m.__opacity??1;const u="IntGrid"===m.__type;if(u){const x=Array(h*k).fill(0);(m.intGridCsv||[]).forEach((w,z)=>zisArray(x.px));if(!q.length){u||l.layers.push({id:t,name:n,type:"tilelayer",width:h,height:k,data:Array(h*k).fill(0),opacity:r,visible:!1!==m.visible,x:0,y:0});continue}if(a&&(m.__tilesetDefUid!==a.uid||a.tileGridSize!==g)){console.warn(`tileLayersFromLDtk: the tiles of layer ${n} are on another tileset, left out`);continue}n=u?n+" tiles":n;const v=[{depth:0,alpha:1,data:Array(h*k).fill(0)}];var p=(x,w)=>{let z=v.find(A=>A.depth===x&&A.alpha===w);z||v.push(z={depth:x,alpha:w,data:Array(h*k).fill(0)});return z.data};const y=new Uint16Array(h*k);for(const x of q){q=floor(x.px[0]/g);const w=floor(x.px[1]/g),z=q+w*h;0<=q&&q>>0)}m=!1!==m.visible;v.sort((x,w)=>x.depth-w.depth||w.alpha-x.alpha);for(const{depth:x,alpha:w,data:z}of v)p=n+(x?` (${x+1})`:"")+(1>w?" "+String(w).replace(/^0/,""):""),l.layers.push({id:u||x||1>w?l.nextlayerid++:t,name:p,type:"tilelayer",width:h,height:k,data:z,opacity:r*w,visible:m,x:0,y:0})}return l}const objectLayersTypes=new Map;function objectLayersAddType(a,b,c={},d){objectLayersTypes.set(String(a),{make:b,defaults:c,tileInfo:d})}function objectLayersLoad(a){a&&editorMapRestore(a);const b=[],c=d=>{for(const e of d||[])if("group"===e.type&&c(e.layers),"objectgroup"===e.type)for(const f of e.objects||[])d=objectLayersMake(a,f),editorObjectMade(a,e,f,d),d&&b.push(d)};c(a?.layers);return b}function objectLayersProperties(a,b){const c={};for(const[d,e]of Object.entries(a.defaults))c[d]=e?.copy?e.copy():e;for(const d of b.properties||[]){const{name:e,value:f}=d;if("color"===d.type)f&&(c[e]=tileLayersColor(f));else if(isVector2(a.defaults[e])){b=String(f).split(",");const[g,h]=b.map(Number);2===b.length&&b.every(k=>k.trim())&&isNumber(g)&&isNumber(h)&&(c[e]=vec2(g,h))}else c[e]=f}return c}function objectLayersMake(a,b){const c=b.type||b.class,d=objectLayersTypes.get(c);if(d){var{height:e=0,tilewidth:f=1,tileheight:g=1}=a;a=vec2(b.x/f,e-b.y/g);var{make:h}=d;if((a=h.prototype?new h(a):h(a))&&"object"===typeof a){for(const[k,l]of Object.entries(objectLayersProperties(d,b)))"function"===typeof a[k]&&"function"!==typeof l?debug&&console.warn(`objectLayersLoad: ${c} property ${k} has a method's name, left out`):a[k]=l;return a}}else debug&&c&&console.warn(`objectLayersLoad: no type added for ${c}, skipped`)}class TileLayerData{constructor(a,b=0,c=!1,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d.copy()}clear(){this.tile=void 0;this.direction=0;this.mirror=!1;this.color=new Color}}class CanvasLayer extends EngineObject{constructor(a,b,c=0,d=0,e=vec2(512),f=!0){super(a,b,void 0,c,WHITE,d);this.context=headlessMode?void 0:createCanvasContext(e.x,e.y);this.canvas=this.context?.canvas;this.textureInfo=new TextureInfo(this.canvas,f);(a=f&&glContext?glContext.getParameter(glContext.MAX_TEXTURE_SIZE):0)&&max(e.x,e.y)>a&&console.warn(`LittleJS: a ${e.x}x${e.y} layer is over this device's ${a} pixel texture limit and draws black, split it into smaller layers`);this.mass=0}destroy(a=!1){this.destroyed||(this.textureInfo.destroyWebGLTexture(),super.destroy(a))}render(){this.draw(this.pos,this.size,this.color,this.angle,this.mirror,this.additiveColor,!1)}draw(a,b,c=WHITE,d=0,e=!1,f,g=drawScreenSpace,h){var k=this.textureInfo,l=this.canvas;!l||this.hasWebGL()||l.width===k.size.x&&l.height===k.size.y||(k.size=vec2(l.width,l.height),k.sizeInverse=vec2(1/l.width,1/l.height));k=(new TileInfo).setFullImage(k);l=!h&&this.hasWebGL();drawTile(a,b,k,c,d,e,f,l,g,h)}updateWebGL(){this.textureInfo.createWebGLTexture()}hasWebGL(){return glEnable&&this.textureInfo.hasWebGL()}}function tileLayerDefaultTile(){return textureInfos[0]?.size.x?tile():void 0}class TileLayer extends CanvasLayer{constructor(a,b,c=tileLayerDefaultTile(),d=0,e=!0){b=b.floor();const f=c?b.multiply(c.size):b;super(a,b,0,d,f,e);this.tileInfo=void 0;this.data=[];this.isUsingWebGL=!1;this.tilesInWebGL=void 0;this.debugShow=!0;c&&(this.tileInfo=c.frame(0),this.tileInfo.bleed=0,this.tileInfo.tiles=c.tiles);for(a=this.size.area();a--;)this.data.push(new TileLayerData);headlessMode&&(this.render=()=>{},this.redraw=()=>{},this.redrawStart=()=>{},this.redrawEnd=()=>{},this.drawTileData=()=>{},this.redrawTileData=()=>{},this.drawLayerTile=()=>{},this.drawLayerRect=()=>{},this.drawTile=()=>{},this.drawRect=()=>{},this.clearLayerRect=()=>{})}setData(a,b,c=!1){a=a.floor();a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+(a.x|0)]=b,c&&(drawContext===this.context?this.drawTileData(a):this.redrawTileData(a)))}clearData(a,b=!1){this.setData(a,new TileLayerData,b)}getData(a){return a.arrayCheck(this.size)?this.data[(a.y|0)*this.size.x+(a.x|0)]:void 0}update(){}render(){this.redrawIfSwitched();const a=this.drawSize||this.size,b=this.pos.add(a.scale(.5));this.draw(b,a,this.color,this.angle,this.mirror,this.additiveColor,!1)}onRedraw(){}redraw(){this.redrawStart(!0);try{for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b),!1);this.isUsingWebGL&&glFlush();this.onRedraw()}finally{this.redrawEnd()}this.tilesInWebGL=this.isUsingWebGL}redrawIfSwitched(){void 0!==this.tilesInWebGL&&this.hasWebGL()!==this.tilesInWebGL&&this.redraw()}redrawStart(a=!1){if(this.context){a||this.redrawIfSwitched();this.savedRenderSettings=[drawContext,mainCanvasSize,cameraPos,cameraScale,cameraAngle,canvasClearColor,glCustomShader];setShader();this.savedRenderTarget=[glRenderTarget,glColorMask,glColorAdditive,glSkipScreenSpace];glColorMask=-1;glColorAdditive=0;glSkipScreenSpace=!1;drawContext=this.context;var b=this.tileInfo?.size??vec2(1);mainCanvasSize=this.size.multiply(b);canvasClearColor=CLEAR_BLACK;cameraPos=this.size.multiply(b).scale(.5);cameraScale=1;cameraAngle=0;(this.isUsingWebGL=this.hasWebGL())?glSetRenderTarget(this.textureInfo.glTexture,a):(a&&(this.canvas.width=mainCanvasSize.x,this.canvas.height=mainCanvasSize.y),this.context.imageSmoothingEnabled=!tilesPixelated)}}redrawEnd(){if(this.context){[drawContext,mainCanvasSize,cameraPos,cameraScale,cameraAngle,canvasClearColor,glCustomShader]=this.savedRenderSettings;var[a,b,c,d]=this.savedRenderTarget;this.isUsingWebGL&&glSetRenderTarget(a);glColorMask=b;glColorAdditive=c;glSkipScreenSpace=d}}drawTileData(a,b=!0){if(this.context){var c=this.tileInfo?.size??vec2(1),d=a.multiply(c);b&&this.clearLayerRect(d,c);if((a=this.getData(a))&&void 0!==a.tile){b=this.tileInfo;var e=tileLayerTileInfo(b,a.tile);b&&!e||this.drawLayerTile(d,c,e,a.color,a.direction*PI/2,a.mirror)}}}redrawTileData(a,b=!0){if(this.context){this.redrawStart();try{this.drawTileData(a,b)}finally{this.redrawEnd()}}}drawLayerTile(a,b=vec2(1),c,d=WHITE,e=0,f,g){a=a.add(b.scale(.5));drawTile(a,b,c,d,e,f,g,this.isUsingWebGL,!1)}drawLayerRect(a,b,c,d=0){this.drawLayerTile(a,b,void 0,c,d)}drawTile(a,b=vec2(1),c,d=new Color,e=0,f=!1){var g=this.tileInfo?.size??vec2(1);a=a.subtract(this.pos).multiply(g);b=b.multiply(g);a.x-=.5;a.y=this.canvas.height-a.y-.5;g=mainCanvasSize;const h=glRenderTarget,k=glColorMask,l=glSkipScreenSpace,m=glColorAdditive,n=glCustomShader;mainCanvasSize=vec2(this.canvas.width,this.canvas.height);glColorMask=-1;glColorAdditive=0;setShader();glSkipScreenSpace=!1;const r=this.hasWebGL();r&&glSetRenderTarget(this.textureInfo.glTexture);drawTile(a,b,c,d,e,f,void 0,r,!0,r?void 0:this.context);mainCanvasSize=g;r&&glSetRenderTarget(h);glColorMask=k;glColorAdditive=m;glSkipScreenSpace=l;setShader(n)}drawRect(a,b,c,d){this.drawTile(a,b,void 0,c,d)}clearLayerRect(a,b){const c=a.x;a=this.canvas.height-a.y-b.y;this.hasWebGL()?glClearRect(c,a,b.x,b.y):this.context.clearRect(c,a,b.x,b.y)}}class TileCollisionLayer extends TileLayer{constructor(a,b,c=tileLayerDefaultTile(),d=0,e=!0){super(a,b.floor(),c,d,e);this.collisionData=[];this.initCollision(this.size);tileCollisionLayers.push(this);this.shadowSolidOnly=this.isSolid=!0;this.oneWayTiles=new Map}setOneWay(a,b=vec2(0,1)){this.oneWayTiles.set(a,b.copy())}renderShadow(){if(!this.shadowSolidOnly||this.angle||this.mirror)return super.renderShadow();const a=this.size,b=(this.drawSize||a).divide(a),c=this.tileInfo?this.tileInfo.size:vec2(1);var d=getCameraSize().scale(.5),e=cameraPos.subtract(d),f=cameraPos.add(d);d=max(0,floor((e.x-this.pos.x)/b.x));const g=min(a.x,ceil((f.x-this.pos.x)/b.x));var h=max(0,floor((e.y-this.pos.y)/b.y));e=min(a.y,ceil((f.y-this.pos.y)/b.y));f=a.y*c.y;const k=this.hasWebGL();for(;he+b.x/2||e-b.x/2>this.size.x||0>f+b.y/2||f-b.y/2>this.size.y)return!1;a=max(e-b.x/2|0,0);var g=max(f-b.y/2|0,0);e=min(b.x?e+b.x/2:a+1,this.size.x);for(f=min(b.y?f+b.y/2:g+1,this.size.y);gl||l>n)return;continue}const r=(-1-l)/m,q=(n-l)/m;h=max(h,min(r,q));k=min(k,max(r,q))}if(!(h>k)){if(c=lineTest(h?c.add(g.scale(h)):c,1>k?c.add(g.scale(k)):b.subtract(f),l=>{const m=this.getCollisionData(l);return m&&!tileCollisionOneWayPass(this,l.x|0,l.y|0,a.x,a.y)&&e(m,vec2(l.x+f.x,l.y+f.y))},d))g=c.floor(),c.x+=f.x,c.y+=f.y,h=(l,m)=>la){this.emitTimeBuffer+=a*b+(this.emitTime&&this.emitElapsed>=this.emitTime?1e-6:0);a=this.emitFrom&&this.pos.distance(this.emitFrom)<=2*objectMaxSpeed;b=floor(this.emitTimeBuffer);try{for(var c=b;c--;--this.emitTimeBuffer)this.emitBehind=a?c/b:0,this.emitParticle()}finally{this.emitBehind=0}}}else 0===this.particles.length&&(this.destroy(!0),this.finishCallback?.(this));a=this.particles;b=0;for(c=0;cn+n*rand(e,-e);d=f(this.particleTime);const g=f(this.sizeStart)*a,h=f(this.sizeEnd)*a;var k=f(this.speed)*a,l=f(this.angleSpeed)*randSign(),m=rand(this.emitConeAngle,-this.emitConeAngle);a=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear);f=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);m=this.localSpace?m:this.angle+m;k=vec2(k*sin(m),k*cos(m));!this.localSpace&&0=this.lifeTime||time-this.spawnTime>this.lifeTime)this.destroy();else{var l=enablePhysicsSolver&&g,m=this.pos.x;g=this.pos.y;var n=this.scale,r=gravity.x*f*n;f=(gravity.y*f+(a.gravity||0))*n;a.localSpace&&a.angle&&(n=cos(a.angle),a=sin(a.angle),[r,f]=[r*n-f*a,r*a+f*n]);this.velocity.x=this.velocity.x*b+r;this.velocity.y=this.velocity.y*b+f;l&&(b=this.velocity.lengthSquared(),b>objectMaxSpeed*objectMaxSpeed&&(b=objectMaxSpeed/b**.5,this.velocity.x*=b,this.velocity.y*=b));this.pos.x+=this.velocity.x;this.pos.y+=this.velocity.y;this.angle+=this.angleVelocity*=c;if(l){this.groundObject=void 0;particleCollideFromX=m;particleCollideFromY=g;if(particleCollideTest(this,h,this.pos.x,this.pos.y)&&(c=tileCollisionDataLayer,!particleCollideTest(this,h,m,g))){l=particleCollideTest(this,h,this.pos.x,g);h=particleCollideTest(this,h,m,this.pos.y);d=c?max(d,c.restitution):d;e=c?max(e,c.friction):e;l&&(this.pos.x=m,this.velocity.x*=-d,this.velocity.y*=e);if(h||!l){m=f;if(0>this.velocity.y&&0>m||01-e?(1-f)/e:1);e=particleDrawPos.set(this.pos.x,this.pos.y);f=this.angle;if(b){g=a.angle;const k=cos(-g),l=sin(-g);e.set(a.pos.x+e.x*k-e.y*l,a.pos.y+e.x*l+e.y*k);f+=g}c&&setAdditiveBlendMode();d&&(a=b?this.velocity.rotate(a.angle):this.velocity,b=a.length())&&(h.y=max(h.x,b*d),f=atan2(a.x,a.y));glEnable&&!headlessMode?(d=this.tileInfo,particleTileBatch&&d===particleTile||particleTileSet(d),particleTileTextured)?particleTileEmpty||(d=d.textureInfo.glTexture,glActiveTexture===d||glSetTexture(d),glDraw(e.x,e.y,this.mirror?-h.x:h.x,h.y,f,particleTileU0,particleTileV0,particleTileU1,particleTileV1,this.color.rgbaInt())):glDrawUntextured(e.x,e.y,h.x,h.y,f,this.color.rgbaInt()):drawTile(e,h,this.tileInfo,this.color,f,this.mirror,void 0,!1,!1);c&&setAdditiveBlendMode(!1);debugParticles&&debugRect(e,h,"#f005",0,f,!1,!1)}}let glCanvas,glContext,glMaxTextureSize=0;function glClampTextureSize(a){return glMaxTextureSize?min(a,glMaxTextureSize):a}let glAntialias=!0,glMipmappedTextures=new WeakSet,glMipmapsUntilTarget=new WeakSet,glMipmapsStale=new Set,glPremultipliedTextures=new WeakSet,glShaderPremultiplied,glEnableBeforeLoss=!0,glShader,glPolyShader,glPolyMode,glAdditive,glBatchAdditive,glActiveTexture,glArrayBuffer,glGeometryBuffer,glPositionData,glColorData,glBatchCount,glTextureInfos=new Set,glInstancedVAO,glPolyVAO,glFramebuffer,glRenderTarget,glShaderObjects=[],glCustomShader,glBatchShader,glProgramCustom,glTransform,glRenderTargetSaved,glUniformLocations=new WeakMap,glCanBeEnabled=!0,glDeviceFailed=!1,glFailedPrograms=new WeakSet,glColorMask=-1,glColorAdditive=0,glRenderTargetBase,glSkipScreenSpace=!1;const gl_ARRAY_BUFFER_SIZE=5e5,gl_INDICES_PER_INSTANCE=11,gl_INSTANCE_BYTE_STRIDE=4*gl_INDICES_PER_INSTANCE,gl_MAX_INSTANCES=gl_ARRAY_BUFFER_SIZE/gl_INSTANCE_BYTE_STRIDE|0,gl_INDICES_PER_POLY_VERTEX=3,gl_POLY_VERTEX_BYTE_STRIDE=4*gl_INDICES_PER_POLY_VERTEX,gl_MAX_POLY_VERTEXES=gl_ARRAY_BUFFER_SIZE/gl_POLY_VERTEX_BYTE_STRIDE|0,gl_VERTEX_SOURCE="#version 300 es\nprecision highp float;uniform mat4 m;layout(location=0) in vec2 g;layout(location=1) in vec4 p;layout(location=2) in vec4 u;layout(location=3) in vec4 c;layout(location=4) in vec4 a;layout(location=5) in float r;out vec2 v,l;out vec4 d,e;void main(){vec2 s=(g-.5)*p.zw;gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);v=mix(u.xw,u.zy,g);l=g;d=c;e=a;}",gl_FRAGMENT_TINT_SOURCE="c=t*d+e;if(premultipliedTexture){c.a=min(c.a,1.);c.rgb=min(t.rgb*d.rgb*min(d.a+e.a,1.)+e.rgb*c.a,c.a);}";function glInit(a){function b(){glMaxTextureSize=glContext.getParameter(glContext.MAX_TEXTURE_SIZE)|0;glShader=glCreateProgram(gl_VERTEX_SOURCE,"#version 300 es\nprecision highp float;uniform sampler2D s;uniform bool premultipliedTexture;in vec2 v;in vec4 d,e;out vec4 c;void main(){vec4 t=texture(s,v);"+gl_FRAGMENT_TINT_SOURCE+"}");glShaderPremultiplied=!1;glPolyShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;in vec2 p;in vec4 c;out vec4 d;void main(){gl_Position=m*vec4(p,1,1);d=c;}","#version 300 es\nprecision highp float;in vec4 d;out vec4 c;void main(){c=d;}");if(glFailedPrograms.has(glShader)||glFailedPrograms.has(glPolyShader))console.error("LittleJS: WebGL can not draw on this device, using Canvas2D"),glEnable=glCanBeEnabled=!1,glDeviceFailed=!0,glCanvas.style.display="none";var c=new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);glPositionData=new Float32Array(c);glColorData=new Uint32Array(c);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();glFramebuffer=glContext.createFramebuffer();glBatchCount=0;c=new Float32Array([0,0,1,0,0,1,1,1]);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,c,glContext.STATIC_DRAW);let d,e,f;c=(g,h,k,l,m=0)=>{g=glContext.getAttribLocation(e,g);const n=1===k,r=k&&f;glContext.enableVertexAttribArray(g);glContext.vertexAttribPointer(g,l,h,n,r,d);glContext.vertexAttribDivisor(g,m);d+=l*k};glInstancedVAO=glContext.createVertexArray();glContext.bindVertexArray(glInstancedVAO);d=0;e=glShader;f=gl_INSTANCE_BYTE_STRIDE;glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);c("g",glContext.FLOAT,0,2);glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(glContext.ARRAY_BUFFER,gl_ARRAY_BUFFER_SIZE,glContext.DYNAMIC_DRAW);c("p",glContext.FLOAT,4,4,1);c("u",glContext.FLOAT,4,4,1);c("c",glContext.UNSIGNED_BYTE,1,4,1);c("a",glContext.UNSIGNED_BYTE,1,4,1);c("r",glContext.FLOAT,4,1,1);glPolyVAO=glContext.createVertexArray();glContext.bindVertexArray(glPolyVAO);d=0;e=glPolyShader;f=gl_POLY_VERTEX_BYTE_STRIDE;c("p",glContext.FLOAT,4,2);c("c",glContext.UNSIGNED_BYTE,1,4)}if(!glEnable||headlessMode)glCanBeEnabled=!1;else if(glCanvas=document.createElement("canvas"),glContext=glCanvas.getContext("webgl2",{antialias:glAntialias})){a.appendChild(glCanvas);b();for(const c of glTextureInfos){let d;(d=c).glTexture||(d.glTexture=glCreateTexture(c.image,c.wrap,c.pixelated))}glCanvas.addEventListener("webglcontextlost",c=>{glEnableBeforeLoss=glEnable;glEnable=!1;glCanvas.style.display="none";c.preventDefault();for(const d of glTextureInfos)d.glTexture=void 0;glActiveTexture=void 0;for(const d of glShaderObjects)d.program=void 0;glBatchShader=void 0;glProgramCustom=!0;glUniformLocations=new WeakMap;glBatchCount=0;glPolyMode=!1;pluginList.forEach(d=>d.glContextLost?.())});glCanvas.addEventListener("webglcontextrestored",()=>{glEnable=glEnableBeforeLoss;glCanvas.style.display="";glMipmappedTextures=new WeakSet;glMipmapsUntilTarget=new WeakSet;glMipmapsStale.clear();glPremultipliedTextures=new WeakSet;b();for(const c of glTextureInfos)c.glTexture=glCreateTexture(c.image,c.wrap,c.pixelated);pluginList.forEach(c=>c.glContextRestored?.());for(const c of engineObjects)c instanceof TileLayer&&c.isUsingWebGL&&!c.destroyed&&c.redraw()})}else console.warn("WebGL2 not supported, falling back to 2D canvas rendering!"),glCanvas=glContext=void 0,glCanBeEnabled=glEnable=!1,glDeviceFailed=!0}function glSetInstancedMode(a=!1){if(a||glPolyMode)glFlush(),glPolyMode=!1,glContext.useProgram(glShader),glContext.bindVertexArray(glInstancedVAO),glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer)}function glSetPolyMode(){glPolyMode||(glFlush(),glPolyMode=!0,glContext.useProgram(glPolyShader),glContext.bindVertexArray(glPolyVAO))}function glPreRender(a=!0){if(glEnable&&glContext){var b=glRenderTarget?1:getCanvasPixelRatio(),c=mainCanvasSize.x*b|0;b=mainCanvasSize.y*b|0;glRenderTarget||glCanvas.width===c&&glCanvas.height===b||(glCanvas.width=c,glCanvas.height=b);glContext.viewport(0,0,c,b);a&&glClearCanvas();a=vec2(2*cameraScale).divide(mainCanvasSize);glRenderTarget&&(a.y=-a.y);c=cameraPos.rotate(-cameraAngle);c=vec2(-1).subtract(c.multiply(a));b=cos(cameraAngle);var d=sin(cameraAngle);glTransform=a=[a.x*b,a.y*d,0,0,-a.x*d,a.y*b,0,0,1,1,1,0,c.x,c.y,0,1];c=glPolyShader;glContext.useProgram(c);glContext.uniformMatrix4fv(glUniformLocation(c,"m"),!1,a);c=glShader;glContext.useProgram(c);glContext.uniformMatrix4fv(glUniformLocation(c,"m"),!1,a);glContext.activeTexture(glContext.TEXTURE0);textureInfos[0]&&(glActiveTexture=textureInfos[0].glTexture,glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture));glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer);glAdditive=glBatchAdditive=!1;glSetInstancedMode(!0)}}function glClearCanvas(){if(glContext){var a=canvasClearColor;glContext.clearColor(a.r*a.a,a.g*a.a,a.b*a.a,a.a);glContext.clear(glContext.COLOR_BUFFER_BIT)}}function glSetTexture(a){glContext&&(a!==glActiveTexture&&(glFlush(),glActiveTexture=a,glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture)),glMipmapsStale.size&&glUpdateMipmaps(a))}function glUpdateMipmaps(a){glMipmapsStale.has(a)&&(glMipmapsStale.delete(a),glContext.generateMipmap(glContext.TEXTURE_2D))}const glWrapRepeat=Object.freeze([10497,10497]),glWrapClamp=Object.freeze([33071,33071]);function glWrapModes(a){return isArray(a)?a:a?glWrapRepeat:glWrapClamp}function glSetTextureWrap(a,b=!0){if(glContext&&a){var c=a===glActiveTexture;c?glFlush():glContext.bindTexture(glContext.TEXTURE_2D,a);var[d,e]=glWrapModes(b);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_S,d);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_T,e);!c&&glActiveTexture&&glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture)}}function glCompileShader(a,b){if(glContext){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,glContext.COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}}function glCreateProgram(a,b){if(glContext){var c=glContext.createProgram();a=glCompileShader(a,glContext.VERTEX_SHADER);b=glCompileShader(b,glContext.FRAGMENT_SHADER);glContext.attachShader(c,a);glContext.attachShader(c,b);glContext.linkProgram(c);if(!glContext.getProgramParameter(c,glContext.LINK_STATUS)){b=glContext.getProgramInfoLog(c)+"\n"+glContext.getShaderInfoLog(a)+glContext.getShaderInfoLog(b);if(debug)throw b;console.error("LittleJS: a shader failed to build\n"+b);glFailedPrograms.add(c)}return c}}function glUniformLocation(a,b){let c=glUniformLocations.get(a);c||glUniformLocations.set(a,c={});let d;return(d=c)[b]??(d[b]=glContext.getUniformLocation(a,b))}function glShaderProgram(a){a.program||glShaderTrack(a);a=a.program||(a.program=glCreateProgram(gl_VERTEX_SOURCE,"#version 300 es\nprecision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;uniform bool premultipliedTexture;in vec2 v,l;in vec4 d,e;out vec4 c;void mainImage(out vec4,vec2);void main(){vec4 t;mainImage(t,v);"+gl_FRAGMENT_TINT_SOURCE+"}\n#define localUV l\n"+a.fragmentCode+"\n"));return glFailedPrograms.has(a)?glShader:a}function glShaderTrack(a){glShaderObjects.includes(a)||glShaderObjects.push(a)}function glShaderDispose(a){glContext&&!headlessMode&&glBatchShader===a&&glFlush();const b=glShaderObjects.indexOf(a);0>b||glShaderObjects.splice(b,1);if(glContext&&!headlessMode)for(const c of[a.program,a.program3D])c&&glContext.deleteProgram(c);a.program=a.program3D=void 0}function glCreateTexture(a,b=!1,c=tilesPixelated){if(glContext){var d=glContext.createTexture(),e=!1;a?.width?(glSetTextureData(d,a,c),glContext.bindTexture(glContext.TEXTURE_2D,d),e=!c,!e||isPowerOfTwo(a.width)&&isPowerOfTwo(a.height)||glMipmapsUntilTarget.add(d)):(a=new Uint8Array([255,255,255,255]),glContext.bindTexture(glContext.TEXTURE_2D,d),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,1,1,0,glContext.RGBA,glContext.UNSIGNED_BYTE,a));c=c?glContext.NEAREST:glContext.LINEAR;a=e?glContext.LINEAR_MIPMAP_LINEAR:c;glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MAG_FILTER,c);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MIN_FILTER,a);var[f,g]=glWrapModes(b);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_S,f);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_T,g);e&&(glContext.generateMipmap(glContext.TEXTURE_2D),glMipmappedTextures.add(d));glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture);return d}}function glDeleteTexture(a){glContext&&a&&(a===glActiveTexture&&(glFlush(),glActiveTexture=void 0),glMipmapsStale.delete(a),glPremultipliedTextures.delete(a),glContext.deleteTexture(a))}function glSetTextureData(a,b,c=tilesPixelated){if(glContext){a===glActiveTexture&&glFlush();glContext.bindTexture(glContext.TEXTURE_2D,a);if("undefined"!=typeof ImageBitmap&&b instanceof ImageBitmap){const d=createCanvasContext(b.width,b.height);d.drawImage(b,0,0);b=d.canvas}c=!c;glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL,c);glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,b);glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);c?glPremultipliedTextures.add(a):glPremultipliedTextures.delete(a);glMipmappedTextures.has(a)&&glContext.generateMipmap(glContext.TEXTURE_2D);glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture)}}function glRegisterTextureInfo(a){headlessMode||(glTextureInfos.add(a),glContext&&(a.glTexture?glSetTextureData(a.glTexture,a.image,a.pixelated):a.glTexture=glCreateTexture(a.image,a.wrap,a.pixelated)))}function glUnregisterTextureInfo(a){if(!headlessMode){glTextureInfos.delete(a);var b=a.glTexture;a.glTexture=void 0;glDeleteTexture(b)}}function glFlush(){if(glEnable&&glContext&&glBatchCount){const b=!glPolyMode&&glPremultipliedTextures.has(glActiveTexture);var a=glBatchAdditive?glContext.ONE:glContext.ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(b?glContext.ONE:glContext.SRC_ALPHA,a,glContext.ONE,a);glContext.enable(glContext.BLEND);if(!glPolyMode&&(glBatchShader||glProgramCustom)&&(a=glBatchShader?glShaderProgram(glBatchShader):glShader,glContext.useProgram(a),glProgramCustom=!!glBatchShader,glBatchShader)){glContext.uniformMatrix4fv(glUniformLocation(a,"m"),!1,glTransform);glContext.uniform1f(glUniformLocation(a,"iTime"),time);const c=glRenderTarget?mainCanvasSize.x:glCanvas.width,d=glRenderTarget?mainCanvasSize.y:glCanvas.height;glContext.uniform3f(glUniformLocation(a,"iResolution"),c,d,1);glContext.uniform1i(glUniformLocation(a,"premultipliedTexture"),+b);a===glShader&&(glShaderPremultiplied=b)}glPolyMode||glBatchShader||glShaderPremultiplied===b||(glContext.uniform1i(glUniformLocation(glShader,"premultipliedTexture"),+b),glShaderPremultiplied=b);glContext.bufferSubData(glContext.ARRAY_BUFFER,0,glPositionData,0,glBatchCount*(glPolyMode?gl_INDICES_PER_POLY_VERTEX:gl_INDICES_PER_INSTANCE));glPolyMode?glContext.drawArrays(glContext.TRIANGLE_STRIP,0,glBatchCount):glContext.drawArraysInstanced(glContext.TRIANGLE_STRIP,0,4,glBatchCount);++drawCount;primitiveCount+=glBatchCount;glBatchCount=0}glBatchAdditive=glAdditive;glBatchShader=glCustomShader}function glCopyToContext(a){glEnable&&glContext&&(glFlush(),a.drawImage(glCanvas,0,0))}function glSetAntialias(a=!0){glAntialias=a}function glDraw(a,b,c,d,e=0,f=0,g=0,h=1,k=1,l=-1,m=0){(glBatchCount>=gl_MAX_INSTANCES||glBatchAdditive!==glAdditive||glBatchShader!==glCustomShader)&&glFlush();glSetInstancedMode();let n=glBatchCount++*gl_INDICES_PER_INSTANCE;glPositionData[n++]=a;glPositionData[n++]=b;glPositionData[n++]=c;glPositionData[n++]=d;glPositionData[n++]=f;glPositionData[n++]=g;glPositionData[n++]=h;glPositionData[n++]=k;glColorData[n++]=l&glColorMask;glColorData[n++]=m&glColorMask|glColorAdditive;glPositionData[n++]=e}function glDrawUntextured(a,b,c,d,e,f){glDraw(a,b,c,d,e,0,0,0,0,0,f)}const glPointsOut=[],glPointsPool=[];function glDrawPointsTransform(a,b,c,d,e,f,g,h=!0){const k=glPointsOut,l=glPointsPool,m=a.length;k.length=m;const n=sin(-g);g=cos(-g);for(let q=0;qa.length)){var d=a.length+2;(glBatchCount+d>=gl_MAX_POLY_VERTEXES||glBatchAdditive!==glAdditive)&&glFlush();if(!(d>=gl_MAX_POLY_VERTEXES)){glSetPolyMode();var e=glBatchCount*gl_INDICES_PER_POLY_VERTEX;for(let g=d;g--;){var f=clamp(g-1,0,d-3);const h=a[f];f=c?c[f]:b;glPositionData[e++]=h.x;glPositionData[e++]=h.y;glColorData[e++]=f&glColorMask|glColorAdditive}glBatchCount+=d}}}function glSetRenderTarget(a,b=!1){glFlush();const c=glRenderTarget;if(a)glMipmapsUntilTarget.has(a)&&(glMipmapsUntilTarget.delete(a),glMipmappedTextures.delete(a),glContext.bindTexture(glContext.TEXTURE_2D,a),glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MIN_FILTER,glContext.LINEAR),glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture)),glPremultipliedTextures.add(a),glRenderTarget||(glRenderTargetSaved=[glTransform,glAdditive]),glRenderTarget=a,glContext.bindFramebuffer(glContext.FRAMEBUFFER,glFramebuffer),glContext.framebufferTexture2D(glContext.FRAMEBUFFER,glContext.COLOR_ATTACHMENT0,glContext.TEXTURE_2D,a,0),glPreRender(b);else{glRenderTarget=void 0;if(glRenderTargetBase){const[d,e]=glRenderTargetBase;glContext.bindFramebuffer(glContext.FRAMEBUFFER,glFramebuffer);glContext.framebufferTexture2D(glContext.FRAMEBUFFER,glContext.COLOR_ATTACHMENT0,glContext.TEXTURE_2D,d,0);glContext.viewport(0,0,e.x,e.y)}else glContext.bindFramebuffer(glContext.FRAMEBUFFER,null),glContext.viewport(0,0,glCanvas.width,glCanvas.height);if(glRenderTargetSaved){[glTransform,glAdditive]=glRenderTargetSaved;glRenderTargetSaved=void 0;for(const d of[glPolyShader,glShader])glContext.useProgram(d),glContext.uniformMatrix4fv(glUniformLocation(d,"m"),!1,glTransform);glBatchAdditive=glAdditive;glSetInstancedMode(!0)}}c&&c!==a&&glMipmappedTextures.has(c)&&glMipmapsStale.add(c)}function glClearRect(a,b,c,d){glEnable&&(glFlush(),glContext.enable(glContext.SCISSOR_TEST),glContext.scissor(a,b,c,d),glContext.clearColor(0,0,0,0),glContext.clear(glContext.COLOR_BUFFER_BIT),glContext.disable(glContext.SCISSOR_TEST))}const glOutlineStrip=[],glOutlinePool=[];function glMakeOutline(a,b,c=!0){if(2>a.length)return[];b/=2;const d=glOutlineStrip,e=glOutlinePool;d.length=0;const f=a.length;for(let n=0;nm&&1e-6>h)continue;l=1e-6h?(k=l,g=m):(k/=h,g/=h,l=l*k+m*g,1e-6a.length)return[];const b=(p,t,u)=>(t.x-p.x)*(u.y-p.y)-(t.y-p.y)*(u.x-p.x);0>(p=>{let t=0;for(let u=p.length;u--;)t+=p[u].cross(p[(u+1)%p.length]);return t})(a)&&(a=a.slice().reverse());var c=a.length,d=!0,e=0,f=0;for(var g=0;d&&gh?-1:0)&&h!==f&&(f&&++e,f=h)}if(d&&2>=e){e=[a[0]];for(let p=1,t=c-1;p<=t;++p,--t)e.push(a[p]),p===t||e.push(a[t]);return e}e=(p,t,u,v)=>{const y=b(t,u,p);u=b(u,v,p);p=b(v,t,p);return!((-1e-9>y?1:0)+(-1e-9>u?1:0)+(-1e-9>p?1:0)&&(1e-9b(t,u,v))continue;let y=!1;for(let x=0;xh)break;c.push([f[(h+f.length-1)%f.length],f[h],f[(h+1)%f.length]]);f.splice(h,1)}}3===f.length&&c.push([f[0],f[1],f[2]]);if(!c.length)return[];e=[];let[n,r,q]=c[0];e.push(a[n],a[r],a[q]);for(f=1;f{0<=q?(l=b.fillStyle=b.createLinearGradient(l,m,n,r),l.addColorStop(0,`hsl(${360*[.95,.56,.13][q%3]} 99%${75}%)`),l.addColorStop(1,`hsl(${360*[.95,.56,.13][q%3]} 99%${50}%)`)):b.fillStyle="#000";-1<=q?(b.fill(),p&&b.stroke()):b.stroke()};f=(l,m,n,r=0,q=2*PI,p,t)=>{b.beginPath();b.arc(l,m,n,k*r,k*q);h(l,m-n,l,m+n,p,t)};g=(l,m,n,r,q)=>{b.beginPath();b.rect(l,m,n,r*k);h(l,m+r,l+n,m,q)};e=(l,m,n,r)=>{b.beginPath();for(const q of l)b.lineTo(q.x,q.y);b.closePath();h(0,n,0,n+r,m)};a=oscillate(1,1,a);const k=percent(a,.1,.5);a=min(6,min(c,d)/99);b.translate(c/2,d/2);b.scale(a,a);b.translate(-40,-35);1>k&&b.setLineDash([99*k,99]);b.lineJoin=b.lineCap="round";b.lineWidth=.1+1.9*k;b.font="900 15.5px arial";b.lineWidth=.1+3.9*k;b.textAlign="center";b.textBaseline="top";g(11,55,59,8*k,-1);b.beginPath();c=0;for(d=0;8>d;++d)c+=b.measureText("LittleJS"[d]).width;for(d=2;d--;)for(let l=0,m=40-c/2;8>l;++l){a=b.measureText("LittleJS"[l]).width;const n=m+a/2;h(n,54,n+2,67,5c.unlocked&&c.isLocal()&&b.push(c));medalsSaveName=a;medalsLoad();b.length&&(b.forEach(c=>c.unlocked=!0),medalsSave());"undefined"!=typeof wavedash&&wavedash?.sendAchievements();medalsRenderAdded||engineAddPlugin(void 0,medalsRender);medalsRenderAdded=!0}function medalsLoad(){if(!debugMedals&&medalsSaveName){var a=readSaveData(medalsSaveName);medalsForEach(b=>{b.isLocal()&&(b.unlocked=!!a[b.id]?.unlocked)});medalsSave()}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayTimeLast=0,medalsDisplayQueue.shift();else{const c=min(medalDisplaySlideTime,medalDisplayTime/2),d=medalDisplayTime-c;a.render(bd?(b-d)/c:0)}else medalsDisplayTimeLast=timeReal}}function medalsForEach(a){Object.values(medals).forEach(b=>a(b))}function medalsReset(){medalsForEach(a=>a.isLocal()&&(a.unlocked=!1));if(medalsSaveName&&!debugMedals){const a=readSaveData(medalsSaveName);for(const b in a)medals[b]&&!medals[b].isLocal()||!a[b]||"object"!==typeof a[b]||(a[b].unlocked=!1);writeSaveData(medalsSaveName,a)}medalsSave()}function medalsSave(){if(!debugMedals&&medalsSaveName){var a=readSaveData(medalsSaveName),b={...a};medalsForEach(c=>{if(c.isLocal()){var d={name:c.name,description:c.description,icon:c.icon,unlocked:c.unlocked||!!a[c.id]?.unlocked};c.image&&(d.src=c.image.src);b[c.id]=d}else a[c.id]&&(b[c.id]=a[c.id])});writeSaveData(medalsSaveName,b)}}class Medal{constructor(a,b,c="",d="🏆",e){this.id=a;this.name=b;this.description=c;this.icon=d;this.unlocked=!1;this.image=void 0;e&&((this.image=new Image).src=e);medals[a]=this;medalsSaveName&&!debugMedals&&this.isLocal()&&(this.unlocked=!!readSaveData(medalsSaveName)[a]?.unlocked)}unlock(){medalsPreventUnlock||this.unlocked||(this.unlocked=!0,medalsSave(),medalsDisplayQueue.push(this));return Promise.resolve(this.unlocked)}isLocal(){return!0}render(a=0){const b=mainContext;var c=min(medalDisplaySize.x,mainCanvasSize.x);const d=medalDisplaySize.y;var e=mainCanvasSize.x-c;a*=-d;var f=hsl(0,0,.9);b.save();b.beginPath();b.fillStyle=f.toString();b.strokeStyle=BLACK.toString();f=b.lineWidth=3;b.rect(e+f/2,a+f/2,c-f,d-f);b.fill();b.stroke();b.clip();f=vec2(.1,.05).scale(d);const g=d-2*f.x;this.renderIcon(vec2(e+f.x+g/2,a+d/2),g);const h=.5*d,k=.3*d;e=vec2(e+g+2*f.x,a+2*f.y+h/2);c=c-g-3*f.x;drawTextScreen(this.name,e,h,BLACK,0,void 0,"left",void 0,void 0,c);e.y=a+d-2*f.y-k/2;drawTextScreen(this.description,e,k,BLACK,0,void 0,"left",void 0,void 0,c);b.restore()}renderIcon(a,b){const c=this.image;c&&c.complete&&c.naturalWidth?mainContext.drawImage(c,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,BLACK)}}function setMedalDisplayTime(a){medalDisplayTime=a}function setMedalDisplaySlideTime(a){medalDisplaySlideTime=a}function setMedalDisplaySize(a){medalDisplaySize=a.copy()}function setMedalsPreventUnlock(a){medalsPreventUnlock=a}let newgrounds;const newgroundsUnlocksToResend=new Set,newgroundsUnlocksRefused=new Set,newgroundsSecureComponents=["Medal.unlock","ScoreBoard.postScore"],newgroundsSessionErrors=[104,110,111],newgroundsTimeoutMS=15e3;function newgroundsSessionLost(a){return newgroundsSessionErrors.includes(a?.result?.data?.error?.code??a?.error?.code)}function newgroundsNotifyPage(a,b){globalThis.top?.postMessage(JSON.stringify({ngioComponent:a,id:b}),"*")}class NewgroundsMedal extends Medal{constructor(a,b,c,d,e){super(a,b,c,d,e);this.value=this.difficulty=void 0}isLocal(){return!newgrounds?.session_id}unlock(){if(medalsPreventUnlock||this.unlocked||this.isLocal())return super.unlock();if(newgroundsUnlocksRefused.has(this))return Promise.resolve(!1);const a=newgrounds.pendingUnlocks;if(a.has(this))return a.get(this);const b=newgrounds.unlockMedal(this.id).then(c=>{newgroundsSessionLost(c)&&newgrounds.dropSession();const d=c?.result?.data?.medal;if(!d?.unlocked||medalsPreventUnlock){if(this.isLocal())return this.unlocked;!c||d?.unlocked?newgroundsUnlocksToResend.add(this):(a.delete(this),newgroundsUnlocksRefused.add(this));return!1}(c=newgrounds.medals.find(e=>e.id==this.id))&&Object.assign(c,d);d.icon&&d.icon!=this.image?.src&&((this.image=new Image).src=d.icon);a.delete(this);newgroundsNotifyPage("Medal.unlock",this.id);return super.unlock()});a.set(this,b);return b}}class NewgroundsPlugin{constructor(a,b){newgrounds=this;this.app_id=a;this.cipher=b;this.cryptoKey=void 0;this.host=(a="undefined"!=typeof location)?location.hostname:"";this.medals=[];this.scoreboards=[];this.loadFailures=new Map;this.user=null;this.pendingUnlocks=new Map;(this.session_id=a?new URL(location.href).searchParams.get("ngio_session_id"):null)&&medalsForEach(c=>c instanceof NewgroundsMedal&&(c.unlocked=!1));this.ready=this.init()}async init(){this.call("App.logView",{host:this.host});var a;if(this.session_id){const c=(a=(await this.call("App.checkSession"))?.result?.data?.session)&&!a.expired&&a.user;(a=c&&(await this.call("Medal.getList"))?.result?.data?.medals)&&this.session_id?this.user=c:(this.dropSession(),a=void 0)}this.medals=(a=a||(await this.call("Medal.getList"))?.result?.data?.medals)||[];for(const c of this.medals)a=medals[c.id],a instanceof NewgroundsMedal&&(a.image=new Image,a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=a.unlocked||!!c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description+=` (${a.value})`),this.session_id&&a.unlocked&&(c.unlocked=!0,this.pendingUnlocks.delete(a),newgroundsUnlocksToResend.delete(a),newgroundsUnlocksRefused.delete(a)));this.scoreboards=(await this.call("ScoreBoard.getBoards"))?.result?.data?.scoreboards||[];if(!this.session_id)return this;const b=setInterval(async()=>{if(!this.session_id)return clearInterval(b);const c=await this.call("App.checkSession"),d=c?.result?.data?.session;if(newgroundsSessionLost(c)||d&&(d.expired||!d.user))return this.dropSession();this.resendUnlocks()},6e4);return this}dropSession(){if(this.session_id){var a=Object.values(medals).filter(b=>b.unlocked);this.user=this.session_id=null;medalsLoad();a.forEach(b=>b.unlocked=!0);medalsSave();a=[...this.pendingUnlocks.keys()];this.pendingUnlocks.clear();newgroundsUnlocksToResend.clear();newgroundsUnlocksRefused.clear();for(const b of a)b.unlock()}}resendUnlocks(){if(!medalsPreventUnlock){for(const a of newgroundsUnlocksToResend)this.pendingUnlocks.delete(a),a.unlock();newgroundsUnlocksToResend.clear()}}unlockMedal(a){return this.call("Medal.unlock",{id:a})}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b}).then(c=>{c?.result?.data?.success&&newgroundsNotifyPage("ScoreBoard.postScore",a);newgroundsSessionLost(c)&&this.dropSession();return c})}getScores(a,b,c=!1,d=0,e=10,f){return this.call("ScoreBoard.getScores",{id:a,user:b,social:c,skip:d,limit:e,period:f},b||c?this.session_id:null)}async cloudSave(a,b){if(!this.session_id)return!1;let c;try{c=JSON.stringify(b)}catch(d){}if(void 0===c)return console.warn("Newgrounds cloudSave: slot "+a+" was given a value JSON can not hold"),!1;a=await this.call("CloudSave.setData",{id:a,data:c});newgroundsSessionLost(a)&&this.dropSession();return!!a?.result?.data?.success}async cloudLoad(a){const{value:b,failure:c}=await this.loadSlot(a);c?this.loadFailures.set(+a,c):this.loadFailures.delete(+a);return b}loadFailure(a){return this.loadFailures.get(+a)}async loadSlot(a){const b=e=>{e&&console.warn("Newgrounds could not load slot "+a+e);return{value:void 0,failure:"failed"}};if(!this.session_id)return b("");var c=await this.call("CloudSave.loadSlot",{id:a});newgroundsSessionLost(c)&&this.dropSession();c=c?.result?.data?.slot;if(!c)return b(".");c=c.url;if(!c)return{value:null,failure:void 0};let d;try{const e=globalThis.AbortSignal?.timeout?.(newgroundsTimeoutMS),f=await fetch(c,{cache:"no-store",signal:e});if(!f.ok)return b(": "+f.status);d=await f.text()}catch(e){return b(": "+e)}if(!d)return b(", it came back empty");try{return{value:JSON.parse(d),failure:void 0}}catch(e){return console.warn("Newgrounds cloudLoad: slot "+a+" holds a file that is not a save"),{value:void 0,failure:"notSave"}}}logEvent(a){return this.call("Event.logEvent",{event_name:a,host:this.host})}async encrypt(a){if(!this.cryptoKey){var b=Uint8Array.from(atob(this.cipher),d=>d.charCodeAt(0));this.cryptoKey=await crypto.subtle.importKey("raw",b,"AES-CBC",!1,["encrypt"])}b=crypto.getRandomValues(new Uint8Array(16));const c=new Uint8Array(await crypto.subtle.encrypt({name:"AES-CBC",iv:b},this.cryptoKey,(new TextEncoder).encode(a)));a=new Uint8Array(b.length+c.length);a.set(b);a.set(c,b.length);b="";for(const d of a)b+=String.fromCharCode(d);return btoa(b)}async call(a,b,c=this.session_id){try{b={component:a,parameters:b};if(this.cipher&&newgroundsSecureComponents.includes(a)){const h=await this.encrypt(JSON.stringify(b)).catch(k=>debugMedals&&!1);if(!h)return{success:!1,error:{code:201,message:"Invalid Encryption: the cipher is not a Base64 AES-128 key"}};b={secure:h}}const d={app_id:this.app_id,session_id:c,execute:b},e=new FormData;e.append("request",JSON.stringify(d));const f=globalThis.AbortSignal?.timeout?.(newgroundsTimeoutMS),g=await(await fetch("https://www.newgrounds.io/gateway_v3.php",{method:"POST",body:e,signal:f})).text();return g?JSON.parse(g):void 0}catch(d){}}}let wavedash;const wavedashRetryMS=2e3,wavedashRetries=30,wavedashTimeoutMS=15e3,wavedashDisplayTypes={number:0,seconds:1,milliseconds:2,ticks:3},wavedashSDK=()=>globalThis.Wavedash,wavedashSavePath=a=>"saves/slot"+a+".json";function wavedashWait(a,b,c=!1){let d;const e={},f=new Promise(g=>d=setTimeout(()=>g(e),wavedashTimeoutMS));return Promise.race([Promise.resolve(b),f]).then(g=>g!==e?g:c?void 0:void console.warn("Wavedash "+a+" took over "+wavedashTimeoutMS/1e3+" seconds"),g=>{console.warn("Wavedash "+a+" failed: "+g)}).finally(()=>clearTimeout(d))}function wavedashSaveText(a,b){let c;try{c=JSON.stringify(b)}catch(d){}void 0===c&&console.warn("Wavedash cloudSave: slot "+a+" was given a value JSON can not hold");return c}class WavedashMedal extends Medal{constructor(a,b,c,d,e,f){super(a,c,d,e,f);this.achievement=b}unlock(){if(medalsPreventUnlock||this.unlocked||!wavedashSDK()||debugMedals)return super.unlock();this.unlocked=!0;medalsSave();wavedash?.sendAchievements();return Promise.resolve(!0)}}class WavedashPlugin{constructor(a={}){wavedash=this;this.leaderboards=Object.create(null);this.leaderboardSettings=a;this.achievementsSent=new Set;this.achievementTries=Object.create(null);this.stats=this.achievementRetry=void 0;this.slotQueues=new Map;this.slotCalls=new Map;this.loadFailures=new Map;wavedashWait("init",this.call("init"));for(const b in a)this.leaderboard(b);this.sendAchievements()}isActive(){return!!wavedashSDK()}call(a,...b){const c=wavedashSDK();if(c)try{return c[a](...b)}catch(d){console.warn("Wavedash "+a+" failed: "+d)}}leaderboard(a){if(this.leaderboards[a])return this.leaderboards[a];var b=Object.prototype.hasOwnProperty.call(this.leaderboardSettings,a)?this.leaderboardSettings[a]:void 0;const{lowerWins:c=!1,display:d="number"}=b||{};b=wavedashDisplayTypes.hasOwnProperty(d);b=this.call("getOrCreateLeaderboard",a,c?0:1,b?wavedashDisplayTypes[d]:0);const e=wavedashWait("leaderboard "+a,b).then(f=>f?.success?f.data?.id:void 0);e.then(f=>void 0===f&&this.leaderboards[a]===e&&delete this.leaderboards[a]);return this.leaderboards[a]=e}async postScore(a,b){if(!this.isActive())return!1;a=await this.leaderboard(a);return void 0===a?!1:!!(await wavedashWait("postScore",this.call("uploadLeaderboardScore",a,round(b),!0)))?.success}async getScores(a,b=0,c=10,d=!1){if(this.isActive()&&(a=await this.leaderboard(a),void 0!==a))return b=await wavedashWait("getScores",this.call("listLeaderboardEntries",a,b|0,c|0,!!d)),b?.success?b.data:void 0}async cloudSave(a,b){if(!this.isActive())return!1;const c=wavedashSaveText(a,b);return void 0===c?!1:this.slotQueue(a,!1,async d=>{const e=wavedashSavePath(a),f=await wavedashWait("cloudSave",d(this.call("writeLocalFile",e,(new TextEncoder).encode(c))));if(!0!==f&&!f?.success)return f&&console.warn("Wavedash refused writing slot "+a+": "+(f.message??f.error??"no reason given")),!1;(d=await wavedashWait("cloudSave",d(this.call("uploadRemoteFile",e))))&&!d.success&&console.warn("Wavedash refused cloudSave of slot "+a+": "+(d.message??d.error??"no reason given"));return!!d?.success})}async cloudLoad(a){var b={value:void 0,failure:"failed"};const{value:c,failure:d}=this.isActive()?await this.slotQueue(a,b,e=>this.loadSlot(a,e)):b;b=wavedashSavePath(a);d?this.loadFailures.set(b,d):this.loadFailures.delete(b);return c}loadFailure(a){return this.loadFailures.get(wavedashSavePath(a))}async loadSlot(a,b){const c=wavedashSavePath(a),d=f=>{console.warn("Wavedash "+f);return{value:void 0,failure:"failed"}},e=await wavedashWait("cloudLoad",b(this.call("downloadRemoteFile",c)));if(!0!==e&&!e?.success)return b=await wavedashWait("cloudLoad",b(this.call("remoteFileExists",c))),!1===b||b?.success&&!1===b.data?{value:null,failure:void 0}:d("could not load slot "+a);b=await wavedashWait("cloudLoad",b(this.call("readLocalFile",c)));b=(b=b instanceof Uint8Array||b instanceof ArrayBuffer||"string"==typeof b?b:b?.data)?"string"==typeof b?b:(new TextDecoder).decode(b):"";if(!b)return d("could not read slot "+a);try{return{value:JSON.parse(b),failure:void 0}}catch(f){return console.warn("Wavedash cloudLoad: slot "+a+" holds a file that is not a save"),{value:void 0,failure:"notSave"}}}slotQueue(a,b,c){const d=wavedashSavePath(a),e=this.slotCalls.get(d)||new Set;this.slotCalls.set(d,e);const f=k=>{if("function"==typeof k?.then){e.add(k);const l=()=>{e.delete(k);e.size||this.slotQueues.has(d)||this.slotCalls.get(d)!==e||this.slotCalls.delete(d)};k.then(l,l)}return k};var g=async()=>e.size&&!await wavedashWait("slot "+a,Promise.allSettled([...e]).then(()=>!0),!0)?(console.warn("Wavedash slot "+a+" is still busy with a call that timed out, not used"),b):c(f);g=(this.slotQueues.get(d)||Promise.resolve()).then(g,g);const h=g.catch(()=>{});this.slotQueues.set(d,h);h.then(()=>{this.slotQueues.get(d)===h&&(this.slotQueues.delete(d),e.size||this.slotCalls.get(d)!==e||this.slotCalls.delete(d))});return g}async setStat(a,b,c=!1){return this.isActive()&&await this.statsLoaded()?!0===this.call("setStat",a,b,!!c):!1}async getStat(a){if(!this.isActive()||!await this.statsLoaded())return 0;a=this.call("getStat",a);return isNumber(a)?a:0}statsLoaded(){return this.stats||(this.stats=wavedashWait("requestStats",this.call("requestStats")).then(a=>{(a=!!a?.success)||(this.stats=void 0);return a}))}async setPresence(a,b){if(!this.isActive())return!1;const c={};void 0===a||(c.status=String(a));void 0===b||(c.details=String(b));return!!(await wavedashWait("setPresence",this.call("updateUserPresence",c)))?.success}sendAchievements(){if(this.isActive()&&!debugMedals){var a=!1;medalsForEach(b=>{if((b=b instanceof WavedashMedal&&b.unlocked&&b.achievement)&&!this.achievementsSent.has(b)){var c=this.call("setAchievement",b,!0);!0===c||!0===c?.success?this.achievementsSent.add(b):(this.achievementTries[b]=(this.achievementTries[b]||0)+1)this.sendAchievements(),wavedashRetryMS):void 0}}}let postProcess;class PostProcessPlugin{constructor(a,b=!1,c=!1){function d(){if(!headlessMode&&glEnable){c&&(postProcess.feedbackTexture=glCreateTexture(),glContext.bindTexture(glContext.TEXTURE_2D,postProcess.feedbackTexture),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,1,1,0,glContext.RGBA,glContext.UNSIGNED_BYTE,new Uint8Array([0,0,0,255])),glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture));postProcess.texture=glCreateTexture();postProcess.shader=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;void main(){gl_Position=vec4(p+p-1.,1,1);}",postProcessFragmentSource(postProcess.shaderCode,postProcess.values));postProcess.valueNames=postProcessValueKey(postProcess.values);postProcess.vao=glContext.createVertexArray();glContext.bindVertexArray(postProcess.vao);glContext.bindBuffer(glContext.ARRAY_BUFFER,glGeometryBuffer);var e=glContext.getAttribLocation(postProcess.shader,"p");glContext.enableVertexAttribArray(e);glContext.vertexAttribPointer(e,2,glContext.FLOAT,!1,8,0);glContext.bindVertexArray(glPolyMode?glPolyVAO:glInstancedVAO);glContext.bindBuffer(glContext.ARRAY_BUFFER,glArrayBuffer)}}postProcess=this;this.shaderCode=postProcessShaderCode(a);this.enabled=!0;this.values={};this.valueNames="";this.vao=this.feedbackTexture=this.texture=this.shader=void 0;headlessMode||glEnable||console.warn("PostProcessPlugin: WebGL not enabled!");engineAddPlugin(void 0,function(){if(!headlessMode&&glEnable&&postProcess.enabled){glFlush();postProcess.shader&&postProcessValueKey(postProcess.values)!==postProcess.valueNames&&postProcess.setShaderCode(postProcess.shaderCode);if(!postProcess.shader){if(glContext.isContextLost())return;d()}if(!glFailedPrograms.has(postProcess.shader)){glContext.bindFramebuffer(glContext.FRAMEBUFFER,null);glContext.useProgram(postProcess.shader);glContext.bindVertexArray(postProcess.vao);glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL,!0);glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);glContext.disable(glContext.BLEND);glContext.activeTexture(glContext.TEXTURE0);glContext.bindTexture(glContext.TEXTURE_2D,postProcess.texture);b?(workCanvas.width!==mainCanvas.width||workCanvas.height!==mainCanvas.height?(workCanvas.width=mainCanvas.width,workCanvas.height=mainCanvas.height):workContext.clearRect(0,0,workCanvas.width,workCanvas.height),glCopyToContext(workContext),workContext.drawImage(mainCanvas,0,0),mainContext.save(),mainContext.setTransform(1,0,0,1,0,0),mainContext.clearRect(0,0,mainCanvas.width,mainCanvas.height),mainContext.restore(),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,workCanvas)):glContext.copyTexImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,0,0,glCanvas.width,glCanvas.height,0);c&&(glContext.activeTexture(glContext.TEXTURE1),glContext.bindTexture(glContext.TEXTURE_2D,postProcess.feedbackTexture));var e="undefined"!=typeof render3D&&render3D?.depthTexture?render3D:void 0;glContext.activeTexture(glContext.TEXTURE2);glContext.bindTexture(glContext.TEXTURE_2D,e?.cameraDepthTexture||null);glContext.activeTexture(glContext.TEXTURE0);e=e?.camera;glContext.uniform3f(glUniformLocation(postProcess.shader,"iDepthRange"),e?.near||0,e&&Infinity!=e.far?e.far:0,e?.orthographic?1:0);glContext.uniform1i(glUniformLocation(postProcess.shader,"iChannel0"),0);glContext.uniform1i(glUniformLocation(postProcess.shader,"iChannel1"),1);glContext.uniform1i(glUniformLocation(postProcess.shader,"iChannel2"),2);glContext.uniform1f(glUniformLocation(postProcess.shader,"iTime"),time);glContext.uniform3f(glUniformLocation(postProcess.shader,"iResolution"),mainCanvas.width,mainCanvas.height,1);for(const f in postProcess.values){e=postProcess.values[f];const g=glUniformLocation(postProcess.shader,f);isArray(e)?[,,glContext.uniform2fv,glContext.uniform3fv,glContext.uniform4fv][e.length]?.call(glContext,g,e):glContext.uniform1f(g,e)}glContext.drawArrays(glContext.TRIANGLE_STRIP,0,4);c&&(glContext.activeTexture(glContext.TEXTURE1),glContext.copyTexImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,0,0,glCanvas.width,glCanvas.height,0),glContext.activeTexture(glContext.TEXTURE0));glContext.activeTexture(glContext.TEXTURE2);glContext.bindTexture(glContext.TEXTURE_2D,null);glContext.activeTexture(glContext.TEXTURE0);glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL,!1);glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);glActiveTexture&&glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture);glSetInstancedMode(!0)}}},function(){postProcess.shader=void 0;postProcess.texture=void 0;postProcess.feedbackTexture=void 0},function(){d()})}setShaderCode(a){this.shaderCode=postProcessShaderCode(a);this.shader&&!headlessMode&&glContext&&(glContext.deleteProgram(this.shader),glContext.deleteTexture(this.texture),this.feedbackTexture&&glContext.deleteTexture(this.feedbackTexture),glContext.deleteVertexArray(this.vao),this.shader=this.texture=this.feedbackTexture=this.vao=void 0)}}const postProcessValueKey=a=>Object.entries(a).map(([b,c])=>b+":"+(isArray(c)?c.length:1)).join();function postProcessShaderCode(a){return a?a.includes("mainImage")?a:postProcessEffects(a):postProcessEffects()}function postProcessFragmentSource(a,b={}){let c="";for(const e in b){var d=b[e];d=isArray(d)?d.length:1;c+=`uniform ${10.?(d*(f-n)+f+n)/2.:f>0.?2.*n*f/(f+n-d*(f-n)):2.*n/max(1.-d,1e-7);}\n#define LJS_HAS_DEPTH (iDepthRange != vec3(0))\nvoid mainImage(out vec4,vec2);void main(){mainImage(c,gl_FragCoord.xy);c.a=1.;}\n"+a+"\n"}function postProcessBloomShader(a=.6,b=1,c=6){return postProcessEffects(postProcessGlow(a,b,c))}function postProcessBloom(a=.6,b=1,c=6,d=!1){return new PostProcessPlugin(postProcessBloomShader(a,b,c),d)}const postProcessNumber=a=>"string"===typeof a?a:a&&.01>abs(a)?String(a):a.toFixed(4),postProcessGLSLWords=new Set("c uv p sceneDepth mainImage main attribute const uniform varying layout centroid flat smooth noperspective patch sample break continue do for while switch case default if else subroutine in out inout float double int void bool true false invariant precise discard return lowp mediump highp precision struct common partition active asm class union enum typedef template this resource goto inline noinline public static extern external interface long short half fixed unsigned superp input output filter sizeof cast namespace using coherent volatile restrict readonly writeonly atomic_uint uint mat2 mat3 mat4 vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 uvec2 uvec3 uvec4 radians degrees sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh pow exp log exp2 log2 sqrt inversesqrt abs sign floor trunc round roundEven ceil fract mod modf min max clamp mix step smoothstep isnan isinf length distance dot cross normalize faceforward reflect refract matrixCompMult outerProduct transpose determinant inverse lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not textureSize texture textureProj textureLod textureOffset texelFetch texelFetchOffset textureProjOffset textureLodOffset textureProjLod textureProjLodOffset textureGrad textureGradOffset textureProjGrad textureProjGradOffset dFdx dFdy fwidth".split(" ")),postProcessNameCheck=a=>/^[A-Za-z][A-Za-z0-9_]*$/.test(a)&&!a.includes("__")&&!/^(i[A-Z]|gl_|webgl_|GL_|mat[2-4]|[dfh]vec[2-4]|[iu]?(sampler|image)([123]D|Cube|Buffer|External))/.test(a)&&!postProcessGLSLWords.has(a);function postProcessEffects(...a){return"void mainImage(out vec4 c, vec2 p)\n{\n vec2 uv = p / iResolution.xy;\n c = texture(iChannel0, uv);\n"+a.map(b=>" {\n"+b+"\n }\n").join("")+"}\n"}function postProcessGlow(a=.6,b=1,c=6){let d="",e=0;for(let f=0;3>f;++f){const g=((f+.5)/3)**.5*c,h=max(5+2*f,round(2*g))|1;e+=h;d+=` for (int _k = 0; _k < ${h}; ++_k) { float _a = float(_k) * ${(2*PI/h).toFixed(7)}${f?" + "+(2.3999632*f).toFixed(7):""}; _glow += max(vec3(0), texture(iChannel0, uv + vec2(cos(_a), sin(_a)) * ${g.toFixed(4)} / iResolution.xy).rgb - ${postProcessNumber(a)}); }`}return` // glow vec3 _glow = vec3(0);${d} c.rgb += _glow * ${"string"===typeof b?postProcessNumber(b)+" / "+e+".":(b/e).toFixed(6)};`}function postProcessScanlines(a=.5,b=6){return` // scanlines c.rgb *= 1. - ${postProcessNumber(a)} * cos(p.y * 6.2832 / ${postProcessNumber(b)});`}function postProcessNoise(a=.1,b=2){return` // noise vec2 _q = fract((floor(p / ${postProcessNumber(b)}) + mod(iTime * 500., 1e3)) * .3197); c.rgb += ${postProcessNumber(a)} * fract(1. + sin(51. * _q.x + 73. * _q.y) * 13753.3);`}function postProcessVignette(a=1,b=3){return` // vignette vec2 _d = uv * 2. - 1.; c.rgb *= 1. - ${postProcessNumber(a)} * min(1., pow(dot(_d, _d) / 2., ${postProcessNumber(b)}));`}function postProcessCurve(a=.1){return` // curve vec2 _d = uv * 2. - 1.; _d *= 1. + ${postProcessNumber(a)} * dot(_d, _d); uv = _d * .5 + .5; c = all(lessThan(abs(_d), vec2(1))) ? texture(iChannel0, uv) : vec4(0, 0, 0, 1);`}function postProcessChromatic(a=.005){return` // chromatic vec2 _d = (uv - .5) * ${postProcessNumber(a)} * 2.; c.r = texture(iChannel0, uv + _d).r; c.b = texture(iChannel0, uv - _d).b;`}const postProcessBlurCheck=a=>!1;function postProcessDiscBlur(a){return` vec3 _sum = vec3(0); float _total = 0.; for (int _k = 0; _k < 24; ++_k) { float _s = sqrt((float(_k) + .5) / 24.), _a = float(_k) * 2.39996; vec2 _puv = uv + vec2(cos(_a), sin(_a)) * _s * _r / iResolution.xy; float _w = ${a||"1."}; _sum += texture(iChannel0, _puv).rgb * _w; _total += _w; } c.rgb = _total > 0. ? _sum / _total : c.rgb;`}function postProcessTiltShift(a=.5,b=.25,c=8){postProcessBlurCheck(c);const d=postProcessNumber;return` // tilt shift float _r = ${d(c)} * smoothstep(0., .5, abs(uv.y - ${d(a)}) - ${d(b)} * .5);${postProcessDiscBlur()}`}function postProcessDepthOfField(a=10,b=4,c=8){postProcessBlurCheck(c);const d=postProcessNumber,e=f=>`${d(c)} * smoothstep(0., ${d(b)}, abs(${f} - ${d(a)}) - ${d(b)} * .5)`;return` // depth of field, none where there is no depth, as with render3D.depthTexture off float _r = LJS_HAS_DEPTH ? ${e("sceneDepth(uv)")} : 0.;${postProcessDiscBlur(`clamp(${e("sceneDepth(_puv)")} - _s * _r + 1., 0., 1.)`)}`}function postProcessOutline(a=BLACK,b=1,c=.02){const d=postProcessNumber;return` // outline vec2 _o = ${d(b)} / iResolution.xy; float _d = sceneDepth(uv); float _dx = abs(sceneDepth(uv + vec2(_o.x, 0)) + sceneDepth(uv - vec2(_o.x, 0)) - 2. * _d); float _dy = abs(sceneDepth(uv + vec2(0, _o.y)) + sceneDepth(uv - vec2(0, _o.y)) - 2. * _d); vec4 _line = vec4(${d(a.r)}, ${d(a.g)}, ${d(a.b)}, ${d(a.a)}); if (LJS_HAS_DEPTH) c.rgb = mix(c.rgb, _line.rgb, _line.a * step(${d(c)}, max(_dx, _dy) / max(abs(_d), 1e-6)));`}function postProcessTV({noise:a=.1,scanlines:b=.5,scanlineSpacing:c=6,glow:d=.4,vignette:e=1,curve:f=0}={}){const g=[];f&&g.push(postProcessCurve(f));d&&g.push(postProcessGlow(0,d,2));b&&g.push(postProcessScanlines(b,c));a&&g.push(postProcessNoise(a,1));e&&g.push(postProcessVignette(e,6));return g.map(h=>" {\n"+h+"\n }").join("\n")}let lightSystem;class LightSystemPlugin{constructor(a,b){function c(){if(!headlessMode)if(glEnable){var q;(q=lightSystem).shadowContext||(q.shadowContext=createCanvasContext(1));lightSystem.textureSizeAuto&&(lightSystem.textureSize=mainCanvasSize.copy());lightSystem.clampTextureSizes();lightSystem.texture=glContext.createTexture();glContext.bindTexture(glContext.TEXTURE_2D,lightSystem.texture);glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,lightSystem.textureSize.x,lightSystem.textureSize.y,0,glContext.RGBA,glContext.UNSIGNED_BYTE,null);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MAG_FILTER,glContext.LINEAR);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_MIN_FILTER,glContext.LINEAR);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_S,glContext.CLAMP_TO_EDGE);glContext.texParameteri(glContext.TEXTURE_2D,glContext.TEXTURE_WRAP_T,glContext.CLAMP_TO_EDGE);lightSystem.lightShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;uniform vec2 lightPos;uniform float radius;in vec2 g;out vec2 vWorldPos;out vec2 vUV;void main(){vec2 worldP=lightPos+(g-.5)*2.*radius;gl_Position=m*vec4(worldP,1,1);vWorldPos=worldP;vUV=g;}","#version 300 es\nprecision highp float;uniform vec2 lightPos;uniform float radius;uniform float fadeRange;uniform vec4 color;uniform sampler2D shadowTexture;uniform bool useShadow;uniform vec2 forward;uniform vec2 cone;uniform sampler2D gelTexture;uniform vec4 gelRect;uniform bool useGel;in vec2 vWorldPos;in vec2 vUV;out vec4 c;void main(){vec2 d=vWorldPos-lightPos;float dist=length(d);float t=clamp((radius-dist)/max(fadeRange,1e-6),0.,1.);c=vec4(color.rgb*t*color.a,1.);if(useShadow)c.rgb*=texture(shadowTexture,vUV).rgb;float k=clamp(dot(forward,d/max(dist,1e-6))*cone.x-cone.y,0.,1.);c.rgb*=k*k*(3.-2.*k);if(useGel){vec2 g=clamp(vec2(dot(d,vec2(forward.y,-forward.x)),dot(d,forward))/(radius*2.)+.5,0.,1.);c.rgb*=texture(gelTexture,gelRect.xy+vec2(g.x,1.-g.y)*gelRect.zw).rgb;}}");d(lightSystem.lightShader)||(glContext.useProgram(lightSystem.lightShader),glContext.uniform1i(glUniformLocation(lightSystem.lightShader,"shadowTexture"),1),glContext.uniform1i(glUniformLocation(lightSystem.lightShader,"gelTexture"),2),lightSystem.compositeShader=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;void main(){gl_Position=vec4(p+p-1.,1,1);}","#version 300 es\nprecision highp float;uniform sampler2D s;uniform vec3 iResolution;out vec4 c;void main(){vec2 uv=gl_FragCoord.xy/iResolution.xy;c=vec4(texture(s,uv).rgb,1.);}"),d(lightSystem.compositeShader)||(lightSystem.lightVAO=e(lightSystem.lightShader,"g"),lightSystem.compositeVAO=e(lightSystem.compositeShader,"p")))}else console.warn("LightSystemPlugin: WebGL not enabled!")}function d(...q){!lightSystem.shadersFailed&&q.some(p=>glFailedPrograms.has(p))&&(console.error("LightSystemPlugin: its shaders did not build on this device, the scene draws without it"),lightSystem.shadersFailed=!0);return lightSystem.shadersFailed}function e(q,p){const t=glContext,u=t.createVertexArray();t.bindVertexArray(u);t.bindBuffer(t.ARRAY_BUFFER,glGeometryBuffer);q=t.getAttribLocation(q,p);t.enableVertexAttribArray(q);t.vertexAttribPointer(q,2,t.FLOAT,!1,8,0);return u}function f(q){const p=glContext,t=p.createTexture();p.bindTexture(p.TEXTURE_2D,t);p.texImage2D(p.TEXTURE_2D,0,p.RGBA,q,q,0,p.RGBA,p.UNSIGNED_BYTE,null);p.texParameteri(p.TEXTURE_2D,p.TEXTURE_MAG_FILTER,p.LINEAR);p.texParameteri(p.TEXTURE_2D,p.TEXTURE_MIN_FILTER,p.LINEAR);p.texParameteri(p.TEXTURE_2D,p.TEXTURE_WRAP_S,p.CLAMP_TO_EDGE);p.texParameteri(p.TEXTURE_2D,p.TEXTURE_WRAP_T,p.CLAMP_TO_EDGE);return t}function g(){const q=glContext,p=lightSystem;p.shadowMap=f(p.shadowMapSize);p.shadowTextureA=f(p.shadowTextureSize);p.shadowTextureB=f(p.shadowTextureSize);p.shadowMapSizeAllocated=p.shadowMapSize;p.shadowTextureSizeAllocated=p.shadowTextureSize;glActiveTexture&&q.bindTexture(q.TEXTURE_2D,glActiveTexture);p.shadowCopyShader||(p.shadowCopyShader=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;out vec2 uv;void main(){gl_Position=vec4(p+p-1.,1,1);uv=p;}","#version 300 es\nprecision highp float;uniform sampler2D s;uniform vec2 lightPos;uniform float radius;uniform vec2 mapOrigin;uniform float mapInvSize;uniform float tap;uniform float core;in vec2 uv;out vec4 c;void main(){vec2 w=lightPos+(uv-.5)*2.*radius;vec3 o=vec3(1);for(int i=0;i<4;i++){vec2 m=(w+tap*(vec2(i%2,i/2)*2.-1.)-mapOrigin)*mapInvSize;o=min(o,m==clamp(m,0.,1.)?texture(s,vec2(m.x,1.-m.y)).rgb:vec3(1));}c=vec4(length(w-lightPos){glSetRenderTarget(y,!0);for(const w of engineObjects)!w.destroyed&&x(w)&&(glColorMask=4278190080,setShader(w.shader),w.renderShadow());glFlush()},(q.shadows||q.directionalLight?.castShadow)&&t(q.shadowMap,y=>y.castShadow),q.backgroundCasters=!!q.directionalLight&&engineObjects.some(y=>!y.destroyed&&y.castBackgroundShadow),q.backgroundCasters&&(q.backgroundMap||(q.backgroundMap=f(p),glActiveTexture&&glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture)),t(q.backgroundMap,y=>y.castBackgroundShadow))}finally{q.shadowPass=!1,glColorMask=-1,glSkipScreenSpace=!1,glSetRenderTarget(),[drawContext,mainCanvasSize,cameraPos,cameraScale,cameraAngle,canvasClearColor,glCustomShader]=u}}function l(){const q=glContext,p=lightSystem,t=p.directionalTextureSize;p.directionalTexture=f(t);p.directionalTextureA=f(t);p.directionalTextureB=f(t);p.directionalTextureSizeAllocated=t;glActiveTexture&&q.bindTexture(q.TEXTURE_2D,glActiveTexture)}function m(){const q=glContext,p=lightSystem;for(const t of[p.directionalTexture,p.directionalTextureA,p.directionalTextureB])q.deleteTexture(t);p.directionalTexture=p.directionalTextureA=p.directionalTextureB=void 0;p.directionalTextureSizeAllocated=0}function n(){const q=glContext,p=lightSystem.directionalPrograms;p.seed=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;out vec2 uv;void main(){gl_Position=vec4(p+p-1.,1,1);uv=p;}","#version 300 es\nprecision highp float;in vec2 uv;out vec4 c;uniform sampler2D f,b;uniform float useF,useB,tap;void main(){vec3 o=vec3(1);for(int i=0;i<4;i++){vec2 m=uv+tap*(vec2(i%2,i/2)*2.-1.);m.y=1.-m.y;vec3 v=mix(vec3(1),texture(f,m).rgb,useF)*mix(vec3(1),texture(b,m).rgb,useB);o=min(o,v);}c=vec4(o,1);}");p.shadow=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;out vec2 uv;void main(){gl_Position=vec4(p+p-1.,1,1);uv=p;}","#version 300 es\nprecision highp float;in vec2 uv;out vec4 c;uniform sampler2D s;uniform vec2 shift;uniform float fade;void main(){vec2 u=uv-shift;vec3 b=u==clamp(u,0.,1.)?texture(s,u).rgb+fade:vec3(1);c=vec4(min(texture(s,uv).rgb,b),1);}");p.leak=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;out vec2 uv;void main(){gl_Position=vec4(p+p-1.,1,1);uv=p;}","#version 300 es\nprecision highp float;in vec2 uv;out vec4 c;uniform sampler2D s;uniform vec2 shift;uniform float fade;void main(){vec2 u=uv-shift;vec3 b=(u==clamp(u,0.,1.)?texture(s,u).rgb:vec3(1))-fade;c=vec4(max(texture(s,uv).rgb,b),1);}");p.combine=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;out vec2 uv;void main(){gl_Position=vec4(p+p-1.,1,1);uv=p;}","#version 300 es\nprecision highp float;in vec2 uv;out vec4 c;uniform sampler2D s,t,f;uniform vec2 rim;uniform float useF,useT;void main(){vec3 l=texture(s,uv).rgb*mix(vec3(1),texture(t,uv).rgb,useT);vec2 u=uv-rim;vec3 up=u==clamp(u,0.,1.)?texture(s,u).rgb*mix(vec3(1),texture(t,u).rgb,useT):vec3(1);vec3 dark=1.-mix(vec3(1),texture(f,vec2(uv.x,1.-uv.y)).rgb,useF);c=vec4(max(l,.8*up*dark),1);}");p.add=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;uniform vec2 origin;uniform float worldSize;in vec2 g;out vec2 uv;void main(){uv=g*3.-1.;gl_Position=m*vec4(origin+uv*worldSize,1,1);}","#version 300 es\nprecision highp float;in vec2 uv;out vec4 c;uniform sampler2D s;uniform vec4 color;void main(){c=vec4(texture(s,uv).rgb*color.rgb*color.a,1);}");if(!d(p.seed,p.shadow,p.leak,p.combine,p.add)){p.seedVAO=e(p.seed,"p");p.shadowVAO=e(p.shadow,"p");p.leakVAO=e(p.leak,"p");p.combineVAO=e(p.combine,"p");p.addVAO=e(p.add,"g");var t=(u,v)=>{q.useProgram(u);v.forEach((y,x)=>q.uniform1i(glUniformLocation(u,y),x+1))};t(p.seed,["f","b"]);t(p.shadow,["s"]);t(p.leak,["s"]);t(p.combine,["s","t","f"]);t(p.add,["s"])}}function r(){const q=glContext,p=lightSystem;var t=p.directionalLight;if(!p.directionalPrograms.seed&&(n(),p.shadersFailed))return;p.directionalTexture&&p.directionalTextureSize===p.directionalTextureSizeAllocated||(p.directionalTexture&&m(),l());const u=p.directionalPrograms,v=p.directionalTextureSize;var y=p.shadowMapWorldSize;const x=t.sunDirection.normalize(-1);var w=K=>vec2(x.x*K/v,x.y*K/v);const z=t.castShadow?1:0;var A=ceil(log2(v))+1;q.bindFramebuffer(q.FRAMEBUFFER,glFramebuffer);q.viewport(0,0,v,v);q.disable(q.BLEND);const C=K=>q.framebufferTexture2D(q.FRAMEBUFFER,q.COLOR_ATTACHMENT0,q.TEXTURE_2D,K,0),D=(K,N)=>{q.activeTexture(q.TEXTURE0+K);q.bindTexture(q.TEXTURE_2D,N)},B=K=>{q.useProgram(u[K]);q.bindVertexArray(u[K+"VAO"]);return u[K]},E=glUniformLocation;let F=B("seed");D(1,p.shadowMap);D(2,p.backgroundMap||p.shadowMap);q.uniform1f(E(F,"useF"),z);q.uniform1f(E(F,"useB"),0);q.uniform1f(E(F,"tap"),.25/v);C(p.directionalTextureA);q.drawArrays(q.TRIANGLE_STRIP,0,4);var G=p.directionalTextureA,H=p.directionalTextureB,J=t.shadowLength*v/y;if(z&&0K!==M&&K!==L);F=B("combine");D(1,M);D(2,L);D(3,p.shadowMap);w=w(3);q.uniform2f(E(F,"rim"),w.x,w.y);q.uniform1f(E(F,"useF"),z);q.uniform1f(E(F,"useT"),G?1:0);C(I);q.drawArrays(q.TRIANGLE_STRIP,0,4);[p.directionalTextureA,p.directionalTextureB]=A.filter(K=>K!==I);p.directionalTexture=I;D(1,null);D(2,null);D(3,null);q.activeTexture(q.TEXTURE0);glActiveTexture&&q.bindTexture(q.TEXTURE_2D,glActiveTexture);q.bindFramebuffer(q.FRAMEBUFFER,null);q.enable(q.BLEND)}lightSystem=this;this.enabled=!0;this.shadersFailed=!1;this.ambientColor=(b||BLACK).copy();this.textureSize=a?a.copy():void 0;this.textureSizeAuto=!a;this.compositeVAO=this.lightVAO=this.compositeShader=this.lightShader=this.texture=void 0;this.shadows=!1;this.shadowMapSize=1024;this.shadowMapScale=2;this.shadowTextureSize=256;this.shadowPassCount=16;this.shadowSoftness=.5;this.emissivePass=this.shadowPass=!1;this.shadowContext=this.shadowStretchVAO=this.shadowCopyVAO=this.shadowStretchShader=this.shadowCopyShader=this.shadowTextureB=this.shadowTextureA=this.backgroundMap=this.shadowMap=void 0;this.shadowMapOrigin=vec2();this.shadowMapWorldSize=0;this.directionalLight=void 0;this.directionalTextureSize=512;this.directionalTextureB=this.directionalTextureA=this.directionalTexture=void 0;this.directionalTextureSizeAllocated=0;this.backgroundCasters=!1;this.directionalPrograms={};this.shadowTextureSizeAllocated=this.shadowMapSizeAllocated=0;c();engineAddPlugin(void 0,function(){if(!headlessMode&&glEnable&&!lightSystem.shadersFailed&&lightSystem.enabled){if(!lightSystem.texture){if(glContext.isContextLost())return;c();if(!lightSystem.texture)return}glFlush();var q=glAdditive;(lightSystem.shadows||lightSystem.directionalLight)&&k();if(!lightSystem.shadersFailed){var p=lightSystem.directionalLight;if(p)r();else{if(lightSystem.directionalTexture||lightSystem.backgroundMap)m(),glContext.deleteTexture(lightSystem.backgroundMap),lightSystem.backgroundMap=void 0,lightSystem.backgroundCasters=!1;!lightSystem.shadows&&lightSystem.shadowMap&&h()}if(!lightSystem.shadersFailed){var t=lightSystem.textureSize,u=glClampTextureSize(mainCanvasSize.x),v=glClampTextureSize(mainCanvasSize.y);!lightSystem.textureSizeAuto||t.x===u&&t.y===v||(lightSystem.textureSize=vec2(u,v),glContext.bindTexture(glContext.TEXTURE_2D,lightSystem.texture),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,u,v,0,glContext.RGBA,glContext.UNSIGNED_BYTE,null),glActiveTexture&&glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture));t=lightSystem.ambientColor;glContext.bindFramebuffer(glContext.FRAMEBUFFER,glFramebuffer);glContext.framebufferTexture2D(glContext.FRAMEBUFFER,glContext.COLOR_ATTACHMENT0,glContext.TEXTURE_2D,lightSystem.texture,0);glContext.viewport(0,0,lightSystem.textureSize.x,lightSystem.textureSize.y);glContext.clearColor(t.r,t.g,t.b,t.a);glContext.clear(glContext.COLOR_BUFFER_BIT);setAdditiveBlendMode();glContext.enable(glContext.BLEND);glContext.blendFunc(glContext.ONE,glContext.ONE);t=lightSystem.lightShader;glContext.useProgram(t);glContext.uniformMatrix4fv(glUniformLocation(t,"m"),!1,glTransform);glSetInstancedMode(!0);glRenderTargetBase=[lightSystem.texture,lightSystem.textureSize];try{for(var y of engineObjects)y.destroyed||(glAdditive||setAdditiveBlendMode(),y.renderLight());if(p&&lightSystem.directionalTexture){glFlush();y=glContext;const w=lightSystem.directionalPrograms,z=w.add,A=p.color;y.useProgram(z);y.bindVertexArray(w.addVAO);y.uniformMatrix4fv(glUniformLocation(z,"m"),!1,glTransform);y.uniform2f(glUniformLocation(z,"origin"),lightSystem.shadowMapOrigin.x,lightSystem.shadowMapOrigin.y);y.uniform1f(glUniformLocation(z,"worldSize"),lightSystem.shadowMapWorldSize);y.uniform4f(glUniformLocation(z,"color"),A.r,A.g,A.b,A.a);y.activeTexture(y.TEXTURE1);y.bindTexture(y.TEXTURE_2D,lightSystem.directionalTexture);y.activeTexture(y.TEXTURE0);y.enable(y.BLEND);y.blendFunc(y.ONE,y.ONE);y.drawArrays(y.TRIANGLE_STRIP,0,4);glSetInstancedMode(!0)}p=[drawContext,glCustomShader];drawContext=lightSystem.shadowContext;lightSystem.emissivePass=!0;try{for(var x of engineObjects){if(x.destroyed||!(0d.disconnect();d.start();d.stop(audioContext.currentTime+c)}}connect(a){if(!audioContext)return a;const b=a&&"input"in a?a.input:a;this.output.disconnect();this.output.connect(b);return a}disconnect(){this.output?.disconnect()}connectEffect(a,b=a){this.input.connect(a);b.connect(this.wetGain)}}class AudioFilter extends AudioEffect{constructor(a="lowpass",b=1e3,c=1,d=1){super(d);audioContext&&(this.node=audioContext.createBiquadFilter(),this.node.type=a,this.node.frequency.value=b,this.node.Q.value=c,this.connectEffect(this.node))}setFrequency(a,b=0){audioContext&&this.rampParam(this.node.frequency,a,b)}setQ(a,b=0){audioContext&&this.rampParam(this.node.Q,a,b)}}class AudioReverb extends AudioEffect{constructor(a=2,b=2,c=.5){super(c);audioContext&&(this.node=audioContext.createConvolver(),this.setRoom(a,b),this.connectEffect(this.node))}setRoom(a,b=2){audioContext&&(this.node.buffer=this.createImpulse(a,b))}createImpulse(a,b){var c=audioContext.sampleRate;a=max(1,c*a|0);c=audioContext.createBuffer(2,a,c);for(let d=2;d--;){const e=c.getChannelData(d);for(let f=a;f--;)e[f]=rand(-1,1)*(1-f/a)**b}return c}}class AudioDelay extends AudioEffect{constructor(a=.3,b=.4,c=.5){super(c);audioContext&&(this.node=audioContext.createDelay(5),this.feedbackGain=audioContext.createGain(),this.node.connect(this.feedbackGain).connect(this.node),this.connectEffect(this.node),this.setTime(a),this.setFeedback(b))}setTime(a,b=0){audioContext&&this.rampParam(this.node.delayTime,a,b)}setFeedback(a,b=0){audioContext&&this.rampParam(this.feedbackGain.gain,clamp(a,0,.95),b)}}class AudioDistortion extends AudioEffect{constructor(a=.5,b=1){super(b);this.amount=clamp(a);audioContext&&(this.node=audioContext.createWaveShaper(),this.node.oversample="2x",this.setAmount(a),this.connectEffect(this.node))}setAmount(a){this.amount=a=clamp(a);if(audioContext){a*=100*a;var b=new Float32Array(1024);for(let c=1024;c--;){const d=2*c/1023-1;b[c]=(1+a)*d/(1+a*abs(d))}this.node.curve=b}}}class AudioCompressor extends AudioEffect{constructor(a=-24,b=12,c=1){super(c);audioContext&&(this.node=audioContext.createDynamicsCompressor(),this.node.threshold.value=a,this.node.ratio.value=b,this.connectEffect(this.node))}setThreshold(a,b=0){audioContext&&this.rampParam(this.node.threshold,a,b)}setRatio(a,b=0){audioContext&&this.rampParam(this.node.ratio,a,b)}}let uiSystem,uiDebug=0,uiActiveReleased=!1;function uiSetDebug(a){uiDebug="boolean"===typeof a?a?1:0:a}class UISystemPlugin{constructor(a=mainContext){function b(d){let e,f;d.parent?(e=d.parent.nativePos,f=d.parent.size):(e=uiSystem.screenToNative(mainCanvasSize.scale(.5)),f=uiSystem.nativeHeight?vec2(mainCanvasSize.x*uiSystem.nativeHeight/mainCanvasSize.y,uiSystem.nativeHeight):mainCanvasSize);const g=d.anchor;d.nativePos=e.add(f.multiply(g).scale(.5)).subtract(d.size.multiply(g).scale(.5)).add(d.localPos)}uiSystem=this;this.activateOnPress=!1;this.defaultColor=WHITE;this.defaultTextColor=this.defaultLineColor=BLACK;this.defaultButtonColor=hsl(0,0,.7);this.defaultHoverColor=hsl(0,0,.9);this.defaultDisabledColor=hsl(0,0,.3);this.defaultGradientColor=void 0;this.defaultLineWidth=4;this.defaultCornerRadius=0;this.defaultTextFitScale=.8;this.defaultFont=fontDefault;this.defaultSoundClick=this.defaultSoundRelease=this.defaultSoundPress=void 0;this.defaultShadowColor=CLEAR_BLACK;this.defaultShadowBlur=5;this.defaultShadowOffset=vec2(5);this.defaultHandleSlice=this.defaultSlice=void 0;this.nativeHeight=0;this.navigationObject=void 0;this.navigationTimer=new Timer(void 0,!0);this.navigationDelay=.2;this.navigationDirection=1;this.navigationMode=!1;this.uiObjects=[];this.uiContext=a;this._dragListeners=this._keyInputObject=this.confirmDialog=this.lastHoverObject=this.hoverObject=this.activeObject=void 0;this._onKeyDown=d=>{const e=this._keyInputObject;if(e&&uiObjectIsUsable(e)&&!uiObjectIsBehindDialog(e)){d.stopPropagation();var f=d.key||"";d.ctrlKey||d.metaKey||d.altKey||(1===f.length||/^(Backspace|Delete|Tab|Arrow(Up|Down|Left|Right)|Home|End|Enter|Escape)$/.test(f))&&d.preventDefault();"keydown"===d.type&&e.onKeyDown(d)}};engineAddPlugin(function(){function d(k){if(!k.destroyed&&k.visible&&k.uiUpdatePass!==c){k.uiUpdatePass=c;b(k);var l=k.children.slice();for(let m=l.length;m--;)d(l[m]);k.destroyed||k.update()}}++c;var e=uiSystem.activeObject;e&&!uiObjectIsUsable(e)&&(uiSystem.activeObject=void 0,e.destroyed||e===uiSystem.keyInputObject||e.onRelease());!(e=uiSystem.keyInputObject)||uiObjectIsUsable(e)&&!uiObjectIsBehindDialog(e)||(e instanceof UITextInput&&!e.destroyed?e.stopEditing():uiSystem.keyInputObject=void 0);var f=uiSystem.keyInputObject;(e=f instanceof UITextInput&&mouseWasPressed(0)&&!f.isMouseOverlapping())&&f.stopEditing();uiSystem.lastHoverObject=uiSystem.hoverObject;uiSystem.hoverObject=void 0;(f=uiSystem.lastHoverObject)&&!f.destroyed&&uiObjectIsHidden(f)&&(uiSystem.lastHoverObject=void 0,f.onLeave());mouseWasPressed(0)&&(uiSystem.navigationMode=!1,uiSystem.navigationObject=void 0);uiSystem.keyInputObject&&(uiSystem.activeObject=uiSystem.keyInputObject,uiSystem.hoverObject=uiSystem.lastHoverObject);f=uiSystem.getNavigableObjects();if(!f.length)uiSystem.navigationObject=void 0;else if(!uiSystem.keyInputObject){f.includes(uiSystem.navigationObject)||(uiSystem.navigationObject=void 0);isTouchDevice||!uiSystem.navigationMode||uiSystem.navigationObject||(uiSystem.navigationObject=f.find(k=>k.navigationAutoSelect));if(!uiSystem.navigationTimer.active()){var g=sign(uiSystem.getNavigationDirection());if(g){if(uiSystem.navigationObject){var h=f.indexOf(uiSystem.navigationObject);g=mod(h+g,f.length);h=f[g]}else(h=f.find(k=>k.navigationAutoSelect))||(h=f[0!k.destroyed)},function(){function d(g){if(!g.destroyed&&g.visible){b(g);g.render();for(const h of g.children)d(h)}}const e=uiSystem.uiContext;e.save();if(uiSystem.nativeHeight){const g=mainCanvasSize.y/uiSystem.nativeHeight;e.translate(-g*mainCanvasSize.x/2,0);e.scale(g,g);e.translate(mainCanvasSize.x/2/g,0)}const f=uiSystem.confirmDialog;uiSystem.uiObjects.forEach(g=>g.parent||g===f||d(g));f&&d(f);if(0uiDebug)){b(h);h.renderDebug(k);for(const l of h.children)g(l,k)}}uiSystem.uiObjects.forEach(h=>h.parent||h===f||g(h));f&&g(f)}e.restore()});let c=0}drawRect(a,b,c=WHITE,d=0,e=BLACK,f=0,g,h=BLACK,k=0,l=vec2()){const m=uiSystem.uiContext;if(g){const n=m.createLinearGradient(a.x,a.y-b.y/2,a.x,a.y+b.y/2);c=c.toString();n.addColorStop(0,c);n.addColorStop(.5,g.toString());n.addColorStop(1,c);m.fillStyle=n}else m.fillStyle=c.toString();uiSetShadow(m,h,k,l);m.beginPath();f&&m.roundRect?m.roundRect(a.x-b.x/2,a.y-b.y/2,b.x,b.y,f):m.rect(a.x-b.x/2,a.y-b.y/2,b.x,b.y);m.fill();m.shadowColor="#0000";d&&0!0)=>{const l=m=>{m.preventDefault();k()&&g&&g(m)};document.addEventListener(h,l);this._dragListeners.push([h,l])};let f=0;e(a,"drop",()=>{f=0;return!0});e(b,"dragenter",()=>!f++);e(c,"dragleave",()=>!!f&&!--f);e(d,"dragover")}screenToNative(a){if(!uiSystem.nativeHeight)return a;const b=mainCanvasSize.y/uiSystem.nativeHeight,c=1/b;a=a.copy();a.x+=b*mainCanvasSize.x/2;a.x*=c;a.y*=c;a.x-=c*mainCanvasSize.x/2;return a}get keyInputObject(){return this._keyInputObject}set keyInputObject(a){const b=!!this._keyInputObject;this._keyInputObject=a;!b&&a?(addEventListener("keydown",this._onKeyDown,!0),addEventListener("keyup",this._onKeyDown,!0),inputClearKeyboard(),(a=this.activeObject)&&mouseIsDown(0)&&(this.activeObject=void 0,a.onRelease(),a.soundRelease&&a.soundRelease.play())):b&&!a&&(removeEventListener("keydown",this._onKeyDown,!0),removeEventListener("keyup",this._onKeyDown,!0))}destroyObjects(){for(const a of this.uiObjects)a.parent||a.destroy();this.uiObjects=this.uiObjects.filter(a=>!a.destroyed);this.confirmDialog=this.keyInputObject=this.lastHoverObject=this.hoverObject=this.activeObject=void 0}getNavigableObjects(){function a(c){if(!c.destroyed&&c.visible&&!c.disabled){c.isInteractive()&&void 0!==c.navigationIndex&&b.push(c);for(const d of c.children)a(d)}}const b=[];if(uiSystem.confirmDialog)a(uiSystem.confirmDialog);else for(const c of uiSystem.uiObjects)c.parent||a(c);b.sort((c,d)=>c.navigationIndex-d.navigationIndex);return b}isMouseOverUI(){function a(b){return b.destroyed||!b.visible?!1:b.canBeHover&&b.isMouseOverlapping()?!0:b.children.some(a)}return uiSystem.keyInputObject?!0:uiSystem.confirmDialog?a(uiSystem.confirmDialog):uiSystem.uiObjects.some(b=>!b.parent&&a(b))}getNavigationDirection(){const a=1===uiSystem.navigationDirection;var b=2===uiSystem.navigationDirection;if(isUsingGamepad){const c=gamepadStick(0,gamepadPrimary),d=gamepadDpad(gamepadPrimary);return b?-(c.y||d.y)||c.x||d.x:a?-(c.y||d.y):c.x||d.x}if(b)return keyIsDown("ArrowUp")||keyIsDown("ArrowLeft")?-1:keyIsDown("ArrowDown")||keyIsDown("ArrowRight")?1:0;b=a?"ArrowDown":"ArrowRight";return keyIsDown(a?"ArrowUp":"ArrowLeft")?-1:keyIsDown(b)?1:0}getNavigationOtherDirection(){if(2===uiSystem.navigationDirection)return 0;const a=1===uiSystem.navigationDirection;if(isUsingGamepad){const b=gamepadStick(0,gamepadPrimary),c=gamepadDpad(gamepadPrimary);return a?b.x||c.x:b.y||c.y}return a?keyIsDown("ArrowLeft")?-1:keyIsDown("ArrowRight")?1:0:keyIsDown("ArrowUp")?1:keyIsDown("ArrowDown")?-1:0}getNavigationWasPressed(){return isUsingGamepad?gamepadWasPressed(0,gamepadPrimary):keyWasPressed("Space")||keyWasPressed("Enter")}showConfirmDialog(a="Are you sure?",b,c,d=vec2(500,250),e="Escape"){if(uiSystem.confirmDialog)return uiSystem.confirmDialog;const f=uiSystem.navigationDirection,g=uiSystem.navigationObject;uiSystem.navigationDirection=2;const h=new UIObject(vec2(),d);uiSystem.confirmDialog=h;h.onRender=()=>{const q=hsl(0,0,0,.7);uiSystem.drawRect(vec2(),vec2(1e9),q)};let k=!1;h.onUpdate=()=>{k&&(keyWasPressed(e)||gamepadWasPressed(1))&&(h.destroy(),inputClear(),c&&c());k=!0};h.isMouseOverlapping=()=>!0;var l=d.x/500;const m=d.y/250,n=d.y/5;a=new UIText(vec2(0,-n),vec2(d.x-50,70*m),a);h.addChild(a);a=vec2(120*l,70*m);d=new UIButton(vec2(-80*l,n),a,"Yes");d.textHeight=40*m;d.navigationIndex=1;d.hoverColor=hsl(0,1,.5);d.onClick=()=>{h.destroy();inputClear();b&&b()};h.addChild(d);l=new UIButton(vec2(80*l,n),a,"No");l.textHeight=40*m;l.navigationIndex=2;l.navigationAutoSelect=!0;l.onClick=()=>{h.destroy();inputClear();c&&c()};h.addChild(l);const r=h.destroy.bind(h);h.destroy=()=>{const q=uiSystem.confirmDialog===h;q&&(uiSystem.confirmDialog=void 0,uiSystem.navigationDirection=f);r();q&&g&&!g.destroyed&&(uiSystem.navigationObject=g)};return h}}function uiObjectIsUsable(a){for(;a;a=a.parent)if(a.destroyed||!a.visible||a.disabled)return!1;return!0}function uiSetShadow(a,b,c,d){0timeReal%1?"█":"░");uiSystem.drawText(b,this.getTextPos(a),a,this.textColor,this.textLineWidth,this.textLineColor,this.align,this.font,this.fontStyle,!0,this.textShadow)}}class UITile extends UIObject{constructor(a,b,c,d=WHITE,e=0,f=!1){super(a,b);this.tileInfo=c;this.angle=e;this.mirror=f;this.color=d.copy();this.shadowColor=CLEAR_BLACK.copy()}render(){this.onRender();uiSystem.drawTile(this.nativePos,this.size,this.tileInfo,this.color,this.angle,this.mirror,this.shadowColor||CLEAR_BLACK,this.shadowBlur,this.shadowOffset)}}class UIButton extends UIObject{constructor(a,b,c="",d=uiSystem.defaultButtonColor){super(a,b);this.textOffset=vec2();this.text=c;this.color=d.copy();this.interactive=!0}render(){super.render();const a=this.getTextSize();uiSystem.drawText(this.text,this.getTextPos(a).add(this.textOffset),a,this.textColor,this.textLineWidth,this.textLineColor,this.align,this.font,this.fontStyle,!0,this.textShadow)}}class UICheckbox extends UIObject{constructor(a,b,c=!1,d="",e=uiSystem.defaultButtonColor){super(a,b);this.checked=c;this.text=d;this.color=e.copy();this.interactive=!0}click(a=!0){this.checked=!this.checked;super.click(a);this.onChange()}render(){super.render();if(this.checked){var a=this.cornerRadius/min(this.size.x,this.size.y)*2;a=lerp(1,2**.5/2,a)/2;a=this.size.scale(a);uiSystem.drawLine(this.nativePos.add(a.multiply(vec2(-1))),this.nativePos.add(a.multiply(vec2(1))),this.lineWidth,this.lineColor);uiSystem.drawLine(this.nativePos.add(a.multiply(vec2(-1,1))),this.nativePos.add(a.multiply(vec2(1,-1))),this.lineWidth,this.lineColor)}a=this.getTextSize();const b=this.nativePos.add(vec2(this.size.x,0));uiSystem.drawText(this.text,b,a,this.textColor,this.textLineWidth,this.textLineColor,"left",this.font,this.fontStyle,!1,this.textShadow)}}class UISlider extends UIObject{constructor(a,b,c=.5,d="",e=uiSystem.defaultButtonColor,f=WHITE){super(a,b);this.value=c;this.handleColor=f.copy();this.handleSlice=uiSystem.defaultHandleSlice;this.fillMode=!1;this.text=d;this.color=e.copy();this.interactive=!0}update(){var a=this.isActiveObject();super.update();if(this.interactive){var b=this.value;if(a||this.isActiveObject()){var c=(a=this.size.x>this.size.y)?this.nativePos.x:this.nativePos.y,d=(a?this.size.x:this.size.y)-(a?this.size.y:this.size.x);const e=c-d/2;c+=d/2;d=uiSystem.screenToNative(mousePosScreen);this.value=a?percent(d.x,e,c):percent(d.y,c,e)}else this.isNavigationObject()&&(a=uiSystem.getNavigationOtherDirection(),uiSystem.navigationTimer.active()||(this.value=clamp(this.value+.01*a)));this.value===b||this.onChange()}}drawHandle(a,b,c){const d=this.handleSlice||this.slice;d?uiSystem.drawSlice(d,a,b,c):uiSystem.drawRect(a,b,c,this.lineWidth,this.lineColor,this.cornerRadius,this.gradientColor)}render(){super.render();var a=this.size.x>this.size.y,b=a?this.size.x:this.size.y,c=a?this.size.y:this.size.x,d=uiObjectIsDisabled(this)?this.disabledColor:this.handleColor;if(this.fillMode)c=min(c,2*this.cornerRadius),c=lerp(c,b,this.value),b=(c-b)*(a?.5:-.5),b=this.nativePos.add(a?vec2(b,0):vec2(0,b)),a=a?vec2(c,this.size.y):vec2(this.size.x,c),this.drawHandle(b,a,d);else{const e=clamp(a?this.value:1-this.value);b=(b-c)*(e-.5);a=this.nativePos.add(a?vec2(b,0):vec2(0,b));b=vec2(c);this.drawHandle(a,b,d)}d=this.getTextSize();uiSystem.drawText(this.text,this.getTextPos(d),d,this.textColor,this.textLineWidth,this.textLineColor,this.align,this.font,this.fontStyle,!0,this.textShadow)}navigatePressed(){this.value=this.value?0:1;this.onChange();this.onRelease();super.navigatePressed()}}class UIVideo extends UIObject{constructor(a,b,c,d=!1,e=!1,f=1){super(a,b||vec2());this.color=BLACK.copy();this.cornerRadius=0;this.volume=f;this.video=document.createElement("video");this.video.loop=e;this.video.volume=clamp(f*soundVolume);this.video.muted=!soundEnable;this._soundEnabled=soundEnable;this.video.style.display="none";this.video.playsInline=!0;this.video.src=c;document.body.appendChild(this.video);d&&this.play()}async play(){try{return await this.video.play(),!0}catch(a){return!1}}pause(){this.video.pause()}stop(){this.video.pause();this.video.currentTime=0}isLoading(){return this.video.readyStater.visible),b=a.length;if(b){var c=clamp(floor(this.columns),1,b),d=ceil(b/c),e=Array(c).fill(0),f=Array(d).fill(0);for(var g=0;g=e.get_x()&&g.get_y()<=b.get_y()&&h.get_y()>=e.get_y())return!0}return!1}function box2dEdgePoints(a,b){const c=[];for(const d of a)(!c.length||25e-6=c[c.length-1].distanceSquared(c[0]);)c.pop();return c}function box2dWakeWithContacts(a){a.SetAwake(!0);for(a=a.GetContactList();!box2d.isNull(a);a=a.get_next())a.get_other().SetAwake(!0)}const box2dFinite=(a,b)=>isFinite(a)?a:b;function box2dWakeJoint(a){a.GetBodyA().SetAwake(!0);a.GetBodyB().SetAwake(!0)}function box2dCenterInertia(a,b,c){const d=Math.fround;return d(d(a)*d(d(d(b)*d(b))+d(d(c)*d(c))))}const box2dPending=[];let box2dPendingBusy=0;function box2dWhenUnlocked(a){box2dPending.push(a);box2d.world.IsLocked()||box2dPendingBusy||box2dRunPending()}function box2dRunPending(){++box2dPendingBusy;try{for(;box2dPending.length;)box2dPending.shift()()}finally{--box2dPendingBusy}}const box2dJoints=new Map,box2dGearJoints=new Set;function box2dDestroyGears(a){for(const b of box2dGearJoints)if(!b.box2dJoint)box2dGearJoints.delete(b);else if(b.joint1===a||b.joint2===a)box2dGearJoints.delete(b),b.destroy()}function box2dSetDebug(a){box2dDebug=a}const box2dUnusedFields={velocity:"setLinearVelocity",angleVelocity:"setAngularVelocity",damping:"setLinearDamping",angleDamping:"setAngularDamping",mass:"setMass or the density of its shapes",friction:"the friction of its shapes, given to addBox and the rest",restitution:"the restitution of its shapes, given to addBox and the rest"},box2dUnusedWarned=new Set,box2dUnusedStarts=new WeakMap;function box2dUnusedFieldValues(a){const b=[];for(const c in box2dUnusedFields){const d=a[c];d instanceof Vector2?b.push(d.x,d.y):b.push(d)}b.push(a.gravityScale);return b}function box2dUnusedWarn(a,b){box2dUnusedWarned.has(a)||(box2dUnusedWarned.add(a),console.warn("Box2dObject."+a+" does nothing on a Box2D body, use "+b))}function box2dCheckUnusedFields(a){const b=box2dUnusedStarts.get(a);if(b){var c=0;for(const e in box2dUnusedFields){var d=a[e];d instanceof Vector2?(d=d.x!==b[c]||d.y!==b[c+1],c+=2):d=d!==b[c++];d&&box2dUnusedWarn(e,box2dUnusedFields[e])}a.gravityScale!==b[c]&&(b[c]=a.gravityScale,Math.fround(a.gravityScale)===a.body.GetGravityScale()||box2dUnusedWarn("gravityScale","setGravityScale"))}}class Box2dObject extends EngineObject{constructor(a=vec2(),b=vec2(),c,d=0,e,f=box2d.bodyTypeDynamic,g=0){super(a,b,c,d,e,g);b=new box2d.instance.b2BodyDef;b.set_type(f);b.set_position(box2dTemp(a));b.set_angle(-d);this.body=box2d.world.CreateBody(b);box2d.instance.destroy(b);this.lineColor=BLACK.copy();this.lineWidth=.1;this.edgeLists=[];this.edgeLoops=[];this.edgeListFixtures=new Map;this.body.object=this;box2d.objects.push(this);debug&&box2dUnusedStarts.set(this,box2dUnusedFieldValues(this))}destroy(a=!1){if(!this.destroyed){var b=this.body;box2dWhenUnlocked(()=>{this.body===b&&(box2d.world.DestroyBody(b),this.body=b.object=void 0)});super.destroy(a)}}updatePhysics(){}updateTransforms(a=!0){super.updateTransforms(a)}render(){this.tileInfo?super.render():this.drawFixtures(this.color,this.lineColor,this.lineWidth)}renderDebugInfo(){var a=!this.getIsAwake();const b=this.getBodyType()===box2d.bodyTypeStatic;a=rgb(a?1:0,a?1:0,b?1:0,.5);this.drawFixtures(a)}drawFixtures(a=WHITE,b=BLACK,c=.1,d,e){const f=this.edgeListFixtures;this.getFixtureList().forEach(g=>{f.has(box2d.instance.getPointer(g))||box2d.drawFixture(g,this.pos,this.angle,a,b,c,d,e)});this.edgeLists.forEach(g=>drawLineList(g,c,b,!1,this.pos,this.angle,d,!1,e));this.edgeLoops.forEach(g=>drawLineList(g,c,b,!0,this.pos,this.angle,d,!1,e))}beginContact(a,b,c,d){}endContact(a,b,c){}addShape(a,b=1,c=.2,d=0,e=!1){const f=new box2d.instance.b2FixtureDef;f.set_shape(a);f.set_density(b);f.set_friction(c);f.set_restitution(d);f.set_isSensor(e);a=this.body.CreateFixture(f);box2d.instance.destroy(f);return a}addBox(a=vec2(1),b=vec2(),c=0,d,e,f,g){if(1e-6f.slice(0,m).every(n=>1e-6=f.length)for(var h of f)for(var k of f)for(const l of f)g=max(g,abs(k.subtract(h).cross(l.subtract(h))));if(1e-6<=g){g=box2d.instance._malloc(8*f.length);for(let l=0,m=0;l>2]=f[l].x,m+=4,box2d.instance.HEAPF32[g+m>>2]=f[l].y,m+=4;h=box2d.instance.wrapPointer(g,box2d.instance.b2Vec2);k=new box2d.instance.b2PolygonShape;k.Set(h,f.length);box2d.instance._free(g);return k}}(a))return b=this.addShape(a,b,c,d,e),box2d.instance.destroy(a),b}addRegularPoly(a=1,b=8,c,d,e,f){b=min(b,8);const g=[];a/=2;for(let h=b;0a.length)return f;for(let h=0;hthis.edgeListFixtures.set(box2d.instance.getPointer(h),g));return f}addEdgeLoop(a,b,c,d,e){a=box2dEdgePoints(a,!0);const f=[],g=[];if(2>a.length)return f;for(let h=0;hthis.edgeListFixtures.set(box2d.instance.getPointer(h),g));return f}destroyFixture(a){const b=box2d.instance.getPointer(a),c=this.edgeListFixtures,d=c.get(b);d&&(this.edgeLists=this.edgeLists.filter(e=>e!==d),this.edgeLoops=this.edgeLoops.filter(e=>e!==d),c.forEach((e,f)=>e===d&&c.delete(f)));box2dWhenUnlocked(()=>this.body&&this.getFixtureList().some(e=>box2d.instance.getPointer(e)===b)&&this.body.DestroyFixture(a))}destroyAllFixtures(){this.edgeLists=[];this.edgeLoops=[];this.edgeListFixtures.clear();const a=this.getFixtureList(),b=box2d.instance.getPointer;box2dWhenUnlocked(()=>{if(this.body){var c=new Set(this.getFixtureList().map(b));for(const d of a)c.has(b(d))&&this.body.DestroyFixture(d)}})}getCenterOfMass(){return box2d.vec2From(this.body.GetWorldCenter())}getLinearVelocity(){return box2d.vec2From(this.body.GetLinearVelocity())}getAngularVelocity(){return-this.body.GetAngularVelocity()}getMass(){return this.body.GetMass()}getInertia(){const a=this.body.GetLocalCenter();return max(0,Math.fround(this.body.GetInertia()-box2dCenterInertia(this.getMass(),a.get_x(),a.get_y())))}getIsAwake(){return this.body.IsAwake()}getBodyType(){return this.body.GetType()}getSpeed(){return this.getLinearVelocity().length()}getVelocityAtPoint(a){return box2d.vec2From(this.body.GetLinearVelocityFromWorldPoint(box2dTemp(a)))}setTransform(a,b){this.pos.set(a.x,a.y);this.angle=b;const c=a.x,d=a.y;box2dWhenUnlocked(()=>{this.body&&(this.body.SetTransform(box2dTemp(vec2(c,d)),-b),box2dWakeWithContacts(this.body))})}setPosition(a){this.pos.set(a.x,a.y);const b=a.x,c=a.y;box2dWhenUnlocked(()=>{this.body&&(this.body.SetTransform(box2dTemp(vec2(b,c)),this.body.GetAngle()),box2dWakeWithContacts(this.body))})}setAngle(a){this.angle=a;box2dWhenUnlocked(()=>{this.body&&(this.body.SetTransform(this.body.GetPosition(),-a),box2dWakeWithContacts(this.body))})}setLinearVelocity(a){this.body.SetLinearVelocity(box2dTemp(a))}setAngularVelocity(a){this.body.SetAngularVelocity(-a)}setLinearDamping(a){this.body.SetLinearDamping(a)}setAngularDamping(a){this.body.SetAngularDamping(a)}setGravityScale(a=1){this.body.SetGravityScale(this.gravityScale=a);this.body.SetAwake(!0)}setBullet(a=!0){this.body.SetBullet(a)}setAwake(a=!0){this.body.SetAwake(a)}setBodyType(a){box2dWhenUnlocked(()=>this.body&&this.body.SetType(a))}setSleepingAllowed(a=!0){this.body.SetSleepingAllowed(a)}setFixedRotation(a=!0){this.body.SetFixedRotation(a);this.body.SetAwake(!0)}setCenterOfMass(a){this.setMassData(a)}setMass(a){this.setMassData(void 0,a)}setMomentOfInertia(a){this.setMassData(void 0,void 0,a)}resetMassData(){box2dWhenUnlocked(()=>this.body&&this.body.ResetMassData())}setMassData(a,b,c){a=a&&a.copy();box2dWhenUnlocked(()=>{if(this.body){var d=box2dQueryObject("massData","b2MassData");this.body.GetMassData(d);var e=d.get_center(),f=d.get_mass(),g=a?a.x:e.get_x(),h=a?a.y:e.get_y(),k=Math.fround;e=k(d.get_I()-box2dCenterInertia(f,e.get_x(),e.get_y()));e=c??e;b=box2dFinite(b??f,f);f=box2dCenterInertia(0{const e=d.GetFilterData();e.set_categoryBits(a);e.set_maskBits(65535&~b);e.set_groupIndex(c);d.SetFilterData(e)})}setSensor(a=!0){this.getFixtureList().forEach(b=>b.SetSensor(a));box2dWakeWithContacts(this.body)}applyForce(a,b){b||=this.getCenterOfMass();this.setAwake();this.body.ApplyForce(box2dTemp(a),box2dTemp(b,1))}applyAcceleration(a,b){b||=this.getCenterOfMass();this.setAwake();a=a.scale(this.getMass());this.body.ApplyLinearImpulse(box2dTemp(a),box2dTemp(b,1))}applyImpulse(a,b){b||=this.getCenterOfMass();this.setAwake();this.body.ApplyLinearImpulse(box2dTemp(a),box2dTemp(b,1))}applyTorque(a){this.setAwake();this.body.ApplyTorque(-a)}applyAngularAcceleration(a){this.getBodyType()!==box2d.bodyTypeDynamic||this.body.IsFixedRotation()||(this.setAwake(),this.setAngularVelocity(this.getAngularVelocity()+a))}applyAngularImpulse(a){this.setAwake();this.body.ApplyAngularImpulse(-a)}hasFixtures(){return!box2d.isNull(this.body.GetFixtureList())}getFixtureList(){const a=[];for(let b=this.body.GetFixtureList();!box2d.isNull(b);)a.push(b),b=b.GetNext();return a}hasJoints(){return 0k+l*this.size.x,e=(k,l)=>!c[d(k,l)]&&0{box2dJoints.get(b)===this&&(box2dJoints.delete(b),box2d.world.DestroyJoint(a))})}}getObjectA(){return this.box2dJoint.GetBodyA().object}getObjectB(){return this.box2dJoint.GetBodyB().object}getAnchorA(){return box2d.vec2From(this.box2dJoint.GetAnchorA())}getAnchorB(){return box2d.vec2From(this.box2dJoint.GetAnchorB())}getReactionForce(a=timeDelta){return box2d.vec2From(this.box2dJoint.GetReactionForce(1/a))}getReactionTorque(a=timeDelta){return-this.box2dJoint.GetReactionTorque(1/a)}getCollideConnected(){return this.box2dJoint.GetCollideConnected()}isActive(){return!!this.box2dJoint&&this.box2dJoint.IsActive()}isDestroyed(){return!this.box2dJoint}}class Box2dTargetJoint extends Box2dJoint{constructor(a,b,c){a.setAwake();const d=new box2d.instance.b2MouseJointDef;d.set_bodyA(b.body);d.set_bodyB(a.body);d.set_target(box2dTemp(c));d.set_maxForce(2e3*a.getMass());super(d)}setTarget(a){this.box2dJoint.SetTarget(box2dTemp(a))}getTarget(){return box2d.vec2From(this.box2dJoint.GetTarget())}setMaxForce(a){this.box2dJoint.SetMaxForce(a);box2dWakeJoint(this.box2dJoint)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setFrequency(a){this.box2dJoint.SetFrequency(max(box2dFinite(a,0),.001));box2dWakeJoint(this.box2dJoint)}getFrequency(){return this.box2dJoint.GetFrequency()}}class Box2dDistanceJoint extends Box2dJoint{constructor(a,b,c,d,e=!1){c||=box2d.vec2From(a.body.GetPosition());d||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c),g=b.worldToLocal(d),h=new box2d.instance.b2DistanceJointDef;h.set_bodyA(a.body);h.set_bodyB(b.body);h.set_localAnchorA(box2dTemp(f));h.set_localAnchorB(box2dTemp(g));h.set_length(c.distance(d));h.set_collideConnected(e);super(h)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setLength(a){this.box2dJoint.SetLength(a);box2dWakeJoint(this.box2dJoint)}getLength(){return this.box2dJoint.GetLength()}setFrequency(a){this.box2dJoint.SetFrequency(a);box2dWakeJoint(this.box2dJoint)}getFrequency(){return this.box2dJoint.GetFrequency()}setDampingRatio(a){this.box2dJoint.SetDampingRatio(a);box2dWakeJoint(this.box2dJoint)}getDampingRatio(){return this.box2dJoint.GetDampingRatio()}}class Box2dRopeJoint extends Box2dJoint{constructor(a,b,c,d,e=0,f=!1){c||=box2d.vec2From(a.body.GetPosition());d||=box2d.vec2From(b.body.GetPosition());const g=a.worldToLocal(c),h=b.worldToLocal(d),k=new box2d.instance.b2RopeJointDef;k.set_bodyA(a.body);k.set_bodyB(b.body);k.set_localAnchorA(box2dTemp(g));k.set_localAnchorB(box2dTemp(h));k.set_maxLength(c.distance(d)+e);k.set_collideConnected(f);super(k)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setMaxLength(a){this.box2dJoint.SetMaxLength(a);box2dWakeJoint(this.box2dJoint)}getMaxLength(){return this.box2dJoint.GetMaxLength()}}class Box2dRevoluteJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2RevoluteJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2dTemp(e));f.set_localAnchorB(box2dTemp(c));f.set_referenceAngle(b.body.GetAngle()-a.body.GetAngle());f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getReferenceAngle(){return-this.box2dJoint.GetReferenceAngle()}getJointAngle(){return-this.box2dJoint.GetJointAngle()}getJointSpeed(){return-this.box2dJoint.GetJointSpeed()}isLimitEnabled(){return this.box2dJoint.IsLimitEnabled()}enableLimit(a=!0){this.box2dJoint.EnableLimit(a)}getLowerLimit(){return-this.box2dJoint.GetUpperLimit()}getUpperLimit(){return-this.box2dJoint.GetLowerLimit()}setLimits(a,b){a=box2dFinite(a,0);b=box2dFinite(b,0);a>b&&([a,b]=[b,a]);this.box2dJoint.SetLimits(-b,-a)}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){this.box2dJoint.SetMotorSpeed(-a)}getMotorSpeed(){return-this.box2dJoint.GetMotorSpeed()}setMaxMotorTorque(a){this.box2dJoint.SetMaxMotorTorque(a)}getMaxMotorTorque(){return this.box2dJoint.GetMaxMotorTorque()}getMotorTorque(a=timeDelta){return-this.box2dJoint.GetMotorTorque(1/a)}}class Box2dPinJoint extends Box2dRevoluteJoint{constructor(a,b,c=a.pos,d=!1){super(a,b,c,d)}}class Box2dGearJoint extends Box2dJoint{constructor(a,b,c,d,e=1){const f=c instanceof Box2dRevoluteJoint===d instanceof Box2dRevoluteJoint?1:-1,g=new box2d.instance.b2GearJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_joint1(c.box2dJoint);g.set_joint2(d.box2dJoint);g.set_ratio(e*f);super(g);this.joint1=c;this.joint2=d;this.ratioSign=f;box2dGearJoints.add(this)}getJoint1(){return this.joint1}getJoint2(){return this.joint2}setRatio(a){this.box2dJoint.SetRatio(a*this.ratioSign);box2dWakeJoint(this.box2dJoint)}getRatio(){return this.box2dJoint.GetRatio()*this.ratioSign}}class Box2dPrismaticJoint extends Box2dJoint{constructor(a,b,c,d=vec2(0,1),e=!1){c||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c);c=b.worldToLocal(c);d=a.worldToLocalVector(d);const g=new box2d.instance.b2PrismaticJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_localAnchorA(box2dTemp(f));g.set_localAnchorB(box2dTemp(c));g.set_localAxisA(box2dTemp(d));g.set_referenceAngle(b.body.GetAngle()-a.body.GetAngle());g.set_collideConnected(e);super(g)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getLocalAxisA(){return box2d.vec2From(this.box2dJoint.GetLocalAxisA())}getReferenceAngle(){return-this.box2dJoint.GetReferenceAngle()}getJointTranslation(){return this.box2dJoint.GetJointTranslation()}getJointSpeed(){return this.box2dJoint.GetJointSpeed()}isLimitEnabled(){return this.box2dJoint.IsLimitEnabled()}enableLimit(a=!0){this.box2dJoint.EnableLimit(a)}getLowerLimit(){return this.box2dJoint.GetLowerLimit()}getUpperLimit(){return this.box2dJoint.GetUpperLimit()}setLimits(a,b){a=box2dFinite(a,0);b=box2dFinite(b,0);a>b&&([a,b]=[b,a]);this.box2dJoint.SetLimits(a,b)}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){this.box2dJoint.SetMotorSpeed(a)}getMotorSpeed(){return this.box2dJoint.GetMotorSpeed()}setMaxMotorForce(a){this.box2dJoint.SetMaxMotorForce(a)}getMaxMotorForce(){return this.box2dJoint.GetMaxMotorForce()}getMotorForce(a=timeDelta){return this.box2dJoint.GetMotorForce(1/a)}}class Box2dWheelJoint extends Box2dJoint{constructor(a,b,c,d=vec2(0,1),e=!1){c||=box2d.vec2From(b.body.GetPosition());const f=a.worldToLocal(c);c=b.worldToLocal(c);d=a.worldToLocalVector(d).normalize();const g=new box2d.instance.b2WheelJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_localAnchorA(box2dTemp(f));g.set_localAnchorB(box2dTemp(c));g.set_localAxisA(box2dTemp(d));g.set_collideConnected(e);super(g)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getLocalAxisA(){return box2d.vec2From(this.box2dJoint.GetLocalAxisA())}getJointTranslation(){return this.box2dJoint.GetJointTranslation()}getJointSpeed(){return-this.box2dJoint.GetJointSpeed()}isMotorEnabled(){return this.box2dJoint.IsMotorEnabled()}enableMotor(a=!0){this.box2dJoint.EnableMotor(a)}setMotorSpeed(a){this.box2dJoint.SetMotorSpeed(-a)}getMotorSpeed(){return-this.box2dJoint.GetMotorSpeed()}setMaxMotorTorque(a){this.box2dJoint.SetMaxMotorTorque(a)}getMaxMotorTorque(){return this.box2dJoint.GetMaxMotorTorque()}getMotorTorque(a=timeDelta){return-this.box2dJoint.GetMotorTorque(1/a)}setSpringFrequencyHz(a){this.box2dJoint.SetSpringFrequencyHz(a);box2dWakeJoint(this.box2dJoint)}getSpringFrequencyHz(){return this.box2dJoint.GetSpringFrequencyHz()}setSpringDampingRatio(a){this.box2dJoint.SetSpringDampingRatio(a);box2dWakeJoint(this.box2dJoint)}getSpringDampingRatio(){return this.box2dJoint.GetSpringDampingRatio()}}class Box2dWeldJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=b.body.GetAngle()-a.body.GetAngle(),g=new box2d.instance.b2WeldJointDef;g.set_bodyA(a.body);g.set_bodyB(b.body);g.set_localAnchorA(box2dTemp(e));g.set_localAnchorB(box2dTemp(c));g.set_referenceAngle(f);g.set_collideConnected(d);super(g);this.referenceAngle=-f}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}getReferenceAngle(){return this.referenceAngle}setFrequency(a){this.box2dJoint.SetFrequency(a);box2dWakeJoint(this.box2dJoint)}getFrequency(){return this.box2dJoint.GetFrequency()}setDampingRatio(a){this.box2dJoint.SetDampingRatio(a);box2dWakeJoint(this.box2dJoint)}getDampingRatio(){return this.box2dJoint.GetDampingRatio()}}class Box2dFrictionJoint extends Box2dJoint{constructor(a,b,c,d=!1){c||=box2d.vec2From(b.body.GetPosition());const e=a.worldToLocal(c);c=b.worldToLocal(c);const f=new box2d.instance.b2FrictionJointDef;f.set_bodyA(a.body);f.set_bodyB(b.body);f.set_localAnchorA(box2dTemp(e));f.set_localAnchorB(box2dTemp(c));f.set_collideConnected(d);super(f)}getLocalAnchorA(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorA())}getLocalAnchorB(){return box2d.vec2From(this.box2dJoint.GetLocalAnchorB())}setMaxForce(a){this.box2dJoint.SetMaxForce(max(box2dFinite(a,0),0))}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(max(box2dFinite(a,0),0))}getMaxTorque(){return this.box2dJoint.GetMaxTorque()}}class Box2dPulleyJoint extends Box2dJoint{constructor(a,b,c,d,e,f,g=1,h=!1){e||=box2d.vec2From(a.body.GetPosition());f||=box2d.vec2From(b.body.GetPosition());const k=a.worldToLocal(e),l=b.worldToLocal(f),m=new box2d.instance.b2PulleyJointDef;m.set_bodyA(a.body);m.set_bodyB(b.body);m.set_groundAnchorA(box2dTemp(c));m.set_groundAnchorB(box2dTemp(d));m.set_localAnchorA(box2dTemp(k));m.set_localAnchorB(box2dTemp(l));m.set_ratio(box2dFinite(g,1)||1);m.set_lengthA(c.distance(e));m.set_lengthB(d.distance(f));m.set_collideConnected(h);super(m)}getGroundAnchorA(){return box2d.vec2From(this.box2dJoint.GetGroundAnchorA())}getGroundAnchorB(){return box2d.vec2From(this.box2dJoint.GetGroundAnchorB())}getLengthA(){return this.box2dJoint.GetLengthA()}getLengthB(){return this.box2dJoint.GetLengthB()}getRatio(){return this.box2dJoint.GetRatio()}getCurrentLengthA(){return this.box2dJoint.GetCurrentLengthA()}getCurrentLengthB(){return this.box2dJoint.GetCurrentLengthB()}}class Box2dMotorJoint extends Box2dJoint{constructor(a,b){const c=a.worldToLocal(box2d.vec2From(b.body.GetPosition())),d=b.body.GetAngle()-a.body.GetAngle(),e=new box2d.instance.b2MotorJointDef;e.set_bodyA(a.body);e.set_bodyB(b.body);e.set_linearOffset(box2dTemp(c));e.set_angularOffset(d);super(e)}setLinearOffset(a){this.box2dJoint.SetLinearOffset(box2dTemp(a))}getLinearOffset(){return box2d.vec2From(this.box2dJoint.GetLinearOffset())}setAngularOffset(a){this.box2dJoint.SetAngularOffset(-a)}getAngularOffset(){return-this.box2dJoint.GetAngularOffset()}setMaxForce(a){this.box2dJoint.SetMaxForce(max(box2dFinite(a,0),0));box2dWakeJoint(this.box2dJoint)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(max(box2dFinite(a,0),0));box2dWakeJoint(this.box2dJoint)}getMaxTorque(){return this.box2dJoint.GetMaxTorque()}setCorrectionFactor(a){this.box2dJoint.SetCorrectionFactor(clamp(a));box2dWakeJoint(this.box2dJoint)}getCorrectionFactor(){return this.box2dJoint.GetCorrectionFactor()}}class Box2dPlugin{constructor(a){box2d=this;this.instance=a;this.world=new box2d.instance.b2World;this.objects=[];this.velocityIterations=8;this.positionIterations=3;this.bodyTypeStatic=a.b2_staticBody;this.bodyTypeKinematic=a.b2_kinematicBody;this.bodyTypeDynamic=a.b2_dynamicBody;a=new box2d.instance.JSDestructionListener;a.SayGoodbyeJoint=function(b){const c=box2dJoints.get(b);c&&(box2dDestroyGears(c),c.box2dJoint=0);box2dJoints.delete(b)};a.SayGoodbyeFixture=function(){};box2d.world.SetDestructionListener(a);a=new box2d.instance.JSContactListener;a.BeginContact=function(b){var c=box2d.instance.wrapPointer(b,box2d.instance.b2Contact);b=c.GetFixtureA();const d=c.GetFixtureB(),e=b.GetBody().object,f=d.GetBody().object;e&&f&&(c=box2dImpactSpeed(c),e.beginContact(f,b,d,c),f.beginContact(e,d,b,c))};a.EndContact=function(b){var c=box2d.instance.wrapPointer(b,box2d.instance.b2Contact);b=c.GetFixtureA();c=c.GetFixtureB();const d=b.GetBody().object,e=c.GetBody().object;d&&e&&(d.endContact(e,b,c),e.endContact(d,c,b))};a.PreSolve=function(){};a.PostSolve=function(){};box2d.world.SetContactListener(a)}step(a=1){if(gravity.x!==box2dGravity.x||gravity.y!==box2dGravity.y){box2dGravity.x=gravity.x;box2dGravity.y=gravity.y;box2d.world.SetGravity(box2dTemp(gravity));for(let b=box2d.world.GetBodyList();!box2d.isNull(b);b=b.GetNext())b.SetAwake(!0)}for(;a--;)box2d.world.Step(timeDelta,this.velocityIterations,this.positionIterations),box2dRunPending();this.objects=this.objects.filter(b=>!b.destroyed)}raycastAll(a,b,c=!1){var d=Math.fround;const e=d(d(b.x)-d(a.x)),f=d(d(b.y)-d(a.y));d=d(d(e*e)+d(f*f));if(!(0d))return[];d=box2dQueryObject("rayCast","JSRayCastCallback");d.ReportFixture=function(h,k,l,m){h=box2d.instance.wrapPointer(h,box2d.instance.b2Fixture);const n=h.GetBody().object;if(!n||n.destroyed)return 1;if(!c&&h.IsSensor())return-1;k=box2d.vec2FromPointer(k);l=box2d.vec2FromPointer(l);g.push(new Box2dRaycastResult(h,k,l,m));return 1};const g=[];box2d.world.RayCast(d,box2dTemp(a),box2dTemp(b,1));g.sort((h,k)=>h.fraction-k.fraction);debugRaycast&&debugLine(a,b,g.length?"#f00":"#00f",.02,0,!1);return g}raycast(a,b,c=!1){return box2d.raycastAll(a,b,c)[0]}boxCastAll(a,b,c=!1){const d=box2dQueryObject("query","JSQueryCallback");d.ReportFixture=function(g){g=box2d.instance.wrapPointer(g,box2d.instance.b2Fixture);if(!c&&g.IsSensor())return!0;const h=g.GetBody().object;h&&!h.destroyed&&!f.includes(h)&&box2dFixtureOverlaps(g,e)&&f.push(h);return!0};const e=box2dQueryObject("aabb","b2AABB");e.set_lowerBound(box2dTemp(a.subtract(b.scale(.5))));e.set_upperBound(box2dTemp(a.add(b.scale(.5))));let f=[];box2d.world.QueryAABB(d,e);debugRaycast&&debugRect(a,b,f.length?"#f00":"#00f",0,0,!1,!1);return f}boxCast(a,b,c=!1){const d=box2dQueryObject("query","JSQueryCallback");d.ReportFixture=function(g){g=box2d.instance.wrapPointer(g,box2d.instance.b2Fixture);if(!c&&g.IsSensor())return!0;const h=g.GetBody().object;if(!h||h.destroyed||!box2dFixtureOverlaps(g,e))return!0;f=h;return!1};const e=box2dQueryObject("aabb","b2AABB");e.set_lowerBound(box2dTemp(a.subtract(b.scale(.5))));e.set_upperBound(box2dTemp(a.add(b.scale(.5))));let f;box2d.world.QueryAABB(d,e);debugRaycast&&debugRect(a,b,f?"#f00":"#00f",0,0,!1,!1);return f}circleCastAll(a,b,c=!1){const d=(b/2)**2,e=box2d.objects.filter(f=>!f.destroyed&&f.body&&f.pos.distanceSquared(a)!g.IsSensor())));debugRaycast&&debugCircle(a,b,e.length?"#f00":"#00f",0,!1,!1);return e}circleCast(a,b,c=!1){let d,e;for(const f of box2d.circleCastAll(a,b,c))if(b=f.pos.distanceSquared(a),!d||b{d=box2d.instance.wrapPointer(d,box2d.instance.b2Color);return new Color(d.get_r(),d.get_g(),d.get_b())},c=(d,e)=>{const f=[];for(;e--;)f.push(box2d.vec2FromPointer(d+8*e));return f};a.DrawSegment=function(d,e,f){f=b(f).scale(1,.8);d=box2d.vec2FromPointer(d);e=box2d.vec2FromPointer(e);drawLine(d,e,.1,f,vec2(),0,!1,!1)};a.DrawPolygon=function(d,e,f){f=b(f).scale(1,.8);d=c(d,e);drawPoly(d,CLEAR_WHITE,.1,f,vec2(),0,!1,!1)};a.DrawSolidPolygon=function(d,e,f){f=b(f).scale(1,.8);d=c(d,e);drawPoly(d,f,0,f,vec2(),0,!1,!1)};a.DrawCircle=function(d,e,f){f=b(f).scale(1,.8);d=box2d.vec2FromPointer(d);drawCircle(d,2*e,CLEAR_WHITE,.1,f,!1,!1)};a.DrawSolidCircle=function(d,e,f,g){g=b(g).scale(1,.8);d=box2d.vec2FromPointer(d);f=box2d.vec2FromPointer(f).scale(e);drawCircle(d,2*e,g,.1,g,!1,!1);drawLine(vec2(),f,.1,g,d,0,!1,!1)};a.DrawTransform=function(d){d=box2d.instance.wrapPointer(d,box2d.instance.b2Transform);const e=box2d.vec2From(d.get_p());d=-d.get_q().GetAngle();const f=vec2(1,0),g=rgb(.75,0,0,.8),h=vec2(0,1),k=rgb(0,.75,0,.8);drawLine(vec2(),f,.1,g,e,d,!1,!1);drawLine(vec2(),h,.1,k,e,d,!1,!1)};a.AppendFlags(box2d.instance.b2Draw.e_shapeBit);a.AppendFlags(box2d.instance.b2Draw.e_jointBit);box2d.world.SetDebugDraw(a)})();engineAddPlugin(function(){if(paused||!timeScale)box2d.objects=box2d.objects.filter(a=>!a.destroyed);else{box2d.step();for(const a of box2d.objects)if(a.body){debug&&box2dCheckUnusedFields(a);const b=a.body.GetPosition();a.pos.set(b.get_x(),b.get_y());a.angle=-a.body.GetAngle()}}},function(){(box2dDebug||debugPhysics)&&box2d.world.DrawDebugData()});return box2d}function drawNineSliceScreen(a,b,c,d=WHITE,e=32,f,g=2,h=0,k=!1,l){drawNineSlice(a,b,c,d,e,f,g,h,k,!0,l)}function drawNineSlice(a,b,c,d,e,f,g,h=0,k=glEnable,l=drawScreenSpace,m){e??=l?32:1;g??=l?2:.05;if(b.x&&b.y){d&&1>d.a&&(g=0);var n=c.size.add(vec2(2*c.padding));if(l&&!h)drawSliceSnapped(a,b,e,(x,w)=>[c.offset(n.multiply(vec2(x,w))),0],d,f,k,m);else{e=min(e,abs(b.x)/2,abs(b.y)/2);var r=c.offset(n),q=b.add(vec2(g-2*e));g=vec2(e);b=b.scale(.5).subtract(g.scale(.5));var p=l?-1:1,t=l?-h:h;drawTile(a,q,r,d,h,!1,f,k,l,m);for(var u=4;u--;){var v=u%2,y=b.multiply(vec2(v?1===u?1:-1:0,v?0:u?-1:1));v=vec2(v?e:q.x,v?q.y:e);const x=r.offset(n.multiply(vec2(1===u?1:3===u?-1:0,0===u?-p:2===u?p:0)));drawTile(a.add(y.rotate(t)),v,x,d,h,!1,f,k,l,m)}for(e=4;e--;)u=1e,q=b.multiply(vec2(u?-1:1,y?-1:1)),u=r.offset(n.multiply(vec2(u?-1:1,y?p:-p))),drawTile(a.add(q.rotate(t)),g,u,d,h,!1,f,k,l,m)}}}function drawThreeSliceScreen(a,b,c,d=WHITE,e=32,f,g=2,h=0,k=!1,l){drawThreeSlice(a,b,c,d,e,f,g,h,k,!0,l)}function drawThreeSlice(a,b,c,d,e,f,g,h=0,k=glEnable,l=drawScreenSpace,m){e??=l?32:1;g??=l?2:.05;if(b.x&&b.y){d&&1>d.a&&(g=0);var n=c.frame(0),r=c.frame(1),q=c.frame(2);if(l&&!h){const y=[[0,0,1],[3,-1,1],[3,2,2]];drawSliceSnapped(a,b,e,(x,w)=>{const z=y[w][x];return 0>z?[q,0]:[1!==x&&1!==w?n:r,z*PI/2]},d,f,k,m)}else{e=min(e,abs(b.x)/2,abs(b.y)/2);var p=b.add(vec2(g-2*e));c=vec2(e);b=b.scale(.5).subtract(c.scale(.5));g=l?-1:1;var t=l?-h:h;drawTile(a,p,q,d,h,!1,f,k,l,m);for(var u=4;u--;){const y=h+u*PI/2;var v=u%2;const x=b.multiply(vec2(v?1===u?1:-1:0,v?0:u?-g:g));v=vec2(v?p.y:p.x,e);drawTile(a.add(x.rotate(t)),v,r,d,y,!1,f,k,l,m)}for(e=4;e--;)p=h+e*PI/2,u=b.multiply(vec2(!e||2{var y=max(1,round(c*abs(u)));p=round((p-t/2)*u+v);var x=p+round(t*u);t=min(p,x);p=max(p,x);x=min(t+y,floor((t+p)/2));y=[t,x,max(p-y,x),p];return(0>u?y.reverse():y).map(w=>(w-v)/u)};k=l(a.x,b.x,m,r);a=l(a.y,b.y,n,q);for(b=3;b--;)for(l=3;l--;){const p=k[l+1]-k[l],t=a[b+1]-a[b];if(0>=p||0>=t)continue;const[u,v]=d(l,b),y=round(v/(PI/2))%2,x=vec2(k[l]+p/2-.5,a[b]+t/2-.5);drawTile(x,y?vec2(t,p):vec2(p,t),u,e,v,!1,f,g,!0,h)}}function drawCrescent(a,b=1,c=0,d=WHITE,e=0,f=!1,g=0,h=BLACK,k=glEnable,l=drawScreenSpace,m){b=getCrescentPoints(vec2(),b,c,0,f);drawPoly(b,d,g,h,a,e,k,l,m)}function getCrescentPoints(a,b=1,c=0,d=0,e=!1,f=glCircleSides){c=mod(4*c,4);2<=c&&(d+=PI);c=2>=c?c-1:3-c;e&&(c=-c,d+=PI);e=[];f=max(3,f>>1);b/=2;for(var g=0;g<=f;g++){var h=g/f*PI;e.push(vec2(b*cos(h),b*sin(h)).rotate(d).add(a))}for(g=f;0<=g;g--)h=g/f*PI,e.push(vec2(b*cos(h),-b*c*sin(h)).rotate(d).add(a));return e}let textureSheetSize=2048,textureSheetPadding=1,textureSheets=[],textureSheetQueue=Promise.resolve(),textureSheetPendingCount=0;const textureSheetLoaded=new Map,textureSheetLoadKey=(...a)=>a.map(b=>isVector2(b)?b.x+","+b.y:String(b)).join("|"),textureSheetLoadFailed=(a,b)=>textureSheetLoaded.get(a)===b&&textureSheetLoaded.delete(a);class TextureSheet{constructor(a=textureSheetSize){this.size=a;this.context=headlessMode?void 0:createCanvasContext(a);this.canvas=this.context?.canvas;this.textureInfo=new TextureInfo(this.canvas);this.cursor=vec2();this.rowHeight=0;this.glDirty=!1;headlessMode&&(this.textureInfo.size=vec2(a),this.textureInfo.sizeInverse=vec2(1/a))}tryAdd(a,b,c=textureSheetPadding,d=0){var e=isNumber(d)?vec2(d):d;b||=a.subtract(e.scale(2));var f=b.x+2*c;d=b.y+2*c;var g=this.size/f|0,h=a.x/(b.x+2*e.x)|0;if(e=h*(a.y/(b.y+2*e.y)|0))if(a=min(h,g),f*=a,d*=ceil(e/a),g=this.cursor.x,h=this.cursor.y,e=this.rowHeight,g+f>this.size&&(g=0,h+=e,e=0),!(h+d>this.size))return this.cursor.x=g+f,this.cursor.y=h,this.rowHeight=max(e,d),new TileInfo(vec2(g+c,h+c),b,this.textureInfo,c,0,a)}drawImage(a,b,c=!0,d=0){d=isNumber(d)?vec2(d):d;const e=b.size,f=e.x+2*d.x,g=e.y+2*d.y,h=a.width/f|0;var k=h*(a.height/g|0);const l=b.columns||k,m=e.x+2*b.padding,n=e.y+2*b.padding;for(;k--;)this.context.drawImage(a,k%h*f+d.x,(k/h|0)*g+d.y,e.x,e.y,b.pos.x+k%l*m,b.pos.y+(k/l|0)*n,e.x,e.y);this.glDirty=!0;c&&this.updateTexture()}updateTexture(){this.glDirty&&(this.glDirty=!1,this.textureInfo.createWebGLTexture())}}function loadSprite(a,b,c=textureSheetPadding,d=0){isNumber(b)&&(b=vec2(b));const e=textureSheetLoadKey("sprite",a,b,c,d);if(!headlessMode&&textureSheetLoaded.has(e))return textureSheetLoaded.get(e);const f=new TileInfo(vec2(),vec2(),void 0,c,0);if(headlessMode)return f;textureSheetLoaded.set(e,f);f.textureInfo=(textureSheets[0]||textureSheetCreate()).textureInfo;const g=new Image,h=new Promise(k=>{g.onerror=g.onload=k;g.crossOrigin="anonymous";g.src=a});textureSheetQueueJob("loadSprite "+a,async()=>{await h;if(g.width){var k=vec2(g.width,g.height);(k=textureSheetAdd(k,b,c,d))?(Object.assign(f,k.tile),k.sheet.drawImage(g,f,!1,d)):console.warn("loadSprite image is too large to fit on a texture sheet:",a)}else console.warn("loadSprite failed to load image:",a),textureSheetLoadFailed(e,f)},()=>textureSheetLoadFailed(e,f));return f}function loadTiles(a,b=tileDefaultSize,c=textureSheetPadding){const d=isNumber(b)?vec2(b):b.copy(),e=textureSheetLoadKey("tiles",a.join("\n"),d,c);if(!headlessMode&&textureSheetLoaded.has(e))return textureSheetLoaded.get(e);const f=new TileInfo(vec2(),d,void 0,0,0);f.tiles=[];if(headlessMode)return f;textureSheetLoaded.set(e,f);f.textureInfo=(textureSheets[0]||textureSheetCreate()).textureInfo;for(const g of a){const h=new Image,k=new Promise(l=>{h.onerror=h.onload=l;h.crossOrigin="anonymous";h.src=g});textureSheetQueueJob("loadTiles "+g,async()=>{await k;var l=h.width/d.x|0,m=h.height/d.y|0;const n=l*m;l=n&&textureSheetAdd(vec2(l*d.x,m*d.y),d,c,0);h.width||textureSheetLoadFailed(e,f);if(!l)return console.warn("loadTiles: "+g+(n?" does not fit on a texture sheet":" failed to load, or is smaller than a tile")+", its tiles are left out");l.sheet.drawImage(h,l.tile,!1);for(m=0;mtextureSheetLoadFailed(e,f))}return f}function loadAtlas(a,b,c=textureSheetPadding){const d="object"===typeof b?void 0:textureSheetLoadKey("atlas",a,b,c);if(!headlessMode&&textureSheetLoaded.has(d))return textureSheetLoaded.get(d);const e={};if(headlessMode)return e;d&&textureSheetLoaded.set(d,e);const f="object"===typeof b?Promise.resolve(b):fetch(b).then(k=>k.ok&&k.json()).catch(()=>{}),g=new Image,h=new Promise(k=>{g.onerror=g.onload=k;g.crossOrigin="anonymous";g.src=a});textureSheetQueueJob("loadAtlas "+a,async()=>{var k=await f;await h;if(g.width&&k)for(const m of parseAtlas(k)){if(!m.frames.length)continue;k=m.frames[0].sourceSize;var l=vec2(k.x*m.frames.length,k.y);l=textureSheetAdd(l,k,c);if(!l){console.warn("loadAtlas frames are too large to fit on a texture sheet:",m.name);continue}const{sheet:n,tile:r}=l,q=n.context,p=k.x+2*c,t=k.y+2*c;m.frames.forEach((u,v)=>{const y=r.pos.x+v%r.columns*p+u.offset.x;v=r.pos.y+(v/r.columns|0)*t+u.offset.y;u.rotated?(q.save(),q.translate(y,v),q.rotate(-PI/2),q.drawImage(g,u.pos.x,u.pos.y,u.size.y,u.size.x,-u.size.y,0,u.size.y,u.size.x),q.restore()):q.drawImage(g,u.pos.x,u.pos.y,u.size.x,u.size.y,y,v,u.size.x,u.size.y)});n.glDirty=!0;e[m.name]=r}else console.warn("loadAtlas failed to load:",a,b),textureSheetLoadFailed(d,e)},()=>textureSheetLoadFailed(d,e));return e}function textureSheetQueueJob(a,b,c){++textureSheetPendingCount;textureSheetQueue=textureSheetQueue.then(async()=>{try{await b()}catch(d){console.error(a+" failed:",d),c?.()}finally{if(!--textureSheetPendingCount)for(const d of textureSheets)try{d.updateTexture()}catch(e){console.error("texture sheet upload failed:",e)}}})}function parseAtlas(a){var b=(isArray(a.frames)?a.frames.map(f=>[f.filename,f]):Object.entries(a.frames)).map(([f,g])=>({name:f.replace(/\.[^.\\/]+$/,""),pos:vec2(g.frame.x,g.frame.y),size:vec2(g.frame.w,g.frame.h),offset:vec2(g.spriteSourceSize?.x??0,g.spriteSourceSize?.y??0),sourceSize:vec2(g.sourceSize?.w??g.frame.w,g.sourceSize?.h??g.frame.h),rotated:!!g.rotated}));const c=[];a=a.meta?.frameTags;if(a?.length){const f=new Set;for(var d of a){a=max(0,floor(d.from)||0);var e=min(b.length-1,floor(d.to)||0);for(c.push({name:d.name,frames:b.slice(a,e+1)});a<=e;++a)f.add(a)}b.forEach((g,h)=>f.has(h)||c.push({name:g.name,frames:[g]}));return parseAtlasNamesCheck(c)}d=new Map;for(e of b)(b=e.name.match(/^(.+?)([-_ /])?(\d+)$/))&&!b[2]&&/\d$/.test(b[1])&&(b=void 0),a=b?b[1]:e.name,e.groupIndex=b?Number(b[3]):void 0,d.has(a)||d.set(a,[]),d.get(a).push(e);for(const[f,g]of d)g.sort((h,k)=>h.groupIndex-k.groupIndex),1h.groupIndex===g[0].groupIndex+k)&&g.every(h=>h.sourceSize.x===g[0].sourceSize.x&&h.sourceSize.y===g[0].sourceSize.y)?c.push({name:f,frames:g}):g.forEach(h=>c.push({name:h.name,frames:[h]}));return parseAtlasNamesCheck(c)}function parseAtlasNamesCheck(a){const b=new Set;for(const{name:c}of a)b.has(c)?console.warn(`parseAtlas: two sprites are named ${c}, the second takes the first's place`):b.add(c);return a}async function spritesReady(){for(;textureSheetPendingCount;)await textureSheetQueue}function textureSheetCreate(){const a=new TextureSheet;textureSheets.push(a);return a}function textureSheetAdd(a,b,c,d){let e;for(f of textureSheets)if(e=f.tryAdd(a,b,c,d))break;if(!e){var f={size:textureSheetSize,cursor:vec2(),rowHeight:0};if(!TextureSheet.prototype.tryAdd.call(f,a,b,c,d))return;f=textureSheetCreate();e=f.tryAdd(a,b,c,d)}return{sheet:f,tile:e}}function setTextureSheetSize(a){textureSheetSize=a}function setTextureSheetPadding(a){textureSheetPadding=a}const tweenActive=[],tweenUpdateList=[];let tweenUpdatePass=0;function tweenActivate(a){a.activePass=tweenUpdatePass;a.active||(a.active=!0,a.listed||tweenActive.push(a),a.listed=!0)}function tweenDeactivate(a){a.active=!1}function tweenCall(a,b,c){try{a.callback(a.interp(b))}catch(d){throw a.active&&(void 0===c||a.activePasstweenLoopContinuation(this);return this}pingPong(a=Infinity){this.loopRemaining=a;this.thenCallback=()=>tweenPingPongContinuation(this);return this}pause(){this.paused=!0}resume(){this.paused=!1}restart(){this.life=this.duration;this.paused=!1;this.lastTime=time;this.lastTimeReal=timeReal;tweenActivate(this);tweenCall(this,this.duration)}isActive(){return!this.paused&&this.active}getPercent(){return percent(this.duration-this.life,0,this.duration)}getValue(){return this.interp(this.life)}interp(a){const b=this.start,c=this.end;if(0>=a)return"function"===typeof c.copy?c.copy():c;a=this.ease((this.duration-a)/this.duration);const d=1-a;return b instanceof Vector2?vec2(c.x*a+b.x*d,c.y*a+b.y*d):"undefined"!==typeof Vector3&&b instanceof Vector3?vec3(c.x*a+b.x*d,c.y*a+b.y*d,c.z*a+b.z*d):tweenIsLerpable(b)?b.lerp(c,a):b+(c-b)*a}stop(){tweenDeactivate(this);this.thenCallback=void 0}}const Ease={LINEAR:a=>a,POWER:a=>b=>b**a,SINE:a=>1-cos(PI/2*a),CIRC:a=>1-(1-a*a)**.5,EXPO:a=>0===a?0:2**(10*a-10),BACK:a=>a*a*(2.70158*a-1.70158),ELASTIC:a=>0===a?0:1===a?1:-(2**(10*a-10))*sin((37-40*a)*PI/6),SPRING:a=>1-(sin(PI*(1-a)*(.2+2.5*(1-a)**3))*a**2.2+(1-a))*(1+1.2*a),BOUNCE:a=>{a=1-a;return 1-(a<4/11?7.5625*a*a:a<8/11?7.5625*(a-=6/11)*a+.75:a<10/11?7.5625*(a-=9/11)*a+.9375:7.5625*(a-=10.5/11)*a+.984375)},IN:a=>a,OUT:a=>b=>1-a(1-b),IN_OUT:a=>Ease.PIECEWISE(a,Ease.OUT(a)),PIECEWISE:(...a)=>{const b=a.length;return c=>{const d=c*b-1e-9>>0;return(a[d]((c-d/b)*b)+d)/b}},BEZIER:(a,b,c,d)=>{const e=f=>{var g=1-f;const h=3*g*g*f;g=3*g*f*f;f**=3;return[h*a+g*c+f,h*b+g*d+f]};return f=>{if(0>=f)return 0;if(1<=f)return 1;let g=0,h=1;for(let k=32;k--;){const l=(g+h)/2;e(l)[0]{if(a.destroyed)return void k?.stop();let m=a;for(const n of g)m=m[n];m[h]=l},c,d,e,f);k.target=a;return k}function tweenCarryOvershoot(a){const b=a.duration;a.life=0tweenLoopContinuation(a))}function tweenPingPongContinuation(a){const b=tweenPassed(a),c=a.loopRemaining<=b,d=c?max(a.loopRemaining-1,0):b;if(d&1){const e=a.start;a.start=a.end;a.end=e}return c?(d&1&&a.callback(a.interp(0)),!1):tweenNextIteration(a,b,()=>tweenPingPongContinuation(a))}function tweenUpdate(a,b){const c=void 0===a;c||void 0!==b||(b=a);const d=tweenUpdateList.length?[]:tweenUpdateList,e=++tweenUpdatePass;let f=0;for(const h of tweenActive)h.active?d.push(tweenActive[f++]=h):h.listed=!1;tweenActive.length=f;let g;try{for(let h=d.length;h--;){const k=d[h];try{tweenStep(k,e,c,a,b)}catch(l){g??={error:l}}}}finally{d.length=0}if(g)throw g.error}function tweenStep(a,b,c,d,e){if(a.active&&!(a.activePass>=b))if(c?(c=a.useRealTime?timeReal-a.lastTimeReal:time-a.lastTime,a.lastTime=time,a.lastTimeReal=timeReal):c=a.useRealTime?e:d,a.target?.destroyed)a.stop();else if(!(a.paused||0>=c))if(a.life-=c,1e-9=b||(tweenDeactivate(a),b=a.thenCallback,a.thenCallback=void 0,b&&b()||!a.onComplete)))a.onComplete()}function tweenStopAll(){for(const a of tweenActive)a.thenCallback=void 0,a.active=a.listed=!1;tweenActive.length=0}engineAddPlugin(tweenUpdate);let sceneCurrent,sceneLeaving=!1,scenePluginAdded=!1;function setScene(a){scenePluginAdded||(scenePluginAdded=!0,engineAddPlugin(sceneUpdate,sceneRenderPost,void 0,void 0,sceneRender));if(sceneCurrent){sceneLeaving=!0;try{sceneCurrent.leave?.()}finally{sceneLeaving=!1}}engineObjectsDestroy();sceneCurrent=a;a?.enter?.()}function getScene(){return sceneCurrent}function sceneUpdate(){paused||!timeScale||sceneCurrent?.update?.()}function sceneRender(){sceneCurrent?.render?.()}function sceneRenderPost(){sceneCurrent?.renderPost?.()}class ParallaxLayer extends CanvasLayer{constructor(a=vec2(),b=vec2(32,16),c=.5,d=-1e3,e=parallaxMountains(),f=vec2(512,256)){super(a,b,0,d,f);this.castShadow=!1;this.parallax=isVector2(c)?c.copy():vec2(c);this.wrapX=!0;this.wrapY=!1;this.zoomFollow=1;this.zoomScale=cameraScale;this.drawFunction=e;this.redraw()}redraw(){const a=this.context;if(a){var b=vec2(this.canvas.width,this.canvas.height);a.clearRect(0,0,b.x,b.y);this.drawFunction(a,b,this);this.updateWebGL()}}zoomFactor(){return 1>this.zoomFollow&&0{if(!(m&&0c.float()&&(h=c.float(-d,d));c=e[a]-e[0];for(d=0;d<=a;++d)e[d]=clamp(e[d]-c*d/a,0,b);return e}function parallaxMountains(a=hsl(.6,.2,.6),b=hsl(.6,.3,.25),c){return(d,e)=>{var f=e.x;e=e.y;var g=new RandomGenerator(void 0===c?randInt(1e9)+1:7919*c+1);g=parallaxRidge(f,e,g);const h=createCanvasContext(1,e);for(let k=e;k--;)h.fillStyle=a.lerp(b,k/e).toString(),h.fillRect(0,k,1,1);for(;f--;)g[f]a||0>b||a>=this.size.x||b>=this.size.y?null:this.nodes[a+b*this.size.x]}worldToTile(a){const b=this.tileLayer?this.tileLayer.pos.y:0;return vec2(floor(a.x-(this.tileLayer?this.tileLayer.pos.x:0)),floor(a.y-b))}tileToWorld(a,b){return vec2(a+.5+(this.tileLayer?this.tileLayer.pos.x:0),b+.5+(this.tileLayer?this.tileLayer.pos.y:0))}buildNodeData(){this.nodeDataBuilt=!0;const a=this.size.x,b=this.size.y,c=this.tileLayer?this.tileLayer.pos.x:0,d=this.tileLayer?this.tileLayer.pos.y:0;for(let e=0;el.f{let m=l.heapIndex;for(;m;){const n=m-1>>1;if(!f(l,e[n]))break;(e[m]=e[n]).heapIndex=m;m=n}(e[m]=l).heapIndex=m};const g=()=>{const l=e[0],m=e.pop();if(m!==l){let r=0;for(;;){var n=2*r+1;const q=n+1;if(n>=e.length)break;n=qa){this.searchGaveUp=!b.parent;break}g();l.isOpen=!1;l.isClosed=!0;this.debug&&0=m;++m)for(let n=-1;1>=n;++n){if(0===n&&0===m)continue;const r=this.getNode(l.pos.x+n,l.pos.y+m);if(!r||!r.walkable||r.isClosed)continue;var k=1;if(0!==n&&0!==m){k=this.getNode(l.pos.x+n,l.pos.y);if(!k||!k.walkable)continue;k=this.getNode(l.pos.x,l.pos.y+m);if(!k||!k.walkable)continue;k=PATHFINDER_DIAGONAL_COST}k=l.g+k+r.cost;if(!r.isOpen)r.isOpen=!0,r.heapIndex=e.length,e.push(r),c.push(r);else if(k>=r.g)continue;r.parent=l;r.g=k;k=abs(b.pos.x-r.pos.x);const q=abs(b.pos.y-r.pos.y);k=max(k,q)+(Math.SQRT2-1)*min(k,q);r.h=k;r.f=r.g+k*this.heuristicWeight;d(r)}}return null!==b.parent}getNearestClearNode(a,b=10,c=!0){!c&&this.nodeDataBuilt||this.buildNodeData();return pathFinderNearestNode(this,a,b,d=>d.isClear())}smoothPathCorners(a){if(!(2>=a.length))for(var b=1;b=a.length)){var b=a.slice(),c=b.length-1,d=[];for(var e=1;eb[k].isClear()&&this.isLineClear(b[h].pos,b[k].pos);f=d.length-1;for(g=c+1;0<=f&&d[f]>h+1&&!e(d[f]);)g=d[f--];f=0<=f&&d[f]>h+1?d[f]:h+1;for(--g;g>f;--g)if(e(g)){f=g;break}}a.push(b[f]);h=f}}}dropCollinearNodes(a){if(!(3>a.length)){var b=1;for(let c=1;cd.walkable;a=pathFinderNearestNode(this,a,10,c);b=pathFinderNearestNode(this,b,10,c);if(!a||!b)return[];if(a===b)return[a.posWorld.copy()];if(!this.aStarSearch(a,b))return[];for(a=[];b;b=b.parent)a.push(b);a.reverse();this.smoothPath&&(this.smoothPathCorners(a),this.smoothPathStringPull(a),this.dropCollinearNodes(a));b=a.map(d=>d.posWorld.copy());if(this.debug&&0=h)break;for(k=-m;k<=m;++k)for(let n=-m,r=abs(k)===m?1:2*m;n<=m;n+=r){const q=a.getNode(f+n,e+k);if(!q||!d(q))continue;var l=q.posWorld.x-b.x;const p=q.posWorld.y-b.y;l=l*l+p*p;if(!g||l=a)return new Vector3;b=clamp(b/a);return randVector3(a*rand(b**3,1)**(1/3))}class Vector3{constructor(a=0,b=0,c=0){this.x=a;this.y=b;this.z=c}set(a=0,b=0,c=0){this.x=a;this.y=b;this.z=c;return this}setFrom(a){return this.set(a.x,a.y,a.z)}copy(){return new Vector3(this.x,this.y,this.z)}add(a){return new Vector3(this.x+a.x,this.y+a.y,this.z+a.z)}subtract(a){return new Vector3(this.x-a.x,this.y-a.y,this.z-a.z)}multiply(a){return new Vector3(this.x*a.x,this.y*a.y,this.z*a.z)}divide(a){return new Vector3(this.x/a.x,this.y/a.y,this.z/a.z)}scale(a){return new Vector3(this.x*a,this.y*a,this.z*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2+this.z**2}reflect(a,b=1){return this.subtract(a.scale((1+b)*this.dot(a)))}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2+(this.z-a.z)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector3}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this.copy()}dot(a){return this.x*a.x+this.y*a.y+this.z*a.z}cross(a){return new Vector3(this.y*a.z-this.z*a.y,this.z*a.x-this.x*a.z,this.x*a.y-this.y*a.x)}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}rotate(a,b){const c=cos(b);b=sin(b);const d=a.dot(this)*(1-c);return this.scale(c).add(a.cross(this).scale(b)).add(a.scale(d))}rotateX(a){const b=cos(a);a=sin(a);return new Vector3(this.x,this.y*b-this.z*a,this.y*a+this.z*b)}rotateY(a){const b=cos(a);a=sin(a);return new Vector3(this.x*b+this.z*a,this.y,this.z*b-this.x*a)}rotateZ(a){const b=cos(a);a=sin(a);return new Vector3(this.x*b-this.y*a,this.x*a+this.y*b,this.z)}abs(){return new Vector3(abs(this.x),abs(this.y),abs(this.z))}floor(){return new Vector3(floor(this.x),floor(this.y),floor(this.z))}round(){return new Vector3(round(this.x),round(this.y),round(this.z))}snap(a){return new Vector3(floor(this.x*a)/a,floor(this.y*a)/a,floor(this.z*a)/a)}transform(a){return a.transformPoint(this)}transformDirection(a){return a.transformDirection(this)}isValid(){return isNumber(this.x)&&isNumber(this.y)&&isNumber(this.z)}toString(a=3){if(!this.isValid())return`(${this.x},${this.y},${this.z})`;const b=c=>(0>c?"":" ")+c.toFixed(a);return`(${b(this.x)},${b(this.y)},${b(this.z)} )`}}const matrix4Scratch=new Float32Array(16);class Matrix4{constructor(a){this.m=new Float32Array(16);a?this.m.set(a):this.m[0]=this.m[5]=this.m[10]=this.m[15]=1}static identity(){return new Matrix4}static translation(a){const b=new Matrix4;b.m[12]=a.x;b.m[13]=a.y;b.m[14]=a.z;return b}static rotation(a,b=new Matrix4){matrix4RotationAt(b.m,0,a);return b}static scaling(a){const b=new Matrix4;b.m[0]=a.x;b.m[5]=a.y;b.m[10]=a.z;return b}static perspective(a,b,c,d){a=1/tan(a/2);const e=new Matrix4,f=e.m;f[0]=a/b;f[5]=a;f[10]=Infinity==d?-1:(d+c)/(c-d);f[11]=-1;f[14]=Infinity==d?-2*c:2*d*c/(c-d);f[15]=0;return e}static orthographic(a,b,c,d,e,f){const g=new Matrix4,h=g.m;h[0]=2/(b-a);h[5]=2/(d-c);h[10]=-2/(f-e);h[12]=-(b+a)/(b-a);h[13]=-(d+c)/(d-c);h[14]=-(f+e)/(f-e);return g}static lookAt(a,b,c=vec3(0,1,0)){b=a.subtract(b).normalize();b.lengthSquared()||(b=vec3(0,0,1));c=c.cross(b).normalize();c.lengthSquared()||(c=(.99d;++d)for(let e=0;4>e;++e)c[4*d+e]=b[e]*a[4*d]+b[4+e]*a[4*d+1]+b[8+e]*a[4*d+2]+b[12+e]*a[4*d+3];this.m.set(c);return this}translate(a){return this.multiply(Matrix4.translation(a))}rotate(a){return this.multiply(Matrix4.rotation(a))}scale(a){return this.multiply(Matrix4.scaling(a))}transpose(){const a=this.m;for(let b=0;4>b;++b)for(let c=b+1;4>c;++c){const d=a[4*b+c];a[4*b+c]=a[4*c+b];a[4*c+b]=d}return this}invert(){const a=this.m,[b,c,d,e,f,g,h,k,l,m,n,r,q,p,t,u]=a,v=b*g-c*f,y=b*h-d*f,x=b*k-e*f,w=c*h-d*g,z=c*k-e*g,A=d*k-e*h,C=l*p-m*q,D=l*t-n*q,B=l*u-r*q,E=m*t-n*p,F=m*u-r*p,G=n*u-r*t;let H=v*G-y*F+x*E+w*B-z*D+A*C;if(!H)return this;H=1/H;a[0]=(g*G-h*F+k*E)*H;a[1]=(d*F-c*G-e*E)*H;a[2]=(p*A-t*z+u*w)*H;a[3]=(n*z-m*A-r*w)*H;a[4]=(h*B-f*G-k*D)*H;a[5]=(b*G-d*B+e*D)*H;a[6]=(t*x-q*A-u*y)*H;a[7]=(l*A-n*x+r*y)*H;a[8]=(f*F-g*B+k*C)*H;a[9]=(c*B-b*F-e*C)*H;a[10]=(q*z-p*x+u*v)*H;a[11]=(m*x-l*z-r*v)*H;a[12]=(g*D-f*E-h*C)*H;a[13]=(b*E-c*D+d*C)*H;a[14]=(p*y-q*w-t*v)*H;a[15]=(l*w-m*y+n*v)*H;return this}transformPoint(a){const b=this.m;return new Vector3(b[0]*a.x+b[4]*a.y+b[8]*a.z+b[12],b[1]*a.x+b[5]*a.y+b[9]*a.z+b[13],b[2]*a.x+b[6]*a.y+b[10]*a.z+b[14])}transformDirection(a){const b=this.m;return new Vector3(b[0]*a.x+b[4]*a.y+b[8]*a.z,b[1]*a.x+b[5]*a.y+b[9]*a.z,b[2]*a.x+b[6]*a.y+b[10]*a.z)}getTranslation(){return new Vector3(this.m[12],this.m[13],this.m[14])}determinant(){const a=this.m;return a[0]*(a[5]*a[10]-a[6]*a[9])-a[4]*(a[1]*a[10]-a[2]*a[9])+a[8]*(a[1]*a[6]-a[2]*a[5])}getScale(){var a=this.m;const b=hypot(a[0],a[1],a[2]),c=hypot(a[4],a[5],a[6]);a=hypot(a[8],a[9],a[10]);return new Vector3(0>this.determinant()?-b:b,c,a)}getRotation(){const a=this.m;var b=this.getScale();const c=b.x||1,d=b.y||1;var e=b.z||1;b=a[1]/c;const f=a[5]/d,g=a[8]/e,h=a[9]/e;e=a[10]/e;const k=hypot(g,e),l=atan2(-h,k);return 1e-9c;++c)b+=`[${a[c].toFixed(2).padStart(7)} ${a[4+c].toFixed(2).padStart(7)} ${a[8+c].toFixed(2).padStart(7)} ${a[12+c].toFixed(2).padStart(7)} ]\n`;return b}}function buildMatrix(a,b,c,d=new Matrix4){matrix4Compose(d.m,0,a,b,c);return d}function matrix4RotationAt(a,b,c){const d=cos(c.x),e=sin(c.x),f=cos(c.y),g=sin(c.y),h=cos(c.z);c=sin(c.z);a[b]=f*h+g*e*c;a[b+1]=d*c;a[b+2]=-g*h+f*e*c;a[b+3]=0;a[b+4]=-f*c+g*e*h;a[b+5]=d*h;a[b+6]=g*c+f*e*h;a[b+7]=0;a[b+8]=g*d;a[b+9]=-e;a[b+10]=f*d;a[b+11]=0;a[b+12]=a[b+13]=a[b+14]=0;a[b+15]=1}function matrix4Compose(a,b,c,d,e){const f=e?e.x:1,g=e?e.y:1;e=e?e.z:1;if(d&&(d.x||d.y||d.z)){const h=cos(d.x),k=sin(d.x),l=cos(d.y),m=sin(d.y),n=cos(d.z);d=sin(d.z);a[b]=(l*n+m*k*d)*f;a[b+1]=h*d*f;a[b+2]=(-m*n+l*k*d)*f;a[b+4]=(-l*d+m*k*n)*g;a[b+5]=h*n*g;a[b+6]=(m*d+l*k*n)*g;a[b+8]=m*h*e;a[b+9]=-k*e;a[b+10]=l*h*e}else a[b]=f,a[b+1]=0,a[b+2]=0,a[b+4]=0,a[b+5]=g,a[b+6]=0,a[b+8]=0,a[b+9]=0,a[b+10]=e;a[b+3]=a[b+7]=a[b+11]=0;a[b+15]=1;a[b+12]=c?c.x:0;a[b+13]=c?c.y:0;a[b+14]=c?c.z:0}class Ray3D{constructor(a=vec3(),b=vec3(0,0,-1)){this.origin=a;this.direction=b}getPosition(a){return this.origin.add(this.direction.scale(a))}copy(){return new Ray3D(this.origin.copy(),this.direction.copy())}}const isTurned3D=a=>!!a&&!!(a.x||a.y||a.z);function boxAxes3D(a){a=buildMatrix(void 0,a).m;return[vec3(a[0],a[1],a[2]),vec3(a[4],a[5],a[6]),vec3(a[8],a[9],a[10])]}function boxLocal3D(a,b,c){a=a.subtract(b);return vec3(a.dot(c[0]),a.dot(c[1]),a.dot(c[2]))}const boxWorld3D=(a,b)=>b[0].scale(a.x).add(b[1].scale(a.y)).add(b[2].scale(a.z));function isPointInBox3D(a,b,c,d){return isTurned3D(d)?isPointInBox3D(boxLocal3D(a,b,boxAxes3D(d)),vec3(),c):abs(a.x-b.x)<=c.x/2&&abs(a.y-b.y)<=c.y/2&&abs(a.z-b.z)<=c.z/2}function isOverlapping3D(a,b,c,d=vec3(),e,f){if(isTurned3D(e)||isTurned3D(f))return!!collideBoxBox3D(a,b,c,d,e,f);a=a.subtract(c);return abs(a.x)<(b.x+d.x)/2&&abs(a.y)<(b.y+d.y)/2&&abs(a.z)<(b.z+d.z)/2}function collideSphereSphere(a,b,c,d){a=a.subtract(c);b+=d;d=a.length();if(!(d>=b))return d?a.normalize(b-d):vec3(0,b,0)}function collideSphereBox(a,b,c,d,e){if(isTurned3D(e))return collideSphereOrientedBox3D(a,b,c,d,boxAxes3D(e));d=d.scale(.5);e=vec3(clamp(a.x,c.x-d.x,c.x+d.x),clamp(a.y,c.y-d.y,c.y+d.y),clamp(a.z,c.z-d.z,c.z+d.z));e=a.subtract(e);const f=e.lengthSquared();if(f)return f>=b*b?void 0:e.normalize(b-f**.5);a=a.subtract(c);return pushOutAxis3D(a,d.x-abs(a.x),d.y-abs(a.y),d.z-abs(a.z),b)}function collideSphereInBox(a,b,c,d){const e=max(0,d.x/2-b),f=max(0,d.y/2-b);b=max(0,d.z/2-b);a=vec3(clamp(a.x,c.x-e,c.x+e)-a.x,clamp(a.y,c.y-f,c.y+f)-a.y,clamp(a.z,c.z-b,c.z+b)-a.z);return a.lengthSquared()?a:void 0}function pushOutAxis3D(a,b,c,d,e=0){return b<=c&&b<=d?vec3((0<=a.x?1:-1)*(b+e),0,0):c<=d?vec3(0,(0<=a.y?1:-1)*(c+e),0):vec3(0,0,(0<=a.z?1:-1)*(d+e))}function collideSphereCylinder(a,b,c,d,e){var f=e/2;e=a.x-c.x;const g=a.z-c.z,h=a.y-c.y,k=(e**2+g**2)**.5,l=k?min(k,d)/k:0;c=vec3(c.x+e*l,clamp(a.y,c.y-f,c.y+f),c.z+g*l);a=a.subtract(c);if(c=a.lengthSquared())return c>=b*b?void 0:a.normalize(b-c**.5);d-=k;f-=abs(h);return d<=f?(k?vec3(e/k,0,g/k):vec3(1,0,0)).scale(d+b):vec3(0,(0<=h?1:-1)*(f+b),0)}function collideBoxBox3D(a,b,c,d,e,f){if(isTurned3D(e)||isTurned3D(f))return collideOrientedBoxes3D(a,b,boxAxes3D(e),c,d,boxAxes3D(f));a=a.subtract(c);c=(b.x+d.x)/2-abs(a.x);e=(b.y+d.y)/2-abs(a.y);b=(b.z+d.z)/2-abs(a.z);if(!(0>=c||0>=e||0>=b))return pushOutAxis3D(a,c,e,b)}function collideSphereOrientedBox3D(a,b,c,d,e){return(a=collideSphereBox(boxLocal3D(a,c,e),b,vec3(),d))&&boxWorld3D(a,e)}const BOX_WORLD_AXES=Object.freeze([vec3(1,0,0),vec3(0,1,0),vec3(0,0,1)]);function collideOrientedBoxes3D(a,b,c,d,e,f){const g=a.subtract(d),h=b.scale(.5),k=e.scale(.5),l=(r,q,p)=>r.x*abs(q[0].dot(p))+r.y*abs(q[1].dot(p))+r.z*abs(q[2].dot(p));let m,n=Infinity;a=(r,q)=>{var p=r.lengthSquared();if(1e-12>p)return!1;r=r.scale(p**-.5);p=g.dot(r);const t=l(h,c,r)+l(k,f,r)-abs(p);if(0>=t)return!0;t*qp?-t:t));return!1};for(const r of[...c,...f])if(a(r,1))return;for(const r of c)for(const q of f)if(a(r.cross(q),1.05))return;return m}function raycastSphere(a,b,c){const{origin:d,direction:e}=a;a=d.x-b.x;var f=d.y-b.y;b=d.z-b.z;const g=a*a+f*f+b*b-c*c;if(0>g)return 0;if(c=e.dot(e))if(a=2*(a*e.x+f*e.y+b*e.z),f=a*a-4*c*g,!(0>f))return a=(-a-f**.5)/(2*c),0<=a?a:void 0}function raycastPlane(a,b,c){const{origin:d,direction:e}=a;a=e.dot(c);if(!(1e-9>abs(a)))return b=b.subtract(d).dot(c)/a,0>b?void 0:b}function raycastBox(a,b,c,d){if(isTurned3D(d)){var e=boxAxes3D(d);d=a.direction;d=vec3(d.dot(e[0]),d.dot(e[1]),d.dot(e[2]));return raycastBox(new Ray3D(boxLocal3D(a.origin,b,e),d),vec3(),c)}const{origin:f,direction:g}=a;c=c.scale(.5);a=b.subtract(c);b=b.add(c);c=0;d=Infinity;for(e of"xyz"){var h=f[e];const l=g[e];var k=a[e];const m=b[e];if(l){if(k=(k-h)/l,h=(m-h)/l,k>h&&([k,h]=[h,k]),c=max(c,k),d=min(d,h),c>d)return}else if(hm)return}return c}let render3D;const RENDER3D_VERTEX_FLOATS=9,RENDER3D_VERTEX_BYTES=4*RENDER3D_VERTEX_FLOATS,RENDER3D_INSTANCE_FLOATS=24,RENDER3D_INSTANCE_BYTES=4*RENDER3D_INSTANCE_FLOATS,RENDER3D_MATRIX_FLOATS=16,RENDER3D_COLOR_FLOATS=8,RENDER3D_INSTANCE_ATTRIBS=[[4,4,0],[5,4,16],[6,4,32],[7,4,48],[11,4,64],[12,4,80]],RENDER3D_VERTEX_INPUTS="layout(location=0) in vec3 p;layout(location=1) in vec3 n;layout(location=2) in vec2 t;layout(location=3) in vec4 c;layout(location=4) in vec4 m0;layout(location=5) in vec4 m1;layout(location=6) in vec4 m2;layout(location=7) in vec4 m3;layout(location=11) in vec4 tint;layout(location=12) in vec4 uvRect;",RENDER3D_MAX_STREAM_VERTS=32768,RENDER3D_MAX_LIGHTS=8,RENDER3D_QUAD_UVS=Object.freeze([vec2(0,0),vec2(0,1),vec2(1,0),vec2(1,1)].map(a=>Object.freeze(a))),RENDER3D_FULL_UV_RECT=Object.freeze({x:0,y:0,w:1,h:1}),RENDER3D_DEFAULT_NORMAL=Object.freeze(vec3(0,1,0)),RENDER3D_DEFAULT_UV=Object.freeze(vec2()),RENDER3D_SHADOW_COLOR=Object.freeze(hsl(0,0,0,.5)),RENDER3D_IDENTITY=new Matrix4;let render3DShadowCut;const render3DFogFadeValid=(a,b)=>!b||aa.determinant()}function render3DAxis(a,b){return vec3(a[b],a[b+1],a[b+2])}function render3DAxisRotation(a,b){const c=vec3(1,0,0).rotate(a,b),d=vec3(0,1,0).rotate(a,b);a=vec3(0,0,1).rotate(a,b);return new Matrix4([c.x,c.y,c.z,0,d.x,d.y,d.z,0,a.x,a.y,a.z,0,0,0,0,1])}function render3DMaxScale(a){return max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])**.5}function render3DMaxStretch(a,b=0){return render3DMaxStretchSquared(a,b)**.5}function render3DMaxStretchSquared(a,b=0){const c=a[b]*a[b]+a[b+1]*a[b+1]+a[b+2]*a[b+2],d=a[b+4]*a[b+4]+a[b+5]*a[b+5]+a[b+6]*a[b+6],e=a[b+8]*a[b+8]+a[b+9]*a[b+9]+a[b+10]*a[b+10],f=abs(a[b]*a[b+4]+a[b+1]*a[b+5]+a[b+2]*a[b+6]),g=abs(a[b]*a[b+8]+a[b+1]*a[b+9]+a[b+2]*a[b+10]);a=abs(a[b+4]*a[b+8]+a[b+5]*a[b+9]+a[b+6]*a[b+10]);return max(c+f+g,d+f+a,e+g+a)}function render3DQuadAxes(a,b,c){return[a.subtract(b).add(c),a.subtract(b).subtract(c),a.add(b).add(c),a.add(b).subtract(c)]}function render3DSetObjectState(a){const b=render3D,c=a?.transparent;a=a?.drawOwner?render3DPartSettings(a):a;b.lighting=!0;b.emissive=a?.emissive||0;b.additive=!!a?.additive;b.specular=a?.specular||0;b.shininess=a?.shininess??16;b.reflectivity=a?.reflectivity||0;b.normalMap=a?.normalMap||void 0;b.normalScale=a?.normalScale??1;b.emissiveMap=a?.emissiveMap||void 0;b.emissiveMapColor=a?.emissiveMapColor||WHITE;b.environmentMap=a?.environment||void 0;b.receiveShadow=!a||a.receiveShadow;b.cullBackFaces=b.mirrored=!1;b.pixelated=!!a?.pixelated;b.shader=a?.shader||void 0;b.depthTest=!0;b.shadowPass&&(b.blend=!!c)}function render3DDrawObjects(a){for(const b of a)render3DSetObjectState(b),b.render3D();render3DSetObjectState()}function render3DInstance(a,b,c,d){const e=render3DInstanceSlot(a,render3DTextureOf(c),render3DMirrors(b));a=a.instanceData;a.set(b.m,e);a[e+16]=d.r;a[e+17]=d.g;a[e+18]=d.b;a[e+19]=d.a;b=render3DGetTileUVs(c);a[e+20]=b.x;a[e+21]=b.y;a[e+22]=b.w;a[e+23]=b.h}function render3DInstanceSlot(a,b,c,d=!1){const e=render3D;a.instanceCount&&(a.instanceTextureInfo!==b||a.instanceMirrored!==c||a.instanceUnlit!==d||render3DStateChanged(a.instanceState))&&render3DFlushInstances(a);a.instanceCount||(a.instanceTextureInfo=b,a.instanceMirrored=c,a.instanceUnlit=d,a.instanceState=render3DCaptureBatchState(),e.instanceMeshes.push(a));b=a.instanceData;c=a.instanceCount++*RENDER3D_INSTANCE_FLOATS;if(!b||b.lengtha||b.instanceMeshes.splice(a,1)):b.instanceMeshes.length=0}function render3DDrawInstanced(a,b,c,d,e,f){const g=glContext,h=4*RENDER3D_MATRIX_FLOATS;for(const[k,l,m]of RENDER3D_INSTANCE_ATTRIBS){const n=f&&m>=h,r=f?n?4*RENDER3D_COLOR_FLOATS:h:RENDER3D_INSTANCE_BYTES;g.bindBuffer(g.ARRAY_BUFFER,n?f:b);g.vertexAttribPointer(k,l,g.FLOAT,!1,r,n?m-h:m);g.enableVertexAttribArray(k);g.vertexAttribDivisor(k,1)}render3DSetDrawUniforms(RENDER3D_IDENTITY,d,WHITE,RENDER3D_FULL_UV_RECT,e);render3DBindMesh(a);g.drawElementsInstanced(g.TRIANGLES,a.bufferCount,a.indexType,0,c);for(const[k]of RENDER3D_INSTANCE_ATTRIBS)g.disableVertexAttribArray(k),g.vertexAttribDivisor(k,0);++drawCount;primitiveCount+=a.bufferCount/3*c}function render3DClearInstances(){for(const a of render3D.instanceMeshes)a.instanceCount=0;render3D.instanceMeshes.length=0}function render3DLayerObjects(a){return engineObjects.filter(b=>!b.destroyed&&b instanceof EngineObject3D&&render3DIsAfter2D(b)===a)}function render3DCollectLights(){const a=engineObjects.filter(c=>!c.destroyed&&c instanceof Light3D&&0RENDER3D_MAX_LIGHTS){var b=render3D.camera.pos;const c=new Map;for(const d of a)c.set(d,d.directional?-1:d.getWorldPos3D().distanceSquared(b));a.sort((d,e)=>c.get(d)-c.get(e));(b=render3DShadowCaster())&&a.indexOf(b)>=RENDER3D_MAX_LIGHTS&&(a[RENDER3D_MAX_LIGHTS-1]=b);a.length=RENDER3D_MAX_LIGHTS}return a}function render3DShadowCaster(){const a=render3D.shadowLight;return a&&!a.destroyed&&!a.directional&&0abs(a.x)+abs(a.z)?vec3(0=c||-1>d))return vec3((b[0]*a.x+b[4]*a.y+b[8]*a.z+b[12])/c,(b[1]*a.x+b[5]*a.y+b[9]*a.z+b[13])/c,d)}worldToScreen(a,b=mainCanvasSize){if(a=this.worldToClip(a))return vec2((a.x+1)/2*b.x,(1-a.y)/2*b.y)}screenToRay(a,b=mainCanvasSize){var c=b.x||1,d=b.y||1,e=c/d;b=this.camera;this.updateMatrices(e);c=a.x/c*2-1;a=1-a.y/d*2;d=b.orthographic?b.orthographic/2:tan(b.fov/2);e=this.cameraRight.scale(c*d*e).add(this.cameraUp.scale(a*d));return b.orthographic?new Ray3D(b.pos.add(e).add(this.cameraForward.scale(b.near)),this.cameraForward.copy()):new Ray3D(b.pos.copy(),this.cameraForward.add(e).normalize())}screenToGround(a,b=0,c=mainCanvasSize){a=this.screenToRay(a,c);b=raycastPlane(a,vec3(0,b,0),RENDER3D_DEFAULT_NORMAL);return void 0===b?void 0:a.getPosition(b)}pick(a,b=engineObjects){a=a instanceof Ray3D?a:this.screenToRay(a);let c;for(const d of b)b=render3DRaycastObject(a,d),void 0!==b&&(!c||b=h)return;const l=h*a.taper;k>l&&(c*=percent(k,h,l))}a=a.play(void 0,c,d,e,f,g);a?.setPan(b.normalize().dot(this.cameraRight));return a}playSoundLoop(a,b,c=1,d=1,e=1){return this.playSound(a,b,c,d,e,!0)}isSphereVisible(a,b){return render3DSphereVisible(a.x,a.y,a.z,b)}drawMesh(a,b=RENDER3D_IDENTITY,c,d=WHITE){b=render3DMatrix(b);if(this.capture)return void this.capture.combine(a,b,d);if(this.transparentQueue){const f=b.copy(),g=d.copy();return this.queueTransparent(f.getTranslation(),()=>this.drawMesh(a,f,c,g))}if(render3DCanDraw()&&(!this.shadowPass||this.lighting)&&(render3DMeshUpload(a),a.bufferCount)){var e=b.m;if(!this.frustumCulling||render3DSphereVisible(e[12],e[13],e[14],a.radius*render3DMaxStretch(e)))if(!this.blend&&this.depthTest&&(a.instanced??this.instancing))render3DInstance(a,b,c,d);else{e=this.cullBackFaces;const f=this.mirrored;this.cullBackFaces=!a.doubleSided;this.mirrored=render3DMirrors(b);this.flush();render3DFlushBeforeOverlay();render3DSetDrawUniforms(b,c,d);render3DBindMesh(a);glContext.drawElements(glContext.TRIANGLES,a.bufferCount,a.indexType,0);++drawCount;primitiveCount+=a.bufferCount/3;this.cullBackFaces=e;this.mirrored=f}}}drawStrip(a,b,c,d,e){if(this.capture)this.capture.addStrip(a,b,c,d);else{if(this.transparentQueue){var f=0,g=0,h=0;for(var k of a)f+=k.x,g+=k.y,h+=k.z;return this.queueTransparent(vec3(f,g,h).scale(1/a.length),()=>this.drawStrip(a,b,c,d,e))}f=a.length;g=render3DStripCount(f);if(h=render3DBeginStrip(g,e)){k=this.streamFloats;var l=this.streamInts,m=isArray(b),n=isArray(c),r=isArray(d),q=r?0:(d||WHITE).rgbaInt();for(let p=0;pthis.drawStrip(a,b,c,d,e))}flush(){if(this.streamCount&&render3DCanDraw()){var a=glContext;this.streamUnlit&&(this.streamState.lighting=!1);render3DSetDrawUniforms(RENDER3D_IDENTITY,this.streamTileInfo,WHITE,RENDER3D_FULL_UV_RECT,this.streamState);render3DBindVertexBuffer(this.streamBuffer);a.bufferSubData(a.ARRAY_BUFFER,0,this.streamFloats,0,this.streamCount*RENDER3D_VERTEX_FLOATS);a.drawArrays(a.TRIANGLE_STRIP,0,this.streamCount);++drawCount;primitiveCount+=this.streamCount;this.streamCount=0}}bake(a){this.flush();const b=this.capture=new Mesh;try{a()}finally{this.capture=void 0}return b}renderStages(a,b=!0){const c=[],d=[];for(var e of a)(e.transparent||render3DSetting(e,"additive")?d:c).push(e);b&&(this.skyBox&&this.skyBox!==this.capturingCube||this.sky)&&this.drawSky();this.blend=!1;this.depthWrite=!0;e=(f,g)=>(f.drawOwner?render3DSetting(f,"renderOrder"):f.renderOrder)-(g.drawOwner?render3DSetting(g,"renderOrder"):g.renderOrder);c.sort(e);d.sort(e);render3DDrawObjects(c);b&&this.onRenderOpaque?.();this.flush();render3DFlushInstances();this.blend=!0;this.depthWrite=!1;this.transparentQueue=this.sortTransparent?[]:void 0;try{render3DDrawObjects(d);for(const f of a)if(f.softShadow){const g=render3DObjectMatrix(f);this.drawSoftShadow(g.getTranslation(),f.softShadow*render3DMaxScale(g.m),this.softShadowHeight)}b&&this.onRenderTransparent?.()}finally{this.flushTransparentQueue()}b&&!this.capturingCube&&render3DRenderDebug();this.flush();render3DSetObjectState();this.blend=!1;this.depthWrite=!0}queueTransparent(a,b){if(this.transparentQueue){var c=this.cameraForward,d=this.camera.pos;this.transparentQueue.push({distance:(a.x-d.x)*c.x+(a.y-d.y)*c.y+(a.z-d.z)*c.z,state:render3DCaptureBatchState(),draw:b})}else b()}flushTransparentQueue(){const a=this.transparentQueue;if(a){this.transparentQueue=void 0;a.sort((c,d)=>d.distance-c.distance);var b=render3DCaptureBatchState();try{for(const c of a)render3DApplyBatchState(c.state),c.draw()}finally{render3DApplyBatchState(b)}}}drawSky(){this.flush();if((!this.skyBox||this.skyBox===this.capturingCube||!render3DDrawSkyBox(this.skyBox))&&this.sky){var{near:a,far:b}=this.camera,c=Infinity==b?1e4*a:(a+b)/2;render3DWithState({lighting:!1,blend:!1,depthTest:!1,depthWrite:!1,fogEnd:0,shader:void 0,emissiveMap:void 0},()=>this.drawMesh(this.sky,buildMatrix(this.camera.pos,void 0,vec3(c))))}}updateShadowMatrix(){var a=render3DShadowCaster();if(a){var b=a.getWorldPos3D(),c=a.getForward3D();const g=.99this.drawBillboard(A,C,c,D,e,f))}var g=!this.shadowPass;if(!this.blend&&this.depthTest&&this.instancing){if(!(!render3DCanDraw()||this.shadowPass&&!this.lighting||this.frustumCulling&&!render3DSphereVisible(a.x,a.y,a.z,hypot(b.x,b.y)/2))){var h=this.billboardMesh,k=this.cameraBack,l=render3DGetTileUVs(c);render3DMeshUpload(h);b=render3DBillboardAxes(b,e,f);g=render3DInstanceSlot(h,render3DTextureOf(c),!1,g);h=h.instanceData;h[g]=2*b[0];h[g+1]=2*b[1];h[g+2]=2*b[2];h[g+3]=0;h[g+4]=2*b[3];h[g+5]=2*b[4];h[g+6]=2*b[5];h[g+7]=0;h[g+8]=k.x;h[g+9]=k.y;h[g+10]=k.z;h[g+11]=0;h[g+12]=a.x;h[g+13]=a.y;h[g+14]=a.z;h[g+15]=1;h[g+16]=d.r;h[g+17]=d.g;h[g+18]=d.b;h[g+19]=d.a;h[g+20]=l.x;h[g+21]=l.y;h[g+22]=l.w;h[g+23]=l.h}}else{var m=render3DBeginStrip(6,c,g);if(m){var n=render3DBillboardAxes(b,e,f);k=n[0];l=n[1];h=n[2];b=n[3];g=n[4];n=n[5];var r=a.x,q=a.y;a=a.z;var p=this.cameraBack;d=d.rgbaInt();var t=m.x,u=m.y,v=t+m.w;m=u+m.h;var y=this.streamFloats,x=this.streamInts,w=RENDER3D_VERTEX_FLOATS,z=this.streamCount*w;this.streamCount+=6;render3DWriteVertex(y,x,z,r-k+b,q-l+g,a-h+n,p,t,u,d);render3DWriteVertex(y,x,z+=w,r-k+b,q-l+g,a-h+n,p,t,u,d);render3DWriteVertex(y,x,z+=w,r-k-b,q-l-g,a-h-n,p,t,m,d);render3DWriteVertex(y,x,z+=w,r+k+b,q+l+g,a+h+n,p,v,u,d);render3DWriteVertex(y,x,z+=w,r+k-b,q+l-g,a+h-n,p,v,m,d);render3DWriteVertex(y,x,z+=w,r+k-b,q+l-g,a+h-n,p,v,m,d)}}}drawQuad(a,b,c,d,e,f=WHITE){this.transparentQueue&&(a=a.copy(),b=b.copy(),c=c.copy(),d=d.copy(),f=isArray(f)?f.map(g=>g.copy()):f.copy());this.drawStrip(render3DQuadStrip(a,b,c,d),render3DFaceNormal(a,b,c,d),RENDER3D_QUAD_UVS,render3DQuadValues(f),e)}drawTriangle(a,b,c,d=WHITE){this.transparentQueue&&(a=a.copy(),b=b.copy(),c=c.copy(),d=d.copy());this.drawStrip([a,b,c],render3DFaceNormal(a,b,c),void 0,d)}drawLine(a,b,c=.1,d=WHITE){this.drawRibbon([a,b],c,void 0,d)}drawRibbon(a,b=.1,c,d=WHITE,e){const f=a.length,g=[],h=c?[]:void 0,k=[],l=this.cameraForward;let m=vec3(1,0,0);const n=2a[0].distanceSquared(a[f-1]);for(let p=0;pthis.drawStrip(g,l.scale(-1),h,k,c))}drawSoftDisc(a,b=1,c=WHITE,d=this.cameraBack,e=16){render3DAssertBlending();if(this.transparentQueue&&!this.capture){const h=a.copy(),k=c.copy(),l=d.copy();return this.queueTransparent(h,()=>this.drawSoftDisc(h,b,k,l,e))}d=d.normalize();const f=(.9>abs(d.y)?vec3(0,1,0):vec3(1,0,0)).cross(d).normalize(),g=f.cross(d);render3DDrawSoftDisc(b/2,c,e,d,(h,k,l)=>vec3(a.x+(f.x*h+g.x*k)*l,a.y+(f.y*h+g.y*k)*l,a.z+(f.z*h+g.z*k)*l))}drawSoftShadow(a,b=1,c=0,d=RENDER3D_SHADOW_COLOR,e=.02){render3DAssertBlending();const f=isNumber(c)?()=>c:c.getHeight?(g,h)=>c.getHeight(g,h):c;if(this.transparentQueue&&!this.capture){const g=a.copy(),h=d.copy();return this.queueTransparent(vec3(g.x,f(g.x,g.z)+e,g.z),()=>this.drawSoftShadow(g,b,c,h,e))}render3DDrawSoftDisc(b/2,d,16,RENDER3D_DEFAULT_NORMAL,(g,h,k)=>{g=a.x+g*k;h=a.z+h*k;return vec3(g,f(g,h)+e,h)})}}function render3DAssertBlending(){}function render3DDrawSoftDisc(a,b,c,d,e){const f=[1,.9,.7,0],g=render3DCircle(c);for(let h=0;3>h;++h){const k=[],l=[],m=b.withAlpha(b.a*f[h]),n=b.withAlpha(b.a*f[h+1]),r=a*h/3,q=a*(h+1)/3;for(let p=0;p<=c;++p){const t=g[2*p],u=g[2*p+1];k.push(e(t,u,q),e(t,u,r));l.push(n,m)}render3D.drawStripUnlit(k,d,void 0,l)}}class Camera3D{constructor(){this.pos=vec3(0,0,10);this.rotation=vec3();this.fov=PI/3;this.near=.1;this.far=1e3;this.orthographic=0;this.align2D=!1;this.align2DZ=0}getMatrix(){return buildMatrix(this.pos,this.rotation)}getViewMatrix(){return this.getMatrix().invert()}getProjectionMatrix(a){const b=this.orthographic/2,c=b*a;return b?Matrix4.orthographic(-c,c,-b,b,this.near,this.far):Matrix4.perspective(this.fov,a,this.near,this.far)}getForward(){return render3DAxis(this.getMatrix().m,8).scale(-1)}getRight(){return render3DAxis(this.getMatrix().m,0)}getUp(){return render3DAxis(this.getMatrix().m,4)}lookAt(a){this.rotation=render3DLookRotation(a.subtract(this.pos),this.rotation)}orbit(a,b,c,d=.5){const e=cos(d)*b;this.pos=a.add(vec3(sin(c)*e,sin(d)*b,cos(c)*e));this.rotation=render3DLookRotation(a.subtract(this.pos),vec3(0,c,0))}follow(a,b,c=1){this.pos=this.pos.lerp(a.add(b),c);this.lookAt(a)}update2D(a=mainCanvasSize.y){a=a/2/cameraScale;const b=a/tan(this.fov/2);this.orthographic&&(this.orthographic=2*a);this.pos=vec3(cameraPos.x,cameraPos.y,this.align2DZ+b);this.rotation=vec3(0,0,-cameraAngle)}}const RENDER3D_ATTRIBS=[[0,3,5126,!1,0],[1,3,5126,!1,12],[2,2,5126,!1,24],[3,4,5121,!0,32]],RENDER3D_VERTEX_SOURCE="#version 300 es\nprecision highp float;uniform mat4 viewProj,lightViewProj;"+RENDER3D_VERTEX_INPUTS+"out vec3 P,N;out vec2 T,L;out vec4 C,S;void main(){vec4 w=mat4(m0,m1,m2,m3)*vec4(p,1.);gl_Position=viewProj*w;P=w.xyz;vec3 c0=m0.xyz,c1=m1.xyz,c2=m2.xyz;N=mat3(c0/max(dot(c0,c0),1e-20),c1/max(dot(c1,c1),1e-20),c2/max(dot(c2,c2),1e-20))*n;T=uvRect.xy+t*uvRect.zw;L=t;C=c*tint;S=lightViewProj*w;}",RENDER3D_SNIPPET_NAMES="uniform float iTime;uniform vec3 iResolution;\n#define iChannel0 tex\n#define localUV L\n#define worldPos P\n#define worldNormal N\n#define sunDirection (-lightDir.xyz)\n#define sunColor lightColor.rgb\n#define ambientColor ambientFog.rgb\n#define ambientGroundColor ambientGround.rgb\n#define lightCount extraLightCount\n#define lights extraLights\n#define lightColors extraLightColors\n";function render3DFragmentSource(a){const b=/\bmainNormal\s*\(/.test(a||"");return"#version 300 es\nprecision highp float;uniform vec4 lightDir,lightColor,ambientFog,ambientGround,fogColor,shadowParams,fogFade;uniform vec4 extraLights["+RENDER3D_MAX_LIGHTS+"],extraLightColors["+RENDER3D_MAX_LIGHTS+"];uniform vec4 extraLightCones["+RENDER3D_MAX_LIGHTS+"];uniform int extraLightCount;uniform vec3 cameraPos,cameraDir;uniform vec4 materialParams,emissiveTint,skyTop,skyHorizon,skyBottom,gelAxes;uniform sampler2D tex,normalTex,emissiveTex,gelTex;uniform samplerCube envMap;uniform vec4 envParams;uniform bool premultipliedTexture;uniform highp sampler2DShadow shadowMap;in vec3 P,N;in vec2 T,L;in vec4 C,S;out vec4 o;float shadow(){if(shadowParams.x<=0.||S.w<=0.)return 1.;vec3 q=S.xyz/S.w*.5+.5;if(any(greaterThanEqual(abs(q-.5),vec3(.5))))return 1.;q.z-=shadowParams.y/(S.w*S.w);float s=0.;for(int x=-1;x<=1;++x)for(int y=-1;y<=1;++y)s+=texture(shadowMap,vec3(q.xy+vec2(x,y)*shadowParams.z,q.z));return s/9.;}vec3 gel(){if(S.w<=0.)return vec3(1);vec2 g=S.xy/S.w,u=vec2(dot(gelAxes.xy,g),dot(gelAxes.zw,g))*.5+.5;return texture(gelTex,vec2(u.x,1.-u.y)).rgb;}vec3 normalMapNormal(vec3 n){vec3 p1=dFdx(P),p2=dFdy(P);vec2 t1=dFdx(T),t2=dFdy(T);vec3 a=cross(p2,n),b=cross(n,p1),u=a*t1.x+b*t2.x,v=a*t1.y+b*t2.y;float k=max(dot(u,u),dot(v,v));if(k<=0.)return n;vec3 m=texture(normalTex,T).xyz*2.-1.;m.xy*=materialParams.x;return normalize((u*m.x-v*m.y)*inversesqrt(k)+n*m.z);}"+(a?"void mainImage(out vec4,vec2);":"")+(b?"void mainNormal(inout vec3);":"")+"void main(){"+(a?"vec4 t;mainImage(t,T);":"vec4 t=texture(tex,T);")+"if(premultipliedTexture&&t.a>0.)t.rgb/=t.a;vec4 c=C*t;float e=lightDir.w;if(e<1.){vec3 n=dot(N,N)>0.?normalize(N):vec3(0,1,0);if(!gl_FrontFacing)n=-n;if(materialParams.x!=0.)n=normalMapNormal(n);"+(b?"mainNormal(n);n=normalize(n);":"")+"float nl=dot(n,-lightDir.xyz);float sh=shadow(),s=shadowParams.x<1.5?sh:1.;int si=int(shadowParams.x+.5)-2;vec3 l=(ambientGround.a>0.?mix(ambientGround.rgb,ambientFog.rgb,n.y*.5+.5):ambientFog.rgb)+lightColor.rgb*max(nl,0.)*s;vec3 eye=lightColor.a>0.?normalize(cameraPos-P):vec3(0),sp=vec3(0);for(int i=0;i<"+RENDER3D_MAX_LIGHTS+";++i){if(i>=extraLightCount)break;vec4 L=extraLights[i];bool directional=L.w<0.;vec3 v=directional?L.xyz:L.xyz-P;float d=length(v);float a=directional?1.:max(0.,1.-d/L.w);v/=max(d,1e-6);float ln=dot(n,v);vec3 lc=extraLightColors[i].rgb*extraLightColors[i].a*a*a;vec4 K=extraLightCones[i];float k=clamp(dot(K.xyz,-v)-K.w,0.,1.);lc*=k*k*(3.-2.*k);if(i==si)lc*=sh*gel();l+=lc*max(0.,ln);if(lightColor.a>0.)sp+=lc*pow(max(dot(reflect(-v,n),eye),0.),materialParams.y)*step(0.,ln);}c.rgb*=l*(1.-e)+e;if(lightColor.a>0.){vec3 r=reflect(lightDir.xyz,n);c.rgb+=lightColor.rgb*pow(max(dot(r,eye),0.),materialParams.y)*lightColor.a*step(0.,nl)*s*(1.-e)+sp*lightColor.a*(1.-e);}if(materialParams.z>0.){vec3 w=normalize(P-cameraPos),q=reflect(w,n);float f=materialParams.z+(1.-materialParams.z)*pow(clamp(1.-dot(n,-w),0.,1.),5.);c.rgb=mix(c.rgb,envParams.x>0.?textureLod(envMap,q,clamp(max(envParams.z-.5*log2(materialParams.y+2.),envParams.w+log2(max(max(length(dFdx(q)),length(dFdy(q))),1e-9))),0.,envParams.y)).rgb:q.y>0.?mix(skyHorizon.rgb,skyTop.rgb,q.y):mix(skyHorizon.rgb,skyBottom.rgb,-q.y),f);}}else c.rgb*=e;if(emissiveTint.a>0.)c.rgb+=texture(emissiveTex,T).rgb*emissiveTint.rgb;if(ambientFog.a>0.||fogFade.y>0.){float z=fogFade.z>0.?dot(P-cameraPos,cameraDir):distance(cameraPos,P);if(ambientFog.a>0.)c.rgb=mix(c.rgb,shadowParams.w<0.?vec3(0):fogColor.rgb,smoothstep(fogColor.a,ambientFog.a,z));if(fogFade.y>0.&&shadowParams.w<=0.)c.a*=clamp((fogFade.y-z)/(fogFade.y-fogFade.x),0.,1.);}if(shadowParams.w>0.&&t.a<.5)discard;o=vec4(c.rgb,shadowParams.w>0.?1.:c.a);}"+(a?"\n"+RENDER3D_SNIPPET_NAMES+a+"\n":"")}function render3DShaderProgram(a){a.program3D||glShaderTrack(a);a=a.program3D||(a.program3D=glCreateProgram(RENDER3D_VERTEX_SOURCE,render3DFragmentSource(a.fragmentCode)));return glFailedPrograms.has(a)?render3D.program:a}function render3DUseProgram(a){const b=glContext,c=render3D;b.useProgram(c.currentProgram=a);c.uniformValues={};b.uniformMatrix4fv(render3DUniform("viewProj"),!1,c.viewProjection.m);b.uniformMatrix4fv(render3DUniform("lightViewProj"),!1,c.shadowMatrix.m);b.uniform1i(render3DUniform("tex"),0);b.uniform1i(render3DUniform("shadowMap"),1);b.uniform1i(render3DUniform("normalTex"),2);b.uniform1i(render3DUniform("emissiveTex"),3);b.uniform1i(render3DUniform("gelTex"),4);b.uniform1i(render3DUniform("envMap"),5);b.uniform4fv(render3DUniform("gelAxes"),c.gelAxes);const d=c.camera.pos,e=c.cameraForward;b.uniform3f(render3DUniform("cameraPos"),d.x,d.y,d.z);b.uniform3f(render3DUniform("cameraDir"),e.x,e.y,e.z);b.uniform1i(render3DUniform("extraLightCount"),c.lightCount);c.lightCount&&(b.uniform4fv(render3DUniform("extraLights"),c.lightPositions,0,4*c.lightCount),b.uniform4fv(render3DUniform("extraLightColors"),c.lightColors,0,4*c.lightCount),b.uniform4fv(render3DUniform("extraLightCones"),c.lightCones,0,4*c.lightCount));a!==c.program&&(b.uniform1f(render3DUniform("iTime"),time),a=c.capturingCube?.size,b.uniform3f(render3DUniform("iResolution"),a||glCanvas.width,a||glCanvas.height,1))}function render3DInitGL(){if(!headlessMode)if(glEnable&&glContext){var a=glContext,b=render3D;glFlush();b.uniforms=new WeakMap;b.uniformValues={};render3DShadowCut=void 0;b.attribValues=[];b.program=glCreateProgram(RENDER3D_VERTEX_SOURCE,render3DFragmentSource());b.shadowShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 viewProj;"+RENDER3D_VERTEX_INPUTS+"out vec2 T;out float A;void main(){T=uvRect.xy+t*uvRect.zw;A=c.a*tint.a;gl_Position=viewProj*mat4(m0,m1,m2,m3)*vec4(p,1.);}","#version 300 es\nprecision highp float;uniform sampler2D tex;uniform float cut;in vec2 T;in float A;void main(){if(texture(tex,T).a*mix(1.,A,cut)<.5)discard;}");if(glFailedPrograms.has(b.program)||glFailedPrograms.has(b.shadowShader))console.error("Render3DPlugin: its shaders did not build on this device, so nothing 3D is drawn"),b.program=b.shadowShader=void 0;else{b.vao=a.createVertexArray();a.bindVertexArray(b.vao);for(const[c]of RENDER3D_ATTRIBS)a.enableVertexAttribArray(c);b.streamBuffer=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,b.streamBuffer);a.bufferData(a.ARRAY_BUFFER,b.streamData.byteLength,a.DYNAMIC_DRAW);b.streamCount=0;b.instanceBuffers=[a.createBuffer(),a.createBuffer(),a.createBuffer()];b.whiteTexture=glCreateTexture();b.samplers=new Map;b.samplerKey=void 0;render3DUpdateShadowMap(1);a.bindBuffer(a.ARRAY_BUFFER,glArrayBuffer);glSetInstancedMode(!0)}}else console.warn(glDeviceFailed?"Render3DPlugin: this device can not draw WebGL, so nothing 3D is drawn":"Render3DPlugin: WebGL not enabled, construct the plugin in gameInit with glEnable set")}class CubeMap{constructor(a,b){this.size=a;this.faces=b;this.glTexture=this.capturePos=void 0;this.contextGeneration=-1}capture(a){this.capturePos=a.copy();render3D.cubeCaptures.add(this)}dispose(){this.glTexture&&glContext?.deleteTexture(this.glTexture);this.glTexture=void 0;render3D?.cubeCaptures.delete(this)}}function makeCubeMap(a,b){const c=[];for(let d=0;6>d;++d){const e=new Uint8Array(a*a*4);for(let f=0;fnew Promise((e,f)=>{const g=new Image;g.crossOrigin="anonymous";g.onload=()=>e(g);g.onerror=()=>f(Error("loadCubeMap could not load "+d));g.src=d}))),c=b[0].width;if(!b.every(d=>d.width===c&&d.height===c))throw Error("loadCubeMap needs six square images of one size");a=[1,0,2,3,4,5].map(d=>{const e=createCanvasContext(c);e.scale(-1,1);e.drawImage(b[d],-c,0);return e.canvas});return new CubeMap(c,a)}function render3DCubeDirection(a,b,c){return(0===a?vec3(1,-c,-b):1===a?vec3(-1,-c,b):2===a?vec3(b,1,c):3===a?vec3(b,-1,-c):4===a?vec3(b,-c,1):vec3(-b,-c,-1)).normalize()}function render3DCubeTexture(a){const b=glContext;if(a&&b){if(a.glTexture&&a.contextGeneration===render3D.contextGeneration)return a.glTexture;var c=a.glTexture=b.createTexture();a.contextGeneration=render3D.contextGeneration;b.bindTexture(b.TEXTURE_CUBE_MAP,c);b.pixelStorei(b.UNPACK_FLIP_Y_WEBGL,!1);if(a.faces)a.faces.forEach((d,e)=>d instanceof Uint8Array?b.texImage2D(b.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,b.RGBA,a.size,a.size,0,b.RGBA,b.UNSIGNED_BYTE,d):b.texImage2D(b.TEXTURE_CUBE_MAP_POSITIVE_X+e,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,d));else{a.size=min(a.size,b.getParameter(b.MAX_CUBE_MAP_TEXTURE_SIZE),b.getParameter(b.MAX_RENDERBUFFER_SIZE));for(let d=0;6>d;++d)b.texImage2D(b.TEXTURE_CUBE_MAP_POSITIVE_X+d,0,b.RGBA,a.size,a.size,0,b.RGBA,b.UNSIGNED_BYTE,null);a.capturePos&&render3D.cubeCaptures.add(a)}b.texParameteri(b.TEXTURE_CUBE_MAP,b.TEXTURE_MIN_FILTER,b.LINEAR_MIPMAP_LINEAR);b.texParameteri(b.TEXTURE_CUBE_MAP,b.TEXTURE_MAG_FILTER,b.LINEAR);b.texParameteri(b.TEXTURE_CUBE_MAP,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_CUBE_MAP,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.generateMipmap(b.TEXTURE_CUBE_MAP);return c}}function render3DCubeFaceMatrix(a,b){const[c,d,e]=[[vec3(0,0,-1),vec3(0,-1,0),vec3(1,0,0)],[vec3(0,0,1),vec3(0,-1,0),vec3(-1,0,0)],[vec3(1,0,0),vec3(0,0,1),vec3(0,1,0)],[vec3(1,0,0),vec3(0,0,-1),vec3(0,-1,0)],[vec3(1,0,0),vec3(0,-1,0),vec3(0,0,1)],[vec3(-1,0,0),vec3(0,-1,0),vec3(0,0,-1)]][a];return new Matrix4([c.x,c.y,c.z,0,d.x,d.y,d.z,0,-e.x,-e.y,-e.z,0,b.x,b.y,b.z,1])}function render3DCaptureCubes(a){const b=glContext,c=render3D,d=c.camera;var e=[...c.cubeCaptures];c.cubeCaptures.clear();c.captureFramebuffer||(c.captureFramebuffer=b.createFramebuffer(),c.captureDepth=b.createRenderbuffer(),c.captureDepthSize=0);const f=new Camera3D;f.fov=PI/2;f.near=!d.orthographic&&0g.copy();b.bindFramebuffer(b.FRAMEBUFFER,c.captureFramebuffer);try{for(const h of e){const k=render3DCubeTexture(h),l=h.size;c.cubeCaptures.delete(h);c.captureDepthSize!==l&&(b.bindRenderbuffer(b.RENDERBUFFER,c.captureDepth),b.renderbufferStorage(b.RENDERBUFFER,b.DEPTH_COMPONENT24,l,l),b.framebufferRenderbuffer(b.FRAMEBUFFER,b.DEPTH_ATTACHMENT,b.RENDERBUFFER,c.captureDepth),c.captureDepthSize=l);c.capturingCube=h;b.activeTexture(b.TEXTURE0+5);b.bindTexture(b.TEXTURE_CUBE_MAP,null);b.activeTexture(b.TEXTURE0);render3DBoundEnvironment=null;b.viewport(0,0,l,l);f.pos=h.capturePos;c.camera=f;for(e=0;6>e;++e){b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_CUBE_MAP_POSITIVE_X+e,k,0);g=render3DCubeFaceMatrix(e,h.capturePos);c.updateMatrices(1);if(2>e||3>1)*4.-1.;gl_Position=vec4(v,0,1);}","#version 300 es\nprecision highp float;uniform mat4 inverseViewProj;uniform samplerCube sky;in vec2 v;out vec4 o;void main(){vec4 a=inverseViewProj*vec4(v,-1,1),b=inverseViewProj*vec4(v,0,1);o=vec4(texture(sky,b.xyz/b.w-a.xyz/a.w).rgb,1);}"));if(glFailedPrograms.has(c.skyBoxProgram))return!1;c.skyBoxVao||(c.skyBoxVao=b.createVertexArray());const d=b.isEnabled(b.DEPTH_TEST),e=b.isEnabled(b.BLEND),f=b.isEnabled(b.CULL_FACE),g=b.getParameter(b.DEPTH_WRITEMASK);b.useProgram(c.skyBoxProgram);c.currentProgram=void 0;b.activeTexture(b.TEXTURE6);b.bindTexture(b.TEXTURE_CUBE_MAP,render3DCubeTexture(a));b.bindSampler(6,null);b.uniform1i(glUniformLocation(c.skyBoxProgram,"sky"),6);a=c.viewMatrix.copy();a.m[12]=a.m[13]=a.m[14]=0;b.uniformMatrix4fv(glUniformLocation(c.skyBoxProgram,"inverseViewProj"),!1,c.projectionMatrix.copy().multiply(a).invert().m);b.disable(b.DEPTH_TEST);b.disable(b.BLEND);b.disable(b.CULL_FACE);b.depthMask(!1);b.bindVertexArray(c.skyBoxVao);b.drawArrays(b.TRIANGLES,0,3);b.bindVertexArray(c.vao);b.bindTexture(b.TEXTURE_CUBE_MAP,null);b.activeTexture(b.TEXTURE0);d&&b.enable(b.DEPTH_TEST);e&&b.enable(b.BLEND);f&&b.enable(b.CULL_FACE);b.depthMask(g);return!0}function render3DContextLost(){const a=render3D;a.program=a.currentProgram=a.shadowShader=a.vao=a.streamBuffer=a.whiteTexture=void 0;a.skyBoxProgram=a.skyBoxVao=a.captureFramebuffer=a.captureDepth=void 0;a.captureDepthSize=0;for(const b of glShaderObjects)b.program3D=void 0;a.lightCount=0;a.instanceBuffers=[];a.samplers=new Map;a.samplerKey=void 0;render3DClearInstances();a.shadowFramebuffer=a.shadowTexture=void 0;a.shadowTextureSize=0;a.cameraDepthFramebuffer=a.cameraDepthTexture=void 0;a.cameraDepthWidth=a.cameraDepthHeight=0;a.streamCount=0;++a.contextGeneration}function render3DContextRestored(){render3DInitGL()}function render3DUniform(a,b=render3D.currentProgram){const c=render3D.uniforms;let d=c.get(b);d||c.set(b,d={});let e;return(e=d)[a]??(e[a]=glContext.getUniformLocation(b,a))}function render3DDrawAttribs(a,b,c){const d=glContext;d.vertexAttrib4f(4,a[0],a[1],a[2],a[3]);d.vertexAttrib4f(5,a[4],a[5],a[6],a[7]);d.vertexAttrib4f(6,a[8],a[9],a[10],a[11]);d.vertexAttrib4f(7,a[12],a[13],a[14],a[15]);render3DAttrib4f(11,b.r,b.g,b.b,b.a);render3DAttrib4f(12,c.x,c.y,c.w,c.h)}function render3DAttrib4f(a,b,c,d,e){let f;const g=(f=render3D.attribValues)[a]||(f[a]=[NaN,NaN,NaN,NaN]);if(g[0]!==b||g[1]!==c||g[2]!==d||g[3]!==e)g[0]=b,g[1]=c,g[2]=d,g[3]=e,glContext.vertexAttrib4f(a,b,c,d,e)}function render3DUpdateSamplers(){const a=render3D,b=tilesPixelated+" "+a.anisotropy;if(a.samplerKey!==b){a.samplerKey=b;for(const c of a.samplers.values())glContext.deleteSampler(c);a.samplers.clear()}}function render3DSampler(a,b,c=tilesPixelated){const d=glContext,e=render3D,[f,g]=glWrapModes(a);a=1e5*f+4*g+(b?1:0)+(c?2:0);let h=e.samplers.get(a);if(h)return h;h=d.createSampler();d.samplerParameteri(h,d.TEXTURE_MAG_FILTER,b||c?d.NEAREST:d.LINEAR);d.samplerParameteri(h,d.TEXTURE_MIN_FILTER,b?d.NEAREST:c?d.NEAREST_MIPMAP_LINEAR:d.LINEAR_MIPMAP_LINEAR);d.samplerParameteri(h,d.TEXTURE_WRAP_S,f);d.samplerParameteri(h,d.TEXTURE_WRAP_T,g);(c=d.getExtension("EXT_texture_filter_anisotropic"))&&!b&&(b=d.getParameter(c.MAX_TEXTURE_MAX_ANISOTROPY_EXT),d.samplerParameterf(h,c.TEXTURE_MAX_ANISOTROPY_EXT,clamp(e.anisotropy,1,b)));e.samplers.set(a,h);return h}function render3DBindTexture(a,b=render3D,c=0){const d=glContext,e=render3D;a=render3DTextureOf(a);const f=a?.glTexture||e.whiteTexture;c&&d.activeTexture(d.TEXTURE0+c);d.bindTexture(d.TEXTURE_2D,f);f===e.whiteTexture||!e.mipmaps&&!b.pixelated?d.bindSampler(c,null):(d.bindSampler(c,render3DSampler(a?.wrap,b.pixelated,a?.pixelated??tilesPixelated)),glUpdateMipmaps(f),b.pixelated||glMipmappedTextures.has(f)||(glMipmappedTextures.add(f),d.generateMipmap(d.TEXTURE_2D)));c&&d.activeTexture(d.TEXTURE0)}function render3DSetMaterialUniforms(a){var b=render3D;if(a.normalScale){var c=a.normalMap;c=render3DTextureOf(c)?.glTexture?c:void 0}else c=void 0;var d=a.emissiveMap;d=render3DTextureOf(d)?.glTexture?d:void 0;render3DUniform4f("materialParams",c?a.normalScale:0,max(a.shininess,.001),a.reflectivity,0);var e=a.emissiveMapColor||WHITE;d?render3DUniform4f("emissiveTint",e.r,e.g,e.b,1):render3DUniform4f("emissiveTint",0,0,0,0);render3DBindMap(2,c,a);render3DBindMap(3,d,a);0c;++c)for(const d of[1,-1]){const e=[a[3]+d*a[c],a[7]+d*a[4+c],a[11]+d*a[8+c],a[15]+d*a[12+c]],f=hypot(e[0],e[1],e[2])||1;b.push(e.map(g=>g/f))}return b}function render3DPreRender(){const a=render3D;editor3DCameraBegin();a.updateMatrices();a.shadowMapDrawn=!1;render3DRenderPass(!1)}function render3DRender(){render3DRenderPass(!0);editor3DCameraEnd()}function render3DRenderPass(a){const b=glContext,c=render3D;if(c.program&&glEnable){render3DUpdateSamplers();var d=a===!!c.renderAfter2D;a=render3DLayerObjects(a);if(d||a.length){c.passIsDefault=d;glFlush();c.streamCount=0;c.capture=c.transparentQueue=void 0;render3DClearInstances();var e=render3DCollectLights();c.lightCount=e.length;var f=render3DShadowCaster();c.shadowLightIndex=f?e.indexOf(f):-1;var g=c.lightPositions,h=c.lightColors;e.forEach((k,l)=>{const m=k.directional?k.getWorldPos3D().normalize():k.getWorldPos3D(),n=k.color;l*=4;g[l]=m.x;g[l+1]=m.y;g[l+2]=m.z;g[l+3]=k.directional?-1:max(0,k.radius);h[l]=n.r;h[l+1]=n.g;h[l+2]=n.b;h[l+3]=n.a*k.intensity;c.lightCones.set(render3DLightCone(k),l)});b.bindVertexArray(c.vao);b.frontFace(b.CW);b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,c.shadowTexture||null);render3DSetMapUnits(c.whiteTexture);if(e=render3DTextureOf(render3DShadowCaster()?.gel)?.glTexture)b.activeTexture(b.TEXTURE4),b.bindTexture(b.TEXTURE_2D,e),b.activeTexture(b.TEXTURE0);b.depthMask(!0);b.clear(b.DEPTH_BUFFER_BIT);c.isRendering=!0;try{c.shadows&&!c.shadowMapDrawn&&(render3DRenderShadowMap(),c.shadowMapDrawn=!0),c.depthTexture&&d&&render3DRenderDepth(),d&&c.cubeCaptures.size&&render3DCaptureCubes(a),render3DUseProgram(c.program),c.renderStages(a,d)}finally{c.isRendering=!1,c.currentProgram=void 0,c.streamCount=0,c.capture=c.transparentQueue=void 0,b.disable(b.DEPTH_TEST),b.disable(b.CULL_FACE),b.depthMask(!0),b.frontFace(b.CCW),b.bindSampler(0,null),render3DSetMapUnits(null),glActiveTexture&&b.bindTexture(b.TEXTURE_2D,glActiveTexture),b.bindBuffer(b.ARRAY_BUFFER,glArrayBuffer),glSetInstancedMode(!0)}}}}function render3DSetMapUnits(a){const b=glContext;for(const c of[2,3,4])b.activeTexture(b.TEXTURE0+c),b.bindTexture(b.TEXTURE_2D,a),b.bindSampler(c,null);b.activeTexture(b.TEXTURE0+5);b.bindTexture(b.TEXTURE_CUBE_MAP,a&&render3DCubeTexture(render3D.environment)||null);b.bindSampler(5,null);render3DBoundEnvironment=a&&render3D.environment||null;b.activeTexture(b.TEXTURE0);render3DBoundMaps=[]}function render3DUpdateShadowMap(a){const b=glContext,c=render3D;a=glClampTextureSize(a);if(!c.shadowTexture||c.shadowTextureSize!==a){c.shadowTexture&&b.deleteTexture(c.shadowTexture);c.shadowFramebuffer&&b.deleteFramebuffer(c.shadowFramebuffer);var d=c.shadowTexture=b.createTexture();b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,d);b.texImage2D(b.TEXTURE_2D,0,b.DEPTH_COMPONENT24,a,a,0,b.DEPTH_COMPONENT,b.UNSIGNED_INT,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.LINEAR);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.LINEAR);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_COMPARE_MODE,b.COMPARE_REF_TO_TEXTURE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_COMPARE_FUNC,b.LEQUAL);b.activeTexture(b.TEXTURE0);var e=c.shadowFramebuffer=b.createFramebuffer();b.bindFramebuffer(b.FRAMEBUFFER,e);b.framebufferTexture2D(b.FRAMEBUFFER,b.DEPTH_ATTACHMENT,b.TEXTURE_2D,d,0);b.drawBuffers([b.NONE]);b.readBuffer(b.NONE);b.bindFramebuffer(b.FRAMEBUFFER,null);c.shadowTextureSize=a}}function render3DRenderShadowMap(){const a=glContext,b=render3D;render3DUpdateShadowMap(b.shadowMapSize|0);b.updateShadowMatrix();a.activeTexture(a.TEXTURE1);a.bindTexture(a.TEXTURE_2D,null);a.activeTexture(a.TEXTURE0);a.bindFramebuffer(a.FRAMEBUFFER,b.shadowFramebuffer);a.viewport(0,0,b.shadowTextureSize,b.shadowTextureSize);a.clear(a.DEPTH_BUFFER_BIT);a.useProgram(b.shadowShader);a.uniformMatrix4fv(render3DUniform("viewProj",b.shadowShader),!1,b.shadowMatrix.m);a.enable(a.DEPTH_TEST);a.depthMask(!0);a.disable(a.BLEND);a.disable(a.CULL_FACE);b.shadowPass=!0;try{const c=render3DLayerObjects(!!b.renderAfter2D).filter(d=>render3DSetting(d,"castShadow")&&!render3DSetting(d,"additive")&&(!d.transparent||d.tileInfo));render3DDrawObjects(c);b.onRenderOpaque?.();b.flush();render3DFlushInstances()}finally{b.shadowPass=!1,a.bindFramebuffer(a.FRAMEBUFFER,null),a.viewport(0,0,glCanvas.width,glCanvas.height),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,b.shadowTexture),a.activeTexture(a.TEXTURE0)}}function render3DUpdateCameraDepth(a,b){const c=glContext,d=render3D;if(!d.cameraDepthTexture||d.cameraDepthWidth!==a||d.cameraDepthHeight!==b){d.cameraDepthTexture&&c.deleteTexture(d.cameraDepthTexture);d.cameraDepthFramebuffer&&c.deleteFramebuffer(d.cameraDepthFramebuffer);var e=d.cameraDepthTexture=c.createTexture();c.bindTexture(c.TEXTURE_2D,e);c.texImage2D(c.TEXTURE_2D,0,c.DEPTH_COMPONENT24,a,b,0,c.DEPTH_COMPONENT,c.UNSIGNED_INT,null);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.NEAREST);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.NEAREST);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE);c.bindTexture(c.TEXTURE_2D,null);var f=d.cameraDepthFramebuffer=c.createFramebuffer();c.bindFramebuffer(c.FRAMEBUFFER,f);c.framebufferTexture2D(c.FRAMEBUFFER,c.DEPTH_ATTACHMENT,c.TEXTURE_2D,e,0);c.drawBuffers([c.NONE]);c.readBuffer(c.NONE);c.bindFramebuffer(c.FRAMEBUFFER,null);d.cameraDepthWidth=a;d.cameraDepthHeight=b}}function render3DRenderDepth(){const a=glContext,b=render3D,c=glCanvas.width,d=glCanvas.height;render3DUpdateCameraDepth(c,d);a.bindFramebuffer(a.FRAMEBUFFER,b.cameraDepthFramebuffer);a.viewport(0,0,c,d);a.clear(a.DEPTH_BUFFER_BIT);a.useProgram(b.shadowShader);a.uniformMatrix4fv(render3DUniform("viewProj",b.shadowShader),!1,b.viewProjection.m);a.enable(a.DEPTH_TEST);a.depthMask(!0);a.disable(a.BLEND);a.disable(a.CULL_FACE);b.shadowPass=b.depthPass=!0;try{const e=render3DLayerObjects(!!b.renderAfter2D).filter(f=>!render3DSetting(f,"additive")&&(!f.transparent||f.tileInfo));render3DDrawObjects(e);b.onRenderOpaque?.();b.flush();render3DFlushInstances()}finally{b.shadowPass=b.depthPass=!1,a.bindFramebuffer(a.FRAMEBUFFER,null),a.viewport(0,0,c,d)}}function render3DBeginStrip(a,b,c=!1){const d=render3D;if(render3DCanDraw()&&!(d.shadowPass&&!d.lighting||a>RENDER3D_MAX_STREAM_VERTS)){var e=render3DTextureOf(b);d.streamCount&&(e!==d.streamTileInfo||d.streamUnlit!==c||render3DStateChanged(d.streamState)||d.streamCount+a>RENDER3D_MAX_STREAM_VERTS)&&d.flush();render3DFlushBeforeOverlay();d.streamCount||(d.streamState=render3DCaptureBatchState());d.streamUnlit=c;d.streamTileInfo=e;return render3DGetTileUVs(b)}}function render3DFlushBeforeOverlay(){const a=render3D;a.depthTest||a.shadowPass||!a.instanceMeshes.length||(a.flush(),render3DFlushInstances())}function render3DMeshUpload(a){a.buffer&&!a.dirty&&a.contextGeneration===render3D.contextGeneration||a.upload()}function render3DWorldSize(a,b){a=a.size3D;return vec3(a.x*hypot(b[0],b[1],b[2]),a.y*hypot(b[4],b[5],b[6]),a.z*hypot(b[8],b[9],b[10]))}function render3DSlopeNormal(a,b,c,d,e,f,g){const h=max(b-d,-f);f=min(b+d,f);d=max(c-e,-g);e=min(c+e,g);c=(a(f,c)-a(h,c))/(f-h||1);a=(a(b,e)-a(b,d))/(e-d||1);b=1/hypot(c,1,a);return vec3(-c*b,b,-a*b)}const render3DBillboardAxesScratch=new Float64Array(6);function render3DBillboardAxes(a,b,c){var d=render3D.cameraRight,e=render3D.cameraUp;let f=d.x,g=d.y;d=d.z;var h=e.x;let k=e.y;e=e.z;c&&(f=(h=hypot(f,d))?f/h:1,g=0,d=h?d/h:0,h=0,k=1,e=0);c=cos(b);b=sin(b);const l=a.x/2;a=a.y/2;const m=render3DBillboardAxesScratch;m[0]=(f*c+h*b)*l;m[1]=(g*c+k*b)*l;m[2]=(d*c+e*b)*l;m[3]=(h*c-f*b)*a;m[4]=(k*c-g*b)*a;m[5]=(e*c-d*b)*a;return m}function render3DBillboardCorners(a,b,c,d){var e=render3DBillboardAxes(b,c,d);b=e[0];c=e[1];d=e[2];const f=e[3],g=e[4];e=e[5];return[vec3(a.x-b+f,a.y-c+g,a.z-d+e),vec3(a.x-b-f,a.y-c-g,a.z-d-e),vec3(a.x+b+f,a.y+c+g,a.z+d+e),vec3(a.x+b-f,a.y+c-g,a.z+d-e)]}function render3DStripCount(a){return a+2+(a&1)}function render3DStripIndex(a,b){return 1>a?0:a<=b?a-1:b-1}function render3DForEachStripVertex(a,b,c,d,e){const f=a.length,g=render3DStripCount(f),h=isArray(b),k=isArray(c),l=isArray(d);for(let m=0;m{c===render3D?.contextGeneration&&glContext&&(glContext.deleteBuffer(a),glContext.deleteBuffer(b))});function render3DPlaceGroups(a){const b=new Int32Array(a.length),c=new Map,d=[],e=[];for(let g=0;g{var x=u.x-t.x,w=u.y-t.y;u=u.z-t.z;const z=v.x-t.x,A=v.y-t.y;t=v.z-t.z;x=Math.acos(clamp((x*z+w*A+u*t)/((x**2+w**2+u**2)**.5*(z**2+A**2+t**2)**.5||1),-1,1));w=3*y;g[w]+=k*x;g[w+1]+=l*x;g[w+2]+=m*x;h[y]=1};for(let t=0;t{this.points.push(e);this.normals.push(f);this.uvs.push(g);this.colors.push(h)});this.vertexKeys=void 0;this.dirty=!0;return this}addTriangles(a,b,c,d,e){this.toIndexed();const f=this.points.length,g=isArray(c),h=isArray(d),k=isArray(e);for(let l=0;lthis.points[c]);this.normals=a.map(c=>this.normals[c]||RENDER3D_DEFAULT_NORMAL);this.uvs=a.map(c=>this.uvs[c]||RENDER3D_DEFAULT_UV);this.colors=a.map(c=>this.colors[c]||WHITE);this.indices=render3DFlipTriangles(b);this.vertexKeys=void 0;this.dirty=!0;return this}addQuad(a,b,c,d,e,f){return this.addStrip(render3DQuadStrip(a,b,c,d),render3DFaceNormal(a,b,c,d),f?render3DQuadValues(f):RENDER3D_QUAD_UVS,render3DQuadValues(e))}combine(a,b=RENDER3D_IDENTITY,c=WHITE){b=render3DMatrix(b);const d=render3DNormalMatrix(b);var e=render3DMirrors(b);let f=a;if(this.indices||a.indices){this.toIndexed();f=a.indices?a:(new Mesh).combine(a).toIndexed();const h=this.points.length,k=f.indices;for(let l=0,m=k.length;lvec2(c.x*b.x,c.y*b.y));this.dirty=!0;return this}transform(a){a=render3DMatrix(a);const b=render3DNormalMatrix(a);for(let c=0;ca.scale(-1));this.dirty=!0;return this}setColor(a){this.colors=this.points.map(()=>a);this.dirty=!0;return this}getBounds(){if(!this.points.length)return{min:vec3(),max:vec3()};const a=vec3(Infinity),b=vec3(-Infinity);for(const c of this.points)a.x=min(a.x,c.x),a.y=min(a.y,c.y),a.z=min(a.z,c.z),b.x=max(b.x,c.x),b.y=max(b.y,c.y),b.z=max(b.z,c.z);return{min:a,max:b}}center(){const a=this.getBounds();return this.transform(a.min.add(a.max).scale(-.5))}fit(a=1){var b=this.getBounds();b=b.max.subtract(b.min);a/=max(b.x,b.y,b.z)||1;return this.transform(Matrix4.scaling(vec3(a)))}computeRadius(){let a=0;for(const b of this.points)a=max(a,b.lengthSquared());this.bounds=this.getBounds();return this.radius=a**.5}computeNormals(a=!1){if(this.indices){if(a){const{groups:h,sums:k,touched:l}=render3DSmoothNormalSums(this.points,this.indices);this.normals=this.points.map((m,n)=>{var r=3*h[n];m=k[r];const q=k[r+1];r=k[r+2];const p=m**2+q**2+r**2,t=1/p**.5;return l[h[n]]&&p?vec3(m*t,q*t,r*t):RENDER3D_DEFAULT_NORMAL});this.dirty=!0;return this}var b=h=>this.indices.map(k=>h[k]);this.points=b(this.points);this.normals=b(this.normals);this.uvs=b(this.uvs);this.colors=b(this.colors);this.indices=this.indices.map((h,k)=>k);b=this.points;var c=this.indices;a=b.map(()=>RENDER3D_DEFAULT_NORMAL);for(var d=0;d{var r=3*h[n];m=k[r];const q=k[r+1];r=k[r+2];const p=(m**2+q**2+r**2)**.5;return l[h[n]]?p?vec3(1/p*m,1/p*q,1/p*r):vec3():vec3(0,1,0)});this.vertexKeys=void 0;this.dirty=!0;return this}a=[];for(d=0;d+2RENDER3D_DEFAULT_NORMAL);a.forEach((h,k)=>h&&(g[k]=g[k+1]=g[k+2]=h));this.normals=g;this.vertexKeys=void 0;this.dirty=!0;return this}upload(){if(!render3D?.program||!glContext)return this.computeRadius(),this;const a=glContext;var b=this.vertexLayout;if(this.dynamicDraw&&b&&this.buffer&&this.contextGeneration===render3D.contextGeneration&&b.pointCount===this.points.length)return a.bindBuffer(a.ARRAY_BUFFER,this.buffer),a.bufferSubData(a.ARRAY_BUFFER,0,this.vertexDataPacked?b.data:render3DMeshVertexData(this,b.vertices,b.data)),a.bindBuffer(a.ARRAY_BUFFER,glArrayBuffer),this.dirty=this.vertexDataPacked=!1,this;this.dispose();const{vertices:c,indices:d}=this.getTriangles();b=65535k?(f[h]=g,c[g]=b.length,b.push(g)):c[g]=c[k];d[g]=f[h]}return{vertices:b,indices:render3DStripTriangles(a,c,d)}}e=new Float64Array(9*a);for(h=1;h<2*a;)h*=2;f=h-1;g=new Int32Array(h);h=new Int32Array(h);for(k=0;k>>0;m=Math.imul(m^q,2654435761)>>>0;m=Math.imul(m^l,2654435761)>>>0;for(n=m&f;;n=n+1&f){const t=h[n]-1;if(0>t){h[n]=k+1;d[k]=k;break}if(e[9*t]===r&&e[9*t+1]===q&&e[9*t+2]===l){d[k]=t;break}}for(r=3;9>r;++r)m=Math.imul(m^e[p+r],2654435761)>>>0;for(r=m&f;;r=r+1&f){q=g[r]-1;if(0>q){g[r]=k+1;c[k]=b.length;b.push(k);break}l=!0;for(m=0;l&&9>m;++m)l=e[9*q+m]===e[p+m];if(l){c[k]=c[q];break}}}return{vertices:b,indices:render3DStripTriangles(a,c,d)}}render(a,b,c){render3D?.drawMesh(this,a,b,c)}dispose(){this.buffer&&(render3DMeshBuffers?.unregister(this),this.contextGeneration===render3D?.contextGeneration&&(glContext?.deleteBuffer(this.buffer),glContext?.deleteBuffer(this.indexBuffer)),this.buffer=this.indexBuffer=void 0,this.bufferCount=0)}}function buildLathe(a,b=16,c=render3D?.smoothShading,d=!0){b|=0;const e=new Mesh,f=a.length,g=(w,z)=>vec3(sin(z)*a[w][0],a[w][1],cos(z)*a[w][0]),h=w=>{const[z,A]=a[w],[C,D]=a[w+1];w=vec2(D-A,z-C);return w.length()?w.normalize():vec2(1,0)},k=2abs(a[0][0]-a[f-1][0])&&1e-9>abs(a[0][1]-a[f-1][1]);var l=w=>{if(!(k||w&&w!=f-1)&&1e-9>abs(a[w][0])){var z=w?1:-1;if(h(w?w-1:0).y*z>Math.SQRT1_2-1e-9)return vec2(0,z)}let A=vec2();z=C=>A=A.add(h(C).scale(hypot(a[C+1][0]-a[C][0],a[C+1][1]-a[C][1])));0vec3(sin(z)*w.x,w.y,cos(z)*w.x),n=[0];for(var r=1;rabs(a[w+1][0])?-y:0;y=1e-9>abs(a[w][0])?y:0;for(let z=0;z<=b;++z){const A=z/b*2*PI,C=z/b;q.push(g(w+1,A),g(w,A));p.push(m(v,A+x),m(u,A+y));t.push(vec2(C,1-n[w+1]/r),vec2(C,1-n[w]/r))}e.addStrip(q,p,t)}else for(q=h(w),p=0;pabs(a[w][0]))){c=[];l=[];for(m=0;m{let x=p.subtract(q).cross(t.subtract(q));if(!(1e-20>x.lengthSquared())){0>x.dot(q.add(p).add(t))&&([p,t,v,y,x]=[t,p,y,v,x.scale(-1)]);x=x.normalize();var w=d[0];for(const B of d)B[0].dot(x)>w[0].dot(x)&&(w=B);var[,z,A]=w,C=abs(a.dot(z)),D=abs(a.dot(A));w=B=>vec2(.5+B.dot(z)/(2*C),.5-B.dot(A)/(2*D));e.addStrip([q,p,t],1k;++k)for(var l of[-1,1])for(var m of[-1,1]){const q=h[(k+1)%3].scale(l),p=h[(k+2)%3].scale(m);var n=q.multiply(f).add(p.multiply(f)),r=h[k].multiply(f);const t=n.subtract(r);n=n.add(r);r=u=>q.scale(cos(u/g*PI/2)).add(p.scale(sin(u/g*PI/2)));for(let u=0;u{const z=x/g*PI/2;x=x?w/x*PI/2:0;return y.scale(cos(z)).add(u.scale(cos(x)*sin(z))).add(v.scale(sin(x)*sin(z)))};for(h=0;h0;a=render3DSize2(a);b=render3DSize2(b);const f=new Mesh,g=b.x,h=b.y,k=a.x/g,l=a.y/h,m=a.x/2,n=a.y/2,r=k/2,q=l/2,p=(y,x)=>c?isColor(c)?c:c(y*k-m,x*l-n):WHITE;a=y=>{const x=[],w=[],z=[],A=[],C=y*l-n;for(let D=0;D<=g;++D){const B=D*k-m;x.push(vec3(B,d(B,C),C));z.push(vec2(D/g,y/h));e&&(w.push(render3DSlopeNormal(d,B,C,r,q,m,n)),A.push(p(D,y)))}return{points:x,normals:w,uvs:z,colors:A}};b=a(0);for(var t=0;t0>f.y?b.lerp(c,-f.y):b.lerp(a,f.y));render3DSkyColors.set(d,[a.copy(),b.copy(),c.copy()]);return d}const render3DSkyColors=new WeakMap;class EngineObject3D extends EngineObject{constructor(a=vec3(),b,c,d=WHITE){c instanceof TextureInfo&&render3DWholeTiles.add(c=new TileInfo(vec2(),c.size,c,0,0));super(vec2(a.x,a.y),vec2(),c,0,d);this.mass=0;this.pos3D=a.copy();this.rotation3D=vec3();this.scale3D=vec3(1);this.velocity3D=vec3();this.angleVelocity3D=vec3();this.size3D=(a=(this.mesh=b)&&b.points.length?!b.dirty&&b.bounds||b.getBounds():void 0)?a.max.subtract(a.min):vec3(1);this.softShadow=0;this.sync2D=this.pixelated=this.upright=!1;this.transparent=!b&&!!c;this.additive=!1;this.specular=this.emissive=0;this.shininess=16;this.normalMap=void 0;this.normalScale=1;this.reflectivity=0;this.emissiveMap=void 0;this.emissiveMapColor=WHITE;this.environment=void 0;this.castShadow=!0;this.collideAsSphere3D=!1;this.groundAngle=PI/4;this.receiveShadow=!0;this.localMatrix=this.renderAfter2D=void 0;this.worldMatrix=new Matrix4;this.matrixBuilt=new Float64Array(9).fill(NaN);this.matrixVersion=0;this.matrixParent=void 0;this.matrixParentVersion=0;this.movePass=engineObjectsUpdateCount;this.collideFrom=vec3();this.collideFromPass=-1;this.drawOwner=void 0}updatePhysics(){this.sync2D&&super.updatePhysics();const a=this.groundObject;this.sync2D||(this.groundObject=void 0);const b=enablePhysicsSolver&&!this.sync2D;var c=this.clampSpeed&&b&&(this.collideSolidObjects||this.collideLevel&&this.mass)?objectMaxSpeed:void 0;const d=(this.collideLevel||this.collideSolidObjects)&&this.mass&&!this.sync2D?this.pos3D.copy():void 0;this.collideSolidObjects&&!this.sync2D&&render3DCollideFrom(this);render3DMove(this,c);if(a&&this.mass&&!this.sync2D){c=max(this.friction,a.friction);const f=this.velocity3D;var e=a instanceof EngineObject3D?a.velocity3D:void 0;const g=e?.x??0;e=e?.z??0;f.x=g+(f.x-g)*c;f.z=e+(f.z-e)*c}d&&this.collideLevel&&b&&render3DCollideLevel(this,d,a);this.collideSolidObjects&&b&&render3DCollideSolid(this)}updateTransforms(a=!0){!paused&&this.parent&&this.movePass!==engineObjectsUpdateCount&&(this.movePass=engineObjectsUpdateCount,render3DMove(this));super.updateTransforms(!1);!paused&&this.sync2D&&(this.pos3D.x=this.pos.x,this.pos3D.y=this.pos.y,this.rotation3D.z=-this.angle);if(a)for(const b of this.children)b.updateTransforms()}setCollision(a=!0,b=!0,c=!0,d=!1){super.setCollision(a,b,c,d)}collideWithVoxel(a,b){return!0}getWorldPos3D(){return render3DObjectMatrix(this).getTranslation()}getForward3D(){return render3DAxis(render3DObjectMatrix(this).m,8).normalize(-1)}getRight3D(){return render3DAxis(render3DObjectMatrix(this).m,0).normalize()}getUp3D(){return render3DAxis(render3DObjectMatrix(this).m,4).normalize()}getMatrix(){return render3DObjectMatrix(this).copy()}get roughness(){return(2/(this.shininess+2))**.25}set roughness(a){this.shininess=max(1,2/max(a,.001)**4-2)}lookAt(a){const b=this.parent instanceof EngineObject3D?this.parent:void 0;a=b?b.getMatrix().invert().transformPoint(a):a;this.rotation3D=render3DLookRotation(a.subtract(this.pos3D),this.rotation3D)}addChild(a,b,c){a instanceof EngineObject3D&&(a.movePass=engineObjectsUpdateCount);return super.addChild(a,b,c)}attach(a){if(!(a instanceof EngineObject3D))return super.attach(a);a.parent?.removeChild(a);const b=render3DObjectMatrix(this).copy().invert().multiply(render3DObjectMatrix(a));super.attach(a);a.pos3D=b.getTranslation();a.rotation3D=b.getRotation();a.scale3D=b.getScale();a.localMatrix&&(a.localMatrix=b);return a}removeChild(a){a instanceof EngineObject3D&&!a.destroyed&&render3DTakeWorld(a,render3DObjectMatrix(a));a instanceof EngineObject3D&&a.drawOwner===this&&(a.drawOwner=void 0);super.removeChild(a)}setMesh(a){const b=this.mesh;this.mesh=a;b&&b!==a&&b.buffer&&!engineObjects.some(c=>c.mesh===b)&&b.dispose();return a}render(){}render3D(){var a=render3DObjectMatrix(this);if(this.mesh)render3D.drawMesh(this.mesh,a,this.tileInfo,this.color);else if(this.tileInfo){a=a.m;const b=render3DWorldSize(this,a);render3D.drawBillboard(vec3(a[12],a[13],a[14]),vec2(b.x,b.y),this.tileInfo,this.color,this.rotation3D.z,this.upright)}}}const RENDER3D_PART_SETTINGS={emissive:0,additive:!1,specular:0,shininess:16,reflectivity:0,normalMap:void 0,normalScale:1,emissiveMap:void 0,emissiveMapColor:WHITE,receiveShadow:!0,castShadow:!0,pixelated:!1,shader:void 0,environment:void 0,renderAfter2D:void 0,renderOrder:0};function render3DShareSettings(a,b){a.drawOwner=b}function render3DSetting(a,b){var c=a.drawOwner;return c&&(c=render3DSetting(c,b),c!==RENDER3D_PART_SETTINGS[b])?c:a[b]}const render3DPartScratch={...RENDER3D_PART_SETTINGS};function render3DPartSettings(a){for(const b in RENDER3D_PART_SETTINGS)render3DPartScratch[b]=render3DSetting(a,b);return render3DPartScratch}function render3DTakeWorld(a,b){a.pos3D=b.getTranslation();a.rotation3D=b.getRotation();a.scale3D=b.getScale();a.localMatrix&&(a.localMatrix=b.copy())}const render3DLocalMatrix=new Matrix4;function render3DObjectMatrix(a){const b=a.parent instanceof EngineObject3D?a.parent:void 0,c=b&&render3DObjectMatrix(b),d=a.pos3D,e=a.rotation3D,f=a.scale3D,g=a.matrixBuilt,h=a.localMatrix;if(h)b?(a.worldMatrix.m.set(c.m),a.worldMatrix.multiply(h),a.matrixParentVersion=b.matrixVersion):a.worldMatrix.m.set(h.m),g[0]=NaN,a.matrixParent=b,++a.matrixVersion;else if(g[0]!==d.x||g[1]!==d.y||g[2]!==d.z||g[3]!==e.x||g[4]!==e.y||g[5]!==e.z||g[6]!==f.x||g[7]!==f.y||g[8]!==f.z||a.matrixParent!==b||b&&a.matrixParentVersion!==b.matrixVersion)g[0]=d.x,g[1]=d.y,g[2]=d.z,g[3]=e.x,g[4]=e.y,g[5]=e.z,g[6]=f.x,g[7]=f.y,g[8]=f.z,b?(buildMatrix(d,e,f,render3DLocalMatrix),a.worldMatrix.m.set(c.m),a.worldMatrix.multiply(render3DLocalMatrix),a.matrixParentVersion=b.matrixVersion):buildMatrix(d,e,f,a.worldMatrix),a.matrixParent=b,++a.matrixVersion;return a.worldMatrix}function render3DMove(a,b){const c=a.pos3D,d=a.velocity3D,e=a.rotation3D,f=a.angleVelocity3D;var g=a.sync2D?1:a.damping;const h=a.sync2D?1:a.angleDamping;d.x*=g;d.y*=g;d.z*=g;a.mass&&!a.sync2D&&(g=render3D.gravity,a=a.gravityScale,d.x+=g.x*a,d.y+=g.y*a,d.z+=g.z*a);void 0!==b&&(d.x=clamp(d.x,-b,b),d.y=clamp(d.y,-b,b),d.z=clamp(d.z,-b,b));c.x+=d.x;c.y+=d.y;c.z+=d.z;e.x+=f.x*=h;e.y+=f.y*=h;e.z+=f.z*=h}function render3DCollideLevel(a,b,c){for(const d of render3DLevel)d.destroyed||d.levelCollide3D(a,b,d===c)}function render3DSolidShape(a){const b=a.size3D;var c=a.scale3D;const d=abs(c.x),e=abs(c.y);c=abs(c.z);if(a.collideAsSphere3D)return{pos:a.pos3D.copy(),radius:max(b.x,b.y,b.z)/2*max(d,e,c)};const f=!render3DIsSprite(a)&&isTurned3D(a.rotation3D)?render3DSolidAxes(a):void 0;return{pos:a.pos3D.copy(),size:vec3(b.x*d,b.y*e,b.z*c),axes:f}}const render3DSolidAxesCache=new WeakMap;function render3DSolidAxes(a){const b=a.rotation3D;var c=render3DSolidAxesCache.get(a);if(c&&c.x===b.x&&c.y===b.y&&c.z===b.z)return c.axes;c=boxAxes3D(b);render3DSolidAxesCache.set(a,{x:b.x,y:b.y,z:b.z,axes:c});return c}function render3DSolidReach(a){var b=a.size3D,c=a.scale3D;const d=abs(c.x);var e=abs(c.y);c=abs(c.z);if(a.collideAsSphere3D)return max(b.x,b.y,b.z)/2*max(d,e,c);a=b.x*d;e*=b.y;b=b.z*c;return(a*a+e*e+b*b)**.5/2}function render3DSolidPush(a,b){const c=(d,e)=>e.axes?collideSphereOrientedBox3D(d.pos,d.radius,e.pos,e.size,e.axes):collideSphereBox(d.pos,d.radius,e.pos,e.size);return a.size?b.size?a.axes||b.axes?collideOrientedBoxes3D(a.pos,a.size,a.axes??BOX_WORLD_AXES,b.pos,b.size,b.axes??BOX_WORLD_AXES):collideBoxBox3D(a.pos,a.size,b.pos,b.size):(a=c(b,a))&&a.scale(-1):b.size?c(a,b):collideSphereSphere(a.pos,a.radius,b.pos,b.radius)}function render3DCollideAsk(a,b,c,d=!0){var e=d||render3DSettleAsked(a,b)?engineObjectsCollidePairAnswer(a,b):void 0;if(void 0!==e)return e;e=a.collideWithObject(b,c);c=b.collideWithObject(a,c.scale(-1));c=!(!e||!c);engineObjectsCollidePairAdd(a,b,c);engineObjectsCollidePairAdd(b,a,c);d&&render3DSettleAsked(a,b,!0);return c}const render3DSettleAskedPairs={pass:-1,pairs:new Map};function render3DSettleAsked(a,b,c=!1){const d=render3DSettleAskedPairs;if(d.pass!==engineObjectsUpdateCount){if(!c)return!1;d.pass=engineObjectsUpdateCount;d.pairs.clear()}if(c){for(const[e,f]of[[a,b],[b,a]])(a=d.pairs.get(e))?a.add(f):d.pairs.set(e,new Set([f]));return!0}return!!d.pairs.get(a)?.has(b)}function render3DCollideFrom(a){a.collideFromPass!==engineObjectsUpdateCount&&(a.collideFromPass=engineObjectsUpdateCount,a.collideFrom.set(a.pos3D.x,a.pos3D.y,a.pos3D.z));return a.collideFrom}function render3DPushFrom(a,b,c,d,e){const f=render3DCollideFrom(c),g=render3DCollideFrom(d);c=c.pos3D;d=d.pos3D;return 0>=e.x*(c.x-f.x-d.x+g.x)+e.y*(c.y-f.y-d.y+g.y)+e.z*(c.z-f.z-d.z+g.z)?e:render3DSolidPushBack(a,b,f,g)??e}const render3DFixed={pass:-1,list:[]};function render3DFixedSolids(){render3DFixed.pass!==engineObjectsUpdateCount&&(render3DFixed.pass=engineObjectsUpdateCount,render3DFixed.list=engineObjectsCollide.filter(a=>!a.mass&&a instanceof EngineObject3D&&!a.parent&&!a.sync2D));return render3DFixed.list}function render3DSettleFixed(a,b,c){if(!a.destroyed&&a.collideSolidObjects){var d=render3DSolidShape(a),e=render3DSolidReach(a);for(const l of render3DFixedSolids()){if(l===a||l===b||l.mass||l.destroyed||!a.isSolid&&!l.isSolid)continue;var f=d.pos;const m=l.pos3D;var g=e+render3DSolidReach(l),h=f.x-m.x,k=f.y-m.y;f=f.z-m.z;h*h+k*k+f*f>g*g||(g=render3DSolidShape(l),!(h=render3DSolidPush(d,g))||1e-12>h.lengthSquared()||(h=render3DPushFrom(d,g,a,l,h),!render3DCollideAsk(a,l,h)))||(d=h.lengthSquared(),k=h.y/d**.5,0=cos(a.groundAngle)&&render3DOnFace(h,g)&&(a.groundObject=l,h.x||h.z)&&(h=vec3(0,d/h.y,0)),a.pos3D=a.pos3D.add(h),d=render3DSolidShape(a),g=h.normalize(),0>a.velocity3D.dot(g)&&(a.velocity3D=a.velocity3D.reflect(g,a.restitution)))}a.collideLevel&&a.mass&&render3DCollideLevel(a,c,void 0)}}function render3DSolidPushBack(a,b,c,d){if(!a.axes&&!b.axes){var e=n=>n.size?n.size.scale(.5):vec3(n.radius),f=e(a),g=e(b);e=Infinity;var h=0;for(const n of["x","y","z"]){var k=f[n]+g[n],l=c[n]-d[n];if(!(abs(l)!a.mesh&&!!a.tileInfo;function render3DOnFace(a,b){if(!b.size)return!1;a=a.normalize();b=b.axes??BOX_WORLD_AXES;return.999999f*f)&&(d=render3DSolidShape(k),g=render3DSolidPush(b,d))&&(g=render3DPushFrom(b,d,a,k,g),render3DCollideAsk(a,k,g,!1))){f=g.lengthSquared();h=g.y/f**.5;d=0=cos(a.groundAngle)&&render3DOnFace(g,d);h=0>h&&k.mass&&-h>=cos(k.groundAngle)&&render3DOnFace(g,b);if(d||h)if(d?a.groundObject=k:k.groundObject=a,g.x||g.z)g=vec3(0,f/g.y,0);h=a.mass+k.mass;f=a.mass?k.mass?k.mass/h:1:0;e=k.mass?a.mass?a.mass/h:1:0;h=a.pos3D.copy();d=k.pos3D.copy();a.pos3D=a.pos3D.add(g.scale(f));k.pos3D=k.pos3D.subtract(g.scale(e));g=g.normalize();f&&0>a.velocity3D.dot(g)&&(a.velocity3D=a.velocity3D.reflect(g,a.restitution));e&&0vec3(k[m],k[m+1],k[m+2]).normalize();if((g=d||render3DIsSprite(h)||!(k[1]||k[2]||k[4]||k[6]||k[8]||k[9])?void 0:[g(0),g(4),g(8)])&&(1e-6n.scale(r?12*(abs(m[0][n])+abs(m[1][n])+abs(m[2][n]));l.set(g("x"),g("y"),g("z"));g=void 0}if(b&&g)c=!!collideOrientedBoxes3D(a,b,BOX_WORLD_AXES,c,l,g);else if(b)c=isOverlapping3D(a,b,c,l);else if(g)c=!!collideSphereOrientedBox3D(a,e**.5,c,l,g);else{g=max(abs(a.x-c.x)-l.x/2,0);const m=max(abs(a.y-c.y)-l.y/2,0);c=max(abs(a.z-c.z)-l.z/2,0);c=g*g+m*m+c*cA))continue;const C=e-n.x,D=f-n.y;n=g-n.z;v=(C*v+D*y+n*z)/A;0<=v&&1>=v&&(y=D*u-n*t,u=n*p-C*u,p=C*t-D*p,t=(h*y+k*u+a*p)/A,0<=t&&1>=v+t&&(r=(r*y+w*u+q*p)/A,0<=r&&!(r>=m)&&(m=r)))}return m}function render3DRaycastSprite(a,b,c){const d=c.getTranslation();c=render3DWorldSize(b,c.m);c=vec2(c.x,c.y);if(0d.distance-e.distance).map(d=>d.o)}function engineObjectsCallback3D(a,b,c,d=engineObjects,e=!1){for(const f of engineObjectsCollect3D(a,b,d,e))f.destroyed||c(f)}class InstancedMesh3D extends EngineObject3D{constructor(a,b,c,d=WHITE){super(vec3(),a,c,d);this.size3D=vec3();this.maxCount=this.count=b;this.matrixData=new Float32Array(b*RENDER3D_MATRIX_FLOATS);this.colorData=new Float32Array(b*RENDER3D_COLOR_FLOATS);this.dirtyStart=0;this.dirtyEnd=b;this.colorDirtyStart=0;this.colorDirtyEnd=b;this.boundsStart=this.scaleSquared=this.reachSquared=0;this.boundsEnd=b;this.colorBuffer=this.buffer=this.fixedRadius=void 0;this.bufferGeneration=-1;this.uvTileInfo=c;a=render3DGetTileUVs(c);c=this.matrixData;const e=this.colorData;for(let f=0;fe;++e)c[d+e]=b[e];this.markDirty(a)}getMatrixAt(a){a*=RENDER3D_MATRIX_FLOATS;const b=new Matrix4;b.m.set(this.matrixData.subarray(a,a+16));return b}setColorAt(a,b){const c=this.colorData,d=a*RENDER3D_COLOR_FLOATS;c[d]=b.r;c[d+1]=b.g;c[d+2]=b.b;c[d+3]=b.a;this.markColorDirty(a)}markDirty(a){a=this.dirtyEnd&&(this.dirtyEnd=a+1);a=this.boundsEnd&&(this.boundsEnd=a+1)}markDirtyRange(a,b){athis.dirtyEnd&&(this.dirtyEnd=b);athis.boundsEnd&&(this.boundsEnd=b)}markColorDirty(a){a=this.colorDirtyEnd&&(this.colorDirtyEnd=a+1)}get radius(){if(void 0!==this.fixedRadius)return this.fixedRadius;if(this.boundsEnd>this.boundsStart){var a=this.matrixData;let d=this.reachSquared,e=this.scaleSquared;for(let f=this.boundsStart;fd&&(d=c);b>e&&(e=b)}this.reachSquared=d;this.scaleSquared=e;this.boundsStart=Infinity;this.boundsEnd=0}a=this.mesh;a=a.radius||a.computeRadius();return this.reachSquared**.5+a*this.scaleSquared**.5}set radius(a){this.fixedRadius=a}render3D(){const a=render3D,b=glContext,c=this.mesh;if(a.transparentQueue)return a.queueTransparent(this.getWorldPos3D(),()=>this.render3D());if(c&&this.count&&render3DCanDraw()&&(!a.shadowPass||a.lighting)&&(render3DMeshUpload(c),c.bufferCount&&(!a.frustumCulling||render3DSphereVisible(0,0,0,this.radius)))){if(this.uvTileInfo!==this.tileInfo){var d=render3DGetTileUVs(this.tileInfo),e=this.colorData;for(let f=4;f{l<=k||(b.bindBuffer(b.ARRAY_BUFFER,f),b.bufferSubData(b.ARRAY_BUFFER,k*h*4,g,k*h,(l-k)*h))},d(this.buffer,this.matrixData,RENDER3D_MATRIX_FLOATS,this.dirtyStart,this.dirtyEnd),d(this.colorBuffer,this.colorData,RENDER3D_COLOR_FLOATS,this.colorDirtyStart,this.colorDirtyEnd)):(this.bufferGeneration=a.contextGeneration,b.bindBuffer(b.ARRAY_BUFFER,this.buffer=b.createBuffer()),b.bufferData(b.ARRAY_BUFFER,this.matrixData,b.DYNAMIC_DRAW),b.bindBuffer(b.ARRAY_BUFFER,this.colorBuffer=b.createBuffer()),b.bufferData(b.ARRAY_BUFFER,this.colorData,b.DYNAMIC_DRAW));this.dirtyStart=this.colorDirtyStart=Infinity;this.dirtyEnd=this.colorDirtyEnd=0;a.flush();render3DFlushBeforeOverlay();d=a.cullBackFaces;e=this.tileInfo;a.cullBackFaces=!c.doubleSided;render3DDrawInstanced(c,this.buffer,this.count,render3DTextureOf(e),a,this.colorBuffer);a.cullBackFaces=d}}destroy(a){this.buffer&&this.bufferGeneration===render3D?.contextGeneration&&(glContext?.deleteBuffer(this.buffer),glContext?.deleteBuffer(this.colorBuffer));this.buffer=this.colorBuffer=void 0;super.destroy(a)}}class Light3D extends EngineObject3D{constructor(a=vec3(),b=5,c=WHITE,d=1){super(a,void 0,void 0,c);this.size3D=vec3();this.radius=b;this.intensity=d;this.directional=!1;this.coneAngle=0;this.coneSoftness=.2;this.glow=0;this.glowFalloff=1;this.gel=void 0;this.additive=!0;this.flareObject=void 0}addFlare(a,b,c,d,e){return this.flare=a=new LensFlare3D(a,b,c,d,e)}get flare(){return this.flareObject&&!this.flareObject.destroyed?this.flareObject:void 0}set flare(a){const b=this.flare;a!==b&&(b&&b.destroy(),a&&(a.light=this,a.parent||this.addChild(a)),this.flareObject=a||void 0)}destroy(a){this.flare=void 0;super.destroy(a)}render3D(){if(0e[mod(l,b)*a+mod(k,a)];for(g=0;gabs(e.y)?vec3(0,1,0):vec3(1,0,0)).cross(e).normalize();for(let m=0;m[vec3(-f/2,lerp(h,g,k),e),vec3(0,g,e),vec3(f/2,lerp(h,g,k),e),vec3(0,h,e)];for(var d=0;d+1g;++g)b.addQuad(e[g],e[(g+1)%4],f[(g+1)%4],f[g])}d=c(a[a.length-1]);a=c(a[0]);b.addQuad(d[0],d[1],d[2],d[3]);b.addQuad(a[3],a[2],a[1],a[0]);return b}function buildExtrude(a,b=vec2(1),c=1){let d=a,e,f;if(a instanceof TileInfo){var g=render3DReadPixels(a.textureInfo);const u=g.data,v=a.pos.x|0,y=a.pos.y|0;e=a.size.x|0;f=a.size.y|0;d=[];for(a=0;a{if(!(0>u||0>v||u>=e||v>=f)&&(u=d[v]&&d[v][u]))return isColor(u)?.5{let x=0,w;for(let A=0;A<=u;++A){const C=Ak.addStrip(render3DQuadAxes(u.add(v.scale(.5)).add(y.scale(.5)),v.scale(.5),y.scale(.5)),x,RENDER3D_QUAD_UVS,w),q=vec3(1,0,0),p=vec3(0,1,0),t=vec3(0,0,1);for(let u=0;uh(v,u),(v,y,x)=>{const w=q.scale((y-v)*l),z=p.scale(m);r(vec3(v*l-b.x/2,b.y/2-(u+1)*m,n),w,z,t,x);r(vec3(y*l-b.x/2,b.y/2-(u+1)*m,-n),w.scale(-1),z,t.scale(-1),x)}),g(e,v=>h(v,u-1)?void 0:h(v,u),(v,y,x)=>r(vec3(v*l-b.x/2,b.y/2-u*m,n),q.scale((y-v)*l),t.scale(-c),p,x)),g(e,v=>h(v,u+1)?void 0:h(v,u),(v,y,x)=>r(vec3(v*l-b.x/2,b.y/2-(u+1)*m,-n),q.scale((y-v)*l),t.scale(c),p.scale(-1),x));for(let u=0;uh(u-1,v)?void 0:h(u,v),(v,y,x)=>r(vec3(u*l-b.x/2,b.y/2-y*m,-n),t.scale(c),p.scale((y-v)*m),q.scale(-1),x)),g(f,v=>h(u+1,v)?void 0:h(u,v),(v,y,x)=>r(vec3((u+1)*l-b.x/2,b.y/2-y*m,n),t.scale(-c),p.scale((y-v)*m),q,x));return k}function buildText3D(a,b=1,c=.2,d=engineImageFont){const e=d.tileInfo;let f=render3DGlyphCache.get(d);f||render3DGlyphCache.set(d,f=new Map);const g=vec2(b*e.size.x/e.size.y,b),h=new Mesh,k=textLines(a);k.forEach((l,m)=>{m=((k.length-1)/2-m)*g.y*RENDER3D_TEXT_LEADING;l=textCharacters(l);for(let q=0;qn||127g/255));d&&!isArray(d)&&(d=render3DImageToArray(d,(g,h,k,l)=>rgb(g/255,h/255,k/255,l/255)));this.heights=a;this.colors=d;this.mapSize=b.copy();this.height=c;this.smooth=!!f;this.size3D=vec3(b.x,c,b.y);this.rebuild();render3DLevel.push(this)}get rows(){return this.heights.length}get columns(){return this.heights[0].length}getHeight(a,b){a instanceof Vector3&&(b=a.z,a=a.x);const c=this.pos3D;a-=c.x;b-=c.z;var d=this.columns,e=this.rows,f=this.heights;a=clamp((a/this.mapSize.x+.5)*(d-1),0,d-1);b=clamp((b/this.mapSize.y+.5)*(e-1),0,e-1);d=min(floor(a),d-2);e=min(floor(b),e-2);a-=d;b-=e;const g=f[e][d],h=f[e+1][d],k=f[e+1][d+1];f=f[e][d+1];return(1>=a+b?g+a*(f-g)+b*(h-g):k+(1-a)*(h-k)+(1-b)*(f-k))*this.height+c.y}getNormal(a,b){a instanceof Vector3&&(b=a.z,a=a.x);const c=this.pos3D,d=this.mapSize;return render3DSlopeNormal((e,f)=>this.getHeight(e+c.x,f+c.z),a-c.x,b-c.z,d.x/(this.columns-1)/2,d.y/(this.rows-1)/2,d.x/2,d.y/2)}getColor(a,b){a instanceof Vector3&&(b=a.z,a=a.x);const c=this.colors;if(!c)return WHITE;a-=this.pos3D.x;b-=this.pos3D.z;const d=c[0].length,e=c.length;a=clamp(round((a/this.mapSize.x+.5)*(d-1)),0,d-1);b=clamp(round((b/this.mapSize.y+.5)*(e-1)),0,e-1);return c[b][a]}raycast(a){const b=this.pos3D,c=a.origin.subtract(b),d=a.direction;var e=this.mapSize,f=this.height,g=d.length();if(g&&(a=raycastBox(new Ray3D(c,d),vec3(0,f/2,0),vec3(e.x,abs(f)+.001,e.y)),void 0!==a&&0m-n);g=m=>{m=c.add(d.scale(m));return m.y+b.y-this.getHeight(m.x+b.x,m.z+b.z)};h=a;k=g(h);if(1e-9>=abs(k))return a;a=0>=k;for(const m of e)if(!(m<=h||m>f)){e=g(m);if(1e-9>=abs(e))return m;if(0>=e!==a)return k===e?m:h+(m-h)*k/(k-e);h=m;k=e}}}buildMesh(a=render3D?.smoothShading){const b=this.pos3D,c=this.mapSize,d=a?0:c.x/(this.columns-1)/1e3,e=a?0:c.y/(this.rows-1)/1e3;return buildGrid(c,vec2(this.columns-1,this.rows-1),this.colors&&((f,g)=>this.getColor(f-d+b.x,g-e+b.z)),(f,g)=>this.getHeight(f+b.x,g+b.z)-b.y,a)}rebuild(){this.setMesh(this.buildMesh(this.smooth))}levelRaycast3D(a){return this.raycast(a)}levelSegment3D(a,b){var c=this.pos3D.y+max(this.height,0);if(!(a.y>c&&b.y>c||a.y=this.getHeight(b.x,b.z))))return{distance:c,normal:this.getNormal(a.x+(b.x-a.x)*c,a.z+(b.z-a.z)*c)}}levelCollide3D(a,b,c){var d=a.pos3D,e=this.pos3D,f=this.mapSize;if(!(abs(d.x-e.x)>f.x/2||abs(d.z-e.z)>f.y/2)){e=a.size3D.y*abs(a.scale3D.y)/2;f=this.getHeight(d.x,d.z);var g=e/2,h=max(d.y-e,f)+g;if((g=b&&this.levelSegment3D(vec3(b.x,b.y-e+g,b.z),vec3(d.x,h,d.z)))&&g.distance)d.x=b.x+(d.x-b.x)*g.distance,d.z=b.z+(d.z-b.z)*g.distance,f=this.getHeight(d.x,d.z);else if(b=c&&0>=a.velocity3D.y?hypot(d.x-b.x,d.z-b.z):0,d.y-e>f+b)return;d.y=f+e;d=a.velocity3D;0>d.y&&(d.y*=-max(a.restitution,this.restitution));a.groundObject=this}}update(){super.update();render3DLevelAssertPlaced(this)}destroy(a){render3DLevelLeave(this);super.destroy(a)}}function render3DImageData(a){a instanceof TextureInfo&&(a=a.image);const b=a.width,c=a.height;workReadCanvas.width=b;workReadCanvas.height=c;workReadContext.drawImage(a,0,0);return workReadContext.getImageData(0,0,b,c)}function render3DImageToArray(a,b){const{data:c,width:d,height:e}=render3DImageData(a);a=[];for(let f=0;fa){this.emitTimeBuffer+=a*c+(this.emitTime&&this.emitElapsed>=this.emitTime?1e-6:0);a=this.emitFrom&&this.worldPos3D.distance(this.emitFrom)<=2*objectMaxSpeed;c=floor(this.emitTimeBuffer);try{for(var d=c;d--;--this.emitTimeBuffer)this.emitBehind=a?d/c:0,this.emitParticle()}finally{this.emitBehind=0}}}else this.particleCount||this.destroy();a=this.trailTime?max(1,round(this.trailTime*frameRate)):0;if(a!==this.trailMax)for(this.trailData=(this.trailMax=a)?new Float32Array(this.particleData.length/RENDER3D_PARTICLE_FLOATS*a*3):void 0,c=20;c{e=this.particleData;f=this.trailData};const g=this.damping,h=this.angleDamping;var k=render3D.gravity,l=this.gravityScale;const m=k.x*l*b,n=(this.gravity+k.y*l)*b;b*=k.z*l;k=this.collideLevel&&enablePhysicsSolver&&render3DLevel.length;l=this.particleUpdateCallback;const r=this.particleDestroyCallback;for(let u=this.particleCount;u--;){const v=u*c;var q=e[v+3]=e[v+3]*g+m,p=e[v+4]=e[v+4]*g+n,t=e[v+5]=e[v+5]*g+b;e[v]+=q;e[v+1]+=p;e[v+2]+=t;e[v+18]+=e[v+19]*=h;p=k&&this.particleCollide(v,e[v]-q,e[v+1]-p,e[v+2]-t);k&&d();q=u*a*3;if(a){t=e[v+20];t===a&&(f.copyWithin(q,q+3,q+3*t),--t);const y=q+3*t;f[y]=e[v];f[y+1]=e[v+1];f[y+2]=e[v+2];e[v+20]=t+1}l&&!p&&(this.particleCall(l,v),d());(e[v+17]+=timeDelta)>=e[v+16]&&(r&&(this.particleCall(r,v),d()),p=--this.particleCount,t=p*c,u!==p&&(e.copyWithin(v,t,t+c),a&&f.copyWithin(q,p*a*3,(p+1)*a*3)))}}destroy(a){if(a||this.destroyed)return super.destroy(a);this.particleCount?(this.emitTime=-1,render3DDetach(this)):(super.destroy(a),this.finishCallback?.(this))}emitParticle(){const a=()=>rand(1-this.randomness,1+this.randomness);var b=render3DObjectMatrix(this);const c=render3DMaxScale(b.m);var d=this.emitSize,e=this.emitFlat;isVector3(d)?e=vec3(rand(-.5,.5)*d.x,e?0:rand(-.5,.5)*d.y,rand(-.5,.5)*d.z):e?(d=randInCircle(d/2),e=vec3(d.x,0,d.y)):e=randInSphere(d/2);d=b.transformDirection(randVector3(1,this.emitConeAngle)).normalize();b=b.transformPoint(e);e=this.speed*a()*c;var f=this.emitFrom,g=this.emitBehind;if(f&&g){var h=this.worldPos3D;b.x+=(f.x-h.x)*g;b.y+=(f.y-h.y)*g;b.z+=(f.z-h.z)*g}f=randColor(this.colorStartA,this.colorStartB,!0);g=randColor(this.colorEndA,this.colorEndB,!0);var k=RENDER3D_PARTICLE_FLOATS;h=this.particleCount++*k;h+k>this.particleData.length&&(k=new Float32Array(2*this.particleData.length),k.set(this.particleData),this.particleData=k,this.trailData&&(k=new Float32Array(2*this.trailData.length),k.set(this.trailData),this.trailData=k));k=this.particleData;k[h]=b.x;k[h+1]=b.y;k[h+2]=b.z;k[h+3]=d.x*e;k[h+4]=d.y*e;k[h+5]=d.z*e;k[h+6]=f.r;k[h+7]=f.g;k[h+8]=f.b;k[h+9]=f.a;k[h+10]=g.r;k[h+11]=g.g;k[h+12]=g.b;k[h+13]=g.a;k[h+14]=this.sizeStart*a()*c;k[h+15]=this.sizeEnd*a()*c;k[h+16]=this.particleTime*a();k[h+17]=0;k[h+18]=this.angleSpeed?rand(2*PI):0;k[h+19]=this.angleSpeed?this.angleSpeed*a()*randSign():0;k[h+20]=0;this.particleView.scale=c;this.particleCreateCallback&&this.particleCall(this.particleCreateCallback,h)}particleCall(a,b,c,d){const e=render3DParticlesCalling.has(this),f=e?render3DParticleView(this):this.particleView,g=this.particleData;f.scale=this.particleView.scale;f.pos.set(g[b],g[b+1],g[b+2]);f.velocity.set(g[b+3],g[b+4],g[b+5]);f.age=g[b+17];f.lifeTime=g[b+16];f.destroyed=!1;render3DParticlesCalling.add(this);let h;try{h=a(f,c,d)}finally{e||render3DParticlesCalling.delete(this)}a=this.particleData;a[b]=f.pos.x;a[b+1]=f.pos.y;a[b+2]=f.pos.z;a[b+3]=f.velocity.x;a[b+4]=f.velocity.y;a[b+5]=f.velocity.z;a[b+16]=f.lifeTime;a[b+17]=f.age;f.destroyed&&(a[b+17]=max(a[b+17],a[b+16]));return h}particleCollide(a,b,c,d){var e=this.particleData;b=render3DParticleFrom.set(b,c,d);e=render3DParticleTo.set(e[a],e[a+1],e[a+2]);for(var f of render3DLevel)if((c=f.destroyed?void 0:f.levelSegment3D(b,e))&&(!g||c.distancethis.render3D());const b=this.fadeRate/2,c=this.tileInfo||render3DSoftDot(),d=render3DParticleColor,e=render3DParticleSize,f=a.billboardMesh,g=c&&a.instancing&&!a.capture&&render3DCanDraw();let h,k,l,m;g&&(render3DMeshUpload(f),k=render3DTextureOf(c),l=render3DGetTileUVs(c),m=a.lighting,a.lighting=a.shadowPass&&m,a.cullBackFaces=a.mirrored=!1);const n=a.cameraBack,r=RENDER3D_PARTICLE_FLOATS,q=this.particleData,p=this.trailMax,t=render3DParticlePos;try{for(let y=0,x=this.particleCount;y1-b?(1-w)/b:1;d.r=q[u+6]+(q[u+10]-q[u+6])*w;d.g=q[u+7]+(q[u+11]-q[u+7])*w;d.b=q[u+8]+(q[u+12]-q[u+8])*w;d.a=(q[u+9]+(q[u+13]-q[u+9])*w)*v;const z=e.x=e.y=lerp(q[u+14],q[u+15],w),A=q[u+18],C=q[u+20];if(1this.lifeTime;)a.shift();this.finishing&&!a.length&&this.destroy()}render3D(){var a=this.samples;if(!(2>a.length)){var b=[],c=[],d=[],e=this.side?[]:void 0;for(const f of a)a=clamp((time-f.time)/this.lifeTime),b.push(f.pos),c.push(this.width*(1-a)),d.push(this.color.lerp(this.colorEnd,a)),e?.push(f.side);render3D.drawRibbon(b,c,this.tileInfo,d,e)}}}const render3DFlareShapes="glow disc ring hex streak star".split(" ");let render3DFlareTiles;function render3DFlareTile(a){if(!render3DFlareTiles){if(headlessMode||!glContext||!canvasAvailable())return;const b=render3DFlareShapes,c=createCanvasContext(128*b.length,128),d={glow:h=>engineGlowAlpha(h,1),disc:h=>.8>h?.4+.1*h:.92>h?.48+3*(h-.8):(1-h)/.08*.84,ring:h=>max(0,1-abs(h-.86)/.12),hex:h=>.8>h?.4+.1*h:.92>h?.48+3*(h-.8):(1-h)/.08*.84,streak:h=>(1-h)**1.5},e=(h,k,l)=>{const m=c.createRadialGradient(0,0,0,0,0,k);for(let n=0;32>=n;++n)m.addColorStop(n/32,"rgba(255,255,255,"+clamp(d[h](n/32)).toFixed(4)+")");c.fillStyle=m;c.beginPath();l?l():c.arc(0,0,k,0,2*PI);c.fill()},f=(h,k)=>{c.save();c.rotate(k);c.scale(1,.07);e("streak",h);c.restore()};b.forEach((h,k)=>{c.save();c.translate(128*k+64,64);if("hex"==h){h=c.createImageData(128,128);const m=h.data,n=62*cos(PI/6);for(let r=0;16384>r;++r){var l=abs(r%128+.5-64);const q=abs((r/128|0)+.5-64);l=max(q,l*cos(PI/6)+q/2)/n;m[4*r]=m[4*r+1]=m[4*r+2]=255;m[4*r+3]=1>l?255*clamp(d.hex(l)):0}c.putImageData(h,128*k,0)}else if("streak"==h)f(62,0);else if("star"==h){for(k=3;k--;)f(62,k*PI/3+PI/2);c.scale(.3,.3);e("glow",62)}else e(h,62);c.restore()});const g=new TextureInfo(c.canvas,!0,!1,!1);render3DFlareTiles=new Map(b.map((h,k)=>[h,new TileInfo(vec2(128*k,0),vec2(128),g)]))}return render3DFlareTiles.get(a)||render3DFlareTiles.get("glow")}class LensFlare3D extends EngineObject3D{constructor(a=1,b=7,c=1,d=1,e=WHITE){super(vec3(),void 0,void 0,e);this.size3D=vec3();this.flareSize=a;this.count=b;this.intensity=c;this.saturation=d;this.seed=1;this.shapes=void 0;this.ghostSize=this.glowSize=1;this.light=this.elements=void 0;this.occlusion=!0;this.fadeTime=.15;this.visible=0;this.visibleFound=!1;this.renderOrder=1e9;this.madeKey="";this.made=[]}getElements(){if(this.elements)return this.elements;const a=this.shapes?.length?this.shapes:void 0;var b=this.glowSize;const c=this.ghostSize,d=[this.count,this.seed,this.saturation,b,c,a?.length,a].join();if(d!==this.madeKey){const f=new RandomGenerator(7919*this.seed+1),g=clamp(this.saturation);b=this.made=0e?"disc":.8>e?"ring":"glow";b.push({at:k,size:f.float(.04,.1)*(1+k)*c,shape:e,color:hsl(f.float(),.9*g,.6,f.float(.15,.4))})}this.madeKey=d}return this.made}flareSource(){var a=render3D.camera.pos,b=this.light;if(!b?.destroyed){if(!b||b.directional){b=b?b.getWorldPos3D():render3D.sunDirection;if(!b.lengthSquared())return;b=b.normalize();return{direction:b,distance:Infinity,pos:a.add(b.scale(100))}}b=b.getWorldPos3D();a=b.subtract(a);var c=a.length();return c?{direction:a.scale(1/c),distance:c,pos:b}:void 0}}flareLook(){const a=this.flareSource(),b=mainCanvasSize.scale(.5),c=a&&render3D.worldToScreen(a.pos);if(c&&b.x&&b.y){var d=max(abs(c.x-b.x)/b.x,abs(c.y-b.y)/b.y);d=clamp((1.3-d)/.5)*this.intensity;if(0{const h=g.color.multiply(d),k="number"==typeof g.size?g.size*e:g.size.scale(e);return{pos:b.add(c.subtract(b).scale(g.at)),size:k,shape:g.shape,tileInfo:g.tileInfo,angle:g.angle||0,color:rgb(h.r,h.g,h.b,h.a*f)}})}isHidden(){const a=this.flareSource();if(!a)return!0;const b=new Ray3D(render3D.camera.pos,a.direction),c=a.distance;var d=engineObjects.filter(h=>h!==this&&h instanceof EngineObject3D&&!h.destroyed&&!h.transparent&&!render3DSetting(h,"additive"));const e="undefined"==typeof VoxelMap?[]:d.filter(h=>h instanceof VoxelMap);for(const h of e)if(h.raycast(b,c,k=>!h.blockType(k).seeThrough))return!0;const f=h=>{if(!h.mesh||h instanceof HeightMap)return!1;var k=render3DObjectMatrix(h);h=h.mesh.bounds||h.mesh.getBounds();var l=k.m;l=min((h.max.x-h.min.x)*hypot(l[0],l[1],l[2]),(h.max.y-h.min.y)*hypot(l[4],l[5],l[6]),(h.max.z-h.min.z)*hypot(l[8],l[9],l[10]));if(!k.determinant()||l>2*g)return!1;k=k.copy().invert().transformPoint(a.pos);return k.x>=h.min.x&&k.x<=h.max.x&&k.y>=h.min.y&&k.y<=h.max.y&&k.z>=h.min.z&&k.z<=h.max.z},g=this.light&&Infinity>c?min(2,.4*this.light.radius):0;d=d.filter(h=>!e.some(k=>k===h));for(let h=5;h--;){const k=render3D.pick(b,d);if(!k||k.distance>=c)return!1;if(!(c-k.distance<=g&&f(k.object)))break;d=d.filter(l=>l!==k.object)}return!0}update(){super.update();if(this.light?.destroyed)return this.destroy();this.updateVisible(timeDelta)}updateVisible(a){this.visibleFound||render3D.updateMatrices();const b=!!this.flareLook()&&!(this.occlusion&&this.isHidden());a=0{t=parseInt(t);return 0>t?u.length+t:t-1};for(const t of a.replace(/\\\r?\n/g," ").split(/\r\n?|\n/))switch(a=t.replace(/#.*/,"").trim().split(/\s+/),a[0]){case"v":c.push(vec3(+a[1],+a[2],+a[3]));break;case"vn":d.push(vec3(+a[1],+a[2],+a[3]));break;case"vt":e.push(vec2(+a[1],1-(+a[2]||0)));break;case"f":a=a.slice(1).map(x=>x.split("/"));if(3>a.length)break;const u=a.map(x=>c[q(x[0],c)]);if(!u.every(isVector3))break;const v=a.every(x=>x[2]);n||=!v;const y=v?void 0:render3DFaceNormal(u[0],u[1],u[2],u[3]);a=a.map((x,w)=>{const z=q(x[0],c)+"/"+(x[1]?q(x[1],e):"")+"/"+(v?q(x[2],d):b?"":"f"+r);let A=l.get(z);void 0===A&&(l.set(z,A=f.length),f.push(u[w]),h.push(x[1]?e[q(x[1],e)]:RENDER3D_DEFAULT_UV),g.push(v?d[q(x[2],d)]:y),m.push(v));return A});for(let x=2;xu&&(p.normals[v]=t[v]))}return p}async function loadOBJ(a,b=render3D?.smoothShading){var c=await loadFetch(a,"loadOBJ");if(!c.ok)throw Error(`loadOBJ: could not load ${a}, ${c.status} ${c.statusText}`);c=await c.text();b=parseOBJ(c,b);b.points.length||console.warn("loadOBJ: "+a+" has no faces"+(loadIsWebPage(c)?", it is a web page, so the path may be wrong":""));return b}const RENDER3D_CSG_EPSILON=1e-5;class Render3DCSGVertex{constructor(a,b,c,d){this.pos=a;this.normal=b;this.uv=c;this.color=d}lerp(a,b){return new Render3DCSGVertex(this.pos.lerp(a.pos,b),this.normal.lerp(a.normal,b),this.uv.lerp(a.uv,b),this.color.lerp(a.color,b))}flipped(){return new Render3DCSGVertex(this.pos,this.normal.scale(-1),this.uv,this.color)}}class Render3DCSGPolygon{constructor(a,b){this.vertices=a;this.plane=b}flipped(){const a={normal:this.plane.normal.scale(-1),w:-this.plane.w};return new Render3DCSGPolygon(this.vertices.map(b=>b.flipped()).reverse(),a)}}class Render3DCSGNode{constructor(){this.back=this.front=this.plane=void 0;this.polygons=[]}}function render3DCSGPlane(a,b,c){b=b.subtract(a).cross(c.subtract(a));if(!(1e-18>b.lengthSquared()))return b=b.normalize(),{normal:b,w:b.dot(a)}}function render3DCSGSplit(a,b,c,d,e,f){const{normal:g,w:h}=a;a=b.vertices;const k=[];var l=0;for(var m of a){var n=g.dot(m.pos)-h;n=n<-RENDER3D_CSG_EPSILON?2:n>RENDER3D_CSG_EPSILON?1:0;l|=n;k.push(n)}if(0===l)(0d.x+g||md.y+g||nd.z+g||r{var d=floor(c.x/a);const e=floor(c.y/a),f=floor(c.z/a);for(let g=d-1;g<=d+1;++g)for(let h=e-1;h<=e+1;++h)for(let k=f-1;k<=f+1;++k)for(const l of b.get(g+","+h+","+k)||[])if(l.distanceSquared(c)new Render3DCSGVertex(c.points[d],c.normals[d],c.uvs[d],c.colors[d]);b=[];for(let d=0;d{const t=[];for(const u of p.vertices)p=c(u.pos),d.add(p),t.length&&t[t.length-1].pos===p||t.push(new Render3DCSGVertex(p,u.normal,u.uv,u.color));1{var t=floor((p.x-f.x)/k),u=floor((p.y-f.y)/k);p=floor((p.z-f.z)/k);return t+","+u+","+p};for(var m of e)e=h(m),l.has(e)||l.set(e,[]),l.get(e).push(m);m=(p,t)=>{const u=[],v=t.subtract(p),y=v.lengthSquared();var x=floor((min(p.x,t.x)-f.x-b)/k);const w=floor((max(p.x,t.x)-f.x+b)/k),z=floor((min(p.y,t.y)-f.y-b)/k),A=floor((max(p.y,t.y)-f.y+b)/k),C=floor((min(p.z,t.z)-f.z-b)/k),D=floor((max(p.z,t.z)-f.z+b)/k);for(;x<=w;++x)for(let B=z;B<=A;++B)for(let E=C;E<=D;++E)for(const F of l.get(x+","+B+","+E)||[]){if(F===p||F===t)continue;const G=F.subtract(p).dot(v)/y;0>=G||1<=G||p.add(v.scale(G)).distanceSquared(F)B[0]-E[0])};const n=new Mesh,r=new Map;n.indices=[];const q=p=>{const t=p.normal.lengthSquared()?p.normal.normalize():RENDER3D_DEFAULT_NORMAL,u=p.color,v=[t.x,t.y,t.z,p.uv.x,p.uv.y,u.r,u.g,u.b,u.a].map(w=>round(1e6*w)).join();let y=r.get(p.pos),x;y||r.set(p.pos,y=new Map);void 0===(x=y.get(v))&&(y.set(v,x=n.points.length),n.points.push(p.pos.copy()),n.normals.push(t),n.uvs.push(p.uv.copy()),n.colors.push(u.copy()));return x};for(const p of a){if(3>p.length)continue;a=[];for(e=0;et.lengthSquared())continue;const u=a.map(y=>({pos:y.pos,id:q(y)})),v=y=>{const x=u[(y+u.length-1)%u.length].pos,w=u[(y+1)%u.length].pos;return u[y].pos.subtract(x).cross(w.subtract(x))};for(;3{y=v(x);return 1e-18<=y.lengthSquared()&&1e-18<=t.subtract(y).lengthSquared()}),0>a&&(a=0),t=t.subtract(v(a)),n.indices.push(u[(a+u.length-1)%u.length].id,u[a].id,u[(a+1)%u.length].id),u.splice(a,1);n.indices.push(u[0].id,u[1].id,u[2].id)}n.dirty=!0;return n}function render3DMeshCSG(a,b,c,d){a=render3DCSGPolygons(a);var e=render3DCSGPolygons(b,c);const[f,g]=render3DCSGNear(a,e),[h,k]=render3DCSGNear(e,a);b=new Render3DCSGNode;c=new Render3DCSGNode;render3DCSGBuild(b,a);render3DCSGBuild(c,e);a=render3DCSGClipPolygons;e=l=>l.map(m=>m.flipped());0===d?d=[...g,...a(c,f),...k,...e(a(b,e(a(b,h))))]:1===d?(render3DCSGInvert(b),d=[...g,...e(a(c,e(f))),...a(b,e(a(b,h)))]):(render3DCSGInvert(b),render3DCSGInvert(c),d=[...e(a(c,e(f))),...e(a(b,e(a(b,h))))]);return render3DCSGMesh(d)}const RENDER3D_VOXEL_CHUNK=16,RENDER3D_VOXEL_FACES=[[vec3(1,0,0),vec3(0,0,-1),vec3(0,1,0)],[vec3(-1,0,0),vec3(0,0,1),vec3(0,1,0)],[vec3(0,1,0),vec3(1,0,0),vec3(0,0,-1)],[vec3(0,-1,0),vec3(1,0,0),vec3(0,0,1)],[vec3(0,0,1),vec3(1,0,0),vec3(0,1,0)],[vec3(0,0,-1),vec3(-1,0,0),vec3(0,1,0)]],RENDER3D_VOXEL_SHADES=[.55,.7,.85,1].map(a=>Object.freeze(rgb(a,a,a))),RENDER3D_VOXEL_CORNERS=RENDER3D_VOXEL_FACES.map(([a,b,c])=>render3DQuadAxes(a.scale(.5),b.scale(.5),c.scale(.5))),RENDER3D_VOXEL_CORNER_SIDES=[[-1,1],[-1,-1],[1,1],[1,-1]],RENDER3D_VOXEL_ORDER=[0,1,2,3],RENDER3D_VOXEL_FLIPPED=[1,3,0,2];class VoxelMap extends EngineObject3D{constructor(a=vec3(),b=vec3(16),c=tile()){super(a);this.mapSize=b.floor();this.tileInfo=c;this.data=new Uint8Array(this.mapSize.x*this.mapSize.y*this.mapSize.z);this.ambientOcclusion=!0;this.size3D=vec3();a=RENDER3D_VOXEL_CHUNK;b=this.mapSize;this.chunkCount=vec3(ceil(b.x/a),ceil(b.y/a),ceil(b.z/a));this.chunkMeshes=[];this.chunkTransparentMeshes=[];this.chunkCenters=[];this.chunksChanged=new Set;this.blockTypes=[];this.tiles=new Map;a=new EngineObject3D;a.size3D=vec3();a.transparent=!0;a.render3D=()=>this.renderChunks(!0);render3DShareSettings(a,this);this.addChild(a);render3DLevel.push(this)}getVoxel(a){return this.voxelAt(floor(a.x),floor(a.y),floor(a.z))}voxelAt(a,b,c){const d=this.mapSize;return 0>a||0>b||0>c||a>=d.x||b>=d.y||c>=d.z?0:this.data[a+d.x*(b+d.y*c)]}setVoxel(a,b){const c=floor(a.x),d=floor(a.y);a=floor(a.z);var e=this.mapSize;if(!(0>c||0>d||0>a||c>=e.x||d>=e.y||a>=e.z)&&(e=c+e.x*(d+e.y*a),this.data[e]!==b))for(this.data[e]=b,this.markChunk(c,d,a),b=-1;1>=b;++b)for(e=-1;1>=e;++e)for(let f=-1;1>=f;++f)(this.ambientOcclusion||1===abs(f)+abs(e)+abs(b))&&this.voxelAt(c+f,d+e,a+b)&&this.markChunk(c+f,d+e,a+b)}markChunk(a,b,c){const d=this.mapSize,e=this.chunkCount,f=RENDER3D_VOXEL_CHUNK;0>a||0>b||0>c||a>=d.x||b>=d.y||c>=d.z||this.chunksChanged.add(floor(a/f)+e.x*(floor(b/f)+e.y*floor(c/f)))}setBlockType(a,b,{seeThrough:c=!1,transparent:d=!1,doubleSided:e=!1}={}){b=isNumber(b)?[b,b,b,b,b,b]:isArray(b)?b:[b.side,b.side,b.top??b.side,b.bottom??b.side,b.side,b.side];this.blockTypes[a]={faces:b,seeThrough:c||d,transparent:d,doubleSided:e};this.rebuild()}blockType(a){let b;return(b=this.blockTypes)[a]||(b[a]={faces:[a,a,a,a,a,a],seeThrough:!1,transparent:!1,doubleSided:!1})}rebuild(){this.tiles.clear();var a=this.chunkCount;for(a=a.x*a.y*a.z;a--;)this.chunksChanged.add(a)}buildChunks(){for(const a of this.chunksChanged)this.buildChunk(a);this.chunksChanged.clear()}buildChunk(a){var b=this.chunkCount,c=RENDER3D_VOXEL_CHUNK;const d=this.mapSize,e=this.data,f=a%b.x*c,g=floor(a/b.x)%b.y*c;var h=floor(a/(b.x*b.y))*c;b=min(f+c,d.x);const k=min(g+c,d.y);c=min(h+c,d.z);const l=vec3((f+b)/2,(g+k)/2,(h+c)/2),m=new Mesh,n=new Mesh,r=this.ambientOcclusion,q=(D,B,E)=>(D=this.voxelAt(D,B,E))&&!this.blockType(D).seeThrough?1:0,p=[],t=[],u=[],v=[];for(;hL;++L){const[I,K,N]=RENDER3D_VOXEL_FACES[L];var y=B+I.x,x=D+I.y,w=h+I.z,z=this.voxelAt(y,x,w);if(!z||z!==E&&this.blockType(z).seeThrough){for(z=0;4>z;++z){const[O,P]=RENDER3D_VOXEL_CORNER_SIDES[z];var A=r&&q(y+K.x*O,x+K.y*O,w+K.z*O),C=r&&q(y+N.x*P,x+N.y*P,w+N.z*P);const Q=r&&q(y+K.x*O+N.x*P,x+K.y*O+N.y*P,w+K.z*O+N.z*P);v[z]=A&&C?0:3-+A-+C-+Q}y=RENDER3D_VOXEL_CORNERS[L];x=this.tileUVs(F.faces[L]);w=v[0]+v[3]>v[1]+v[2]?RENDER3D_VOXEL_FLIPPED:RENDER3D_VOXEL_ORDER;for(z=0;4>z;++z)A=w[z],C=y[A],p[z]=vec3(H+C.x,J+C.y,M+C.z),t[z]=x[A],u[z]=r?RENDER3D_VOXEL_SHADES[v[A]]:WHITE;G.addStrip(p,I,t,u);F.doubleSided&&G.addStrip([p[0],p[2],p[1],p[3]],I.scale(-1),[t[0],t[2],t[1],t[3]],[u[0],u[2],u[1],u[3]])}}}this.chunkMeshes[a]?.dispose();this.chunkTransparentMeshes[a]?.dispose();this.chunkMeshes[a]=m.points.length?m:void 0;this.chunkTransparentMeshes[a]=n.points.length?n:void 0;this.chunkCenters[a]=l}tileUVs(a){var b=this.tiles.get(a);if(!b){b=this.tileInfo;const c=render3DGetTileUVs(b.columns?b.frame(a):b.index(a));b=RENDER3D_QUAD_UVS.map(d=>Object.freeze(vec2(c.x+d.x*c.w,c.y+d.y*c.h)));this.tiles.set(a,b)}return b}boxBlocked(a,b,c){var d=this.pos3D;const e=this.mapSize;var f=(r,q,p,t)=>{const u=floor(r-q-p+1e-9);r=max(ceil(r+q-p-1e-9)-1,u);return[max(u,0),min(r,t-1)]};const[g,h]=f(a.x,b.x/2,d.x,e.x),[k,l]=f(a.y,b.y/2,d.y,e.y),[m,n]=f(a.z,b.z/2,d.z,e.z);for(a=m;a<=n;++a)for(b=k;b<=l;++b)for(d=g;d<=h;++d)if((f=this.data[d+e.x*(b+e.y*a)])&&c.collideWithVoxel(f,vec3(d,b,a)))return!0;return!1}levelCollide3D(a,b){var c=a.scale3D;c=vec3(a.size3D.x*abs(c.x),a.size3D.y*abs(c.y),a.size3D.z*abs(c.z));const d=a.pos3D,e=a.velocity3D,f=this.pos3D;if(this.boxBlocked(d,c,a))if(this.boxBlocked(b,c,a)){var g=c.y/2,h=vec3(c.x,0,c.z),k;for(var l=floor(b.y-g-f.y);l<=floor(b.y-f.y);++l)this.boxBlocked(vec3(b.x,f.y+l+.5,b.z),h,a)&&(k=l+1);if((g=void 0===k?void 0:vec3(b.x,f.y+k+g+1e-4,b.z))&&!this.boxBlocked(g,c,a))d.set(g.x,g.y,g.z),e.y=max(e.y,0),a.groundObject=this;else{b=b.copy();for(var m of["y","x","z"]){const r=d[m]-b[m],q=c[m]/2,p=f[m];if(!r)continue;k=u=>0r&&(a.groundObject=this),e[m]=0):b[m]=d[m]}d.set(b.x,b.y,b.z)}}else{m=max(a.restitution,this.restitution);k=b.copy();for(g of["y","x","z"])if(h=k.copy(),h[g]=d[g],this.boxBlocked(h,c,a)){l=c[g]/2;if(n=d[g]-b[g])h[g]=0>n?f[g]+floor(d[g]-l-f[g])+1+l+1e-4:f[g]+ceil(d[g]+l-f[g])-1-l-1e-4,this.boxBlocked(h,c,a)||(k[g]=h[g]);"y"===g&&0>n&&(a.groundObject=this);e[g]*=-m}else k[g]=d[g];d.set(k.x,k.y,k.z)}}raycast(a,b=Infinity,c=()=>!0){const d=this.mapSize;var e=a.origin.subtract(this.pos3D),f=a.direction;a=["x","y","z"];if(f.lengthSquared()){var g=0,h=b,k=-1;for(var l=0;3>l;++l){var m=a[l],n=f[m],r=e[m];if(n){var q=-r/n;m=(d[m]-r)/n;q>m&&([q,m]=[m,q]);q>g&&(g=q,k=l);h=min(h,m)}else if(0>r||r>d[m])return}if(!(g>h)){q=e.add(f.scale(g));e=[];var p=[];h=[];l=[];for(m=0;3>m;++m)n=a[m],r=f[n],e[m]=clamp(floor(q[n]),0,d[n]-1),p[m]=sign(r),h[m]=r?g+(e[m]+(0vec3(0===t?-p[0]:0,1===t?-p[1]:0,2===t?-p[2]:0);0<=k?f=q(k):(f=abs(f.x)>=abs(f.y)&&abs(f.x)>=abs(f.z)?0:abs(f.y)>=abs(f.z)?1:2,f=q(f));for(;g<=b;){if(k=this.data[e[0]+d.x*(e[1]+d.y*e[2])])if(m=vec3(e[0],e[1],e[2]),c(k,m))return{distance:g,cell:m,normal:f,type:k};f=h[0]e[f]||e[f]>=d[a[f]])break;h[f]+=l[f];f=q(f)}}}}levelRaycast3D(a){return this.raycast(a)?.distance}levelSegment3D(a,b){const c=b.subtract(a);if(b=this.raycast(new Ray3D(a,c),1))return!b.distance&&(a=a.subtract(c.normalize(1e-6)).subtract(this.pos3D),this.voxelAt(floor(a.x),floor(a.y),floor(a.z)))?void 0:{distance:b.distance,normal:b.normal}}update(){super.update();render3DLevelAssertPlaced(this)}render3D(){this.renderChunks(!1)}renderChunks(a){this.buildChunks();a=a?this.chunkTransparentMeshes:this.chunkMeshes;const b=this.pos3D,c=this.tileInfo.textureInfo;for(let d=0;dc)break;c=min(e+floor(c),b.length);b.fill(0<=f&&255>=f&&0===f%1?f:0,e,c);e=c}}function level3DVoxelsShape(a){if(a&&"object"===typeof a){var b=level3DVector(a.size);if(!(!b||[b.x,b.y,b.z].some(c=>1>c||c%1)||b.x*b.y*b.z>LEVEL3D_VOXEL_CELLS))return{pos:level3DVector(a.pos,vec3()),size:b}}}function level3DVoxelsMake(a){var b=level3DVoxelsShape(a);if(b&&"undefined"!=typeof VoxelMap)return b=new VoxelMap(b.pos,b.size,level3DVoxelTiles||level3DVoxelPlainTiles()),level3DVoxelsDecode(a.blocks,b.data),level3DVoxelSetupMap?.(b),b.rebuild(),b}let level3DTerrainMap;const LEVEL3D_TERRAIN_SAMPLES=129;function level3DTerrainShape(a){if(a&&"object"===typeof a){var b=a.size,c=a.heights,d=LEVEL3D_TERRAIN_SAMPLES;if(isArray(b)&&2===b.length&&b.every(f=>level3DFinite(f)&&0c.length||c.length>d)&&isArray(c[0])){var e=c[0].length;if(!(2>e||e>d)&&c.every(f=>isArray(f)&&f.length===e))return c=c.map(f=>f.map(g=>level3DFinite(g)?clamp(g):0)),{pos:level3DVector(a.pos,vec3()),size:vec2(b[0],b[1]),height:level3DFinite(a.height)&&0"number"===typeof a&&isFinite(a);function level3DTerrainPaint(a,b){var c=a?.paint;a=c?.colors;c=c?.cells;if(isArray(a)&&isArray(c)&&!(255a.length||e+g>b)return;d.fill(h,e,e+=g)}return e===b?{colors:a.slice(),cells:d}:void 0}}function level3DTerrainSetColors(a,b,c=level3DTerrainPaint(b,a.rows*a.columns)){const d=level3DHexColor(b.color)||WHITE;a.color=d;a.colors=void 0;if(c&&c.cells.some(f=>f)){var e=[d,...c.colors.map(level3DHexColor)];a.color=WHITE;a.colors=a.heights.map((f,g)=>f.map((h,k)=>e[c.cells[g*a.columns+k]]||d))}}let level3DVoxelPlain;function level3DVoxelPlainTiles(){if(textureInfos[0]?.size.x||headlessMode||!canvasAvailable())return tile();if(!level3DVoxelPlain){const a=createCanvasContext(256);for(let b=0;256>b;++b){const c=b%16*16,d=16*(b/16|0),e=.618*b%1;a.fillStyle=hsl(e,.45,.4).toString();a.fillRect(c,d,16,16);a.fillStyle=hsl(e,.5,.55).toString();a.fillRect(c+1,d+1,14,14)}level3DVoxelPlain=new TextureInfo(a.canvas)}return tile(0,16,level3DVoxelPlain,0)}function level3DTerrainMake(a){var b=level3DTerrainShape(a);if(b&&"undefined"!=typeof HeightMap)return b=new HeightMap(b.heights,b.size,b.height,void 0,b.pos),level3DTerrainSetColors(b,a),b.colors&&b.rebuild(),b}const level3DSkies=new WeakSet;function level3DSceneApply(a){++level3DSceneCubeLoads.skyBox;++level3DSceneCubeLoads.environment;const b=render3D;if(b&&a&&"object"===typeof a){var c=level3DHexColor,d=isArray(a.sky)&&3===a.sky.length?a.sky.map(c):[];if(d.length&&d.every(e=>e)){const[e,f,g]=d;d=level3DFinite(a.ambient)?a.ambient:.5;level3DSkies.has(b.sky)&&b.sky.dispose();level3DSkies.add(b.sky=buildSky(e,f,g));b.fogColor=f.copy();b.ambientColor=e.scale(d,1);b.ambientGroundColor=g.scale(d,1)}(d=level3DVector(a.sunDirection))&&d.lengthSquared()&&(b.sunDirection=d);b.sunColor=c(a.sunColor)||b.sunColor;d=a.fog;isArray(d)&&2===d.length&&d.every(level3DFinite)&&(b.fogStart=d[0],b.fogEnd=d[1]);b.fogColor=c(a.fogColor)||b.fogColor;"boolean"===typeof a.shadows&&(b.shadows=a.shadows);"boolean"===typeof a.lensFlare&&level3DSceneFlare(a.lensFlare);level3DSceneCubeMap("skyBox",a.skyBox);level3DSceneCubeMap("environment",a.environment)}}const level3DSceneCubeMaps=new Map,level3DSceneCubeLoaded=new WeakMap,level3DSceneCubeLoads={skyBox:0,environment:0};function level3DSceneCubeMap(a,b){if(isArray(b)&&6===b.length&&b.every(g=>"string"===typeof g)){var c=b.join("\n"),d=++level3DSceneCubeLoads[a],e=render3D[a],f=level3DSceneCubeMaps.get(c);level3DSceneCubeMaps.delete(c);level3DSceneCubeMaps.set(c,f||=loadCubeMap(b));f.then(g=>level3DSceneCubeLoaded.set(f,g),()=>{});for(const[g,h]of level3DSceneCubeMaps){if(4>=level3DSceneCubeMaps.size)break;b=level3DSceneCubeLoaded.get(h);if(!b||b!==render3D.skyBox&&b!==render3D.environment)level3DSceneCubeMaps.delete(g),h.then(k=>k!==render3D.skyBox&&k!==render3D.environment&&k.dispose(),()=>{})}f.then(g=>d===level3DSceneCubeLoads[a]&&render3D[a]===e&&(render3D[a]=g),g=>{level3DSceneCubeMaps.get(c)===f&&level3DSceneCubeMaps.delete(c);console.warn(g.message)})}}let level3DSunFlare;function level3DSceneFlare(a){a?level3DSunHasFlare()||(level3DSunFlare=new LensFlare3D):(level3DSunFlare&&!level3DSunFlare.destroyed&&level3DSunFlare.destroy(),level3DSunFlare=void 0)}const level3DSunHasFlare=()=>engineObjects.some(a=>a instanceof LensFlare3D&&!a.destroyed&&!a.light);function level3DVector(a,b){return isArray(a)&&3===a.length&&a.every(level3DFinite)?vec3(a[0],a[1],a[2]):b}function level3DProperties(a,b){const c={};b=b.properties;for(const[d,e]of Object.entries(a.defaults))c[d]=e?.copy?e.copy():e;for(const[d,e]of Object.entries(b&&"object"===typeof b?b:{}))if(b=a.defaults[d],isColor(b))level3DHexColor(e)&&(c[d]=level3DHexColor(e));else if(isVector3(b))c[d]=level3DVector(e,c[d]);else if(isVector2(b))isArray(e)&&2===e.length&&e.every(level3DFinite)&&(c[d]=vec2(e[0],e[1]));else if("number"===typeof b)level3DFinite(e)&&(c[d]=e);else if(void 0===b||typeof e===typeof b)c[d]=e;return c}function level3DMake(a){return level3DMakeAt(a,level3DVector(a.pos,vec3()),level3DVector(a.rotation,vec3()).scale(PI/180),level3DVector(a.scale,vec3(1)))}function level3DMakeAt(a,b,c,d){const e=level3DTypes.get(a.type);if(e){var f=level3DProperties(e,a),{make:g}=e,h=engineObjects.length;try{var k=g.prototype?new g(b,f):g(b,f)}catch(l){if(!debug)throw l;console.error(`level3DLoad: ${a.type} ${a.id} could not be made, skipped:`,l);for(const m of engineObjects.slice(h))m.destroy();return}if(k&&"object"===typeof k){k instanceof EngineObject3D&&(level3DBaseScale.set(k,k.scale3D.copy()),k.rotation3D=c.copy(),k.scale3D=k.scale3D.multiply(d));for(const l in e.defaults)k[l]=f[l];k instanceof Prefab3D&&k.placeAt(b);return k}}else debug&&console.warn(`level3DLoad: no type added for ${a.type}, skipped`)}function level3DSpawn(a,b=vec3(),c=vec3(),d=vec3(1),e){return level3DMakeAt(e?{type:a,properties:e}:{type:a},b.copy(),c,d)}const level3DPrefabs=new Map;let level3DPrefabDepth=0,level3DPrefabAttached=0;const level3DPrefabMaking=[];function level3DAddPrefab(a,b){level3DPrefabSet(a,b,!1)}function level3DPrefabSet(a,b,c){a=String(a);const d=isArray(b?.objects)?b.objects.filter(e=>e&&"object"===typeof e):[];level3DPrefabs.set(a,{attached:!!b?.attached,objects:JSON.parse(JSON.stringify(d)),fromLevel:c,source:b});level3DTypes.set(a,{make:class extends Prefab3D{constructor(e){super(e,a)}},defaults:{},tileInfo:void 0})}function level3DPrefabsAdd(a){if(a&&"object"===typeof a&&!isArray(a))for(const b in a){const c=level3DPrefabs.get(b);(c?c.fromLevel:!level3DTypes.has(b))&&a[b]&&"object"===typeof a[b]&&level3DPrefabSet(b,a[b],!0)}}async function level3DLoadPrefab(a,b){level3DAddPrefab(a,await fetchJSON(b))}function level3DPrefabPartTransform(a,b){const c=level3DVector(b.pos,vec3()),d=level3DVector(b.scale,vec3(1));b=level3DVector(b.rotation,vec3()).scale(PI/180);b=buildMatrix(vec3(),a.rotation3D).multiply(buildMatrix(vec3(),b));return{pos:buildMatrix(a.pos3D,a.rotation3D,a.scale3D).transformPoint(c),rotation:b.getRotation(),scale:d.multiply(a.scale3D)}}class Prefab3D extends EngineObject3D{constructor(a,b=""){super(a);this.prefabName=b;this.attached=!!level3DPrefabs.get(b)?.attached||0{a instanceof EngineObject3D&&(b=level3DPrefabPartTransform(this,this.partObjects[b]),a.rotation3D=b.rotation,a.scale3D=(level3DBaseScale.get(a)??vec3(1)).multiply(b.scale),a instanceof Prefab3D?a.placeAt(b.pos):a.pos3D=b.pos)}))}placeKey(){const a=this.pos3D,b=this.rotation3D,c=this.scale3D;return[a.x,a.y,a.z,b.x,b.y,b.z,c.x,c.y,c.z].join()}makeParts(){var a=level3DPrefabs.get(this.prefabName);if(a)if(level3DPrefabMaking.includes(this.prefabName)||8<=level3DPrefabDepth)debug&&console.error(`level3DLoad: the prefab ${this.prefabName} holds itself, left out there`);else{level3DPrefabMaking.push(this.prefabName);++level3DPrefabDepth;this.attached&&++level3DPrefabAttached;try{const b=vec3(Infinity),c=vec3(-Infinity),d=[];for(const e of a.objects){const f={pos:level3DVector(e.pos,vec3()),scale:level3DVector(e.scale,vec3(1)),rotation:level3DVector(e.rotation,vec3()).scale(PI/180)},g=this.attached?f:level3DPrefabPartTransform(this,e),h=level3DMakeAt(e,g.pos,g.rotation,g.scale);if(!h)continue;this.parts.push(h);this.partObjects.push(e);if(!(this.attached&&h instanceof EngineObject3D))continue;h.setCollision(!1,!1,!1);d.push(h);const k=buildMatrix(h.pos3D,h.rotation3D,h.size3D.multiply(h.scale3D));for(a=8;a--;){const l=k.transformPoint(vec3(a&1?.5:-.5,a&2?.5:-.5,a&4?.5:-.5));for(const m of["x","y","z"])b[m]=min(b[m],l[m]),c[m]=max(c[m],l[m])}}d.length&&(this.size3D=c.subtract(b),this.originOffset=b.add(c).scale(.5));for(const e of d)e.pos3D=e.pos3D.subtract(this.originOffset),render3DShareSettings(e,this),this.addChild(e)}finally{--level3DPrefabDepth,level3DPrefabMaking.pop(),this.attached&&--level3DPrefabAttached}}}update(){super.update();this.attached||this.partsPlaced===this.placeKey()||this.placeParts()}destroy(a){if(!this.destroyed){for(const b of this.parts)b.parent===this||b.destroy?.(a);super.destroy(a)}}render3D(){}}function level3DMakeShape(a,b,c,d,e=!1){a=new EngineObject3D(a,c,0<=b.tile?tile(b.tile):d,b.color);a.collideAsSphere3D=e;b.solid&&a.setCollision();return a}let level3DCylinderMesh;level3DAddType("Box",function(a,b){return level3DMakeShape(a,b,render3D.boxMesh)},{color:WHITE,tile:-1,solid:!0});level3DAddType("Sphere",function(a,b){return level3DMakeShape(a,b,render3D.sphereMesh,void 0,!0)},{color:WHITE,tile:-1,solid:!0});level3DAddType("Cylinder",function(a,b){return level3DMakeShape(a,b,level3DCylinderMesh||=buildCylinder())},{color:WHITE,tile:-1,solid:!0});level3DAddType("Light",function(a,b){a=new Light3D(a,b.radius,b.color,b.intensity);a.coneAngle=max(b.cone,0)*PI/180;a.coneSoftness=b.softness;b.shadows&&render3D&&(render3D.shadowLight=a);b.lensFlare&&a.addFlare();return a},{color:WHITE,radius:5,intensity:1,cone:0,softness:.2,shadows:!1,lensFlare:!1});const particleEffectGroups="Emitter Particles Color Motion Collision Texture Behaviors".split(" "),particleEffectSettings=[];let particleEffectSettingGroup;function particleEffectAddSetting(a,b,c,d,e,f,g,h=d,k=e){const l="trailScale velocityInheritance localSpace restitution friction gravity".split(" ").includes(a);particleEffectSettings.push({group:particleEffectSettingGroup,name:a,kind:b,value:c,min:d,max:e,step:f,description:g,hardMin:h,hardMax:k,extra:l})}particleEffectSettingGroup="Emitter";particleEffectAddSetting("emitRate","number",100,0,500,.1,"Particles per second, 0 emits none",0,1e4);particleEffectAddSetting("emitTime","number",0,0,5,.05,"Seconds to emit for, 0 is forever",0,1e9);particleEffectAddSetting("emitSize","number",0,0,10,.05,"Diameter, or width when rectangular",0,1e9);particleEffectAddSetting("emitRect","checkbox",!1,0,0,0,"Rectangle emitter, off is a circle");particleEffectAddSetting("emitHeight","number",0,0,10,.05,"Rectangle height",0,1e9);particleEffectAddSetting("emitConeAngle","number",PI,0,PI,.01,"Half angle particles move in, 3.14 is all ways");particleEffectAddSetting("angle","number",0,-3.14,3.14,.01,"Emitter angle, 0 points up",-PI,PI);particleEffectSettingGroup="Particles";particleEffectAddSetting("particleTime","number",.5,0,5,.05,"Seconds each particle lives",0,1e9);particleEffectAddSetting("sizeStart","number",.1,0,5,.01,"Size at the start of life",0,1e9);particleEffectAddSetting("sizeEnd","number",1,0,5,.01,"Size at the end of life",0,1e9);particleEffectAddSetting("fadeRate","number",.1,0,1,.01,"Share of life spent fading in and out");particleEffectAddSetting("randomness","number",.2,0,1,.01,"How much each particle varies");particleEffectAddSetting("particleConeAngle","number",PI,0,PI,.01,"Half angle of start rotation, 3.14 is any");particleEffectAddSetting("trailScale","number",0,0,20,.1,"Stretch along the motion, 0 is off",0,1e9);particleEffectAddSetting("additive","checkbox",!1,0,0,0,"Glow with additive blending");particleEffectSettingGroup="Color";particleEffectAddSetting("colorStartA","color",[1,1,1,1],0,1,.01,"Start color, each particle picks between A and B");particleEffectAddSetting("colorStartB","color",[1,1,1,1],0,1,.01,"Second start color");particleEffectAddSetting("colorEndA","color",[1,1,1,0],0,1,.01,"End color, each particle picks between A and B");particleEffectAddSetting("colorEndB","color",[1,1,1,0],0,1,.01,"Second end color");particleEffectAddSetting("randomColorLinear","checkbox",!0,0,0,0,"Pick along A to B, off picks each channel");particleEffectSettingGroup="Motion";particleEffectAddSetting("speed","number",.1,0,.5,.005,"Start speed, world units per frame",-1e9,1e9);particleEffectAddSetting("angleSpeed","number",.05,0,.5,.005,"Spin speed, radians per frame",-1e9,1e9);particleEffectAddSetting("damping","number",1,.8,1,.001,"Speed kept each frame, 1 keeps it all",0,1);particleEffectAddSetting("angleDamping","number",1,.8,1,.001,"Spin kept each frame",0,1);particleEffectAddSetting("gravityScale","number",0,-2,2,.05,"How much gravity pulls",-1e9,1e9);particleEffectAddSetting("gravity","number",0,-.02,.02,5e-4,"Its own fall each frame, the same in any game",-1,1);particleEffectAddSetting("velocityInheritance","number",0,0,1,.01,"Share of emitter motion passed on");particleEffectAddSetting("localSpace","checkbox",!1,0,0,0,"Particles move with the emitter");particleEffectSettingGroup="Collision";particleEffectAddSetting("collideLevel","checkbox",!1,0,0,0,"Hit tiles, the preview adds a floor");particleEffectAddSetting("restitution","number",0,0,1,.01,"Bounce when hitting tiles");particleEffectAddSetting("friction","number",.8,0,1,.01,"Speed kept sliding along tiles, the larger of this and the friction of the layer, as for an object");particleEffectSettingGroup="Texture";particleEffectAddSetting("shape","shape","soft",0,0,0,"Built-in shape, none uses the tile");particleEffectAddSetting("tileIndex","number",-1,-1,63,1,"Tile in texture 0 when no shape, -1 is untextured",-1,1e4);particleEffectAddSetting("tileSize","number",16,1,128,1,"Tile size in texture pixels",1,4096);particleEffectAddSetting("tilePadding","number",1,0,8,1,"Pixels of padding around each tile",0,64);const particleEffectBehaviors=[{name:"wobble",min:0,max:5,value:1,description:"Sway from side to side"},{name:"swirl",min:-2,max:2,value:1,description:"Turn the direction of travel"},{name:"turbulence",min:0,max:5,value:1,description:"Random pushes every frame"},{name:"attract",min:-2,max:2,value:1,description:"Pull toward the emitter, negative pushes away"},{name:"orbit",min:-2,max:2,value:1,description:"Push around the emitter, add attract to circle it"},{name:"wind",min:-2,max:2,value:1,description:"A sideways push that grows with age"},{name:"stick",min:0,max:1,value:1,description:"Grip on landing, pair with collideLevel"}].map(a=>({...a,update:void 0,update3D:void 0})),particleEffectBehavior=a=>particleEffectBehaviors.find(b=>b.name===a),particleEffectShapes="dot soft glow smoke spark square triangle ring star plus".split(" ");function particleEffectColor(a){a instanceof Color&&(a=[a.r,a.g,a.b,a.a]);if(isArray(a)&&4===a.length&&a.every(isNumber))return a.map(b=>clamp(b))}function particleEffectSanitize(a){var b="string"===typeof a?.name?a.name.replace(/[\x00-\x1f\x7f]+/g," ").trim():"";b=b?textGraphemes(b).slice(0,60).join("").trim():"Effect";var c=a?.settings&&"object"===typeof a.settings?{...a.settings}:{};void 0===c.shape&&isNumber(c.tileIndex)&&(c.shape="");const d={};for(var e of particleEffectSettings){var f=c[e.name],g=e.value;"checkbox"===e.kind?d[e.name]="boolean"===typeof f?f:0===f||1===f?!!f:g:"color"===e.kind?d[e.name]=particleEffectColor(f)||g.slice():"shape"===e.kind?d[e.name]=""===f||particleEffectShapes.includes(f)?f:g:isNumber(f)?(g="angle"===e.name&&isFinite(f)&&abs(f)>PI,f=clamp(g?mod(f+PI,2*PI)-PI:f,e.hardMin,e.hardMax),d[e.name]=1<=e.step?round(f):f):d[e.name]=g}d.localSpace&&(d.collideLevel=!1);e=[];a=isArray(a?.behaviors)?a.behaviors:[];for(const h of particleEffectBehaviors)if(c=a.find(k=>k?.name===h.name))c=isNumber(c.strength)?clamp(c.strength,h.min,h.max):h.value,e.push({name:h.name,strength:c});for(const h of a)"string"!==typeof h?.name||!h.name||particleEffectBehavior(h.name)||e.some(k=>k.name===h.name)||e.push({name:h.name,strength:isNumber(h.strength)?h.strength:1});return{name:b,settings:d,behaviors:e}}function particleEffectRecolor(a,b=0,c=1){a=particleEffectSanitize(a);const d={...a.settings};for(const e of["colorStartA","colorStartB","colorEndA","colorEndB"]){const[f,g,h,k]=new Color(...d[e]).HSLA(),l=(new Color).setHSLA(mod(f+b),clamp(g*c),h,k);d[e]=[l.r,l.g,l.b,l.a]}return{...a,settings:d,behaviors:a.behaviors.map(e=>({...e}))}}const particleEffectsByName=new Map;function particleEffectsAdd(a){for(const b of isArray(a)?a:[a])a=particleEffectSanitize(b),particleEffectsByName.set(a.name.toLowerCase(),a)}function particleEffectsGet(a){return particleEffectsByName.get(String(a).toLowerCase())}function particleEffectsParse(a){return particleEffectsFromData(JSON.parse(a))}function particleEffectsFromData(a){a=isArray(a?.effects)?a.effects:a?.settings?[a]:void 0;if(!a||!a.length)throw Error("no effects in this file");return a.map(particleEffectSanitize)}function particleEffectsText(a){return JSON.stringify({version:1,effects:a},void 0,1)}async function particleEffectsLoad(a){a=particleEffectsFromData(await fetchJSON(a));particleEffectsAdd(a);return a}let particleEffectShapeTiles;function particleEffectShapeTile(a){if(!particleEffectShapeTiles){if(headlessMode||!glContext||!canvasAvailable())return;const b=createCanvasContext(128*particleEffectShapes.length,128);b.scale(4,4);b.fillStyle=b.strokeStyle="#fff";const c=(f,g,h,k=l=>1-l)=>{const l=b.createRadialGradient(f,g,0,f,g,h);for(let m=0;8>=m;++m)l.addColorStop(m/8,"rgba(255,255,255,"+k(m/8).toFixed(3)+")");b.fillStyle=l;b.beginPath();b.arc(f,g,h,0,2*PI);b.fill();b.fillStyle="#fff"},d={dot:(f,g)=>{b.beginPath();b.arc(f,g,15,0,2*PI);b.fill()},soft:(f,g)=>c(f,g,15),glow:(f,g)=>c(f,g,15,h=>engineGlowAlpha(h,1)),smoke:(f,g)=>{for(const[h,k,l]of[[-4,-3,9],[4,-2,8],[0,4,9],[-5,5,6],[6,5,6]])c(f+h,g+k,l,m=>.7*(1-m))},spark:(f,g)=>{b.save();b.translate(f,g);b.scale(.3,1);c(0,0,15,h=>engineGlowAlpha(h,.6));b.restore()},square:(f,g)=>b.fillRect(f-15,g-15,30,30),triangle:(f,g)=>{b.beginPath();b.moveTo(f,g-15);b.lineTo(f+15,g+15);b.lineTo(f-15,g+15);b.fill()},ring:(f,g)=>{b.lineWidth=3;b.beginPath();b.arc(f,g,13,0,2*PI);b.stroke()},star:(f,g)=>{b.beginPath();for(let h=0;10>h;++h){const k=h*PI/5-PI/2,l=h%2?6.75:15;b.lineTo(f+cos(k)*l,g+sin(k)*l)}b.fill()},plus:(f,g)=>{b.fillRect(f-15,g-4,30,8);b.fillRect(f-4,g-15,8,30)}};particleEffectShapes.forEach((f,g)=>d[f](32*g+16,16));const e=new TextureInfo(b.canvas,!0,!1,!1);particleEffectShapeTiles=new Map(particleEffectShapes.map((f,g)=>[f,new TileInfo(vec2(4*(32*g+1),4),vec2(120),e)]))}return particleEffectShapeTiles.get(a)}const b$jscomp$91=particleEffectBehavior;b$jscomp$91("wobble").update=(a,b)=>{a.velocity.x+=.003*b*a.scale*sin(6*time+97*a.lifeTime%9)};b$jscomp$91("swirl").update=(a,b)=>{var c=.05*b;b=cos(c);c=sin(c);a=a.velocity;a.set(a.x*b-a.y*c,a.x*c+a.y*b)};b$jscomp$91("turbulence").update=(a,b)=>{a.velocity.x+=rand(-1,1)*b*.005*a.scale;a.velocity.y+=rand(-1,1)*b*.005*a.scale};b$jscomp$91("attract").update=(a,b)=>{const c=a.emitter,d=c.localSpace?0:c.pos.y;a.velocity.x+=((c.localSpace?0:c.pos.x)-a.pos.x)*b*.002;a.velocity.y+=(d-a.pos.y)*b*.002};b$jscomp$91("orbit").update=(a,b)=>{const c=a.emitter,d=c.localSpace?0:c.pos.x;a.velocity.x-=(a.pos.y-(c.localSpace?0:c.pos.y))*b*.002;a.velocity.y+=(a.pos.x-d)*b*.002};b$jscomp$91("wind").update=(a,b)=>a.velocity.x+=.004*b*a.scale*min((time-a.spawnTime)/a.lifeTime,1);b$jscomp$91("stick").update=(a,b)=>{a.groundObject&&(a.velocity.x*=1-b,a.angleVelocity*=1-b)};function particleEffectsAddBehavior(a,b,c,d=-2,e=2,f=1,g=""){const h=particleEffectBehavior(a);h&&particleEffectBehaviors.splice(particleEffectBehaviors.indexOf(h),1);particleEffectBehaviors.push({name:a,update:b,update3D:c,min:d,max:e,value:f,description:g})}function particleEffectUpdateCallback(a,b){const c=a.map(d=>[particleEffectBehavior(d.name)?.[b?"update3D":"update"],d.strength]).filter(d=>d[0]);if(c.length)return d=>{for(const[e,f]of c)e(d,f)}}const particleEffectIndirect="emitSize emitRect emitHeight tileIndex tileSize tilePadding shape".split(" ");function particleEffectTileInfo(a){if(a.shape)return particleEffectShapeTile(a.shape);if(!(0>a.tileIndex)){var b=textureInfos[0],c=a.tileSize+2*a.tilePadding;if(b&&b.size.x&&a.tileIndexa.emitTime;for(const e of particleEffectSettings)particleEffectIndirect.includes(e.name)||(a[e.name]="color"===e.kind?new Color(...c[e.name]):c[e.name]);d&&(a.emitTime=-1);a.emitCircle=!c.emitRect;a.emitSize=vec2(c.emitSize,c.emitRect?c.emitHeight:c.emitSize);a.tileInfo=particleEffectTileInfo(c);a.renderOrder=c.additive?1e9:0;a.particleUpdateCallback=particleEffectUpdateCallback(b.behaviors)}const PARTICLE_EFFECT_OPTIONS="hue saturation scale angle tileInfo flatten".split(" ");function particleEffectOptionValid(a,b){return"checkbox"===a.kind?"boolean"===typeof b||0===b||1===b:"color"===a.kind?!!particleEffectColor(b):"shape"===a.kind?""===b||particleEffectShapes.includes(b):isNumber(b)}function particleEffectResolve(a,b){if(a="string"==typeof a?particleEffectsGet(a):a){isVector2(b.emitSize)&&(b={...b,emitSize:b.emitSize.x,emitHeight:b.emitSize.y,emitRect:b.emitRect??!0});if(debug)for(const g in b)PARTICLE_EFFECT_OPTIONS.includes(g)||particleEffectSettings.some(h=>h.name===g)||[...new Set([...PARTICLE_EFFECT_OPTIONS,...particleEffectSettings.map(h=>h.name)])].find(h=>h.toLowerCase()===g.toLowerCase());var c={...a.settings};for(var d of particleEffectSettings){const g=b[d.name];void 0!==g&&particleEffectOptionValid(d,g)&&(c[d.name]=g)}d=particleEffectSanitize({...a,settings:c});var{hue:e=0,saturation:f=1}=b;return e||1!=f?particleEffectRecolor(d,e,f):d}}function particleEffect(a,b=vec2(),c={}){c||={};if(a=particleEffectResolve(a,c)){b=new ParticleEmitter(b.copy());particleEffectSet(b,a);b.scale=c.scale??1;void 0!==c.angle&&(b.angle=c.angle);if(c=c.tileInfo)b.tileInfo=c instanceof TextureInfo?new TileInfo(vec2(),c.size,c):c;return b}}function particleEffectFromEmitter(a,b="Effect"){const c={};for(const d of particleEffectSettings)particleEffectIndirect.includes(d.name)||void 0===a[d.name]||(c[d.name]=a[d.name]);0>a.emitTime&&(c.emitTime=a.emitElapsed);c.emitRect=!a.emitCircle;c.emitSize=a.emitSize.x;c.emitHeight=a.emitSize.y;c.shape="";c.tileIndex=-1;return particleEffectSanitize({name:b,settings:c})}const b$jscomp$93=particleEffectBehavior,center$jscomp$24=a=>a.emitter.worldPos3D||a.emitter.pos3D;b$jscomp$93("wobble").update3D=(a,b)=>a.velocity.x+=.003*b*a.scale*sin(6*time+97*a.lifeTime%9);b$jscomp$93("swirl").update3D=(a,b)=>{var c=.05*b;b=cos(c);c=sin(c);a=a.velocity;a.set(a.x*b-a.y*c,a.x*c+a.y*b,a.z)};b$jscomp$93("turbulence").update3D=(a,b)=>{b=.005*b*a.scale;a.velocity.x+=rand(-1,1)*b;a.velocity.y+=rand(-1,1)*b;a.velocity.z+=rand(-1,1)*b};b$jscomp$93("attract").update3D=(a,b)=>{const c=center$jscomp$24(a);a.velocity.x+=(c.x-a.pos.x)*b*.002;a.velocity.y+=(c.y-a.pos.y)*b*.002;a.velocity.z+=(c.z-a.pos.z)*b*.002};b$jscomp$93("orbit").update3D=(a,b)=>{const c=center$jscomp$24(a);a.velocity.x-=(a.pos.y-c.y)*b*.002;a.velocity.y+=(a.pos.x-c.x)*b*.002};b$jscomp$93("wind").update3D=(a,b)=>a.velocity.x+=.004*b*a.scale*min(a.age/a.lifeTime,1);function particleEffectApply3D(a,b){particleEffectSet3D(a,particleEffectSanitize(b))}function particleEffectSet3D(a,b){const c=b.settings;a.emitSize=c.emitRect?vec3(c.emitSize,c.emitHeight,c.emitSize):c.emitSize;a.emitTime=0>a.emitTime?-1:c.emitTime;a.emitRate=c.emitRate;a.emitConeAngle=c.emitConeAngle;a.tileInfo=particleEffectTileInfo(c);for(const d of["colorStartA","colorStartB","colorEndA","colorEndB"])a[d]=new Color(...c[d]);for(const d of"particleTime sizeStart sizeEnd speed damping gravity fadeRate randomness additive gravityScale angleSpeed angleDamping collideLevel restitution".split(" "))a[d]=c[d];a.trailTime=c.trailScale/60;a.friction=c.friction;a.stick=b.behaviors.find(d=>"stick"==d.name)?.strength??0;a.rotation3D=vec3(0,0,-c.angle);a.particleUpdateCallback=particleEffectUpdateCallback(b.behaviors,!0)}function particleEffect3D(a,b=vec3(),c={}){c||={};if(a=particleEffectResolve(a,c))return b=new ParticleEmitter3D(b.copy()),particleEffectSet3D(b,a),void 0!==c.angle&&(b.rotation3D=vec3(0,0,-c.angle)),b.scale3D=vec3(c.scale??1),b.emitFlat=!!c.flatten,c.tileInfo&&(b.tileInfo=c.tileInfo),b}const particleEffectsBuiltIn=[],add$jscomp$1=(a,b,c=[])=>{particleEffectsBuiltIn.push(a);particleEffectsAdd({name:a,settings:b,behaviors:c})},clear$jscomp$6=(a,b,c)=>hsl(a,b,c,0);add$jscomp$1("fire",{emitRate:120,emitSize:.6,emitConeAngle:.3,shape:"glow",particleTime:.8,sizeStart:.7,sizeEnd:.15,speed:.02,angleSpeed:.02,damping:.95,gravity:.003,fadeRate:.3,randomness:.3,additive:!0,colorStartA:hsl(.08,1,.6),colorStartB:hsl(.14,1,.65),colorEndA:clear$jscomp$6(.02,1,.5),colorEndB:clear$jscomp$6(0,1,.3)});add$jscomp$1("torch",{emitRate:60,emitSize:.25,emitConeAngle:.2,shape:"glow",particleTime:.6,sizeStart:.45,sizeEnd:.1,speed:.015,angleSpeed:.02,damping:.95,gravity:.003,fadeRate:.3,randomness:.3,additive:!0,colorStartA:hsl(.09,1,.6),colorStartB:hsl(.13,1,.7),colorEndA:clear$jscomp$6(.03,1,.5),colorEndB:clear$jscomp$6(0,1,.35)});add$jscomp$1("smoke",{emitRate:25,emitSize:.5,emitConeAngle:.3,shape:"smoke",particleTime:3,sizeStart:.5,sizeEnd:2,speed:.01,angleSpeed:.01,damping:.99,gravity:4e-4,fadeRate:.5,randomness:.3,colorStartA:hsl(0,0,.5,.5),colorStartB:hsl(0,0,.3,.5),colorEndA:clear$jscomp$6(0,0,.2),colorEndB:clear$jscomp$6(0,0,.4)},[{name:"wobble",strength:.5}]);add$jscomp$1("steam",{emitRate:30,emitSize:.4,emitConeAngle:.2,shape:"smoke",particleTime:1.5,sizeStart:.3,sizeEnd:1.5,speed:.02,damping:.98,gravity:8e-4,fadeRate:.6,randomness:.3,colorStartA:hsl(0,0,1,.4),colorStartB:hsl(.6,.2,.9,.3),colorEndA:clear$jscomp$6(0,0,1),colorEndB:clear$jscomp$6(.6,.2,.9)},[{name:"wobble",strength:.3}]);add$jscomp$1("explosion",{emitRate:600,emitTime:.1,emitSize:.5,shape:"glow",particleTime:.6,sizeStart:1,sizeEnd:.1,speed:.1,damping:.9,fadeRate:.2,randomness:.5,additive:!0,colorStartA:hsl(.12,1,.65),colorStartB:hsl(.06,1,.55),colorEndA:clear$jscomp$6(0,1,.5),colorEndB:clear$jscomp$6(0,0,.3)});add$jscomp$1("sparks",{emitRate:100,emitSize:.2,shape:"soft",particleTime:.6,sizeStart:.08,sizeEnd:.04,speed:.07,damping:.96,gravity:-.006,fadeRate:.1,randomness:.4,additive:!0,trailScale:3,colorStartA:hsl(.17,1,.9),colorStartB:hsl(.12,1,.65),colorEndA:clear$jscomp$6(.07,1,.5),colorEndB:clear$jscomp$6(.03,1,.5)});add$jscomp$1("hit",{emitRate:400,emitTime:.05,emitSize:.2,shape:"spark",particleTime:.35,sizeStart:.5,sizeEnd:.1,speed:.08,damping:.85,fadeRate:.1,randomness:.4,additive:!0,trailScale:2,colorStartA:hsl(0,0,1),colorStartB:hsl(0,1,.7),colorEndA:clear$jscomp$6(0,1,.5),colorEndB:clear$jscomp$6(0,1,.4)});add$jscomp$1("dust",{emitRate:300,emitTime:.05,emitSize:1,emitRect:!0,emitHeight:.1,emitConeAngle:1.2,shape:"smoke",particleTime:.8,sizeStart:.3,sizeEnd:.8,speed:.04,damping:.9,gravity:5e-4,fadeRate:.5,randomness:.4,colorStartA:hsl(.1,.3,.6,.5),colorStartB:hsl(.08,.2,.5,.5),colorEndA:clear$jscomp$6(.1,.3,.6),colorEndB:clear$jscomp$6(.08,.2,.5)});add$jscomp$1("debris",{emitRate:200,emitTime:.05,emitSize:.5,emitConeAngle:1,shape:"square",particleTime:1.5,sizeStart:.15,sizeEnd:.1,speed:.07,angleSpeed:.2,damping:.99,gravity:-.008,fadeRate:.1,randomness:.5,colorStartA:hsl(.08,.4,.35),colorStartB:hsl(0,0,.4),colorEndA:hsl(.08,.4,.3),colorEndB:hsl(0,0,.35)});add$jscomp$1("sparkle",{emitRate:30,emitSize:1,shape:"star",particleTime:.8,sizeStart:.3,sizeEnd:0,speed:.005,angleSpeed:.05,fadeRate:.5,randomness:.3,additive:!0,colorStartA:hsl(.14,1,.7),colorStartB:hsl(0,0,1),colorEndA:clear$jscomp$6(.14,1,.7),colorEndB:clear$jscomp$6(0,0,1)});add$jscomp$1("magic",{emitRate:60,emitSize:1,shape:"soft",particleTime:1.5,sizeStart:.25,sizeEnd:0,speed:.015,fadeRate:.3,randomness:.3,additive:!0,colorStartA:hsl(.55,1,.65),colorStartB:hsl(.79,1,.65),colorEndA:clear$jscomp$6(0,0,1),colorEndB:clear$jscomp$6(0,0,1)},[{name:"swirl",strength:.5}]);add$jscomp$1("heal",{emitRate:30,emitSize:.8,emitConeAngle:.2,shape:"plus",particleTime:1.2,sizeStart:.25,sizeEnd:.1,speed:.015,angleSpeed:0,particleConeAngle:0,gravity:5e-4,fadeRate:.4,randomness:.3,additive:!0,colorStartA:hsl(.33,1,.6),colorStartB:hsl(.3,1,.75),colorEndA:clear$jscomp$6(.33,1,.6),colorEndB:clear$jscomp$6(.3,1,.75)});add$jscomp$1("poison",{emitRate:20,emitSize:.8,shape:"smoke",particleTime:2,sizeStart:.3,sizeEnd:1,speed:.006,gravity:2e-4,fadeRate:.6,randomness:.4,colorStartA:hsl(.3,.8,.45,.6),colorStartB:hsl(.8,.6,.45,.6),colorEndA:clear$jscomp$6(.3,.8,.4),colorEndB:clear$jscomp$6(.8,.6,.4)},[{name:"wobble",strength:.5}]);add$jscomp$1("portal",{emitRate:80,emitSize:1,shape:"soft",particleTime:1,sizeStart:.15,sizeEnd:.05,speed:.02,fadeRate:.3,randomness:.3,additive:!0,colorStartA:hsl(.75,1,.6),colorStartB:hsl(.6,1,.6),colorEndA:clear$jscomp$6(.75,1,.6),colorEndB:clear$jscomp$6(.6,1,.6)},[{name:"orbit",strength:1},{name:"attract",strength:.5}]);add$jscomp$1("rain",{emitRate:30,emitSize:1,emitRect:!0,emitHeight:.6,angle:PI,emitConeAngle:0,shape:"soft",particleTime:.8,sizeStart:.02,sizeEnd:.02,speed:.03,gravity:-.001,fadeRate:.1,randomness:.2,trailScale:5,colorStartA:hsl(.63,1,.8,.6),colorStartB:hsl(.63,1,.8,.4),colorEndA:hsl(.63,1,.8,.6),colorEndB:hsl(.63,1,.8,.4)});add$jscomp$1("snow",{emitRate:6,emitSize:1,emitRect:!0,emitHeight:.6,angle:PI,emitConeAngle:.3,shape:"soft",particleTime:4,sizeStart:.05,sizeEnd:.05,speed:.004,damping:.98,gravity:-2e-4,fadeRate:.2,randomness:.3,colorStartA:hsl(0,0,1),colorStartB:hsl(.58,1,.9),colorEndA:hsl(0,0,1),colorEndB:hsl(.58,1,.9)},[{name:"wobble",strength:.15}]);add$jscomp$1("leaves",{emitRate:3,emitSize:1,emitRect:!0,emitHeight:.2,angle:PI,emitConeAngle:.5,shape:"triangle",particleTime:4,sizeStart:.12,sizeEnd:.12,speed:.003,angleSpeed:.05,damping:.98,gravity:-1e-4,fadeRate:.2,randomness:.4,randomColorLinear:!1,colorStartA:hsl(.25,.7,.4),colorStartB:hsl(.07,.8,.5),colorEndA:hsl(.08,.6,.35),colorEndB:hsl(.05,.7,.4)},[{name:"wobble",strength:.15},{name:"wind",strength:.05}]);add$jscomp$1("bubbles",{emitRate:8,emitSize:1,emitRect:!0,emitHeight:.1,emitConeAngle:.2,shape:"ring",particleTime:2,sizeStart:.1,sizeEnd:.2,speed:.01,gravity:3e-4,fadeRate:.2,randomness:.4,colorStartA:hsl(.55,.8,.8,.8),colorStartB:hsl(.5,.6,.9,.6),colorEndA:hsl(.55,.8,.8,.3),colorEndB:hsl(.5,.6,.9,.2)},[{name:"wobble",strength:.3}]);add$jscomp$1("fireflies",{emitRate:3,emitSize:1,shape:"glow",particleTime:3,sizeStart:.15,sizeEnd:.15,speed:.003,damping:.99,fadeRate:.8,randomness:.3,additive:!0,colorStartA:hsl(.2,1,.6),colorStartB:hsl(.15,1,.7),colorEndA:hsl(.2,1,.6),colorEndB:hsl(.15,1,.7)},[{name:"turbulence",strength:.3}]);add$jscomp$1("trail",{emitRate:60,shape:"soft",particleTime:.5,sizeStart:.4,sizeEnd:0,speed:0,angleSpeed:0,fadeRate:.1,randomness:.2,additive:!0,colorStartA:hsl(.08,1,.6),colorStartB:hsl(.12,1,.65),colorEndA:clear$jscomp$6(.03,1,.5),colorEndB:clear$jscomp$6(0,1,.4)});add$jscomp$1("muzzle",{emitRate:300,emitTime:.05,emitConeAngle:.3,shape:"glow",particleTime:.2,sizeStart:.5,sizeEnd:.1,speed:.1,damping:.8,fadeRate:.1,randomness:.3,additive:!0,colorStartA:hsl(.14,1,.8),colorStartB:hsl(.1,1,.6),colorEndA:clear$jscomp$6(.08,1,.5),colorEndB:clear$jscomp$6(.05,1,.4)});add$jscomp$1("blood",{emitRate:300,emitTime:.1,emitConeAngle:.8,shape:"dot",particleTime:3,sizeStart:.15,sizeEnd:.1,speed:.09,gravity:-.01,fadeRate:.1,randomness:.4,collideLevel:!0,restitution:.1,colorStartA:hsl(0,1,.35),colorStartB:hsl(0,1,.2),colorEndA:hsl(0,1,.25),colorEndB:hsl(0,1,.15)},[{name:"stick",strength:1}]);add$jscomp$1("confetti",{emitRate:200,emitTime:.1,emitSize:.2,emitConeAngle:.6,shape:"square",particleTime:3,sizeStart:.1,sizeEnd:.1,speed:.09,angleSpeed:.15,damping:.96,gravity:-.004,fadeRate:.1,randomness:.4,randomColorLinear:!1,colorStartA:hsl(0,1,.5),colorStartB:hsl(.6,1,.6),colorEndA:hsl(0,1,.5),colorEndB:hsl(.6,1,.6)},[{name:"wobble",strength:.3}]);add$jscomp$1("splash",{emitRate:300,emitTime:.05,emitSize:.5,emitConeAngle:.6,shape:"soft",particleTime:.7,sizeStart:.12,sizeEnd:.06,speed:.08,gravity:-.008,fadeRate:.2,randomness:.4,colorStartA:hsl(.58,.8,.7,.8),colorStartB:hsl(.55,.6,.85,.8),colorEndA:hsl(.58,.8,.7,.2),colorEndB:hsl(.55,.6,.85,.2)});class GLTFPart{constructor(a,b,c,d,e){this.name=a;this.mesh=b;this.color=c;this.textureInfo=d;this.transparent=e;this.pixelated=!1;this.node=0;this.unlit=!1;this.normalMap=void 0;this.normalScale=1;this.emissiveMap=void 0;this.emissiveMapColor=WHITE;this.roughness=1;this.vertexSource=this.skin=void 0}}class GLTFAnimation{constructor(a,b){this.name=a;this.channels=b;this.duration=b.reduce((c,d)=>max(c,d.times[d.times.length-1]||0),0)}}class GLTFModel{constructor(a,b=[],c){this.parts=a;this.animations=b;this.nodeTree=c;this.modelMatrix=new Matrix4;this.mesh=new Mesh;for(const d of a)this.mesh.combine(d.mesh,!d.skin&&c?.restPose?.[d.node]||RENDER3D_IDENTITY,d.color);a=new Set(a.map(d=>d.textureInfo));this.textureInfo=1===a.size?a.values().next().value:void 0;this.bounds=void 0}getBounds(){const a=this.bounds||(this.bounds=this.mesh.getBounds());return{min:a.min.copy(),max:a.max.copy()}}center(){const a=this.getBounds();return this.transform(a.min.add(a.max).scale(-.5))}fit(a=1){var b=this.getBounds();b=b.max.subtract(b.min);return this.transform(Matrix4.scaling(vec3(a/(max(b.x,b.y,b.z)||1))))}transform(a){a=render3DMatrix(a);for(const b of this.parts)b.mesh.transform(a);this.mesh.transform(a);this.bounds=void 0;this.modelMatrix=a.copy().multiply(this.modelMatrix);return this}getAnimation(a){return a instanceof GLTFAnimation?a:isNumber(a)?this.animations[a]:this.animations.find(b=>b.name===a)}getPose(a,b){return this.nodeTree?this.partPoses(gltfNodeWorlds(this.nodeTree,gltfPoseNodes(this.nodeTree,a,b))):this.parts.map(()=>new Matrix4)}partPoses(a){const b=this.nodeTree,c=this.modelMatrix,d=c.copy().invert();return this.parts.map(e=>e.skin?new Matrix4:c.copy().multiply(a(e.node)).multiply(b.restInverse[e.node]).multiply(d))}dispose(){for(const a of this.parts)a.mesh.dispose();this.mesh.dispose();for(const a of new Set(this.parts.flatMap(b=>[b.textureInfo,b.normalMap,b.emissiveMap])))a!==gltfWhiteTextureInfo&&a?.destroyWebGLTexture()}createObject(a=vec3()){return new GLTFObject(this,a)}}class GLTFObject extends EngineObject3D{constructor(a,b=vec3()){super(b);if(b=a.mesh.points.length?a.getBounds():void 0)this.size3D=b.max.subtract(b.min);this.model=a;this.animation=void 0;this.animationTime=0;this.animationSpeed=1;this.animationLoop=!0;this.animationPlaying=!1;this.blendFrom=void 0;this.blendElapsed=this.blendTime=0;this.poseNodes=void 0;this.poseMixed=!1;this.poseWorldOf=void 0;this.parts=[];for(const d of a.parts){b=new EngineObject3D(vec3(),d.skin?gltfSkinMeshCopy(d.mesh):d.mesh,d.textureInfo,d.color);b.transparent=d.transparent;b.pixelated=d.pixelated;b.emissive=d.unlit?1:0;b.normalMap=d.normalMap;b.normalScale=d.normalScale;b.emissiveMap=d.emissiveMap;b.emissiveMapColor=d.emissiveMapColor.copy();b.roughness=d.roughness;var c=!d.skin&&a.nodeTree?.restPose?.[d.node];if(c){const e=a.modelMatrix;c=e.copy().multiply(c).multiply(e.copy().invert());b.localMatrix=c;b.pos3D=c.getTranslation();b.rotation3D=c.getRotation();b.scale3D=c.getScale()}render3DShareSettings(b,this);this.addChild(b);this.parts.push(b)}}destroy(a){this.destroyed||(this.parts.forEach((b,c)=>this.model.parts[c]?.skin&&b.mesh?.dispose()),super.destroy(a))}play(a=0,b=!0,c=1,d=0){if(a=this.model.getAnimation(a))if(0c?a.duration:0)}}stop(){this.animationPlaying=!1;this.blendFrom=void 0}setAnimationTime(a){this.animationTime=a;const b=this.model;var c=b.nodeTree;if(this.animation&&c){a=gltfPoseNodes(c,this.animation,a);var d=this.blendFrom;if(d){var e=d.nodes||gltfPoseNodes(c,d.animation,d.time);a=gltfPoseBlend(c,e,a,smoothStep(clamp(this.blendElapsed/this.blendTime)))}c=gltfNodeWorlds(c,a);this.poseNodes=a;this.poseWorldOf=c;this.poseMixed=!!d;a=b.partPoses(c);d=this.parts;for(e=0;e=a.duration||0>=c)&&(this.animationPlaying=!1));b&&(this.blendElapsed+=timeDelta,b.animation&&(b.time=gltfAnimationStep(b.animation,b.time,b.speed,b.loop)));this.setAnimationTime(c);b&&this.blendElapsed>=this.blendTime&&(this.blendFrom=void 0)}}getJointMatrix(a){var b=this.model.nodeTree;const c=b?.nodes?.findIndex(d=>d.name===a)??-1;if(!(0>c))return b=this.poseWorldOf||gltfNodeWorlds(b,new Map),this.getMatrix().multiply(this.model.modelMatrix).multiply(b(c))}}async function loadGLTF(a){var b=await loadFetch(a,"loadGLTF");if(!b.ok)throw Error(`loadGLTF: could not load ${a}, ${b.status} ${b.statusText}`);const c=b.url||a;var d="";/^(blob|data):/i.test(c)||(d=b.url?new URL(".",c).href:c.slice(0,c.lastIndexOf("/")+1));b=await b.arrayBuffer();try{return await parseGLTF(b,d)}catch(e){throw d=loadIsWebPage(String.fromCharCode(...new Uint8Array(b,0,min(b.byteLength,64)))),Error("loadGLTF "+a+(d?" is a web page, so the path may be wrong":": "+e.message))}}async function parseGLTF(a,b="",c){ArrayBuffer.isView(a)&&(a=a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength));let d=a,e;if(a instanceof ArrayBuffer){const w=new DataView(a);if(12<=a.byteLength&&1179937895===w.getUint32(0,!0)){if(2!==w.getUint32(4,!0))throw Error("only GLB version 2 is read");for(let z=12;z+8<=a.byteLength;){const A=w.getUint32(z,!0),C=w.getUint32(z+4,!0),D=a.slice(z+8,z+8+A);1313821514===C?d=(new TextDecoder).decode(D):5130562===C&&(e=D);z+=8+A}}else d=(new TextDecoder).decode(a)}"string"==typeof d&&(d=JSON.parse(d));if(!d.asset||!String(d.asset.version).startsWith("2"))throw Error("only glTF 2.0 is read");for(const w of d.extensionsRequired||[]){if("KHR_draco_mesh_compression"===w||"EXT_meshopt_compression"===w)throw Error(`glTF with ${w} is not read, export it uncompressed`);if("KHR_texture_basisu"===w)throw Error("glTF with KHR_texture_basisu textures is not read, export them as png or jpeg")}d.extensionsUsed?.includes("KHR_texture_basisu")&&!d.extensionsRequired?.includes("KHR_texture_basisu")&&console.warn("glTF: KHR_texture_basisu textures are not read and are left out, export them as png or jpeg");const f=await Promise.all((d.buffers||[]).map((w,z)=>w.uri?gltfFetch(w.uri,b,c).then(A=>A.arrayBuffer()):e)),g=new Set((d.materials||[]).flatMap(w=>[w.pbrMetallicRoughness?.baseColorTexture?.index,w.normalTexture?.index,w.emissiveTexture?.index])),h=new Set((d.materials||[]).map(w=>w.normalTexture?.index)),k=gltfOpaqueTextures(d),l=await Promise.all((d.textures||[]).map(async(w,z)=>{if(glContext&&"undefined"!=typeof createImageBitmap&&g.has(z))try{const A=d.images[w.source??w.extensions?.EXT_texture_webp?.source??w.extensions?.EXT_texture_avif?.source],C=d.samplers?.[w.sampler]||{};let D;if(A.uri)D=await gltfFetch(A.uri,b,c).then(F=>F.blob());else{const F=d.bufferViews[A.bufferView];D=new Blob([new Uint8Array(f[F.buffer],F.byteOffset||0,F.byteLength)],{type:A.mimeType})}const B=k.has(z)&&"image/jpeg"!==D.type,E=h.has(z)?await createImageBitmap(D,{colorSpaceConversion:"none",premultiplyAlpha:"none"}):B?await createImageBitmap(D,{premultiplyAlpha:"none"}).then(gltfOpaqueImage):await createImageBitmap(D);return new TextureInfo(E,!0,[C.wrapS??10497,C.wrapT??10497],9728===C.magFilter)}catch(A){console.warn("glTF image not loaded, left out: "+(A?.message||A))}})),m=[],n=[],r=[],q=[],p=new Set;let t,u;(d.nodes||[]).forEach((w,z)=>(w.children||[]).forEach(A=>(t=n)[u=A]??(t[u]=z)));const v=(w,z,A,C)=>{if(p.has(w))throw Error("glTF node "+w+" is reached twice, nodes must form trees");p.add(w);const D=d.nodes[w];var B=gltfNodeMatrix(D),E=z?z.copy().multiply(B):B;C=C&&C.copy().multiply(B);!D.matrix&&D.scale?.includes(0)&&(C||=E,E=gltfNodeMatrix({...D,scale:D.scale.map(F=>F||1)}),E=z?z.copy().multiply(E):E);n[w]=A;r[w]=E.copy().invert();C&&(q[w]=C.copy().multiply(r[w]));if(void 0!==D.mesh){z=d.meshes[D.mesh];A=void 0!==D.skin?d.skins?.[D.skin]:void 0;for(const F of z.primitives){B=A?.joints?.length&&void 0!==F.attributes.JOINTS_0&&void 0!==F.attributes.WEIGHTS_0;const G=gltfPart(d,f,l,F,B?new Matrix4:E,D.name||z.name||"part "+m.length);G&&(G.node=w,B&&(G.skin=gltfSkin(d,f,A,F,G)),m.push(G))}}for(const F of D.children||[])v(F,E,w,C)};let y;try{const w=d.scenes?.[d.scene??0];if(w)(w.nodes||[]).forEach(z=>v(z));else if(d.nodes){const z=new Set(d.nodes.flatMap(A=>A.children||[]));d.nodes.forEach((A,C)=>z.has(C)||v(C))}y=(d.animations||[]).map((z,A)=>new GLTFAnimation(z.name||"animation "+A,z.channels.filter(C=>void 0!==C.target.node&&["translation","rotation","scale"].includes(C.target.path)&&!d.nodes[C.target.node].matrix).map(C=>{const D=z.samplers[C.sampler];return{node:C.target.node,path:C.target.path,interpolation:D.interpolation||"LINEAR",times:gltfAccessor(d,f,D.input).data,values:gltfAccessor(d,f,D.output).data,components:"rotation"===C.target.path?4:3}})))}catch(w){for(const z of l)z?.destroyWebGLTexture();throw w}a=new Set(m.flatMap(w=>[w.textureInfo,w.normalMap,w.emissiveMap]));for(var x of l)x&&!a.has(x)&&x.destroyWebGLTexture();x={nodes:d.nodes,parents:n,restInverse:r,restPose:q};a=gltfNodeWorlds(x,new Map);for(const w of m)w.skin&&gltfSkinApply(w.skin,a,RENDER3D_IDENTITY,w.mesh);return new GLTFModel(m,y,x)}function gltfPoseNodes(a,b,c){const d=new Map;for(const e of b.channels)(b=d.get(e.node))||d.set(e.node,b=gltfNodeTRS(a.nodes[e.node])),gltfSample(e,c,b[e.path]);return d}function gltfPoseBlend(a,b,c,d){const e=new Map,f=(g,h)=>g.map((k,l)=>k+(h[l]-k)*d);for(const g of new Set([...b.keys(),...c.keys()])){const h=b.get(g)||gltfNodeTRS(a.nodes[g]),k=c.get(g)||gltfNodeTRS(a.nodes[g]);e.set(g,{translation:f(h.translation,k.translation),scale:f(h.scale,k.scale),rotation:gltfSlerp(h.rotation,k.rotation,d)})}return e}function gltfSlerp(a,b,c){var d=a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3];let e=1;0>d&&(d=-d,e=-1);let f=1-c,g=c*e;if(.9995>d){d=Math.acos(d);const k=sin(d);f=sin(f*d)/k;g=sin(c*d)/k*e}a=a.map((k,l)=>k*f+b[l]*g);const h=hypot(...a)||1;return a.map(k=>k/h)}function gltfNodeWorlds(a,b){const c=[],d=e=>{if(c[e])return c[e];const f=gltfNodeMatrix(b.get(e)||a.nodes[e]),g=a.parents[e];return c[e]=void 0===g?f:d(g).copy().multiply(f)};return d}function gltfAnimationStep(a,b,c,d){a=a.duration;b+=timeDelta*c;return d?a?mod(b,a):0:clamp(b,0,a)}function gltfSkin(a,b,c,d,e){const f=c.joints,g=e.mesh,h=g.points.length,k=void 0!==c.inverseBindMatrices?gltfAccessor(a,b,c.inverseBindMatrices).data:void 0;c=f.map((p,t)=>k?new Matrix4(k.subarray(16*t,16*t+16)):new Matrix4);var l=d.attributes;d=[[gltfAccessor(a,b,l.JOINTS_0).data,gltfAccessor(a,b,l.WEIGHTS_0).data]];void 0!==l.JOINTS_1&&void 0!==l.WEIGHTS_1&&d.push([gltfAccessor(a,b,l.JOINTS_1).data,gltfAccessor(a,b,l.WEIGHTS_1).data]);a=new Uint16Array(4*h);b=new Float32Array(4*h);l=new Float32Array(3*h);const m=new Float32Array(3*h);for(let p=0;pq;++q)r.push([t[4*n+q],u[4*n+q]]);1u[1]-t[1]);n=0;for(q=0;4>q;++q)n+=r[q][1];for(q=0;4>q;++q){const[t,u]=r[q];a[4*p+q]=tc.copy());b.normals=a.normals.map(c=>c.copy());b.uvs=a.uvs.slice();b.colors=a.colors.slice();b.indices=a.indices&&a.indices.slice();b.doubleSided=a.doubleSided;b.dynamicDraw=!0;return b}function gltfSkinApply(a,b,c,d){var e=a.joints.length;const f=a.jointMatrices||(a.jointMatrices=new Float32Array(21*e));var g=gltfSkinScratch[0],h=gltfSkinScratch[1];for(var k=0;kM;++M){const L=q[y+M];if(!L)continue;const I=21*r[y+M];v+=L*(f[I]*x+f[I+3]*w+f[I+6]*C+f[I+9]);F+=L*(f[I+1]*x+f[I+4]*w+f[I+7]*C+f[I+10]);G+=L*(f[I+2]*x+f[I+5]*w+f[I+8]*C+f[I+11]);z+=L*(f[I+12]*D+f[I+15]*B+f[I+18]*E);H+=L*(f[I+13]*D+f[I+16]*B+f[I+19]*E);J+=L*(f[I+14]*D+f[I+17]*B+f[I+20]*E)}x=a[A];y=b[A];w=(z*z+H*H+J*J)**.5||1;x.x=v;x.y=F;x.z=G;y.x=z/w;y.y=H/w;y.z=J/w;e&&(z=A*RENDER3D_VERTEX_FLOATS,e[z]=v,e[z+1]=F,e[z+2]=G,e[z+3]=y.x,e[z+4]=y.y,e[z+5]=y.z,g=max(g,v*v+F*F+G*G),h=min(h,v),k=min(k,F),l=min(l,G),m=max(m,v),n=max(n,F),u=max(u,G))}e&&(d.radius=g**.5,d.bounds=c?{min:vec3(h,k,l),max:vec3(m,n,u)}:{min:vec3(),max:vec3()},d.vertexDataPacked=!0);d.dirty=!0}const gltfSkinScratch=[new Matrix4,new Matrix4];function gltfNodeTRS(a){return{translation:[...a.translation||[0,0,0]],rotation:[...a.rotation||[0,0,0,1]],scale:[...a.scale||[1,1,1]]}}function gltfOpaqueTextures(a){const b=new Set,c=new Set;for(const d of a.materials||[])a=d.pbrMetallicRoughness?.baseColorTexture?.index,void 0!==a&&(d.alphaMode&&"OPAQUE"!==d.alphaMode?c:b).add(a);for(const d of c)b.delete(d);return b}function gltfOpaqueImage(a){var b=glContext;const{width:c,height:d}=a;if(b.isContextLost())return a;const e=new Uint8ClampedArray(c*d*4),f=b.createTexture(),g=b.createFramebuffer(),h=b.getParameter(b.FRAMEBUFFER_BINDING);try{b.bindTexture(b.TEXTURE_2D,f),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,a),b.bindFramebuffer(b.FRAMEBUFFER,g),b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,f,0),b.readPixels(0,0,c,d,b.RGBA,b.UNSIGNED_BYTE,e)}finally{b.bindFramebuffer(b.FRAMEBUFFER,h),b.bindTexture(b.TEXTURE_2D,glActiveTexture),b.deleteFramebuffer(g),b.deleteTexture(f)}for(b=3;b>1;d[r]<=b?a=r:n=r-1}if(a>=h||b<=d[0]||"STEP"===g)for(b=0;bm;++m)h+=e[a+m]*e[l+m];k=0>h?-1:1;h*=k;m=1-b;n=b*k;.9995>h&&(h=Math.acos(h),n=sin(h),m=sin((1-b)*h)/n,n=sin(b*h)/n*k);for(b=0;4>b;++b)c[b]=m*e[a+b]+n*e[l+b]}else for(m=0;ml;++l)c[l]/=a}}function gltfFetch(a,b,c){if(c&&!/^(data|https?|blob):/i.test(a)){var d=a.replace(/[?#].*$/,"");try{d=decodeURIComponent(d)}catch{}const f=l=>{const m=[];for(const n of l.replace(/\\/g,"/").split("/"))if(".."===n?!m.pop():n&&"."!==n&&!m.push(n))return;return m.join("/")};b=f(b+d);if(void 0===b)return Promise.reject(Error("glTF needs "+d+", which is above the files given"));const g=b.toLowerCase(),h=g.slice(g.lastIndexOf("/")+1),k=new Map([...c].map(([l,m])=>[f(l)?.toLowerCase(),m]));d=c.get(b)??k.get(g);c=[...k.keys()];if(d)return Promise.resolve(new Response(d));if(d=c.filter(l=>l?.includes("/")&&g.endsWith("/"+l)).sort((l,m)=>m.length-l.length)[0])return Promise.resolve(new Response(k.get(d)));c=new Set(c.filter(l=>l?.slice(l.lastIndexOf("/")+1)===h).map(l=>k.get(l)));return 1===c.size?Promise.resolve(new Response([...c][0])):Promise.reject(Error("glTF needs "+b+(c.size?", and more than one file has its name":", which is not among the files given")))}if(a.startsWith("data:")){b=a.indexOf(",");b=atob(a.slice(b+1));c=new Uint8Array(b.length);for(d=0;d{if(!f.ok)throw Error("glTF needs "+a+", not found at "+e);return f})}function gltfNodeMatrix(a){if(a.matrix)return new Matrix4(a.matrix);const[b,c,d,e]=a.rotation||[0,0,0,1],[f,g,h]=a.scale||[1,1,1];a=a.translation||[0,0,0];return new Matrix4([(1-2*(c*c+d*d))*f,2*(b*c+d*e)*f,2*(b*d-c*e)*f,0,2*(b*c-d*e)*g,(1-2*(b*b+d*d))*g,2*(c*d+b*e)*g,0,2*(b*d+c*e)*h,2*(c*d-b*e)*h,(1-2*(b*b+c*c))*h,0,a[0],a[1],a[2],1])}function gltfAccessor(a,b,c){const d=a.accessors[c];var e=a.bufferViews?.[d.bufferView];const f={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT4:16}[d.type];var g={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array},h=g[d.componentType];if(!f||!h)throw Error(`glTF accessor of ${d.type} ${d.componentType} is not read`);const k=h.BYTES_PER_ELEMENT;var l=[[Int8Array,127],[Uint8Array,255],[Int16Array,32767],[Uint16Array,65535]];l=d.normalized?new Map(l).get(h)||1:1;if(!(e||1048576>=d.count))throw Error("glTF accessor "+c+" has no buffer and a count of "+d.count);var m=e&&(b[e.buffer]?.byteLength??0),n=e?.byteStride||f*k;if(e&&!((e.byteOffset||0)+(d.byteOffset||0)+(d.count-1)*n+f*k<=m))throw Error("glTF accessor "+c+" reaches past its buffer");m=new Float32Array(d.count*f);if(e){var r=b[e.buffer];e=(e.byteOffset||0)+(d.byteOffset||0);if(e%k||n%k)throw Error("glTF accessor "+c+" is not aligned to its "+k+" byte values");if(n===f*k)m.set(new h(r,e,d.count*f));else for(var q=0;qg)){var h=d.attributes,k=(B,E)=>{const{data:F,components:G,count:H}=gltfAccessor(a,b,B);B=[];for(let J=0;Jvec3(B[E],B[E+1],B[E+2])),m=void 0!==h.NORMAL?k(h.NORMAL,(B,E)=>vec3(B[E],B[E+1],B[E+2])):void 0,n=a.materials?.[d.material]||{},r=n.pbrMetallicRoughness||{},q=r.baseColorTexture,p=q?.extensions?.KHR_texture_transform,t=h["TEXCOORD_"+(p?.texCoord??q?.texCoord??0)],[u,v]=p?.offset||[0,0],[y,x]=p?.scale||[1,1];p=p?.rotation||0;var w=cos(p),z=sin(p);t=void 0!==t?k(t,(B,E)=>vec2(w*y*B[E]+z*x*B[E+1]+u,w*x*B[E+1]-z*y*B[E]+v)):void 0;h=void 0!==h.COLOR_0?k(h.COLOR_0,(B,E,F)=>rgb(gltfSRGB(B[E]),gltfSRGB(B[E+1]),gltfSRGB(B[E+2]),3E);5===g?d=d.flatMap((B,E,F)=>2>E?[]:E&1?[F[E-1],F[E-2],F[E]]:[F[E-2],F[E-1],F[E]]):6===g&&(d=d.flatMap((B,E,F)=>2>E?[]:[F[0],F[E-1],F[E]]));l=(new Mesh).addTriangles(l,d,m,t,h);g=m?void 0:l.indices.slice();m||l.computeNormals(!1);l.transform(e);m=r.baseColorFactor||[1,1,1,1];l.doubleSided=!!n.doubleSided;d=n.extensions?.KHR_materials_transmission?.transmissionFactor||0;h="BLEND"===n.alphaMode;k=(h?m[3]:1)*(1-.8*d);e=q&&a.textures?.[q.index];f=new GLTFPart(f,l,rgb(gltfSRGB(m[0]),gltfSRGB(m[1]),gltfSRGB(m[2]),k),q?c[q.index]:void 0,h||0=a?12.92*a:1<=a?a:1.055*a**(1/2.4)-.055}let threeJS;class ThreeJSPlugin{constructor(a,b=60){threeJS=this;headlessMode||(this.THREE=a,this.renderer=new a.WebGLRenderer({antialias:!0}),this.scene=new a.Scene,this.camera=new a.PerspectiveCamera(b,1,.1,1e3),this.cameraAlign2D=!0,this.cameraFar=this.cameraNear=void 0,a=this.renderer.domElement,b=mainCanvas.parentElement,b.insertBefore(a,b.firstChild),a.style.cssText=mainCanvas.style.cssText,setBackgroundCanvas(a),engineAddPlugin(void 0,()=>this.render()))}alignCamera2D(){const a=mainCanvasSize.y/2/cameraScale/tan(this.camera.fov/2*PI/180);var b=this.cameraNear??(this.cameraNear=this.camera.near),c=this.cameraFar??(this.cameraFar=this.camera.far);const d=max(1,2*a/c);b*=d;c*=d;if(b!=this.camera.near||c!=this.camera.far)this.camera.near=b,this.camera.far=c,this.camera.updateProjectionMatrix();this.camera.position.set(cameraPos.x,cameraPos.y,a);this.camera.rotation.set(0,0,-cameraAngle)}render(){if(this.renderer){var a=this.renderer.domElement,b=getCanvasPixelRatio(),c=mainCanvasSize.y*b|0;if(a.width!=(mainCanvasSize.x*b|0)||a.height!=c)this.renderer.setPixelRatio(b),this.renderer.setSize(mainCanvasSize.x,mainCanvasSize.y,!1),this.camera.aspect=mainCanvasSize.x/mainCanvasSize.y,this.camera.updateProjectionMatrix();a.style.cssText!=mainCanvas.style.cssText&&(a.style.cssText=mainCanvas.style.cssText);this.cameraAlign2D&&this.alignCamera2D();this.renderer.render(this.scene,this.camera)}}}class ThreeJSObject extends EngineObject{constructor(a,b,c,d=0){super(a,b);this.mesh=c;this.z=d;c&&(threeJS.scene?.add(c),this.syncMesh())}updateTransforms(a=!0){super.updateTransforms(a);this.syncMesh()}syncMesh(){this.mesh&&(this.mesh.position.set(this.pos.x,this.pos.y,this.z),this.mesh.rotation.z=-this.angle)}render(){}destroy(a){this.destroyed||(this.mesh&&threeJS.scene?.remove(this.mesh),super.destroy(a))}}