littlejsengine 1.25.0 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -0
- package/FAQ.md +49 -11
- package/README.md +6 -2
- package/REFERENCE.md +120 -18
- package/dist/littlejs.d.ts +464 -99
- package/dist/littlejs.esm.js +2853 -704
- package/dist/littlejs.esm.min.js +3 -3
- package/dist/littlejs.js +2844 -701
- package/dist/littlejs.min.js +2 -2
- package/dist/littlejs.release.js +2658 -512
- package/package.json +4 -4
- package/plugins/box2d.js +110 -34
- package/plugins/gltf.js +74 -22
- package/plugins/lightSystem.js +410 -28
- package/plugins/math3d.js +4 -2
- package/plugins/medalSystem.js +19 -7
- package/plugins/newgrounds.js +4 -2
- package/plugins/parallax.js +1 -0
- package/plugins/particleEffects.js +44 -10
- package/plugins/pathFinder.js +9 -11
- package/plugins/pluginExport.js +9 -0
- package/plugins/postProcess.js +4 -2
- package/plugins/render3d.js +485 -2385
- package/plugins/render3dDebug.js +5 -8
- package/plugins/render3dEditor.js +81 -6
- package/plugins/render3dExtras.js +103 -31
- package/plugins/render3dLevel.js +53 -5
- package/plugins/render3dMesh.js +1158 -0
- package/plugins/render3dObject.js +1451 -0
- package/plugins/render3dVoxels.js +15 -3
- package/plugins/textureSheet.js +9 -8
- package/plugins/threejs.js +1 -1
- package/plugins/tweenSystem.js +76 -51
- package/plugins/uiSystem.js +37 -8
- package/plugins/wavedash.js +229 -0
- package/src/engine.js +184 -36
- package/src/engineAudio.js +37 -21
- package/src/engineBuild.mjs +6 -1
- package/src/engineDebug.js +22 -162
- package/src/engineDraw.js +139 -34
- package/src/engineEditor.js +79 -18
- package/src/engineExport.js +0 -3
- package/src/engineInput.js +27 -18
- package/src/engineMath.js +35 -14
- package/src/engineObject.js +60 -41
- package/src/engineParticles.js +58 -11
- package/src/engineRelease.js +1 -5
- package/src/engineSettings.js +48 -9
- package/src/engineTileLayer.js +11 -4
- package/src/engineUtilities.js +41 -9
- package/src/engineWebGL.js +37 -13
package/dist/littlejs.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// LittleJS Engine - MIT License - Copyright 2021 Frank Force
|
|
2
2
|
// https://github.com/KilledByAPixel/LittleJS
|
|
3
3
|
|
|
4
|
-
const engineName="LittleJS",engineVersion="1.25.0",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 frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;const frameDeltaHistory=[];let frameIntervalMS=1e3/60,frameDeltaCarryMS=0,frameDeltaCarryAverageMS=0,frameDeltaSmoothing=!0;function engineSmoothDelta(a){if(!(0<a))return 0;if(250>a){frameDeltaHistory.push(a);64<frameDeltaHistory.length&&frameDeltaHistory.shift();var b=frameDeltaHistory.slice(-16).sort((g,h)=>g-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 engineInitialized=!1,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 p(x){z=!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();debugVideoCaptureIsActive()&&r()}function r(){if(!headlessMode){z||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();debugRenderPost();primitiveCount=drawCount=0}}var q=engineManualStep,u=n-frameTimeLastMS;frameTimeLastMS||(u=0);frameTimeLastMS=n;if(debug||debugWatermark)averageFPS=lerp(averageFPS,1e3/(u||1),.05);q||(u=engineSmoothDelta(u));audioUpdateVolume();var t=debug&&(debugOverlay||debugKeysAlways);n=t&&keyIsDown("Equal");t=t&&keyIsDown("Minus");n=n?10:t?.1:1;t=u;timeReal+=u*n/1e3;const v=timeScale*n;u*=v;let z=!1;if(engineVariableStep){if(0<t||q)u=paused||!v,u||(timeDelta=q?v/frameRate:min(t,50)*v/1e3,time+=timeDelta,++frame),p(u)}else{const x=paused||!v;frameTimeBufferMS+=x?t:u;frameTimeBufferMS=min(frameTimeBufferMS,50*(x?1:max(1,v)));u=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(u=frameTimeBufferMS,frameTimeBufferMS=0);try{for(;0<=frameTimeBufferMS;)try{(t=paused||!(timeScale*n))||(time=timeFixedStart+(frame++-frameFixedStart)/frameRate),p(t)}finally{frameTimeBufferMS-=1e3/frameRate}}finally{frameTimeBufferMS+=u}}engineManualStep&&!q&&(frameTimeBufferMS=-500/frameRate);q=!1;headlessMode||(u=devicePixelRatio,q=windowWidthLast!==innerWidth||windowHeightLast!==innerHeight||windowPixelRatioLast!==u,windowWidthLast=innerWidth,windowHeightLast=innerHeight,windowPixelRatioLast=u);debugVideoCaptureIsActive()||!z&&!q||r();engineManualStep||engineScheduleFrame()}async function l(n){const p=(async()=>{await Promise.all(n);await a()})();engineAddLoad(p);await engineWaitForLoads();engineLoads=void 0;await p;engineUpdateInternal=k;engineManualStep||k()}showEngineVersion&&console.log(`${engineName} Engine v${engineVersion}`);if(!engineInitialized){engineInitialized=!0;engineLoads=[];engineLoadsDone=0;a||=()=>{};b||=()=>{};c||=()=>{};d||=()=>{};e||=()=>{};if(headlessMode)return l([]);document.body||document.documentElement.appendChild(document.createElement("body"));g||=document.body;glInit(g);var 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,p)=>loadTexture(p,n));f.length||g.push(loadTexture(0));g.push(imageFontInit());showSplashScreen&&(f=new Promise(n=>{function p(){inputClear();drawEngineLogo(r+=.01);1<r?n():setTimeout(p,16)}let r=0;p()}),g.push(f));showSplashScreen&&await g[g.length-1];return l(g)}}function engineUpdateCanvas(){if(!headlessMode){var a=getCanvasPixelRatio();if(canvasFixedSize.x){mainCanvasSize=canvasFixedSize.copy();var b=innerWidth/innerHeight;const d=canvasFixedSize.x/canvasFixedSize.y;var c=b<d?"100%":"";b=b<d?"":"100%";mainCanvas.style.width=c;mainCanvas.style.height=b;glCanvas&&(glCanvas.style.width=c,glCanvas.style.height=b)}else mainCanvasSize.x=min(innerWidth,canvasMaxSize.x)|0,mainCanvasSize.y=min(innerHeight,canvasMaxSize.y)|0,c=mainCanvasSize.x/mainCanvasSize.y,canvasMaxAspect&&c>canvasMaxAspect?mainCanvasSize.x=min(mainCanvasSize.y*canvasMaxAspect|0,canvasMaxSize.x):c<canvasMinAspect&&(mainCanvasSize.y=min(mainCanvasSize.x/canvasMinAspect|0,canvasMaxSize.y)),mainCanvas.style.width=mainCanvasSize.x+"px",mainCanvas.style.height=mainCanvasSize.y+"px",glCanvas&&(glCanvas.style.width=mainCanvasSize.x+"px",glCanvas.style.height=mainCanvasSize.y+"px");c=mainCanvasSize.x*a|0;b=mainCanvasSize.y*a|0;mainCanvas.width!==c||mainCanvas.height!==b?(mainCanvas.width=c,mainCanvas.height=b):(mainContext.setTransform(1,0,0,1,0,0),mainContext.globalCompositeOperation="source-over",mainContext.clearRect(0,0,c,b));mainContext.setTransform(a,0,0,a,0,0);0<canvasClearColor.a&&!glEnable&&(mainContext.fillStyle=canvasClearColor.toString(),mainContext.fillRect(0,0,mainCanvasSize.x,mainCanvasSize.y),mainContext.fillStyle=BLACK.toString());mainContext.lineJoin="round";mainContext.lineCap="round"}}function engineScheduleFrame(){if(!engineFrameScheduled){engineFrameScheduled=!0;var a=b=>{engineFrameScheduled=!1;if(!engineManualStep){if(debug)return engineUpdateInternal(b);try{engineUpdateInternal(b)}catch(c){b=String(c),b===engineFrameErrorLast||console.error(c),engineFrameErrorLast=b,inputUpdatePost(),engineScheduleFrame()}}};"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<a&&engineManualStep;--a)engineUpdateInternal(frameTimeLastMS+1e3/frameRate)}function engineObjectsUpdate(){function a(e){if(e.length){var f=engineChildStack.length;for(const h of e)engineChildStack.push(h);try{for(e=f;e<engineChildStack.length;++e){var g=engineChildStack[e];g.destroyed||g.updatePass===d||(g.updatePass=d,g.updateTransforms(!1),g.update(),g.children.length&&g.updateTransforms(!1),a(g.children))}}finally{engineChildStack.length=f}}}function b(e){e.parent||e.destroyed||e.updatePass===d||(e.updatePass=d,e.update(),a(e.children),e.updateTransforms())}++engineObjectsUpdateCount;engineObjectsCollidePairs.clear();engineObjectsSort();const c=[];engineObjectsCollide=[];engineObjectsCollideStaticLast=[];for(const e of engineObjects)e.collideSolidObjects&&(engineObjectsCollide.push(e),(e.mass?engineObjectsCollideStaticLast:c).push(e));for(const e of c)engineObjectsCollideStaticLast.push(e);for(const e of engineObjects)e.parent||e.destroyed||e.updatePhysics();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].renderOrder<engineObjects[a-1].renderOrder)return void engineObjects.sort((b,c)=>b.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*b<g&&e.push(f))}else for(const h of c)h.destroyed||e.push(h);return e}function engineObjectsCallback(a,b,c,d=engineObjects,e=!1){for(const f of engineObjectsCollect(a,b,d,e))f.destroyed||c(f)}function engineObjectsRaycast(a,b,c=engineObjects){const d=[];for(const e of c)e.collideRaycast&&!e.destroyed&&isIntersecting(a,b,e.pos,e.size)&&(debugRaycast&&debugRect(e.pos,e.size,"#f00",0,0,!1,!1),d.push(e));debugRaycast&&debugLine(a,b,d.length?"#f00":"#00f",.02,0,!1);return d}let debugWatermark=!1,debugKey="",debugKeysAlways=!1,debugTweakables=!1;const debug=!1,debugOverlay=!1,debugPhysics=!1,debugParticles=!1,debugRaycast=!1,debugGamepads=!1,debugSound=!1,debugPointSize=.5;function ASSERT(){}function LOG(){}function debugInit(){}function debugUpdate(){}function debugRender(){}function debugRenderPost(){}function debugRect(){}function debugPoly(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugOverlap(){}function debugText(){}function debugClear(){}function debugScreenshot(){}function debugShowErrors(){}function setDebugOverlay(){}function debugVideoCaptureIsActive(){return!1}function debugVideoCaptureStart(){}function debugVideoCaptureStop(){}function debugProtectConstant(a){return a}function tweak(){}function tweakButton(){}function tweakDivider(){}function tweakEngineDefaults(){}const editorEdit2DRelease={map:void 0,layer:void 0,hover:void 0,get objects(){return[]},get selection(){return new Set},paint(){return!1},changeObjects(){return!1},strokeEnd(){},strokeCancel(){},bulk(){},undo(){return!1},toJSON(){return""}};class LevelEditor{constructor(){this.paletteTiles=this.use3D=this.tool=void 0;this.keys={};this.buttons=[];this.tools={}}get isOpen(){return!1}get is3D(){return!1}get edit2D(){return editorEdit2DRelease}get edit3D(){}open(){}close(){}addKey(){}addButton(){}addTool(){}onTile(){}onRestart(){}onPlayFrom(){}onOpen(){}onClose(){}onUpdate(){}onDraw(){}onPanel(){}onSave(){return!1}}let levelEditor=new LevelEditor;function setLevelEditor(a){levelEditor=a}function editorMapRestore(a){return a}function editorMapLoaded(){}function editorJSONFetched(){}function editorPreRender(){}function editorObjectMade(){}function inputCaptureHides(){return!1}function inputCaptureMouse(){}function inputLockExit(){}function debugBox3D(){}function debugSphere3D(){}function debugLine3D(){}function debugPoint3D(){}function render3DRenderDebug(){}function editor3DCameraBegin(){}function editor3DCameraEnd(){}function editor3DLevelLoaded(){}function editor3DObjectMade(){}const PI=Math.PI,abs=Math.abs,floor=Math.floor,ceil=Math.ceil,round=Math.round,min=Math.min,max=Math.max,sign=a=>Math.sign(a),hypot=(...a)=>Math.hypot(...a),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 a<b?b:a>c?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 0<a&&0===a%1&&2**round(log2(a))===a}function nearestPowerOfTwo(a){const b=2**ceil(log2(max(a,1)));return b<a?2*b:b}function isOverlapping(a,b,c,d=vec2()){const e=2*(a.y-c.y),f=b.x+d.x;b=b.y+d.y;return abs(2*(a.x-c.x))<f&&abs(e)<b}function isIntersecting(a,b,c,d){c=c.subtract(d.scale(.5));d=c.add(d);b=b.subtract(a);c=a.subtract(c);d=a.subtract(d);a=[-b.x,b.x,-b.y,b.y];b=[c.x,-d.x,c.y,-d.y];c=0;d=1;for(let e=4;e--;)if(a[e]){const f=b[e]/a[e];if(0>a[e]){if(f>d)return!1;c=max(f,c)}else{if(f<c)return!1;d=min(f,d)}}else if(0>b[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&&!isNaN(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=0<e?b.x+1:b.x,p=0<f?b.y+1:b.y,r=0;n=h?(n-a.x)/h:Infinity;var q=k?(p-a.y)/k:Infinity;for(p=l<m;r<g;){if(c(b))return a=vec2(a.x+h*r,a.y+k*r),c=a.floor(),c.x<b.x?a.x=b.x:c.x>b.x&&(a.x=b.x+1-1e-9),c.y<b.y?a.y=b.y:c.y>b.y&&(a.y=b.y+1-1e-9),d&&(p?d.set(-e,0):d.set(0,-f)),a;(p=n<q)?(b.x+=e,r=n,n+=l):(b.y+=f,r=q,q+=m)}}}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return floor(rand(a,b))}function randBool(a=.5){return rand()<a}function randSign(){return 2*randInt(2)-1}function randVec2(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){if(0>=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}sign(){return.5<this.float()?1:-1}floatSign(a=1,b=0){const c=min(a,b);a=max(a,b)-c;b=this.float(2*a);return b<a?c+b:a-c-b}angle(){return this.float(-PI,PI)}vec2(a=1,b=0){return vec2(this.float(a,b),this.float(a,b))}direction(a=1){return(new Vector2).setAngle(this.float(2*PI),a)}randColor(a=new Color,b=new Color(0,0,0,1),c=!1){return c?a.lerp(b,this.float()):new Color(this.float(a.r,b.r),this.float(a.g,b.g),this.float(a.b,b.b),this.float(a.a,b.a))}mutateColor(a,b=.05,c=0){return new Color(a.r+this.float(b,-b),a.g+this.float(b,-b),a.b+this.float(b,-b),a.a+this.float(c,-c)).clamp()}}function vec2(a=0,b){return new Vector2(a,b??a)}function isVector2(a){return a instanceof Vector2&&a.isValid()}function ASSERT_VECTOR2_VALID(a){}function ASSERT_NUMBER_VALID(a){}class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}set(a=0,b=0){this.x=a;this.y=b;return this}setFrom(a){return this.set(a.x,a.y)}copy(){return new Vector2(this.x,this.y)}add(a){return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){return new Vector2(this.x*a.x,this.y*a.y)}divide(a){return new Vector2(this.x/a.x,this.y/a.y)}scale(a){return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(0,a)}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}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.x<a.x&&this.y<a.y}toString(a=3){return this.isValid()?`(${(0>this.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){return new Color(a,b,c,d)}function hsl(a,b,c,d){return(new Color).setHSLA(a,b,c,d)}function isColor(a){return a instanceof Color&&a.isValid()}function ASSERT_COLOR_VALID(a){}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}set(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d;return this}setFrom(a){return this.set(a.r,a.g,a.b,a.a)}setAlpha(a=1){this.a=a;return this}copy(){return new Color(this.r,this.g,this.b,this.a)}withAlpha(a=1){return new Color(this.r,this.g,this.b,a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){b=clamp(b);return new Color(a.r*b+this.r*(1-b),a.g*b+this.g*(1-b),a.b*b+this.b*(1-b),a.a*b+this.a*(1-b))}setHSLA(a=0,b=0,c=1,d=1){a=mod(a,1);b=clamp(b);c=clamp(c);b=.5>c?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<g?l/(2-e-f):l/(e+f);a===e?h=(b-c)/l+(b<c?6:0):b===e?h=(c-a)/l+2:c===e&&(h=(a-b)/l+4)}return[h/6,k,g,d]}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}toString(a=!0){if(debug&&!this.isValid())return"#000";const b=c=>(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}elapsed(){return this.getGlobalTime()>=this.time}get(){return this.isSet()?this.getGlobalTime()-this.time:0}getPercent(){return this.isSet()?0<this.setTime?1-percent(this.time-this.getGlobalTime(),0,this.setTime):1:0}getSetTime(){return this.isSet()?this.setTime:0}getGlobalTime(){return this.useRealTime?timeReal:time}toString(){return this.isSet()?abs(this.get())+" seconds "+(0>this.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 fetch(a);if(!b.ok)throw Error(`Failed to fetch JSON from ${a}: ${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*</.test(a);function saveText(a,b="text",c="text/plain"){saveDataURL(URL.createObjectURL(new Blob([a],{type:c})),b,1e3)}function createCanvasContext(a,b=a,c=!1){return("undefined"!=typeof OffscreenCanvas?new OffscreenCanvas(a,b):Object.assign(document.createElement("canvas"),{width:a,height:b})).getContext("2d",{willReadFrequently:c})}function canvasAvailable(){return"undefined"!=typeof OffscreenCanvas||"undefined"!=typeof document&&!!document.createElement}function saveCanvas(a,b="screenshot",c="image/png"){if("undefined"!=typeof OffscreenCanvas&&a instanceof OffscreenCanvas){const d=document.createElement("canvas");d.width=a.width;d.height=a.height;d.getContext("2d").drawImage(a,0,0);saveDataURL(d.toDataURL(c),b)}else saveDataURL(a.toDataURL(c),b)}function saveDataURL(a,b="download",c){const d=document.createElement("a");d.download=b;d.href=a;d.click();void 0!==c&&setTimeout(()=>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{}if(!c||"object"!==typeof c||isArray(c))c={}}}catch{}return{...b,...c}}function writeSaveData(a,b){try{return localStorage.setItem(a,JSON.stringify(b)),!0}catch{return!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;0<a&&(touchGamepadRightStick=!1)}function setTouchGamepadLeftStick(a){(touchGamepadLeftStick=a)&&(touchGamepadLeftButtonCount=0)}function setTouchGamepadLeftButtonCount(a){touchGamepadLeftButtonCount=a;0<a&&(touchGamepadLeftStick=!1)}function setTouchGamepadRightStick(a){(touchGamepadRightStick=a)&&(touchGamepadButtonCount=0)}function setTouchGamepadAnalog(a){touchGamepadAnalog=a}function setTouchGamepadFloating(a){touchGamepadFloating=a}function setTouchGamepadSize(a){touchGamepadSize=a}function setTouchGamepadAlpha(a){touchGamepadAlpha=a}function setTouchGamepadDisplayTime(a){touchGamepadDisplayTime=a}function setTouchGamepadVibration(a){touchGamepadVibration=a}function setVibrateEnable(a){vibrateEnable=a}function setSoundEnable(a){soundEnable=a}function setSoundIgnoreSilentSwitch(a){soundIgnoreSilentSwitch=a;audioSetSession()}function setSoundVolume(a){soundVolume=a;audioUpdateVolume()}function setSoundDefaultRange(a){soundDefaultRange=a}function setSoundDefaultTaper(a){soundDefaultTaper=a}function setSoundPauseWhenHidden(a){soundPauseWhenHidden=a}function setDebugWatermark(a){debugWatermark=a}function setDebugKey(a){debugKey=a}function setDebugKeysAlways(a=!0){debugKeysAlways=a}function setDebugTweakables(a=!0){debugTweakables=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.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.localPos=this.parent=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){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}if(a)for(const d of this.children)d.updateTransforms()}updatePhysics(){if(!this.destroyed){this.clampSpeed&&enablePhysicsSolver&&(this.collideSolidObjects||this.collideLevel&&this.mass)&&(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed));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.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||0<this.velocity.y&&0<a;if(this.groundObject){var d=max(this.friction,this.groundObject.friction),e=this.groundObject.velocity.x;this.velocity.x=e+(this.velocity.x-e)*d;this.groundObject=void 0}if(this.collideSolidObjects&&this.size.x&&this.size.y)for(var f of engineObjectsCollideStaticLast)if(!f.destroyed&&!f.parent&&f!==this&&f.size.x&&f.size.y&&(this.isSolid||f.isSolid)&&this.isOverlappingObject(f)&&(d=engineObjectsCollidePairAnswer(f,this),!1!==d)){if(!d&&(d=this.collideWithObject(f),e=f.collideWithObject(this),!d||!e)){engineObjectsCollidePairAdd(this,f);continue}d=isOverlapping(b,this.size,f.pos,f.size);if(!d||f.mass&&!f.groundObject)if(d)d=b.subtract(f.pos),e=d.length(),d=.001>e?vec2(0,.001):d.scale(.001/e),this.velocity=this.velocity.add(d),f.mass&&(f.velocity=f.velocity.subtract(d)),engineObjectsCollidePairAdd(this,f),debugPhysics&&debugOverlap(this.pos,this.size,f.pos,f.size,"#f00",void 0,!1);else{e=this.size.add(f.size);k=2*(0<a?f.pos.y-b.y:b.y-f.pos.y)>e.y-abs(a);var g=2*abs(b.y-f.pos.y)<e.y,h=2*abs(b.x-f.pos.x)<e.x;d=max(this.restitution,f.restitution);if(k||h||!g)if(this.pos.y=f.pos.y+(e.y/2+.001)*sign(b.y-f.pos.y),f.groundObject&&c||!f.mass)c&&(this.groundObject=f),this.velocity.y=f.velocity.y-(this.velocity.y-f.velocity.y)*d;else{h=(this.mass*this.velocity.y+f.mass*f.velocity.y)/(this.mass+f.mass);const l=f.velocity.y*(f.mass-this.mass)/(this.mass+f.mass)+2*this.velocity.y*this.mass/(this.mass+f.mass);this.velocity.y=lerp(h,this.velocity.y*(this.mass-f.mass)/(this.mass+f.mass)+2*f.velocity.y*f.mass/(this.mass+f.mass),d);f.velocity.y=lerp(h,l,d)}!k&&g&&(this.pos.x=f.pos.x+(e.x/2+.001)*sign(b.x-f.pos.x),f.mass?(e=(this.mass*this.velocity.x+f.mass*f.velocity.x)/(this.mass+f.mass),k=f.velocity.x*(f.mass-this.mass)/(this.mass+f.mass)+2*this.velocity.x*this.mass/(this.mass+f.mass),this.velocity.x=lerp(e,this.velocity.x*(this.mass-f.mass)/(this.mass+f.mass)+2*f.velocity.x*f.mass/(this.mass+f.mass),d),f.velocity.x=lerp(e,k,d)):this.velocity.x=f.velocity.x-(this.velocity.x-f.velocity.x)*d);engineObjectsCollidePairAdd(this,f,!0);debugPhysics&&debugOverlap(this.pos,this.size,f.pos,f.size,"#f0f",void 0,!1)}else{if(d=collideBoxBox(this.pos,this.size,f.pos,f.size))if(this.pos.x+=d.x+.001*sign(d.x),this.pos.y+=d.y+.001*sign(d.y),e=max(this.restitution,f.restitution),d.x){var k=this.velocity.x-f.velocity.x;0>k*d.x&&(this.velocity.x=f.velocity.x-k*e)}else k=this.velocity.y-f.velocity.y,0>k*d.y&&(this.velocity.y=f.velocity.y-k*e),0>d.y*a&&(this.groundObject=f);engineObjectsCollidePairAdd(this,f);debugPhysics&&debugOverlap(this.pos,this.size,f.pos,f.size,"#f00",void 0,!1)}}if(this.collideLevel&&(f=tileCollisionTest(this.pos,this.size,this))&&!tileCollisionTest(b,this.size,this)){e=tileCollisionTest(vec2(this.pos.x,b.y),this.size,this);k=tileCollisionTest(vec2(b.x,this.pos.y),this.size,this);d=max(this.restitution,f.restitution);if(e){g=0<a?ceil(b.y+this.size.y/2-1)-this.size.y/2-.001:floor(b.y-this.size.y/2+1)+this.size.y/2+.001;if(.1>abs(g-this.pos.y)&&!tileCollisionTest(vec2(this.pos.x,g),this.size,this)){this.pos.y=g;debugPhysics&&debugRect(this.pos,this.size,"#ff0",0,0,!1,!1);return}this.pos.x=b.x;this.velocity.x*=-d}if(k||!e)c?(c=this.size.y/2+1e-4,e=f.pos.y,this.pos.y=e+(0>a?floor(b.y-e-this.size.y/2)+c:ceil(b.y-e+this.size.y/2)-c),this.groundObject=f):(this.pos.y=b.y,this.groundObject=void 0),this.velocity.y*=-d;debugPhysics&&debugRect(this.pos,this.size,"#f00",0,0,!1,!1)}}}}update(){}render(){drawTile(this.pos,this.drawSize||this.size,this.tileInfo,this.color,this.angle,this.mirror,this.additiveColor,glEnable,!1)}renderLight(){}renderShadow(){this.render()}renderEmissive(){this.render()}destroy(a=!1){if(!this.destroyed){this.destroyed=!0;this.parent?.removeChild(this);for(const b of this.children)b.parent=void 0,b.destroy(a)}}localToWorld(a){return this.pos.add(a.rotate(this.angle))}worldToLocal(a){return a.subtract(this.pos).rotate(-this.angle)}localToWorldVector(a){return a.rotate(this.angle)}worldToLocalVector(a){return a.rotate(-this.angle)}collideWithTile(a,b){return 0<a}collideWithObject(a,b){return!0}getUp(a=1){return vec2().setAngle(this.angle,a)}getRight(a=1){return vec2().setAngle(this.angle+PI/2,a)}getAliveTime(){return time-this.spawnTime}getSpeed(){return this.velocity.length()}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyAngularAcceleration(a){this.mass&&(this.angleVelocity+=a)}applyForce(a){this.mass&&this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){if(this.destroyed)return a;for(let d=this;d;d=d.parent);this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c;a.updateTransforms();return a}attach(a){a.parent?.removeChild(a);const b=this.getMirrorSign(),c=this.worldToLocal(a.pos);c.x*=b;return this.addChild(a,c,b*(a.angle-this.angle))}removeChild(a){const b=this.children.indexOf(a);0>b||(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<a?b:c-b}get tileInfo(){return this.firstTile.frame(this.frame)}get isDone(){const a="once"==this.mode&&void 0===this.heldFrame&&abs(this.elapsedFrames)>=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)}}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 p=m.sizeInverse;h=c.pos.x*p.x;k=c.pos.y*p.y;l=c.size.x*p.x;const r=c.size.y*p.y;glSetTexture(m.glTexture);if(n){const q=p.x*n;p=p.y*n;glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+q,k+p,h-q+l,k-p+r,d.rgbaInt(),g&&g.rgbaInt())}else glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h,k,h+l,k+r,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,r=>{if(m)r.scale(1,-1),drawImageColor(r,m.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1,d,g,n);else{const q=g?d.add(g):d;r.fillStyle=q.toString();r.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 p=n&1?h:-h,r=n&2?b:-b,q=n&2?k:l;f.push(vec2(a.x+(p*m-r*e),a.y+(p*e+r*m)));g.push(q)}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),k=!canvasColorTiles||isWhite(e)&&(!g||isBlack(g)),h=!k&&g&&!isBlack(g),g=k?d.image:bakeTintedImage(d.image,e,g),l=l||drawContext,l.save(),l.translate(a.x+.5,a.y+.5),l.rotate(f),l.globalAlpha=h?1:e.a,a=l.createPattern(g,"repeat"),c=(new DOMMatrix).translate(-b.x/2,-b.y/2).scale(b.x/(c.x*g.width),b.y/(c.y*g.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<a.length;++m){const n=a[m];l.lineTo(n.x,n.y)}d&&l.closePath();l.stroke()}},h,k)}function drawLine(a,b,c=.1,d=WHITE,e=vec2(),f=0,g=glEnable,h=drawScreenSpace,k){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());a=a.add(b);e=e.add(f?a.rotate(h?-f:f):a);h&&(b.y*=-1);f+=b.angle();drawRect(e,c,d,f,g,h,k)}function drawRegularPoly(a,b=vec2(1),c=3,d=WHITE,e=0,f=BLACK,g=0,h=glEnable,k=drawScreenSpace,l){const m=drawRegularPolyPoints,n=drawRegularPolyPool;m.length=0;const p=b.x/2;b=b.y/2;for(let r=c;0<r--;){const q=r/c*PI*2;let u,t;const v=(u=n)[t=m.length]||(u[t]=vec2());v.x=sin(q)*p;v.y=cos(q)*b;m.push(v)}drawPoly(m,d,e,f,a,g,h,k,l)}const drawRegularPolyPoints=[],drawRegularPolyPool=[];function drawPoly(a,b=WHITE,c=0,d=BLACK,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}glDrawPointsTransform(a,b.rgbaInt(),e.x,e.y,g,k,f);0<c&&glDrawOutlineTransform(a,d.rgbaInt(),c,e.x,e.y,g,k,f)}else++drawCount,++primitiveCount,drawCanvas2D(e,vec2(1),f,!1,l=>{l.fillStyle=b.toString();l.beginPath();for(const m of a)l.lineTo(m.x,m.y);l.closePath();l.fill();0<c&&(l.strokeStyle=d.toString(),l.lineWidth=c,l.stroke())},h,k)}const drawEllipseRings=new Map;function drawEllipse(a,b=vec2(1),c=WHITE,d=0,e=0,f=BLACK,g=glEnable,h=drawScreenSpace,k){if(!headlessMode||k)if(e=clamp(e,0,min(abs(b.x),abs(b.y))),g&&glEnable){const l=glCircleSides;if(0<e)drawRegularPoly(a,b,l,c,e,f,d,g,h,k);else{g=drawEllipseRings.get(l);if(!g){g=[];for(k=l;0<k--;){const m=k/l*PI*2;g.push(vec2(sin(m),cos(m)))}drawEllipseRings.set(l,g=glPolyStrip(g))}if(h){if(glSkipScreenSpace)return;[a,b,d]=screenToWorldTransform(a,b,d)}glDrawPointsTransform(g,c.rgbaInt(),a.x,a.y,b.x/2,b.y/2,d,!1)}}else++drawCount,++primitiveCount,drawCanvas2D(a,vec2(1),d,!1,l=>{l.fillStyle=c.toString();l.beginPath();l.ellipse(0,0,abs(b.x)/2,abs(b.y)/2,0,0,9);l.fill();0<e&&(l.strokeStyle=f.toString(),l.lineWidth=e,l.stroke())},h,k)}function drawCircle(a,b=1,c=WHITE,d=0,e=BLACK,f=glEnable,g=drawScreenSpace,h){drawEllipse(a,vec2(b),c,0,d,e,f,g,h)}let drawEllipseGradientOffset=0;function drawEllipseGradient(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=glCircleSides;const k=b.x/2,l=b.y/2;b=c.rgbaInt();g=d.rgbaInt();h=drawEllipseGradientOffset++;const m=cos(-e),n=sin(-e);e=q=>{const u=sin(q)*k;q=cos(q)*l;return vec2(a.x+u*m-q*n,a.y+u*n+q*m)};const p=[e(h%f/f*PI*2)],r=[g];for(let q=f;0<q--;){const u=(q+h)%f/f*PI*2;p.push(a);r.push(b);p.push(e(u));r.push(g)}glDrawColoredPoints(p,r)}else++drawCount,++primitiveCount,drawCanvas2D(a,b,e,!1,k=>{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)}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=(a+"").split("\n");n.save();n.fillStyle=d.toString();n.strokeStyle=f.toString();n.lineWidth=e;n.textAlign=g;n.font=k+" "+c+"px "+h;n.textBaseline="middle";n.translate(b.x+.5,b.y+.5);n.rotate(m);var p=-(a.length-1)*c/2;a.forEach(r=>{e&&n.strokeText(r,0,p,l);n.fillText(r,0,p,l);p+=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<g&&0<h&&0<k&&0<l))return cameraScale;b=cos(cameraAngle);c=sin(cameraAngle);const m=abs(b)*g+abs(c)*h;g=abs(c)*g+abs(b)*h;cameraScale=min(k/m,l/g);f=vec2(f.right-f.left,f.top-f.bottom).scale(.5);g=.5*(d.right-d.left)/cameraScale;d=.5*(d.top-d.bottom)/cameraScale;d=vec2(g*b+d*c,d*b-g*c);cameraPos=a.add(f).add(d);return cameraScale}function isOnScreen(a,b=0){if(!cameraScale)return!1;let c=a.x-cameraPos.x;a=a.y-cameraPos.y;if(cameraAngle){var d=cos(cameraAngle),e=sin(cameraAngle);const f=c*e+a*d;c=c*d-a*e;a=f}c*=2*cameraScale;a*=2*-cameraScale;b instanceof Vector2&&(b=b.length());b*=cameraScale;d=mainCanvasSize.x;e=mainCanvasSize.y;return c+b>-d&&c-b<d&&a+b>-e&&a-b<e}function setAdditiveBlendMode(a=!0){glAdditive=a;drawContext&&(drawContext.globalCompositeOperation=a?"lighter":"source-over")}function setShader(a){glCustomShader=a||void 0}function setBackgroundCanvas(a){backgroundCanvas=a}function combineCanvases(){const a=mainCanvas.width,b=mainCanvas.height;workCanvas.width=a;workCanvas.height=b;workContext.fillStyle="#000";workContext.fillRect(0,0,a,b);backgroundCanvas&&workContext.drawImage(backgroundCanvas,0,0,a,b);glCopyToContext(workContext);workContext.drawImage(mainCanvas,0,0);mainContext.save();mainContext.setTransform(1,0,0,1,0,0);mainContext.drawImage(workCanvas,0,0);mainContext.restore()}function tintImageData(a,b,c){if(c&&!isBlack(c)){b=[clamp(b.r),clamp(b.g),clamp(b.b),clamp(b.a)];c=[255*c.r,255*c.g,255*c.b,255*c.a];for(let d=0;d<a.length;++d)a[d]=a[d]*b[d&3]+c[d&3]|0;return!0}for(c=0;c<a.length;c+=4)a[c]*=clamp(b.r),a[c+1]*=clamp(b.g),a[c+2]*=clamp(b.b);return!1}function bakeTintedImage(a,b,c){const d=a.width|0,e=a.height|0;workReadCanvas.width=d;workReadCanvas.height=e;workReadContext.drawImage(a,0,0);a=workReadContext.getImageData(0,0,d,e);tintImageData(a.data,b,c);workReadContext.putImageData(a,0,0);return workReadCanvas}function drawImageColor(a,b,c,d,e,f,g,h,k,l,m,n,p=0){e=max(1,e|0);f=max(1,f|0);const r=e-2*p,q=f-2*p;!canvasColorTiles||isWhite(m)&&(!n||isBlack(n))?(a.globalAlpha=m.a,a.drawImage(b,c+p,d+p,r,q,g,h,k,l),a.globalAlpha=1):(workReadCanvas.width!==e||workReadCanvas.height!==f?(workReadCanvas.width=e,workReadCanvas.height=f):workReadContext.clearRect(0,0,e,f),workReadContext.drawImage(b,c|0,d|0,e,f,0,0,e,f),b=workReadContext.getImageData(0,0,e,f),n=tintImageData(b.data,m,n),workReadContext.putImageData(b,0,0),n||(a.globalAlpha=m.a),a.drawImage(workReadCanvas,p,p,r,q,g,h,k,l),n||(a.globalAlpha=1))}function isFullscreen(){return!!document.fullscreenElement}function toggleFullscreen(){const a=mainCanvas.parentElement;isFullscreen()?document.exitFullscreen&&document.exitFullscreen():a.requestFullscreen&&a.requestFullscreen()}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=(a+"").split("\n");const m=d?(a.length-1)*h.y/2:0;a.forEach((n,p)=>{const r=d?(n.length-1)*h.x/2:0;for(let q=n.length;q--;){const u=n.charCodeAt(q);this.getGlyphPos(32>u||127<u?95:u-32,l.pos);k.x=ceil(b.x+q*h.x-r-h.x/2)+h.x/2-.5;k.y=ceil(b.y+p*h.y-m-h.y/2)+h.y/2-.5;drawTile(k,h,l,e,0,!1,void 0,f,!0,g)}})}getGlyphPos(a,b=new Vector2){const c=this.tileInfo,d=c.padding,e=c.size.x+2*d,f=c.size.y+2*d;if(c.columns)return b.set(c.pos.x+a%c.columns*e,c.pos.y+(a/c.columns|0)*f);const g=c.textureInfo.size.x/e|0;a=((c.pos.y-d)/f|0)*g+((c.pos.x-d)/e|0)+a;return b.set(a%g*e+d,(a/g|0)*f+d)}}function engineGlowAlpha(a,b){b*=3.5;const c=Math.exp(-b);return(Math.exp(-b*a*a)-c)/(1-c)}const engineGlowTextures=new Map;function engineGlowTexture(a=1){a=max(round(10*a),1)/10;var b=engineGlowTextures.get(a);if(b||!glContext||!canvasAvailable())return b;b=createCanvasContext(64);const c=b.createRadialGradient(32,32,0,32,32,32);for(let d=0;16>=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<a.axes.length;++b)if(.5<abs(a.axes[b]))return!0}return!1}function inputClearKeyboard(){const a=inputData[0];for(const b in a)isNaN(+b)&&(a[b]=0);inputKeysHeld.clear()}function inputClear(){for(let a=inputData.length;a--;)if(!a||inputData[a])inputData[a]=[];inputKeysHeld.clear();inputWasTouching=0;inputPinch=void 0;touchGamepadPointerRole.clear();touchGamepadButtons.length=0;touchGamepadButtonsPressed.length=0;touchGamepadSticks.length=0;touchGamepadStickPointerId.length=0;gamepadStickData.length=0;gamepadDpadData.length=0}function keyIsDown(a,b=0){return!!(inputData[b]?.[a]&1)&&!inputCaptureHides(b)}function keyWasPressed(a,b=0){return!!(inputData[b]?.[a]&2)&&!inputCaptureHides(b)}function keyWasReleased(a,b=0){return!!(inputData[b]?.[a]&4)&&!inputCaptureHides(b)}function keyDirection(a="ArrowUp",b="ArrowDown",c="ArrowLeft",d="ArrowRight"){return vec2((keyIsDown(d)?1:0)-(keyIsDown(c)?1:0),(keyIsDown(a)?1:0)-(keyIsDown(b)?1:0))}function mouseIsDown(a){return keyIsDown(a)}function mouseWasPressed(a){return keyWasPressed(a)}function mouseWasReleased(a){return keyWasReleased(a)}function gamepadIsDown(a,b=gamepadPrimary){return keyIsDown(a,b+1)}function gamepadWasPressed(a,b=gamepadPrimary){return keyWasPressed(a,b+1)}function gamepadWasReleased(a,b=gamepadPrimary){return keyWasReleased(a,b+1)}function gamepadStick(a,b=gamepadPrimary){return gamepadStickData[b]?.[a]??vec2()}function gamepadDpad(a=gamepadPrimary){return gamepadDpadData[a]?.copy()??vec2()}function gamepadConnected(a=gamepadPrimary){return!!inputData[a+1]}function gamepadStickCount(a=gamepadPrimary){return gamepadStickData[a]?.length??0}function gamepadVibrate(a=gamepadPrimary,b=200,c=1,d=1,e=0){vibrateEnable&&!headlessMode&&inputGetGamepads()[a]?.vibrationActuator?.playEffect?.("dual-rumble",{duration:b,strongMagnitude:c,weakMagnitude:d,startDelay:e})?.catch?.(()=>{})}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){if(touchInputEnable){inputLastTouchTime=performance.now();soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioResume();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(u=>!m(u)),p=n||k[0];let r=vec2(p.clientX,p.clientY);const q=1<l&&touchPinchWheel;if(1<l){const[u,t]=k;k=u.identifier+" "+t.identifier;const v=hypot(u.clientX-t.clientX,u.clientY-t.clientY);if(inputPinch&&inputPinch.key===k){const z=(inputPinch.distance-v)/50;touchPinch+=z;touchPinchWheel&&(mouseWheel+=z)}inputPinch={key:k,distance:v};q&&(r=vec2((u.clientX+t.clientX)/2,(u.clientY+t.clientY)/2))}else inputPinch=void 0;k=mousePosScreen;mousePosScreen=f(r);q?inputData[0][0]&1&&(inputData[0][0]=inputData[0][0]&2|4):inputWasTouching&&p.identifier===inputTouchIdentifier?mouseDeltaScreen=mouseDeltaScreen.add(mousePosScreen.subtract(k)):n&&e(n.clientX,n.clientY)&&(inputData[0][0]=3);inputTouchIdentifier=q?void 0:p.identifier}else inputPinch=void 0,inputWasTouching&&inputData[0][0]&1&&(inputData[0][0]=inputData[0][0]&2|4);inputWasTouching=l}inputPreventDefault&&h.cancelable&&document.hasFocus()&&!a(h)&&(l=document.activeElement,"touchstart"==h.type&&b(l)&&!l.contains(h.target)&&l.blur(),h.preventDefault());return!0}inputWasTouching&&inputData[0][0]&1&&(inputData[0][0]=inputData[0][0]&2|4);inputWasTouching=0}document.addEventListener("touchstart",h=>g(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.add(g.code);inputWASDEmulateDirection&&inputKeysHeld.has(inputArrowToWASD[g.code])&&inputData[0][g.code]&1||(inputData[0][g.code]=3);var k=g.code;k=inputWASDEmulateDirection&&inputWASDToArrow[k]||k;k===g.code||inputData[0][k]&1||(inputData[0][k]=3)}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;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){inputPreventDefault&&!b(g.target)&&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=>.3<n?percent(n,.3,.8):-.3>n?-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(.3<f.lengthSquared()){var g=clamp(round(f.x),-1,1);f=clamp(round(f.y),-1,1);b[e]=vec2(g,-f).clampLength();e||c.set(g,-f)}}a=inputData[1]??(inputData[1]=[]);for(b=12;b--;)c=gamepadIsDown(b,0),d=touchGamepadButtons[b],e=touchGamepadButtonsPressed[b]||d&&!c,a[b]=d?e?3:1:e?6:c?4:0,touchGamepadVibration&&a[b]&2&&(9===b||touchGamepadIsFaceButton(b))&&vibrate(touchGamepadVibration);touchGamepadButtonsPressed.length=0;gamepadButtonsLast[0]=void 0}else{if(gamepadsEnable&&!debug&&!document.hasFocus())return void(gamepadButtonsLast.length=0);b=gamepadsEnable?inputGetGamepads():[];for(c=0;8>c;++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=p=>{const r=isFinite(l.axes[p])?l.axes[p]:0;if(m&&4>p||!gamepadAxisFilterEnable)return r;const q=n[p]|0;if(q>gamepadAxisCenteredFrames)return r;n[p]=.3>abs(r)?q+1:0;return 0};for(var k=0;k<l.axes.length-1;k+=2)g[k>>1]=a(vec2(h(k),h(k+1)));h=g.some(p=>.25<p.lengthSquared());for(k=l.buttons.length;k--;){const p=l.buttons[k],r=e[k];e[k]=p.pressed;d[k]=p.pressed?r?1:3:r?4:0;p.pressed&&(!p.value||.9<p.value)&&(h=!0)}d.length=e.length=l.buttons.length;g.length=l.axes.length>>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<gamepadStick(c).lengthSquared();for(c=17;c--&&!b;)b=gamepadIsDown(c);c=!1;for(const d in inputData[0])if(isNaN(+d)&&inputData[0][d]&1){c=!0;break}b?lastInputDevice="gamepad":a?lastInputDevice="mouse":c&&(lastInputDevice="keyboard");isUsingGamepad="gamepad"===lastInputDevice}())}function inputUpdatePost(){if(!headlessMode){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=touchPinch=0;mouseDelta=vec2();mouseDeltaScreen=vec2()}}function inputRender(){touchGamepadRender()}const touchGamepadSvgNS="http://www.w3.org/2000/svg";function touchGamepadInit(){if(!touchGamepadOverlay&&touchGamepadEnable&&isTouchDevice&&!headlessMode&&document.body){var a=touchGamepadOverlay=document.createElement("div");a.style.cssText="position:fixed;inset:0;z-index:50;pointer-events:none;opacity:0;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;transition:opacity .2s;box-sizing:border-box;padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)";var b=touchGamepadStage=document.createElement("div");b.style.cssText="position:relative;width:100%;height:100%;pointer-events:none";a.appendChild(b);var c=touchGamepadSvg=document.createElementNS(touchGamepadSvgNS,"svg");c.style.cssText="position:absolute;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible;fill:none;stroke:#fff;stroke-width:3";b.appendChild(c);c=()=>{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)||0<touchGamepadSideButtonCount(a)}function touchGamepadIsFaceButton(a){for(let b=0;2>b;b++){const c=touchGamepadSideButtonBase(b);if(!touchGamepadSideStick(b)&&a>=c&&a<c+touchGamepadSideButtonCount(b))return!0}return!1}function touchGamepadSideCenter(a,b,c){if(touchGamepadFloating&&touchGamepadSideStick(a)&&touchGamepadStickAnchors[a])return touchGamepadStickAnchors[a];c-=touchGamepadSize;const d=touchGamepadSideButtonCount(a);touchGamepadSideStick(a)||2!==d&&3!==d||(c-=touchGamepadSize/4);return vec2(a?b-touchGamepadSize:touchGamepadSize,c)}function touchGamepadRelayout(){if(touchGamepadOverlay){var a=touchGamepadStageRect(),b=a.width;a=a.height;var c=touchGamepadSize,d=(f,g)=>f.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 p=document.createElementNS(touchGamepadSvgNS,"circle");p.setAttribute("cx",k);p.setAttribute("cy",l);p.setAttribute("r",m);n&&p.setAttribute("fill",n);c.appendChild(p);return p},g=k=>{const l=.18*e,m=.5*e,n=k.x;k=k.y;const p=document.createElementNS(touchGamepadSvgNS,"path");p.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(p)};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 p=0;p<l;p++){var h=mod(p-1,4);let r=2<l?h:min(h,l-1);r=touchGamepadFaceIndex(r);h=vec2().setDirection(h,e/2);2===l&&(h.x*=-1);k||(h.x*=-1);h=n.add(h);d.face[m+r]=f(h.x,h.y,e/4,"#000")}}debug&&debugGamepads&&touchGamepadBuildDebug(a,b)}function touchGamepadBuildDebug(a,b){const c=touchGamepadSize,d=touchGamepadSvg,e=(h,k,l)=>{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()&&0<b&&!paused;touchGamepadOverlay.style.opacity=c?a?1:b*touchGamepadAlpha:0;if(c){b=touchGamepadStageRect();a=b.width;c=b.height;var d=touchGamepadSize;if(b=touchGamepadSvgEls){for(let e=0;2>e;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<b.face.length;a++)b.face[a]&&b.face[a].setAttribute("fill",touchGamepadButtons[a]?"#fff":"#000")}}}else"none"!==touchGamepadOverlay.style.display&&(touchGamepadOverlay.style.display="none",touchGamepadPointerRole.clear(),touchGamepadButtons.length=0,touchGamepadButtonsPressed.length=0,touchGamepadSticks.length=0,touchGamepadStickPointerId.length=0,inputData[1]=void 0,gamepadStickData[0]=gamepadDpadData[0]=void 0)}function touchGamepadEventPos(a){const b=touchGamepadStageRect();return vec2(a.clientX-b.left,a.clientY-b.top)}function touchGamepadApplyStick(a,b){b=b.subtract(touchGamepadStickAnchors[a]);touchGamepadSticks[a]=b.scale(2/touchGamepadSize).clampLength();touchGamepadButtons[touchGamepadStickButton(a)]=1}function touchGamepadFaceButtonAt(a,b,c,d){const e=touchGamepadSideButtonCount(a),f=touchGamepadSideButtonBase(a);c=touchGamepadSideCenter(a,c,d);if(c.distance(b)>=touchGamepadSize)return-1;if(1===e)return f;b=c.subtract(b);a||(b.x*=-1);a=2===e?b.x<b.y?1:0:mod(b.direction()+2,4);a=touchGamepadFaceIndex(a);return a<e?f+a:-1}function touchGamepadControlAt(a,b,c){const d=touchGamepadSize,e=a.x<b/2,f=.4*c;if(touchGamepadCenterButtonSize&&vec2(b/2,c/2).distance(a)<touchGamepadCenterButtonSize&&!touchGamepadStartBlockedAt(a,b,c))return{role:"start"};for(let h=0;2>h;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&&(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}function audioParamRamp(a,b,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??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)))}}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<a.numberOfChannels;c++)b.push(a.getChannelData(c).slice());this._sampleChannels=b}return this._sampleChannels}set sampleChannels(a){this._sampleChannels=a;this.sampleBuffer=void 0;this.sampleLength=a?.[0]?.length||0}buildSampleBuffer(){this.sampleBuffer||!this._sampleChannels||headlessMode||(this.sampleBuffer=createAudioBuffer(this._sampleChannels,this.sampleRate),this._sampleChannels=void 0)}play(a,b=1,c=1,d=1,e=!1,f=!1){if(soundEnable&&!headlessMode&&(this.sampleBuffer||this._sampleChannels)){var g;if(a){if(g=this.range){var h=cameraPos.distanceSquared(a);if(h>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 fetch(a);if(!b.ok)throw Error(`Failed to load sound from ${a}: ${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=b;this.rate=c;this.pan=d;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;this.gainNode&&audioParamRamp(this.gainNode.gain,a,b)}setPan(a){this.pan=a;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;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?mod(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()){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,p=0,r=0,q=0,u=0,t=0,v=1,z=0,x=0,w=0){var y=audioDefaultSampleRate;let A=2*PI,C=k*=500*A/y/y;b=c*=(1+rand(b,-b))*A/y;let D=0,B=0,E=0,F=1,H,G=0,I=0,K=0,O;var N=A*min(abs(w),y/4-1)*2/y,L=cos(N),M=sin(N)/2/2,J=1+M;N=-2*L/J;M=(1-M)/J;let P=(1+sign(w)*L)/2/J;L=-(sign(w)+L)/J;let Q=J=0,R=0,S=0;d=d*y||9;z*=y;e*=y;f*=y;t*=y;l*=500*A/y**3;q*=A/y;m*=A/y;n*=y;p=p*y|0;y=d+z+e+f+t|0;for(H=new Float32Array(0<y?y:0);I<y;H[I++]=K*a)++E%(100*u|0)||(K=g?1<g?2<g?3<g?4<g?G/A%1<h/2?1:-1:sin(G**3):max(min(tan(G),1),-1):1-(2*G/A%2+2)%2:1-4*abs(round(G/A)-G/A):sin(G),K=(p?1-x+x*sin(A*I/p):1)*(4<g?K:sign(K)*abs(K)**h)*(I<d?I/d:I<d+z?1-(I-d)/z*(1-v):I<d+z+e?v:I<y-t?(y-I-t)/f*v:0),K=t?K/2+(t>I?0:(I<y-t?1:(y-I)/t)*H[I-t|0]/2/(a||1)):K,w&&(K=S=P*J+L*(J=Q)+P*(Q=K)-M*R-N*(R=S))),O=(c+=k+=l)*cos(q*D++),G+=O+O*r*(I*I*A%2-1),F&&++F>n&&(c+=m,b+=m,F=0),!p||++B%p||(c=b,k=C,F||=1);return H}const tileCollisionLayers=[];function tileCollisionAssertWhole(a){}function tileCollisionTester(a){return a?"function"===typeof a?(b,c)=>a(b,c):(b,c)=>a.collideWithTile(b,c):b=>0<b}function tileCollisionGetData(a,b=!0){let c=0;for(const e of tileCollisionLayers)if(!b||e.isSolid){var d=a.x-e.pos.x;const f=a.y-e.pos.y,g=e.size;if(0<=d&&0<=f&&d<g.x&&f<g.y){d=e.collisionData[(f|0)*g.x+(d|0)];if(0<d)return d;d&&!c&&(c=d)}}return c}function tileCollisionTest(a,b=vec2(),c,d=!0){for(const e of tileCollisionLayers)if((!d||e.isSolid)&&e.collisionTest(a,b,c))return e}function tileCollisionRaycast(a,b,c,d,e=!0){let f,g,h;const k=d&&vec2();for(const l of tileCollisionLayers)if(!e||l.isSolid){const m=l.collisionRaycast(a,b,c,k);if(m){const n=a.distanceSquared(m);if(void 0===f||n<g)f=m,g=n,d&&(h=k.copy())}}f&&d&&d.setFrom(h);return f}const tileLayersTiledFlips=[[0,0],[3,1],[2,1],[3,0],[0,1],[1,0],[2,0],[1,1]];function tileLayerTileInfo(a,b){if(a){if(a.tiles)return a.tiles[b];if(!a.columns)return a.index(b);if(!(a.textureInfo&&a.pos.y+(b/a.columns|0)*(a.size.y+2*a.padding)+a.size.y>a.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<f&&0<g))throw Error(`tileLayersLoad: a map is a whole number of cells across and down, not ${f} by ${g}`);if(!isArray(a.layers)||!a.layers.length)throw Error("tileLayersLoad: a map has a list of layers");var h=a.tilesets?.[0];if(b&&!b.tiles&&h&&(0<h.margin||0<h.spacing)){var k=h.margin||0,l=h.spacing||0,m=b.size,n=b.textureInfo?.size.x||0;h=h.columns||max(1,floor((n-2*k+l)/(m.x+l)));n=b.pos.subtract(vec2(b.padding));b=new TileInfo(n.add(vec2(k)),m,b.textureInfo,l/2,b.bleed,h)}const p=[],r=(u,t,v)=>{for(const x of u){if((u=x.type)&&"tilelayer"!==u&&"group"!==u){p.push({dataLayer:x});continue}var z=x.tintcolor;z=z?tileLayersColor(z):(x.color||WHITE).copy();z.a*=x.opacity??1;const w=v&&!1!==x.visible;"group"===u?r(x.layers||[],t.multiply(z),w):p.push({dataLayer:x,color:t.multiply(z),visible:w})}};r(a.layers,WHITE,!0);if("string"===typeof d){const u=d;d=p.findIndex(t=>t.color&&t.dataLayer.name===u);0>d&&console.error("tileLayersLoad: no tile layer is named "+u+", none is solid")}k=[];l=vec2(a.width,a.height);m=p.length;for(const[u,{dataLayer:t,color:v}]of p.entries())if(h=t.data,v&&(!isArray(h)&&!ArrayBuffer.isView(h)||t.data.length!==l.area()))throw Error(`tileLayersLoad: layer ${t.name??u} has ${t.data?.length} tiles for a map of `+`${l.area()}; infinite maps and compressed layers are not read`);for(h=m;h--;){const{dataLayer:u,color:t,visible:v}=p[h];if(t){n=c-(m-1-h);n=new TileCollisionLayer(vec2(),l,b,n);n.isSolid=h===d;k[h]=n;v||(n.render=()=>{});for(let z=0;z<l.x;++z)for(let x=0;x<l.y;++x){const w=vec2(z,l.y-1-x);var q=u.data[z+x*l.x];if(q){const[y,A]=tileLayersTiledFlips[q>>>29];q=new TileLayerData((q&268435455)-1,y,!!A,t);n.setData(w,q);h===d&&n.setCollisionData(w,1)}}e&&v&&n.redraw()}}editorMapLoaded(a,k,p);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(u=>u.levels||[]),d="string"===typeof b?c.find(u=>u.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=u=>"Entities"!==u.__type,f=c.find(u=>e(u)&&void 0!=u.__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&&0<k&&4194304>=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(u=>u.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 u=l.nextlayerid++;if(!e(m)){var p=(m.entityInstances||[]).filter(x=>isArray(x.px)).map(x=>{const[w=0,y=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-y)*C,width:A,height:C,rotation:0,visible:!0,properties:D}});l.layers.push({id:u,name:n,type:"objectgroup",objects:p,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}p=m.__opacity??1;const t="IntGrid"===m.__type;if(t){const x=Array(h*k).fill(0);(m.intGridCsv||[]).forEach((w,y)=>y<x.length&&(x[y]=w));l.layers.push({id:u,name:n,type:"tilelayer",width:h,height:k,data:x,opacity:p,visible:!1,x:0,y:0})}var r=[...m.autoLayerTiles||[],...m.gridTiles||[]].filter(x=>isArray(x.px));if(!r.length){t||l.layers.push({id:u,name:n,type:"tilelayer",width:h,height:k,data:Array(h*k).fill(0),opacity:p,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=t?n+" tiles":n;const v=[{depth:0,alpha:1,data:Array(h*k).fill(0)}];var q=(x,w)=>{let y=v.find(A=>A.depth===x&&A.alpha===w);y||v.push(y={depth:x,alpha:w,data:Array(h*k).fill(0)});return y.data};const z=new Uint16Array(h*k);for(const x of r){r=floor(x.px[0]/g);const w=floor(x.px[1]/g),y=r+w*h;0<=r&&r<h&&0<=w&&w<k&&(q(z[y]++,round(1e3*clamp(x.a??1))/1e3)[y]=(x.t+1|(x.f&1?2147483648:0)|(x.f&2?1073741824:0))>>>0)}m=!1!==m.visible;v.sort((x,w)=>x.depth-w.depth||w.alpha-x.alpha);for(const{depth:x,alpha:w,data:y}of v)q=n+(x?` (${x+1})`:"")+(1>w?" "+String(w).replace(/^0/,""):""),l.layers.push({id:t||x||1>w?l.nextlayerid++:u,name:q,type:"tilelayer",width:h,height:k,data:y,opacity:p*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);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();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){this.context&&(this.redrawStart(),this.drawTileData(a,b),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 p=this.hasWebGL();p&&glSetRenderTarget(this.textureInfo.glTexture);drawTile(a,b,c,d,e,f,void 0,p,!0,p?void 0:this.context);mainCanvasSize=g;p&&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}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(;h<e;++h)for(var l=d;l<g;++l){if(!this.collisionData[h*a.x+l])continue;let m=l+1;for(;m<g&&this.collisionData[h*a.x+m];)++m;const n=m-l,p=new TileInfo(vec2(l*c.x,f-(h+1)*c.y),vec2(n*c.x,c.y),this.textureInfo,0,0);l=vec2(this.pos.x+(l+n/2)*b.x,this.pos.y+(h+.5)*b.y);drawTile(l,vec2(n*b.x,b.y),p,this.color,0,!1,void 0,k,!1);l=m}}destroy(a=!1){if(!this.destroyed){var b=tileCollisionLayers.indexOf(this);0<=b&&tileCollisionLayers.splice(b,1);super.destroy(a)}}initCollision(a){this.size=a.floor();this.collisionData=Array(this.size.area()).fill(0)}setCollisionData(a,b=1){const c=(a.y|0)*this.size.x+(a.x|0);a.arrayCheck(this.size)&&(this.collisionData[c]=b)}clearCollisionData(a){this.setCollisionData(a,0)}getCollisionData(a){const b=(a.y|0)*this.size.x+(a.x|0);return a.arrayCheck(this.size)?this.collisionData[b]:0}collisionTest(a,b=new Vector2,c){tileCollisionAssertWhole(this);c=tileCollisionTester(c);var d=a.x-this.pos.x,e=a.y-this.pos.y;if(0>d+b.x/2||d-b.x/2>this.size.x||0>e+b.y/2||e-b.y/2>this.size.y)return!1;a=max(d-b.x/2|0,0);var f=max(e-b.y/2|0,0);d=min(b.x?d+b.x/2:a+1,this.size.x);for(b=min(b.y?e+b.y/2:f+1,this.size.y);f<b;++f)for(e=a;e<d;++e){const g=this.collisionData[f*this.size.x+e];if(g&&c(g,vec2(e+this.pos.x,f+this.pos.y)))return!0}return!1}collisionRaycast(a,b,c,d){tileCollisionAssertWhole(this);const e=tileCollisionTester(c),f=this.pos;c=a.subtract(f);var g=b.subtract(a);let h=0,k=1;for(const[l,m,n]of[[c.x,g.x,this.size.x+1],[c.y,g.y,this.size.y+1]]){if(!m){if(-1>l||l>n)return;continue}const p=(-1-l)/m,r=(n-l)/m;h=max(h,min(p,r));k=min(k,max(p,r))}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&&e(m,vec2(l.x+f.x,l.y+f.y))},d))c.x+=f.x,c.y+=f.y;debugRaycast&&c&&(g=c.floor().add(vec2(.5)),debugRect(g,vec2(1),"#f008",0,0,!1,!1),debugLine(a,b,"#00f",.02,0,!1),debugLine(a,c,"#f00",.02,0,!1),debugPoint(c,"#0f0",void 0,void 0,!1),d&&debugLine(c,c.add(d),"#ff0",.02,0,!1));return c}}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=WHITE,k=WHITE,l=CLEAR_WHITE,m=CLEAR_WHITE,n=.5,p=.1,r=1,q=.1,u=.05,t=1,v=1,z=0,x=PI,w=.1,y=.2,A=!1,C=!1,D=!0,B=C?1e9:0,E=!1){super(a,vec2(),g,b,void 0,B);this.emitCircle="number"===typeof c;this.emitSize="number"===typeof c?vec2(c):c.copy();this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h.copy();this.colorStartB=k.copy();this.colorEndA=l.copy();this.colorEndB=m.copy();this.randomColorLinear=D;this.particleTime=n;this.sizeStart=p;this.sizeEnd=r;this.speed=q;this.angleSpeed=u;this.damping=t;this.angleDamping=v;this.gravityScale=z;this.particleConeAngle=x;this.fadeRate=w;this.randomness=y;this.collideLevel=A;this.additive=C;this.localSpace=E;this.trailScale=0;this.scale=1;this.gravity=0;this.particleUpdateCallback=this.particleCollideCallback=this.particleDestroyCallback=this.particleCreateCallback=void 0;this.velocityInheritance=0;this.emitTimeBuffer=1;this.particles=[];this.previousPos=void 0;this.previousAngle=this.angle}update(){this.previousPos||(this.previousPos=this.pos.copy(),this.previousAngle=this.angle);if(this.velocityInheritance){var a=this.velocityInheritance;this.velocity.x=a*(this.pos.x-this.previousPos.x);this.velocity.y=a*(this.pos.y-this.previousPos.y);this.angleVelocity=a*(this.angle-this.previousAngle)}this.previousAngle=this.angle;this.previousPos.x=this.pos.x;this.previousPos.y=this.pos.y;if(this.isActive()){if(a=this.emitRate*particleEmitRateScale,0<a&&Infinity>a)for(this.emitTimeBuffer+=a*timeDelta;1<=this.emitTimeBuffer;--this.emitTimeBuffer)this.emitParticle()}else 0===this.particles.length&&this.destroy(!0);a=this.particles;let b=0;for(let c=0;c<a.length;++c){const d=a[c];d.update();d.destroyed||(a[b++]=d)}a.length=b;debugParticles&&(this.emitCircle?debugCircle(this.pos,this.emitSize.x*this.scale,"#0f0",0,!1,!1):debugRect(this.pos,this.emitSize.scale(this.scale),"#0f0",0,this.angle,!1,!1))}emitParticle(){var a=this.scale,b=this.emitCircle?randInCircle(this.emitSize.x/2*a):vec2(rand(-.5,.5)*this.emitSize.x*a,rand(-.5,.5)*this.emitSize.y*a);let c=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(this.emitCircle||(b=b.rotate(this.angle)),b.x+=this.pos.x,b.y+=this.pos.y,c+=this.angle);const d=this.randomness;var e=n=>n+n*rand(d,-d);const f=e(this.particleTime),g=e(this.sizeStart)*a,h=e(this.sizeEnd)*a;var k=e(this.speed)*a,l=e(this.angleSpeed)*randSign(),m=rand(this.emitConeAngle,-this.emitConeAngle);e=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear);a=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.velocityInheritance&&(k.x+=this.velocity.x,k.y+=this.velocity.y,l+=this.angleVelocity);b=new Particle(this,b,c,e,a,f,g,h,k,l);this.particles.push(b);this.particleCreateCallback?.(b);return b}updatePhysics(){}render(){this.additive&&setAdditiveBlendMode();particleTile=null;particleTileBatch=!0;for(const a of this.particles)a.render();particleTileBatch=!1;this.additive&&setAdditiveBlendMode(!1)}isActive(){return!this.emitTime||this.getAliveTime()<this.emitTime}destroy(a=!1){this.destroyed||(super.destroy(a),!a&&0<this.particles.length&&(this.destroyed=!1,this.emitTime=-1))}}const particleDrawPos=new Vector2,particleDrawSize=new Vector2,particleCollidePos=new Vector2;let particleTile,particleTileBatch=!1,particleTileTextured=!1,particleTileEmpty=!1,particleTileU0=0,particleTileV0=0,particleTileU1=0,particleTileV1=0;function particleTileSet(a){particleTile=a;var b=a?.textureInfo;particleTileTextured=!!b;particleTileEmpty=!!b&&!(a.size.x&&a.size.y);if(b&&!particleTileEmpty){glSetTexture(b.glTexture);var c=b.sizeInverse,d=a.bleed;b=a.pos.x*c.x;var e=a.pos.y*c.y,f=a.size.x*c.x;a=a.size.y*c.y;if(d){const g=c.x*d;c=c.y*d;particleTileU0=b+g;particleTileV0=e+c;particleTileU1=b-g+f;particleTileV1=e-c+a}else particleTileU0=b,particleTileV0=e,particleTileU1=b+f,particleTileV1=e+a}}function particleCollideTest(a,b,c,d){const e=tileCollisionGetData(particleCollidePos.set(c,d));return b?!!e&&!!b(a,e,vec2(c,d)):0<e}class Particle{constructor(a,b,c,d,e,f,g,h,k=vec2(),l=0){this.emitter=a;this.scale=a.scale??1;this.pos=b;this.angle=c;this.size=vec2(g);this.color=d.copy();this.colorStart=d;this.colorEnd=e;this.lifeTime=f;this.sizeStart=g;this.sizeEnd=h;this.velocity=k;this.angleVelocity=l;this.spawnTime=time;this.mirror=randBool();this.groundObject=void 0;this.destroyed=!1;this.tileInfo=a.tileInfo}update(){if(!this.destroyed){var a=this.emitter,b=a.damping,c=a.angleDamping,d=a.restitution,e=a.friction,f=a.gravityScale,g=a.collideLevel,h=a.particleCollideCallback,k=a.particleUpdateCallback;if(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,p=gravity.x*f*n;f=(gravity.y*f+(a.gravity||0))*n;a.localSpace&&a.angle&&(n=cos(a.angle),a=sin(a.angle),[p,f]=[p*n-f*a,p*a+f*n]);this.velocity.x=this.velocity.x*b+p;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;if(particleCollideTest(this,h,this.pos.x,this.pos.y)&&(c=tileCollisionTest(this.pos),!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||0<this.velocity.y&&0<m)this.groundObject=c;this.pos.y=g;this.velocity.y*=-d;this.velocity.x*=e}debugPhysics&&debugRect(this.pos,this.size,"#f00",0,0,!1,!1)}this.destroyed||k?.(this)}else k?.(this)}}}destroy(){if(!this.destroyed){var a=this.emitter.particleDestroyCallback,b=this.colorEnd;this.color.set(b.r,b.g,b.b,b.a);this.size.set(this.sizeEnd,this.sizeEnd);this.destroyed=!0;a?.(this)}}render(){var a=this.emitter,b=a.localSpace;const c=a.additive&&!glAdditive;var d=a.trailScale,e=a.fadeRate/2,f=0<this.lifeTime?min((time-this.spawnTime)/this.lifeTime,1):1,g=1-f,h=g*this.sizeStart+f*this.sizeEnd;this.size.set(h,h);h=particleDrawSize.set(h,h);this.color.r=g*this.colorStart.r+f*this.colorEnd.r;this.color.g=g*this.colorStart.g+f*this.colorEnd.g;this.color.b=g*this.colorStart.b+f*this.colorEnd.b;this.color.a=(g*this.colorStart.a+f*this.colorEnd.a)*(f<e?f/e:f>1-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,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,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,p=k&&f;glContext.enableVertexAttribArray(g);glContext.vertexAttribPointer(g,l,h,n,p,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}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=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;\n#define localUV l\n"+a.fragmentCode+"\nvoid main(){vec4 t;mainImage(t,v);"+gl_FRAGMENT_TINT_SOURCE+"}"));return glFailedPrograms.has(a)?glShader:a}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&&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;b&&b===glActiveTexture&&(glFlush(),glActiveTexture=void 0);glMipmapsStale.delete(b);glPremultipliedTextures.delete(b);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 r=0;r<m;++r){var p=a[r];let q,u;const t=(q=l)[u=r]||(q[u]=vec2()),v=p.x*e;p=p.y*f;t.x=c+g*v-n*p;t.y=d+n*v+g*p;k[r]=t}a=h?glPolyStrip(k):k;glDrawPoints(a,b)}function glDrawOutlineTransform(a,b,c,d,e,f,g,h,k=!0){a=glMakeOutline(a,c,k);glDrawPointsTransform(a,b,d,e,f,g,h,!1)}function glDrawPoints(a,b){glDrawPolyStrip(a,b)}function glDrawColoredPoints(a,b){glDrawPolyStrip(a,0,b)}function glDrawPolyStrip(a,b,c){if(glEnable&&!(3>a.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;n<f;n++){var g=a[c?(n-1+f)%f:max(n-1,0)];const p=a[n];var h=a[c?(n+1)%f:min(n+1,f-1)],k=p.x-g.x,l=p.y-g.y,m=(k*k+l*l)**.5;g=h.x-p.x;const r=h.y-p.y;h=(g*g+r*r)**.5;if(1e-6>m&&1e-6>h)continue;l=1e-6<m?-l/m:0;m=1e-6<m?k/m:0;k=l+(1e-6<h?-r/h:0);g=m+(1e-6<h?g/h:0);h=(k*k+g*g)**.5;1e-6>h?(k=l,g=m):(k/=h,g/=h,l=l*k+m*g,1e-6<l&&(l=min(1/l,10),k*=l,g*=l));let q,u;l=(q=e)[u=d.length]||(q[u]=vec2());let t,v;h=(t=e)[v=d.length+1]||(t[v]=vec2());l.x=p.x-k*b;l.y=p.y-g*b;h.x=p.x+k*b;h.y=p.y+g*b;d.push(l,h)}1<d.length&&c&&(d.push(d[0]),d.push(d[1]));return d}function glPolyStrip(a){if(3>a.length)return[];const b=(q,u,t)=>(u.x-q.x)*(t.y-q.y)-(u.y-q.y)*(t.x-q.x);0>(q=>{let u=0;for(let t=q.length;t--;)u+=q[t].cross(q[(t+1)%q.length]);return u})(a)&&(a=a.slice().reverse());var c=a.length,d=!0,e=0,f=0;for(var g=0;d&&g<c;++g){d=a[g];var h=a[(g+1)%c].x-d.x;d=-1e-9<b(a[(g+c-1)%c],d,a[(g+1)%c]);(h=1e-9<h?1:-1e-9>h?-1:0)&&h!==f&&(f&&++e,f=h)}if(d&&2>=e){e=[a[0]];for(let q=1,u=c-1;q<=u;++q,--u)e.push(a[q]),q===u||e.push(a[u]);return e}e=(q,u,t,v)=>{const z=b(u,t,q);t=b(t,v,q);q=b(v,u,q);return!((-1e-9>z?1:0)+(-1e-9>t?1:0)+(-1e-9>q?1:0)&&(1e-9<z?1:0)+(1e-9<t?1:0)+(1e-9<q?1:0))};f=[];for(c=0;c<a.length;++c)f[c]=c;c=[];g=0;for(d=a.length**2+100;3<f.length&&g++<d;){h=!1;for(var k=0;k<f.length;k++){var l=f[(k+f.length-1)%f.length],m=f[k];const q=f[(k+1)%f.length],u=a[l],t=a[m],v=a[q];if(1e-9>b(u,t,v))continue;let z=!1;for(let x=0;x<f.length;x++){const w=f[x];if(w!==l&&w!==m&&w!==q&&(z=e(a[w],u,t,v)))break}if(!z){c.push([l,m,q]);f.splice(k,1);h=!0;break}}if(!h){h=-1;k=Infinity;for(l=0;l<f.length;l++)m=abs(b(a[f[(l+f.length-1)%f.length]],a[f[l]],a[f[(l+1)%f.length]])),m<k&&(k=m,h=l);if(0>h)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,p,r]=c[0];e.push(a[n],a[p],a[r]);for(f=1;f<c.length;f++){const[q,u,t]=c[f];e.push(a[r],a[q]);e.push(a[q],a[u],a[t]);r=t}return e}function drawLoadingScreen(a){const b=mainContext,c=mainCanvasSize.x,d=mainCanvasSize.y,e=min(.6*c,400),f=(c-e)/2,g=d/2;b.save();b.fillStyle="#000";b.fillRect(0,0,c,d);b.fillStyle=b.strokeStyle="#fff";b.font="28px "+fontDefault;b.textAlign="center";b.textBaseline="bottom";b.fillText("Loading",c/2,g-16);b.lineWidth=2;b.strokeRect(f,g,e,12);b.fillRect(f,g,e*clamp(a),12);b.restore()}function drawEngineLogo(a){engineUpdateCanvas();const b=mainContext;var c=mainCanvasSize.x,d=mainCanvasSize.y,e=percent(a,1,.8),f=percent(a,0,.5),g=b.createRadialGradient(c/2,d/2,0,c/2,d/2,.6*hypot(c,d));g.addColorStop(0,hsl(0,0,lerp(0,e/2,f),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);const h=(l,m,n,p,r,q=1)=>{0<=r?(l=b.fillStyle=b.createLinearGradient(l,m,n,p),l.addColorStop(0,`hsl(${360*[.95,.56,.13][r%3]} 99%${75}%)`),l.addColorStop(1,`hsl(${360*[.95,.56,.13][r%3]} 99%${50}%)`)):b.fillStyle="#000";-1<=r?(b.fill(),q&&b.stroke()):b.stroke()};f=(l,m,n,p=0,r=2*PI,q,u)=>{b.beginPath();b.arc(l,m,n,k*p,k*r);h(l,m-n,l,m+n,q,u)};g=(l,m,n,p,r)=>{b.beginPath();b.rect(l,m,n,p*k);h(l,m+p,l+n,m,r)};e=(l,m,n,p)=>{b.beginPath();for(const r of l)b.lineTo(r.x,r.y);b.closePath();h(0,n,0,n+p,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,5<l?1:0);b[d?"strokeText":"fillText"]("LittleJS"[l],n,54.5,17*k);m+=a}b.lineWidth=.1+1.9*k;g(3,54,73,0);g(7,15,26,-7,0);g(25,15,8,25,-1);g(10,40,15,-25,1);g(14,21,7,9,2);g(38,20,6,-6,2);g(49,20,10,-6,0);c=[vec2(44,8),vec2(64,8),vec2(59,8+6*k),vec2(49,8+6*k)];e(c,2,8,6*k);g(44,8,20,-7,0);for(c=5;c--;)f(59-6*c*k,30,10,0,2*PI,1,0);f(59,30,4,0,7,2);g(35,20,24,0);f(59,30,10);f(47,30,10,PI/2,3*PI/2);f(35,30,10,PI/2,3*PI/2);g(7,40,13,7,-1);g(17,40,43,14,-1);for(g=3;g--;)for(c=2;c--;)f(17+15*g,47,c?7:1,0,2*PI,2);for(f=2;f--;)g=53+6*k*f,g=[vec2(g+7,54),vec2(g,40),vec2(g+6*k,40),vec2(g+7+6*k,54)],e(g,0,40,14);b.restore()}let debugMedals=!1,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalsPreventUnlock=!1;const medals={};let medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast,medalsRenderAdded;function medalsInit(a){medalsSaveName=a;medalsLoad();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(b<c?1-b/c:b>d?(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]&&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};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.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 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 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=a||postProcessEffects();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){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.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,glCanvas);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.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,glCanvas),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=a||postProcessEffects();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 postProcessFragmentSource(a,b={}){let c="";for(const e in b){var d=b[e];d=isArray(d)?d.length:1;c+=`uniform ${1<d?"vec"+d:"float"} ${e};`}return"#version 300 es\nprecision highp float;uniform sampler2D iChannel0;uniform sampler2D iChannel1;uniform highp sampler2D iChannel2;uniform vec3 iResolution;uniform float iTime;uniform vec3 iDepthRange;"+c+"out vec4 c;float sceneDepth(vec2 uv){float d=texture(iChannel2,uv).r*2.-1.,n=iDepthRange.x,f=iDepthRange.y;return iDepthRange.z>0.?(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))\n\n"+a+"\nvoid main(){mainImage(c,gl_FragCoord.xy);c.a=1.;}"}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+=`
|
|
4
|
+
const engineName="LittleJS",engineVersion="1.26.0",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 frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;const frameDeltaHistory=[];let frameIntervalMS=1e3/60,frameDeltaCarryMS=0,frameDeltaCarryAverageMS=0,frameDeltaSmoothing=!0;function engineSmoothDelta(a){if(!(0<a))return 0;if(250>a){frameDeltaHistory.push(a);64<frameDeltaHistory.length&&frameDeltaHistory.shift();var b=frameDeltaHistory.slice(-16).sort((g,h)=>g-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;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;if(debug||debugWatermark)averageFPS=lerp(averageFPS,1e3/(t||1),.05);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(0<u||p)t=paused||!v,t||(timeDelta=p?v/frameRate:min(u,50)*v/1e3,time+=timeDelta,++frame),r(t)}else{const x=paused||!v;frameTimeBufferMS+=x?u:t;frameTimeBufferMS=min(frameTimeBufferMS,50*(x?1:max(1,v)));t=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(t=frameTimeBufferMS,frameTimeBufferMS=0);try{for(;0<=frameTimeBufferMS;)try{(u=paused||!(timeScale*n))||(time=timeFixedStart+(frame++-frameFixedStart)/frameRate),r(u)}finally{frameTimeBufferMS-=1e3/frameRate}}finally{frameTimeBufferMS+=t}}engineManualStep&&!p&&(frameTimeBufferMS=-500/frameRate);p=!1;headlessMode||(t=devicePixelRatio,p=windowWidthLast!==innerWidth||windowHeightLast!==innerHeight||windowPixelRatioLast!==t,windowWidthLast=innerWidth,windowHeightLast=innerHeight,windowPixelRatioLast=t);(y||p)&&q();engineManualStep||engineScheduleFrame()}async function l(n){showSplashScreen&&!headlessMode&&await n[n.length-1];const r=(async()=>{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);1<q?n():setTimeout(r,16)}let q=0;r()}),g.push(f));return engineInitDone=l(g)}function engineUpdateCanvas(){if(!headlessMode){var a=getCanvasPixelRatio();if(canvasFixedSize.x){mainCanvasSize.set(canvasFixedSize.x,canvasFixedSize.y);var b=innerWidth/innerHeight;const d=canvasFixedSize.x/canvasFixedSize.y;var c=b<d?"100%":"";b=b<d?"":"100%";mainCanvas.style.width=c;mainCanvas.style.height=b;glCanvas&&(glCanvas.style.width=c,glCanvas.style.height=b)}else mainCanvasSize.x=min(innerWidth,canvasMaxSize.x)|0,mainCanvasSize.y=min(innerHeight,canvasMaxSize.y)|0,c=mainCanvasSize.x/mainCanvasSize.y,canvasMaxAspect&&c>canvasMaxAspect?mainCanvasSize.x=min(mainCanvasSize.y*canvasMaxAspect|0,canvasMaxSize.x):c<canvasMinAspect&&(mainCanvasSize.y=min(mainCanvasSize.x/canvasMinAspect|0,canvasMaxSize.y)),mainCanvas.style.width=mainCanvasSize.x+"px",mainCanvas.style.height=mainCanvasSize.y+"px",glCanvas&&(glCanvas.style.width=mainCanvasSize.x+"px",glCanvas.style.height=mainCanvasSize.y+"px");c=mainCanvasSize.x*a|0;b=mainCanvasSize.y*a|0;mainCanvas.width!==c||mainCanvas.height!==b?(mainCanvas.width=c,mainCanvas.height=b):(mainContext.setTransform(1,0,0,1,0,0),mainContext.globalCompositeOperation="source-over",mainContext.globalAlpha=1,mainContext.filter="none",mainContext.shadowColor="rgba(0,0,0,0)",mainContext.clearRect(0,0,c,b));mainContext.setTransform(a,0,0,a,0,0);0<canvasClearColor.a&&!glEnable&&(mainContext.fillStyle=canvasClearColor.toString(),mainContext.fillRect(0,0,mainCanvasSize.x,mainCanvasSize.y),mainContext.fillStyle=BLACK.toString());mainContext.lineJoin="round";mainContext.lineCap="round"}}function engineFrameFailed(a){const b=String(a);b===engineFrameErrorLast||console.error(a);engineFrameErrorLast=b;inputUpdatePost();engineScheduleFrame()}function engineScheduleFrame(){if(!engineFrameScheduled){engineFrameScheduled=!0;var a=b=>{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<a&&engineManualStep;--a)engineUpdateInternal(frameTimeLastMS+1e3/frameRate)}function engineObjectsUpdate(){function a(e){if(e.length){var f=engineChildStack.length;for(const h of e)engineChildStack.push(h);try{for(e=f;e<engineChildStack.length;++e){var g=engineChildStack[e];g.destroyed||g.updatePass===d||(g.updatePass=d,g.updateTransforms(!1),g.update(),g.children.length&&g.updateTransforms(!1),a(g.children))}}finally{engineChildStack.length=f}}}function b(e){e.parent||e.destroyed||e.updatePass===d||(e.updatePass=d,e.update(),a(e.children),e.updateTransforms())}++engineObjectsUpdateCount;engineObjectsCollidePairs.clear();engineObjectsSort();const c=[];engineObjectsCollide=[];engineObjectsCollideStaticLast=[];for(const e of engineObjects)e.collideSolidObjects&&(engineObjectsCollide.push(e),(e.mass?engineObjectsCollideStaticLast:c).push(e));for(const e of c)engineObjectsCollideStaticLast.push(e);engineObjectsCollideStaticLast.length>=engineCollideGridMin&&(engineCollideGrid={list:engineObjectsCollideStaticLast,built:void 0});try{for(const e of engineObjects)e.parent||e.destroyed||(e.updatePhysics(),engineCollideGrid?.built&&engineCollideGridPlace(engineCollideGrid.built,e))}finally{engineCollideGrid&&=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].renderOrder<engineObjects[a-1].renderOrder)return void engineObjects.sort((b,c)=>b.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*b<g&&e.push(f))}else for(const h of c)h.destroyed||e.push(h);return e}function engineObjectsCallback(a,b,c,d=engineObjects,e=!1){for(const f of engineObjectsCollect(a,b,d,e))f.destroyed||c(f)}function engineObjectsRaycast(a,b,c=engineObjects){const d=[];for(const e of c)e.collideRaycast&&!e.destroyed&&isIntersecting(a,b,e.pos,e.size)&&(debugRaycast&&debugRect(e.pos,e.size,"#f00",0,0,!1,!1),d.push(e));debugRaycast&&debugLine(a,b,d.length?"#f00":"#00f",.02,0,!1);return d}let debugWatermark=!1,debugKey="",debugKeysAlways=!1,debugTweakables=!1;const debug=!1,debugOverlay=!1,debugPhysics=!1,debugParticles=!1,debugRaycast=!1,debugGamepads=!1,debugSound=!1,debugPointSize=.5;function ASSERT(){}function LOG(){}function debugInit(){}function debugUpdate(){}function debugRender(){}function debugRect(){}function debugPoly(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugOverlap(){}function debugText(){}function debugClear(){}function debugScreenshot(){}function debugShowErrors(){}function setDebugOverlay(){}function debugProtectConstant(a){return Object.freeze(a)}function tweak(){}function tweakButton(){}function tweakDivider(){}function tweakEngineDefaults(){}const editorEdit2DRelease={map:void 0,layer:void 0,hover:void 0,get objects(){return[]},get selection(){return new Set},paint(){return!1},changeObjects(){return!1},strokeEnd(){},strokeCancel(){},bulk(){},undo(){return!1},toJSON(){return""}};class LevelEditor{constructor(){this.paletteTiles=this.use3D=this.tool=void 0;this.keys={};this.buttons=[];this.tools={}}get isOpen(){return!1}get is3D(){return!1}get edit2D(){return editorEdit2DRelease}get edit3D(){}open(){}close(){}addKey(){}addButton(){}addTool(){}onTile(){}onRestart(){}onPlayFrom(){}onOpen(){}onClose(){}onUpdate(){}onDraw(){}onPanel(){}onSave(){return!1}}let levelEditor=new LevelEditor;function setLevelEditor(a){levelEditor=a}function editorMapRestore(a){return a}function editorMapLoaded(){}function editorJSONFetched(){}function editorPreRender(){}function editorObjectMade(){}function inputCaptureHides(){return!1}function inputCaptureMouse(){}function inputLockExit(){}function debugBox3D(){}function debugSphere3D(){}function debugLine3D(){}function debugPoint3D(){}function render3DRenderDebug(){}function editor3DCameraBegin(){}function editor3DCameraEnd(){}function editor3DLevelLoaded(){}function editor3DObjectMade(){}const PI=Math.PI,abs=Math.abs,floor=Math.floor,ceil=Math.ceil,round=Math.round,min=Math.min,max=Math.max,sign=a=>Math.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 a<b?b:a>c?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 0<a&&0===a%1&&2**round(log2(a))===a}function nearestPowerOfTwo(a){const b=2**ceil(log2(max(a,1)));return b<a?2*b:b}function isOverlapping(a,b,c,d=vec2()){const e=2*(a.y-c.y),f=b.x+d.x;b=b.y+d.y;return abs(2*(a.x-c.x))<f&&abs(e)<b}function isIntersecting(a,b,c,d){c=c.subtract(d.scale(.5));d=c.add(d);b=b.subtract(a);c=a.subtract(c);d=a.subtract(d);a=[-b.x,b.x,-b.y,b.y];b=[c.x,-d.x,c.y,-d.y];c=0;d=1;for(let e=4;e--;)if(a[e]){const f=b[e]/a[e];if(0>a[e]){if(f>d)return!1;c=max(f,c)}else{if(f<c)return!1;d=min(f,d)}}else if(0>b[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=0<e?b.x+1:b.x,r=0<f?b.y+1:b.y,q=0;n=h?(n-a.x)/h:Infinity;var p=k?(r-a.y)/k:Infinity;for(r=l<m;q<g;){if(c(b))return a=vec2(a.x+h*q,a.y+k*q),c=a.floor(),c.x<b.x?a.x=b.x:c.x>b.x&&(a.x=b.x+1-1e-9),c.y<b.y?a.y=b.y:c.y>b.y&&(a.y=b.y+1-1e-9),d&&(r?d.set(-e,0):d.set(0,-f)),a;(r=n<p)?(b.x+=e,q=n,n+=l):(b.y+=f,q=p,p+=m)}}}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return floor(rand(a,b))}function randBool(a=.5){return rand()<a}function randSign(){return 2*randInt(2)-1}function randVec2(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){if(0>=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}sign(){return.5<this.float()?1:-1}floatSign(a=1,b=0){const c=min(a,b);a=max(a,b)-c;b=this.float(2*a);return b<a?c+b:a-c-b}angle(){return this.float(-PI,PI)}vec2(a=1,b=0){return vec2(this.float(a,b),this.float(a,b))}direction(a=1){return(new Vector2).setAngle(this.float(2*PI),a)}randColor(a=new Color,b=new Color(0,0,0,1),c=!1){return c?a.lerp(b,this.float()):new Color(this.float(a.r,b.r),this.float(a.g,b.g),this.float(a.b,b.b),this.float(a.a,b.a))}mutateColor(a,b=.05,c=0){return new Color(a.r+this.float(b,-b),a.g+this.float(b,-b),a.b+this.float(b,-b),a.a+this.float(c,-c)).clamp()}}function vec2(a=0,b){return new Vector2(a,b??a)}function isVector2(a){return a instanceof Vector2&&a.isValid()}function ASSERT_VECTOR2_VALID(a){}function ASSERT_NUMBER_VALID(a){}class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}set(a=0,b=0){this.x=a;this.y=b;return this}setFrom(a){return this.set(a.x,a.y)}copy(){return new Vector2(this.x,this.y)}add(a){return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){return new Vector2(this.x*a.x,this.y*a.y)}divide(a){return new Vector2(this.x/a.x,this.y/a.y)}scale(a){return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(0,a)}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}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.x<a.x&&this.y<a.y}toString(a=3){return this.isValid()?`(${(0>this.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&&(2<a||2<b||2<c)&&colorRangeWarn("rgb(255, 0, 0) is rgb(1, 0, 0)");return new Color(a,b,c,d)}let colorRangeWarned=!1;function colorRangeWarn(a){colorRangeWarned||(colorRangeWarned=!0,console.warn("color values are 0 to 1 here, not 0 to 255 or percents: "+a))}function hsl(a,b,c,d){debug&&(2<b||2<c)&&colorRangeWarn("hsl(.5, 100, 50) is hsl(.5, 1, .5)");return(new Color).setHSLA(a,b,c,d)}function isColor(a){return a instanceof Color&&a.isValid()}function ASSERT_COLOR_VALID(a){}class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}set(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d;return this}setFrom(a){return this.set(a.r,a.g,a.b,a.a)}setAlpha(a=1){this.a=a;return this}copy(){return new Color(this.r,this.g,this.b,this.a)}withAlpha(a=1){return new Color(this.r,this.g,this.b,a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){b=clamp(b);return new Color(a.r*b+this.r*(1-b),a.g*b+this.g*(1-b),a.b*b+this.b*(1-b),a.a*b+this.a*(1-b))}setHSLA(a=0,b=0,c=1,d=1){a=mod(a,1);b=clamp(b);c=clamp(c);b=.5>c?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<g?l/(2-e-f):l/(e+f);a===e?h=(b-c)/l+(b<c?6:0):b===e?h=(c-a)/l+2:c===e&&(h=(a-b)/l+4)}return[h/6,k,g,d]}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}toString(a=!0){if(!this.isValid())return"#000";const b=c=>(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}elapsed(){return this.getGlobalTime()>=this.time}get(){return this.isSet()?this.getGlobalTime()-this.time:0}getPercent(){return this.isSet()?0<this.setTime?1-percent(this.time-this.getGlobalTime(),0,this.setTime):1:0}getSetTime(){return this.isSet()?this.setTime:0}getGlobalTime(){return this.useRealTime?timeReal:time}toString(){return this.isSet()?abs(this.get())+" seconds "+(0>this.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*</.test(a);async function loadFetch(a,b){try{return await fetch(a)}catch(c){throw a=Error(`${b}: could not load ${a}, ${c.message}`+("file:"===globalThis.location?.protocol?", the page was opened from a file, serve it from a local web server":"")),a.cause=c,a}}function saveText(a,b="text",c="text/plain"){saveDataURL(URL.createObjectURL(new Blob([a],{type:c})),b,1e3)}function createCanvasContext(a,b=a,c=!1){return("undefined"!=typeof OffscreenCanvas?new OffscreenCanvas(a,b):Object.assign(document.createElement("canvas"),{width:a,height:b})).getContext("2d",{willReadFrequently:c})}function canvasAvailable(){return"undefined"!=typeof OffscreenCanvas||"undefined"!=typeof document&&!!document.createElement}function saveCanvas(a,b="screenshot",c="image/png"){if("undefined"!=typeof OffscreenCanvas&&a instanceof OffscreenCanvas){const d=document.createElement("canvas");d.width=a.width;d.height=a.height;d.getContext("2d").drawImage(a,0,0);saveDataURL(d.toDataURL(c),b)}else saveDataURL(a.toDataURL(c),b)}function saveDataURL(a,b="download",c){const d=document.createElement("a");d.download=b;d.href=a;d.click();void 0!==c&&setTimeout(()=>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;0<a&&(touchGamepadRightStick=!1)}function setTouchGamepadLeftStick(a){(touchGamepadLeftStick=a)&&(touchGamepadLeftButtonCount=0)}function setTouchGamepadLeftButtonCount(a){touchGamepadLeftButtonCount=a;0<a&&(touchGamepadLeftStick=!1)}function setTouchGamepadRightStick(a){(touchGamepadRightStick=a)&&(touchGamepadButtonCount=0)}function setTouchGamepadAnalog(a){touchGamepadAnalog=a}function setTouchGamepadFloating(a){touchGamepadFloating=a}function setTouchGamepadSize(a){touchGamepadSize=a}function setTouchGamepadAlpha(a){touchGamepadAlpha=a}function setTouchGamepadDisplayTime(a){touchGamepadDisplayTime=a}function setTouchGamepadVibration(a){touchGamepadVibration=a}function setVibrateEnable(a){vibrateEnable=a}function setSoundEnable(a){soundEnable=a}function setSoundIgnoreSilentSwitch(a){soundIgnoreSilentSwitch=a;audioSetSession()}function setSoundVolume(a){soundVolume=a;audioUpdateVolume()}function setSoundDefaultRange(a){soundDefaultRange=a}function setSoundDefaultTaper(a){soundDefaultTaper=a}function setSoundPauseWhenHidden(a){soundPauseWhenHidden=a}function setDebugWatermark(a){debugWatermark=a}function setDebugKey(a){debugKey=a}function setDebugKeysAlways(a=!0){debugKeysAlways=a}function setDebugTweakables(a=!0){debugTweakables=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.localPos=this.parent=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){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}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.collideLevel&&this.mass)&&(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){var c=0>this.gravityScale?-gravity.y:gravity.y;a=0>this.velocity.y&&0>c||0<this.velocity.y&&0<c;if(this.groundObject){var d=max(this.friction,this.groundObject.friction),e=this.groundObject.velocity.x;this.velocity.x=e+(this.velocity.x-e)*d;this.groundObject=void 0}if(this.collideSolidObjects&&this.size.x&&this.size.y)for(var f of engineCollideGrid?engineCollideGridWalk(this):engineObjectsCollideStaticLast)if(!f.destroyed&&!f.parent&&f!==this&&f.size.x&&f.size.y&&(this.isSolid||f.isSolid)&&this.isOverlappingObject(f)&&(d=engineObjectsCollidePairAnswer(f,this),!1!==d)){if(!d&&(d=this.collideWithObject(f),e=f.collideWithObject(this),engineCollideGrid?.built&&engineCollideGridPlace(engineCollideGrid.built,f),!d||!e)){engineObjectsCollidePairAdd(this,f);continue}d=isOverlapping(b,this.size,f.pos,f.size);if(!d||f.mass&&!f.groundObject)if(d)d=b.subtract(f.pos),e=d.length(),d=.001>e?vec2(0,.001):d.scale(.001/e),this.velocity=this.velocity.add(d),f.mass&&(f.velocity=f.velocity.subtract(d)),engineObjectsCollidePairAdd(this,f),debugPhysics&&debugOverlap(this.pos,this.size,f.pos,f.size,"#f00",void 0,!1);else{e=this.size.add(f.size);k=2*(0<c?f.pos.y-b.y:b.y-f.pos.y)>e.y-abs(c);var g=2*abs(b.y-f.pos.y)<e.y,h=2*abs(b.x-f.pos.x)<e.x;d=max(this.restitution,f.restitution);if(k||h||!g)if(this.pos.y=f.pos.y+(e.y/2+.001)*sign(b.y-f.pos.y),f.groundObject&&a||!f.mass)a&&(this.groundObject=f),this.velocity.y=f.velocity.y-(this.velocity.y-f.velocity.y)*d;else{h=(this.mass*this.velocity.y+f.mass*f.velocity.y)/(this.mass+f.mass);const l=f.velocity.y*(f.mass-this.mass)/(this.mass+f.mass)+2*this.velocity.y*this.mass/(this.mass+f.mass);this.velocity.y=lerp(h,this.velocity.y*(this.mass-f.mass)/(this.mass+f.mass)+2*f.velocity.y*f.mass/(this.mass+f.mass),d);f.velocity.y=lerp(h,l,d)}!k&&g&&(this.pos.x=f.pos.x+(e.x/2+.001)*sign(b.x-f.pos.x),f.mass?(e=(this.mass*this.velocity.x+f.mass*f.velocity.x)/(this.mass+f.mass),k=f.velocity.x*(f.mass-this.mass)/(this.mass+f.mass)+2*this.velocity.x*this.mass/(this.mass+f.mass),this.velocity.x=lerp(e,this.velocity.x*(this.mass-f.mass)/(this.mass+f.mass)+2*f.velocity.x*f.mass/(this.mass+f.mass),d),f.velocity.x=lerp(e,k,d)):this.velocity.x=f.velocity.x-(this.velocity.x-f.velocity.x)*d);engineObjectsCollidePairAdd(this,f,!0);debugPhysics&&debugOverlap(this.pos,this.size,f.pos,f.size,"#f0f",void 0,!1)}else{if(d=collideBoxBox(this.pos,this.size,f.pos,f.size))if(this.pos.x+=d.x+.001*sign(d.x),this.pos.y+=d.y+.001*sign(d.y),e=max(this.restitution,f.restitution),d.x){var k=this.velocity.x-f.velocity.x;0>k*d.x&&(this.velocity.x=f.velocity.x-k*e)}else k=this.velocity.y-f.velocity.y,0>k*d.y&&(this.velocity.y=f.velocity.y-k*e),0>d.y*c&&(this.groundObject=f);engineObjectsCollidePairAdd(this,f);debugPhysics&&debugOverlap(this.pos,this.size,f.pos,f.size,"#f00",void 0,!1)}}if(this.collideLevel&&(f=tileCollisionTest(this.pos,this.size,this))&&!tileCollisionTest(b,this.size,this)){e=tileCollisionTest(vec2(this.pos.x,b.y),this.size,this);k=tileCollisionTest(vec2(b.x,this.pos.y),this.size,this);d=max(this.restitution,f.restitution);if(e){c=0<c?ceil(b.y+this.size.y/2-1)-this.size.y/2-.001:floor(b.y-this.size.y/2+1)+this.size.y/2+.001;if(.1>abs(c-this.pos.y)&&!tileCollisionTest(vec2(this.pos.x,c),this.size,this)){this.pos.y=c;debugPhysics&&debugRect(this.pos,this.size,"#ff0",0,0,!1,!1);return}g=f.pos.x;h=this.size.x/2+1e-4;c=this.pos.x<b.x;g+=c?floor(b.x-g-this.size.x/2)+h:ceil(b.x-g+this.size.x/2)-h;c=c?min(g,b.x):max(g,b.x);this.pos.x=tileCollisionTest(vec2(c,b.y),this.size,this)?b.x:c;this.velocity.x*=-d}if(k||!e)c=this.size.y/2+1e-4,e=f.pos.y,c=e+(this.pos.y<b.y?floor(b.y-e-this.size.y/2)+c:ceil(b.y-e+this.size.y/2)-c),e=this.pos.y!==b.y&&!tileCollisionTest(vec2(this.pos.x,c),this.size,this),this.pos.y=e?c:b.y,this.groundObject=a?f:void 0,this.velocity.y*=-d;debugPhysics&&debugRect(this.pos,this.size,"#f00",0,0,!1,!1)}}}}update(){}render(){drawTile(this.pos,this.drawSize||this.size,this.tileInfo,this.color,this.angle,this.mirror,this.additiveColor,glEnable,!1)}renderLight(){}renderShadow(){this.render()}renderEmissive(){this.render()}destroy(a=!1){if(!this.destroyed){this.destroyed=!0;this.parent?.removeChild(this);for(const b of this.children)b.parent=void 0,b.destroy(a)}}localToWorld(a){return this.pos.add(a.rotate(this.angle))}worldToLocal(a){return a.subtract(this.pos).rotate(-this.angle)}localToWorldVector(a){return a.rotate(this.angle)}worldToLocalVector(a){return a.rotate(-this.angle)}collideWithTile(a,b){return 0<a}collideWithObject(a,b){return!0}getUp(a=1){return vec2().setAngle(this.angle,a)}getRight(a=1){return vec2().setAngle(this.angle+PI/2,a)}getAliveTime(){return time-this.spawnTime}getSpeed(){return this.velocity.length()}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyAngularAcceleration(a){this.mass&&(this.angleVelocity+=a)}applyForce(a){this.mass&&this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){if(this.destroyed)return a;for(let d=this;d;d=d.parent);this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c;a.updateTransforms();return a}attach(a){a.parent?.removeChild(a);const b=this.getMirrorSign(),c=this.worldToLocal(a.pos);c.x*=b;return this.addChild(a,c,b*(a.angle-this.angle))}removeChild(a){const b=this.children.indexOf(a);0>b||(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<a?b:c-b}get tileInfo(){return this.firstTile.frame(this.frame)}get isDone(){const a="once"==this.mode&&void 0===this.heldFrame&&abs(this.elapsedFrames)>=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<a.length;++m){const n=a[m];l.lineTo(n.x,n.y)}d&&l.closePath();l.stroke()}},h,k)}function drawLine(a,b,c=.1,d=WHITE,e=vec2(),f=0,g=glEnable,h=drawScreenSpace,k){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());a=a.add(b);e=e.add(f?a.rotate(h?-f:f):a);h&&(b.y*=-1);f+=b.angle();drawRect(e,c,d,f,g,h,k)}function drawRegularPoly(a,b=vec2(1),c=3,d=WHITE,e=0,f=BLACK,g=0,h=glEnable,k=drawScreenSpace,l){const m=drawRegularPolyPoints,n=drawRegularPolyPool;m.length=0;const r=b.x/2;b=b.y/2;for(let q=c;0<q--;){const p=q/c*PI*2;let t,u;const v=(t=n)[u=m.length]||(t[u]=vec2());v.x=sin(p)*r;v.y=cos(p)*b;m.push(v)}drawPoly(m,d,e,f,a,g,h,k,l)}const drawRegularPolyPoints=[],drawRegularPolyPool=[];function drawPoly(a,b=WHITE,c=0,d=BLACK,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}glDrawPointsTransform(a,b.rgbaInt(),e.x,e.y,g,k,f);0<c&&glDrawOutlineTransform(a,d.rgbaInt(),c,e.x,e.y,g,k,f)}else++drawCount,++primitiveCount,drawCanvas2D(e,vec2(1),f,!1,l=>{l.fillStyle=b.toString();l.beginPath();for(const m of a)l.lineTo(m.x,m.y);l.closePath();l.fill();0<c&&(l.strokeStyle=d.toString(),l.lineWidth=c,l.stroke())},h,k)}const drawEllipseRings=new Map;function drawEllipse(a,b=vec2(1),c=WHITE,d=0,e=0,f=BLACK,g=glEnable,h=drawScreenSpace,k){if(!headlessMode||k)if(e=clamp(e,0,min(abs(b.x),abs(b.y))),g&&glEnable){const l=glCircleSides;if(0<e)drawRegularPoly(a,b,l,c,e,f,d,g,h,k);else{g=drawEllipseRings.get(l);if(!g){g=[];for(k=l;0<k--;){const m=k/l*PI*2;g.push(vec2(sin(m),cos(m)))}drawEllipseRings.set(l,g=glPolyStrip(g))}if(h){if(glSkipScreenSpace)return;[a,b,d]=screenToWorldTransform(a,b,d)}glDrawPointsTransform(g,c.rgbaInt(),a.x,a.y,b.x/2,b.y/2,d,!1)}}else++drawCount,++primitiveCount,drawCanvas2D(a,vec2(1),d,!1,l=>{l.fillStyle=c.toString();l.beginPath();l.ellipse(0,0,abs(b.x)/2,abs(b.y)/2,0,0,9);l.fill();0<e&&(l.strokeStyle=f.toString(),l.lineWidth=e,l.stroke())},h,k)}function drawCircle(a,b=1,c=WHITE,d=0,e=BLACK,f=glEnable,g=drawScreenSpace,h){drawEllipse(a,vec2(b),c,0,d,e,f,g,h)}let drawEllipseGradientOffset=0;function drawEllipseGradient(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=glCircleSides;const k=b.x/2,l=b.y/2;b=c.rgbaInt();g=d.rgbaInt();h=drawEllipseGradientOffset++;const m=cos(-e),n=sin(-e);e=p=>{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<p--;){const t=(p+h)%f/f*PI*2;r.push(a);q.push(b);r.push(e(t));q.push(g)}glDrawColoredPoints(r,q)}else++drawCount,++primitiveCount,drawCanvas2D(a,b,e,!1,k=>{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<g&&0<h&&0<k&&0<l))return cameraScale;b=cos(cameraAngle);c=sin(cameraAngle);const m=abs(b)*g+abs(c)*h;g=abs(c)*g+abs(b)*h;cameraScale=min(k/m,l/g);f=vec2(f.right-f.left,f.top-f.bottom).scale(.5);g=.5*(d.right-d.left)/cameraScale;d=.5*(d.top-d.bottom)/cameraScale;d=vec2(g*b+d*c,d*b-g*c);cameraPos=a.add(f).add(d);return cameraScale}function isOnScreen(a,b=0){if(!cameraScale)return!1;let c=a.x-cameraPos.x;a=a.y-cameraPos.y;if(cameraAngle){var d=cos(cameraAngle),e=sin(cameraAngle);const f=c*e+a*d;c=c*d-a*e;a=f}c*=2*cameraScale;a*=2*-cameraScale;b instanceof Vector2&&(b=b.length());b*=cameraScale;d=mainCanvasSize.x;e=mainCanvasSize.y;return c+b>-d&&c-b<d&&a+b>-e&&a-b<e}function setAdditiveBlendMode(a=!0){glAdditive=a;drawContext&&(drawContext.globalCompositeOperation=a?"lighter":"source-over")}function setShader(a){glCustomShader=a||void 0}function setBackgroundCanvas(a){backgroundCanvas=a}function combineCanvases(){const a=mainCanvas.width,b=mainCanvas.height;workCanvas.width=a;workCanvas.height=b;workContext.fillStyle="#000";workContext.fillRect(0,0,a,b);backgroundCanvas&&workContext.drawImage(backgroundCanvas,0,0,a,b);glCopyToContext(workContext);workContext.drawImage(mainCanvas,0,0);mainContext.save();mainContext.setTransform(1,0,0,1,0,0);mainContext.drawImage(workCanvas,0,0);mainContext.restore()}function tintImageData(a,b,c){if(c&&!isBlack(c)){b=[clamp(b.r),clamp(b.g),clamp(b.b),clamp(b.a)];c=[255*c.r,255*c.g,255*c.b,255*c.a];for(let d=0;d<a.length;++d)a[d]=a[d]*b[d&3]+c[d&3]|0;return!0}for(c=0;c<a.length;c+=4)a[c]*=clamp(b.r),a[c+1]*=clamp(b.g),a[c+2]*=clamp(b.b);return!1}function bakeTintedImage(a,b,c,d=workReadContext){const e=a.width|0,f=a.height|0;d.canvas.width=e;d.canvas.height=f;d.drawImage(a,0,0);a=d.getImageData(0,0,e,f);tintImageData(a.data,b,c);d.putImageData(a,0,0);return d.canvas}const drawTextureWrappedBakes=new WeakMap;function drawImageColor(a,b,c,d,e,f,g,h,k,l,m,n,r=0){e=max(1,e|0);f=max(1,f|0);const q=e-2*r,p=f-2*r;!canvasColorTiles||isWhite(m)&&(!n||isBlack(n))?(a.globalAlpha=m.a,a.drawImage(b,c+r,d+r,q,p,g,h,k,l),a.globalAlpha=1):(workReadCanvas.width!==e||workReadCanvas.height!==f?(workReadCanvas.width=e,workReadCanvas.height=f):workReadContext.clearRect(0,0,e,f),workReadContext.drawImage(b,c|0,d|0,e,f,0,0,e,f),b=workReadContext.getImageData(0,0,e,f),n=tintImageData(b.data,m,n),workReadContext.putImageData(b,0,0),n||(a.globalAlpha=m.a),a.drawImage(workReadCanvas,r,r,q,p,g,h,k,l),n||(a.globalAlpha=1))}function isFullscreen(){return!!document.fullscreenElement}function toggleFullscreen(){const a=mainCanvas.parentElement;isFullscreen()?document.exitFullscreen&&document.exitFullscreen()?.catch?.(()=>{}):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<t?95:t-32,l.pos);k.x=ceil(b.x+p*h.x-q-h.x/2)+h.x/2-.5;k.y=ceil(b.y+r*h.y-m-h.y/2)+h.y/2-.5;drawTile(k,h,l,e,0,!1,void 0,f,!0,g)}})}getGlyphPos(a,b=new Vector2){const c=this.tileInfo,d=c.padding,e=c.size.x+2*d,f=c.size.y+2*d;if(c.columns)return b.set(c.pos.x+a%c.columns*e,c.pos.y+(a/c.columns|0)*f);const g=c.textureInfo.size.x/e|0;a=((c.pos.y-d)/f|0)*g+((c.pos.x-d)/e|0)+a;return b.set(a%g*e+d,(a/g|0)*f+d)}}function engineGlowAlpha(a,b){b*=3.5;const c=Math.exp(-b);return(Math.exp(-b*a*a)-c)/(1-c)}const engineGlowTextures=new Map;function engineGlowTexture(a=1){a=max(round(10*a),1)/10;var b=engineGlowTextures.get(a);if(b||!glContext||!canvasAvailable())return b;b=createCanvasContext(64);const c=b.createRadialGradient(32,32,0,32,32,32);for(let d=0;16>=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<a.axes.length;++b)if(.5<abs(a.axes[b]))return!0}return!1}function inputClearKeyboard(){const a=inputData[0];for(const b in a)isNaN(+b)&&(a[b]=0);inputKeysHeld.clear()}function inputClear(){for(let a=inputData.length;a--;)if(!a||inputData[a])inputData[a]=[];inputKeysHeld.clear();inputWasTouching=0;inputPinch=void 0;touchGamepadPointerRole.clear();touchGamepadButtons.length=0;touchGamepadButtonsPressed.length=0;touchGamepadSticks.length=0;touchGamepadStickPointerId.length=0;gamepadStickData.length=0;gamepadDpadData.length=0}function keyIsDown(a,b=0){return!!(inputData[b]?.[a]&1)&&!inputCaptureHides(b)}function keyWasPressed(a,b=0){return!!(inputData[b]?.[a]&2)&&!inputCaptureHides(b)}function keyWasReleased(a,b=0){return!!(inputData[b]?.[a]&4)&&!inputCaptureHides(b)}function keyDirection(a="ArrowUp",b="ArrowDown",c="ArrowLeft",d="ArrowRight"){return vec2((keyIsDown(d)?1:0)-(keyIsDown(c)?1:0),(keyIsDown(a)?1:0)-(keyIsDown(b)?1:0))}function mouseIsDown(a){return keyIsDown(a)}function mouseWasPressed(a){return keyWasPressed(a)}function mouseWasReleased(a){return keyWasReleased(a)}function gamepadIsDown(a,b=gamepadPrimary){return keyIsDown(a,b+1)}function gamepadWasPressed(a,b=gamepadPrimary){return keyWasPressed(a,b+1)}function gamepadWasReleased(a,b=gamepadPrimary){return keyWasReleased(a,b+1)}function gamepadStick(a,b=gamepadPrimary){return gamepadStickData[b]?.[a]??vec2()}function gamepadDpad(a=gamepadPrimary){return gamepadDpadData[a]?.copy()??vec2()}function gamepadConnected(a=gamepadPrimary){return!!inputData[a+1]}function gamepadStickCount(a=gamepadPrimary){return gamepadStickData[a]?.length??0}function gamepadVibrate(a=gamepadPrimary,b=200,c=1,d=1,e=0){vibrateEnable&&!headlessMode&&inputGetGamepads()[a]?.vibrationActuator?.playEffect?.("dual-rumble",{duration:b,strongMagnitude:c,weakMagnitude:d,startDelay:e})?.catch?.(()=>{})}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){if(touchInputEnable){inputLastTouchTime=performance.now();soundEnable&&!headlessMode&&audioContext&&!audioIsRunning()&&audioResume();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=1<l&&touchPinchWheel;if(1<l){const[t,u]=k;k=t.identifier+" "+u.identifier;const v=hypot(t.clientX-u.clientX,t.clientY-u.clientY);if(inputPinch&&inputPinch.key===k){const y=(inputPinch.distance-v)/50;touchPinch+=y;touchPinchWheel&&(mouseWheel+=y)}inputPinch={key:k,distance:v};p&&(q=vec2((t.clientX+u.clientX)/2,(t.clientY+u.clientY)/2))}else inputPinch=void 0;k=mousePosScreen;mousePosScreen=f(q);p?inputData[0][0]&1&&(inputData[0][0]=inputData[0][0]&2|4):inputWasTouching&&r.identifier===inputTouchIdentifier?mouseDeltaScreen=mouseDeltaScreen.add(mousePosScreen.subtract(k)):n&&e(n.clientX,n.clientY)&&(inputData[0][0]=3|inputData[0][0]&4);inputTouchIdentifier=p?void 0:r.identifier}else inputPinch=void 0,inputWasTouching&&inputData[0][0]&1&&(inputData[0][0]=inputData[0][0]&2|4);inputWasTouching=l}inputPreventDefault&&h.cancelable&&document.hasFocus()&&!a(h)&&(l=document.activeElement,"touchstart"==h.type&&b(l)&&!l.contains(h.target)&&l.blur(),h.preventDefault());return!0}inputWasTouching&&inputData[0][0]&1&&(inputData[0][0]=inputData[0][0]&2|4);inputWasTouching=0}document.addEventListener("touchstart",h=>g(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){inputPreventDefault&&!b(g.target)&&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=>.3<n?percent(n,.3,.8):-.3>n?-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(.3<f.lengthSquared()){var g=clamp(round(f.x),-1,1);f=clamp(round(f.y),-1,1);b[e]=vec2(g,-f).clampLength();e||c.set(g,-f)}}a=inputData[1]??(inputData[1]=[]);for(b=12;b--;)c=gamepadIsDown(b,0),d=touchGamepadButtons[b],e=touchGamepadButtonsPressed[b]||d&&!c,a[b]=d?e?3:1:e?6:c?4:0,touchGamepadVibration&&a[b]&2&&(9===b||touchGamepadIsFaceButton(b))&&vibrate(touchGamepadVibration);touchGamepadButtonsPressed.length=0;gamepadButtonsLast[0]=void 0}else{if(gamepadsEnable&&!debug&&!document.hasFocus())return void(gamepadButtonsLast.length=0);b=gamepadsEnable?inputGetGamepads():[];for(c=0;8>c;++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<l.axes.length-1;k+=2)g[k>>1]=a(vec2(h(k),h(k+1)));h=g.some(r=>.25<r.lengthSquared());for(k=l.buttons.length;k--;){const r=l.buttons[k],q=e[k];e[k]=r.pressed;d[k]=r.pressed?q?1:3:q?4:0;r.pressed&&(!r.value||.9<r.value)&&(h=!0)}d.length=e.length=l.buttons.length;g.length=l.axes.length>>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<gamepadStick(c).lengthSquared();for(c=17;c--&&!b;)b=gamepadIsDown(c);c=!1;for(const d in inputData[0])if(isNaN(+d)&&inputData[0][d]&1){c=!0;break}b?lastInputDevice="gamepad":a?lastInputDevice="mouse":c&&(lastInputDevice="keyboard");isUsingGamepad="gamepad"===lastInputDevice}())}function inputUpdatePost(){if(!headlessMode){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=touchPinch=0;mouseDelta=vec2();mouseDeltaScreen=vec2()}}function inputRender(){touchGamepadRender()}const touchGamepadSvgNS="http://www.w3.org/2000/svg";function touchGamepadInit(){if(!touchGamepadOverlay&&touchGamepadEnable&&isTouchDevice&&!headlessMode&&document.body){var a=touchGamepadOverlay=document.createElement("div");a.style.cssText="position:fixed;inset:0;z-index:50;pointer-events:none;opacity:0;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;transition:opacity .2s;box-sizing:border-box;padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)";var b=touchGamepadStage=document.createElement("div");b.style.cssText="position:relative;width:100%;height:100%;pointer-events:none";a.appendChild(b);var c=touchGamepadSvg=document.createElementNS(touchGamepadSvgNS,"svg");c.style.cssText="position:absolute;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible;fill:none;stroke:#fff;stroke-width:3";b.appendChild(c);c=()=>{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)||0<touchGamepadSideButtonCount(a)}function touchGamepadIsFaceButton(a){for(let b=0;2>b;b++){const c=touchGamepadSideButtonBase(b);if(!touchGamepadSideStick(b)&&a>=c&&a<c+touchGamepadSideButtonCount(b))return!0}return!1}function touchGamepadSideCenter(a,b,c){if(touchGamepadFloating&&touchGamepadSideStick(a)&&touchGamepadStickAnchors[a])return touchGamepadStickAnchors[a];c-=touchGamepadSize;const d=touchGamepadSideButtonCount(a);touchGamepadSideStick(a)||2!==d&&3!==d||(c-=touchGamepadSize/4);return vec2(a?b-touchGamepadSize:touchGamepadSize,c)}function touchGamepadRelayout(){if(touchGamepadOverlay){var a=touchGamepadStageRect(),b=a.width;a=a.height;var c=touchGamepadSize,d=(f,g)=>f.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<l;r++){var h=mod(r-1,4);let q=2<l?h:min(h,l-1);q=touchGamepadFaceIndex(q);h=vec2().setDirection(h,e/2);2===l&&(h.x*=-1);k||(h.x*=-1);h=n.add(h);d.face[m+q]=f(h.x,h.y,e/4,"#000")}}debug&&debugGamepads&&touchGamepadBuildDebug(a,b)}function touchGamepadBuildDebug(a,b){const c=touchGamepadSize,d=touchGamepadSvg,e=(h,k,l)=>{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()&&0<b&&!paused;touchGamepadOverlay.style.opacity=c?a?1:b*touchGamepadAlpha:0;if(c){b=touchGamepadStageRect();a=b.width;c=b.height;var d=touchGamepadSize;if(b=touchGamepadSvgEls){for(let e=0;2>e;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<b.face.length;a++)b.face[a]&&b.face[a].setAttribute("fill",touchGamepadButtons[a]?"#fff":"#000")}}}else"none"!==touchGamepadOverlay.style.display&&(touchGamepadOverlay.style.display="none",touchGamepadPointerRole.clear(),touchGamepadButtons.length=0,touchGamepadButtonsPressed.length=0,touchGamepadSticks.length=0,touchGamepadStickPointerId.length=0,inputData[1]=void 0,gamepadStickData[0]=gamepadDpadData[0]=void 0)}function touchGamepadEventPos(a){const b=touchGamepadStageRect();return vec2(a.clientX-b.left,a.clientY-b.top)}function touchGamepadApplyStick(a,b){b=b.subtract(touchGamepadStickAnchors[a]);touchGamepadSticks[a]=b.scale(2/touchGamepadSize).clampLength();touchGamepadButtons[touchGamepadStickButton(a)]=1}function touchGamepadFaceButtonAt(a,b,c,d){const e=touchGamepadSideButtonCount(a),f=touchGamepadSideButtonBase(a);c=touchGamepadSideCenter(a,c,d);if(c.distance(b)>=touchGamepadSize)return-1;if(1===e)return f;b=c.subtract(b);a||(b.x*=-1);a=2===e?b.x<b.y?1:0:mod(b.direction()+2,4);a=touchGamepadFaceIndex(a);return a<e?f+a:-1}function touchGamepadControlAt(a,b,c){const d=touchGamepadSize,e=a.x<b/2,f=.4*c;if(touchGamepadCenterButtonSize&&vec2(b/2,c/2).distance(a)<touchGamepadCenterButtonSize&&!touchGamepadStartBlockedAt(a,b,c))return{role:"start"};for(let h=0;2>h;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<a.numberOfChannels;c++)b.push(a.getChannelData(c).slice());this._sampleChannels=b}return this._sampleChannels}set sampleChannels(a){this._sampleChannels=a;this.sampleBuffer=void 0;this.sampleLength=a?.[0]?.length||0}buildSampleBuffer(){this.sampleBuffer||!this._sampleChannels||headlessMode||(this.sampleBuffer=createAudioBuffer(this._sampleChannels,this.sampleRate),this._sampleChannels=void 0)}play(a,b=1,c=1,d=1,e=!1,f=!1){if(soundEnable&&!headlessMode&&(this.sampleBuffer||this._sampleChannels)){var g;if(a){if(g=this.range){var h=cameraPos.distanceSquared(a);if(h>=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(0<z?z:0);J<z;G[J++]=M*a)++E%(100*t|0)||(M=g?1<g?2<g?3<g?4<g?H/A%1<h/2?1:-1:sin(H**3):max(min(tan(H),1),-1):1-(2*H/A%2+2)%2:1-4*abs(round(H/A)-H/A):sin(H),M=(r?1-x+x*sin(A*J/r):1)*(4<g?M:sign(M)*abs(M)**h)*(J<d?J/d:J<d+y?1-(J-d)/y*(1-v):J<d+y+e?v:J<z-u?(z-J-u)/f*v:0),M=u?M/2+(u>J?0:(J<z-u?1:(z-J)/u)*G[J-u|0]/2/(a||1)):M,w&&(M=S=P*O+K*(O=Q)+P*(Q=M)-N*R-I*(R=S))),L=(c+=k+=l)*cos(p*D++),H+=L+L*q*(J*J*A%2-1),F&&++F>n&&(c+=m,b+=m,F=0),!r||++B%r||(c=b,k=C,F||=1);return G}const tileCollisionLayers=[];function tileCollisionAssertWhole(a){}function tileCollisionTester(a){return a?"function"===typeof a?(b,c)=>a(b,c):(b,c)=>a.collideWithTile(b,c):b=>0<b}function tileCollisionGetData(a,b=!0){let c=0;for(const e of tileCollisionLayers)if(!b||e.isSolid){var d=a.x-e.pos.x;const f=a.y-e.pos.y,g=e.size;if(0<=d&&0<=f&&d<g.x&&f<g.y){d=e.collisionData[(f|0)*g.x+(d|0)];if(0<d)return d;d&&!c&&(c=d)}}return c}function tileCollisionTest(a,b=vec2(),c,d=!0){for(const e of tileCollisionLayers)if((!d||e.isSolid)&&e.collisionTest(a,b,c))return e}function tileCollisionRaycast(a,b,c,d,e=!0){let f,g,h;const k=d&&vec2();for(const l of tileCollisionLayers)if(!e||l.isSolid){const m=l.collisionRaycast(a,b,c,k);if(m){const n=a.distanceSquared(m);if(void 0===f||n<g)f=m,g=n,d&&(h=k.copy())}}f&&d&&d.setFrom(h);return f}const tileLayersTiledFlips=[[0,0],[3,1],[2,1],[3,0],[0,1],[1,0],[2,0],[1,1]];function tileLayerTileInfo(a,b){if(a){if(a.tiles)return a.tiles[b];if(!a.columns)return a.index(b);if(!(a.textureInfo&&a.pos.y+(b/a.columns|0)*(a.size.y+2*a.padding)+a.size.y>a.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<f&&0<g))throw Error(`tileLayersLoad: a map is a whole number of cells across and down, not ${f} by ${g}`);if(!isArray(a.layers)||!a.layers.length)throw Error("tileLayersLoad: a map has a list of layers");var h=a.tilesets?.[0];if(b&&!b.tiles&&h&&(0<h.margin||0<h.spacing)){var k=h.margin||0,l=h.spacing||0,m=b.size,n=b.textureInfo?.size.x||0;h=h.columns||max(1,floor((n-2*k+l)/(m.x+l)));n=b.pos.subtract(vec2(b.padding));b=new TileInfo(n.add(vec2(k)),m,b.textureInfo,l/2,b.bleed,h)}const r=[],q=(t,u,v)=>{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<l.x;++y)for(let x=0;x<l.y;++x){const w=vec2(y,l.y-1-x);var p=t.data[y+x*l.x];if(p){const[z,A]=tileLayersTiledFlips[p>>>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&&0<k&&4194304>=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)=>z<x.length&&(x[z]=w));l.layers.push({id:t,name:n,type:"tilelayer",width:h,height:k,data:x,opacity:r,visible:!1,x:0,y:0})}var q=[...m.autoLayerTiles||[],...m.gridTiles||[]].filter(x=>isArray(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<h&&0<=w&&w<k&&(p(y[z]++,round(1e3*clamp(x.a??1))/1e3)[z]=(x.t+1|(x.f&1?2147483648:0)|(x.f&2?1073741824:0))>>>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);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();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){this.context&&(this.redrawStart(),this.drawTileData(a,b),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}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(;h<e;++h)for(var l=d;l<g;++l){if(!(0<this.collisionData[h*a.x+l]))continue;let m=l+1;for(;m<g&&0<this.collisionData[h*a.x+m];)++m;const n=m-l,r=new TileInfo(vec2(l*c.x,f-(h+1)*c.y),vec2(n*c.x,c.y),this.textureInfo,0,0);l=vec2(this.pos.x+(l+n/2)*b.x,this.pos.y+(h+.5)*b.y);drawTile(l,vec2(n*b.x,b.y),r,this.color,0,!1,void 0,k,!1);l=m}}destroy(a=!1){if(!this.destroyed){var b=tileCollisionLayers.indexOf(this);0<=b&&tileCollisionLayers.splice(b,1);super.destroy(a)}}initCollision(a){this.size=a.floor();this.collisionData=Array(this.size.area()).fill(0)}setCollisionData(a,b=1){const c=(a.y|0)*this.size.x+(a.x|0);a.arrayCheck(this.size)&&(this.collisionData[c]=b)}clearCollisionData(a){this.setCollisionData(a,0)}getCollisionData(a){const b=(a.y|0)*this.size.x+(a.x|0);return a.arrayCheck(this.size)?this.collisionData[b]:0}collisionTest(a,b=new Vector2,c){tileCollisionAssertWhole(this);c=tileCollisionTester(c);var d=a.x-this.pos.x,e=a.y-this.pos.y;if(0>d+b.x/2||d-b.x/2>this.size.x||0>e+b.y/2||e-b.y/2>this.size.y)return!1;a=max(d-b.x/2|0,0);var f=max(e-b.y/2|0,0);d=min(b.x?d+b.x/2:a+1,this.size.x);for(b=min(b.y?e+b.y/2:f+1,this.size.y);f<b;++f)for(e=a;e<d;++e){const g=this.collisionData[f*this.size.x+e];if(g&&c(g,vec2(e+this.pos.x,f+this.pos.y)))return!0}return!1}collisionRaycast(a,b,c,d){tileCollisionAssertWhole(this);const e=tileCollisionTester(c),f=this.pos;c=a.subtract(f);var g=b.subtract(a),h=0;let k=1;for(const[l,m,n]of[[c.x,g.x,this.size.x+1],[c.y,g.y,this.size.y+1]]){if(!m){if(-1>l||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&&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)=>l<m?m:l<m+1?l:m+1-max(1e-9,1e-15*abs(m)),c.x=h(c.x,g.x+f.x),c.y=h(c.y,g.y+f.y);debugRaycast&&c&&(g=c.floor().add(vec2(.5)),debugRect(g,vec2(1),"#f008",0,0,!1,!1),debugLine(a,b,"#00f",.02,0,!1),debugLine(a,c,"#f00",.02,0,!1),debugPoint(c,"#0f0",void 0,void 0,!1),d&&debugLine(c,c.add(d),"#ff0",.02,0,!1));return c}}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=WHITE,k=WHITE,l=CLEAR_WHITE,m=CLEAR_WHITE,n=.5,r=.1,q=1,p=.1,t=.05,u=1,v=1,y=0,x=PI,w=.1,z=.2,A=!1,C=!1,D=!0,B=C?1e9:0,E=!1){super(a,vec2(),g,b,void 0,B);if(debug){a={emitTime:d,emitRate:e,emitConeAngle:f,particleTime:n,sizeStart:r,sizeEnd:q,speed:p,angleSpeed:t,damping:u,angleDamping:v,gravityScale:y,particleConeAngle:x,fadeRate:w,randomness:z};for(var F in a);F={colorStartA:h,colorStartB:k,colorEndA:l,colorEndB:m};for(const G in F);}this.emitCircle="number"===typeof c;this.emitSize="number"===typeof c?vec2(c):c.copy();this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h.copy();this.colorStartB=k.copy();this.colorEndA=l.copy();this.colorEndB=m.copy();this.randomColorLinear=D;this.particleTime=n;this.sizeStart=r;this.sizeEnd=q;this.speed=p;this.angleSpeed=t;this.damping=u;this.angleDamping=v;this.gravityScale=y;this.particleConeAngle=x;this.fadeRate=w;this.randomness=z;this.collideLevel=A;this.additive=C;this.localSpace=E;this.trailScale=0;this.scale=1;this.gravity=0;this.particleUpdateCallback=this.particleCollideCallback=this.particleDestroyCallback=this.particleCreateCallback=void 0;this.velocityInheritance=0;this.emitTimeBuffer=1;this.emitElapsed=0;this.particles=[];this.previousPos=void 0;this.previousAngle=this.angle;this.emitFrom=vec2();this.emitBehind=0}update(){this.previousPos||(this.previousPos=this.pos.copy(),this.previousAngle=this.angle);if(this.velocityInheritance){var a=this.velocityInheritance;this.velocity.x=a*(this.pos.x-this.previousPos.x);this.velocity.y=a*(this.pos.y-this.previousPos.y);this.angleVelocity=a*(this.angle-this.previousAngle)}this.previousAngle=this.angle;this.emitFrom.x=this.previousPos.x;this.emitFrom.y=this.previousPos.y;this.previousPos.x=this.pos.x;this.previousPos.y=this.pos.y;if(this.isActive()){a=this.emitRate*particleEmitRateScale;var b=this.emitTime?min(timeDelta,this.emitTime-this.emitElapsed):timeDelta;this.emitElapsed+=timeDelta;if(0<a&&Infinity>a){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);a=this.particles;b=0;for(c=0;c<a.length;++c){const d=a[c];d.update();d.destroyed||(a[b++]=d)}a.length=b;debugParticles&&(this.emitCircle?debugCircle(this.pos,this.emitSize.x*this.scale,"#0f0",0,!1,!1):debugRect(this.pos,this.emitSize.scale(this.scale),"#0f0",0,this.angle,!1,!1))}emitParticle(){var a=this.scale,b=this.emitCircle?randInCircle(this.emitSize.x/2*a):vec2(rand(-.5,.5)*this.emitSize.x*a,rand(-.5,.5)*this.emitSize.y*a);let c=rand(this.particleConeAngle,-this.particleConeAngle);if(!this.localSpace){this.emitCircle||(b=b.rotate(this.angle));var d=this.emitBehind;b.x+=this.pos.x+(this.emitFrom.x-this.pos.x)*d;b.y+=this.pos.y+(this.emitFrom.y-this.pos.y)*d;c+=this.angle}const e=this.randomness;var f=n=>n+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.velocityInheritance&&(k.x+=this.velocity.x,k.y+=this.velocity.y,l+=this.angleVelocity);b=new Particle(this,b,c,a,f,d,g,h,k,l);this.particles.push(b);this.particleCreateCallback?.(b);return b}updatePhysics(){}render(){this.additive&&setAdditiveBlendMode();particleTile=null;particleTileBatch=!0;for(const a of this.particles)a.render();particleTileBatch=!1;this.additive&&setAdditiveBlendMode(!1)}isActive(){return!this.emitTime||this.emitElapsed<this.emitTime}destroy(a=!1){this.destroyed||(super.destroy(a),!a&&0<this.particles.length&&(this.destroyed=!1,this.emitTime=-1))}}const particleDrawPos=new Vector2,particleDrawSize=new Vector2,particleCollidePos=new Vector2;let particleTile,particleTileBatch=!1,particleTileTextured=!1,particleTileEmpty=!1,particleTileU0=0,particleTileV0=0,particleTileU1=0,particleTileV1=0;function particleTileSet(a){particleTile=a;var b=a?.textureInfo;particleTileTextured=!!b;particleTileEmpty=!!b&&!(a.size.x&&a.size.y);if(b&&!particleTileEmpty){glSetTexture(b.glTexture);var c=b.sizeInverse,d=a.bleed;b=a.pos.x*c.x;var e=a.pos.y*c.y,f=a.size.x*c.x;a=a.size.y*c.y;if(d){const g=c.x*d;c=c.y*d;particleTileU0=b+g;particleTileV0=e+c;particleTileU1=b-g+f;particleTileV1=e-c+a}else particleTileU0=b,particleTileV0=e,particleTileU1=b+f,particleTileV1=e+a}}function particleCollideTest(a,b,c,d){const e=tileCollisionGetData(particleCollidePos.set(c,d));return b?!!e&&!!b(a,e,vec2(c,d)):0<e}class Particle{constructor(a,b,c,d,e,f,g,h,k=vec2(),l=0){this.emitter=a;this.scale=a.scale??1;this.pos=b;this.angle=c;this.size=vec2(g);this.color=d.copy();this.colorStart=d;this.colorEnd=e;this.lifeTime=f;this.sizeStart=g;this.sizeEnd=h;this.velocity=k;this.angleVelocity=l;this.spawnTime=time;this.mirror=randBool();this.groundObject=void 0;this.destroyed=!1;this.tileInfo=a.tileInfo}update(){if(!this.destroyed){var a=this.emitter,b=a.damping,c=a.angleDamping,d=a.restitution,e=a.friction,f=a.gravityScale,g=a.collideLevel,h=a.particleCollideCallback,k=a.particleUpdateCallback;if(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;if(particleCollideTest(this,h,this.pos.x,this.pos.y)&&(c=tileCollisionTest(this.pos),!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||0<this.velocity.y&&0<m)this.groundObject=c;this.pos.y=g;this.velocity.y*=-d;this.velocity.x*=e}debugPhysics&&debugRect(this.pos,this.size,"#f00",0,0,!1,!1)}this.destroyed||k?.(this)}else k?.(this)}}}destroy(){if(!this.destroyed){var a=this.emitter.particleDestroyCallback,b=this.colorEnd;this.color.set(b.r,b.g,b.b,b.a);this.size.set(this.sizeEnd,this.sizeEnd);this.destroyed=!0;a?.(this)}}render(){var a=this.emitter,b=a.localSpace;const c=a.additive&&!glAdditive;var d=a.trailScale,e=a.fadeRate/2,f=0<this.lifeTime?min((time-this.spawnTime)/this.lifeTime,1):1,g=1-f,h=g*this.sizeStart+f*this.sizeEnd;this.size.set(h,h);h=particleDrawSize.set(h,h);this.color.r=g*this.colorStart.r+f*this.colorEnd.r;this.color.g=g*this.colorStart.g+f*this.colorEnd.g;this.color.b=g*this.colorStart.b+f*this.colorEnd.b;this.color.a=(g*this.colorStart.a+f*this.colorEnd.a)*(f<e?f/e:f>1-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){const b=glShaderObjects.indexOf(a);0>b||glShaderObjects.splice(b,1);if(glContext&&!headlessMode){glBatchShader===a&&glFlush();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;q<m;++q){var r=a[q];let p,t;const u=(p=l)[t=q]||(p[t]=vec2()),v=r.x*e;r=r.y*f;u.x=c+g*v-n*r;u.y=d+n*v+g*r;k[q]=u}a=h?glPolyStrip(k):k;glDrawPoints(a,b)}function glDrawOutlineTransform(a,b,c,d,e,f,g,h,k=!0){a=glMakeOutline(a,c,k);glDrawPointsTransform(a,b,d,e,f,g,h,!1)}function glDrawPoints(a,b){glDrawPolyStrip(a,b)}function glDrawColoredPoints(a,b){glDrawPolyStrip(a,0,b)}function glDrawPolyStrip(a,b,c){if(glEnable&&!(3>a.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;n<f;n++){var g=a[c?(n-1+f)%f:max(n-1,0)];const r=a[n];var h=a[c?(n+1)%f:min(n+1,f-1)],k=r.x-g.x,l=r.y-g.y,m=(k*k+l*l)**.5;g=h.x-r.x;const q=h.y-r.y;h=(g*g+q*q)**.5;if(1e-6>m&&1e-6>h)continue;l=1e-6<m?-l/m:0;m=1e-6<m?k/m:0;k=l+(1e-6<h?-q/h:0);g=m+(1e-6<h?g/h:0);h=(k*k+g*g)**.5;1e-6>h?(k=l,g=m):(k/=h,g/=h,l=l*k+m*g,1e-6<l&&(l=min(1/l,10),k*=l,g*=l));let p,t;l=(p=e)[t=d.length]||(p[t]=vec2());let u,v;h=(u=e)[v=d.length+1]||(u[v]=vec2());l.x=r.x-k*b;l.y=r.y-g*b;h.x=r.x+k*b;h.y=r.y+g*b;d.push(l,h)}1<d.length&&c&&(d.push(d[0]),d.push(d[1]));return d}function glPolyStrip(a){if(3>a.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&&g<c;++g){d=a[g];var h=a[(g+1)%c].x-d.x;d=-1e-9<b(a[(g+c-1)%c],d,a[(g+1)%c]);(h=1e-9<h?1:-1e-9>h?-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-9<y?1:0)+(1e-9<u?1:0)+(1e-9<p?1:0))};f=[];for(c=0;c<a.length;++c)f[c]=c;c=[];g=0;for(d=a.length**2+100;3<f.length&&g++<d;){h=!1;for(var k=0;k<f.length;k++){var l=f[(k+f.length-1)%f.length],m=f[k];const p=f[(k+1)%f.length],t=a[l],u=a[m],v=a[p];if(1e-9>b(t,u,v))continue;let y=!1;for(let x=0;x<f.length;x++){const w=f[x];if(w!==l&&w!==m&&w!==p&&(y=e(a[w],t,u,v)))break}if(!y){c.push([l,m,p]);f.splice(k,1);h=!0;break}}if(!h){h=-1;k=Infinity;for(l=0;l<f.length;l++)m=abs(b(a[f[(l+f.length-1)%f.length]],a[f[l]],a[f[(l+1)%f.length]])),m<k&&(k=m,h=l);if(0>h)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<c.length;f++){const[p,t,u]=c[f];e.push(a[q],a[p]);e.push(a[p],a[t],a[u]);q=u}return e}function drawLoadingScreen(a){const b=mainContext,c=mainCanvasSize.x,d=mainCanvasSize.y,e=min(.6*c,400),f=(c-e)/2,g=d/2;b.save();b.fillStyle="#000";b.fillRect(0,0,c,d);b.fillStyle=b.strokeStyle="#fff";b.font="28px "+fontDefault;b.textAlign="center";b.textBaseline="bottom";b.fillText("Loading",c/2,g-16);b.lineWidth=2;b.strokeRect(f,g,e,12);b.fillRect(f,g,e*clamp(a),12);b.restore()}function drawEngineLogo(a){engineUpdateCanvas();const b=mainContext;var c=mainCanvasSize.x,d=mainCanvasSize.y,e=percent(a,1,.8),f=percent(a,0,.5),g=b.createRadialGradient(c/2,d/2,0,c/2,d/2,.6*hypot(c,d));g.addColorStop(0,hsl(0,0,lerp(0,e/2,f),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);const h=(l,m,n,r,q,p=1)=>{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,5<l?1:0);b[d?"strokeText":"fillText"]("LittleJS"[l],n,54.5,17*k);m+=a}b.lineWidth=.1+1.9*k;g(3,54,73,0);g(7,15,26,-7,0);g(25,15,8,25,-1);g(10,40,15,-25,1);g(14,21,7,9,2);g(38,20,6,-6,2);g(49,20,10,-6,0);c=[vec2(44,8),vec2(64,8),vec2(59,8+6*k),vec2(49,8+6*k)];e(c,2,8,6*k);g(44,8,20,-7,0);for(c=5;c--;)f(59-6*c*k,30,10,0,2*PI,1,0);f(59,30,4,0,7,2);g(35,20,24,0);f(59,30,10);f(47,30,10,PI/2,3*PI/2);f(35,30,10,PI/2,3*PI/2);g(7,40,13,7,-1);g(17,40,43,14,-1);for(g=3;g--;)for(c=2;c--;)f(17+15*g,47,c?7:1,0,2*PI,2);for(f=2;f--;)g=53+6*k*f,g=[vec2(g+7,54),vec2(g,40),vec2(g+6*k,40),vec2(g+7+6*k,54)],e(g,0,40,14);b.restore()}let debugMedals=!1,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalsPreventUnlock=!1;const medals={};let medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast,medalsRenderAdded;function medalsInit(a){const b=[];medalsSaveName||medalsForEach(c=>c.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(b<c?1-b/c:b>d?(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.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 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;function wavedashWait(a,b){let c;const d=new Promise(e=>c=setTimeout(e,wavedashTimeoutMS));return Promise.race([Promise.resolve(b),d]).catch(e=>{console.warn("Wavedash "+a+" failed: "+e)}).finally(()=>clearTimeout(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.achievementRetry=void 0;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}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)<wavedashRetries?a=!0:(console.warn("Wavedash refused achievement "+b+" "+wavedashRetries+" times; is it made, with that identifier?"),this.achievementsSent.add(b))}});clearTimeout(this.achievementRetry);this.achievementRetry=a?setTimeout(()=>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=a||postProcessEffects();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){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.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,glCanvas);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.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,glContext.RGBA,glContext.UNSIGNED_BYTE,glCanvas),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=a||postProcessEffects();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 postProcessFragmentSource(a,b={}){let c="";for(const e in b){var d=b[e];d=isArray(d)?d.length:1;c+=`uniform ${1<d?"vec"+d:"float"} ${e};`}return"#version 300 es\nprecision highp float;uniform sampler2D iChannel0;uniform sampler2D iChannel1;uniform highp sampler2D iChannel2;uniform vec3 iResolution;uniform float iTime;uniform vec3 iDepthRange;"+c+"out vec4 c;float sceneDepth(vec2 uv){float d=texture(iChannel2,uv).r*2.-1.,n=iDepthRange.x,f=iDepthRange.y;return iDepthRange.z>0.?(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+=`
|
|
5
5
|
for (int _k = 0; _k < ${h}; ++_k)
|
|
6
6
|
{
|
|
7
7
|
float _a = float(_k) * ${(2*PI/h).toFixed(7)}${f?" + "+(2.3999632*f).toFixed(7):""};
|
|
@@ -40,4 +40,4 @@ const engineName="LittleJS",engineVersion="1.25.0",frameRate=60;let timeDelta=1/
|
|
|
40
40
|
float _dy = abs(sceneDepth(uv + vec2(0, _o.y)) + sceneDepth(uv - vec2(0, _o.y)) - 2. * _d);
|
|
41
41
|
vec4 _line = vec4(${d(a.r)}, ${d(a.g)}, ${d(a.b)}, ${d(a.a)});
|
|
42
42
|
if (LJS_HAS_DEPTH)
|
|
43
|
-
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 g;(g=lightSystem).shadowContext||(g.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;in vec2 vWorldPos;in vec2 vUV;out vec4 c;void main(){float dist=distance(vWorldPos,lightPos);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;}");glContext.useProgram(lightSystem.lightShader);glContext.uniform1i(glUniformLocation(lightSystem.lightShader,"shadowTexture"),1);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.);}");lightSystem.lightVAO=d(lightSystem.lightShader,"g");lightSystem.compositeVAO=d(lightSystem.compositeShader,"p")}else console.warn("LightSystemPlugin: WebGL not enabled!")}function d(g,h){const k=glContext,l=k.createVertexArray();k.bindVertexArray(l);k.bindBuffer(k.ARRAY_BUFFER,glGeometryBuffer);g=k.getAttribLocation(g,h);k.enableVertexAttribArray(g);k.vertexAttribPointer(g,2,k.FLOAT,!1,8,0);return l}function e(g){const h=glContext,k=h.createTexture();h.bindTexture(h.TEXTURE_2D,k);h.texImage2D(h.TEXTURE_2D,0,h.RGBA,g,g,0,h.RGBA,h.UNSIGNED_BYTE,null);h.texParameteri(h.TEXTURE_2D,h.TEXTURE_MAG_FILTER,h.LINEAR);h.texParameteri(h.TEXTURE_2D,h.TEXTURE_MIN_FILTER,h.LINEAR);h.texParameteri(h.TEXTURE_2D,h.TEXTURE_WRAP_S,h.CLAMP_TO_EDGE);h.texParameteri(h.TEXTURE_2D,h.TEXTURE_WRAP_T,h.CLAMP_TO_EDGE);return k}function f(){const g=lightSystem;g.shadowMap=g.shadowTextureA=g.shadowTextureB=void 0;g.shadowCopyShader=g.shadowStretchShader=void 0;g.shadowCopyVAO=g.shadowStretchVAO=void 0}lightSystem=this;this.enabled=!0;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.shadowMap=void 0;this.shadowMapOrigin=vec2();this.shadowTextureSizeAllocated=this.shadowMapSizeAllocated=this.shadowMapWorldSize=0;c();engineAddPlugin(void 0,function(){if(!headlessMode&&glEnable&&lightSystem.enabled){if(!lightSystem.texture){if(glContext.isContextLost())return;c();if(!lightSystem.texture)return}glFlush();var g=glAdditive;if(lightSystem.shadows){var h=lightSystem;h.clampTextureSizes();if(!h.shadowMap||h.shadowMapSize!==h.shadowMapSizeAllocated||h.shadowTextureSize!==h.shadowTextureSizeAllocated){if(h.shadowMap){var k=glContext,l=lightSystem;k.deleteTexture(l.shadowMap);k.deleteTexture(l.shadowTextureA);k.deleteTexture(l.shadowTextureB);k.deleteProgram(l.shadowCopyShader);k.deleteProgram(l.shadowStretchShader);k.deleteVertexArray(l.shadowCopyVAO);k.deleteVertexArray(l.shadowStretchVAO);f()}k=glContext;l=lightSystem;l.shadowMap=e(l.shadowMapSize);l.shadowTextureA=e(l.shadowTextureSize);l.shadowTextureB=e(l.shadowTextureSize);l.shadowMapSizeAllocated=l.shadowMapSize;l.shadowTextureSizeAllocated=l.shadowTextureSize;glActiveTexture&&k.bindTexture(k.TEXTURE_2D,glActiveTexture);l.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)<core?vec3(1):o,1);}");l.shadowStretchShader=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 float scale;uniform float brightness;in vec2 uv;out vec4 c;void main(){float mask=1.-smoothstep(.35,.525,length(uv-.5));vec3 b=texture(s,(uv-.5)/scale+.5).rgb;c=vec4(min(texture(s,uv).rgb+brightness*mask*b,b),1);}");l.shadowCopyVAO=d(l.shadowCopyShader,"p");l.shadowStretchVAO=d(l.shadowStretchShader,"p");k.useProgram(l.shadowCopyShader);k.uniform1i(glUniformLocation(l.shadowCopyShader,"s"),1);k.useProgram(l.shadowStretchShader);k.uniform1i(glUniformLocation(l.shadowStretchShader,"s"),1)}k=h.shadowMapSize;l=mainCanvasSize.scale(1/cameraScale);l=h.shadowMapScale*max(l.x,l.y);var m=l/k;m=vec2(floor(cameraPos.x/m)*m,floor(cameraPos.y/m)*m);h.shadowMapOrigin=m.subtract(vec2(l/2));h.shadowMapWorldSize=l;const q=[drawContext,mainCanvasSize,cameraPos,cameraScale,cameraAngle,canvasClearColor,glCustomShader];drawContext=h.shadowContext;mainCanvasSize=vec2(k);cameraPos=m;cameraScale=k/l;cameraAngle=0;canvasClearColor=WHITE;glSetRenderTarget(h.shadowMap,!0);glSkipScreenSpace=!0;h.shadowPass=!0;try{for(var n of engineObjects)!n.destroyed&&n.castShadow&&(glColorMask=4278190080,setShader(n.shader),n.renderShadow())}finally{h.shadowPass=!1,glColorMask=-1,glSkipScreenSpace=!1,glSetRenderTarget(),[drawContext,mainCanvasSize,cameraPos,cameraScale,cameraAngle,canvasClearColor,glCustomShader]=q}}h=lightSystem.textureSize;n=glClampTextureSize(mainCanvasSize.x);k=glClampTextureSize(mainCanvasSize.y);!lightSystem.textureSizeAuto||h.x===n&&h.y===k||(lightSystem.textureSize=vec2(n,k),glContext.bindTexture(glContext.TEXTURE_2D,lightSystem.texture),glContext.texImage2D(glContext.TEXTURE_2D,0,glContext.RGBA,n,k,0,glContext.RGBA,glContext.UNSIGNED_BYTE,null),glActiveTexture&&glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture));h=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(h.r,h.g,h.b,h.a);glContext.clear(glContext.COLOR_BUFFER_BIT);setAdditiveBlendMode();glContext.enable(glContext.BLEND);glContext.blendFunc(glContext.ONE,glContext.ONE);h=lightSystem.lightShader;glContext.useProgram(h);glContext.uniformMatrix4fv(glUniformLocation(h,"m"),!1,glTransform);glSetInstancedMode(!0);glRenderTargetBase=[lightSystem.texture,lightSystem.textureSize];try{for(var p of engineObjects)p.destroyed||(glAdditive||setAdditiveBlendMode(),p.renderLight());p=[drawContext,glCustomShader];drawContext=lightSystem.shadowContext;lightSystem.emissivePass=!0;try{for(var r of engineObjects){if(r.destroyed||!(0<r.emissive))continue;const q=255*clamp(r.emissive)+.5|0;glColorMask=4278190080;glColorAdditive=q|q<<8|q<<16;glAdditive||setAdditiveBlendMode();setShader(r.shader);r.renderEmissive()}glFlush()}finally{lightSystem.emissivePass=!1,glColorMask=-1,glColorAdditive=0,[drawContext,glCustomShader]=p}}finally{glRenderTargetBase=void 0}glFlush();glContext.bindFramebuffer(glContext.FRAMEBUFFER,null);glContext.viewport(0,0,glCanvas.width,glCanvas.height);glContext.useProgram(lightSystem.compositeShader);glContext.bindVertexArray(lightSystem.compositeVAO);glContext.activeTexture(glContext.TEXTURE0);glContext.bindTexture(glContext.TEXTURE_2D,lightSystem.texture);r=lightSystem.compositeShader;glContext.uniform1i(glUniformLocation(r,"s"),0);glContext.uniform3f(glUniformLocation(r,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.blendFunc(glContext.DST_COLOR,glContext.ZERO);glContext.drawArrays(glContext.TRIANGLE_STRIP,0,4);glActiveTexture&&glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture);glSetInstancedMode(!0);setAdditiveBlendMode();for(const q of engineObjects)q instanceof Light&&!q.destroyed&&q.renderGlow();glFlush();setAdditiveBlendMode(g)}},function(){lightSystem.texture=void 0;lightSystem.lightShader=void 0;lightSystem.compositeShader=void 0;lightSystem.lightVAO=void 0;lightSystem.compositeVAO=void 0;f()},function(){c()})}clampTextureSizes(){this.shadowMapSize=glClampTextureSize(this.shadowMapSize);this.shadowTextureSize=glClampTextureSize(this.shadowTextureSize);const a=this.textureSize;if(a){var b=glClampTextureSize(a.x),c=glClampTextureSize(a.y);if(b!==a.x||c!==a.y)this.textureSize=vec2(b,c)}}drawLight(a){if(!headlessMode&&glEnable&&this.lightShader&&isOnScreen(a.pos,2*a.radius)){glFlush();var b=this.shadows&&a.castShadow&&!!this.shadowMap;b&&this.renderLightShadow(a);glContext.useProgram(this.lightShader);glContext.bindVertexArray(this.lightVAO);glContext.enable(glContext.BLEND);glContext.blendFunc(glContext.ONE,glContext.ONE);var c=this.lightShader;glContext.uniform2f(glUniformLocation(c,"lightPos"),a.pos.x,a.pos.y);glContext.uniform1f(glUniformLocation(c,"radius"),a.radius);glContext.uniform1f(glUniformLocation(c,"fadeRange"),a.fadeRange);glContext.uniform1i(glUniformLocation(c,"useShadow"),b?1:0);a=a.color;glContext.uniform4f(glUniformLocation(c,"color"),a.r,a.g,a.b,a.a);glContext.drawArrays(glContext.TRIANGLE_STRIP,0,4);glSetInstancedMode(!0)}}renderLightShadow(a){const b=glContext;var c=this.shadowTextureSize;b.disable(b.BLEND);b.viewport(0,0,c,c);b.activeTexture(b.TEXTURE1);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,this.shadowTextureA,0);var d=this.shadowCopyShader;b.useProgram(d);b.bindVertexArray(this.shadowCopyVAO);b.bindTexture(b.TEXTURE_2D,this.shadowMap);b.uniform2f(glUniformLocation(d,"lightPos"),a.pos.x,a.pos.y);b.uniform1f(glUniformLocation(d,"radius"),a.radius);b.uniform2f(glUniformLocation(d,"mapOrigin"),this.shadowMapOrigin.x,this.shadowMapOrigin.y);b.uniform1f(glUniformLocation(d,"mapInvSize"),1/this.shadowMapWorldSize);b.uniform1f(glUniformLocation(d,"tap"),a.radius/c);b.uniform1f(glUniformLocation(d,"core"),a.shadowCore);b.drawArrays(b.TRIANGLE_STRIP,0,4);a=this.shadowStretchShader;b.useProgram(a);b.bindVertexArray(this.shadowStretchVAO);c=this.shadowTextureA;d=this.shadowTextureB;for(let e=0;e<this.shadowPassCount;++e)b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,d,0),b.bindTexture(b.TEXTURE_2D,c),b.uniform1f(glUniformLocation(a,"scale"),1+2*1.5**e/256),b.uniform1f(glUniformLocation(a,"brightness"),clamp((10.1-e)/7.2)**2*this.shadowSoftness),b.drawArrays(b.TRIANGLE_STRIP,0,4),[c,d]=[d,c];b.bindTexture(b.TEXTURE_2D,c);b.activeTexture(b.TEXTURE0);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,this.texture,0);b.viewport(0,0,this.textureSize.x,this.textureSize.y);b.enable(b.BLEND);b.blendFunc(b.ONE,b.ONE)}setShadowTransparent(a=!0){this.shadowPass&&(glColorMask=a?-1:4278190080)}}class Light extends EngineObject{constructor(a,b,c,d){super(a,vec2(1),void 0,0,c);this.mass=0;this.radius=b;this.fadeRange=void 0===d?b:d;this.glow=this.shadowCore=0;this.glowFalloff=1;this.glowTileInfo=void 0}render(){}renderLight(){lightSystem&&lightSystem.drawLight(this)}renderGlow(){if(0<this.glow){var a=vec2(this.glow);if(isOnScreen(this.pos,a)){var b=engineGlowTexture(this.glowFalloff);b&&(this.glowTileInfo?.textureInfo!==b&&(this.glowTileInfo=new TileInfo(vec2(),b.size,b)),drawTile(this.pos,a,this.glowTileInfo,this.color,0,!1,void 0,!0,!1))}}}}class AudioEffect{constructor(a=1){this.mix=clamp(a);audioContext&&(this.input=audioContext.createGain(),this.output=audioContext.createGain(),this.dryGain=audioContext.createGain(),this.wetGain=audioContext.createGain(),this.input.connect(this.dryGain).connect(this.output),this.wetGain.connect(this.output),this.setMix(a),this.output.connect(audioMasterGain))}setMix(a,b=0){this.mix=a=clamp(a);audioContext&&(this.rampParam(this.dryGain.gain,1-a,b),this.rampParam(this.wetGain.gain,a,b))}rampParam(a,b,c=0){audioParamRamp(a,b,c);if(c){var d=new ConstantSourceNode(audioContext,{offset:0});d.connect(this.input);d.onended=()=>d.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;function uiSetDebug(a){uiDebug="boolean"===typeof a?a?1:0:a}class UISystemPlugin{constructor(a=mainContext){function b(c){let d,e;c.parent?(d=c.parent.nativePos,e=c.parent.size):(d=uiSystem.screenToNative(mainCanvasSize.scale(.5)),e=uiSystem.nativeHeight?vec2(mainCanvasSize.x*uiSystem.nativeHeight/mainCanvasSize.y,uiSystem.nativeHeight):mainCanvasSize);const f=c.anchor;c.nativePos=d.add(e.multiply(f).scale(.5)).subtract(c.size.multiply(f).scale(.5)).add(c.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=c=>{const d=this._keyInputObject;if(d&&uiObjectIsUsable(d)&&!uiObjectIsBehindDialog(d)){c.stopPropagation();var e=c.key||"";c.ctrlKey||c.metaKey||c.altKey||(1===e.length||/^(Backspace|Delete|Tab|Arrow(Up|Down|Left|Right)|Home|End|Enter|Escape)$/.test(e))&&c.preventDefault();"keydown"===c.type&&d.onKeyDown(c)}};engineAddPlugin(function(){function c(h){if(!h.destroyed&&h.visible){b(h);var k=h.children.slice();for(let l=k.length;l--;)c(k[l]);h.destroyed||h.update()}}var d=uiSystem.activeObject;d&&!uiObjectIsUsable(d)&&(uiSystem.activeObject=void 0,d.destroyed||d===uiSystem.keyInputObject||d.onRelease());!(d=uiSystem.keyInputObject)||uiObjectIsUsable(d)&&!uiObjectIsBehindDialog(d)||(d instanceof UITextInput&&!d.destroyed?d.stopEditing():uiSystem.keyInputObject=void 0);var e=uiSystem.keyInputObject;(d=e instanceof UITextInput&&mouseWasPressed(0)&&!e.isMouseOverlapping())&&e.stopEditing();uiSystem.lastHoverObject=uiSystem.hoverObject;uiSystem.hoverObject=void 0;(e=uiSystem.lastHoverObject)&&!e.destroyed&&uiObjectIsHidden(e)&&(uiSystem.lastHoverObject=void 0,e.onLeave());mouseWasPressed(0)&&(uiSystem.navigationMode=!1,uiSystem.navigationObject=void 0);uiSystem.keyInputObject&&(uiSystem.activeObject=uiSystem.keyInputObject,uiSystem.hoverObject=uiSystem.lastHoverObject);e=uiSystem.getNavigableObjects();if(!e.length)uiSystem.navigationObject=void 0;else if(!uiSystem.keyInputObject){e.includes(uiSystem.navigationObject)||(uiSystem.navigationObject=void 0);isTouchDevice||!uiSystem.navigationMode||uiSystem.navigationObject||(uiSystem.navigationObject=e.find(h=>h.navigationAutoSelect));if(!uiSystem.navigationTimer.active()){var f=sign(uiSystem.getNavigationDirection());if(f){if(uiSystem.navigationObject){var g=e.indexOf(uiSystem.navigationObject);f=mod(g+f,e.length);g=e[f]}else(g=e.find(h=>h.navigationAutoSelect))||(g=e[0<f?0:e.length-1]);uiSystem.navigationObject!==g&&(uiSystem.navigationMode=!0,uiSystem.hoverObject=void 0,uiSystem.navigationObject=g,uiSystem.navigationTimer.set(uiSystem.navigationDelay),g.soundPress&&g.soundPress.play())}}uiSystem.navigationObject&&uiSystem.getNavigationWasPressed()&&(uiSystem.navigationObject.navigatePressed(),isUsingGamepad?inputClearKey(0,gamepadPrimary+1,!1,!0,!1):(inputClearKey("Space",0,!1,!0,!1),inputClearKey("Enter",0,!1,!0,!1)))}e=uiSystem.uiObjects;(f=uiSystem.confirmDialog)&&c(f);for(g=e.length;g--;){const h=e[g];h.parent||h===f||c(h)}d&&mouseWasPressed(0)&&inputClearKey(0,0);uiSystem.uiObjects=uiSystem.uiObjects.filter(h=>!h.destroyed)},function(){function c(f){if(!f.destroyed&&f.visible){b(f);f.render();for(const g of f.children)c(g)}}const d=uiSystem.uiContext;d.save();if(uiSystem.nativeHeight){const f=mainCanvasSize.y/uiSystem.nativeHeight;d.translate(-f*mainCanvasSize.x/2,0);d.scale(f,f);d.translate(mainCanvasSize.x/2/f,0)}const e=uiSystem.confirmDialog;uiSystem.uiObjects.forEach(f=>f.parent||f===e||c(f));e&&c(e);if(0<uiDebug){function f(g,h=!0){h&&=!!g.visible;if(!(g.destroyed||!h&&2>uiDebug)){b(g);g.renderDebug(h);for(const k of g.children)f(k,h)}}uiSystem.uiObjects.forEach(g=>g.parent||g===e||f(g));e&&f(e)}d.restore()})}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<e.a&&(m.strokeStyle=e.toString(),m.lineWidth=d,m.stroke())}drawSlice(a,b,c,d=WHITE){0<d.a&&a.drawScreen(b,c,d,void 0,0,!1,uiSystem.uiContext)}drawLine(a,b,c=uiSystem.defaultLineWidth,d=uiSystem.defaultLineColor){const e=uiSystem.uiContext;e.strokeStyle=d.toString();e.lineWidth=c;e.beginPath();e.lineTo(a.x,a.y);e.lineTo(b.x,b.y);e.stroke()}drawTile(a,b,c,d=uiSystem.defaultColor,e=0,f=!1,g=BLACK,h=0,k=vec2()){const l=uiSystem.uiContext;uiSetShadow(l,g,h,k);drawTile(a,b,c,d,e,f,CLEAR_BLACK,!1,!0,l);l.shadowColor="#0000"}drawText(a,b,c,d=uiSystem.defaultColor,e=uiSystem.defaultLineWidth,f=uiSystem.defaultLineColor,g="center",h=uiSystem.defaultFont,k="",l=!0,m,n=BLACK,p=0,r=vec2()){const q=uiSystem.uiContext;m&&0<n.a&&drawTextScreen(a,b.add(m),c.y,n,e,f,g,h,k,l?c.x:void 0,0,q);uiSetShadow(q,n,p,r);drawTextScreen(a,b,c.y,d,e,f,g,h,k,l?c.x:void 0,0,q);q.shadowColor="#0000"}setupDragAndDrop(a,b,c,d){if(this._dragListeners)for(const[g,h]of this._dragListeners)document.removeEventListener(g,h);this._dragListeners=[];const e=(g,h,k=()=>!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 r=hsl(0,0,0,.7);uiSystem.drawRect(vec2(),vec2(1e9),r)};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 p=h.destroy.bind(h);h.destroy=()=>{const r=uiSystem.confirmDialog===h;r&&(uiSystem.confirmDialog=void 0,uiSystem.navigationDirection=f);p();r&&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){0<b.a&&(c||d.x||d.y)&&(a.shadowColor=b.toString(),a.shadowBlur=c,a.shadowOffsetX=d.x,a.shadowOffsetY=d.y)}function uiObjectIsBehindDialog(a){const b=uiSystem.confirmDialog;if(!b)return!1;for(;a;a=a.parent)if(a===b)return!1;return!0}function uiObjectIsDisabled(a){for(;a;a=a.parent)if(a.disabled)return!0;return!1}function uiObjectIsHidden(a){for(;a;a=a.parent)if(!a.visible)return!0;return!1}class UIObject{constructor(a=vec2(),b=vec2()){this.localPos=a.copy();this.nativePos=a.copy();this.size=b.copy();this.color=uiSystem.defaultColor.copy();this.text=this.activeColor=void 0;this.disabledColor=uiSystem.defaultDisabledColor.copy();this.disabled=!1;this.textColor=uiSystem.defaultTextColor.copy();this.hoverColor=uiSystem.defaultHoverColor.copy();this.lineColor=uiSystem.defaultLineColor.copy();this.gradientColor=uiSystem.defaultGradientColor?uiSystem.defaultGradientColor.copy():void 0;this.lineWidth=uiSystem.defaultLineWidth;this.cornerRadius=uiSystem.defaultCornerRadius;this.slice=uiSystem.defaultSlice;this.font=uiSystem.defaultFont;this.textHeight=this.textWidth=this.fontStyle=void 0;this.textFitScale=uiSystem.defaultTextFitScale;this.textShadow=void 0;this.textLineColor=uiSystem.defaultLineColor.copy();this.textLineWidth=0;this.visible=!0;this.children=[];this.parent=void 0;this.extraTouchSize=0;this.soundPress=uiSystem.defaultSoundPress;this.soundRelease=uiSystem.defaultSoundRelease;this.soundClick=uiSystem.defaultSoundClick;this.dragActivate=this.interactive=!1;this.canBeHover=!0;this.shadowColor=uiSystem.defaultShadowColor?.copy();this.shadowBlur=uiSystem.defaultShadowBlur;this.shadowOffset=uiSystem.defaultShadowOffset?.copy();this.navigationIndex=void 0;this.navigationAutoSelect=!1;this.anchor=vec2();this.align="center";this.destroyed=!1;uiSystem.uiObjects.push(this)}addChild(a){this.children.push(a);a.parent=this;return a}removeChild(a){this.children.splice(this.children.indexOf(a),1);a.parent=void 0}destroy(){if(!this.destroyed){uiSystem.activeObject===this&&(uiSystem.activeObject=void 0);uiSystem.hoverObject===this&&(uiSystem.hoverObject=void 0);uiSystem.lastHoverObject===this&&(uiSystem.lastHoverObject=void 0);uiSystem.navigationObject===this&&(uiSystem.navigationObject=void 0);uiSystem.keyInputObject===this&&(uiSystem.keyInputObject=void 0);this.destroyed=!0;this.parent?.removeChild(this);for(const a of this.children)a.parent=void 0,a.destroy();this.children.length=0}}isMouseOverlapping(){if(!mouseInWindow)return!1;const a=isTouchDevice?this.size.add(vec2(this.extraTouchSize||0)):this.size,b=uiSystem.screenToNative(mousePosScreen);return isOverlapping(this.nativePos,a,b)}update(){this.onUpdate();if(!this.destroyed){var a=uiObjectIsDisabled(this);if(a&&this===uiSystem.activeObject&&(uiSystem.activeObject=void 0,this!==uiSystem.keyInputObject&&(this.onRelease(),this.destroyed)))return;if(!uiSystem.keyInputObject){var b=uiSystem.lastHoverObject===this,c=this.isActiveObject(),d=mouseIsDown(0),e=mouseWasPressed(0)||this.dragActivate&&d;this.canBeHover&&!uiSystem.navigationMode&&(e||c||!d&&!isTouchDevice)&&!uiSystem.hoverObject&&this.isMouseOverlapping()&&(uiSystem.hoverObject=this);if(this.isHoverObject()){if(!a){if(e&&this.interactive){if(a=!this.dragActivate||!b||mouseWasPressed(0)){this.onPress();if(this.destroyed)return void inputClearKey(0,0,!1,!0,!1);this.soundPress&&this.soundPress.play();if(uiSystem.activeObject&&!c)uiSystem.activeObject.onRelease()}uiSystem.keyInputObject&&uiSystem.keyInputObject!==this?(this.onRelease(),this.soundRelease&&this.soundRelease.play()):uiSystem.activeObject=this;a&&uiSystem.activateOnPress&&this.click(!this.soundPress);if(this.destroyed)return void inputClearKey(0,0,!1,!0,!1)}uiSystem.activateOnPress||!d&&c&&this.isActiveObject()&&this.interactive&&this.click();if(this.destroyed)return}e&&inputClearKey(0,0,!1,!0,!1)}c&&(!d||this.dragActivate&&!this.isHoverObject())&&(this.onRelease(),this.soundRelease&&this.soundRelease.play(),uiSystem.activeObject=void 0);this.isHoverObject()!==b&&(this.isHoverObject()?this.onEnter():this.onLeave())}}}render(){this.onRender();if(this.size.x&&this.size.y){var a=this.isNavigationObject(),b=this.interactive?uiObjectIsDisabled(this):this.disabled,c=a?this.color:this.interactive&&this.isActiveObject()&&!b?this.color:this.lineColor;b=a?this.hoverColor:b?this.disabledColor:this.interactive?this.isActiveObject()?this.activeColor||this.hoverColor:this.isHoverObject()?this.hoverColor:this.color:this.color;a=this.lineWidth*(a?1.5:1);this.slice?uiSystem.drawSlice(this.slice,this.nativePos,this.size,b):uiSystem.drawRect(this.nativePos,this.size,b,a,c,this.cornerRadius,this.gradientColor,this.shadowColor||CLEAR_BLACK,this.shadowBlur,this.shadowOffset)}}getTextSize(){const a=this.textHeight?1:(this.text+"").split("\n").length;return vec2(this.textWidth||this.textFitScale*this.size.x,this.textHeight||this.textFitScale*this.size.y/a)}getTextPos(a){return this.nativePos.add(vec2(("left"===this.align?-1:"right"===this.align?1:0)*a.x/2,0))}navigatePressed(){this.click()}isHoverObject(){return uiSystem.hoverObject===this}isActiveObject(){return uiSystem.activeObject===this}isNavigationObject(){return uiSystem.navigationObject===this}isKeyInputObject(){return uiSystem.keyInputObject===this}isInteractive(){return this.interactive&&uiObjectIsUsable(this)}toString(){let a="type = "+this.constructor.name;this.text&&(a+="\ntext = "+this.text);if(this.nativePos.x||this.nativePos.y)a+="\nnativePos = "+this.nativePos;if(this.localPos.x||this.localPos.y)a+="\nlocalPos = "+this.localPos;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.color&&(a+="\ncolor = "+this.color);return a}renderDebug(a=!0){a=a?this.isHoverObject()?YELLOW:uiObjectIsDisabled(this)?PURPLE:this.interactive?RED:BLUE:GREEN;uiSystem.drawRect(this.nativePos,this.size,CLEAR_BLACK,4,a)}click(a=!0){this.onClick();a&&this.soundClick&&this.soundClick.play()}onUpdate(){}onRender(){}onEnter(){}onLeave(){}onPress(){}onRelease(){}onClick(){}onChange(){}onKeyDown(a){}}class UIText extends UIObject{constructor(a,b,c="",d="center",e=uiSystem.defaultFont){super(a,b);this.text=c;this.align=d;this.font=e;this.canBeHover=!1;this.color=CLEAR_BLACK.copy();this.shadowColor=CLEAR_BLACK.copy();this.gradientColor=void 0;this.lineWidth=0;this.textFitScale=1}render(){super.render();const a=this.getTextSize();uiSystem.drawText(this.text,this.getTextPos(a),a,this.textColor,this.textLineWidth,this.textLineColor,this.align,this.font,this.fontStyle,!0,this.textShadow,this.shadowColor||CLEAR_BLACK,this.shadowBlur,this.shadowOffset)}}class UITextInput extends UIObject{constructor(a,b,c=""){super(a,b);this.maxLength=0;this.text=c+"";this.canBeHover=this.interactive=!0}click(a=!0){const b=uiSystem.keyInputObject;b!==this&&b instanceof UITextInput&&b.stopEditing();uiSystem.keyInputObject=this;inputClearKey(0,gamepadPrimary+1,!1,!0,!1);this.onClick();a&&this.soundClick&&this.soundClick.play()}stopEditing(){this.isKeyInputObject()&&(this.soundRelease&&this.soundRelease.play(),uiSystem.activeObject=void 0,uiSystem.keyInputObject=void 0,this.onChange())}onKeyDown(a){const b=a.code,c=a.key||"";if(!a.repeat||"Enter"!==c&&"Space"!==b)this.text+="","Backspace"===c?this.text=[...this.text].slice(0,-1).join(""):"Enter"===c||"Escape"===c?this.stopEditing():1!==c.length||(a.ctrlKey||a.metaKey)&&!a.getModifierState?.("AltGraph")||this.maxLength&&!(this.text.length<this.maxLength)||(this.text+=c)}update(){super.update();this.isKeyInputObject()&&(gamepadWasPressed(0,gamepadPrimary)?(this.stopEditing(),inputClearKey(0,gamepadPrimary+1,!1,!0,!1)):mouseWasPressed(0)&&inputClearKey(0,0,!1,!0,!1))}render(){super.render();const a=this.getTextSize();let b=this.text;this.isKeyInputObject()&&(b+=.5>timeReal%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.readyState<this.video.HAVE_CURRENT_DATA}isPaused(){return this.video.paused}isPlaying(){return!this.isPaused()&&!this.hasEnded()&&!this.isLoading()}hasEnded(){return this.video.ended}setVolume(a){this.volume=a;this.video.volume=clamp(a*soundVolume)}setPlaybackRate(a){this.video.playbackRate=a}getCurrentTime(){return this.video.currentTime||0}getDuration(){return this.video.duration||0}getVideoSize(){return vec2(this.video.videoWidth,this.video.videoHeight)}setTime(a){const b=this.video.duration;this.video.currentTime=b?clamp(a,0,b):max(a,0)}update(){super.update();this.video.volume=clamp(this.volume*soundVolume);this._soundEnabled!==soundEnable&&(this.video.muted=!(this._soundEnabled=soundEnable))}render(){super.render();if(!this.isLoading()){var a=uiSystem.uiContext,b=this.size;a.save();a.translate(this.nativePos.x,this.nativePos.y);a.drawImage(this.video,-b.x/2,-b.y/2,b.x,b.y);a.restore()}}destroy(){this.destroyed||(this.video.pause(),this.video.removeAttribute?.("src"),this.video.load?.(),this.video.remove(),super.destroy())}}class UILayout extends UIObject{constructor(a,b=1,c=10,d=10,e=!1){super(a);this.columns=b;this.gap=c;this.padding=d;e&&(this.color=CLEAR_BLACK.copy(),this.gradientColor=void 0,this.lineWidth=0,this.shadowColor=CLEAR_BLACK.copy(),this.canBeHover=!1);this.relayout()}addChild(a){super.addChild(a);this.relayout();return a}removeChild(a){super.removeChild(a);this.relayout()}relayout(){const a=this.children.filter(p=>p.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<b;++g){var h=g%c,k=floor(g/c),l=a[g];e[h]=max(e[h],l.size.x);f[k]=max(f[k],l.size.y)}g=this.gap*(c-1);for(var m of e)g+=m;m=this.gap*(d-1);for(var n of f)m+=n;n=Array(c);h=0;for(k=0;k<c;++k)n[k]=h,h+=e[k];h=Array(d);k=0;for(l=0;l<d;++l)h[l]=k,k+=f[l];for(d=0;d<b;++d)k=d%c,l=floor(d/c),a[d].localPos=vec2(-g/2+n[k]+this.gap*k+e[k]/2,-m/2+h[l]+this.gap*l+f[l]/2);this.size=vec2(g+2*this.padding,m+2*this.padding)}else this.size=vec2(2*this.padding);this.parent instanceof UILayout&&this.parent.relayout()}}let box2d,box2dDebug=!1,box2dTempVectors;function box2dTemp(a,b=0){b=(box2dTempVectors||=[new box2d.instance.b2Vec2,new box2d.instance.b2Vec2])[b];b.Set(a.x,a.y);return b}const box2dQueryObjects={},box2dGravity={x:NaN,y:NaN};function box2dQueryObject(a,b){let c;return(c=box2dQueryObjects)[a]||(c[a]=new box2d.instance[b])}function box2dFixtureOverlaps(a,b){const c=a.GetShape();a=a.GetBody().GetTransform();const d=box2dQueryObject("shapeAABB","b2AABB"),e=b.get_lowerBound();b=b.get_upperBound();for(let f=c.GetChildCount();f--;){c.ComputeAABB(d,a,f);const g=d.get_lowerBound(),h=d.get_upperBound();if(g.get_x()<=b.get_x()&&h.get_x()>=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<d.distanceSquared(c[c.length-1]))&&c.push(d);for(;b&&1<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)}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}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)}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){}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-6<a.x*a.y){var h=new box2d.instance.b2PolygonShape;h.SetAsBox(a.x/2,a.y/2,box2dTemp(b),-c);a=this.addShape(h,d,e,f,g);box2d.instance.destroy(h);return a}}addPoly(a,b,c,d,e){if(a=function(f){f=f.filter((l,m)=>f.slice(0,m).every(n=>1e-6<l.distanceSquared(n)));var g=0;if(3<=f.length&&8>=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<f.length;++l)box2d.instance.HEAPF32[g+m>>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;0<h--;)g.push(vec2(a,0).rotate((h+.5)/b*PI*2));return this.addPoly(g,c,d,e,f)}addRandomPoly(a=1,b,c,d,e){const f=randInt(3,9),g=[];a/=2;for(let h=f;h--;)g.push(vec2(rand(a/2,1.5*a),0).rotate(h/f*PI*2));return this.addPoly(g,b,c,d,e)}addCircle(a=1,b=vec2(),c,d,e,f){const g=new box2d.instance.b2CircleShape;g.set_m_p(box2dTemp(b));g.set_m_radius(a/2);a=this.addShape(g,c,d,e,f);box2d.instance.destroy(g);return a}addEdge(a,b,c,d,e,f){const g=new box2d.instance.b2EdgeShape;g.Set(box2dTemp(a),box2dTemp(b,1));a=this.addShape(g,c,d,e,f);box2d.instance.destroy(g);return a}addEdgeList(a,b,c,d,e){a=box2dEdgePoints(a);const f=[],g=[];if(2>a.length)return f;for(let h=0;h<a.length-1;++h){const k=new box2d.instance.b2EdgeShape;a[h-1]&&k.set_m_vertex0(box2dTemp(a[h-1]));a[h+0]&&k.set_m_vertex1(box2dTemp(a[h+0]));a[h+1]&&k.set_m_vertex2(box2dTemp(a[h+1]));a[h+2]&&k.set_m_vertex3(box2dTemp(a[h+2]));k.set_m_hasVertex0(!!a[h-1]);k.set_m_hasVertex3(!!a[h+2]);const l=this.addShape(k,b,c,d,e);box2d.instance.destroy(k);f.push(l);g.push(a[h].copy())}g.push(a[a.length-1].copy());this.edgeLists.push(g);f.forEach(h=>this.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;h<a.length;++h){const k=new box2d.instance.b2EdgeShape;k.set_m_vertex0(box2dTemp(a[mod(h-1,a.length)]));k.set_m_vertex1(box2dTemp(a[mod(h+0,a.length)]));k.set_m_vertex2(box2dTemp(a[mod(h+1,a.length)]));k.set_m_vertex3(box2dTemp(a[mod(h+2,a.length)]));k.set_m_hasVertex0(!0);k.set_m_hasVertex3(!0);const l=this.addShape(k,b,c,d,e);box2d.instance.destroy(k);f.push(l);g.push(a[h].copy())}this.edgeLoops.push(g);f.forEach(h=>this.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()}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??=f;f=box2dCenterInertia(0<b?b:1,g,h);var l=k(e+f);d.set_mass(b);d.set_center(box2dTemp(vec2(g,h)));d.set_I(0<e&&0<k(l-f)?l:0);this.body.SetMassData(d);this.body.SetAwake(!0)}})}setFilterData(a=1,b=0,c=0){this.getFixtureList().forEach(d=>{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 0<this.getJointList().length}getJointList(){const a=[];for(let b=this.body.GetJointList();!box2d.isNull(b);b=b.get_next()){const c=b.get_joint(),d=box2dJoints.get(box2d.instance.getPointer(c));d&&!d.box2dJoint||a.push(d||box2d.castJointObject(c))}return a}}class Box2dStaticObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeStatic,f)}}class Box2dKinematicObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeKinematic,f)}}class Box2dTileLayer extends Box2dStaticObject{constructor(a){super(a.pos,a.size);this.tileLayer=a;this.addChild(a);this.buildCollision()}render(){}buildCollision(a=.2,b=0){this.destroyAllFixtures();const c=[],d=(k,l)=>k+l*this.size.x,e=(k,l)=>!c[d(k,l)]&&0<this.tileLayer.getCollisionData(vec2(k,l));for(let k=0;k<this.size.x;++k)for(let l=0;l<this.size.y;++l){if(!e(k,l))continue;var f=1;let m=1;for(var g=!0;e(k+f,l);)++f;for(;g;){for(var h=0;h<f;++h)if(!e(k+h,l+m)){g=!1;break}g&&++m}for(g=f;g--;)for(h=m;h--;)c[d(k+g,l+h)]=!0;g=vec2(f,m);f=vec2(k+f/2,l+m/2);this.addBox(g,f,0,0,a,b)}}}class Box2dRaycastResult{constructor(a,b,c,d){this.object=a.GetBody().object;this.fixture=a;this.point=b;this.normal=c;this.fraction=d}}class Box2dJoint{constructor(a){var b=a.get_bodyA();const c=a.get_bodyB();b=!box2d.isNull(b)&&!box2d.isNull(c);this.box2dJoint=0;b?(this.box2dJoint=box2d.castJointObject(box2d.world.CreateJoint(a)),box2d.instance.destroy(a),box2dJoints.set(box2d.instance.getPointer(this.box2dJoint),this)):box2d.instance.destroy(a)}destroy(){const a=this.box2dJoint;if(a){this.box2dJoint=0;box2dDestroyGears(this);var b=box2d.instance.getPointer(a);box2dWhenUnlocked(()=>{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(a,.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>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>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(a,0))}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(max(a,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(g);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(a,0));box2dWakeJoint(this.box2dJoint)}getMaxForce(){return this.box2dJoint.GetMaxForce()}setMaxTorque(a){this.box2dJoint.SetMaxTorque(max(a,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();c=c.GetFixtureB();const d=b.GetBody().object,e=c.GetBody().object;d&&e&&(d.beginContact(e,b,c),e.beginContact(d,c,b))};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(!(0<d&&Infinity>d))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)<d&&(c||f.getFixtureList().some(g=>!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<e)d=f,e=b;return d}pointCast(a,b=!0,c=!1){const d=box2dQueryObject("query","JSQueryCallback");d.ReportFixture=function(g){g=box2d.instance.wrapPointer(g,box2d.instance.b2Fixture);if(!c&&g.IsSensor()||b&&g.GetBody().GetType()!==box2d.bodyTypeDynamic||!g.TestPoint(box2dTemp(a)))return!0;g=g.GetBody().object;if(!g||g.destroyed)return!0;f=g;return!1};const e=box2dQueryObject("aabb","b2AABB");e.set_lowerBound(box2dTemp(a));e.set_upperBound(box2dTemp(a));let f;box2d.world.QueryAABB(d,e);debugRaycast&&debugRect(a,vec2(),f?"#f00":"#00f",0,0,!1,!1);return f}drawFixture(a,b,c,d=WHITE,e=BLACK,f=.1,g,h){a=box2d.castShapeObject(a.GetShape());switch(a.GetType()){case box2d.instance.b2Shape.e_polygon:var k=[];for(let l=a.GetVertexCount();l--;)k.push(box2d.vec2From(a.GetVertex(l)));drawPoly(k,d,f,e,b,c,g,!1,h);break;case box2d.instance.b2Shape.e_circle:k=a.get_m_radius();a=box2d.vec2From(a.get_m_p());drawCircle(b.add(a.rotate(c)),2*k,d,f,e,g,!1,h);break;case box2d.instance.b2Shape.e_edge:d=box2d.vec2From(a.get_m_vertex1()),a=box2d.vec2From(a.get_m_vertex2()),drawLine(d,a,f,e,b,c,g,!1,h)}}vec2From(a){return new Vector2(a.get_x(),a.get_y())}vec2FromPointer(a){a=box2d.instance.wrapPointer(a,box2d.instance.b2Vec2);return box2d.vec2From(a)}vec2dTo(a){return new box2d.instance.b2Vec2(a.x,a.y)}isNull(a){return!box2d.instance.getPointer(a)}castShapeObject(a){switch(a.GetType()){case box2d.instance.b2Shape.e_circle:return box2d.instance.castObject(a,box2d.instance.b2CircleShape);case box2d.instance.b2Shape.e_edge:return box2d.instance.castObject(a,box2d.instance.b2EdgeShape);case box2d.instance.b2Shape.e_polygon:return box2d.instance.castObject(a,box2d.instance.b2PolygonShape);case box2d.instance.b2Shape.e_chain:return box2d.instance.castObject(a,box2d.instance.b2ChainShape)}}castJointObject(a){switch(a.GetType()){case box2d.instance.e_revoluteJoint:return box2d.instance.castObject(a,box2d.instance.b2RevoluteJoint);case box2d.instance.e_prismaticJoint:return box2d.instance.castObject(a,box2d.instance.b2PrismaticJoint);case box2d.instance.e_distanceJoint:return box2d.instance.castObject(a,box2d.instance.b2DistanceJoint);case box2d.instance.e_pulleyJoint:return box2d.instance.castObject(a,box2d.instance.b2PulleyJoint);case box2d.instance.e_mouseJoint:return box2d.instance.castObject(a,box2d.instance.b2MouseJoint);case box2d.instance.e_gearJoint:return box2d.instance.castObject(a,box2d.instance.b2GearJoint);case box2d.instance.e_wheelJoint:return box2d.instance.castObject(a,box2d.instance.b2WheelJoint);case box2d.instance.e_weldJoint:return box2d.instance.castObject(a,box2d.instance.b2WeldJoint);case box2d.instance.e_frictionJoint:return box2d.instance.castObject(a,box2d.instance.b2FrictionJoint);case box2d.instance.e_ropeJoint:return box2d.instance.castObject(a,box2d.instance.b2RopeJoint);case box2d.instance.e_motorJoint:return box2d.instance.castObject(a,box2d.instance.b2MotorJoint)}}}async function box2dInit(){new Box2dPlugin(await Box2D());(function(){const a=new box2d.instance.JSDraw,b=d=>{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){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 p=c.offset(n),r=b.add(vec2(g-2*e));g=vec2(e);b=b.scale(.5).subtract(g.scale(.5));var q=l?-1:1,u=l?-h:h;drawTile(a,r,p,d,h,!1,f,k,l,m);for(var t=4;t--;){var v=t%2,z=b.multiply(vec2(v?1===t?1:-1:0,v?0:t?-1:1));v=vec2(v?e:r.x,v?r.y:e);const x=p.offset(n.multiply(vec2(1===t?1:3===t?-1:0,0===t?-q:2===t?q:0)));drawTile(a.add(z.rotate(u)),v,x,d,h,!1,f,k,l,m)}for(e=4;e--;)t=1<e,z=e&&3>e,r=b.multiply(vec2(t?-1:1,z?-1:1)),t=p.offset(n.multiply(vec2(t?-1:1,z?q:-q))),drawTile(a.add(r.rotate(u)),g,t,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),p=c.frame(1),r=c.frame(2);if(l&&!h){const z=[[0,0,1],[3,-1,1],[3,2,2]];drawSliceSnapped(a,b,e,(x,w)=>{const y=z[w][x];return 0>y?[r,0]:[1!==x&&1!==w?n:p,y*PI/2]},d,f,k,m)}else{e=min(e,abs(b.x)/2,abs(b.y)/2);var q=b.add(vec2(g-2*e));c=vec2(e);b=b.scale(.5).subtract(c.scale(.5));g=l?-1:1;var u=l?-h:h;drawTile(a,q,r,d,h,!1,f,k,l,m);for(var t=4;t--;){const z=h+t*PI/2;var v=t%2;const x=b.multiply(vec2(v?1===t?1:-1:0,v?0:t?-g:g));v=vec2(v?q.y:q.x,e);drawTile(a.add(x.rotate(u)),v,p,d,z,!1,f,k,l,m)}for(e=4;e--;)q=h+e*PI/2,t=b.multiply(vec2(!e||2<e?-1:1,1<e?-g:g)),drawTile(a.add(t.rotate(u)),c,n,d,q,!1,f,k,l,m)}}}class TileSlice{constructor(a,b=9,c,d){this.tileInfo=a;this.slices=b;this.borderSize=c;this.extraSpace=d}draw(a,b,c=WHITE,d,e=0,f=glEnable,g=drawScreenSpace,h){if(g)return this.drawScreen(a,b,c,d,e,f,h);9===this.slices?drawNineSlice(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g,h):3===this.slices?drawThreeSlice(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g,h):drawTile(a,b,this.tileInfo,c,e,!1,d,f,g,h)}drawScreen(a,b,c=WHITE,d,e=0,f=!1,g){9===this.slices?drawNineSliceScreen(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g):3===this.slices?drawThreeSliceScreen(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g):drawTile(a,b,this.tileInfo,c,e,!1,d,f,!0,g)}}function drawSliceSnapped(a,b,c,d,e,f,g,h){var k=(!g||!glEnable||!!h)&&(h||drawContext)?.getTransform?.(),l=getCanvasPixelRatio();const[m,n,p,r]=k?[k.a||1,k.d||1,k.e||0,k.f||0]:[l,l,0,0];l=(q,u,t,v)=>{var z=max(1,round(c*abs(t)));q=round((q-u/2)*t+v);var x=q+round(u*t);u=min(q,x);q=max(q,x);x=min(u+z,floor((u+q)/2));z=[u,x,max(q-z,x),q];return(0>t?z.reverse():z).map(w=>(w-v)/t)};k=l(a.x,b.x,m,p);a=l(a.y,b.y,n,r);for(b=3;b--;)for(l=3;l--;){const q=k[l+1]-k[l],u=a[b+1]-a[b];if(0>=q||0>=u)continue;const[t,v]=d(l,b),z=round(v/(PI/2))%2,x=vec2(k[l]+q/2-.5,a[b]+u/2-.5);drawTile(x,z?vec2(u,q):vec2(q,u),t,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)});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;m<n;++m)f.tiles.push(l.tile.frame(m))})}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:p}=l,r=n.context,q=k.x+2*c,u=k.y+2*c;m.frames.forEach((t,v)=>{const z=p.pos.x+v%p.columns*q+t.offset.x;v=p.pos.y+(v/p.columns|0)*u+t.offset.y;t.rotated?(r.save(),r.translate(z,v),r.rotate(-PI/2),r.drawImage(g,t.pos.x,t.pos.y,t.size.y,t.size.x,-t.size.y,0,t.size.y,t.size.x),r.restore()):r.drawImage(g,t.pos.x,t.pos.y,t.size.x,t.size.y,z,v,t.size.x,t.size.y)});n.glDirty=!0;e[m.name]=p}else console.warn("loadAtlas failed to load:",a,b),textureSheetLoadFailed(d,e)});return e}function textureSheetQueueJob(a,b){++textureSheetPendingCount;textureSheetQueue=textureSheetQueue.then(async()=>{try{await b()}catch(c){console.error(a+" failed:",c)}finally{if(!--textureSheetPendingCount)for(const c of textureSheets)try{c.updateTexture()}catch(d){console.error("texture sheet upload failed:",d)}}})}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),1<g.length&&g.every((h,k)=>h.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 tweenIsLerpable(a){return a&&"function"===typeof a.lerp}class Tween{constructor(a,b=0,c=1,d=1,e={}){tweenIsLerpable(b);this.callback=a;this.start=b;this.end=c;this.life=this.duration=d;this.ease=e.ease||Ease.LINEAR;this.useRealTime=!!e.useRealTime;this.paused=!!e.paused;this.thenCallback=this.onComplete=void 0;this.loopRemaining=0;this.listed=this.active=!1;this.activePass=0;this.lastTime=time;this.lastTimeReal=timeReal;this.target=void 0;tweenActivate(this);a(this.interp(d))}setEase(a){this.ease=a;return this}then(a){this.onComplete=a;return this}loop(a=Infinity){this.loopRemaining=a;this.thenCallback=()=>tweenLoopContinuation(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);this.callback(this.interp(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]<f?g=l:h=l}return e((g+h)/2)[1]}}};function tweenProperty(a,b,c,d,e=1,f={}){const g=b.split("."),h=g.pop();let k;k=new Tween(l=>{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=0<b?min(a.life,0)%b+b:1e-9}function tweenPassed(a){const b=a.duration;return 0<b?1+floor(-min(a.life,0)/b):1}function tweenNextIteration(a,b,c){a.loopRemaining-=b;tweenCarryOvershoot(a);a.thenCallback=c;tweenActivate(a);a.callback(a.interp(a.life));return!0}function tweenLoopContinuation(a){const b=tweenPassed(a);return a.loopRemaining<=b?!1:tweenNextIteration(a,b,()=>tweenLoopContinuation(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 g of tweenActive)g.active?d.push(tweenActive[f++]=g):g.listed=!1;tweenActive.length=f;try{for(let g=d.length;g--;){const h=d[g];if(!h.active||h.activePass>=e)continue;let k;c?(k=h.useRealTime?timeReal-h.lastTimeReal:time-h.lastTime,h.lastTime=time,h.lastTimeReal=timeReal):k=h.useRealTime?b:a;if(h.target?.destroyed)h.stop();else if(!(h.paused||0>=k))if(h.life-=k,1e-9<h.life)h.callback(h.interp(h.life));else{h.callback(h.interp(0));if(!h.active||h.activePass>=e)continue;tweenDeactivate(h);const l=h.thenCallback;h.thenCallback=void 0;if((!l||!l())&&h.onComplete)h.onComplete()}}}finally{d.length=0}}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.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<cameraScale?(this.zoomScale/cameraScale)**(1-this.zoomFollow):1}getDrawSize(){return this.size.scale(this.zoomFactor())}getDrawPositions(){var a=this.zoomFactor();const b=this.size.scale(a);var c=this.parallax,d=this.pos.subtract(cameraPos);const e=cameraPos.add(vec2(d.x*(1-c.x)*a,d.y*(1-c.y)*a));a=mainCanvasSize.scale(.5/(cameraScale||1));const f=cameraAngle?vec2(a.length()):a;a=(m,n)=>{if(!(m&&0<b[n]))return[0,0];m=cameraPos[n]+f[n]+b[n]/2-e[n];const p=ceil((cameraPos[n]-f[n]-b[n]/2-e[n])/b[n]);return[p,min(floor(m/b[n]),p+99)]};const[g,h]=a(this.wrapX,"x"),[k,l]=a(this.wrapY,"y");a=[];for(c=k;c<=l;++c)for(d=g;d<=h;++d)a.push(vec2(e.x+d*b.x,e.y+c*b.y));return a}render(){const a=this.getDrawSize();for(const b of this.getDrawPositions())this.draw(b,a,this.color,0,this.mirror,this.additiveColor,!1)}}function parallaxRidge(a,b,c){var d=b/256;const e=new Float32Array(a+1),f=b/2;let g=f,h=c.float(-d,d);for(let k=0;k<=a;++k)e[k]=g,g+=h-=.005*(g-f),.2>c.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]<e&&d.drawImage(h.canvas,0,0,1,e,f,g[f],1,e-g[f])}}const PATHFINDER_DIAGONAL_COST=Math.SQRT2,PATHFINDER_TILE_VEC=vec2(1);class PathFinderNode{constructor(a,b){this.pos=vec2(a,b);this.posWorld=vec2();this.walkable=!1;this.h=this.f=this.g=this.cost=0;this.parent=null;this.isClosed=this.isOpen=!1;this.heapIndex=0}resetSearch(){this.g=this.f=this.h=0;this.parent=null;this.isOpen=this.isClosed=!1}reset(){this.walkable=!1;this.cost=0;this.resetSearch()}isClear(){return this.walkable&&0===this.cost}}class PathFinder{constructor(a){isVector2(a)?(this.size=a.floor(),this.tileLayer=void 0):(this.size=a.size,this.tileLayer=a);this.heuristicWeight=1;this.maxLoop=void 0;this.searchGaveUp=!1;this.smoothPath=!0;this.debug=!1;this.debugTime=1;this.nodes=Array(this.size.x*this.size.y);for(a=0;a<this.size.y;++a)for(let b=0;b<this.size.x;++b)this.nodes[b+a*this.size.x]=new PathFinderNode(b,a);this.nodeDataBuilt=!1;this.collisionScratch=vec2();this.searchNodes=[]}isWalkable(a,b){return this.tileLayer?!(0<this.tileLayer.getCollisionData(this.collisionScratch.set(a,b))):!0}getCost(a,b){return 0}getNode(a,b){return 0>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;e<b;++e)for(let f=0;f<a;++f){const g=this.nodes[f+e*a];g.reset();const h=!!this.isWalkable(f,e),k=h?max(0,this.getCost(f,e)):0;g.walkable=h;g.cost=k;g.posWorld.set(f+.5+c,e+.5+d);this.debug&&0<this.debugTime&&(h?0<k&&debugRect(g.posWorld,PATHFINDER_TILE_VEC,rgb(1,0,0,min(.2,.05*k)),this.debugTime,0,!1,!1):debugRect(g.posWorld,PATHFINDER_TILE_VEC,rgb(1,0,0,.25),this.debugTime,0,!1,!1))}}aStarSearch(a,b){const c=this.searchNodes;for(var d of c)d.resetSearch();c.length=0;c.push(a);const e=[],f=(l,m)=>l.f<m.f-1e-9||l.f<m.f+1e-9&&l.h<m.h;d=l=>{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 p=0;for(;;){var n=2*p+1;const r=n+1;if(n>=e.length)break;n=r<e.length&&f(e[r],e[n])?r:n;if(!f(e[n],m))break;(e[p]=e[n]).heapIndex=p;p=n}(e[p]=m).heapIndex=p}return l};a.isOpen=!0;a.heapIndex=e.length;d(a);a=this.maxLoop??this.size.x*this.size.y;let h=0;for(this.searchGaveUp=!1;0<e.length;){const l=e[0];if(l===b)break;if(++h>a){this.searchGaveUp=!b.parent;break}g();l.isOpen=!1;l.isClosed=!0;this.debug&&0<this.debugTime&&debugRect(l.posWorld,PATHFINDER_TILE_VEC,rgb(1,1,1,.05),this.debugTime,0,!1,!1);for(let m=-1;1>=m;++m)for(let n=-1;1>=n;++n){if(0===n&&0===m)continue;const p=this.getNode(l.pos.x+n,l.pos.y+m);if(!p||!p.walkable||p.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+p.cost;if(!p.isOpen)p.isOpen=!0,p.heapIndex=e.length,e.push(p),c.push(p);else if(k>=p.g)continue;p.parent=l;p.g=k;k=abs(b.pos.x-p.pos.x);const r=abs(b.pos.y-p.pos.y);k=max(k,r)+(Math.SQRT2-1)*min(k,r);p.h=k;p.f=p.g+k*this.heuristicWeight;d(p)}}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-1;){var c=a[b-1],d=a[b],e=a[b+1],f=e.pos.x-c.pos.x,g=e.pos.y-c.pos.y,h=f*f+g*g;f=d.pos.x-c.pos.x;var k=d.pos.y-c.pos.y;g=e.pos.x-d.pos.x;var l=e.pos.y-d.pos.y;if(1===h)this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(.5,0,.5,.5),this.debugTime,!1,!1),a.splice(b,1),b=max(1,b-1);else{if(2===h){if(this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(1,0,0,.5),this.debugTime,!1,!1),c.pos.y===d.pos.y&&e.pos.x===d.pos.x?(d=c.pos.x,e=e.pos.y):(d=e.pos.x,e=c.pos.y),(d=this.getNode(d,e))&&d.isClear()){a.splice(b,1);b=max(1,b-1);continue}}else if(5===h){this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(1,1,0,.5),this.debugTime,!1,!1);k=2<=b?a[b-2]:c;0===f||0===g?(f=e.pos.x,g=d.pos.y,h=c.pos.x,c=d.pos.y):(f=d.pos.x,g=e.pos.y,h=d.pos.x,c=c.pos.y);l=f-k.pos.x;const m=g-k.pos.y,n=h-k.pos.x;k=c-k.pos.y;k=l*l+m*m<n*n+k*k;if((k=this.getNode(k?f:h,k?g:c))&&k!==d&&k.isClear()&&(d=this.getNode(e.pos.x+h-f,e.pos.y+c-g))&&d.isClear()){a[b]=k;b=max(1,b-1);continue}}else if(4===h||8===h)if(this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(0,1,0,.5),this.debugTime,!1,!1),f===g&&k===l){++b;continue}else if(c.pos.y===e.pos.y?(e=d.pos.x,d=c.pos.y):(e=c.pos.x,d=d.pos.y),(d=this.getNode(e,d))&&d.isClear()){a[b]=d;b=max(1,b-1);continue}++b}}}smoothPathStringPull(a){if(!(2>=a.length)){var b=a.slice(),c=b.length-1,d=[];for(var e=1;e<c;++e){var f=b[e-1].pos,g=b[e].pos;const h=b[e+1].pos;(g.x-f.x)*(h.y-f.y)!==(g.y-f.y)*(h.x-f.x)&&d.push(e)}d.push(c);a.length=0;a.push(b[0]);for(let h=0;h<c;){f=h+1;if(b[h].isClear()){e=k=>b[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;c<a.length-1;++c){const d=a[b-1],e=a[c],f=a[c+1];(e.pos.x-d.pos.x)*(f.pos.y-d.pos.y)!==(e.pos.y-d.pos.y)*(f.pos.x-d.pos.x)&&(a[b++]=e)}a[b++]=a[a.length-1];a.length=b}}isNodeClear(a,b){a=this.getNode(a,b);return null!==a&&a.isClear()}isLineClear(a,b){const c=b.x-a.x,d=b.y-a.y;var e=abs(c);const f=abs(d),g=sign(c),h=sign(d);let k=a.x,l=a.y;if(f===e){for(;k!==b.x;){if(!(k===a.x||this.isNodeClear(k,l)&&this.isNodeClear(k,l-h))||!this.isNodeClear(k,l+h))return!1;k+=g;l+=h}if(!this.isNodeClear(b.x,b.y-h))return!1}else if(f<e)if(0===d)for(k+=g;k!==b.x;){if(!this.isNodeClear(k,l))return!1;k+=g}else{for(e=a.y;k!==b.x;){l=a.y+Math.trunc(d*(k-a.x)/c);if(!(e===l||this.isNodeClear(k-g,l+h)&&this.isNodeClear(k,l-h)))return!1;e=l;if(k!==a.x&&!this.isNodeClear(k,l))return!1;l+=h;if(!this.isNodeClear(k,l))return!1;k+=g}if(!this.isNodeClear(b.x,b.y-h))return!1}else if(0===c)for(l+=h;l!==b.y;){if(!this.isNodeClear(k,l))return!1;l+=h}else{for(e=a.x;l!==b.y;){k=a.x+Math.trunc(c*(l-a.y)/d);if(!(e===k||this.isNodeClear(k+g,l-h)&&this.isNodeClear(k-g,l)))return!1;e=k;if(l!==a.y&&!this.isNodeClear(k,l))return!1;k+=g;if(!this.isNodeClear(k,l))return!1;l+=h}if(!this.isNodeClear(b.x-g,b.y))return!1}return!0}findPath(a,b,c=!0){this.searchGaveUp=!1;!c&&this.nodeDataBuilt||this.buildNodeData();c=d=>d.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<this.debugTime&&0<b.length){for(a=1;a<b.length;++a)debugLine(b[a-1],b[a],RED,.1,this.debugTime,!1);for(const d of b)debugCircle(d,.5,rgb(1,0,0,.3),this.debugTime,!1,!1);debugCircle(b[0],.5,rgb(0,1,0,.5),this.debugTime,!1,!1);debugCircle(b[b.length-1],.5,rgb(0,1,0,.5),this.debugTime,!1,!1)}return b}}function pathFinderNearestNode(a,b,c,d){var e=a.worldToTile(b);const f=e.x;e=e.y;let g=null,h=0;for(let m=0;m<=c;++m){var k=max(0,m-.5);if(g&&k*k>=h)break;for(k=-m;k<=m;++k)for(let n=-m;n<=m;++n){if(0<m&&abs(n)!==m&&abs(k)!==m)continue;const p=a.getNode(f+n,e+k);if(!p||!d(p))continue;var l=p.posWorld.x-b.x;const r=p.posWorld.y-b.y;l=l*l+r*r;if(!g||l<h)g=p,h=l}}return g}function vec3(a=0,b,c){return void 0===b?new Vector3(a,a,a):new Vector3(a,b,void 0===c?0:c)}function isVector3(a){return a instanceof Vector3&&a.isValid()}function ASSERT_VECTOR3_VALID(a){}function randVector3(a=1,b=PI){b=rand(cos(b),1);const c=(1-b*b)**.5,d=rand(2*PI);return new Vector3(c*cos(d)*a,b*a,c*sin(d)*a)}function randInSphere(a=1,b=0){if(0>=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=(.99<abs(b.y)?vec3(0,0,0<b.y?-1:1):vec3(0,1,0)).cross(b).normalize());const d=b.cross(c);return new Matrix4([c.x,c.y,c.z,0,d.x,d.y,d.z,0,b.x,b.y,b.z,0,a.x,a.y,a.z,1])}copy(){return new Matrix4(this.m)}multiply(a){const b=this.m;a=a.m;const c=matrix4Scratch;for(let d=0;4>d;++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,p,r,q,u,t]=a,v=b*g-c*f,z=b*h-d*f,x=b*k-e*f,w=c*h-d*g,y=c*k-e*g,A=d*k-e*h,C=l*q-m*r,D=l*u-n*r,B=l*t-p*r,E=m*u-n*q,F=m*t-p*q,H=n*t-p*u;let G=v*H-z*F+x*E+w*B-y*D+A*C;if(!G)return this;G=1/G;a[0]=(g*H-h*F+k*E)*G;a[1]=(d*F-c*H-e*E)*G;a[2]=(q*A-u*y+t*w)*G;a[3]=(n*y-m*A-p*w)*G;a[4]=(h*B-f*H-k*D)*G;a[5]=(b*H-d*B+e*D)*G;a[6]=(u*x-r*A-t*z)*G;a[7]=(l*A-n*x+p*z)*G;a[8]=(f*F-g*B+k*C)*G;a[9]=(c*B-b*F-e*C)*G;a[10]=(r*y-q*x+t*v)*G;a[11]=(m*x-l*y-p*v)*G;a[12]=(g*D-f*E-h*C)*G;a[13]=(b*E-c*D+d*C)*G;a[14]=(q*z-r*w-u*v)*G;a[15]=(l*w-m*z+n*v)*G;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=Math.asin(clamp(-h,-1,1));return.999999>abs(h)?new Vector3(k,atan2(g,e),atan2(b,f)):new Vector3(k,atan2(a[4]/d*-h,a[0]/c),0)}toString(){const a=this.m;let b="";for(let c=0;4>c;++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=(p,r,q)=>p.x*abs(r[0].dot(q))+p.y*abs(r[1].dot(q))+p.z*abs(r[2].dot(q));let m,n=Infinity;a=(p,r)=>{var q=p.lengthSquared();if(1e-12>q)return!1;p=p.scale(q**-.5);q=g.dot(p);const u=l(h,c,p)+l(k,f,p)-abs(q);if(0>=u)return!0;u*r<n&&(n=u*r,m=p.scale(0>q?-u:u));return!1};for(const p of[...c,...f])if(a(p,1))return;for(const p of c)for(const r of f)if(a(p.cross(r),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(h<k||h>m)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;function render3DFaceNormal(a,b,c,d=a){a=c.subtract(a).cross(d.subtract(b));return a.lengthSquared()?a.normalize():RENDER3D_DEFAULT_NORMAL}function render3DQuadStrip(a,b,c,d){return[a,b,d,c]}function render3DQuadValues(a){return isArray(a)?render3DQuadStrip(...a):a}function render3DCanDraw(){return render3D.program?render3D.isRendering:!1}const RENDER3D_STATE_FIELDS="blend additive depthTest depthWrite cullBackFaces mirrored lighting emissive receiveShadow specular pixelated shader normalMap normalScale shininess reflectivity emissiveMap emissiveMapColor".split(" ");function render3DCaptureBatchState(){const a=render3D,b=a.drawState;return{blend:b.blend,additive:b.additive,depthTest:b.depthTest,depthWrite:b.depthWrite,cullBackFaces:b.cullBackFaces,mirrored:b.mirrored,lighting:b.lighting,emissive:b.emissive,receiveShadow:b.receiveShadow,specular:b.specular,pixelated:b.pixelated,shader:b.shader,normalMap:b.normalMap,normalScale:b.normalScale,shininess:b.shininess,reflectivity:b.reflectivity,emissiveMap:b.emissiveMap,emissiveMapColor:(b.emissiveMapColor||WHITE).copy(),version:a.stateVersion}}function render3DApplyBatchState(a){const b=render3D;b.blend=a.blend;b.additive=a.additive;b.depthTest=a.depthTest;b.depthWrite=a.depthWrite;b.cullBackFaces=a.cullBackFaces;b.mirrored=a.mirrored;b.lighting=a.lighting;b.emissive=a.emissive;b.receiveShadow=a.receiveShadow;b.specular=a.specular;b.pixelated=a.pixelated;b.shader=a.shader;b.normalMap=a.normalMap;b.normalScale=a.normalScale;b.shininess=a.shininess;b.reflectivity=a.reflectivity;b.emissiveMap=a.emissiveMap;b.emissiveMapColor=a.emissiveMapColor}function render3DStateChanged(a){const b=render3D;if(a.version===b.stateVersion)return!1;const c=b.drawState,d=a.emissiveMapColor;if(c.blend!==a.blend||c.additive!==a.additive||c.depthTest!==a.depthTest||c.depthWrite!==a.depthWrite||c.cullBackFaces!==a.cullBackFaces||c.mirrored!==a.mirrored||c.lighting!==a.lighting||c.emissive!==a.emissive||c.receiveShadow!==a.receiveShadow||c.specular!==a.specular||c.pixelated!==a.pixelated||c.shader!==a.shader||c.normalMap!==a.normalMap||c.normalScale!==a.normalScale||c.shininess!==a.shininess||c.reflectivity!==a.reflectivity||c.emissiveMap!==a.emissiveMap||c.emissiveR!==d.r||c.emissiveG!==d.g||c.emissiveB!==d.b)return!0;a.version=b.stateVersion;return!1}function render3DSphereVisible(a,b,c,d){const e=render3D.shadowPass&&!render3D.depthPass?render3D.shadowPlanes:render3D.frustumPlanes;for(let f=0;f<e.length;++f){const g=e[f];if(g[0]*a+g[1]*b+g[2]*c+g[3]<-d)return!1}return!0}function render3DWithState(a,b){const c=render3D,d={};for(const e in a)d[e]=c[e],c[e]=a[e];try{return b()}finally{Object.assign(c,d)}}function render3DIsAfter2D(a){return!!(a.renderAfter2D??render3D.renderAfter2D)}function render3DSize3(a){return isNumber(a)?vec3(a):a}function render3DSize2(a){return isNumber(a)?vec2(a):a}function render3DMatrix(a){return a instanceof Vector3?buildMatrix(a):a}function render3DNormalMatrix(a){return a.copy().invert().transpose()}function render3DMirrors(a){return 0>a.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;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.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=!!a?.transparent)}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.length<c+RENDER3D_INSTANCE_FLOATS)d=new Float32Array(max(64*RENDER3D_INSTANCE_FLOATS,b?2*b.length:0)),b&&d.set(b),a.instanceData=d;return c}function render3DFlushInstances(a){const b=render3D,c=glContext;for(const e of a?[a]:b.instanceMeshes){const f=e.instanceCount;e.instanceCount=0;if(!f||!e.buffer)continue;var d=b.instanceBuffers;d=d[b.instanceBufferIndex=(b.instanceBufferIndex+1)%d.length];c.bindBuffer(c.ARRAY_BUFFER,d);c.bufferData(c.ARRAY_BUFFER,e.instanceData,c.DYNAMIC_DRAW,0,f*RENDER3D_INSTANCE_FLOATS);const g=e.instanceState;void 0!==e.instanceMirrored&&(g.cullBackFaces=!e.doubleSided,g.mirrored=e.instanceMirrored);e.instanceUnlit&&(g.lighting=!1);render3DDrawInstanced(e,d,f,e.instanceTextureInfo,g)}a?(a=b.instanceMeshes.indexOf(a),0>a||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,p=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,p,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&&0<c.color.a&&0<c.intensity&&(c.directional||0<c.radius));if(a.length>RENDER3D_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&&0<a.coneAngle&&0<a.radius&&0<a.intensity&&0<a.color.a?a:void 0}const RENDER3D_SHADOW_CONE_MAX=1.35;function render3DLightCone(a){var b=a===render3DShadowCaster()?RENDER3D_SHADOW_CONE_MAX:PI,c=a.directional?0:min(a.coneAngle,b);if(!(0<c))return[0,0,0,-1];b=cos(c);c=cos(c*(1-clamp(a.coneSoftness)));c=1/max(c-b,1e-4);a=a.getForward3D();return[a.x*c,a.y*c,a.z*c,b*c]}const render3DCircleCache=new Map;function render3DCircle(a){a|=0;let b=render3DCircleCache.get(a);if(!b){b=new Float32Array(2*a+2);for(let c=0;c<=a;++c){const d=c/a*2*PI;b[2*c]=cos(d);b[2*c+1]=sin(d)}render3DCircleCache.set(a,b)}return b}function render3DLookRotation(a,b){a=a.normalize();return a.lengthSquared()?1e-9>abs(a.x)+abs(a.z)?vec3(0<a.y?PI/2:-PI/2,b.y,0):vec3(Math.asin(clamp(a.y,-1,1)),atan2(-a.x,-a.z),0):b}class Render3DPlugin{constructor(){render3D=this;this.drawState={blend:!1,additive:!1,depthTest:!0,depthWrite:!0,cullBackFaces:!1,mirrored:!1,lighting:!0,emissive:0,receiveShadow:!0,specular:0,pixelated:!1,shader:void 0,normalMap:void 0,normalScale:1,shininess:16,reflectivity:0,emissiveMap:void 0,emissiveMapColor:WHITE,emissiveR:1,emissiveG:1,emissiveB:1};this.stateVersion=0;this.camera=new Camera3D;this.sunDirection=vec3(-.3,1,.5);this.sunColor=WHITE.copy();this.ambientColor=hsl(0,0,.3);this.fogColor=this.ambientGroundColor=void 0;this.fogEnd=this.fogStart=0;this.gravity=vec3();this.softShadowHeight=0;this.shadows=this.depthTexture=this.smoothShading=!1;this.soundDefaultRange=100;this.shadowMapSize=1024;this.shadowLight=void 0;this.shadowRange=40;this.shadowCenter=void 0;this.shadowBias=.003;this.shadowSoftness=1;this.sky=this.onRenderTransparent=this.onRenderOpaque=void 0;this.renderAfter2D=!1;this.mipmaps=this.instancing=this.frustumCulling=this.sortTransparent=!0;this.anisotropy=4;this.boxMesh=buildBox();this.sphereMesh=buildSphere(1,16,8,!0);this.planeMesh=buildGrid();this.planeMesh.doubleSided=!1;this.planeMeshDoubleSided=buildGrid();this.billboardMesh=(new Mesh).addStrip([vec3(-.5,.5,0),vec3(-.5,-.5,0),vec3(.5,.5,0),vec3(.5,-.5,0)],vec3(0,0,1),RENDER3D_QUAD_UVS);this.billboardMesh.doubleSided=!0;this.shadowPass=this.isRendering=!1;this.viewMatrix=new Matrix4;this.projectionMatrix=new Matrix4;this.viewProjection=new Matrix4;this.shadowMatrix=new Matrix4;this.gelAxes=[1,0,0,1];this.cameraRight=vec3(1,0,0);this.cameraUp=vec3(0,1,0);this.cameraForward=vec3(0,0,-1);this.cameraBack=vec3(0,0,1);this.frustumPlanes=[];this.shadowPlanes=[];this.currentProgram=this.program=void 0;this.lightCount=0;this.whiteTexture=this.vao=this.shadowShader=void 0;this.samplers=new Map;this.shadowFramebuffer=this.shadowTexture=this.samplerKey=void 0;this.shadowTextureSize=0;this.cameraDepthFramebuffer=this.cameraDepthTexture=void 0;this.cameraDepthHeight=this.cameraDepthWidth=0;this.depthPass=!1;this.contextGeneration=0;this.uniforms=new Map;this.uniformValues={};this.shadowMapDrawn=!1;this.passIsDefault=!0;this.lightPositions=new Float32Array(4*RENDER3D_MAX_LIGHTS);this.lightColors=new Float32Array(4*RENDER3D_MAX_LIGHTS);this.lightCones=new Float32Array(4*RENDER3D_MAX_LIGHTS);this.shadowLightIndex=-1;this.shadowDepthBias=0;this.streamBuffer=void 0;this.instanceBuffers=[];this.instanceBufferIndex=0;this.instanceMeshes=[];this.attribValues=[];this.streamData=new ArrayBuffer(RENDER3D_MAX_STREAM_VERTS*RENDER3D_VERTEX_BYTES);this.streamFloats=new Float32Array(this.streamData);this.streamInts=new Uint32Array(this.streamData);this.streamCount=0;this.streamState=this.streamTileInfo=void 0;this.streamUnlit=!1;this.transparentQueue=this.capture=void 0;render3DInitGL();engineAddPlugin(void 0,render3DRender,render3DContextLost,render3DContextRestored,render3DPreRender)}get lighting(){return this.drawState.lighting}set lighting(a){const b=this.drawState;b.lighting===a||(b.lighting=a,++this.stateVersion)}get emissive(){return this.drawState.emissive}set emissive(a){const b=this.drawState;b.emissive===a||(b.emissive=a,++this.stateVersion)}get additive(){return this.drawState.additive}set additive(a){const b=this.drawState;b.additive===a||(b.additive=a,++this.stateVersion)}get depthTest(){return this.drawState.depthTest}set depthTest(a){const b=this.drawState;b.depthTest===a||(b.depthTest=a,++this.stateVersion)}get depthWrite(){return this.drawState.depthWrite}set depthWrite(a){const b=this.drawState;b.depthWrite===a||(b.depthWrite=a,++this.stateVersion)}get cullBackFaces(){return this.drawState.cullBackFaces}set cullBackFaces(a){const b=this.drawState;b.cullBackFaces===a||(b.cullBackFaces=a,++this.stateVersion)}get mirrored(){return this.drawState.mirrored}set mirrored(a){const b=this.drawState;b.mirrored===a||(b.mirrored=a,++this.stateVersion)}get specular(){return this.drawState.specular}set specular(a){const b=this.drawState;b.specular===a||(b.specular=a,++this.stateVersion)}get shininess(){return this.drawState.shininess}set shininess(a){const b=this.drawState;b.shininess===a||(b.shininess=a,++this.stateVersion)}get normalMap(){return this.drawState.normalMap}set normalMap(a){const b=this.drawState;b.normalMap===a||(b.normalMap=a,++this.stateVersion)}get normalScale(){return this.drawState.normalScale}set normalScale(a){const b=this.drawState;b.normalScale===a||(b.normalScale=a,++this.stateVersion)}get reflectivity(){return this.drawState.reflectivity}set reflectivity(a){const b=this.drawState;b.reflectivity===a||(b.reflectivity=a,++this.stateVersion)}get emissiveMap(){return this.drawState.emissiveMap}set emissiveMap(a){const b=this.drawState;b.emissiveMap===a||(b.emissiveMap=a,++this.stateVersion)}get emissiveMapColor(){return this.drawState.emissiveMapColor}set emissiveMapColor(a){const b=this.drawState,c=a||WHITE;b.emissiveMapColor=a;if(c.r!==b.emissiveR||c.g!==b.emissiveG||c.b!==b.emissiveB)b.emissiveR=c.r,b.emissiveG=c.g,b.emissiveB=c.b,++this.stateVersion}get shader(){return this.drawState.shader}set shader(a){const b=this.drawState;b.shader===a||(b.shader=a,++this.stateVersion)}get receiveShadow(){return this.drawState.receiveShadow}set receiveShadow(a){const b=this.drawState;b.receiveShadow===a||(b.receiveShadow=a,++this.stateVersion)}get pixelated(){return this.drawState.pixelated}set pixelated(a){const b=this.drawState;b.pixelated===a||(b.pixelated=a,++this.stateVersion)}get blend(){return this.drawState.blend}set blend(a){const b=this.drawState;b.blend===a||(b.blend=a,++this.stateVersion)}updateMatrices(a=mainCanvasSize.y?mainCanvasSize.x/mainCanvasSize.y:1){const b=this.camera;b.align2D&&b.update2D();const c=b.getMatrix();this.viewMatrix=c.copy().invert();this.projectionMatrix=b.getProjectionMatrix(a);this.viewProjection=this.projectionMatrix.copy().multiply(this.viewMatrix);a=c.m;this.cameraRight=render3DAxis(a,0);this.cameraUp=render3DAxis(a,4);this.cameraBack=render3DAxis(a,8);this.cameraForward=this.cameraBack.scale(-1);this.frustumPlanes=render3DFrustumPlanes(this.viewProjection)}worldToClip(a){const b=this.viewProjection.m,c=b[3]*a.x+b[7]*a.y+b[11]*a.z+b[15],d=(b[2]*a.x+b[6]*a.y+b[10]*a.z+b[14])/c;if(!(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<c.distance)&&(c={object:d,distance:b});return c}playSound(a,b,c=1,d=1,e=1,f=!1,g=!1){b=b.subtract(this.camera.pos);const h=a.rangeIsDefault?this.soundDefaultRange:a.range;if(h){const k=b.length();if(k>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),p=isArray(d),r=p?0:(d||WHITE).rgbaInt();for(let q=0;q<g;++q){const u=render3DStripIndex(q,f),t=a[u],v=n?c[u]:c||RENDER3D_DEFAULT_UV;render3DWriteVertex(k,l,this.streamCount++*RENDER3D_VERTEX_FLOATS,t.x,t.y,t.z,m?b[u]:b||RENDER3D_DEFAULT_NORMAL,h.x+v.x*h.w,h.y+v.y*h.h,p?d[u].rgbaInt():r)}}}}drawStripUnlit(a,b,c,d,e){render3DWithState({lighting:!1},()=>this.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||e.additive?d:c).push(e);b&&this.sky&&this.drawSky();this.blend=!1;this.depthWrite=!0;e=(f,g)=>f.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&&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();const{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=.99<abs(c.y)?vec3(0,0,1):vec3(0,1,0);var d=a.radius,e=min(max(d/500,.02),d/2),f=2*min(a.coneAngle,RENDER3D_SHADOW_CONE_MAX)+.1;b=Matrix4.lookAt(b,b.add(c),g);this.shadowMatrix=Matrix4.perspective(f,1,e,d).multiply(b.copy().invert());f=b.m;b=render3DObjectMatrix(a).m;a=vec3(b[0],b[1],b[2]).normalize();b=vec3(b[4],b[5],b[6]).normalize();c=vec3(f[0],f[1],f[2]);f=vec3(f[4],f[5],f[6]);this.gelAxes=[a.dot(c),a.dot(f),b.dot(c),b.dot(f)];this.shadowPlanes=render3DFrustumPlanes(this.shadowMatrix);this.shadowDepthBias=this.shadowBias*d*d*e/(d-e)}else this.shadowDepthBias=this.shadowBias,d=0<this.shadowRange?this.shadowRange:1,e=d/2,a=this.sunDirection.normalize(),f=this.shadowCenter||this.camera.pos.add(this.cameraForward.scale(.8*e)),a=Matrix4.lookAt(f.add(a.scale(d)),f).invert(),f=d/(this.shadowTextureSize||this.shadowMapSize),b=a.m,b[12]=round(b[12]/f)*f,b[13]=round(b[13]/f)*f,this.shadowMatrix=Matrix4.orthographic(-e,e,-e,e,0,2*d).multiply(a),this.shadowPlanes=render3DFrustumPlanes(this.shadowMatrix)}setSky(a=hsl(.6,.8,.55),b=hsl(.6,1,.9),c=b,d=.5){this.sky?.dispose();this.sky=buildSky(a,b,c);this.fogColor=b.copy();this.ambientColor=a.scale(d,1);this.ambientGroundColor=c.scale(d,1);return this.sky}setFog(a,b,c){this.fogStart=a;this.fogEnd=b;c&&(this.fogColor=c.copy())}drawBox(a,b=1,c=WHITE,d){this.drawMesh(this.boxMesh,buildMatrix(a,d,render3DSize3(b)),void 0,c)}drawSphere(a,b=1,c=WHITE){this.drawMesh(this.sphereMesh,buildMatrix(a,void 0,vec3(b)),void 0,c)}drawBillboard(a,b=vec2(1),c,d=WHITE,e=0,f=!1){if(this.capture)return this.drawStripUnlit(render3DBillboardCorners(a,b,e,f),this.cameraBack,RENDER3D_QUAD_UVS,d.copy(),c);if(this.transparentQueue){const A=a.copy(),C=b.copy(),D=d.copy();return this.queueTransparent(A,()=>this.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 p=a.x,r=a.y;a=a.z;var q=this.cameraBack;d=d.rgbaInt();var u=m.x,t=m.y,v=u+m.w;m=t+m.h;var z=this.streamFloats,x=this.streamInts,w=RENDER3D_VERTEX_FLOATS,y=this.streamCount*w;this.streamCount+=6;render3DWriteVertex(z,x,y,p-k+b,r-l+g,a-h+n,q,u,t,d);render3DWriteVertex(z,x,y+=w,p-k+b,r-l+g,a-h+n,q,u,t,d);render3DWriteVertex(z,x,y+=w,p-k-b,r-l-g,a-h-n,q,u,m,d);render3DWriteVertex(z,x,y+=w,p+k+b,r+l+g,a+h+n,q,v,t,d);render3DWriteVertex(z,x,y+=w,p+k-b,r+l-g,a+h-n,q,v,m,d);render3DWriteVertex(z,x,y+=w,p+k-b,r+l-g,a+h-n,q,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=2<f&&1e-12>a[0].distanceSquared(a[f-1]);for(let q=0;q<f;++q){const u=a[q];var p=isArray(b)?b[q]:b;let t=isArray(d)?d[q]:d;this.transparentQueue&&(t=t.copy());var r=e&&(isArray(e)?e[q]:e);const v=a[q<f-1?q+1:n?1:q],z=a[0<q?q-1:n?f-2:q];r=r||v.subtract(z).cross(l);1e-12<r.lengthSquared()&&(m=r.normalize());p=m.scale(p/2);g.push(u.add(p),u.subtract(p));h?.push(vec2(q/(f-1),0),vec2(q/(f-1),1));k.push(t,t)}render3DWithState({lighting:!1,cullBackFaces:!1},()=>this.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]),p=a*h/3,r=a*(h+1)/3;for(let q=0;q<=c;++q){const u=g[2*q],t=g[2*q+1];k.push(e(u,t,r),e(u,t,p));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}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,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){return"#version 300 es\nprecision highp float;uniform vec4 lightDir,lightColor,ambientFog,ambientGround,fogColor,shadowParams;uniform vec4 extraLights["+RENDER3D_MAX_LIGHTS+"],extraLightColors["+RENDER3D_MAX_LIGHTS+"];uniform vec4 extraLightCones["+RENDER3D_MAX_LIGHTS+"];uniform int extraLightCount;uniform vec3 cameraPos;uniform vec4 materialParams,emissiveTint,skyTop,skyHorizon,skyBottom,gelAxes;uniform sampler2D tex,normalTex,emissiveTex,gelTex;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?RENDER3D_SNIPPET_NAMES+a+"\n":"")+"void main(){"+(a?"vec4 t;mainImage(t,T);":"vec4 t=texture(tex,T);")+"if(premultipliedTexture&&t.a>0.)t.rgb/=t.a;if(shadowParams.w>0.&&t.a<.5)discard;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);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,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.){float z=distance(cameraPos,P);c.rgb=mix(c.rgb,shadowParams.w<0.?vec3(0):fogColor.rgb,smoothstep(fogColor.a,ambientFog.a,z));}o=vec4(c.rgb,shadowParams.w>0.?1.:c.a);}"}function render3DShaderProgram(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.uniform4fv(render3DUniform("gelAxes"),c.gelAxes);const d=c.camera.pos;b.uniform3f(render3DUniform("cameraPos"),d.x,d.y,d.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),b.uniform3f(render3DUniform("iResolution"),glCanvas.width,glCanvas.height,1))}function render3DInitGL(){if(!headlessMode)if(glEnable&&glContext){var a=glContext,b=render3D;glFlush();b.uniforms=new Map;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;}");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("Render3DPlugin: WebGL not enabled, construct the plugin in gameInit with glEnable set")}function render3DContextLost(){const a=render3D;a.program=a.currentProgram=a.shadowShader=a.vao=a.streamBuffer=a.whiteTexture=void 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);0<a.reflectivity&&(a=b.sky&&render3DSkyColors.get(b.sky),c=b.ambientColor,b=b.ambientGroundColor||c,d=a?a[0]:c,e=a?a[2]:b,render3DUniform4f("skyTop",d.r,d.g,d.b,1),render3DUniform4f("skyBottom",e.r,e.g,e.b,1),a?render3DUniform4f("skyHorizon",a[1].r,a[1].g,a[1].b,1):render3DUniform4f("skyHorizon",(c.r+b.r)/2,(c.g+b.g)/2,(c.b+b.b)/2,1))}let render3DBoundMaps=[];function render3DBindMap(a,b,c){const d=render3DBoundMaps,e=!!b&&c.pixelated;if(d[a]!==b||d[a+2]!==e)d[a]=b,d[a+2]=e,render3DBindTexture(b,c,a)}function render3DUniform4f(a,b,c,d,e){let f;const g=(f=render3D.uniformValues)[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.uniform4f(render3DUniform(a),b,c,d,e)}function render3DUniform1i(a,b){const c=render3D.uniformValues;c[a]!==b&&(c[a]=b,glContext.uniform1i(render3DUniform(a),b))}function render3DBindVertexBuffer(a){const b=glContext;b.bindBuffer(b.ARRAY_BUFFER,a);for(const c of RENDER3D_ATTRIBS)b.vertexAttribPointer(c[0],c[1],c[2],c[3],RENDER3D_VERTEX_BYTES,c[4])}function render3DBindMesh(a){render3DBindVertexBuffer(a.buffer);glContext.bindBuffer(glContext.ELEMENT_ARRAY_BUFFER,a.indexBuffer)}function render3DTextureOf(a){return a instanceof TileInfo?a.textureInfo:a}const render3DLevel=[];function render3DLevelLeave(a){a=render3DLevel.indexOf(a);0<=a&&render3DLevel.splice(a,1)}function render3DLevelAssertPlaced(a){}const render3DTileUVRect={x:0,y:0,w:1,h:1},render3DWholeTiles=new WeakSet;function render3DGetTileUVs(a){if(!(a instanceof TileInfo&&a.textureInfo)||render3DWholeTiles.has(a))return RENDER3D_FULL_UV_RECT;const b=a.textureInfo.sizeInverse,c=render3DTileUVRect,d=b.x*a.bleed,e=b.y*a.bleed;c.x=a.pos.x*b.x+d;c.y=a.pos.y*b.y+e;c.w=a.size.x*b.x-2*d;c.h=a.size.y*b.y-2*e;return c}function render3DSetDrawUniforms(a,b,c,d,e=render3D){var f=glContext,g=render3D;d||=render3DGetTileUVs(b);render3DDrawAttribs(a.m,c,d);render3DBindTexture(b,e);if(g.shadowPass)e=e.blend?1:0,render3DShadowCut!==e&&glContext.uniform1f(render3DUniform("cut",g.shadowShader),render3DShadowCut=e);else{a=e.shader?render3DShaderProgram(e.shader):g.program;a===g.currentProgram||render3DUseProgram(a);e.blend?(f.enable(f.BLEND),a=e.additive?f.ONE:f.ONE_MINUS_SRC_ALPHA,f.blendFuncSeparate(f.SRC_ALPHA,a,f.ONE,a)):f.disable(f.BLEND);e.depthTest?f.enable(f.DEPTH_TEST):f.disable(f.DEPTH_TEST);f.depthMask(e.depthWrite);e.cullBackFaces?f.enable(f.CULL_FACE):f.disable(f.CULL_FACE);f.frontFace(e.mirrored?f.CCW:f.CW);a=g.sunDirection;c=-(a.length()||1);d=g.sunColor;var h=g.ambientColor;f=g.fogColor||canvasClearColor;render3DUniform4f("lightDir",a.x/c,a.y/c,a.z/c,e.lighting?e.emissive:1);render3DUniform4f("lightColor",d.r,d.g,d.b,e.specular);render3DUniform4f("ambientFog",h.r,h.g,h.b,g.fogEnd);(a=g.ambientGroundColor)?render3DUniform4f("ambientGround",a.r,a.g,a.b,1):render3DUniform4f("ambientGround",0,0,0,0);render3DUniform4f("fogColor",f.r,f.g,f.b,g.fogEnd?min(g.fogStart,g.fogEnd-.001):g.fogStart);f=g.shadows&&g.passIsDefault&&e.receiveShadow?1:0;render3DUniform4f("shadowParams",f&&0<=g.shadowLightIndex?2+g.shadowLightIndex:f,g.shadowDepthBias,g.shadowSoftness/g.shadowTextureSize,e.blend?e.additive?-1:0:1);g=render3DTextureOf(b);render3DUniform1i("premultipliedTexture",+!(!g?.glTexture||!glPremultipliedTextures.has(g.glTexture)));render3DSetMaterialUniforms(e)}}function render3DFrustumPlanes(a){a=a.m;const b=[];for(let c=0;3>c;++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(),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);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=>d.castShadow&&!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=>!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<g;++m){const n=render3DStripIndex(m,f);e(a[n],h?b[n]:b||RENDER3D_DEFAULT_NORMAL,k?c[n]:c||RENDER3D_DEFAULT_UV,l?d[n]:d||WHITE)}}function render3DWriteVertex(a,b,c,d,e,f,g,h,k,l){a[c]=d;a[c+1]=e;a[c+2]=f;a[c+3]=g.x;a[c+4]=g.y;a[c+5]=g.z;a[c+6]=h;a[c+7]=k;b[c+8]=l}function render3DFlipTriangles(a){for(let b=0;b<a.length;b+=3){const c=a[b+1];a[b+1]=a[b+2];a[b+2]=c}return a}function render3DStripTriangles(a,b,c){const d=[];for(let e=2;e<a;++e){const f=e&1?e-1:e-2,g=e&1?e-2:e-1;c[f]!=c[g]&&c[g]!=c[e]&&c[f]!=c[e]&&d.push(b[f],b[g],b[e])}return d}function render3DMeshVertexData(a,b,c=new ArrayBuffer(b.length*RENDER3D_VERTEX_BYTES)){const d=b.length,e=new Float32Array(c),f=new Uint32Array(c);let g=0,h=Infinity,k=Infinity,l=Infinity,m=-Infinity,n=-Infinity,p=-Infinity;for(let q=0;q<d;++q){const u=b[q];var r=a.points[u];const t=a.uvs[u]||RENDER3D_DEFAULT_UV,v=r.x,z=r.y;r=r.z;render3DWriteVertex(e,f,q*RENDER3D_VERTEX_FLOATS,v,z,r,a.normals[u]||RENDER3D_DEFAULT_NORMAL,t.x,t.y,(a.colors[u]||WHITE).rgbaInt());g=max(g,v*v+z*z+r*r);h=min(h,v);k=min(k,z);l=min(l,r);m=max(m,v);n=max(n,z);p=max(p,r)}a.radius=g**.5;a.bounds=d?{min:vec3(h,k,l),max:vec3(m,n,p)}:{min:vec3(),max:vec3()};return c}function render3DPolygonStrip(a){const b=[a[0]];for(let c=1,d=a.length-1;c<=d;++c,--d)b.push(a[c]),c!==d&&b.push(a[d]);return b}function render3DFlipWinding(a){if(a.indices)return void render3DFlipTriangles(a.indices);for(const b of["points","normals","uvs","colors"]){const c=a[b];c.length&&(c.unshift(c[0]),c.push(c[c.length-1]))}a.vertexKeys=void 0}const render3DMeshBuffers="undefined"==typeof FinalizationRegistry?void 0:new FinalizationRegistry(({buffer:a,indexBuffer:b,generation:c})=>{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<a.length;++g){var f=a[g];const h=round(1e5*f.x),k=round(1e5*f.y);f=round(1e5*f.z);const l=Math.imul(h,73856093)^Math.imul(k,19349663)^Math.imul(f,83492791);let m=c.get(l);for(;void 0!==m&&(e[3*m]!==h||e[3*m+1]!==k||e[3*m+2]!==f);)m=d[m];void 0===m&&(m=d.length,d.push(c.get(l)),c.set(l,m),e.push(h,k,f));b[g]=m}return{groups:b,count:d.length}}function render3DSmoothNormalSums(a,b){const c=!b,d=c?max(a.length-2,0):b.length/3|0,{groups:e,count:f}=render3DPlaceGroups(a),g=new Float64Array(3*f),h=new Uint8Array(f);let k=0,l=0,m=0;const n=(u,t,v,z)=>{var x=t.x-u.x,w=t.y-u.y;t=t.z-u.z;const y=v.x-u.x,A=v.y-u.y;u=v.z-u.z;x=Math.acos(clamp((x*y+w*A+t*u)/((x**2+w**2+t**2)**.5*(y**2+A**2+u**2)**.5||1),-1,1));w=3*z;g[w]+=k*x;g[w+1]+=l*x;g[w+2]+=m*x;h[z]=1};for(let u=0;u<d;++u){const t=c?u:b[3*u],v=c?u+1:b[3*u+1],z=c?u+2:b[3*u+2],x=a[t],w=a[v],y=a[z];var p=w.x-x.x,r=w.y-x.y,q=w.z-x.z;const A=y.x-x.x,C=y.y-x.y,D=y.z-x.z,B=r*D-q*C;q=q*A-p*D;p=p*C-r*A;if(r=B**2+q**2+p**2)r=(!c||u&1?1:-1)/r**.5,k=B*r,l=q*r,m=p*r,n(x,w,y,e[t]),n(w,y,x,e[v]),n(y,x,w,e[z])}return{groups:e,sums:g,touched:h}}class Mesh{constructor(){this.points=[];this.normals=[];this.uvs=[];this.colors=[];this.indexBuffer=this.buffer=void 0;this.indexType=this.bufferCount=0;this.dirty=!1;this.instanced=void 0;this.dynamicDraw=this.doubleSided=!1;this.vertexLayout=this.vertexKeys=this.indices=void 0;this.instanceCount=0;this.instanceData=void 0;this.radius=0;this.bounds=void 0;this.contextGeneration=0}get vertexCount(){return this.points.length}addStrip(a,b,c,d){if(this.indices)return a=(new Mesh).addStrip(a,b,c,d).toIndexed(),this.addTriangles(a.points,a.indices,a.normals,a.uvs,a.colors);render3DForEachStripVertex(a,b,c,d,(e,f,g,h)=>{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;l<a.length;++l)this.points.push(a[l]),this.normals.push(g?c[l]:c||RENDER3D_DEFAULT_NORMAL),this.uvs.push(h?d[l]:d||RENDER3D_DEFAULT_UV),this.colors.push(k?e[l]:e||WHITE);for(const l of b)this.indices.push(l+f);this.dirty=!0;return this}toIndexed(){if(this.indices)return this;const{vertices:a,indices:b}=this.getTriangles();this.points=a.map(c=>this.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;l<m;l+=3)this.indices.push(k[l]+h,k[l+(e?2:1)]+h,k[l+(e?1:2)]+h)}else if(e&&f.points.length){var g=f.points.length-1;g=[0,...f.points.keys(),g]}for(let h=0,k=g?g.length:f.points.length;h<k;++h)e=g?g[h]:h,this.points.push(b.transformPoint(f.points[e])),this.normals.push(d.transformDirection(f.normals[e]||RENDER3D_DEFAULT_NORMAL).normalize()),this.uvs.push((f.uvs[e]||RENDER3D_DEFAULT_UV).copy()),this.colors.push((f.colors[e]||WHITE).multiply(c));this.doubleSided||(this.doubleSided=a.doubleSided);this.vertexKeys=void 0;this.dirty=!0;return this}mirror(a=vec3(1,0,0)){a=a.normalize();const b=-2*a.x,c=-2*a.y,d=-2*a.z;a=new Matrix4([1+b*a.x,c*a.x,d*a.x,0,b*a.y,1+c*a.y,d*a.y,0,b*a.z,c*a.z,1+d*a.z,0,0,0,0,1]);return(new Mesh).combine(this).combine(this,a)}spin(a,b=vec3(0,1,0)){const c=new Mesh;b=b.normalize();for(let d=0;d<a;++d)c.combine(this,render3DAxisRotation(b,d/a*2*PI));return c}union(a,b){return render3DMeshCSG(this,a,b,0)}subtract(a,b){return render3DMeshCSG(this,a,b,1)}intersect(a,b){return render3DMeshCSG(this,a,b,2)}scaleUVs(a){const b=render3DSize2(a);this.uvs=this.uvs.map(c=>vec2(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;c<this.points.length;++c){this.points[c]=a.transformPoint(this.points[c]);let d,e;(d=this.normals)[e=c]&&(d[e]=b.transformDirection(this.normals[c]).normalize())}render3DMirrors(a)&&render3DFlipWinding(this);this.dirty=!0;return this}flipNormals(){render3DFlipWinding(this);this.normals=this.normals.map(a=>a.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 p=3*h[n];m=k[p];const r=k[p+1];p=k[p+2];const q=m**2+r**2+p**2,u=1/q**.5;return l[h[n]]&&q?vec3(m*u,r*u,p*u):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<c.length;d+=3){var e=b[c[d]],f=b[c[d+2]];e=b[c[d+1]].subtract(e).cross(f.subtract(e));e.lengthSquared()&&(a[c[d]]=a[c[d+1]]=a[c[d+2]]=e.normalize())}this.normals=a;this.dirty=!0;return this}b=this.points;c=b.length;if(a){const{groups:h,sums:k,touched:l}=render3DSmoothNormalSums(b);this.normals=b.map((m,n)=>{var p=3*h[n];m=k[p];const r=k[p+1];p=k[p+2];const q=(m**2+r**2+p**2)**.5;return l[h[n]]?q?vec3(1/q*m,1/q*r,1/q*p):vec3():vec3(0,1,0)});this.vertexKeys=void 0;this.dirty=!0;return this}a=[];for(d=0;d+2<c;++d)e=b[d],f=b[d+2],e=b[d+1].subtract(e).cross(f.subtract(e)),a.push(e.lengthSquared()?e.normalize(d&1?1:-1):void 0);const g=b.map(()=>RENDER3D_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,render3DMeshVertexData(this,b.vertices,b.data)),a.bindBuffer(a.ARRAY_BUFFER,glArrayBuffer),this.dirty=!1,this;this.dispose();const{vertices:c,indices:d}=this.getTriangles();b=65535<c.length;const e=render3DMeshVertexData(this,c);this.vertexLayout=this.dynamicDraw?{vertices:c,pointCount:this.points.length,data:e}:void 0;this.vertexKeys=void 0;this.buffer=a.createBuffer();this.indexBuffer=a.createBuffer();this.bufferCount=d.length;this.indexType=b?a.UNSIGNED_INT:a.UNSIGNED_SHORT;this.dirty=!1;a.bindBuffer(a.ARRAY_BUFFER,this.buffer);a.bufferData(a.ARRAY_BUFFER,e,this.dynamicDraw?a.DYNAMIC_DRAW:a.STATIC_DRAW);a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer);a.bufferData(a.ELEMENT_ARRAY_BUFFER,b?new Uint32Array(d):new Uint16Array(d),a.STATIC_DRAW);this.contextGeneration=render3D.contextGeneration;b={buffer:this.buffer,indexBuffer:this.indexBuffer,generation:this.contextGeneration};render3DMeshBuffers?.register(this,b,this);a.bindBuffer(a.ARRAY_BUFFER,glArrayBuffer);return this}getTriangles(){const a=this.points.length,b=[];if(this.indices){for(var c=0;c<a;++c)b.push(c);return{vertices:b,indices:render3DFlipTriangles(this.indices.slice())}}c=new Int32Array(a);const d=new Int32Array(a);var e=this.vertexKeys;if(e&&e.length===a){var f=new Int32Array(a).fill(-1);for(var g=0;g<a;++g){var h=e[g],k=f[h];0>k?(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<a;++k){var l=this.points[k],m=this.normals[k]||RENDER3D_DEFAULT_NORMAL,n=this.uvs[k]||RENDER3D_DEFAULT_UV;const q=9*k;var p=e[q]=round(1e6*l.x),r=e[q+1]=round(1e6*l.y);l=e[q+2]=round(1e6*l.z);e[q+3]=round(1e6*m.x);e[q+4]=round(1e6*m.y);e[q+5]=round(1e6*m.z);e[q+6]=round(1e6*n.x);e[q+7]=round(1e6*n.y);e[q+8]=(this.colors[k]||WHITE).rgbaInt();m=Math.imul(2166136261^p,2654435761)>>>0;m=Math.imul(m^r,2654435761)>>>0;m=Math.imul(m^l,2654435761)>>>0;for(n=m&f;;n=n+1&f){const u=h[n]-1;if(0>u){h[n]=k+1;d[k]=k;break}if(e[9*u]===p&&e[9*u+1]===r&&e[9*u+2]===l){d[k]=u;break}}for(p=3;9>p;++p)m=Math.imul(m^e[q+p],2654435761)>>>0;for(p=m&f;;p=p+1&f){r=g[p]-1;if(0>r){g[p]=k+1;c[k]=b.length;b.push(k);break}l=!0;for(m=0;l&&9>m;++m)l=e[9*r+m]===e[q+m];if(l){c[k]=c[r];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,y)=>vec3(sin(y)*a[w][0],a[w][1],cos(y)*a[w][0]),h=w=>{const[y,A]=a[w],[C,D]=a[w+1];w=vec2(D-A,y-C);return w.length()?w.normalize():vec2(1,0)},k=2<f&&1e-9>abs(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 y=w?1:-1;if(h(w?w-1:0).y*y>Math.SQRT1_2-1e-9)return vec2(0,y)}let A=vec2();y=C=>A=A.add(h(C).scale(hypot(a[C+1][0]-a[C][0],a[C+1][1]-a[C][1])));0<w?y(w-1):k&&y(f-2);w<f-1?y(w):k&&y(0);return A.length()?A.normalize():vec2(1,0)},m=(w,y)=>vec3(sin(y)*w.x,w.y,cos(y)*w.x),n=[0];for(var p=1;p<f;++p)n[p]=n[p-1]+hypot(a[p][0]-a[p-1][0],a[p][1]-a[p-1][1]);p=n[f-1]||1;for(let w=0;w+1<f;++w)if(c){var r=[],q=[],u=[],t=l(w),v=l(w+1),z=PI/b,x=1e-9>abs(a[w+1][0])?-z:0;z=1e-9>abs(a[w][0])?z:0;for(let y=0;y<=b;++y){const A=y/b*2*PI,C=y/b;r.push(g(w+1,A),g(w,A));q.push(m(v,A+x),m(t,A+z));u.push(vec2(C,1-n[w+1]/p),vec2(C,1-n[w]/p))}e.addStrip(r,q,u)}else for(r=h(w),q=0;q<b;++q)u=q/b*2*PI,t=(q+1)/b*2*PI,v=q/b,x=(q+1)/b,e.addStrip([g(w+1,u),g(w,u),g(w+1,t),g(w,t)],m(r,(u+t)/2),[vec2(v,1-n[w+1]/p),vec2(v,1-n[w]/p),vec2(x,1-n[w+1]/p),vec2(x,1-n[w]/p)]);if(d&&!k)for(const[w,y]of[[0,!1],[f-1,!0]])if(!(1e-9>abs(a[w][0]))){c=[];l=[];for(m=0;m<b;++m)n=(y?m:-m)/b*2*PI,c.push(g(w,n)),l.push(vec2(.5*sin(n)+.5,.5*cos(n)+.5));e.addStrip(render3DPolygonStrip(c),vec3(0,y?1:-1,0),render3DPolygonStrip(l))}e.doubleSided=!k&&!d&&(1e-9<abs(a[0][0])||1e-9<abs(a[f-1][0]));return e}function buildSphere(a=1,b=16,c=8,d=render3D?.smoothShading){const e=[];for(let f=0;f<=c;++f){const g=f/c*PI-PI/2;e.push([cos(g)*a/2,sin(g)*a/2])}return buildLathe(e,b,d)}function render3DBevelBox(a,b,c,d){const e=new Mesh,f=a.subtract(vec3(b)),g=max(1,c|0);c=(r,q,u,t,v,z)=>{let x=q.subtract(r).cross(u.subtract(r));if(!(1e-20>x.lengthSquared())){0>x.dot(r.add(q).add(u))&&([q,u,v,z,x]=[u,q,z,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[,y,A]=w,C=abs(a.dot(y)),D=abs(a.dot(A));w=B=>vec2(.5+B.dot(y)/(2*C),.5-B.dot(A)/(2*D));e.addStrip([r,q,u],1<g&&t?[t,v,z]:x,[w(r),w(q),w(u)])}};for(const[r,q,u]of d){const[t,v,z,x]=render3DQuadAxes(r.multiply(a),q.multiply(f),u.multiply(f));c(t,v,z);c(z,v,x)}var h=[vec3(1,0,0),vec3(0,1,0),vec3(0,0,1)];for(var k=0;3>k;++k)for(var l of[-1,1])for(var m of[-1,1]){const r=h[(k+1)%3].scale(l),q=h[(k+2)%3].scale(m);var n=r.multiply(f).add(q.multiply(f)),p=h[k].multiply(f);const u=n.subtract(p);n=n.add(p);p=t=>r.scale(cos(t/g*PI/2)).add(q.scale(sin(t/g*PI/2)));for(let t=0;t<g;++t){const v=p(t),z=p(t+1),x=u.add(v.scale(b)),w=n.add(v.scale(b)),y=u.add(z.scale(b)),A=n.add(z.scale(b));c(x,w,y,v,v,z);c(y,w,A,z,v,z)}}for(const r of[-1,1])for(const q of[-1,1])for(const u of[-1,1]){const t=vec3(r,0,0),v=vec3(0,q,0),z=vec3(0,0,u);l=f.multiply(vec3(r,q,u));m=(x,w)=>{const y=x/g*PI/2;x=x?w/x*PI/2:0;return z.scale(cos(y)).add(t.scale(cos(x)*sin(y))).add(v.scale(sin(x)*sin(y)))};for(h=0;h<g;++h){for(k=0;k<=h;++k)c(l.add(m(h,k).scale(b)),l.add(m(h+1,k).scale(b)),l.add(m(h+1,k+1).scale(b)),m(h,k),m(h+1,k),m(h+1,k+1));for(k=0;k<h;++k)c(l.add(m(h,k).scale(b)),l.add(m(h+1,k+1).scale(b)),l.add(m(h,k+1).scale(b)),m(h,k),m(h+1,k+1),m(h,k+1))}}return e}function buildBox(a=1,b=0,c=1){a=render3DSize3(a).scale(.5);var d=[[vec3(0,0,1),vec3(1,0,0),vec3(0,1,0)],[vec3(0,0,-1),vec3(-1,0,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,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)]];b=min(b,a.x,a.y,a.z);if(0<b)return render3DBevelBox(a,b,c,d);c=new Mesh;for(const[e,f,g]of d){d=e.multiply(a);b=f.multiply(a);const h=g.multiply(a);c.addStrip(render3DQuadAxes(d,b,h),e,RENDER3D_QUAD_UVS)}return c}function buildGrid(a=vec2(1),b=1,c,d,e=d&&render3D?.smoothShading){d||=()=>0;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,p=k/2,r=l/2,q=(z,x)=>c?isColor(c)?c:c(z*k-m,x*l-n):WHITE;a=z=>{const x=[],w=[],y=[],A=[],C=z*l-n;for(let D=0;D<=g;++D){const B=D*k-m;x.push(vec3(B,d(B,C),C));y.push(vec2(D/g,z/h));e&&(w.push(render3DSlopeNormal(d,B,C,p,r,m,n)),A.push(q(D,z)))}return{points:x,normals:w,uvs:y,colors:A}};b=a(0);for(var u=0;u<h;++u){var t=a(u+1);if(e){var v=[];const z=[],x=[],w=[];for(let y=0;y<=g;++y)v.push(b.points[y],t.points[y]),z.push(b.normals[y],t.normals[y]),x.push(b.uvs[y],t.uvs[y]),w.push(b.colors[y],t.colors[y]);f.addStrip(v,z,x,w)}else for(v=0;v<g;++v)f.addQuad(b.points[v],t.points[v],t.points[v+1],b.points[v+1],q(v+.5,u+.5),[b.uvs[v],t.uvs[v],t.uvs[v+1],b.uvs[v+1]]);b=t}if(e)for(a=2*(g+1)+2,b=f.vertexKeys=new Int32Array(f.points.length),u=0;u<h;++u){t=u*a;b[t]=u*(g+1);for(v=0;v<=g;++v)b[t+1+2*v]=u*(g+1)+v,b[t+2+2*v]=(u+1)*(g+1)+v;b[t+a-1]=(u+1)*(g+1)+g}f.doubleSided=!0;return f}function buildSky(a=hsl(.6,.8,.55),b=hsl(.6,1,.9),c=b,d=16,e=8){d=buildSphere(2,d,e,!0).flipNormals();d.colors=d.points.map(f=>0>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.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}updatePhysics(){this.sync2D&&super.updatePhysics();const a=this.groundObject;this.sync2D||(this.groundObject=void 0);if(this.clampSpeed&&!this.sync2D&&(this.collideSolidObjects||this.collideLevel&&this.mass)){var b=this.velocity3D,c=objectMaxSpeed;b.x=clamp(b.x,-c,c);b.y=clamp(b.y,-c,c);b.z=clamp(b.z,-c,c)}b=this.collideLevel&&this.mass&&!this.sync2D?this.pos3D.copy():void 0;render3DMove(this);if(a&&this.mass&&!this.sync2D){c=max(this.friction,a.friction);const e=this.velocity3D;var d=a instanceof EngineObject3D?a.velocity3D:void 0;const f=d?.x??0;d=d?.z??0;e.x=f+(e.x-f)*c;e.z=d+(e.z-d)*c}b&&render3DCollideLevel(this,b,a);this.collideSolidObjects&&!this.sync2D&&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()}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){if(a instanceof EngineObject3D&&!a.destroyed){const b=render3DObjectMatrix(a);a.pos3D=b.getTranslation();a.rotation3D=b.getRotation();a.scale3D=b.getScale();a.localMatrix&&(a.localMatrix=b.copy())}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 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){const b=a.pos3D,c=a.velocity3D,d=a.rotation3D,e=a.angleVelocity3D;var f=a.sync2D?1:a.damping;const g=a.sync2D?1:a.angleDamping;c.x*=f;c.y*=f;c.z*=f;a.mass&&!a.sync2D&&(f=render3D.gravity,a=a.gravityScale,c.x+=f.x*a,c.y+=f.y*a,c.z+=f.z*a);b.x+=c.x;b.y+=c.y;b.z+=c.z;d.x+=e.x*=g;d.y+=e.y*=g;d.z+=e.z*=g}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){const b=a.size3D;var c=a.scale3D;const d=abs(c.x),e=abs(c.y);c=abs(c.z);return a.collideAsSphere3D?max(b.x,b.y,b.z)/2*max(d,e,c):hypot(b.x*d,b.y*e,b.z*c)/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)}const render3DIsSprite=a=>!a.mesh&&!!a.tileInfo;function render3DOnFace(a,b){if(!b.size)return!1;a=a.normalize();b=b.axes??BOX_WORLD_AXES;return.999999<max(abs(a.dot(b[0])),abs(a.dot(b[1])),abs(a.dot(b[2])))}function render3DCollideSolid(a){let b=render3DSolidShape(a);const c=render3DSolidReach(a);for(const h of engineObjectsCollide){if(h===a)break;if(h.destroyed||!(h instanceof EngineObject3D)||h.parent||h.sync2D)continue;if(!a.isSolid&&!h.isSolid)continue;var d=b.pos;const k=h.pos3D;var e=c+render3DSolidReach(h),f=d.x-k.x,g=d.y-k.y;d=d.z-k.z;if(!(f*f+g*g+d*d>e*e)&&(f=render3DSolidShape(h),e=render3DSolidPush(b,f))&&(g=a.collideWithObject(h,e),d=h.collideWithObject(a,e.scale(-1)),g&&d)){g=e.lengthSquared();d=e.y/g**.5;f=0<d&&a.mass&&d>=cos(a.groundAngle)&&render3DOnFace(e,f);d=0>d&&h.mass&&-d>=cos(h.groundAngle)&&render3DOnFace(e,b);if(f||d)if(f?a.groundObject=h:h.groundObject=a,e.x||e.z)e=vec3(0,g/e.y,0);g=a.mass+h.mass;f=a.mass?h.mass?h.mass/g:1:0;g=h.mass?a.mass?a.mass/g:1:0;a.pos3D=a.pos3D.add(e.scale(f));h.pos3D=h.pos3D.subtract(e.scale(g));f&&(b=render3DSolidShape(a));e=e.normalize();f&&0>a.velocity3D.dot(e)&&(a.velocity3D=a.velocity3D.reflect(e,a.restitution));g&&0<h.velocity3D.dot(e)&&(h.velocity3D=h.velocity3D.reflect(e,h.restitution))}}}function engineObjectsCollect3D(a,b,c=engineObjects,d=!1){const e="number"===typeof b&&0<b?(b/2)**2:void 0;b=e?void 0:"number"===typeof b?vec3():render3DSize3(b);const f=[];for(const h of c){if(!(h instanceof EngineObject3D)||h.destroyed)continue;const k=render3DObjectMatrix(h).m;c=h.size3D;if(!(c.x||c.y||c.z))continue;c=vec3(k[12],k[13],k[14]);const l=d?vec3():render3DWorldSize(h,k);var g=m=>vec3(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-6<abs(g[0].dot(g[1]))||1e-6<abs(g[0].dot(g[2]))||1e-6<abs(g[1].dot(g[2])))){const m=g.map((n,p)=>n.scale(p?1<p?l.z/2:l.y/2:l.x/2));g=n=>2*(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*c<e}c&&f.push(h)}return f}const render3DRaycastCenter=vec3();function render3DRaycastObject(a,b){if(!b.destroyed&&b instanceof EngineObject3D){if(b instanceof HeightMap||b instanceof VoxelMap)return b.levelRaycast3D(a);if((b.mesh||b.tileInfo)&&!(b instanceof InstancedMesh3D)){var c=render3DObjectMatrix(b),d=b.mesh;if(!d)return render3DRaycastSprite(a,b,c);b=(d.dirty||!d.radius?d.computeRadius():d.radius)*render3DMaxStretch(c.m);if(0<b){var e=c.m;e=render3DRaycastCenter.set(e[12],e[13],e[14]);if(void 0!==raycastSphere(a,e,b)){if(!c.determinant())return render3DRaycastDisc(a,e,b);b=c.copy().invert();c=d.bounds||d.getBounds();b=new Ray3D(b.transformPoint(a.origin),b.transformDirection(a.direction));c=raycastBox(b,c.min.add(c.max).scale(.5),c.max.subtract(c.min));return void 0!==c&&a.direction.lengthSquared()?render3DRaycastMesh(b,d):c}}}}}function render3DRaycastMesh(a,b){const c=b.points,d=b.indices;b=b.doubleSided;const e=a.origin.x,f=a.origin.y,g=a.origin.z,h=a.direction.x,k=a.direction.y;a=a.direction.z;const l=d?d.length/3|0:c.length-2;let m;for(let x=0;x<l;++x){var n=void 0,p=void 0,r=void 0;d?(n=c[d[3*x]],p=c[d[3*x+2]],r=c[d[3*x+1]]):(n=c[x&1?x+1:x],p=c[x&1?x:x+1],r=c[x+2]);var q=p.x-n.x,u=p.y-n.y,t=p.z-n.z;p=r.x-n.x;const w=r.y-n.y;r=r.z-n.z;var v=k*r-a*w,z=a*p-h*r;const y=h*w-k*p,A=q*v+u*z+t*y;if(b?!A:!(0>A))continue;const C=e-n.x,D=f-n.y;n=g-n.z;v=(C*v+D*z+n*y)/A;0<=v&&1>=v&&(z=D*t-n*u,t=n*q-C*t,q=C*u-D*q,u=(h*z+k*t+a*q)/A,0<=u&&1>=v+u&&(p=(p*z+w*t+r*q)/A,0<=p&&!(p>=m)&&(m=p)))}return m}function render3DRaycastSprite(a,b,c){const d=c.getTranslation();c=render3DWorldSize(b,c.m);c=vec2(c.x,c.y);if(0<c.x&&0<c.y){if(!a.direction.lengthSquared())return render3DRaycastDisc(a,d,hypot(c.x,c.y)/2);c=render3DBillboardAxes(c,b.rotation3D.z,b.upright);b=vec3(c[0],c[1],c[2]);c=vec3(c[3],c[4],c[5]);var e=raycastPlane(a,d,b.cross(c));if(void 0!==e)return a=a.getPosition(e).subtract(d),abs(a.dot(b))<=b.lengthSquared()&&abs(a.dot(c))<=c.lengthSquared()?e:void 0}}function render3DRaycastDisc(a,b,c){const d=a.direction;a=b.subtract(a.origin);b=(b=d.dot(d))?a.dot(d)/b:0;return 0<=b&&a.subtract(d.scale(b)).lengthSquared()<=c*c?b:void 0}function engineObjectsRaycast3D(a,b=engineObjects){const c=[];for(const d of b)b=render3DRaycastObject(a,d),void 0!==b&&c.push({o:d,distance:b});return c.sort((d,e)=>d.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;f<b;++f){c.set(RENDER3D_IDENTITY.m,f*RENDER3D_MATRIX_FLOATS);const g=f*RENDER3D_COLOR_FLOATS;e[g]=d.r;e[g+1]=d.g;e[g+2]=d.b;e[g+3]=d.a;e[g+4]=a.x;e[g+5]=a.y;e[g+6]=a.w;e[g+7]=a.h}}setTransformAt(a,b,c,d){matrix4Compose(this.matrixData,a*RENDER3D_MATRIX_FLOATS,b,c,d);this.markDirty(a)}setTransforms(a,b,c,d,e,f,g,h,k,l,m){const n=this.matrixData,p=a+b;for(let r=a;r<p;++r){const q=r*RENDER3D_MATRIX_FLOATS,u=k?k[r]:1,t=l?l[r]:1,v=m?m[r]:1;if(f){const z=cos(f[r]),x=sin(f[r]),w=cos(g[r]),y=sin(g[r]),A=cos(h[r]),C=sin(h[r]);n[q]=(w*A+y*x*C)*u;n[q+1]=z*C*u;n[q+2]=(-y*A+w*x*C)*u;n[q+4]=(-w*C+y*x*A)*t;n[q+5]=z*A*t;n[q+6]=(y*C+w*x*A)*t;n[q+8]=y*z*v;n[q+9]=-x*v;n[q+10]=w*z*v}else n[q]=u,n[q+1]=0,n[q+2]=0,n[q+4]=0,n[q+5]=t,n[q+6]=0,n[q+8]=0,n[q+9]=0,n[q+10]=v;n[q+3]=n[q+7]=n[q+11]=0;n[q+15]=1;n[q+12]=c[r];n[q+13]=d[r];n[q+14]=e[r]}b&&this.markDirtyRange(a,p)}setMatrixAt(a,b){const c=this.matrixData,d=a*RENDER3D_MATRIX_FLOATS;b=b.m;for(let e=0;16>e;++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.dirtyStart&&(this.dirtyStart=a);a>=this.dirtyEnd&&(this.dirtyEnd=a+1);a<this.boundsStart&&(this.boundsStart=a);a>=this.boundsEnd&&(this.boundsEnd=a+1)}markDirtyRange(a,b){a<this.dirtyStart&&(this.dirtyStart=a);b>this.dirtyEnd&&(this.dirtyEnd=b);a<this.boundsStart&&(this.boundsStart=a);b>this.boundsEnd&&(this.boundsEnd=b)}markColorDirty(a){a<this.colorDirtyStart&&(this.colorDirtyStart=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;f<this.boundsEnd;++f){var b=f*RENDER3D_MATRIX_FLOATS,c=a[b+12];const g=a[b+13],h=a[b+14];c=c*c+g*g+h*h;b=render3DMaxStretchSquared(a,b);c>d&&(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<e.length;f+=RENDER3D_COLOR_FLOATS)e[f]=d.x,e[f+1]=d.y,e[f+2]=d.w,e[f+3]=d.h;this.uvTileInfo=this.tileInfo;this.colorDirtyStart=0;this.colorDirtyEnd=this.maxCount}this.buffer&&this.bufferGeneration===a.contextGeneration?(d=(f,g,h,k,l)=>{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(0<this.glow&&!this.directional){var a=render3D,b=this.color,c=render3DObjectMatrix(this).getTranslation(),d=a.camera.pos.subtract(c),e=d.length();c=e?c.add(d.scale(min(this.glow,e)/2/e)):c;b=rgb(b.r,b.g,b.b,b.a*min(this.intensity,1));d=engineGlowTexture(this.glowFalloff);!d&&glContext||a.drawBillboard(c,vec2(this.glow),d,b)}}}class DirectionalLight3D extends Light3D{constructor(a=vec3(0,1,0),b=WHITE,c=1){super(a,0,b,c);this.directional=!0}}const RENDER3D_TEXT_LEADING=1.3;function render3DDetach(a){a.parent?a.parent.removeChild(a):a.worldPos3D&&(a.pos3D=a.worldPos3D)}let render3DSoftDotTexture;function render3DSoftDot(){if(render3DSoftDotTexture||!glContext||!canvasAvailable())return render3DSoftDotTexture;const a=createCanvasContext(32),b=a.createRadialGradient(16,16,0,16,16,16);for(const[c,d]of[[0,1],[.33,.9],[.67,.7],[1,0]])b.addColorStop(c,"rgba(255,255,255,"+d+")");a.fillStyle=b;a.fillRect(0,0,32,32);return render3DSoftDotTexture=new TextureInfo(a.canvas)}function normalMapFromHeight(a,b,c=1){const d=a.x|0;a=a.y|0;if(!canvasAvailable())return b=new TextureInfo(void 0,!1,!0),b.size=vec2(d,a),b.sizeInverse=vec2(1/d,1/a),b;const e=createCanvasContext(d,a);b=render3DNormalMapPixels(d,a,b,c);e.putImageData(new ImageData(b,d,a),0,0);return new TextureInfo(e.canvas,!0,!0)}function render3DNormalMapPixels(a,b,c,d){const e=new Float32Array(a*b),f=new Uint8ClampedArray(a*b*4);for(var g=0;g<b;++g)for(var h=0;h<a;++h)e[g*a+h]=c(h,g);c=(k,l)=>e[mod(l,b)*a+mod(k,a)];for(g=0;g<b;++g)for(h=0;h<a;++h){const k=(c(h+1,g)-c(h-1,g))/2*d,l=(c(h,g+1)-c(h,g-1))/2*d,m=1/hypot(k,l,1),n=4*(g*a+h);f[n]=round(255*(-k*m*.5+.5));f[n+1]=round(255*(l*m*.5+.5));f[n+2]=round(255*(.5*m+.5));f[n+3]=255}return f}function render3DBevelProfile(a,b,c,d,e){var f=[a[0]+b[0]*d,a[1]+b[1]*d];const g=[a[0]+c[0]*d,a[1]+c[1]*d];e=max(1,e|0);if(1===e)return[f,f,g,g];var h=Math.acos(clamp(b[0]*c[0]+b[1]*c[1],-1,1))/2,k=b[0]+c[0];b=b[1]+c[1];c=d/cos(h)/hypot(k,b);k=a[0]+k*c;a=a[1]+b*c;d*=tan(h);h=atan2(f[1]-a,f[0]-k);b=mod(atan2(g[1]-a,g[0]-k)-h+PI,2*PI)-PI;f=[f];for(c=1;c<e;++c){const l=h+b*c/e;f.push([k+cos(l)*d,a+sin(l)*d])}f.push(g);return f}function buildCylinder(a=1,b=1,c=16,d=render3D?.smoothShading,e=!0,f=0,g=1){a/=2;b/=2;f=min(f,a,b);return 0<f?buildLathe([...render3DBevelProfile([a,-b],[-1,0],[0,1],f,g),...render3DBevelProfile([a,b],[0,-1],[-1,0],f,g)],c,d,e):buildLathe([[a,-b],[a,b]],c,d,e)}function buildCone(a=1,b=1,c=16,d=render3D?.smoothShading,e=!0,f=0,g=1){a/=2;const h=b/2,k=hypot(a,b);f=min(f,a,k/2);return 0<f?buildLathe([...render3DBevelProfile([a,-h],[-1,0],[-a/k,b/k],f,g),[0,h]],c,d,e):buildLathe([[a,-h],[0,h]],c,d,e)}function buildCapsule(a=1,b=1,c=16,d=4,e=render3D?.smoothShading){const f=[],g=a/2;a=max(0,b-a)/2;for(b=0;b<=d;++b){var h=b/d*PI/2;f.push([g*sin(h),-a-g*cos(h)])}for(b=0;b<=d;++b)h=b/d*PI/2,f.push([g*cos(h),a+g*sin(h)]);return buildLathe(f,c,e)}function buildTorus(a=1,b=.3,c=16,d=8,e=render3D?.smoothShading){const f=[];a=(a-b)/2;b/=2;for(let g=0;g<=d;++g){const h=g/d*2*PI;f.push([a+b*cos(h),b*sin(h)])}return buildLathe(f,c,e)}function buildRibbon(a,b=1,c=WHITE,d=!1,e=vec3(0,1,0)){const f=new Mesh,g=a.length,h=[];var k=(.9>abs(e.y)?vec3(0,1,0):vec3(1,0,0)).cross(e).normalize();for(let m=0;m<g;++m){var l=a[d?(m+1)%g:min(m+1,g-1)];const n=a[d?(m+g-1)%g:max(m-1,0)];l=l.subtract(n).cross(e);1e-12<l.lengthSquared()&&(k=l.normalize());l=k.scale((isArray(b)?b[m]:b)/2);h.push([a[m].subtract(l),a[m].add(l)])}for(a=0;a+1<g+(d?1:0);++a)k=(a+1)%g,b=h[a],e=h[k],k=isArray(c)?[c[a],c[a],c[k],c[k]]:c,f.addQuad(b[0],b[1],e[1],e[0],k);f.doubleSided=!0;return f}function buildLoft(a){const b=new Mesh,c=([e,f,g,h,k=.5])=>[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+1<a.length;++d){const e=c(a[d]),f=c(a[d+1]);for(let g=0;4>g;++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 t=g.data,v=a.pos.x|0,z=a.pos.y|0;e=a.size.x|0;f=a.size.y|0;d=[];for(a=0;a<f;++a){const x=d[a]=[];for(let w=0;w<e;++w){const y=4*((z+a)*g.width+v+w);x.push(127<t[y+3]?rgb(t[y]/255,t[y+1]/255,t[y+2]/255):void 0)}}}else f=d.length,e=d[0].length;const h=(t,v)=>{if(!(0>t||0>v||t>=e||v>=f)&&(t=d[v]&&d[v][t]))return isColor(t)?.5<t.a?t:void 0:WHITE};g=(t,v,z)=>{let x=0,w;for(let A=0;A<=t;++A){const C=A<t?v(A):void 0;var y=w;C===y||C&&y&&C.rgbaInt()===y.rgbaInt()||(w&&z(x,A,w),x=A,w=C)}};const k=new Mesh,l=b.x/e,m=b.y/f,n=c/2,p=(t,v,z,x,w)=>k.addStrip(render3DQuadAxes(t.add(v.scale(.5)).add(z.scale(.5)),v.scale(.5),z.scale(.5)),x,RENDER3D_QUAD_UVS,w),r=vec3(1,0,0),q=vec3(0,1,0),u=vec3(0,0,1);for(let t=0;t<f;++t)g(e,v=>h(v,t),(v,z,x)=>{const w=r.scale((z-v)*l),y=q.scale(m);p(vec3(v*l-b.x/2,b.y/2-(t+1)*m,n),w,y,u,x);p(vec3(z*l-b.x/2,b.y/2-(t+1)*m,-n),w.scale(-1),y,u.scale(-1),x)}),g(e,v=>h(v,t-1)?void 0:h(v,t),(v,z,x)=>p(vec3(v*l-b.x/2,b.y/2-t*m,n),r.scale((z-v)*l),u.scale(-c),q,x)),g(e,v=>h(v,t+1)?void 0:h(v,t),(v,z,x)=>p(vec3(v*l-b.x/2,b.y/2-(t+1)*m,-n),r.scale((z-v)*l),u.scale(c),q.scale(-1),x));for(let t=0;t<e;++t)g(f,v=>h(t-1,v)?void 0:h(t,v),(v,z,x)=>p(vec3(t*l-b.x/2,b.y/2-z*m,-n),u.scale(c),q.scale((z-v)*m),r.scale(-1),x)),g(f,v=>h(t+1,v)?void 0:h(t,v),(v,z,x)=>p(vec3((t+1)*l-b.x/2,b.y/2-z*m,n),u.scale(-c),q.scale((z-v)*m),r,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=(a+"").split("\n");k.forEach((l,m)=>{m=((k.length-1)/2-m)*g.y*RENDER3D_TEXT_LEADING;for(let r=0;r<l.length;++r){var n=l.charCodeAt(r);if(n=32>n||127<n?95:n-32){var p=f.get(n);p||(p=d.getGlyphPos(n),f.set(n,p=buildExtrude(new TileInfo(p,e.size,e.textureInfo))));h.combine(p,buildMatrix(vec3((r-(l.length-1)/2)*g.x,m,0),void 0,vec3(g.x,g.y,c)))}}});return h}class HeightMap extends EngineObject3D{constructor(a,b=vec2(1),c=1,d,e=vec3(),f=render3D?.smoothShading){super(e);isArray(a)||(a=render3DImageToArray(a,g=>g/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&&0<e.x&&0<e.y)){f=a+hypot(e.x,e.y,f)/g;d.x&&(f=min(f,(sign(d.x)*e.x/2-c.x)/d.x));d.z&&(f=min(f,(sign(d.z)*e.y/2-c.z)/d.z));g=(c.x/e.x+.5)*(this.columns-1);var h=(this.columns-1)/e.x*d.x,k=(c.z/e.y+.5)*(this.rows-1),l=(this.rows-1)/e.y*d.z;e=[a,f];for(const[m,n]of[[g,h],[k,l],[g+k,h+l]])if(n)for(g=m+n*a,h=m+n*f,k=ceil(min(g,h));k<=max(g,h);++k)e.push((k-m)/n);e.sort((m,n)=>m-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,d=this.mapSize;if(!(abs(b.x-c.x)>d.x/2||abs(b.z-c.z)>d.y/2||(c=a.y-this.getHeight(a.x,a.z),d=b.y-this.getHeight(b.x,b.z),0>c||0<=d)))return c/=c-d,{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;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),b=c&&0>=a.velocity3D.y?hypot(d.x-b.x,d.z-b.z):0,d.y-e>f+b||(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;f<e;++f){const g=a[f]=[];for(let h=0;h<d;++h){const k=4*(f*d+h);g.push(b(c[k],c[k+1],c[k+2],c[k+3]))}}return a}const render3DGlyphCache=new WeakMap,render3DPixelCache=new WeakMap;function render3DReadPixels(a){a=a.image;let b=render3DPixelCache.get(a);b||render3DPixelCache.set(a,b=render3DImageData(a));return b}class CameraControl3D extends EngineObject3D{constructor(a=vec3(),b=10,c=.4,d=0){super(a);this.size3D=vec3();this.distance=b;this.pitch=c;this.idleSpin=d;this.dragButton=this.yaw=0;this.dragSpeed=.01;this.zoomSpeed=.1;this.zoomRange=vec2(b/4,3*b);this.pitchRange=vec2(min(-.2,c),max(1.4,c))}update(){mouseIsDown(this.dragButton)?(this.yaw-=mouseDeltaScreen.x*this.dragSpeed,this.pitch+=mouseDeltaScreen.y*this.dragSpeed):this.yaw+=this.idleSpin;this.pitch=clamp(this.pitch,this.pitchRange.x,this.pitchRange.y);this.zoomSpeed&&mouseWheel&&(this.distance=clamp(this.distance*(1+sign(mouseWheel)*this.zoomSpeed),this.zoomRange.x,this.zoomRange.y));render3D.camera.orbit(this.getWorldPos3D(),this.distance,this.yaw,this.pitch)}render3D(){}}class FirstPersonCamera3D extends EngineObject3D{constructor(a=render3D.camera.pos,b=render3D.camera.rotation.y,c=render3D.camera.rotation.x){super(a);this.size3D=vec3();this.mass=1;this.yaw=b;this.pitch=c;this.moveSpeed=.1;this.lookSpeed=.003;this.pitchRange=vec2(-1.5,1.5);this.fly=!1;this.lockPointer=!0;this.eyeHeight=this.jumpSpeed=0}updatePhysics(){const a=this.gravityScale;this.fly&&(this.gravityScale=0);super.updatePhysics();this.gravityScale=a}update(){this.lockPointer&&mouseWasPressed(0)&&pointerLockRequest();if(pointerLockIsActive()||mouseIsDown(0))this.yaw-=mouseDeltaScreen.x*this.lookSpeed,this.pitch-=mouseDeltaScreen.y*this.lookSpeed;this.pitch=clamp(this.pitch,this.pitchRange.x,this.pitchRange.y);var a=keyDirection();a=vec3(a.x,0,-a.y).clampLength(1).scale(this.moveSpeed).rotateX(this.fly?this.pitch:0).rotateY(this.yaw);this.velocity3D=this.fly?a:vec3(a.x,this.velocity3D.y,a.z);this.jumpSpeed&&!this.fly&&this.groundObject&&(keyWasPressed("Space")||gamepadWasPressed(0))&&(this.velocity3D.y=this.jumpSpeed);a=vec3(this.pitch,this.yaw,0);render3D.camera.pos=render3DObjectMatrix(this).transformPoint(vec3(0,this.eyeHeight,0));render3D.camera.rotation=this.parent instanceof EngineObject3D?this.parent.getMatrix().multiply(Matrix4.rotation(a)).getRotation():a}destroy(a){this.lockPointer&&pointerLockIsActive()&&pointerLockExit();super.destroy(a)}render3D(){}}const RENDER3D_PARTICLE_FLOATS=21,render3DParticlePos=vec3(),render3DParticleColor=new Color,render3DParticleSize=vec2(),render3DParticleFrom=vec3(),render3DParticleTo=vec3(),render3DParticlesCalling=new Set;function render3DParticleView(a){return{emitter:a,pos:vec3(),velocity:vec3(),age:0,lifeTime:0,scale:1,destroyed:!1,destroy(){this.destroyed=!0}}}class ParticleEmitter3D extends EngineObject3D{constructor(a=vec3(),b=0,c=0,d=100,e=PI,f,g=WHITE,h=WHITE,k=CLEAR_WHITE,l=CLEAR_WHITE,m=.5,n=.1,p=1,r=.1,q=1,u=0,t=.1,v=.2,z=!1){super(a,void 0,f);this.transparent=!0;this.castShadow=!1;this.size3D=vec3();this.emitSize=b;this.emitFlat=!1;this.emitTime=c;this.emitRate=d;this.emitConeAngle=e;this.colorStartA=g.copy();this.colorStartB=h.copy();this.colorEndA=k.copy();this.colorEndB=l.copy();this.particleTime=m;this.sizeStart=n;this.sizeEnd=p;this.speed=r;this.damping=q;this.gravity=u;this.gravityScale=0;this.fadeRate=t;this.randomness=v;this.additive=z;this.angleSpeed=this.trailTime=0;this.angleDamping=1;this.particleData=new Float32Array(64*RENDER3D_PARTICLE_FLOATS);this.particleCount=0;this.trailData=void 0;this.trailMax=0;this.collideLevel=!1;this.stick=0;this.particleDestroyCallback=this.particleCollideCallback=this.particleUpdateCallback=this.particleCreateCallback=void 0;this.particleView=render3DParticleView(this);this.worldPos3D=void 0;this.emitTimeBuffer=1}update(){var a=render3DObjectMatrix(this);this.worldPos3D=a.getTranslation();var b=render3DMaxScale(a.m);this.particleView.scale=b;if(!this.emitTime||this.getAliveTime()<=this.emitTime){if(a=this.emitRate*particleEmitRateScale,0<a&&Infinity>a)for(this.emitTimeBuffer+=a*timeDelta;1<=this.emitTimeBuffer;--this.emitTimeBuffer)this.emitParticle()}else this.particleCount||this.destroy();a=this.trailTime?max(1,round(this.trailTime*frameRate)):0;if(a!==this.trailMax){this.trailData=(this.trailMax=a)?new Float32Array(this.particleData.length/RENDER3D_PARTICLE_FLOATS*a*3):void 0;for(var c=20;c<this.particleData.length;c+=RENDER3D_PARTICLE_FLOATS)this.particleData[c]=0}c=RENDER3D_PARTICLE_FLOATS;let d=this.particleData,e=this.trailData;const f=()=>{d=this.particleData;e=this.trailData},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&&render3DLevel.length;l=this.particleUpdateCallback;const p=this.particleDestroyCallback;for(let t=this.particleCount;t--;){const v=t*c;var r=d[v+3]=d[v+3]*g+m,q=d[v+4]=d[v+4]*g+n,u=d[v+5]=d[v+5]*g+b;d[v]+=r;d[v+1]+=q;d[v+2]+=u;d[v+18]+=d[v+19]*=h;q=k&&this.particleCollide(v,d[v]-r,d[v+1]-q,d[v+2]-u);k&&f();r=t*a*3;if(a){u=d[v+20];u===a&&(e.copyWithin(r,r+3,r+3*u),--u);const z=r+3*u;e[z]=d[v];e[z+1]=d[v+1];e[z+2]=d[v+2];d[v+20]=u+1}l&&!q&&(this.particleCall(l,v),f());(d[v+17]+=timeDelta)>=d[v+16]&&(p&&(this.particleCall(p,v),f()),q=--this.particleCount,u=q*c,t!==q&&(d.copyWithin(v,u,u+c),a&&e.copyWithin(r,q*a*3,(q+1)*a*3)))}}destroy(a){if(a||!this.particleCount||this.destroyed)return super.destroy(a);this.emitTime=-1;render3DDetach(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;const f=randColor(this.colorStartA,this.colorStartB,!0),g=randColor(this.colorEndA,this.colorEndB,!0);var h=RENDER3D_PARTICLE_FLOATS;const k=this.particleCount++*h;k+h>this.particleData.length&&(h=new Float32Array(2*this.particleData.length),h.set(this.particleData),this.particleData=h,this.trailData&&(h=new Float32Array(2*this.trailData.length),h.set(this.trailData),this.trailData=h));h=this.particleData;h[k]=b.x;h[k+1]=b.y;h[k+2]=b.z;h[k+3]=d.x*e;h[k+4]=d.y*e;h[k+5]=d.z*e;h[k+6]=f.r;h[k+7]=f.g;h[k+8]=f.b;h[k+9]=f.a;h[k+10]=g.r;h[k+11]=g.g;h[k+12]=g.b;h[k+13]=g.a;h[k+14]=this.sizeStart*a()*c;h[k+15]=this.sizeEnd*a()*c;h[k+16]=this.particleTime*a();h[k+17]=0;h[k+18]=this.angleSpeed?rand(2*PI):0;h[k+19]=this.angleSpeed?this.angleSpeed*a()*randSign():0;h[k+20]=0;this.particleCreateCallback&&this.particleCall(this.particleCreateCallback,k)}particleCall(a,b,c,d){const e=render3DParticlesCalling.has(this),f=e?render3DParticleView(this):this.particleView,g=this.particleData;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;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.distance<g.distance)){var g=c;var h=f}if(!g)return!1;f=b.lerp(e,g.distance);if((e=this.particleCollideCallback)&&(!this.particleCall(e,a,h,f.copy())||this.particleView.destroyed))return this.particleView.destroyed;e=this.particleData;g=g.normal;b=vec3(e[a+3],e[a+4],e[a+5]);c=g.scale(b.dot(g));d=max(this.restitution,h.restitution);h=max(this.friction,h.friction)*(1-clamp(this.stick));h=b.subtract(c).scale(h).subtract(c.scale(d));g=f.add(g.scale(.001));e[a]=g.x;e[a+1]=g.y;e[a+2]=g.z;e[a+3]=h.x;e[a+4]=h.y;e[a+5]=h.z;return!1}render3D(){const a=render3D;if(a.transparentQueue)return a.queueTransparent(this.getWorldPos3D(),()=>this.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,p=RENDER3D_PARTICLE_FLOATS,r=this.particleData,q=this.trailMax,u=render3DParticlePos;try{for(let z=0,x=this.particleCount;z<x;++z){var t=z*p;const w=r[t+17]/r[t+16];var v=w<b?w/b:w>1-b?(1-w)/b:1;d.r=r[t+6]+(r[t+10]-r[t+6])*w;d.g=r[t+7]+(r[t+11]-r[t+7])*w;d.b=r[t+8]+(r[t+12]-r[t+8])*w;d.a=(r[t+9]+(r[t+13]-r[t+9])*w)*v;const y=e.x=e.y=lerp(r[t+14],r[t+15],w),A=r[t+18],C=r[t+20];if(1<C){const D=this.trailData;t=[];v=[];const B=[];for(let E=0;E<C;++E){const F=(E+1)/C,H=3*(z*q+E);t.push(vec3(D[H],D[H+1],D[H+2]));v.push(y*F);B.push(d.scale(1,F))}a.drawRibbon(t,v,this.tileInfo,B)}else if(g){const D=render3DBillboardAxes(e,A,!1),B=render3DInstanceSlot(f,k);h=f.instanceData;h[B]=2*D[0];h[B+1]=2*D[1];h[B+2]=2*D[2];h[B+3]=0;h[B+4]=2*D[3];h[B+5]=2*D[4];h[B+6]=2*D[5];h[B+7]=0;h[B+8]=n.x;h[B+9]=n.y;h[B+10]=n.z;h[B+11]=0;h[B+12]=r[t];h[B+13]=r[t+1];h[B+14]=r[t+2];h[B+15]=1;h[B+16]=d.r;h[B+17]=d.g;h[B+18]=d.b;h[B+19]=d.a;h[B+20]=l.x;h[B+21]=l.y;h[B+22]=l.w;h[B+23]=l.h}else u.x=r[t],u.y=r[t+1],u.z=r[t+2],c?a.drawBillboard(u,e,c,d,A):a.drawSoftDisc(u,y,d,void 0,8)}}finally{g&&(a.lighting=m,a.flush(),render3DFlushInstances(f))}}}class Trail3D extends EngineObject3D{constructor(a=vec3(),b=1,c=.2,d,e=WHITE,f=CLEAR_WHITE,g=!1){super(a,void 0,d,e);this.transparent=!0;this.additive=g;this.castShadow=!1;this.size3D=vec3();this.finishing=!1;this.lifeTime=b;this.width=c;this.colorEnd=f.copy();this.side=void 0;this.samples=[]}clear(){this.samples.length=0}destroy(a){if(a||!this.samples.length||this.destroyed||Infinity==this.lifeTime)return super.destroy(a);this.finishing=!0;render3DDetach(this)}update(){const a=this.samples;if(!this.finishing){const b=this.worldPos3D=this.getWorldPos3D(),c=a[a.length-1];(!c||1e-8<b.distanceSquared(c.pos))&&a.push({pos:b,side:this.side?.copy(),time:time})}for(;a.length&&time-a[0].time>this.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 p=0;16384>p;++p){var l=abs(p%128+.5-64);const r=abs((p/128|0)+.5-64);l=max(r,l*cos(PI/6)+r/2)/n;m[4*p]=m[4*p+1]=m[4*p+2]=255;m[4*p+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=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=0<b?[{at:0,size:.7*b,color:hsl(0,0,1,.5),shape:"glow"},{at:0,size:.25*b,color:hsl(0,0,1,.9),shape:"glow"}]:[];for(let h=0;h<this.count;++h){const k=(h+f.float(.2,.8))/max(this.count,1)*1.9+.2;var e=f.float();e=a?a[min(e*a.length|0,a.length-1)]:.5>e?"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<d){var e=this.color.multiply(render3D.sunColor),f=mainCanvasSize.y*this.flareSize,g=this.light;if(g){e=render3DLightCone(g);var h=a.direction;h=clamp(-(e[0]*h.x+e[1]*h.y+e[2]*h.z)-e[3]);e=g.color;h*=e.a*clamp(g.intensity);if(!(0<h))return;e=this.color.multiply(rgb(e.r,e.g,e.b,h));g.directional||(f*=min(1,g.radius/a.distance))}return 0<f?{sun:c,center:b,strength:d,tint:e,height:f}:void 0}}}getScreenPos(){const a=this.flareSource();return a&&render3D.worldToScreen(a.pos)}getScreenElements(){const a=0<this.visible&&this.flareLook();if(!a)return[];const{sun:b,center:c,tint:d,height:e}=a,f=a.strength*this.visible;return this.getElements().map(g=>{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&&!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();const a=!!this.flareLook()&&!(this.occlusion&&this.isHidden()),b=0<this.fadeTime?timeDelta/this.fadeTime:1;this.visible=clamp(this.visible+(a?b:-b))}render(){if(!headlessMode&&glEnable){var a=this.getScreenElements();if(a.length){setAdditiveBlendMode(!0);for(const b of a){a=b.tileInfo||render3DFlareTile(b.shape);const c="number"==typeof b.size?vec2(b.size):b.size;a&&drawTile(b.pos,c,a,b.color,b.angle,!1,void 0,!0,!0)}setAdditiveBlendMode(!1)}}}render3D(){}}function parseOBJ(a,b=render3D?.smoothShading){const c=[],d=[],e=[],f=[],g=[],h=[],k=[],l=new Map,m=[];let n=!1,p=0;const r=(u,t)=>{u=parseInt(u);return 0>u?t.length+u:u-1};for(const u of a.replace(/\\\r?\n/g," ").split(/\r\n?|\n/))switch(a=u.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 t=a.map(x=>c[r(x[0],c)]);if(!t.every(isVector3))break;const v=a.every(x=>x[2]);n||=!v;const z=v?void 0:render3DFaceNormal(t[0],t[1],t[2],t[3]);a=a.map((x,w)=>{const y=r(x[0],c)+"/"+(x[1]?r(x[1],e):"")+"/"+(v?r(x[2],d):b?"":"f"+p);let A=l.get(y);void 0===A&&(l.set(y,A=f.length),f.push(t[w]),h.push(x[1]?e[r(x[1],e)]:RENDER3D_DEFAULT_UV),g.push(v?d[r(x[2],d)]:z),m.push(v));return A});for(let x=2;x<a.length;++x)k.push(a[1],a[x],a[(x+1)%a.length]);++p}const q=(new Mesh).addTriangles(f,k,g,h);if(n&&b){const u=q.normals;q.computeNormals(!0);m.forEach((t,v)=>t&&(q.normals[v]=u[v]))}return q}async function loadOBJ(a,b=render3D?.smoothShading){var c=await fetch(a);if(!c.ok)throw Error("loadOBJ failed: "+a);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)(0<g.dot(b.plane.normal)?c:d).push(b);else if(1===l)e.push(b);else if(2===l)f.push(b);else{c=[];d=[];for(m=0;m<a.length;++m){var p=(m+1)%a.length;l=k[m];n=k[p];const r=a[m];p=a[p];2!==l&&c.push(r);1!==l&&d.push(r);3===(l|n)&&(l=r.lerp(p,(h-g.dot(r.pos))/g.dot(p.pos.subtract(r.pos))),c.push(l),d.push(l))}3<=c.length&&e.push(new Render3DCSGPolygon(c,b.plane));3<=d.length&&f.push(new Render3DCSGPolygon(d,b.plane))}}function render3DCSGNodes(a){const b=[];for(a=[a];a.length;){const c=a.pop();b.push(c);c.front&&a.push(c.front);c.back&&a.push(c.back)}return b}function render3DCSGBuild(a,b){for(a=[[a,b]];a.length;){const[c,d]=a.pop();if(!d.length)continue;let e;(e=c).plane||(e.plane=d[0].plane);b=[];const f=[];for(const k of d)render3DCSGSplit(c.plane,k,c.polygons,c.polygons,b,f);let g;b.length&&a.push([(g=c).front||(g.front=new Render3DCSGNode),b]);let h;f.length&&a.push([(h=c).back||(h.back=new Render3DCSGNode),f])}}function render3DCSGInvert(a){for(const b of render3DCSGNodes(a)){let c;(c=b).plane&&(c.plane={normal:b.plane.normal.scale(-1),w:-b.plane.w});[b.front,b.back]=[b.back,b.front]}}function render3DCSGClipPolygons(a,b){const c=[];for(a=[[a,b]];a.length;){const[d,e]=a.pop();if(!d.plane){for(const g of e)c.push(g);continue}b=[];const f=[];for(const g of e)render3DCSGSplit(d.plane,g,b,f,b,f);if(d.front)a.push([d.front,b]);else for(const g of b)c.push(g);d.back&&a.push([d.back,f])}return c}function render3DCSGNear(a,b){const c=vec3(Infinity),d=vec3(-Infinity);for(var e of b)for(var{pos:f}of e.vertices)c.x=min(c.x,f.x),c.y=min(c.y,f.y),c.z=min(c.z,f.z),d.x=max(d.x,f.x),d.y=max(d.y,f.y),d.z=max(d.z,f.z);b=[];e=[];f=[[vec3(1,0,0),d.x],[vec3(-1,0,0),-c.x],[vec3(0,1,0),d.y],[vec3(0,-1,0),-c.y],[vec3(0,0,1),d.z],[vec3(0,0,-1),-c.z]];const g=RENDER3D_CSG_EPSILON;for(const k of a){var h=a=Infinity;let l=Infinity,m=-Infinity,n=-Infinity,p=-Infinity;for(const{pos:r}of k.vertices)a=min(a,r.x),h=min(h,r.y),l=min(l,r.z),m=max(m,r.x),n=max(n,r.y),p=max(p,r.z);if(a>d.x+g||m<c.x-g||h>d.y+g||n<c.y-g||l>d.z+g||p<c.z-g)e.push(k);else{a=[k];for(const[r,q]of f){h=[];for(const u of a)render3DCSGSplit({normal:r,w:q},u,h,h,e,h);a=h}for(const r of a)b.push(r)}}return[b,e]}function render3DCSGPlacer(a){const b=new Map;return c=>{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)<a**2)return l;d=d+","+e+","+f;b.has(d)||b.set(d,[]);b.get(d).push(c);return c}}function render3DMeshIsClosed(a){const b=a.points;a=a.indices;let c=0,d=0,e=0,f=0;for(let h=0;h<a.length;h+=3){var g=b[a[h]];g=b[a[h+1]].subtract(g).cross(b[a[h+2]].subtract(g));c+=g.x;d+=g.y;e+=g.z;f+=g.length()}return 0<f&&hypot(c,d,e)<=1e-4*f}function render3DCSGPolygons(a,b){const c=(new Mesh).combine(a,b).toIndexed();a=d=>new Render3DCSGVertex(c.points[d],c.normals[d],c.uvs[d],c.colors[d]);b=[];for(let d=0;d<c.indices.length;d+=3){const e=c.indices[d],f=c.indices[d+1],g=c.indices[d+2],h=render3DCSGPlane(c.points[e],c.points[f],c.points[g]);h&&b.push(new Render3DCSGPolygon([a(e),a(f),a(g)],h))}return b}function render3DCSGMesh(a){const b=4*RENDER3D_CSG_EPSILON,c=render3DCSGPlacer(RENDER3D_CSG_EPSILON),d=new Set;a=a.map(q=>{const u=[];for(const t of q.vertices)q=c(t.pos),d.add(q),u.length&&u[u.length-1].pos===q||u.push(new Render3DCSGVertex(q,t.normal,t.uv,t.color));1<u.length&&u[0].pos===u[u.length-1].pos&&u.pop();return u});var e=[...d];let f=vec3(Infinity);var g=vec3(-Infinity);for(var h of e)f=vec3(min(f.x,h.x),min(f.y,h.y),min(f.z,h.z)),g=vec3(max(g.x,h.x),max(g.y,h.y),max(g.z,h.z));h=e.length?max(g.x-f.x,g.y-f.y,g.z-f.z):0;const k=max(h/Math.cbrt(e.length||1),b),l=new Map;h=q=>{var u=floor((q.x-f.x)/k),t=floor((q.y-f.y)/k);q=floor((q.z-f.z)/k);return u+","+t+","+q};for(var m of e)e=h(m),l.has(e)||l.set(e,[]),l.get(e).push(m);m=(q,u)=>{const t=[],v=u.subtract(q),z=v.lengthSquared();var x=floor((min(q.x,u.x)-f.x-b)/k);const w=floor((max(q.x,u.x)-f.x+b)/k),y=floor((min(q.y,u.y)-f.y-b)/k),A=floor((max(q.y,u.y)-f.y+b)/k),C=floor((min(q.z,u.z)-f.z-b)/k),D=floor((max(q.z,u.z)-f.z+b)/k);for(;x<=w;++x)for(let B=y;B<=A;++B)for(let E=C;E<=D;++E)for(const F of l.get(x+","+B+","+E)||[]){if(F===q||F===u)continue;const H=F.subtract(q).dot(v)/z;0>=H||1<=H||q.add(v.scale(H)).distanceSquared(F)<b**2&&t.push([H,F])}return t.sort((B,E)=>B[0]-E[0])};const n=new Mesh,p=new Map;n.indices=[];const r=q=>{const u=q.normal.lengthSquared()?q.normal.normalize():RENDER3D_DEFAULT_NORMAL,t=q.color,v=[u.x,u.y,u.z,q.uv.x,q.uv.y,t.r,t.g,t.b,t.a].map(w=>round(1e6*w)).join();let z=p.get(q.pos),x;z||p.set(q.pos,z=new Map);void 0===(x=z.get(v))&&(z.set(v,x=n.points.length),n.points.push(q.pos.copy()),n.normals.push(u),n.uvs.push(q.uv.copy()),n.colors.push(t.copy()));return x};for(const q of a){if(3>q.length)continue;a=[];for(e=0;e<q.length;++e){h=q[e];g=q[(e+1)%q.length];a.push(h);for(const[z,x]of m(h.pos,g.pos)){const w=h.lerp(g,z);a.push(new Render3DCSGVertex(x,w.normal,w.uv,w.color))}}e=a.length;let u=vec3();for(h=1;h<e-1;++h)u=u.add(a[h%e].pos.subtract(a[0%e].pos).cross(a[(h+1)%e].pos.subtract(a[0%e].pos)));if(1e-18>u.lengthSquared())continue;const t=a.map(z=>({pos:z.pos,id:r(z)})),v=z=>{const x=t[(z+t.length-1)%t.length].pos,w=t[(z+1)%t.length].pos;return t[z].pos.subtract(x).cross(w.subtract(x))};for(;3<t.length;)a=t.findIndex((z,x)=>{z=v(x);return 1e-18<=z.lengthSquared()&&1e-18<=u.subtract(z).lengthSquared()}),0>a&&(a=0),u=u.subtract(v(a)),n.indices.push(t[(a+t.length-1)%t.length].id,t[a].id,t[(a+1)%t.length].id),t.splice(a,1);n.indices.push(t[0].id,t[1].id,t[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);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,p=this.ambientOcclusion,r=(D,B,E)=>(D=this.voxelAt(D,B,E))&&!this.blockType(D).seeThrough?1:0,q=[],u=[],t=[],v=[];for(;h<c;++h)for(let D=g;D<k;++D)for(let B=f;B<b;++B){const E=e[B+d.x*(D+d.y*h)];if(!E)continue;const F=this.blockType(E),H=F.transparent?n:m,G=B+.5-l.x,I=D+.5-l.y,K=h+.5-l.z;for(let O=0;6>O;++O){const[N,L,M]=RENDER3D_VOXEL_FACES[O];var z=B+N.x,x=D+N.y,w=h+N.z,y=this.voxelAt(z,x,w);if(!y||y!==E&&this.blockType(y).seeThrough){for(y=0;4>y;++y){const[J,P]=RENDER3D_VOXEL_CORNER_SIDES[y];var A=p&&r(z+L.x*J,x+L.y*J,w+L.z*J),C=p&&r(z+M.x*P,x+M.y*P,w+M.z*P);const Q=p&&r(z+L.x*J+M.x*P,x+L.y*J+M.y*P,w+L.z*J+M.z*P);v[y]=A&&C?0:3-+A-+C-+Q}z=RENDER3D_VOXEL_CORNERS[O];x=this.tileUVs(F.faces[O]);w=v[0]+v[3]>v[1]+v[2]?RENDER3D_VOXEL_FLIPPED:RENDER3D_VOXEL_ORDER;for(y=0;4>y;++y)A=w[y],C=z[A],q[y]=vec3(G+C.x,I+C.y,K+C.z),u[y]=x[A],t[y]=p?RENDER3D_VOXEL_SHADES[v[A]]:WHITE;H.addStrip(q,N,u,t);F.doubleSided&&H.addStrip([q[0],q[2],q[1],q[3]],N.scale(-1),[u[0],u[2],u[1],u[3]],[t[0],t[2],t[1],t[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=(p,r,q,u)=>{const t=floor(p-r-q+1e-9);p=max(ceil(p+r-q-1e-9)-1,t);return[max(t,0),min(p,u-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 p=d[m]-b[m],r=c[m]/2,q=f[m];if(!p)continue;k=t=>0<p?ceil(t+r-q-1e-9)-1:floor(t-r-q+1e-9);g=k(b[m]);k=k(d[m]);h=min(g,k)+(0<p?1:0);l=max(g,k)-(0<p?0:1);var n=b.copy();const u=c.copy();n[m]=q+(h+l+1)/2;u[m]=l-h+1;g!==k&&this.boxBlocked(n,u,a)?("y"===m&&0>p&&(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],p=e[m];if(n){var r=-p/n;m=(d[m]-p)/n;r>m&&([r,m]=[m,r]);r>g&&(g=r,k=l);h=min(h,m)}else if(0>p||p>d[m])return}if(!(g>h)){r=e.add(f.scale(g));e=[];var q=[];h=[];l=[];for(m=0;3>m;++m)n=a[m],p=f[n],e[m]=clamp(floor(r[n]),0,d[n]-1),q[m]=sign(p),h[m]=p?g+(e[m]+(0<p?1:0)-r[n])/p:Infinity,l[m]=p?abs(1/p):Infinity;r=u=>vec3(0===u?-q[0]:0,1===u?-q[1]:0,2===u?-q[2]:0);0<=k?f=r(k):(f=abs(f.x)>=abs(f.y)&&abs(f.x)>=abs(f.z)?0:abs(f.y)>=abs(f.z)?1:2,f=r(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]<h[1]?h[0]<h[2]?0:2:h[1]<h[2]?1:2;g=h[f];e[f]+=q[f];if(0>e[f]||e[f]>=d[a[f]])break;h[f]+=l[f];f=r(f)}}}}levelRaycast3D(a){return this.raycast(a)?.distance}levelSegment3D(a,b){return(a=this.raycast(new Ray3D(a,b.subtract(a)),1))&&0<a.distance?{distance:a.distance,normal:a.normal}:void 0}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;d<a.length;++d){const e=a[d],f=this.chunkCenters[d];e&&render3D.drawMesh(e,vec3(b.x+f.x,b.y+f.y,b.z+f.z),c,this.color)}}destroy(a){render3DLevelLeave(this);for(const b of[...this.chunkMeshes,...this.chunkTransparentMeshes])b?.dispose();super.destroy(a)}}const LEVEL3D_VERSION=1,level3DTypes=new Map,level3DBaseScale=new WeakMap;function level3DAddType(a,b,c={},d){level3DTypes.set(String(a),{make:b,defaults:c,tileInfo:d})}function level3DAddMesh(a,b,c,d=WHITE){level3DAddType(a,function(e,f){return level3DMakeShape(e,f,b,c)},{color:d,solid:!1},c)}function level3DLoad(a){editor3DLevelLoaded(a);level3DPrefabsAdd(a.prefabs);level3DSceneApply(a.scene);const b=[];var c=level3DVoxelMap=level3DVoxelsMake(a.voxels);c&&b.push(c);(c=level3DTerrainMap=level3DTerrainMake(a.terrain))&&b.push(c);for(const d of isArray(a.objects)?a.objects:[])d&&"object"===typeof d&&(a=level3DMake(d),editor3DObjectMade(d,a),a&&b.push(a));return b}let level3DVoxelTiles,level3DVoxelSetupMap,level3DVoxelMap;function level3DVoxelSetup(a,b){level3DVoxelTiles=a;level3DVoxelSetupMap=b}const LEVEL3D_VOXEL_CELLS=2**24;function level3DVoxelsEncode(a){const b=[];for(let c=0;c<a.length;){let d=c+1;for(;d<a.length&&a[d]===a[c];)++d;b.push(d-c,a[c]);c=d}return b}function level3DVoxelsDecode(a,b){b.fill(0);if(isArray(a))for(let d=0,e=0;d+1<a.length&&e<b.length;d+=2){var c=a[d];const f=a[d+1];if(!isNumber(c)||!isNumber(f)||0>c)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)&&0<f)&&!(!isArray(c)||2>c.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<a.height?a.height:1,heights:c}}}}function level3DHexColor(a){return"string"===typeof a&&/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.test(a)?(new Color).setHex(a):void 0}const level3DFinite=a=>"number"===typeof a&&isFinite(a);function level3DTerrainPaint(a,b){var c=a?.paint;a=c?.colors;c=c?.cells;if(isArray(a)&&isArray(c)&&!(255<a.length)&&a.every(level3DHexColor)){var d=new Uint8Array(b),e=0;for(let f=0;f<c.length;f+=2){const g=c[f],h=c[f+1];if(!(0<g&&0===g%1&&0<=h&&0===h%1)||h>a.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){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)}}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<level3DPrefabAttached;this.parts=[];this.originOffset=vec3();this.partObjects=[];this.partsPlaced="";this.partsMade=!1}placeAt(a){this.pos3D=a.copy();this.placeParts();const b=this.originOffset;if(b.x||b.y||b.z)this.pos3D=buildMatrix(a,this.rotation3D,this.scale3D).transformPoint(b)}placeParts(){this.destroyed||(this.partsMade||(this.partsMade=(this.makeParts(),!0)),this.partsPlaced=this.placeKey(),this.attached||this.parts.forEach((a,b)=>{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),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",0,1e9);particleEffectAddSetting("angleSpeed","number",.05,0,.5,.005,"Spin speed, radians per frame",0,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");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?b.slice(0,60).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$83=particleEffectBehavior;b$jscomp$83("wobble").update=(a,b)=>{a.velocity.x+=.003*b*a.scale*sin(6*time+97*a.lifeTime%9)};b$jscomp$83("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$83("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$83("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$83("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$83("wind").update=(a,b)=>a.velocity.x+=.004*b*a.scale*min((time-a.spawnTime)/a.lifeTime,1);b$jscomp$83("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.tileIndex<floor(b.size.x/c)*floor(b.size.y/c))return tile(a.tileIndex,a.tileSize,0,a.tilePadding)}}function particleEffectApply(a,b){particleEffectSet(a,particleEffectSanitize(b))}function particleEffectSet(a,b){const c=b.settings,d=0>a.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)}function particleEffectResolve(a,b){if(a="string"==typeof a?particleEffectsGet(a):a){var c={...a.settings};for(var d of particleEffectSettings)void 0!==b[d.name]&&(c[d.name]=b[d.name]);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={}){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]);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$85=particleEffectBehavior,center$jscomp$24=a=>a.emitter.worldPos3D||a.emitter.pos3D;b$jscomp$85("wobble").update3D=(a,b)=>a.velocity.x+=.003*b*a.scale*sin(6*time+97*a.lifeTime%9);b$jscomp$85("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$85("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$85("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$85("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$85("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={}){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.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();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()}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(0<d&&a===this.animation&&this.animationPlaying)this.animationLoop=b,this.animationSpeed=c;else{var e=this.blendFrom;this.blendFrom=void 0;0<d&&(this.blendFrom=(!this.animation||e||this.poseMixed?void 0:{animation:this.animation,time:this.animationTime,speed:this.animationPlaying?this.animationSpeed:0,loop:this.animationLoop})||{nodes:this.poseNodes||new Map},this.blendTime=d,this.blendElapsed=0);this.animation=a;this.animationLoop=b;this.animationSpeed=c;this.animationPlaying=!0;this.setAnimationTime(0>c?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.length&&e<d.length;++e){const f=d[e],g=a[e],h=b.parts[e].skin;f.destroyed||f.parent!==this||(h?gltfSkinApply(h,c,b.modelMatrix,f.mesh):(f.localMatrix=g,f.pos3D=g.getTranslation(),f.rotation3D=g.getRotation(),f.scale3D=g.getScale()))}}}update(){super.update();const a=this.animation,b=this.blendFrom;if(a&&(this.animationPlaying||b)){var c=this.animationTime;this.animationPlaying&&(c=gltfAnimationStep(a,c,this.animationSpeed,this.animationLoop),!this.animationLoop&&(c>=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 fetch(a);if(!b.ok)throw Error("loadGLTF failed: "+a);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){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 y=12;y+8<=a.byteLength;){const A=w.getUint32(y,!0),C=w.getUint32(y+4,!0),D=a.slice(y+8,y+8+A);1313821514===C?d=(new TextDecoder).decode(D):5130562===C&&(e=D);y+=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,y)=>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,y)=>{if(glContext&&"undefined"!=typeof createImageBitmap&&g.has(y))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(y)&&"image/jpeg"!==D.type,E=h.has(y)?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=[],p=[],r=[],q=new Set;let u,t;(d.nodes||[]).forEach((w,y)=>(w.children||[]).forEach(A=>(u=n)[t=A]??(u[t]=y)));const v=(w,y,A,C)=>{if(q.has(w))throw Error("glTF node "+w+" is reached twice, nodes must form trees");q.add(w);const D=d.nodes[w];var B=gltfNodeMatrix(D),E=y?y.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=y?y.copy().multiply(E):E);n[w]=A;p[w]=E.copy().invert();C&&(r[w]=C.copy().multiply(p[w]));if(void 0!==D.mesh){y=d.meshes[D.mesh];A=void 0!==D.skin?d.skins?.[D.skin]:void 0;for(const F of y.primitives){B=A?.joints?.length&&void 0!==F.attributes.JOINTS_0&&void 0!==F.attributes.WEIGHTS_0;const H=gltfPart(d,f,l,F,B?new Matrix4:E,D.name||y.name||"part "+m.length);H&&(H.node=w,B&&(H.skin=gltfSkin(d,f,A,F,H)),m.push(H))}}for(const F of D.children||[])v(F,E,w,C)};let z;try{const w=d.scenes?.[d.scene??0];if(w)(w.nodes||[]).forEach(y=>v(y));else if(d.nodes){const y=new Set(d.nodes.flatMap(A=>A.children||[]));d.nodes.forEach((A,C)=>y.has(C)||v(C))}z=(d.animations||[]).map((y,A)=>new GLTFAnimation(y.name||"animation "+A,y.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=y.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 y of l)y?.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:p,restPose:r};a=gltfNodeWorlds(x,new Map);for(const w of m)w.skin&&gltfSkinApply(w.skin,a,RENDER3D_IDENTITY,w.mesh);return new GLTFModel(m,z,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((q,u)=>k?new Matrix4(k.subarray(16*u,16*u+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 q=0;q<h;++q){var n=e.vertexSource?e.vertexSource[q]:q,p=[];for(const[u,t]of d)for(var r=0;4>r;++r)p.push([u[4*n+r],t[4*n+r]]);1<d.length&&p.sort((u,t)=>t[1]-u[1]);n=0;for(r=0;4>r;++r)n+=p[r][1];for(r=0;4>r;++r){const[u,t]=p[r];a[4*q+r]=u<f.length?u:0;b[4*q+r]=n?t/n:r?0:1}p=g.points[q];n=g.normals[q];l.set([p.x,p.y,p.z],3*q);m.set([n.x,n.y,n.z],3*q);g.points[q]=p.copy();g.normals[q]=n.copy()}return{joints:f,inverseBind:c,vertexJoints:a,vertexWeights:b,bindPoints:l,bindNormals:m}}function gltfSkinMeshCopy(a){const b=new Mesh;b.points=a.points.map(c=>c.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){const e=[],f=[];for(var g=0;g<a.joints.length;++g){var h=c.copy().multiply(b(a.joints[g])).multiply(a.inverseBind[g]);e.push(h.m);f.push(render3DNormalMatrix(h).m)}const{vertexJoints:k,vertexWeights:l,bindPoints:m,bindNormals:n}=a;a=d.points;b=d.normals;for(c=0;c<a.length;++c){var p=m[3*c],r=m[3*c+1],q=m[3*c+2];const u=n[3*c],t=n[3*c+1],v=n[3*c+2];let z=h=g=0,x=0,w=0,y=0;for(let A=0;4>A;++A){const C=l[4*c+A];if(!C)continue;const D=e[k[4*c+A]],B=f[k[4*c+A]];g+=C*(D[0]*p+D[4]*r+D[8]*q+D[12]);h+=C*(D[1]*p+D[5]*r+D[9]*q+D[13]);z+=C*(D[2]*p+D[6]*r+D[10]*q+D[14]);x+=C*(B[0]*u+B[4]*t+B[8]*v);w+=C*(B[1]*u+B[5]*t+B[9]*v);y+=C*(B[2]*u+B[6]*t+B[10]*v)}p=a[c];r=b[c];q=(x*x+w*w+y*y)**.5||1;p.x=g;p.y=h;p.z=z;r.x=x/q;r.y=w/q;r.z=y/q}d.dirty=!0}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<e.length;b+=4)e[b]=255;a.close();return createImageBitmap(new ImageData(e,c,d))}function gltfSample(a,b,c){const{times:d,values:e,components:f,interpolation:g}=a;var h=d.length-1,k="CUBICSPLINE"===g,l=k?3*f:f,m=k?f:0;a=0;for(var n=h;a<n;){var p=a+n+1>>1;d[p]<=b?a=p:n=p-1}if(a>=h||b<=d[0]||"STEP"===g)for(b=0;b<f;++b)c[b]=e[a*l+m+b];else{m=d[a+1]-d[a];b=(b-d[a])/m;a*=l;l=a+l;if(k)for(n=b*b,p=n*b,k=2*p-3*n+1,b=p-2*n+b,h=-2*p+3*n,n=p-n,p=0;p<f;++p)c[p]=k*e[a+f+p]+b*m*e[a+2*f+p]+h*e[l+f+p]+n*m*e[l+p];else if(4===f){h=0;for(m=0;4>m;++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;m<f;++m)c[m]=e[a+m]+(e[l+m]-e[a+m])*b;if(4===f)for(a=hypot(c[0],c[1],c[2],c[3])||1,l=0;4>l;++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<b.length;++d)c[d]=b.charCodeAt(d);return Promise.resolve(new Response(c.buffer,{headers:{"Content-Type":a.slice(5,a.indexOf(";"))}}))}const e=(c=(c="undefined"!==typeof location&&location.href)?new URL(b,c):/^[a-z][a-z0-9+.-]*:/i.test(b)?b:void 0)?new URL(a,c).href:b+a;return fetch(e).then(f=>{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`);var k=h.BYTES_PER_ELEMENT,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");c=new Float32Array(d.count*f);if(e)if(m=b[e.buffer],e=(e.byteOffset||0)+(d.byteOffset||0),n===f*k)c.set(new h(m,e,d.count*f));else for(k=0;k<d.count;++k)c.set(new h(m,e+k*n,f),k*f);if(k=d.sparse){const{indices:p,values:r}=k;g=g[p.componentType];n=a.bufferViews?.[p.bufferView];a=a.bufferViews?.[r.bufferView];if(!g||!n||!a)throw Error("glTF sparse accessor is missing its indices or values");g=new g(b[n.buffer],(n.byteOffset||0)+(p.byteOffset||0),k.count);b=new h(b[a.buffer],(a.byteOffset||0)+(r.byteOffset||0),k.count*f);for(h=0;h<k.count;++h)c.set(b.subarray(h*f,(h+1)*f),g[h]*f)}if(1!==l)for(b=0;b<c.length;++b)c[b]=max(c[b]/l,-1);return{data:c,components:f,count:d.count}}function gltfPart(a,b,c,d,e,f){var g=d.mode??4;if(!(4>g)){var h=d.attributes,k=(B,E)=>{const{data:F,components:H,count:G}=gltfAccessor(a,b,B);B=[];for(let I=0;I<G;++I)B.push(E(F,I*H,H));return B},l=k(h.POSITION,(B,E)=>vec3(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]||{},p=n.pbrMetallicRoughness||{},r=p.baseColorTexture,q=r?.extensions?.KHR_texture_transform,u=h["TEXCOORD_"+(q?.texCoord??r?.texCoord??0)],[t,v]=q?.offset||[0,0],[z,x]=q?.scale||[1,1];q=q?.rotation||0;var w=cos(q),y=sin(q);u=void 0!==u?k(u,(B,E)=>vec2(w*z*B[E]+y*x*B[E+1]+t,w*x*B[E+1]-y*z*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]),3<F?B[E+3]:1)):void 0;d=void 0!==d.indices?Array.from(gltfAccessor(a,b,d.indices).data):l.map((B,E)=>E);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,u,h);g=m?void 0:l.indices.slice();m||l.computeNormals(!1);l.transform(e);m=p.baseColorFactor||[1,1,1,1];l.doubleSided=!!n.doubleSided;p=n.extensions?.KHR_materials_transmission?.transmissionFactor||0;d="BLEND"===n.alphaMode;h=(d?m[3]:1)*(1-.8*p);e=r&&a.textures?.[r.index];f=new GLTFPart(f,l,rgb(gltfSRGB(m[0]),gltfSRGB(m[1]),gltfSRGB(m[2]),h),r?c[r.index]:void 0,d||0<p);f.pixelated=9728===a.samplers?.[e?.sampler]?.magFilter;f.vertexSource=g;f.unlit=!!n.extensions?.KHR_materials_unlit;e=n.normalTexture;r=n.emissiveTexture;f.normalMap=e&&c[e.index];f.normalScale=e?.scale??1;var[A,C,D]=n.emissiveFactor||[0,0,0];if(A||C||D)n=n.extensions?.KHR_materials_emissive_strength?.emissiveStrength??1,f.emissiveMap=r?c[r.index]:gltfWhiteTexture(),f.emissiveMapColor=rgb(gltfSRGB(A)*n,gltfSRGB(C)*n,gltfSRGB(D)*n);return f}}let gltfWhiteTextureInfo;function gltfWhiteTexture(){if(gltfWhiteTextureInfo||!glContext||!canvasAvailable())return gltfWhiteTextureInfo;const a=createCanvasContext(1);a.fillStyle="#fff";a.fillRect(0,0,1,1);return gltfWhiteTextureInfo=new TextureInfo(a.canvas)}function gltfSRGB(a){return.0031308>=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))}}
|
|
43
|
+
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;in vec2 vWorldPos;in vec2 vUV;out vec4 c;void main(){float dist=distance(vWorldPos,lightPos);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;}");d(lightSystem.lightShader)||(glContext.useProgram(lightSystem.lightShader),glContext.uniform1i(glUniformLocation(lightSystem.lightShader,"shadowTexture"),1),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)<core?vec3(1):o,1);}"),p.shadowStretchShader=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 float scale;uniform float brightness;in vec2 uv;out vec4 c;void main(){float mask=1.-smoothstep(.35,.525,length(uv-.5));vec3 b=texture(s,(uv-.5)/scale+.5).rgb;c=vec4(min(texture(s,uv).rgb+brightness*mask*b,b),1);}"),d(p.shadowCopyShader,p.shadowStretchShader)||(p.shadowCopyVAO=e(p.shadowCopyShader,"p"),p.shadowStretchVAO=e(p.shadowStretchShader,"p"),q.useProgram(p.shadowCopyShader),q.uniform1i(glUniformLocation(p.shadowCopyShader,"s"),1),q.useProgram(p.shadowStretchShader),q.uniform1i(glUniformLocation(p.shadowStretchShader,"s"),1)))}function h(){const q=glContext,p=lightSystem;q.deleteTexture(p.shadowMap);q.deleteTexture(p.shadowTextureA);q.deleteTexture(p.shadowTextureB);q.deleteTexture(p.backgroundMap);p.shadowMap=p.shadowTextureA=p.shadowTextureB=p.backgroundMap=void 0}function k(){const q=lightSystem;q.clampTextureSizes();if(!q.shadowMap||q.shadowMapSize!==q.shadowMapSizeAllocated||q.shadowTextureSize!==q.shadowTextureSizeAllocated)if(q.shadowMap&&h(),g(),q.shadersFailed)return;const p=q.shadowMapSize;var t=mainCanvasSize.scale(1/cameraScale);t=q.shadowMapScale*max(t.x,t.y);var u=q.directionalLight?min(p,q.directionalTextureSize):p;u=t/u;const v=vec2(floor(cameraPos.x/u)*u,floor(cameraPos.y/u)*u);q.shadowMapOrigin=v.subtract(vec2(t/2));q.shadowMapWorldSize=t;u=[drawContext,mainCanvasSize,cameraPos,cameraScale,cameraAngle,canvasClearColor,glCustomShader];drawContext=q.shadowContext;mainCanvasSize=vec2(p);cameraPos=v;cameraScale=p/t;cameraAngle=0;canvasClearColor=WHITE;glSkipScreenSpace=!0;q.shadowPass=!0;try{t=(y,x)=>{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&&0<J){F=B("shadow");const K=clamp(ceil(log2(max(J,1))),1,A);for(let N=0;N<K;++N){const O=w(2**N);q.uniform2f(E(F,"shift"),O.x,O.y);q.uniform1f(E(F,"fade"),2**N/J);D(1,G);C(H);q.drawArrays(q.TRIANGLE_STRIP,0,4);[G,H]=[H,G]}}const M=G;if(G=p.backgroundCasters)F=B("seed"),D(1,p.shadowMap),D(2,p.backgroundMap),q.uniform1f(E(F,"useF"),0),q.uniform1f(E(F,"useB"),1),C(H),q.drawArrays(q.TRIANGLE_STRIP,0,4);let L=H;H=p.directionalTexture;t=t.backgroundDepth*v/y;if(G&&0<t)for(F=B("leak"),A=clamp(ceil(log2(max(t,1))),1,A),y=0;y<A;++y)J=w(2**y),q.uniform2f(E(F,"shift"),J.x,J.y),q.uniform1f(E(F,"fade"),2**y/t),D(1,L),C(H),q.drawArrays(q.TRIANGLE_STRIP,0,4),[L,H]=[H,L];A=[p.directionalTexture,p.directionalTextureA,p.directionalTextureB];const I=A.find(K=>K!==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||!(0<x.emissive))continue;const w=255*clamp(x.emissive)+.5|0;glColorMask=4278190080;glColorAdditive=w|w<<8|w<<16;glAdditive||setAdditiveBlendMode();setShader(x.shader);x.renderEmissive()}glFlush()}finally{lightSystem.emissivePass=!1,glColorMask=-1,glColorAdditive=0,[drawContext,glCustomShader]=p}}finally{glRenderTargetBase=void 0}glFlush();glContext.bindFramebuffer(glContext.FRAMEBUFFER,null);glContext.viewport(0,0,glCanvas.width,glCanvas.height);glContext.useProgram(lightSystem.compositeShader);glContext.bindVertexArray(lightSystem.compositeVAO);glContext.activeTexture(glContext.TEXTURE0);glContext.bindTexture(glContext.TEXTURE_2D,lightSystem.texture);x=lightSystem.compositeShader;glContext.uniform1i(glUniformLocation(x,"s"),0);glContext.uniform3f(glUniformLocation(x,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.blendFunc(glContext.DST_COLOR,glContext.ZERO);glContext.drawArrays(glContext.TRIANGLE_STRIP,0,4);glActiveTexture&&glContext.bindTexture(glContext.TEXTURE_2D,glActiveTexture);glSetInstancedMode(!0);setAdditiveBlendMode();for(const w of engineObjects)w instanceof Light&&!w.destroyed&&w.renderGlow();glFlush();setAdditiveBlendMode(q)}}}},function(){lightSystem.texture=void 0;lightSystem.lightShader=void 0;lightSystem.compositeShader=void 0;lightSystem.lightVAO=void 0;lightSystem.compositeVAO=void 0;var q=lightSystem;q.shadowMap=q.shadowTextureA=q.shadowTextureB=q.backgroundMap=void 0;q.shadowCopyShader=q.shadowStretchShader=void 0;q.shadowCopyVAO=q.shadowStretchVAO=void 0;q=lightSystem;q.directionalTexture=q.directionalTextureA=q.directionalTextureB=void 0;q.directionalPrograms={};q.directionalTextureSizeAllocated=0},function(){lightSystem.shadersFailed=!1;c()})}clampTextureSizes(){this.shadowMapSize=glClampTextureSize(this.shadowMapSize);this.shadowTextureSize=glClampTextureSize(this.shadowTextureSize);this.directionalTextureSize=glClampTextureSize(max(1,floor(this.directionalTextureSize)||1));const a=this.textureSize;if(a){var b=glClampTextureSize(a.x),c=glClampTextureSize(a.y);if(b!==a.x||c!==a.y)this.textureSize=vec2(b,c)}}drawLight(a){if(!headlessMode&&glEnable&&this.lightShader&&isOnScreen(a.pos,2*a.radius)){glFlush();var b=this.shadows&&a.castShadow&&!!this.shadowMap;b&&this.renderLightShadow(a);glContext.useProgram(this.lightShader);glContext.bindVertexArray(this.lightVAO);glContext.enable(glContext.BLEND);glContext.blendFunc(glContext.ONE,glContext.ONE);var c=this.lightShader;glContext.uniform2f(glUniformLocation(c,"lightPos"),a.pos.x,a.pos.y);glContext.uniform1f(glUniformLocation(c,"radius"),a.radius);glContext.uniform1f(glUniformLocation(c,"fadeRange"),a.fadeRange);glContext.uniform1i(glUniformLocation(c,"useShadow"),b?1:0);a=a.color;glContext.uniform4f(glUniformLocation(c,"color"),a.r,a.g,a.b,a.a);glContext.drawArrays(glContext.TRIANGLE_STRIP,0,4);glSetInstancedMode(!0)}}renderLightShadow(a){const b=glContext;var c=this.shadowTextureSize;b.disable(b.BLEND);b.viewport(0,0,c,c);b.activeTexture(b.TEXTURE1);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,this.shadowTextureA,0);var d=this.shadowCopyShader;b.useProgram(d);b.bindVertexArray(this.shadowCopyVAO);b.bindTexture(b.TEXTURE_2D,this.shadowMap);b.uniform2f(glUniformLocation(d,"lightPos"),a.pos.x,a.pos.y);b.uniform1f(glUniformLocation(d,"radius"),a.radius);b.uniform2f(glUniformLocation(d,"mapOrigin"),this.shadowMapOrigin.x,this.shadowMapOrigin.y);b.uniform1f(glUniformLocation(d,"mapInvSize"),1/this.shadowMapWorldSize);b.uniform1f(glUniformLocation(d,"tap"),a.radius/c);b.uniform1f(glUniformLocation(d,"core"),a.shadowCore);b.drawArrays(b.TRIANGLE_STRIP,0,4);a=this.shadowStretchShader;b.useProgram(a);b.bindVertexArray(this.shadowStretchVAO);c=this.shadowTextureA;d=this.shadowTextureB;for(let e=0;e<this.shadowPassCount;++e)b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,d,0),b.bindTexture(b.TEXTURE_2D,c),b.uniform1f(glUniformLocation(a,"scale"),1+2*1.5**e/256),b.uniform1f(glUniformLocation(a,"brightness"),clamp((10.1-e)/7.2)**2*this.shadowSoftness),b.drawArrays(b.TRIANGLE_STRIP,0,4),[c,d]=[d,c];b.bindTexture(b.TEXTURE_2D,c);b.activeTexture(b.TEXTURE0);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,this.texture,0);b.viewport(0,0,this.textureSize.x,this.textureSize.y);b.enable(b.BLEND);b.blendFunc(b.ONE,b.ONE)}setShadowTransparent(a=!0){this.shadowPass&&(glColorMask=a?-1:4278190080)}}class Light extends EngineObject{constructor(a,b,c,d){super(a,vec2(1),void 0,0,c);this.mass=0;this.radius=b;this.fadeRange=void 0===d?b:d;this.glow=this.shadowCore=0;this.glowFalloff=1;this.glowTileInfo=void 0}render(){}renderLight(){lightSystem&&lightSystem.drawLight(this)}renderGlow(){if(0<this.glow){var a=vec2(this.glow);if(isOnScreen(this.pos,a)){var b=engineGlowTexture(this.glowFalloff);b&&(this.glowTileInfo?.textureInfo!==b&&(this.glowTileInfo=new TileInfo(vec2(),b.size,b)),drawTile(this.pos,a,this.glowTileInfo,this.color,0,!1,void 0,!0,!1))}}}}class DirectionalLight extends EngineObject{constructor(a=vec2(-1,1),b=WHITE){super(vec2(),vec2(),void 0,0,b);this.mass=0;this.sunDirection=a.copy();this.shadowLength=20;this.backgroundDepth=3;lightSystem?.directionalLight?.destroy();lightSystem&&(lightSystem.directionalLight=this)}update(){}render(){}destroy(a){lightSystem?.directionalLight===this&&(lightSystem.directionalLight=void 0);super.destroy(a)}}class AudioEffect{constructor(a=1){this.mix=clamp(a);audioContext&&(this.input=audioContext.createGain(),this.output=audioContext.createGain(),this.dryGain=audioContext.createGain(),this.wetGain=audioContext.createGain(),this.input.connect(this.dryGain).connect(this.output),this.wetGain.connect(this.output),this.setMix(a),this.output.connect(audioMasterGain))}setMix(a,b=0){this.mix=a=clamp(a);audioContext&&(this.rampParam(this.dryGain.gain,1-a,b),this.rampParam(this.wetGain.gain,a,b))}rampParam(a,b,c=0){audioParamRamp(a,b,c);if(c){var d=new ConstantSourceNode(audioContext,{offset:0});d.connect(this.input);d.onended=()=>d.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<g?0:f.length-1]);uiSystem.navigationObject!==h&&(uiSystem.navigationMode=!0,uiSystem.hoverObject=void 0,uiSystem.navigationObject=h,uiSystem.navigationTimer.set(uiSystem.navigationDelay),h.soundPress&&h.soundPress.play())}}uiSystem.navigationObject&&uiSystem.getNavigationWasPressed()&&(uiSystem.navigationObject.navigatePressed(),isUsingGamepad?inputClearKey(0,gamepadPrimary+1,!1,!0,!1):(inputClearKey("Space",0,!1,!0,!1),inputClearKey("Enter",0,!1,!0,!1)))}f=uiSystem.uiObjects;(g=uiSystem.confirmDialog)&&d(g);for(h=f.length;h--;){const k=f[h];k.parent||k===g||d(k)}e&&mouseWasPressed(0)&&inputClearKey(0,0);uiSystem.uiObjects=uiSystem.uiObjects.filter(k=>!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(0<uiDebug){function g(h,k=!0){k&&=!!h.visible;if(!(h.destroyed||!k&&2>uiDebug)){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<e.a&&(m.strokeStyle=e.toString(),m.lineWidth=d,m.stroke())}drawSlice(a,b,c,d=WHITE){0<d.a&&a.drawScreen(b,c,d,void 0,0,!1,uiSystem.uiContext)}drawLine(a,b,c=uiSystem.defaultLineWidth,d=uiSystem.defaultLineColor){const e=uiSystem.uiContext;e.strokeStyle=d.toString();e.lineWidth=c;e.beginPath();e.lineTo(a.x,a.y);e.lineTo(b.x,b.y);e.stroke()}drawTile(a,b,c,d=uiSystem.defaultColor,e=0,f=!1,g=BLACK,h=0,k=vec2()){const l=uiSystem.uiContext;uiSetShadow(l,g,h,k);drawTile(a,b,c,d,e,f,CLEAR_BLACK,!1,!0,l);l.shadowColor="#0000"}drawText(a,b,c,d=uiSystem.defaultColor,e=uiSystem.defaultLineWidth,f=uiSystem.defaultLineColor,g="center",h=uiSystem.defaultFont,k="",l=!0,m,n=BLACK,r=0,q=vec2()){const p=uiSystem.uiContext;m&&0<n.a&&drawTextScreen(a,b.add(m),c.y,n,e,f,g,h,k,l?c.x:void 0,0,p);uiSetShadow(p,n,r,q);drawTextScreen(a,b,c.y,d,e,f,g,h,k,l?c.x:void 0,0,p);p.shadowColor="#0000"}setupDragAndDrop(a,b,c,d){if(this._dragListeners)for(const[g,h]of this._dragListeners)document.removeEventListener(g,h);this._dragListeners=[];const e=(g,h,k=()=>!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){0<b.a&&(c||d.x||d.y)&&(a.shadowColor=b.toString(),a.shadowBlur=c,a.shadowOffsetX=d.x,a.shadowOffsetY=d.y)}function uiObjectIsBehindDialog(a){const b=uiSystem.confirmDialog;if(!b)return!1;for(;a;a=a.parent)if(a===b)return!1;return!0}function uiObjectIsDisabled(a){for(;a;a=a.parent)if(a.disabled)return!0;return!1}function uiObjectIsHidden(a){for(;a;a=a.parent)if(!a.visible)return!0;return!1}class UIObject{constructor(a=vec2(),b=vec2()){this.localPos=a.copy();this.nativePos=a.copy();this.size=b.copy();this.color=uiSystem.defaultColor.copy();this.text=this.activeColor=void 0;this.disabledColor=uiSystem.defaultDisabledColor.copy();this.disabled=!1;this.textColor=uiSystem.defaultTextColor.copy();this.hoverColor=uiSystem.defaultHoverColor.copy();this.lineColor=uiSystem.defaultLineColor.copy();this.gradientColor=uiSystem.defaultGradientColor?uiSystem.defaultGradientColor.copy():void 0;this.lineWidth=uiSystem.defaultLineWidth;this.cornerRadius=uiSystem.defaultCornerRadius;this.slice=uiSystem.defaultSlice;this.font=uiSystem.defaultFont;this.textHeight=this.textWidth=this.fontStyle=void 0;this.textFitScale=uiSystem.defaultTextFitScale;this.textShadow=void 0;this.textLineColor=uiSystem.defaultLineColor.copy();this.textLineWidth=0;this.visible=!0;this.uiUpdatePass=0;this.children=[];this.parent=void 0;this.extraTouchSize=0;this.soundPress=uiSystem.defaultSoundPress;this.soundRelease=uiSystem.defaultSoundRelease;this.soundClick=uiSystem.defaultSoundClick;this.dragActivate=this.interactive=!1;this.canBeHover=!0;this.shadowColor=uiSystem.defaultShadowColor?.copy();this.shadowBlur=uiSystem.defaultShadowBlur;this.shadowOffset=uiSystem.defaultShadowOffset?.copy();this.navigationIndex=void 0;this.navigationAutoSelect=!1;this.anchor=vec2();this.align="center";this.destroyed=!1;uiSystem.uiObjects.push(this)}addChild(a){this.children.push(a);a.parent=this;return a}removeChild(a){this.children.splice(this.children.indexOf(a),1);a.parent=void 0}destroy(){if(!this.destroyed){uiSystem.activeObject===this&&(uiSystem.activeObject=void 0);uiSystem.hoverObject===this&&(uiSystem.hoverObject=void 0);uiSystem.lastHoverObject===this&&(uiSystem.lastHoverObject=void 0);uiSystem.navigationObject===this&&(uiSystem.navigationObject=void 0);uiSystem.keyInputObject===this&&(uiSystem.keyInputObject=void 0);this.destroyed=!0;this.parent?.removeChild(this);for(const a of this.children)a.parent=void 0,a.destroy();this.children.length=0}}isMouseOverlapping(){if(!mouseInWindow)return!1;const a=isTouchDevice?this.size.add(vec2(this.extraTouchSize||0)):this.size,b=uiSystem.screenToNative(mousePosScreen);return isOverlapping(this.nativePos,a,b)}update(){this.onUpdate();if(!this.destroyed){var a=uiObjectIsDisabled(this);if(a&&this===uiSystem.activeObject&&(uiSystem.activeObject=void 0,this!==uiSystem.keyInputObject&&(this.onRelease(),this.destroyed)))return;if(!uiSystem.keyInputObject){var b=uiSystem.lastHoverObject===this,c=this.isActiveObject(),d=mouseIsDown(0),e=mouseWasPressed(0)||this.dragActivate&&d;if(c&&mouseWasPressed(0)){uiSystem.activateOnPress||!this.interactive||a||this.click();if(this.destroyed)return;uiSystem.activeObject=void 0;c=!1;this.onRelease();this.soundRelease&&this.soundRelease.play();if(this.destroyed)return}this.canBeHover&&!uiSystem.navigationMode&&(e||c||!d&&!isTouchDevice)&&!uiSystem.hoverObject&&this.isMouseOverlapping()&&(uiSystem.hoverObject=this);if(this.isHoverObject()){if(!a){if(e&&this.interactive){if(a=!this.dragActivate||!b||mouseWasPressed(0)){this.onPress();if(this.destroyed)return void inputClearKey(0,0,!1,!0,!1);this.soundPress&&this.soundPress.play();if(uiSystem.activeObject&&!c)uiSystem.activeObject.onRelease()}uiSystem.keyInputObject&&uiSystem.keyInputObject!==this?(this.onRelease(),this.soundRelease&&this.soundRelease.play()):(uiSystem.activeObject=this,uiActiveReleased=!d);a&&uiSystem.activateOnPress&&this.click(!this.soundPress);if(this.destroyed)return void inputClearKey(0,0,!1,!0,!1)}uiSystem.activateOnPress||!d&&c&&this.isActiveObject()&&this.interactive&&(mouseWasReleased(0)||uiActiveReleased)&&this.click();if(this.destroyed)return}e&&inputClearKey(0,0,!1,!0,!1)}c&&(!d||this.dragActivate&&!this.isHoverObject())&&(this.onRelease(),this.soundRelease&&this.soundRelease.play(),uiSystem.activeObject=void 0);this.isHoverObject()!==b&&(this.isHoverObject()?this.onEnter():this.onLeave())}}}render(){this.onRender();if(this.size.x&&this.size.y){var a=this.isNavigationObject(),b=this.interactive?uiObjectIsDisabled(this):this.disabled,c=a?this.color:this.interactive&&this.isActiveObject()&&!b?this.color:this.lineColor;b=a?this.hoverColor:b?this.disabledColor:this.interactive?this.isActiveObject()?this.activeColor||this.hoverColor:this.isHoverObject()?this.hoverColor:this.color:this.color;a=this.lineWidth*(a?1.5:1);this.slice?uiSystem.drawSlice(this.slice,this.nativePos,this.size,b):uiSystem.drawRect(this.nativePos,this.size,b,a,c,this.cornerRadius,this.gradientColor,this.shadowColor||CLEAR_BLACK,this.shadowBlur,this.shadowOffset)}}getTextSize(){const a=this.textHeight?1:textLineCount(this.text+"");return vec2(this.textWidth||this.textFitScale*this.size.x,this.textHeight||this.textFitScale*this.size.y/a)}getTextPos(a){return this.nativePos.add(vec2(("left"===this.align?-1:"right"===this.align?1:0)*a.x/2,0))}navigatePressed(){this.click()}isHoverObject(){return uiSystem.hoverObject===this}isActiveObject(){return uiSystem.activeObject===this}isNavigationObject(){return uiSystem.navigationObject===this}isKeyInputObject(){return uiSystem.keyInputObject===this}isInteractive(){return this.interactive&&uiObjectIsUsable(this)}toString(){let a="type = "+this.constructor.name;this.text&&(a+="\ntext = "+this.text);if(this.nativePos.x||this.nativePos.y)a+="\nnativePos = "+this.nativePos;if(this.localPos.x||this.localPos.y)a+="\nlocalPos = "+this.localPos;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.color&&(a+="\ncolor = "+this.color);return a}renderDebug(a=!0){a=a?this.isHoverObject()?YELLOW:uiObjectIsDisabled(this)?PURPLE:this.interactive?RED:BLUE:GREEN;uiSystem.drawRect(this.nativePos,this.size,CLEAR_BLACK,4,a)}click(a=!0){this.onClick();a&&this.soundClick&&this.soundClick.play()}onUpdate(){}onRender(){}onEnter(){}onLeave(){}onPress(){}onRelease(){}onClick(){}onChange(){}onKeyDown(a){}}class UIText extends UIObject{constructor(a,b,c="",d="center",e=uiSystem.defaultFont){super(a,b);this.text=c;this.align=d;this.font=e;this.canBeHover=!1;this.color=CLEAR_BLACK.copy();this.shadowColor=CLEAR_BLACK.copy();this.gradientColor=void 0;this.lineWidth=0;this.textFitScale=1}render(){super.render();const a=this.getTextSize();uiSystem.drawText(this.text,this.getTextPos(a),a,this.textColor,this.textLineWidth,this.textLineColor,this.align,this.font,this.fontStyle,!0,this.textShadow,this.shadowColor||CLEAR_BLACK,this.shadowBlur,this.shadowOffset)}}class UITextInput extends UIObject{constructor(a,b,c=""){super(a,b);this.maxLength=0;this.text=c+"";this.canBeHover=this.interactive=!0}click(a=!0){const b=uiSystem.keyInputObject;b!==this&&b instanceof UITextInput&&b.stopEditing();uiSystem.keyInputObject=this;inputClearKey(0,gamepadPrimary+1,!1,!0,!1);this.onClick();a&&this.soundClick&&this.soundClick.play()}stopEditing(){this.isKeyInputObject()&&(this.soundRelease&&this.soundRelease.play(),uiSystem.activeObject=void 0,uiSystem.keyInputObject=void 0,this.onChange())}onKeyDown(a){const b=a.code,c=a.key||"";if(!a.repeat||"Enter"!==c&&"Space"!==b)this.text+="","Backspace"===c?this.text=textGraphemes(this.text).slice(0,-1).join(""):"Enter"===c||"Escape"===c?this.stopEditing():1!==c.length||(a.ctrlKey||a.metaKey)&&!a.getModifierState?.("AltGraph")||this.maxLength&&!(textGraphemes(this.text).length<this.maxLength)||(this.text+=c)}update(){super.update();this.isKeyInputObject()&&(gamepadWasPressed(0,gamepadPrimary)?(this.stopEditing(),inputClearKey(0,gamepadPrimary+1,!1,!0,!1)):mouseWasPressed(0)&&inputClearKey(0,0,!1,!0,!1))}render(){super.render();const a=this.getTextSize();let b=this.text;this.isKeyInputObject()&&(b+=.5>timeReal%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.readyState<this.video.HAVE_CURRENT_DATA}isPaused(){return this.video.paused}isPlaying(){return!this.isPaused()&&!this.hasEnded()&&!this.isLoading()}hasEnded(){return this.video.ended}setVolume(a){this.volume=a;this.video.volume=clamp(a*soundVolume)}setPlaybackRate(a){this.video.playbackRate=a}getCurrentTime(){return this.video.currentTime||0}getDuration(){return this.video.duration||0}getVideoSize(){return vec2(this.video.videoWidth,this.video.videoHeight)}setTime(a){const b=this.video.duration;this.video.currentTime=b?clamp(a,0,b):max(a,0)}update(){super.update();this.video.volume=clamp(this.volume*soundVolume);this._soundEnabled!==soundEnable&&(this.video.muted=!(this._soundEnabled=soundEnable))}render(){super.render();if(!this.isLoading()){var a=uiSystem.uiContext,b=this.size;a.save();a.translate(this.nativePos.x,this.nativePos.y);a.drawImage(this.video,-b.x/2,-b.y/2,b.x,b.y);a.restore()}}destroy(){this.destroyed||(this.video.pause(),this.video.removeAttribute?.("src"),this.video.load?.(),this.video.remove(),super.destroy())}}class UILayout extends UIObject{constructor(a,b=1,c=10,d=10,e=!1){super(a);this.columns=b;this.gap=c;this.padding=d;e&&(this.color=CLEAR_BLACK.copy(),this.gradientColor=void 0,this.lineWidth=0,this.shadowColor=CLEAR_BLACK.copy(),this.canBeHover=!1);this.relayout()}addChild(a){super.addChild(a);this.relayout();return a}removeChild(a){super.removeChild(a);this.relayout()}relayout(){const a=this.children.filter(r=>r.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<b;++g){var h=g%c,k=floor(g/c),l=a[g];e[h]=max(e[h],l.size.x);f[k]=max(f[k],l.size.y)}g=this.gap*(c-1);for(var m of e)g+=m;m=this.gap*(d-1);for(var n of f)m+=n;n=Array(c);h=0;for(k=0;k<c;++k)n[k]=h,h+=e[k];h=Array(d);k=0;for(l=0;l<d;++l)h[l]=k,k+=f[l];for(d=0;d<b;++d)k=d%c,l=floor(d/c),a[d].localPos=vec2(-g/2+n[k]+this.gap*k+e[k]/2,-m/2+h[l]+this.gap*l+f[l]/2);this.size=vec2(g+2*this.padding,m+2*this.padding)}else this.size=vec2(2*this.padding);this.parent instanceof UILayout&&this.parent.relayout()}}let box2d,box2dDebug=!1,box2dTempVectors;function box2dTemp(a,b=0){b=(box2dTempVectors||=[new box2d.instance.b2Vec2,new box2d.instance.b2Vec2])[b];b.Set(a.x,a.y);return b}const box2dQueryObjects={},box2dGravity={x:NaN,y:NaN};function box2dQueryObject(a,b){let c;return(c=box2dQueryObjects)[a]||(c[a]=new box2d.instance[b])}function box2dFixtureOverlaps(a,b){const c=a.GetShape();a=a.GetBody().GetTransform();const d=box2dQueryObject("shapeAABB","b2AABB"),e=b.get_lowerBound();b=b.get_upperBound();for(let f=c.GetChildCount();f--;){c.ComputeAABB(d,a,f);const g=d.get_lowerBound(),h=d.get_upperBound();if(g.get_x()<=b.get_x()&&h.get_x()>=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<d.distanceSquared(c[c.length-1]))&&c.push(d);for(;b&&1<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){}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-6<a.x*a.y&&isFinite(a.x*a.y)){var h=new box2d.instance.b2PolygonShape;h.SetAsBox(a.x/2,a.y/2,box2dTemp(b),-c);a=this.addShape(h,d,e,f,g);box2d.instance.destroy(h);return a}}addPoly(a,b,c,d,e){if(a=function(f){f=f.filter((l,m)=>f.slice(0,m).every(n=>1e-6<l.distanceSquared(n)));var g=0;if(3<=f.length&&8>=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<f.length;++l)box2d.instance.HEAPF32[g+m>>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;0<h--;)g.push(vec2(a,0).rotate((h+.5)/b*PI*2));return this.addPoly(g,c,d,e,f)}addRandomPoly(a=1,b,c,d,e){const f=randInt(3,9),g=[];a/=2;for(let h=f;h--;)g.push(vec2(rand(a/2,1.5*a),0).rotate(h/f*PI*2));return this.addPoly(g,b,c,d,e)}addCircle(a=1,b=vec2(),c,d,e,f){if(isFinite(a)){var g=new box2d.instance.b2CircleShape;g.set_m_p(box2dTemp(b));g.set_m_radius(a/2);a=this.addShape(g,c,d,e,f);box2d.instance.destroy(g);return a}}addEdge(a,b,c,d,e,f){const g=new box2d.instance.b2EdgeShape;g.Set(box2dTemp(a),box2dTemp(b,1));a=this.addShape(g,c,d,e,f);box2d.instance.destroy(g);return a}addEdgeList(a,b,c,d,e){a=box2dEdgePoints(a);const f=[],g=[];if(2>a.length)return f;for(let h=0;h<a.length-1;++h){const k=new box2d.instance.b2EdgeShape;a[h-1]&&k.set_m_vertex0(box2dTemp(a[h-1]));a[h+0]&&k.set_m_vertex1(box2dTemp(a[h+0]));a[h+1]&&k.set_m_vertex2(box2dTemp(a[h+1]));a[h+2]&&k.set_m_vertex3(box2dTemp(a[h+2]));k.set_m_hasVertex0(!!a[h-1]);k.set_m_hasVertex3(!!a[h+2]);const l=this.addShape(k,b,c,d,e);box2d.instance.destroy(k);f.push(l);g.push(a[h].copy())}g.push(a[a.length-1].copy());this.edgeLists.push(g);f.forEach(h=>this.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;h<a.length;++h){const k=new box2d.instance.b2EdgeShape;k.set_m_vertex0(box2dTemp(a[mod(h-1,a.length)]));k.set_m_vertex1(box2dTemp(a[mod(h+0,a.length)]));k.set_m_vertex2(box2dTemp(a[mod(h+1,a.length)]));k.set_m_vertex3(box2dTemp(a[mod(h+2,a.length)]));k.set_m_hasVertex0(!0);k.set_m_hasVertex3(!0);const l=this.addShape(k,b,c,d,e);box2d.instance.destroy(k);f.push(l);g.push(a[h].copy())}this.edgeLoops.push(g);f.forEach(h=>this.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()}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<b?b:1,g,h);var l=k(e+f);d.set_mass(b);d.set_center(box2dTemp(vec2(g,h)));d.set_I(0<e&&0<k(l-f)?l:0);this.body.SetMassData(d);this.body.SetAwake(!0)}})}setFilterData(a=1,b=0,c=0){this.getFixtureList().forEach(d=>{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 0<this.getJointList().length}getJointList(){const a=[];for(let b=this.body.GetJointList();!box2d.isNull(b);b=b.get_next()){const c=b.get_joint(),d=box2dJoints.get(box2d.instance.getPointer(c));d&&!d.box2dJoint||a.push(d||box2d.castJointObject(c))}return a}}class Box2dStaticObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeStatic,f)}}class Box2dKinematicObject extends Box2dObject{constructor(a,b,c,d=0,e,f=0){super(a,b,c,d,e,box2d.bodyTypeKinematic,f)}}class Box2dTileLayer extends Box2dStaticObject{constructor(a){super(a.pos,a.size);this.tileLayer=a;this.addChild(a);this.buildCollision()}render(){}buildCollision(a=.2,b=0){this.destroyAllFixtures();const c=[],d=(k,l)=>k+l*this.size.x,e=(k,l)=>!c[d(k,l)]&&0<this.tileLayer.getCollisionData(vec2(k,l));for(let k=0;k<this.size.x;++k)for(let l=0;l<this.size.y;++l){if(!e(k,l))continue;var f=1;let m=1;for(var g=!0;e(k+f,l);)++f;for(;g;){for(var h=0;h<f;++h)if(!e(k+h,l+m)){g=!1;break}g&&++m}for(g=f;g--;)for(h=m;h--;)c[d(k+g,l+h)]=!0;g=vec2(f,m);f=vec2(k+f/2,l+m/2);this.addBox(g,f,0,0,a,b)}}}class Box2dRaycastResult{constructor(a,b,c,d){this.object=a.GetBody().object;this.fixture=a;this.point=b;this.normal=c;this.fraction=d}}class Box2dJoint{constructor(a){var b=a.get_bodyA();const c=a.get_bodyB(),d=!box2d.isNull(b)&&!box2d.isNull(c);b=!d||box2d.instance.getPointer(b)!==box2d.instance.getPointer(c);this.box2dJoint=0;d&&b?(this.box2dJoint=box2d.castJointObject(box2d.world.CreateJoint(a)),box2d.instance.destroy(a),box2dJoints.set(box2d.instance.getPointer(this.box2dJoint),this)):box2d.instance.destroy(a)}destroy(){const a=this.box2dJoint;if(a){this.box2dJoint=0;box2dDestroyGears(this);var b=box2d.instance.getPointer(a);box2dWhenUnlocked(()=>{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();c=c.GetFixtureB();const d=b.GetBody().object,e=c.GetBody().object;d&&e&&(d.beginContact(e,b,c),e.beginContact(d,c,b))};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(!(0<d&&Infinity>d))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)<d&&(c||f.getFixtureList().some(g=>!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<e)d=f,e=b;return d}pointCast(a,b=!0,c=!1){const d=box2dQueryObject("query","JSQueryCallback");d.ReportFixture=function(g){g=box2d.instance.wrapPointer(g,box2d.instance.b2Fixture);if(!c&&g.IsSensor()||b&&g.GetBody().GetType()!==box2d.bodyTypeDynamic||!g.TestPoint(box2dTemp(a)))return!0;g=g.GetBody().object;if(!g||g.destroyed)return!0;f=g;return!1};const e=box2dQueryObject("aabb","b2AABB");e.set_lowerBound(box2dTemp(a));e.set_upperBound(box2dTemp(a));let f;box2d.world.QueryAABB(d,e);debugRaycast&&debugRect(a,vec2(),f?"#f00":"#00f",0,0,!1,!1);return f}drawFixture(a,b,c,d=WHITE,e=BLACK,f=.1,g,h){a=box2d.castShapeObject(a.GetShape());switch(a.GetType()){case box2d.instance.b2Shape.e_polygon:var k=[];for(let l=a.GetVertexCount();l--;)k.push(box2d.vec2From(a.GetVertex(l)));drawPoly(k,d,f,e,b,c,g,!1,h);break;case box2d.instance.b2Shape.e_circle:k=a.get_m_radius();a=box2d.vec2From(a.get_m_p());drawCircle(b.add(a.rotate(c)),2*k,d,f,e,g,!1,h);break;case box2d.instance.b2Shape.e_edge:d=box2d.vec2From(a.get_m_vertex1()),a=box2d.vec2From(a.get_m_vertex2()),drawLine(d,a,f,e,b,c,g,!1,h)}}vec2From(a){return new Vector2(a.get_x(),a.get_y())}vec2FromPointer(a){a=box2d.instance.wrapPointer(a,box2d.instance.b2Vec2);return box2d.vec2From(a)}vec2dTo(a){return new box2d.instance.b2Vec2(a.x,a.y)}isNull(a){return!box2d.instance.getPointer(a)}castShapeObject(a){switch(a.GetType()){case box2d.instance.b2Shape.e_circle:return box2d.instance.castObject(a,box2d.instance.b2CircleShape);case box2d.instance.b2Shape.e_edge:return box2d.instance.castObject(a,box2d.instance.b2EdgeShape);case box2d.instance.b2Shape.e_polygon:return box2d.instance.castObject(a,box2d.instance.b2PolygonShape);case box2d.instance.b2Shape.e_chain:return box2d.instance.castObject(a,box2d.instance.b2ChainShape)}}castJointObject(a){switch(a.GetType()){case box2d.instance.e_revoluteJoint:return box2d.instance.castObject(a,box2d.instance.b2RevoluteJoint);case box2d.instance.e_prismaticJoint:return box2d.instance.castObject(a,box2d.instance.b2PrismaticJoint);case box2d.instance.e_distanceJoint:return box2d.instance.castObject(a,box2d.instance.b2DistanceJoint);case box2d.instance.e_pulleyJoint:return box2d.instance.castObject(a,box2d.instance.b2PulleyJoint);case box2d.instance.e_mouseJoint:return box2d.instance.castObject(a,box2d.instance.b2MouseJoint);case box2d.instance.e_gearJoint:return box2d.instance.castObject(a,box2d.instance.b2GearJoint);case box2d.instance.e_wheelJoint:return box2d.instance.castObject(a,box2d.instance.b2WheelJoint);case box2d.instance.e_weldJoint:return box2d.instance.castObject(a,box2d.instance.b2WeldJoint);case box2d.instance.e_frictionJoint:return box2d.instance.castObject(a,box2d.instance.b2FrictionJoint);case box2d.instance.e_ropeJoint:return box2d.instance.castObject(a,box2d.instance.b2RopeJoint);case box2d.instance.e_motorJoint:return box2d.instance.castObject(a,box2d.instance.b2MotorJoint)}}}async function box2dInit(){new Box2dPlugin(await Box2D());(function(){const a=new box2d.instance.JSDraw,b=d=>{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=1<e,y=e&&3>e,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<e?-1:1,1<e?-g:g)),drawTile(a.add(u.rotate(t)),c,n,d,p,!1,f,k,l,m)}}}class TileSlice{constructor(a,b=9,c,d){this.tileInfo=a;this.slices=b;this.borderSize=c;this.extraSpace=d}draw(a,b,c=WHITE,d,e=0,f=glEnable,g=drawScreenSpace,h){if(g)return this.drawScreen(a,b,c,d,e,f,h);9===this.slices?drawNineSlice(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g,h):3===this.slices?drawThreeSlice(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g,h):drawTile(a,b,this.tileInfo,c,e,!1,d,f,g,h)}drawScreen(a,b,c=WHITE,d,e=0,f=!1,g){9===this.slices?drawNineSliceScreen(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g):3===this.slices?drawThreeSliceScreen(a,b,this.tileInfo,c,this.borderSize,d,this.extraSpace,e,f,g):drawTile(a,b,this.tileInfo,c,e,!1,d,f,!0,g)}}function drawSliceSnapped(a,b,c,d,e,f,g,h){var k=(!g||!glEnable||!!h)&&(h||drawContext)?.getTransform?.(),l=getCanvasPixelRatio();const[m,n,r,q]=k?[k.a||1,k.d||1,k.e||0,k.f||0]:[l,l,0,0];l=(p,t,u,v)=>{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;m<n;++m)f.tiles.push(l.tile.frame(m))},()=>textureSheetLoadFailed(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),1<g.length&&g.every((h,k)=>h.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.activePass<c)&&tweenDeactivate(a),d}}function tweenIsLerpable(a){return a&&"function"===typeof a.lerp}class Tween{constructor(a,b=0,c=1,d=1,e={}){tweenIsLerpable(b);this.callback=a;this.start=b;this.end=c;this.life=this.duration=d;this.ease=e.ease||Ease.LINEAR;this.useRealTime=!!e.useRealTime;this.paused=!!e.paused;this.thenCallback=this.onComplete=void 0;this.loopRemaining=0;this.listed=this.active=!1;this.activePass=0;this.lastTime=time;this.lastTimeReal=timeReal;this.target=void 0;tweenActivate(this);tweenCall(this,d)}setEase(a){this.ease=a;return this}then(a){this.onComplete=a;return this}loop(a=Infinity){this.loopRemaining=a;this.thenCallback=()=>tweenLoopContinuation(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]<f?g=l:h=l}return e((g+h)/2)[1]}}};function tweenProperty(a,b,c,d,e=1,f={}){const g=b.split("."),h=g.pop();let k;k=new Tween(l=>{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=0<b?min(a.life,0)%b+b:1e-9}function tweenPassed(a){const b=a.duration;return 0<b?1+floor(-min(a.life,0)/b):1}function tweenNextIteration(a,b,c){a.loopRemaining-=b;tweenCarryOvershoot(a);a.thenCallback=c;tweenActivate(a);tweenCall(a,a.life);return!0}function tweenLoopContinuation(a){const b=tweenPassed(a);return a.loopRemaining<=b?!1:tweenNextIteration(a,b,()=>tweenLoopContinuation(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<a.life)tweenCall(a,a.life,b);else if(tweenCall(a,0,b),!(!a.active||a.activePass>=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<cameraScale?(this.zoomScale/cameraScale)**(1-this.zoomFollow):1}getDrawSize(){return this.size.scale(this.zoomFactor())}getDrawPositions(){var a=this.zoomFactor();const b=this.size.scale(a);var c=this.parallax,d=this.pos.subtract(cameraPos);const e=cameraPos.add(vec2(d.x*(1-c.x)*a,d.y*(1-c.y)*a));a=mainCanvasSize.scale(.5/(cameraScale||1));const f=cameraAngle?vec2(a.length()):a;a=(m,n)=>{if(!(m&&0<b[n]))return[0,0];m=cameraPos[n]+f[n]+b[n]/2-e[n];const r=ceil((cameraPos[n]-f[n]-b[n]/2-e[n])/b[n]);return[r,min(floor(m/b[n]),r+99)]};const[g,h]=a(this.wrapX,"x"),[k,l]=a(this.wrapY,"y");a=[];for(c=k;c<=l;++c)for(d=g;d<=h;++d)a.push(vec2(e.x+d*b.x,e.y+c*b.y));return a}render(){const a=this.getDrawSize();for(const b of this.getDrawPositions())this.draw(b,a,this.color,0,this.mirror,this.additiveColor,!1)}}function parallaxRidge(a,b,c){var d=b/256;const e=new Float32Array(a+1),f=b/2;let g=f,h=c.float(-d,d);for(let k=0;k<=a;++k)e[k]=g,g+=h-=.005*(g-f),.2>c.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]<e&&d.drawImage(h.canvas,0,0,1,e,f,g[f],1,e-g[f])}}const PATHFINDER_DIAGONAL_COST=Math.SQRT2,PATHFINDER_TILE_VEC=vec2(1);class PathFinderNode{constructor(a,b){this.pos=vec2(a,b);this.posWorld=vec2();this.walkable=!1;this.h=this.f=this.g=this.cost=0;this.parent=null;this.isClosed=this.isOpen=!1;this.heapIndex=0}resetSearch(){this.g=this.f=this.h=0;this.parent=null;this.isOpen=this.isClosed=!1}reset(){this.walkable=!1;this.cost=0;this.resetSearch()}isClear(){return this.walkable&&0===this.cost}}class PathFinder{constructor(a){isVector2(a)?(this.size=a.floor(),this.tileLayer=void 0):(this.size=a.size,this.tileLayer=a);this.heuristicWeight=1;this.maxLoop=void 0;this.searchGaveUp=!1;this.smoothPath=!0;this.debug=!1;this.debugTime=1;this.nodes=Array(this.size.x*this.size.y);for(a=0;a<this.size.y;++a)for(let b=0;b<this.size.x;++b)this.nodes[b+a*this.size.x]=new PathFinderNode(b,a);this.nodeDataBuilt=!1;this.collisionScratch=vec2();this.searchNodes=[]}isWalkable(a,b){return this.tileLayer?!(0<this.tileLayer.getCollisionData(this.collisionScratch.set(a,b))):!0}getCost(a,b){return 0}getNode(a,b){return 0>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;e<b;++e)for(let f=0;f<a;++f){const g=this.nodes[f+e*a];g.reset();const h=!!this.isWalkable(f,e),k=h?max(0,this.getCost(f,e)):0;g.walkable=h;g.cost=k;g.posWorld.set(f+.5+c,e+.5+d);this.debug&&0<this.debugTime&&(h?0<k&&debugRect(g.posWorld,PATHFINDER_TILE_VEC,rgb(1,0,0,min(.2,.05*k)),this.debugTime,0,!1,!1):debugRect(g.posWorld,PATHFINDER_TILE_VEC,rgb(1,0,0,.25),this.debugTime,0,!1,!1))}}aStarSearch(a,b){const c=this.searchNodes;for(var d of c)d.resetSearch();c.length=0;c.push(a);const e=[],f=(l,m)=>l.f<m.f-1e-9||l.f<m.f+1e-9&&l.h<m.h;d=l=>{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=q<e.length&&f(e[q],e[n])?q:n;if(!f(e[n],m))break;(e[r]=e[n]).heapIndex=r;r=n}(e[r]=m).heapIndex=r}return l};a.isOpen=!0;a.heapIndex=e.length;d(a);a=this.maxLoop??this.size.x*this.size.y;let h=0;for(this.searchGaveUp=!1;0<e.length;){const l=e[0];if(l===b)break;if(++h>a){this.searchGaveUp=!b.parent;break}g();l.isOpen=!1;l.isClosed=!0;this.debug&&0<this.debugTime&&debugRect(l.posWorld,PATHFINDER_TILE_VEC,rgb(1,1,1,.05),this.debugTime,0,!1,!1);for(let m=-1;1>=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-1;){var c=a[b-1],d=a[b],e=a[b+1],f=e.pos.x-c.pos.x,g=e.pos.y-c.pos.y,h=f*f+g*g;f=d.pos.x-c.pos.x;var k=d.pos.y-c.pos.y;g=e.pos.x-d.pos.x;var l=e.pos.y-d.pos.y;if(1===h)this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(.5,0,.5,.5),this.debugTime,!1,!1),a.splice(b,1),b=max(1,b-1);else{if(2===h){if(this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(1,0,0,.5),this.debugTime,!1,!1),c.pos.y===d.pos.y&&e.pos.x===d.pos.x?(d=c.pos.x,e=e.pos.y):(d=e.pos.x,e=c.pos.y),(d=this.getNode(d,e))&&d.isClear()){a.splice(b,1);b=max(1,b-1);continue}}else if(5===h){this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(1,1,0,.5),this.debugTime,!1,!1);k=2<=b?a[b-2]:c;0===f||0===g?(f=e.pos.x,g=d.pos.y,h=c.pos.x,c=d.pos.y):(f=d.pos.x,g=e.pos.y,h=d.pos.x,c=c.pos.y);l=f-k.pos.x;const m=g-k.pos.y,n=h-k.pos.x;k=c-k.pos.y;k=l*l+m*m<n*n+k*k;if((k=this.getNode(k?f:h,k?g:c))&&k!==d&&k.isClear()&&(d=this.getNode(e.pos.x+h-f,e.pos.y+c-g))&&d.isClear()){a[b]=k;b=max(1,b-1);continue}}else if(4===h||8===h)if(this.debug&&0<this.debugTime&&debugCircle(d.posWorld,.3,rgb(0,1,0,.5),this.debugTime,!1,!1),f===g&&k===l){++b;continue}else if(c.pos.y===e.pos.y?(e=d.pos.x,d=c.pos.y):(e=c.pos.x,d=d.pos.y),(d=this.getNode(e,d))&&d.isClear()){a[b]=d;b=max(1,b-1);continue}++b}}}smoothPathStringPull(a){if(!(2>=a.length)){var b=a.slice(),c=b.length-1,d=[];for(var e=1;e<c;++e){var f=b[e-1].pos,g=b[e].pos;const h=b[e+1].pos;(g.x-f.x)*(h.y-f.y)!==(g.y-f.y)*(h.x-f.x)&&d.push(e)}d.push(c);a.length=0;a.push(b[0]);for(let h=0;h<c;){f=h+1;if(b[h].isClear()){e=k=>b[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;c<a.length-1;++c){const d=a[b-1],e=a[c],f=a[c+1];(e.pos.x-d.pos.x)*(f.pos.y-d.pos.y)!==(e.pos.y-d.pos.y)*(f.pos.x-d.pos.x)&&(a[b++]=e)}a[b++]=a[a.length-1];a.length=b}}isNodeClear(a,b){a=this.getNode(a,b);return null!==a&&a.isClear()}isLineClear(a,b){const c=b.x-a.x,d=b.y-a.y;var e=abs(c);const f=abs(d),g=sign(c),h=sign(d);let k=a.x,l=a.y;if(f===e){for(;k!==b.x;){if(!(k===a.x||this.isNodeClear(k,l)&&this.isNodeClear(k,l-h))||!this.isNodeClear(k,l+h))return!1;k+=g;l+=h}if(!this.isNodeClear(b.x,b.y-h))return!1}else if(f<e)if(0===d)for(k+=g;k!==b.x;){if(!this.isNodeClear(k,l))return!1;k+=g}else{for(e=a.y;k!==b.x;){l=a.y+Math.trunc(d*(k-a.x)/c);if(!(e===l||this.isNodeClear(k-g,l+h)&&this.isNodeClear(k,l-h)))return!1;e=l;if(k!==a.x&&!this.isNodeClear(k,l))return!1;l+=h;if(!this.isNodeClear(k,l))return!1;k+=g}if(!this.isNodeClear(b.x,b.y-h))return!1}else if(0===c)for(l+=h;l!==b.y;){if(!this.isNodeClear(k,l))return!1;l+=h}else{for(e=a.x;l!==b.y;){k=a.x+Math.trunc(c*(l-a.y)/d);if(!(e===k||this.isNodeClear(k+g,l-h)&&this.isNodeClear(k-g,l)))return!1;e=k;if(l!==a.y&&!this.isNodeClear(k,l))return!1;k+=g;if(!this.isNodeClear(k,l))return!1;l+=h}if(!this.isNodeClear(b.x-g,b.y))return!1}return!0}findPath(a,b,c=!0){this.searchGaveUp=!1;!c&&this.nodeDataBuilt||this.buildNodeData();c=d=>d.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<this.debugTime&&0<b.length){for(a=1;a<b.length;++a)debugLine(b[a-1],b[a],RED,.1,this.debugTime,!1);for(const d of b)debugCircle(d,.5,rgb(1,0,0,.3),this.debugTime,!1,!1);debugCircle(b[0],.5,rgb(0,1,0,.5),this.debugTime,!1,!1);debugCircle(b[b.length-1],.5,rgb(0,1,0,.5),this.debugTime,!1,!1)}return b}}function pathFinderNearestNode(a,b,c,d){var e=a.worldToTile(b);const f=e.x;e=e.y;let g=null,h=0;for(let m=0;m<=c;++m){var k=max(0,m-.5);if(g&&k*k>=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<h)g=q,h=l}}return g}function vec3(a=0,b,c){return void 0===b?new Vector3(a,a,a):new Vector3(a,b,void 0===c?0:c)}function isVector3(a){return a instanceof Vector3&&a.isValid()}function ASSERT_VECTOR3_VALID(a){}function randVector3(a=1,b=PI){b=rand(cos(b),1);const c=(1-b*b)**.5,d=rand(2*PI);return new Vector3(c*cos(d)*a,b*a,c*sin(d)*a)}function randInSphere(a=1,b=0){if(0>=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=(.99<abs(b.y)?vec3(0,0,0<b.y?-1:1):vec3(0,1,0)).cross(b).normalize());const d=b.cross(c);return new Matrix4([c.x,c.y,c.z,0,d.x,d.y,d.z,0,b.x,b.y,b.z,0,a.x,a.y,a.z,1])}copy(){return new Matrix4(this.m)}multiply(a){const b=this.m;a=a.m;const c=matrix4Scratch;for(let d=0;4>d;++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-9<k?new Vector3(l,atan2(g,e),atan2(b,f)):new Vector3(l,atan2(a[4]/d*-h,a[0]/c),0)}toString(){const a=this.m;let b="";for(let c=0;4>c;++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*q<n&&(n=t*q,m=r.scale(0>p?-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(h<k||h>m)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;function render3DFaceNormal(a,b,c,d=a){a=c.subtract(a).cross(d.subtract(b));return a.lengthSquared()?a.normalize():RENDER3D_DEFAULT_NORMAL}function render3DQuadStrip(a,b,c,d){return[a,b,d,c]}function render3DQuadValues(a){return isArray(a)?render3DQuadStrip(...a):a}function render3DCanDraw(){return render3D.program?render3D.isRendering:!1}const RENDER3D_STATE_FIELDS="blend additive depthTest depthWrite cullBackFaces mirrored lighting emissive receiveShadow specular pixelated shader normalMap normalScale shininess reflectivity emissiveMap emissiveMapColor environmentMap".split(" ");function render3DCaptureBatchState(){const a=render3D,b=a.drawState;return{blend:b.blend,additive:b.additive,depthTest:b.depthTest,depthWrite:b.depthWrite,cullBackFaces:b.cullBackFaces,mirrored:b.mirrored,lighting:b.lighting,emissive:b.emissive,receiveShadow:b.receiveShadow,specular:b.specular,pixelated:b.pixelated,shader:b.shader,normalMap:b.normalMap,normalScale:b.normalScale,shininess:b.shininess,reflectivity:b.reflectivity,emissiveMap:b.emissiveMap,emissiveMapColor:(b.emissiveMapColor||WHITE).copy(),environmentMap:b.environmentMap,version:a.stateVersion}}function render3DApplyBatchState(a){const b=render3D;b.blend=a.blend;b.additive=a.additive;b.depthTest=a.depthTest;b.depthWrite=a.depthWrite;b.cullBackFaces=a.cullBackFaces;b.mirrored=a.mirrored;b.lighting=a.lighting;b.emissive=a.emissive;b.receiveShadow=a.receiveShadow;b.specular=a.specular;b.pixelated=a.pixelated;b.shader=a.shader;b.normalMap=a.normalMap;b.normalScale=a.normalScale;b.shininess=a.shininess;b.reflectivity=a.reflectivity;b.emissiveMap=a.emissiveMap;b.emissiveMapColor=a.emissiveMapColor;b.environmentMap=a.environmentMap}function render3DStateChanged(a){const b=render3D;if(a.version===b.stateVersion)return!1;const c=b.drawState,d=a.emissiveMapColor;if(c.blend!==a.blend||c.additive!==a.additive||c.depthTest!==a.depthTest||c.depthWrite!==a.depthWrite||c.cullBackFaces!==a.cullBackFaces||c.mirrored!==a.mirrored||c.lighting!==a.lighting||c.emissive!==a.emissive||c.receiveShadow!==a.receiveShadow||c.specular!==a.specular||c.pixelated!==a.pixelated||c.shader!==a.shader||c.normalMap!==a.normalMap||c.normalScale!==a.normalScale||c.shininess!==a.shininess||c.reflectivity!==a.reflectivity||c.emissiveMap!==a.emissiveMap||c.environmentMap!==a.environmentMap||c.emissiveR!==d.r||c.emissiveG!==d.g||c.emissiveB!==d.b)return!0;a.version=b.stateVersion;return!1}function render3DSphereVisible(a,b,c,d){const e=render3D.shadowPass&&!render3D.depthPass?render3D.shadowPlanes:render3D.frustumPlanes;for(let f=0;f<e.length;++f){const g=e[f];if(g[0]*a+g[1]*b+g[2]*c+g[3]<-d)return!1}return!0}function render3DWithState(a,b){const c=render3D,d={};for(const e in a)d[e]=c[e],c[e]=a[e];try{return b()}finally{Object.assign(c,d)}}function render3DIsAfter2D(a){return!!((a.drawOwner?render3DSetting(a,"renderAfter2D"):a.renderAfter2D)??render3D.renderAfter2D)}function render3DSize3(a){return isNumber(a)?vec3(a):a}function render3DSize2(a){return isNumber(a)?vec2(a):a}function render3DMatrix(a){return a instanceof Vector3?buildMatrix(a):a}function render3DNormalMatrix(a){return a.copy().invert().transpose()}function render3DMirrors(a){return 0>a.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.length<c+RENDER3D_INSTANCE_FLOATS)d=new Float32Array(max(64*RENDER3D_INSTANCE_FLOATS,b?2*b.length:0)),b&&d.set(b),a.instanceData=d;return c}function render3DFlushInstances(a){const b=render3D,c=glContext;for(const e of a?[a]:b.instanceMeshes){const f=e.instanceCount;e.instanceCount=0;if(!f||!e.buffer)continue;var d=b.instanceBuffers;d=d[b.instanceBufferIndex=(b.instanceBufferIndex+1)%d.length];c.bindBuffer(c.ARRAY_BUFFER,d);c.bufferData(c.ARRAY_BUFFER,e.instanceData,c.DYNAMIC_DRAW,0,f*RENDER3D_INSTANCE_FLOATS);const g=e.instanceState;void 0!==e.instanceMirrored&&(g.cullBackFaces=!e.doubleSided,g.mirrored=e.instanceMirrored);e.instanceUnlit&&(g.lighting=!1);render3DDrawInstanced(e,d,f,e.instanceTextureInfo,g)}a?(a=b.instanceMeshes.indexOf(a),0>a||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&&0<c.color.a&&0<c.intensity&&(c.directional||0<c.radius));if(a.length>RENDER3D_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&&0<a.coneAngle&&0<a.radius&&0<a.intensity&&0<a.color.a?a:void 0}const RENDER3D_SHADOW_CONE_MAX=1.35;function render3DLightCone(a){var b=a===render3DShadowCaster()?RENDER3D_SHADOW_CONE_MAX:PI,c=a.directional?0:min(a.coneAngle,b);if(!(0<c))return[0,0,0,-1];b=cos(c);c=cos(c*(1-clamp(a.coneSoftness)));c=1/max(c-b,1e-4);a=a.getForward3D();return[a.x*c,a.y*c,a.z*c,b*c]}const render3DCircleCache=new Map;function render3DCircle(a){a|=0;let b=render3DCircleCache.get(a);if(!b){b=new Float32Array(2*a+2);for(let c=0;c<=a;++c){const d=c/a*2*PI;b[2*c]=cos(d);b[2*c+1]=sin(d)}render3DCircleCache.set(a,b)}return b}function render3DLookRotation(a,b){a=a.normalize();return a.lengthSquared()?1e-9>abs(a.x)+abs(a.z)?vec3(0<a.y?PI/2:-PI/2,b.y,0):vec3(Math.asin(clamp(a.y,-1,1)),atan2(-a.x,-a.z),0):b}class Render3DPlugin{constructor(){render3D=this;this.drawState={blend:!1,additive:!1,depthTest:!0,depthWrite:!0,cullBackFaces:!1,mirrored:!1,lighting:!0,emissive:0,receiveShadow:!0,specular:0,pixelated:!1,shader:void 0,normalMap:void 0,normalScale:1,shininess:16,reflectivity:0,emissiveMap:void 0,emissiveMapColor:WHITE,environmentMap:void 0,emissiveR:1,emissiveG:1,emissiveB:1};this.stateVersion=0;this.camera=new Camera3D;this.sunDirection=vec3(-.3,1,.5);this.sunColor=WHITE.copy();this.ambientColor=hsl(0,0,.3);this.fogColor=this.ambientGroundColor=void 0;this.fogEnd=this.fogStart=0;this.gravity=vec3();this.softShadowHeight=0;this.shadows=this.depthTexture=this.smoothShading=!1;this.soundDefaultRange=100;this.shadowMapSize=1024;this.shadowLight=void 0;this.shadowRange=40;this.shadowCenter=void 0;this.shadowBias=.003;this.shadowSoftness=1;this.environment=this.skyBox=this.sky=this.onRenderTransparent=this.onRenderOpaque=void 0;this.renderAfter2D=!1;this.mipmaps=this.instancing=this.frustumCulling=this.sortTransparent=!0;this.anisotropy=4;this.boxMesh=buildBox();this.sphereMesh=buildSphere(1,16,8,!0);this.planeMesh=buildGrid();this.planeMesh.doubleSided=!1;this.planeMeshDoubleSided=buildGrid();this.billboardMesh=(new Mesh).addStrip([vec3(-.5,.5,0),vec3(-.5,-.5,0),vec3(.5,.5,0),vec3(.5,-.5,0)],vec3(0,0,1),RENDER3D_QUAD_UVS);this.billboardMesh.doubleSided=!0;this.shadowPass=this.isRendering=!1;this.viewMatrix=new Matrix4;this.projectionMatrix=new Matrix4;this.viewProjection=new Matrix4;this.shadowMatrix=new Matrix4;this.gelAxes=[1,0,0,1];this.cameraRight=vec3(1,0,0);this.cameraUp=vec3(0,1,0);this.cameraForward=vec3(0,0,-1);this.cameraBack=vec3(0,0,1);this.frustumPlanes=[];this.shadowPlanes=[];this.currentProgram=this.program=void 0;this.lightCount=0;this.vao=this.shadowShader=void 0;this.cubeCaptures=new Set;this.captureDepth=this.captureFramebuffer=this.capturingCube=void 0;this.captureDepthSize=0;this.whiteTexture=this.skyBoxVao=this.skyBoxProgram=void 0;this.samplers=new Map;this.shadowFramebuffer=this.shadowTexture=this.samplerKey=void 0;this.shadowTextureSize=0;this.cameraDepthFramebuffer=this.cameraDepthTexture=void 0;this.cameraDepthHeight=this.cameraDepthWidth=0;this.depthPass=!1;this.contextGeneration=0;this.uniforms=new WeakMap;this.uniformValues={};this.shadowMapDrawn=!1;this.passIsDefault=!0;this.lightPositions=new Float32Array(4*RENDER3D_MAX_LIGHTS);this.lightColors=new Float32Array(4*RENDER3D_MAX_LIGHTS);this.lightCones=new Float32Array(4*RENDER3D_MAX_LIGHTS);this.shadowLightIndex=-1;this.shadowDepthBias=0;this.streamBuffer=void 0;this.instanceBuffers=[];this.instanceBufferIndex=0;this.instanceMeshes=[];this.attribValues=[];this.streamData=new ArrayBuffer(RENDER3D_MAX_STREAM_VERTS*RENDER3D_VERTEX_BYTES);this.streamFloats=new Float32Array(this.streamData);this.streamInts=new Uint32Array(this.streamData);this.streamCount=0;this.streamState=this.streamTileInfo=void 0;this.streamUnlit=!1;this.transparentQueue=this.capture=void 0;render3DInitGL();engineAddPlugin(void 0,render3DRender,render3DContextLost,render3DContextRestored,render3DPreRender)}get lighting(){return this.drawState.lighting}set lighting(a){const b=this.drawState;b.lighting===a||(b.lighting=a,++this.stateVersion)}get emissive(){return this.drawState.emissive}set emissive(a){const b=this.drawState;b.emissive===a||(b.emissive=a,++this.stateVersion)}get additive(){return this.drawState.additive}set additive(a){const b=this.drawState;b.additive===a||(b.additive=a,++this.stateVersion)}get depthTest(){return this.drawState.depthTest}set depthTest(a){const b=this.drawState;b.depthTest===a||(b.depthTest=a,++this.stateVersion)}get depthWrite(){return this.drawState.depthWrite}set depthWrite(a){const b=this.drawState;b.depthWrite===a||(b.depthWrite=a,++this.stateVersion)}get cullBackFaces(){return this.drawState.cullBackFaces}set cullBackFaces(a){const b=this.drawState;b.cullBackFaces===a||(b.cullBackFaces=a,++this.stateVersion)}get mirrored(){return this.drawState.mirrored}set mirrored(a){const b=this.drawState;b.mirrored===a||(b.mirrored=a,++this.stateVersion)}get specular(){return this.drawState.specular}set specular(a){const b=this.drawState;b.specular===a||(b.specular=a,++this.stateVersion)}get shininess(){return this.drawState.shininess}set shininess(a){const b=this.drawState;b.shininess===a||(b.shininess=a,++this.stateVersion)}get normalMap(){return this.drawState.normalMap}set normalMap(a){const b=this.drawState;b.normalMap===a||(b.normalMap=a,++this.stateVersion)}get normalScale(){return this.drawState.normalScale}set normalScale(a){const b=this.drawState;b.normalScale===a||(b.normalScale=a,++this.stateVersion)}get reflectivity(){return this.drawState.reflectivity}set reflectivity(a){const b=this.drawState;b.reflectivity===a||(b.reflectivity=a,++this.stateVersion)}get emissiveMap(){return this.drawState.emissiveMap}set emissiveMap(a){const b=this.drawState;b.emissiveMap===a||(b.emissiveMap=a,++this.stateVersion)}get environmentMap(){return this.drawState.environmentMap}set environmentMap(a){const b=this.drawState;b.environmentMap===a||(b.environmentMap=a,++this.stateVersion)}get emissiveMapColor(){return this.drawState.emissiveMapColor}set emissiveMapColor(a){const b=this.drawState,c=a||WHITE;b.emissiveMapColor=a;if(c.r!==b.emissiveR||c.g!==b.emissiveG||c.b!==b.emissiveB)b.emissiveR=c.r,b.emissiveG=c.g,b.emissiveB=c.b,++this.stateVersion}get shader(){return this.drawState.shader}set shader(a){const b=this.drawState;b.shader===a||(b.shader=a,++this.stateVersion)}get receiveShadow(){return this.drawState.receiveShadow}set receiveShadow(a){const b=this.drawState;b.receiveShadow===a||(b.receiveShadow=a,++this.stateVersion)}get pixelated(){return this.drawState.pixelated}set pixelated(a){const b=this.drawState;b.pixelated===a||(b.pixelated=a,++this.stateVersion)}get blend(){return this.drawState.blend}set blend(a){const b=this.drawState;b.blend===a||(b.blend=a,++this.stateVersion)}updateMatrices(a=mainCanvasSize.y?mainCanvasSize.x/mainCanvasSize.y:1){const b=this.camera;b.align2D&&b.update2D();const c=b.getMatrix();this.viewMatrix=c.copy().invert();this.projectionMatrix=b.getProjectionMatrix(a);this.viewProjection=this.projectionMatrix.copy().multiply(this.viewMatrix);a=c.m;this.cameraRight=render3DAxis(a,0);this.cameraUp=render3DAxis(a,4);this.cameraBack=render3DAxis(a,8);this.cameraForward=this.cameraBack.scale(-1);this.frustumPlanes=render3DFrustumPlanes(this.viewProjection)}worldToClip(a){const b=this.viewProjection.m,c=b[3]*a.x+b[7]*a.y+b[11]*a.z+b[15],d=(b[2]*a.x+b[6]*a.y+b[10]*a.z+b[14])/c;if(!(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<c.distance)&&(c={object:d,distance:b});return c}playSound(a,b,c=1,d=1,e=1,f=!1,g=!1){b=b.subtract(this.camera.pos);const h=a.rangeIsDefault?this.soundDefaultRange:a.range;if(h){const k=b.length();if(k>=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;p<g;++p){const t=render3DStripIndex(p,f),u=a[t],v=n?c[t]:c||RENDER3D_DEFAULT_UV;render3DWriteVertex(k,l,this.streamCount++*RENDER3D_VERTEX_FLOATS,u.x,u.y,u.z,m?b[t]:b||RENDER3D_DEFAULT_NORMAL,h.x+v.x*h.w,h.y+v.y*h.h,r?d[t].rgbaInt():q)}}}}drawStripUnlit(a,b,c,d,e){render3DWithState({lighting:!1},()=>this.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=.99<abs(c.y)?vec3(0,0,1):vec3(0,1,0);var d=a.radius,e=min(max(d/500,.02),d/2),f=2*min(a.coneAngle,RENDER3D_SHADOW_CONE_MAX)+.1;b=Matrix4.lookAt(b,b.add(c),g);this.shadowMatrix=Matrix4.perspective(f,1,e,d).multiply(b.copy().invert());f=b.m;b=render3DObjectMatrix(a).m;a=vec3(b[0],b[1],b[2]).normalize();b=vec3(b[4],b[5],b[6]).normalize();c=vec3(f[0],f[1],f[2]);f=vec3(f[4],f[5],f[6]);this.gelAxes=[a.dot(c),a.dot(f),b.dot(c),b.dot(f)];this.shadowPlanes=render3DFrustumPlanes(this.shadowMatrix);this.shadowDepthBias=this.shadowBias*d*d*e/(d-e)}else this.shadowDepthBias=this.shadowBias,d=0<this.shadowRange?this.shadowRange:1,e=d/2,a=this.sunDirection.normalize(),f=this.shadowCenter||this.camera.pos.add(this.cameraForward.scale(.8*e)),a=Matrix4.lookAt(f.add(a.scale(d)),f).invert(),f=d/(this.shadowTextureSize||this.shadowMapSize),b=a.m,b[12]=round(b[12]/f)*f,b[13]=round(b[13]/f)*f,this.shadowMatrix=Matrix4.orthographic(-e,e,-e,e,0,2*d).multiply(a),this.shadowPlanes=render3DFrustumPlanes(this.shadowMatrix)}setSky(a=hsl(.6,.8,.55),b=hsl(.6,1,.9),c=b,d=.5){this.sky?.dispose();this.sky=buildSky(a,b,c);this.fogColor=b.copy();this.ambientColor=a.scale(d,1);this.ambientGroundColor=c.scale(d,1);return this.sky}setFog(a,b,c){this.fogStart=a;this.fogEnd=b;c&&(this.fogColor=c.copy())}drawBox(a,b=1,c=WHITE,d){this.drawMesh(this.boxMesh,buildMatrix(a,d,render3DSize3(b)),void 0,c)}drawSphere(a,b=1,c=WHITE){this.drawMesh(this.sphereMesh,buildMatrix(a,void 0,vec3(b)),void 0,c)}drawBillboard(a,b=vec2(1),c,d=WHITE,e=0,f=!1){if(this.capture)return this.drawStripUnlit(render3DBillboardCorners(a,b,e,f),this.cameraBack,RENDER3D_QUAD_UVS,d.copy(),c);if(this.transparentQueue){const A=a.copy(),C=b.copy(),D=d.copy();return this.queueTransparent(A,()=>this.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=2<f&&1e-12>a[0].distanceSquared(a[f-1]);for(let p=0;p<f;++p){const t=a[p];var r=isArray(b)?b[p]:b;let u=isArray(d)?d[p]:d;this.transparentQueue&&(u=u.copy());var q=e&&(isArray(e)?e[p]:e);const v=a[p<f-1?p+1:n?1:p],y=a[0<p?p-1:n?f-2:p];q=q||v.subtract(y).cross(l);1e-12<q.lengthSquared()&&(m=q.normalize());r=m.scale(r/2);g.push(t.add(r),t.subtract(r));h?.push(vec2(p/(f-1),0),vec2(p/(f-1),1));k.push(u,u)}render3DWithState({lighting:!1,cullBackFaces:!1},()=>this.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}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,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){return"#version 300 es\nprecision highp float;uniform vec4 lightDir,lightColor,ambientFog,ambientGround,fogColor,shadowParams;uniform vec4 extraLights["+RENDER3D_MAX_LIGHTS+"],extraLightColors["+RENDER3D_MAX_LIGHTS+"];uniform vec4 extraLightCones["+RENDER3D_MAX_LIGHTS+"];uniform int extraLightCount;uniform vec3 cameraPos;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);":"")+"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);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.){float z=distance(cameraPos,P);c.rgb=mix(c.rgb,shadowParams.w<0.?vec3(0):fogColor.rgb,smoothstep(fogColor.a,ambientFog.a,z));}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;b.uniform3f(render3DUniform("cameraPos"),d.x,d.y,d.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;f<a;++f)for(let g=0;g<a;++g){const h=b(render3DCubeDirection(d,(g+.5)/a*2-1,(f+.5)/a*2-1)),k=4*(g+f*a);e[k]=255*clamp(h.r)+.5|0;e[k+1]=255*clamp(h.g)+.5|0;e[k+2]=255*clamp(h.b)+.5|0;e[k+3]=255*clamp(h.a)+.5|0}c.push(e)}return new CubeMap(a,c)}async function loadCubeMap(a){const b=await Promise.all(a.map(d=>new 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&&0<d.near?d.near:.1;f.far=d.far;let g=new Matrix4;f.getMatrix=()=>g.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<e)c.cameraRight=c.cameraRight.scale(-1),c.cameraUp=c.cameraUp.scale(-1);const m=canvasClearColor;b.clearColor(m.r,m.g,m.b,1);b.depthMask(!0);b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT);render3DUseProgram(c.program);c.renderStages(a,!0)}b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,null,0);b.bindTexture(b.TEXTURE_CUBE_MAP,k);b.generateMipmap(b.TEXTURE_CUBE_MAP);b.bindTexture(b.TEXTURE_CUBE_MAP,null)}}finally{c.capturingCube=void 0,c.camera=d,c.updateMatrices(),b.bindFramebuffer(b.FRAMEBUFFER,null),b.viewport(0,0,glCanvas.width,glCanvas.height),b.activeTexture(b.TEXTURE0+5),b.bindTexture(b.TEXTURE_CUBE_MAP,render3DCubeTexture(c.environment)||null),b.activeTexture(b.TEXTURE0),render3DBoundEnvironment=c.environment||null}}function render3DDrawSkyBox(a){const b=glContext,c=render3D;c.skyBoxProgram||(c.skyBoxProgram=glCreateProgram("#version 300 es\nprecision highp float;out vec2 v;void main(){v=vec2(gl_VertexID&1,gl_VertexID>>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);0<a.reflectivity&&(a=a.environmentMap||b.environment,a===b.capturingCube&&(a=void 0),render3DBindEnvironment(a),c=a?a.size:1,render3DUniform4f("envParams",a?1:0,max(0,log2(c)-2),log2(.45*c),log2(2*c/PI)),a=b.sky&&render3DSkyColors.get(b.sky),c=b.ambientColor,b=b.ambientGroundColor||c,d=a?a[0]:c,e=a?a[2]:b,render3DUniform4f("skyTop",d.r,d.g,d.b,1),render3DUniform4f("skyBottom",e.r,e.g,e.b,1),a?render3DUniform4f("skyHorizon",a[1].r,a[1].g,a[1].b,1):render3DUniform4f("skyHorizon",(c.r+b.r)/2,(c.g+b.g)/2,(c.b+b.b)/2,1))}let render3DBoundEnvironment;function render3DBindEnvironment(a){const b=glContext;a&&a!==render3DBoundEnvironment&&b&&(b.activeTexture(b.TEXTURE0+5),b.bindTexture(b.TEXTURE_CUBE_MAP,render3DCubeTexture(a)||null),b.activeTexture(b.TEXTURE0),render3DBoundEnvironment=a)}let render3DBoundMaps=[];function render3DBindMap(a,b,c){const d=render3DBoundMaps,e=!!b&&c.pixelated;if(d[a]!==b||d[a+2]!==e)d[a]=b,d[a+2]=e,render3DBindTexture(b,c,a)}function render3DUniform4f(a,b,c,d,e){let f;const g=(f=render3D.uniformValues)[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.uniform4f(render3DUniform(a),b,c,d,e)}function render3DUniform1i(a,b){const c=render3D.uniformValues;c[a]!==b&&(c[a]=b,glContext.uniform1i(render3DUniform(a),b))}function render3DBindVertexBuffer(a){const b=glContext;b.bindBuffer(b.ARRAY_BUFFER,a);for(const c of RENDER3D_ATTRIBS)b.vertexAttribPointer(c[0],c[1],c[2],c[3],RENDER3D_VERTEX_BYTES,c[4])}function render3DBindMesh(a){render3DBindVertexBuffer(a.buffer);glContext.bindBuffer(glContext.ELEMENT_ARRAY_BUFFER,a.indexBuffer)}function render3DTextureOf(a){return a instanceof TileInfo?a.textureInfo:a}const render3DLevel=[];function render3DLevelLeave(a){a=render3DLevel.indexOf(a);0<=a&&render3DLevel.splice(a,1)}function render3DLevelAssertPlaced(a){}const render3DTileUVRect={x:0,y:0,w:1,h:1},render3DWholeTiles=new WeakSet;function render3DGetTileUVs(a){if(!(a instanceof TileInfo&&a.textureInfo)||render3DWholeTiles.has(a))return RENDER3D_FULL_UV_RECT;const b=a.textureInfo.sizeInverse,c=render3DTileUVRect,d=b.x*a.bleed,e=b.y*a.bleed;c.x=a.pos.x*b.x+d;c.y=a.pos.y*b.y+e;c.w=a.size.x*b.x-2*d;c.h=a.size.y*b.y-2*e;return c}function render3DSetDrawUniforms(a,b,c,d,e=render3D){var f=glContext,g=render3D;d||=render3DGetTileUVs(b);render3DDrawAttribs(a.m,c,d);render3DBindTexture(b,e);if(g.shadowPass)e=e.blend?1:0,render3DShadowCut!==e&&glContext.uniform1f(render3DUniform("cut",g.shadowShader),render3DShadowCut=e);else{a=e.shader?render3DShaderProgram(e.shader):g.program;a===g.currentProgram||render3DUseProgram(a);e.blend?(f.enable(f.BLEND),a=e.additive?f.ONE:f.ONE_MINUS_SRC_ALPHA,f.blendFuncSeparate(f.SRC_ALPHA,a,f.ONE,a)):f.disable(f.BLEND);e.depthTest?f.enable(f.DEPTH_TEST):f.disable(f.DEPTH_TEST);f.depthMask(e.depthWrite);e.cullBackFaces?f.enable(f.CULL_FACE):f.disable(f.CULL_FACE);f.frontFace(e.mirrored?f.CCW:f.CW);a=g.sunDirection;c=-(a.length()||1);d=g.sunColor;var h=g.ambientColor;f=g.fogColor||canvasClearColor;render3DUniform4f("lightDir",a.x/c,a.y/c,a.z/c,e.lighting?e.emissive:1);render3DUniform4f("lightColor",d.r,d.g,d.b,e.specular);render3DUniform4f("ambientFog",h.r,h.g,h.b,g.fogEnd);(a=g.ambientGroundColor)?render3DUniform4f("ambientGround",a.r,a.g,a.b,1):render3DUniform4f("ambientGround",0,0,0,0);render3DUniform4f("fogColor",f.r,f.g,f.b,g.fogEnd?min(g.fogStart,g.fogEnd-.001):g.fogStart);f=g.shadows&&g.passIsDefault&&e.receiveShadow?1:0;render3DUniform4f("shadowParams",f&&0<=g.shadowLightIndex?2+g.shadowLightIndex:f,g.shadowDepthBias,g.shadowSoftness/g.shadowTextureSize,e.blend?e.additive?-1:0:1);g=render3DTextureOf(b);render3DUniform1i("premultipliedTexture",+!(!g?.glTexture||!glPremultipliedTextures.has(g.glTexture)));render3DSetMaterialUniforms(e)}}function render3DFrustumPlanes(a){a=a.m;const b=[];for(let c=0;3>c;++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<g;++m){const n=render3DStripIndex(m,f);e(a[n],h?b[n]:b||RENDER3D_DEFAULT_NORMAL,k?c[n]:c||RENDER3D_DEFAULT_UV,l?d[n]:d||WHITE)}}function render3DWriteVertex(a,b,c,d,e,f,g,h,k,l){a[c]=d;a[c+1]=e;a[c+2]=f;a[c+3]=g.x;a[c+4]=g.y;a[c+5]=g.z;a[c+6]=h;a[c+7]=k;b[c+8]=l}function render3DFlipTriangles(a){for(let b=0;b<a.length;b+=3){const c=a[b+1];a[b+1]=a[b+2];a[b+2]=c}return a}function render3DStripTriangles(a,b,c){const d=[];for(let e=2;e<a;++e){const f=e&1?e-1:e-2,g=e&1?e-2:e-1;c[f]!=c[g]&&c[g]!=c[e]&&c[f]!=c[e]&&d.push(b[f],b[g],b[e])}return d}function render3DMeshVertexData(a,b,c=new ArrayBuffer(b.length*RENDER3D_VERTEX_BYTES)){const d=b.length,e=new Float32Array(c),f=new Uint32Array(c);let g=0,h=Infinity,k=Infinity,l=Infinity,m=-Infinity,n=-Infinity,r=-Infinity;for(let p=0;p<d;++p){const t=b[p];var q=a.points[t];const u=a.uvs[t]||RENDER3D_DEFAULT_UV,v=q.x,y=q.y;q=q.z;render3DWriteVertex(e,f,p*RENDER3D_VERTEX_FLOATS,v,y,q,a.normals[t]||RENDER3D_DEFAULT_NORMAL,u.x,u.y,(a.colors[t]||WHITE).rgbaInt());g=max(g,v*v+y*y+q*q);h=min(h,v);k=min(k,y);l=min(l,q);m=max(m,v);n=max(n,y);r=max(r,q)}a.radius=g**.5;a.bounds=d?{min:vec3(h,k,l),max:vec3(m,n,r)}:{min:vec3(),max:vec3()};return c}function render3DPolygonStrip(a){const b=[a[0]];for(let c=1,d=a.length-1;c<=d;++c,--d)b.push(a[c]),c!==d&&b.push(a[d]);return b}function render3DFlipWinding(a){if(a.indices)return void render3DFlipTriangles(a.indices);for(const b of["points","normals","uvs","colors"]){const c=a[b];c.length&&(c.unshift(c[0]),c.push(c[c.length-1]))}a.vertexKeys=void 0}const render3DMeshBuffers="undefined"==typeof FinalizationRegistry?void 0:new FinalizationRegistry(({buffer:a,indexBuffer:b,generation:c})=>{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<a.length;++g){var f=a[g];const h=round(1e5*f.x),k=round(1e5*f.y);f=round(1e5*f.z);const l=Math.imul(h,73856093)^Math.imul(k,19349663)^Math.imul(f,83492791);let m=c.get(l);for(;void 0!==m&&(e[3*m]!==h||e[3*m+1]!==k||e[3*m+2]!==f);)m=d[m];void 0===m&&(m=d.length,d.push(c.get(l)),c.set(l,m),e.push(h,k,f));b[g]=m}return{groups:b,count:d.length}}function render3DSmoothNormalSums(a,b){const c=!b,d=c?max(a.length-2,0):b.length/3|0,{groups:e,count:f}=render3DPlaceGroups(a),g=new Float64Array(3*f),h=new Uint8Array(f);let k=0,l=0,m=0;const n=(t,u,v,y)=>{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<d;++t){const u=c?t:b[3*t],v=c?t+1:b[3*t+1],y=c?t+2:b[3*t+2],x=a[u],w=a[v],z=a[y];var r=w.x-x.x,q=w.y-x.y,p=w.z-x.z;const A=z.x-x.x,C=z.y-x.y,D=z.z-x.z,B=q*D-p*C;p=p*A-r*D;r=r*C-q*A;if(q=B**2+p**2+r**2)q=(!c||t&1?1:-1)/q**.5,k=B*q,l=p*q,m=r*q,n(x,w,z,e[u]),n(w,z,x,e[v]),n(z,x,w,e[y])}return{groups:e,sums:g,touched:h}}class Mesh{constructor(){this.points=[];this.normals=[];this.uvs=[];this.colors=[];this.indexBuffer=this.buffer=void 0;this.indexType=this.bufferCount=0;this.dirty=!1;this.instanced=void 0;this.dynamicDraw=this.doubleSided=!1;this.vertexLayout=this.vertexKeys=this.indices=void 0;this.vertexDataPacked=!1;this.instanceCount=0;this.instanceData=void 0;this.radius=0;this.bounds=void 0;this.contextGeneration=0}get vertexCount(){return this.points.length}addStrip(a,b,c,d){if(this.indices)return a=(new Mesh).addStrip(a,b,c,d).toIndexed(),this.addTriangles(a.points,a.indices,a.normals,a.uvs,a.colors);render3DForEachStripVertex(a,b,c,d,(e,f,g,h)=>{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;l<a.length;++l)this.points.push(a[l]),this.normals.push(g?c[l]:c||RENDER3D_DEFAULT_NORMAL),this.uvs.push(h?d[l]:d||RENDER3D_DEFAULT_UV),this.colors.push(k?e[l]:e||WHITE);for(const l of b)this.indices.push(l+f);this.dirty=!0;return this}toIndexed(){if(this.indices)return this;const{vertices:a,indices:b}=this.getTriangles();this.points=a.map(c=>this.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;l<m;l+=3)this.indices.push(k[l]+h,k[l+(e?2:1)]+h,k[l+(e?1:2)]+h)}else if(e&&f.points.length){var g=f.points.length-1;g=[0,...f.points.keys(),g]}for(let h=0,k=g?g.length:f.points.length;h<k;++h)e=g?g[h]:h,this.points.push(b.transformPoint(f.points[e])),this.normals.push(d.transformDirection(f.normals[e]||RENDER3D_DEFAULT_NORMAL).normalize()),this.uvs.push((f.uvs[e]||RENDER3D_DEFAULT_UV).copy()),this.colors.push((f.colors[e]||WHITE).multiply(c));this.doubleSided||(this.doubleSided=a.doubleSided);this.vertexKeys=void 0;this.dirty=!0;return this}mirror(a=vec3(1,0,0)){a=a.normalize();const b=-2*a.x,c=-2*a.y,d=-2*a.z;a=new Matrix4([1+b*a.x,c*a.x,d*a.x,0,b*a.y,1+c*a.y,d*a.y,0,b*a.z,c*a.z,1+d*a.z,0,0,0,0,1]);return(new Mesh).combine(this).combine(this,a)}spin(a,b=vec3(0,1,0)){const c=new Mesh;b=b.normalize();for(let d=0;d<a;++d)c.combine(this,render3DAxisRotation(b,d/a*2*PI));return c}union(a,b){return render3DMeshCSG(this,a,b,0)}subtract(a,b){return render3DMeshCSG(this,a,b,1)}intersect(a,b){return render3DMeshCSG(this,a,b,2)}scaleUVs(a){const b=render3DSize2(a);this.uvs=this.uvs.map(c=>vec2(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;c<this.points.length;++c){this.points[c]=a.transformPoint(this.points[c]);let d,e;(d=this.normals)[e=c]&&(d[e]=b.transformDirection(this.normals[c]).normalize())}render3DMirrors(a)&&render3DFlipWinding(this);this.dirty=!0;return this}flipNormals(){render3DFlipWinding(this);this.normals=this.normals.map(a=>a.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<c.length;d+=3){var e=b[c[d]],f=b[c[d+2]];e=b[c[d+1]].subtract(e).cross(f.subtract(e));e.lengthSquared()&&(a[c[d]]=a[c[d+1]]=a[c[d+2]]=e.normalize())}this.normals=a;this.dirty=!0;return this}b=this.points;c=b.length;if(a){const{groups:h,sums:k,touched:l}=render3DSmoothNormalSums(b);this.normals=b.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)**.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+2<c;++d)e=b[d],f=b[d+2],e=b[d+1].subtract(e).cross(f.subtract(e)),a.push(e.lengthSquared()?e.normalize(d&1?1:-1):void 0);const g=b.map(()=>RENDER3D_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=65535<c.length;const e=render3DMeshVertexData(this,c);this.vertexLayout=this.dynamicDraw?{vertices:c,pointCount:this.points.length,data:e}:void 0;this.vertexKeys=void 0;this.buffer=a.createBuffer();this.indexBuffer=a.createBuffer();this.bufferCount=d.length;this.indexType=b?a.UNSIGNED_INT:a.UNSIGNED_SHORT;this.dirty=this.vertexDataPacked=!1;a.bindBuffer(a.ARRAY_BUFFER,this.buffer);a.bufferData(a.ARRAY_BUFFER,e,this.dynamicDraw?a.DYNAMIC_DRAW:a.STATIC_DRAW);a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer);a.bufferData(a.ELEMENT_ARRAY_BUFFER,b?new Uint32Array(d):new Uint16Array(d),a.STATIC_DRAW);this.contextGeneration=render3D.contextGeneration;b={buffer:this.buffer,indexBuffer:this.indexBuffer,generation:this.contextGeneration};render3DMeshBuffers?.register(this,b,this);a.bindBuffer(a.ARRAY_BUFFER,glArrayBuffer);return this}getTriangles(){const a=this.points.length,b=[];if(this.indices){for(var c=0;c<a;++c)b.push(c);return{vertices:b,indices:render3DFlipTriangles(this.indices.slice())}}c=new Int32Array(a);const d=new Int32Array(a);var e=this.vertexKeys;if(e&&e.length===a){var f=new Int32Array(a).fill(-1);for(var g=0;g<a;++g){var h=e[g],k=f[h];0>k?(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<a;++k){var l=this.points[k],m=this.normals[k]||RENDER3D_DEFAULT_NORMAL,n=this.uvs[k]||RENDER3D_DEFAULT_UV;const p=9*k;var r=e[p]=round(1e6*l.x),q=e[p+1]=round(1e6*l.y);l=e[p+2]=round(1e6*l.z);e[p+3]=round(1e6*m.x);e[p+4]=round(1e6*m.y);e[p+5]=round(1e6*m.z);e[p+6]=round(1e6*n.x);e[p+7]=round(1e6*n.y);e[p+8]=(this.colors[k]||WHITE).rgbaInt();m=Math.imul(2166136261^r,2654435761)>>>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=2<f&&1e-9>abs(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])));0<w?z(w-1):k&&z(f-2);w<f-1?z(w):k&&z(0);return A.length()?A.normalize():vec2(1,0)},m=(w,z)=>vec3(sin(z)*w.x,w.y,cos(z)*w.x),n=[0];for(var r=1;r<f;++r)n[r]=n[r-1]+hypot(a[r][0]-a[r-1][0],a[r][1]-a[r-1][1]);r=n[f-1]||1;for(let w=0;w+1<f;++w)if(c){var q=[],p=[],t=[],u=l(w),v=l(w+1),y=PI/b,x=1e-9>abs(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;p<b;++p)t=p/b*2*PI,u=(p+1)/b*2*PI,v=p/b,x=(p+1)/b,e.addStrip([g(w+1,t),g(w,t),g(w+1,u),g(w,u)],m(q,(t+u)/2),[vec2(v,1-n[w+1]/r),vec2(v,1-n[w]/r),vec2(x,1-n[w+1]/r),vec2(x,1-n[w]/r)]);if(d&&!k)for(const[w,z]of[[0,!1],[f-1,!0]])if(!(1e-9>abs(a[w][0]))){c=[];l=[];for(m=0;m<b;++m)n=(z?m:-m)/b*2*PI,c.push(g(w,n)),l.push(vec2(.5*sin(n)+.5,.5*cos(n)+.5));e.addStrip(render3DPolygonStrip(c),vec3(0,z?1:-1,0),render3DPolygonStrip(l))}e.doubleSided=!k&&!d&&(1e-9<abs(a[0][0])||1e-9<abs(a[f-1][0]));return e}function buildSphere(a=1,b=16,c=8,d=render3D?.smoothShading){const e=[];for(let f=0;f<=c;++f){const g=f/c*PI-PI/2;e.push([cos(g)*a/2,sin(g)*a/2])}return buildLathe(e,b,d)}function render3DBevelBox(a,b,c,d){const e=new Mesh,f=a.subtract(vec3(b)),g=max(1,c|0);c=(q,p,t,u,v,y)=>{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],1<g&&u?[u,v,y]:x,[w(q),w(p),w(t)])}};for(const[q,p,t]of d){const[u,v,y,x]=render3DQuadAxes(q.multiply(a),p.multiply(f),t.multiply(f));c(u,v,y);c(y,v,x)}var h=[vec3(1,0,0),vec3(0,1,0),vec3(0,0,1)];for(var k=0;3>k;++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<g;++u){const v=r(u),y=r(u+1),x=t.add(v.scale(b)),w=n.add(v.scale(b)),z=t.add(y.scale(b)),A=n.add(y.scale(b));c(x,w,z,v,v,y);c(z,w,A,y,v,y)}}for(const q of[-1,1])for(const p of[-1,1])for(const t of[-1,1]){const u=vec3(q,0,0),v=vec3(0,p,0),y=vec3(0,0,t);l=f.multiply(vec3(q,p,t));m=(x,w)=>{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;h<g;++h){for(k=0;k<=h;++k)c(l.add(m(h,k).scale(b)),l.add(m(h+1,k).scale(b)),l.add(m(h+1,k+1).scale(b)),m(h,k),m(h+1,k),m(h+1,k+1));for(k=0;k<h;++k)c(l.add(m(h,k).scale(b)),l.add(m(h+1,k+1).scale(b)),l.add(m(h,k+1).scale(b)),m(h,k),m(h+1,k+1),m(h,k+1))}}return e}function buildBox(a=1,b=0,c=1){a=render3DSize3(a).scale(.5);var d=[[vec3(0,0,1),vec3(1,0,0),vec3(0,1,0)],[vec3(0,0,-1),vec3(-1,0,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,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)]];b=min(b,a.x,a.y,a.z);if(0<b)return render3DBevelBox(a,b,c,d);c=new Mesh;for(const[e,f,g]of d){d=e.multiply(a);b=f.multiply(a);const h=g.multiply(a);c.addStrip(render3DQuadAxes(d,b,h),e,RENDER3D_QUAD_UVS)}return c}function buildGrid(a=vec2(1),b=1,c,d,e=d&&render3D?.smoothShading){d||=()=>0;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;t<h;++t){var u=a(t+1);if(e){var v=[];const y=[],x=[],w=[];for(let z=0;z<=g;++z)v.push(b.points[z],u.points[z]),y.push(b.normals[z],u.normals[z]),x.push(b.uvs[z],u.uvs[z]),w.push(b.colors[z],u.colors[z]);f.addStrip(v,y,x,w)}else for(v=0;v<g;++v)f.addQuad(b.points[v],u.points[v],u.points[v+1],b.points[v+1],p(v+.5,t+.5),[b.uvs[v],u.uvs[v],u.uvs[v+1],b.uvs[v+1]]);b=u}if(e)for(a=2*(g+1)+2,b=f.vertexKeys=new Int32Array(f.points.length),t=0;t<h;++t){u=t*a;b[u]=t*(g+1);for(v=0;v<=g;++v)b[u+1+2*v]=t*(g+1)+v,b[u+2+2*v]=(t+1)*(g+1)+v;b[u+a-1]=(t+1)*(g+1)+g}f.doubleSided=!0;return f}function buildSky(a=hsl(.6,.8,.55),b=hsl(.6,1,.9),c=b,d=16,e=8){d=buildSphere(2,d,e,!0).flipNormals();d.colors=d.points.map(f=>0>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<k&&a.mass&&k>=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)<k-1e-6)&&(l=sign(l),k-=l*(a.pos[n]-b.pos[n]),0<k&&k<e)){var m=n;e=k;h=l}}if(m)return a=vec3(),a[m]=h*e,a}}const render3DIsSprite=a=>!a.mesh&&!!a.tileInfo;function render3DOnFace(a,b){if(!b.size)return!1;a=a.normalize();b=b.axes??BOX_WORLD_AXES;return.999999<max(abs(a.dot(b[0])),abs(a.dot(b[1])),abs(a.dot(b[2])))}function render3DCollideSolid(a){let b=render3DSolidShape(a);const c=render3DSolidReach(a);for(const k of engineObjectsCollide){if(k===a)break;if(!k.destroyed&&k instanceof EngineObject3D&&!k.parent&&!k.sync2D&&(a.isSolid||k.isSolid)){var d=b.pos,e=k.pos3D,f=c+render3DSolidReach(k),g=d.x-e.x,h=d.y-e.y;d=d.z-e.z;if(!(g*g+h*h+d*d>f*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<h&&a.mass&&h>=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&&0<k.velocity3D.dot(g)&&(k.velocity3D=k.velocity3D.reflect(g,k.restitution));f&&e&&(g=a.pos3D.copy(),render3DSettleFixed(a,k,h),k.pos3D=k.pos3D.add(a.pos3D.subtract(g)));e&&(g=k.pos3D.copy(),render3DSettleFixed(k,a,d),d=k.pos3D.x-g.x,e=k.pos3D.y-g.y,g=k.pos3D.z-g.z,f&&(d||e||g)&&(a.pos3D=a.pos3D.add(vec3(d,e,g)),render3DSettleFixed(a,k,h)));f&&(b=render3DSolidShape(a))}}}}function engineObjectsCollect3D(a,b,c=engineObjects,d=!1){const e="number"===typeof b&&0<b?(b/2)**2:void 0;b=e?void 0:"number"===typeof b?vec3():render3DSize3(b);const f=[];for(const h of c){if(!(h instanceof EngineObject3D)||h.destroyed)continue;const k=render3DObjectMatrix(h).m;c=h.size3D;if(!(c.x||c.y||c.z))continue;c=vec3(k[12],k[13],k[14]);const l=d?vec3():render3DWorldSize(h,k);var g=m=>vec3(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-6<abs(g[0].dot(g[1]))||1e-6<abs(g[0].dot(g[2]))||1e-6<abs(g[1].dot(g[2])))){const m=g.map((n,r)=>n.scale(r?1<r?l.z/2:l.y/2:l.x/2));g=n=>2*(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*c<e}c&&f.push(h)}return f}const render3DRaycastCenter=vec3();function render3DRaycastObject(a,b){if(!b.destroyed&&b instanceof EngineObject3D){if(b instanceof HeightMap||b instanceof VoxelMap)return b.levelRaycast3D(a);if((b.mesh||b.tileInfo)&&!(b instanceof InstancedMesh3D)){var c=render3DObjectMatrix(b),d=b.mesh;if(!d)return render3DRaycastSprite(a,b,c);b=(d.dirty||!d.radius?d.computeRadius():d.radius)*render3DMaxStretch(c.m);if(0<b){var e=c.m;e=render3DRaycastCenter.set(e[12],e[13],e[14]);if(void 0!==raycastSphere(a,e,b)){if(!c.determinant())return render3DRaycastDisc(a,e,b);b=c.copy().invert();c=d.bounds||d.getBounds();b=new Ray3D(b.transformPoint(a.origin),b.transformDirection(a.direction));c=raycastBox(b,c.min.add(c.max).scale(.5),c.max.subtract(c.min));return void 0!==c&&a.direction.lengthSquared()?render3DRaycastMesh(b,d):c}}}}}function render3DRaycastMesh(a,b){const c=b.points,d=b.indices;b=b.doubleSided;const e=a.origin.x,f=a.origin.y,g=a.origin.z,h=a.direction.x,k=a.direction.y;a=a.direction.z;const l=d?d.length/3|0:c.length-2;let m;for(let x=0;x<l;++x){var n=void 0,r=void 0,q=void 0;d?(n=c[d[3*x]],r=c[d[3*x+2]],q=c[d[3*x+1]]):(n=c[x&1?x+1:x],r=c[x&1?x:x+1],q=c[x+2]);var p=r.x-n.x,t=r.y-n.y,u=r.z-n.z;r=q.x-n.x;const w=q.y-n.y;q=q.z-n.z;var v=k*q-a*w,y=a*r-h*q;const z=h*w-k*r,A=p*v+t*y+u*z;if(b?!A:!(0>A))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(0<c.x&&0<c.y){if(!a.direction.lengthSquared())return render3DRaycastDisc(a,d,hypot(c.x,c.y)/2);c=render3DBillboardAxes(c,b.rotation3D.z,b.upright);b=vec3(c[0],c[1],c[2]);c=vec3(c[3],c[4],c[5]);var e=raycastPlane(a,d,b.cross(c));if(void 0!==e)return a=a.getPosition(e).subtract(d),abs(a.dot(b))<=b.lengthSquared()&&abs(a.dot(c))<=c.lengthSquared()?e:void 0}}function render3DRaycastDisc(a,b,c){const d=a.direction;a=b.subtract(a.origin);b=(b=d.dot(d))?a.dot(d)/b:0;return 0<=b&&a.subtract(d.scale(b)).lengthSquared()<=c*c?b:void 0}function engineObjectsRaycast3D(a,b=engineObjects){const c=[];for(const d of b)b=render3DRaycastObject(a,d),void 0!==b&&c.push({o:d,distance:b});return c.sort((d,e)=>d.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;f<b;++f){c.set(RENDER3D_IDENTITY.m,f*RENDER3D_MATRIX_FLOATS);const g=f*RENDER3D_COLOR_FLOATS;e[g]=d.r;e[g+1]=d.g;e[g+2]=d.b;e[g+3]=d.a;e[g+4]=a.x;e[g+5]=a.y;e[g+6]=a.w;e[g+7]=a.h}}setTransformAt(a,b,c,d){matrix4Compose(this.matrixData,a*RENDER3D_MATRIX_FLOATS,b,c,d);this.markDirty(a)}setTransforms(a,b,c,d,e,f,g,h,k,l,m){const n=this.matrixData,r=a+b;for(let q=a;q<r;++q){const p=q*RENDER3D_MATRIX_FLOATS,t=k?k[q]:1,u=l?l[q]:1,v=m?m[q]:1;if(f){const y=cos(f[q]),x=sin(f[q]),w=cos(g[q]),z=sin(g[q]),A=cos(h[q]),C=sin(h[q]);n[p]=(w*A+z*x*C)*t;n[p+1]=y*C*t;n[p+2]=(-z*A+w*x*C)*t;n[p+4]=(-w*C+z*x*A)*u;n[p+5]=y*A*u;n[p+6]=(z*C+w*x*A)*u;n[p+8]=z*y*v;n[p+9]=-x*v;n[p+10]=w*y*v}else n[p]=t,n[p+1]=0,n[p+2]=0,n[p+4]=0,n[p+5]=u,n[p+6]=0,n[p+8]=0,n[p+9]=0,n[p+10]=v;n[p+3]=n[p+7]=n[p+11]=0;n[p+15]=1;n[p+12]=c[q];n[p+13]=d[q];n[p+14]=e[q]}b&&this.markDirtyRange(a,r)}setMatrixAt(a,b){const c=this.matrixData,d=a*RENDER3D_MATRIX_FLOATS;b=b.m;for(let e=0;16>e;++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.dirtyStart&&(this.dirtyStart=a);a>=this.dirtyEnd&&(this.dirtyEnd=a+1);a<this.boundsStart&&(this.boundsStart=a);a>=this.boundsEnd&&(this.boundsEnd=a+1)}markDirtyRange(a,b){a<this.dirtyStart&&(this.dirtyStart=a);b>this.dirtyEnd&&(this.dirtyEnd=b);a<this.boundsStart&&(this.boundsStart=a);b>this.boundsEnd&&(this.boundsEnd=b)}markColorDirty(a){a<this.colorDirtyStart&&(this.colorDirtyStart=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;f<this.boundsEnd;++f){var b=f*RENDER3D_MATRIX_FLOATS,c=a[b+12];const g=a[b+13],h=a[b+14];c=c*c+g*g+h*h;b=render3DMaxStretchSquared(a,b);c>d&&(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<e.length;f+=RENDER3D_COLOR_FLOATS)e[f]=d.x,e[f+1]=d.y,e[f+2]=d.w,e[f+3]=d.h;this.uvTileInfo=this.tileInfo;this.colorDirtyStart=0;this.colorDirtyEnd=this.maxCount}this.buffer&&this.bufferGeneration===a.contextGeneration?(d=(f,g,h,k,l)=>{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(0<this.glow&&!this.directional){var a=render3D,b=this.color,c=render3DObjectMatrix(this).getTranslation(),d=a.camera.pos.subtract(c),e=d.length();c=e?c.add(d.scale(min(this.glow,e)/2/e)):c;b=rgb(b.r,b.g,b.b,b.a*min(this.intensity,1));d=engineGlowTexture(this.glowFalloff);!d&&glContext||a.drawBillboard(c,vec2(this.glow),d,b)}}}class DirectionalLight3D extends Light3D{constructor(a=vec3(0,1,0),b=WHITE,c=1){super(a,0,b,c);this.directional=!0}}const RENDER3D_TEXT_LEADING=1.3;function render3DDetach(a){a.parent?a.parent.removeChild(a):a.matrixParent&&render3DTakeWorld(a,a.worldMatrix)}let render3DSoftDotTexture;function render3DSoftDot(){if(render3DSoftDotTexture||!glContext||!canvasAvailable())return render3DSoftDotTexture;const a=createCanvasContext(32),b=a.createRadialGradient(16,16,0,16,16,16);for(const[c,d]of[[0,1],[.33,.9],[.67,.7],[1,0]])b.addColorStop(c,"rgba(255,255,255,"+d+")");a.fillStyle=b;a.fillRect(0,0,32,32);return render3DSoftDotTexture=new TextureInfo(a.canvas)}function normalMapFromHeight(a,b,c=1){const d=a.x|0;a=a.y|0;if(!canvasAvailable())return b=new TextureInfo(void 0,!1,!0),b.size=vec2(d,a),b.sizeInverse=vec2(1/d,1/a),b;const e=createCanvasContext(d,a);b=render3DNormalMapPixels(d,a,b,c);e.putImageData(new ImageData(b,d,a),0,0);return new TextureInfo(e.canvas,!0,!0)}function render3DNormalMapPixels(a,b,c,d){const e=new Float32Array(a*b),f=new Uint8ClampedArray(a*b*4);for(var g=0;g<b;++g)for(var h=0;h<a;++h)e[g*a+h]=c(h,g);c=(k,l)=>e[mod(l,b)*a+mod(k,a)];for(g=0;g<b;++g)for(h=0;h<a;++h){const k=(c(h+1,g)-c(h-1,g))/2*d,l=(c(h,g+1)-c(h,g-1))/2*d,m=1/hypot(k,l,1),n=4*(g*a+h);f[n]=round(255*(-k*m*.5+.5));f[n+1]=round(255*(l*m*.5+.5));f[n+2]=round(255*(.5*m+.5));f[n+3]=255}return f}function render3DBevelProfile(a,b,c,d,e){var f=[a[0]+b[0]*d,a[1]+b[1]*d];const g=[a[0]+c[0]*d,a[1]+c[1]*d];e=max(1,e|0);if(1===e)return[f,f,g,g];var h=Math.acos(clamp(b[0]*c[0]+b[1]*c[1],-1,1))/2,k=b[0]+c[0];b=b[1]+c[1];c=d/cos(h)/hypot(k,b);k=a[0]+k*c;a=a[1]+b*c;d*=tan(h);h=atan2(f[1]-a,f[0]-k);b=mod(atan2(g[1]-a,g[0]-k)-h+PI,2*PI)-PI;f=[f];for(c=1;c<e;++c){const l=h+b*c/e;f.push([k+cos(l)*d,a+sin(l)*d])}f.push(g);return f}function buildCylinder(a=1,b=1,c=16,d=render3D?.smoothShading,e=!0,f=0,g=1){a/=2;b/=2;f=min(f,a,b);return 0<f?buildLathe([...render3DBevelProfile([a,-b],[-1,0],[0,1],f,g),...render3DBevelProfile([a,b],[0,-1],[-1,0],f,g)],c,d,e):buildLathe([[a,-b],[a,b]],c,d,e)}function buildCone(a=1,b=1,c=16,d=render3D?.smoothShading,e=!0,f=0,g=1){a/=2;const h=b/2,k=hypot(a,b);f=min(f,a,k/2);return 0<f?buildLathe([...render3DBevelProfile([a,-h],[-1,0],[-a/k,b/k],f,g),[0,h]],c,d,e):buildLathe([[a,-h],[0,h]],c,d,e)}function buildCapsule(a=1,b=1,c=16,d=4,e=render3D?.smoothShading){const f=[],g=a/2;a=max(0,b-a)/2;for(b=0;b<=d;++b){var h=b/d*PI/2;f.push([g*sin(h),-a-g*cos(h)])}for(b=0;b<=d;++b)h=b/d*PI/2,f.push([g*cos(h),a+g*sin(h)]);return buildLathe(f,c,e)}function buildTorus(a=1,b=.3,c=16,d=8,e=render3D?.smoothShading){const f=[];a=(a-b)/2;b/=2;for(let g=0;g<=d;++g){const h=g/d*2*PI;f.push([a+b*cos(h),b*sin(h)])}return buildLathe(f,c,e)}function buildRibbon(a,b=1,c=WHITE,d=!1,e=vec3(0,1,0)){const f=new Mesh,g=a.length,h=[];var k=(.9>abs(e.y)?vec3(0,1,0):vec3(1,0,0)).cross(e).normalize();for(let m=0;m<g;++m){var l=a[d?(m+1)%g:min(m+1,g-1)];const n=a[d?(m+g-1)%g:max(m-1,0)];l=l.subtract(n).cross(e);1e-12<l.lengthSquared()&&(k=l.normalize());l=k.scale((isArray(b)?b[m]:b)/2);h.push([a[m].subtract(l),a[m].add(l)])}for(a=0;a+1<g+(d?1:0);++a)k=(a+1)%g,b=h[a],e=h[k],k=isArray(c)?[c[a],c[a],c[k],c[k]]:c,f.addQuad(b[0],b[1],e[1],e[0],k);f.doubleSided=!0;return f}function buildLoft(a){const b=new Mesh,c=([e,f,g,h,k=.5])=>[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+1<a.length;++d){const e=c(a[d]),f=c(a[d+1]);for(let g=0;4>g;++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<f;++a){const x=d[a]=[];for(let w=0;w<e;++w){const z=4*((y+a)*g.width+v+w);x.push(127<u[z+3]?rgb(u[z]/255,u[z+1]/255,u[z+2]/255):void 0)}}}else f=d.length,e=d[0].length;const h=(u,v)=>{if(!(0>u||0>v||u>=e||v>=f)&&(u=d[v]&&d[v][u]))return isColor(u)?.5<u.a?u:void 0:WHITE};g=(u,v,y)=>{let x=0,w;for(let A=0;A<=u;++A){const C=A<u?v(A):void 0;var z=w;C===z||C&&z&&C.rgbaInt()===z.rgbaInt()||(w&&y(x,A,w),x=A,w=C)}};const k=new Mesh,l=b.x/e,m=b.y/f,n=c/2,r=(u,v,y,x,w)=>k.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;u<f;++u)g(e,v=>h(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;u<e;++u)g(f,v=>h(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;q<l.length;++q){var n=textCharacterCode(l,q);if(n=32>n||127<n?95:n-32){var r=f.get(n);r||(r=d.getGlyphPos(n),f.set(n,r=buildExtrude(new TileInfo(r,e.size,e.textureInfo))));h.combine(r,buildMatrix(vec3((q-(l.length-1)/2)*g.x,m,0),void 0,vec3(g.x,g.y,c)))}}});return h}class HeightMap extends EngineObject3D{constructor(a,b=vec2(1),c=1,d,e=vec3(),f=render3D?.smoothShading){super(e);isArray(a)||(a=render3DImageToArray(a,g=>g/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&&0<e.x&&0<e.y)){f=a+hypot(e.x,e.y,f)/g;d.x&&(f=min(f,(sign(d.x)*e.x/2-c.x)/d.x));d.z&&(f=min(f,(sign(d.z)*e.y/2-c.z)/d.z));g=(c.x/e.x+.5)*(this.columns-1);var h=(this.columns-1)/e.x*d.x,k=(c.z/e.y+.5)*(this.rows-1),l=(this.rows-1)/e.y*d.z;e=[a,f];for(const[m,n]of[[g,h],[k,l],[g+k,h+l]])if(n)for(g=m+n*a,h=m+n*f,k=ceil(min(g,h));k<=max(g,h);++k)e.push((k-m)/n);e.sort((m,n)=>m-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(a.x,a.z)||(c=this.raycast(new Ray3D(a,b.subtract(a))),void 0===c||1<c||!c&&b.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;f<e;++f){const g=a[f]=[];for(let h=0;h<d;++h){const k=4*(f*d+h);g.push(b(c[k],c[k+1],c[k+2],c[k+3]))}}return a}const render3DGlyphCache=new WeakMap,render3DPixelCache=new WeakMap;function render3DReadPixels(a){a=a.image;let b=render3DPixelCache.get(a);b||render3DPixelCache.set(a,b=render3DImageData(a));return b}class CameraControl3D extends EngineObject3D{constructor(a=vec3(),b=10,c=.4,d=0){super(a);this.size3D=vec3();this.distance=b;this.pitch=c;this.idleSpin=d;this.dragButton=this.yaw=0;this.dragSpeed=.01;this.zoomSpeed=.1;this.zoomRange=vec2(b/4,3*b);this.pitchRange=vec2(min(-.2,c),max(1.4,c))}update(){mouseIsDown(this.dragButton)?(this.yaw-=mouseDeltaScreen.x*this.dragSpeed,this.pitch+=mouseDeltaScreen.y*this.dragSpeed):this.yaw+=this.idleSpin;this.pitch=clamp(this.pitch,this.pitchRange.x,this.pitchRange.y);this.zoomSpeed&&mouseWheel&&(this.distance=clamp(this.distance*(1+sign(mouseWheel)*this.zoomSpeed),this.zoomRange.x,this.zoomRange.y));render3D.camera.orbit(this.getWorldPos3D(),this.distance,this.yaw,this.pitch)}render3D(){}}class FirstPersonCamera3D extends EngineObject3D{constructor(a=render3D.camera.pos,b=render3D.camera.rotation.y,c=render3D.camera.rotation.x){super(a);this.size3D=vec3();this.mass=1;this.yaw=b;this.pitch=c;this.moveSpeed=.1;this.lookSpeed=.003;this.pitchRange=vec2(-1.5,1.5);this.fly=!1;this.lockPointer=!0;this.eyeHeight=this.jumpSpeed=0}updatePhysics(){const a=this.gravityScale;this.fly&&(this.gravityScale=0);super.updatePhysics();this.gravityScale=a}update(){this.lockPointer&&mouseWasPressed(0)&&pointerLockRequest();if(pointerLockIsActive()||mouseIsDown(0))this.yaw-=mouseDeltaScreen.x*this.lookSpeed,this.pitch-=mouseDeltaScreen.y*this.lookSpeed;this.pitch=clamp(this.pitch,this.pitchRange.x,this.pitchRange.y);var a=keyDirection();a=vec3(a.x,0,-a.y).clampLength(1).scale(this.moveSpeed).rotateX(this.fly?this.pitch:0).rotateY(this.yaw);this.velocity3D=this.fly?a:vec3(a.x,this.velocity3D.y,a.z);this.jumpSpeed&&!this.fly&&this.groundObject&&(keyWasPressed("Space")||gamepadWasPressed(0))&&(this.velocity3D.y=this.jumpSpeed);a=vec3(this.pitch,this.yaw,0);render3D.camera.pos=render3DObjectMatrix(this).transformPoint(vec3(0,this.eyeHeight,0));render3D.camera.rotation=this.parent instanceof EngineObject3D?this.parent.getMatrix().multiply(Matrix4.rotation(a)).getRotation():a}destroy(a){this.lockPointer&&pointerLockIsActive()&&pointerLockExit();super.destroy(a)}render3D(){}}const RENDER3D_PARTICLE_FLOATS=21,render3DParticlePos=vec3(),render3DParticleColor=new Color,render3DParticleSize=vec2(),render3DParticleFrom=vec3(),render3DParticleTo=vec3(),render3DParticlesCalling=new Set;function render3DParticleView(a){return{emitter:a,pos:vec3(),velocity:vec3(),age:0,lifeTime:0,scale:1,destroyed:!1,destroy(){this.destroyed=!0}}}class ParticleEmitter3D extends EngineObject3D{constructor(a=vec3(),b=0,c=0,d=100,e=PI,f,g=WHITE,h=WHITE,k=CLEAR_WHITE,l=CLEAR_WHITE,m=.5,n=.1,r=1,q=.1,p=1,t=0,u=.1,v=.2,y=!1){super(a,void 0,f);this.transparent=!0;this.castShadow=!1;this.size3D=vec3();this.emitSize=b;this.emitFlat=!1;this.emitTime=c;this.emitRate=d;this.emitConeAngle=e;this.colorStartA=g.copy();this.colorStartB=h.copy();this.colorEndA=k.copy();this.colorEndB=l.copy();this.particleTime=m;this.sizeStart=n;this.sizeEnd=r;this.speed=q;this.damping=p;this.gravity=t;this.gravityScale=0;this.fadeRate=u;this.randomness=v;this.additive=y;this.angleSpeed=this.trailTime=0;this.angleDamping=1;this.particleData=new Float32Array(64*RENDER3D_PARTICLE_FLOATS);this.particleCount=0;this.trailData=void 0;this.trailMax=0;this.collideLevel=!1;this.stick=0;this.particleDestroyCallback=this.particleCollideCallback=this.particleUpdateCallback=this.particleCreateCallback=void 0;this.particleView=render3DParticleView(this);this.worldPos3D=void 0;this.emitTimeBuffer=1;this.emitElapsed=0;this.emitFrom=void 0;this.emitBehind=0}update(){var a=render3DObjectMatrix(this);this.emitFrom=this.worldPos3D;this.worldPos3D=a.getTranslation();var b=render3DMaxScale(a.m);this.particleView.scale=b;if(!this.emitTime||this.emitElapsed<this.emitTime){a=this.emitRate*particleEmitRateScale;var c=this.emitTime?min(timeDelta,this.emitTime-this.emitElapsed):timeDelta;this.emitElapsed+=timeDelta;if(0<a&&Infinity>a){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<this.particleData.length;c+=RENDER3D_PARTICLE_FLOATS)this.particleData[c]=0;c=RENDER3D_PARTICLE_FLOATS;let e=this.particleData,f=this.trailData;d=()=>{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.particleCount||this.destroyed)return super.destroy(a);this.emitTime=-1;render3DDetach(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;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.distance<g.distance)){var g=c;var h=f}if(!g)return!1;f=b.lerp(e,g.distance);if((e=this.particleCollideCallback)&&(!this.particleCall(e,a,h,f.copy())||this.particleView.destroyed))return this.particleView.destroyed;e=this.particleData;g=g.normal;b=vec3(e[a+3],e[a+4],e[a+5]);c=g.scale(b.dot(g));d=max(this.restitution,h.restitution);h=max(this.friction,h.friction)*(1-clamp(this.stick));h=b.subtract(c).scale(h).subtract(c.scale(d));g=f.add(g.scale(.001));e[a]=g.x;e[a+1]=g.y;e[a+2]=g.z;e[a+3]=h.x;e[a+4]=h.y;e[a+5]=h.z;return!1}render3D(){const a=render3D;if(a.transparentQueue)return a.queueTransparent(this.getWorldPos3D(),()=>this.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;y<x;++y){var u=y*r;const w=q[u+17]/q[u+16];var v=w<b?w/b:w>1-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(1<C){const D=this.trailData;u=[];v=[];const B=[];for(let E=0;E<C;++E){const F=(E+1)/C,G=3*(y*p+E);u.push(vec3(D[G],D[G+1],D[G+2]));v.push(z*F);B.push(d.scale(1,F))}a.drawRibbon(u,v,this.tileInfo,B)}else if(g){const D=render3DBillboardAxes(e,A,!1),B=render3DInstanceSlot(f,k);h=f.instanceData;h[B]=2*D[0];h[B+1]=2*D[1];h[B+2]=2*D[2];h[B+3]=0;h[B+4]=2*D[3];h[B+5]=2*D[4];h[B+6]=2*D[5];h[B+7]=0;h[B+8]=n.x;h[B+9]=n.y;h[B+10]=n.z;h[B+11]=0;h[B+12]=q[u];h[B+13]=q[u+1];h[B+14]=q[u+2];h[B+15]=1;h[B+16]=d.r;h[B+17]=d.g;h[B+18]=d.b;h[B+19]=d.a;h[B+20]=l.x;h[B+21]=l.y;h[B+22]=l.w;h[B+23]=l.h}else t.x=q[u],t.y=q[u+1],t.z=q[u+2],c?a.drawBillboard(t,e,c,d,A):a.drawSoftDisc(t,z,d,void 0,8)}}finally{g&&(a.lighting=m,a.flush(),render3DFlushInstances(f))}}}class Trail3D extends EngineObject3D{constructor(a=vec3(),b=1,c=.2,d,e=WHITE,f=CLEAR_WHITE,g=!1){super(a,void 0,d,e);this.transparent=!0;this.additive=g;this.castShadow=!1;this.size3D=vec3();this.finishing=!1;this.lifeTime=b;this.width=c;this.colorEnd=f.copy();this.side=void 0;this.samples=[]}clear(){this.samples.length=0}destroy(a){if(a||!this.samples.length||this.destroyed||Infinity==this.lifeTime)return super.destroy(a);this.finishing=!0;render3DDetach(this)}update(){const a=this.samples;if(!this.finishing){const b=this.worldPos3D=this.getWorldPos3D(),c=a[a.length-1];(!c||1e-8<b.distanceSquared(c.pos))&&a.push({pos:b,side:this.side?.copy(),time:time})}for(;a.length&&time-a[0].time>this.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=0<b?[{at:0,size:.7*b,color:hsl(0,0,1,.5),shape:"glow"},{at:0,size:.25*b,color:hsl(0,0,1,.9),shape:"glow"}]:[];for(let h=0;h<this.count;++h){const k=(h+f.float(.2,.8))/max(this.count,1)*1.9+.2;var e=f.float();e=a?a[min(e*a.length|0,a.length-1)]:.5>e?"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<d){var e=this.color.multiply(render3D.sunColor),f=mainCanvasSize.y*this.flareSize,g=this.light;if(g){e=render3DLightCone(g);var h=a.direction;h=clamp(-(e[0]*h.x+e[1]*h.y+e[2]*h.z)-e[3]);e=g.color;h*=e.a*clamp(g.intensity);if(!(0<h))return;e=this.color.multiply(rgb(e.r,e.g,e.b,h));g.directional||(f*=min(1,g.radius/a.distance))}return 0<f?{sun:c,center:b,strength:d,tint:e,height:f}:void 0}}}getScreenPos(){const a=this.flareSource();return a&&render3D.worldToScreen(a.pos)}getScreenElements(){if(!this.visibleFound||paused)this.visibleFound=!1,this.updateVisible(0);const a=0<this.visible&&this.flareLook();if(!a)return[];const{sun:b,center:c,tint:d,height:e}=a,f=a.strength*this.visible;return this.getElements().map(g=>{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<this.fadeTime&&this.visibleFound?a/this.fadeTime:1;this.visible=clamp(this.visible+(b?a:-a));this.visibleFound=!0}render(){if(!headlessMode&&glEnable){var a=this.getScreenElements();if(a.length){setAdditiveBlendMode(!0);for(const b of a){a=b.tileInfo||render3DFlareTile(b.shape);const c="number"==typeof b.size?vec2(b.size):b.size;a&&drawTile(b.pos,c,a,b.color,b.angle,!1,void 0,!0,!0)}setAdditiveBlendMode(!1)}}}render3D(){}}function parseOBJ(a,b=render3D?.smoothShading){const c=[],d=[],e=[],f=[],g=[],h=[],k=[],l=new Map,m=[];let n=!1,r=0;const q=(t,u)=>{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;x<a.length;++x)k.push(a[1],a[x],a[(x+1)%a.length]);++r}const p=(new Mesh).addTriangles(f,k,g,h);if(n&&b){const t=p.normals;p.computeNormals(!0);m.forEach((u,v)=>u&&(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)(0<g.dot(b.plane.normal)?c:d).push(b);else if(1===l)e.push(b);else if(2===l)f.push(b);else{c=[];d=[];for(m=0;m<a.length;++m){var r=(m+1)%a.length;l=k[m];n=k[r];const q=a[m];r=a[r];2!==l&&c.push(q);1!==l&&d.push(q);3===(l|n)&&(l=q.lerp(r,(h-g.dot(q.pos))/g.dot(r.pos.subtract(q.pos))),c.push(l),d.push(l))}3<=c.length&&e.push(new Render3DCSGPolygon(c,b.plane));3<=d.length&&f.push(new Render3DCSGPolygon(d,b.plane))}}function render3DCSGNodes(a){const b=[];for(a=[a];a.length;){const c=a.pop();b.push(c);c.front&&a.push(c.front);c.back&&a.push(c.back)}return b}function render3DCSGBuild(a,b){for(a=[[a,b]];a.length;){const[c,d]=a.pop();if(!d.length)continue;let e;(e=c).plane||(e.plane=d[0].plane);b=[];const f=[];for(const k of d)render3DCSGSplit(c.plane,k,c.polygons,c.polygons,b,f);let g;b.length&&a.push([(g=c).front||(g.front=new Render3DCSGNode),b]);let h;f.length&&a.push([(h=c).back||(h.back=new Render3DCSGNode),f])}}function render3DCSGInvert(a){for(const b of render3DCSGNodes(a)){let c;(c=b).plane&&(c.plane={normal:b.plane.normal.scale(-1),w:-b.plane.w});[b.front,b.back]=[b.back,b.front]}}function render3DCSGClipPolygons(a,b){const c=[];for(a=[[a,b]];a.length;){const[d,e]=a.pop();if(!d.plane){for(const g of e)c.push(g);continue}b=[];const f=[];for(const g of e)render3DCSGSplit(d.plane,g,b,f,b,f);if(d.front)a.push([d.front,b]);else for(const g of b)c.push(g);d.back&&a.push([d.back,f])}return c}function render3DCSGNear(a,b){const c=vec3(Infinity),d=vec3(-Infinity);for(var e of b)for(var{pos:f}of e.vertices)c.x=min(c.x,f.x),c.y=min(c.y,f.y),c.z=min(c.z,f.z),d.x=max(d.x,f.x),d.y=max(d.y,f.y),d.z=max(d.z,f.z);b=[];e=[];f=[[vec3(1,0,0),d.x],[vec3(-1,0,0),-c.x],[vec3(0,1,0),d.y],[vec3(0,-1,0),-c.y],[vec3(0,0,1),d.z],[vec3(0,0,-1),-c.z]];const g=RENDER3D_CSG_EPSILON;for(const k of a){var h=a=Infinity;let l=Infinity,m=-Infinity,n=-Infinity,r=-Infinity;for(const{pos:q}of k.vertices)a=min(a,q.x),h=min(h,q.y),l=min(l,q.z),m=max(m,q.x),n=max(n,q.y),r=max(r,q.z);if(a>d.x+g||m<c.x-g||h>d.y+g||n<c.y-g||l>d.z+g||r<c.z-g)e.push(k);else{a=[k];for(const[q,p]of f){h=[];for(const t of a)render3DCSGSplit({normal:q,w:p},t,h,h,e,h);a=h}for(const q of a)b.push(q)}}return[b,e]}function render3DCSGPlacer(a){const b=new Map;return c=>{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)<a**2)return l;d=d+","+e+","+f;b.has(d)||b.set(d,[]);b.get(d).push(c);return c}}function render3DMeshIsClosed(a){const b=a.points;a=a.indices;let c=0,d=0,e=0,f=0;for(let h=0;h<a.length;h+=3){var g=b[a[h]];g=b[a[h+1]].subtract(g).cross(b[a[h+2]].subtract(g));c+=g.x;d+=g.y;e+=g.z;f+=g.length()}return 0<f&&hypot(c,d,e)<=1e-4*f}function render3DCSGPolygons(a,b){const c=(new Mesh).combine(a,b).toIndexed();a=d=>new Render3DCSGVertex(c.points[d],c.normals[d],c.uvs[d],c.colors[d]);b=[];for(let d=0;d<c.indices.length;d+=3){const e=c.indices[d],f=c.indices[d+1],g=c.indices[d+2],h=render3DCSGPlane(c.points[e],c.points[f],c.points[g]);h&&b.push(new Render3DCSGPolygon([a(e),a(f),a(g)],h))}return b}function render3DCSGMesh(a){const b=4*RENDER3D_CSG_EPSILON,c=render3DCSGPlacer(RENDER3D_CSG_EPSILON),d=new Set;a=a.map(p=>{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<t.length&&t[0].pos===t[t.length-1].pos&&t.pop();return t});var e=[...d];let f=vec3(Infinity);var g=vec3(-Infinity);for(var h of e)f=vec3(min(f.x,h.x),min(f.y,h.y),min(f.z,h.z)),g=vec3(max(g.x,h.x),max(g.y,h.y),max(g.z,h.z));h=e.length?max(g.x-f.x,g.y-f.y,g.z-f.z):0;const k=max(h/Math.cbrt(e.length||1),b),l=new Map;h=p=>{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**2&&u.push([G,F])}return u.sort((B,E)=>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;e<p.length;++e){h=p[e];g=p[(e+1)%p.length];a.push(h);for(const[y,x]of m(h.pos,g.pos)){const w=h.lerp(g,y);a.push(new Render3DCSGVertex(x,w.normal,w.uv,w.color))}}e=a.length;let t=vec3();for(h=1;h<e-1;++h)t=t.add(a[h%e].pos.subtract(a[0%e].pos).cross(a[(h+1)%e].pos.subtract(a[0%e].pos)));if(1e-18>t.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<u.length;)a=u.findIndex((y,x)=>{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(;h<c;++h)for(let D=g;D<k;++D)for(let B=f;B<b;++B){const E=e[B+d.x*(D+d.y*h)];if(!E)continue;const F=this.blockType(E),G=F.transparent?n:m,H=B+.5-l.x,J=D+.5-l.y,M=h+.5-l.z;for(let L=0;6>L;++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=>0<r?ceil(u+q-p-1e-9)-1:floor(u-q-p+1e-9);g=k(b[m]);k=k(d[m]);h=min(g,k)+(0<r?1:0);l=max(g,k)-(0<r?0:1);var n=b.copy();const t=c.copy();n[m]=p+(h+l+1)/2;t[m]=l-h+1;g!==k&&this.boxBlocked(n,t,a)?("y"===m&&0>r&&(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]+(0<r?1:0)-q[n])/r:Infinity,l[m]=r?abs(1/r):Infinity;q=t=>vec3(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]<h[1]?h[0]<h[2]?0:2:h[1]<h[2]?1:2;g=h[f];e[f]+=p[f];if(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;d<a.length;++d){const e=a[d],f=this.chunkCenters[d];e&&render3D.drawMesh(e,vec3(b.x+f.x,b.y+f.y,b.z+f.z),c,this.color)}}destroy(a){render3DLevelLeave(this);for(const b of[...this.chunkMeshes,...this.chunkTransparentMeshes])b?.dispose();super.destroy(a)}}const LEVEL3D_VERSION=1,level3DTypes=new Map,level3DBaseScale=new WeakMap;function level3DAddType(a,b,c={},d){level3DTypes.set(String(a),{make:b,defaults:c,tileInfo:d})}function level3DAddMesh(a,b,c,d=WHITE){level3DAddType(a,function(e,f){return level3DMakeShape(e,f,b,c)},{color:d,solid:!1},c)}function level3DLoad(a){editor3DLevelLoaded(a);level3DPrefabsAdd(a.prefabs);level3DSceneApply(a.scene);const b=[];var c=level3DVoxelMap=level3DVoxelsMake(a.voxels);c&&b.push(c);(c=level3DTerrainMap=level3DTerrainMake(a.terrain))&&b.push(c);for(const d of isArray(a.objects)?a.objects:[])d&&"object"===typeof d&&(a=level3DMake(d),editor3DObjectMade(d,a),a&&b.push(a));return b}let level3DVoxelTiles,level3DVoxelSetupMap,level3DVoxelMap;function level3DVoxelSetup(a,b){level3DVoxelTiles=a;level3DVoxelSetupMap=b}const LEVEL3D_VOXEL_CELLS=2**24;function level3DVoxelsEncode(a){const b=[];for(let c=0;c<a.length;){let d=c+1;for(;d<a.length&&a[d]===a[c];)++d;b.push(d-c,a[c]);c=d}return b}function level3DVoxelsDecode(a,b){b.fill(0);if(isArray(a))for(let d=0,e=0;d+1<a.length&&e<b.length;d+=2){var c=a[d];const f=a[d+1];if(!isNumber(c)||!isNumber(f)||0>c)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)&&0<f)&&!(!isArray(c)||2>c.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<a.height?a.height:1,heights:c}}}}function level3DHexColor(a){return"string"===typeof a&&/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.test(a)?(new Color).setHex(a):void 0}const level3DFinite=a=>"number"===typeof a&&isFinite(a);function level3DTerrainPaint(a,b){var c=a?.paint;a=c?.colors;c=c?.cells;if(isArray(a)&&isArray(c)&&!(255<a.length)&&a.every(level3DHexColor)){var d=new Uint8Array(b),e=0;for(let f=0;f<c.length;f+=2){const g=c[f],h=c[f+1];if(!(0<g&&0===g%1&&0<=h&&0===h%1)||h>a.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<level3DPrefabAttached;this.parts=[];this.originOffset=vec3();this.partObjects=[];this.partsPlaced="";this.partsMade=!1}placeAt(a){this.pos3D=a.copy();this.placeParts();const b=this.originOffset;if(b.x||b.y||b.z)this.pos3D=buildMatrix(a,this.rotation3D,this.scale3D).transformPoint(b)}placeParts(){this.destroyed||(this.partsMade||(this.partsMade=(this.makeParts(),!0)),this.partsPlaced=this.placeKey(),this.attached||this.parts.forEach((a,b)=>{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$89=particleEffectBehavior;b$jscomp$89("wobble").update=(a,b)=>{a.velocity.x+=.003*b*a.scale*sin(6*time+97*a.lifeTime%9)};b$jscomp$89("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$89("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$89("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$89("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$89("wind").update=(a,b)=>a.velocity.x+=.004*b*a.scale*min((time-a.spawnTime)/a.lifeTime,1);b$jscomp$89("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.tileIndex<floor(b.size.x/c)*floor(b.size.y/c))return tile(a.tileIndex,a.tileSize,0,a.tilePadding)}}function particleEffectApply(a,b){particleEffectSet(a,particleEffectSanitize(b))}function particleEffectSet(a,b){const c=b.settings,d=0>a.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(var c in b);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$91=particleEffectBehavior,center$jscomp$24=a=>a.emitter.worldPos3D||a.emitter.pos3D;b$jscomp$91("wobble").update3D=(a,b)=>a.velocity.x+=.003*b*a.scale*sin(6*time+97*a.lifeTime%9);b$jscomp$91("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$91("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$91("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$91("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$91("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(0<d&&a===this.animation&&this.animationPlaying)this.animationLoop=b,this.animationSpeed=c;else{var e=this.blendFrom;this.blendFrom=void 0;0<d&&(this.blendFrom=(!this.animation||e||this.poseMixed?void 0:{animation:this.animation,time:this.animationTime,speed:this.animationPlaying?this.animationSpeed:0,loop:this.animationLoop})||{nodes:this.poseNodes||new Map},this.blendTime=d,this.blendElapsed=0);this.animation=a;this.animationLoop=b;this.animationSpeed=c;this.animationPlaying=!0;this.setAnimationTime(0>c?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.length&&e<d.length;++e){const f=d[e],g=a[e],h=b.parts[e].skin;f.destroyed||f.parent!==this||(h?gltfSkinApply(h,c,b.modelMatrix,f.mesh):(f.localMatrix=g,f.pos3D=g.getTranslation(),f.rotation3D=g.getRotation(),f.scale3D=g.getScale()))}}}update(){super.update();const a=this.animation,b=this.blendFrom;if(a&&(this.animationPlaying||b)){var c=this.animationTime;this.animationPlaying&&(c=gltfAnimationStep(a,c,this.animationSpeed,this.animationLoop),!this.animationLoop&&(c>=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;p<h;++p){var n=e.vertexSource?e.vertexSource[p]:p,r=[];for(const[t,u]of d)for(var q=0;4>q;++q)r.push([t[4*n+q],u[4*n+q]]);1<d.length&&r.sort((t,u)=>u[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]=t<f.length?t:0;b[4*p+q]=n?u/n:q?0:1}r=g.points[p];n=g.normals[p];l.set([r.x,r.y,r.z],3*p);m.set([n.x,n.y,n.z],3*p);g.points[p]=r.copy();g.normals[p]=n.copy()}return{joints:f,inverseBind:c,vertexJoints:a,vertexWeights:b,bindPoints:l,bindNormals:m}}function gltfSkinMeshCopy(a){const b=new Mesh;b.points=a.points.map(c=>c.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;k<e;++k){g.m.set(c.m);g.multiply(b(a.joints[k])).multiply(a.inverseBind[k]);h.m.set(g.m);h.invert().transpose();var l=g.m,m=h.m,n=21*k;f[n]=l[0];f[n+1]=l[1];f[n+2]=l[2];f[n+3]=l[4];f[n+4]=l[5];f[n+5]=l[6];f[n+6]=l[8];f[n+7]=l[9];f[n+8]=l[10];f[n+9]=l[12];f[n+10]=l[13];f[n+11]=l[14];f[n+12]=m[0];f[n+13]=m[1];f[n+14]=m[2];f[n+15]=m[4];f[n+16]=m[5];f[n+17]=m[6];f[n+18]=m[8];f[n+19]=m[9];f[n+20]=m[10]}const{vertexJoints:r,vertexWeights:q,bindPoints:p,bindNormals:t}=a;a=d.points;b=d.normals;e=d.vertexLayout;c=a.length;e=e&&d.indices&&e.pointCount===c?new Float32Array(e.data):void 0;g=0;l=k=h=Infinity;let u=n=m=-Infinity;for(let A=0;A<c;++A){var v=3*A,y=4*A,x=p[v],w=p[v+1];const C=p[v+2],D=t[v],B=t[v+1],E=t[v+2];let F=v=0,G=0;var z=0;let H=0,J=0;for(let M=0;4>M;++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<e.length;b+=4)e[b]=255;a.close();return createImageBitmap(new ImageData(e,c,d))}function gltfSample(a,b,c){const{times:d,values:e,components:f,interpolation:g}=a;var h=d.length-1,k="CUBICSPLINE"===g,l=k?3*f:f,m=k?f:0;a=0;for(var n=h;a<n;){var r=a+n+1>>1;d[r]<=b?a=r:n=r-1}if(a>=h||b<=d[0]||"STEP"===g)for(b=0;b<f;++b)c[b]=e[a*l+m+b];else{m=d[a+1]-d[a];b=(b-d[a])/m;a*=l;l=a+l;if(k)for(n=b*b,r=n*b,k=2*r-3*n+1,b=r-2*n+b,h=-2*r+3*n,n=r-n,r=0;r<f;++r)c[r]=k*e[a+f+r]+b*m*e[a+2*f+r]+h*e[l+f+r]+n*m*e[l+r];else if(4===f){h=0;for(m=0;4>m;++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;m<f;++m)c[m]=e[a+m]+(e[l+m]-e[a+m])*b;if(4===f)for(a=hypot(c[0],c[1],c[2],c[3])||1,l=0;4>l;++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<b.length;++d)c[d]=b.charCodeAt(d);return Promise.resolve(new Response(c.buffer,{headers:{"Content-Type":a.slice(5,a.indexOf(";"))}}))}const e=(c=(c="undefined"!==typeof location&&location.href)?new URL(b,c):/^[a-z][a-z0-9+.-]*:/i.test(b)?b:void 0)?new URL(a,c).href:b+a;return loadFetch(e,"glTF").then(f=>{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;q<d.count;++q)m.set(new h(r,e+q*n,f),q*f)}if(n=d.sparse){const{indices:p,values:t}=n;g=g[p.componentType];e=a.bufferViews?.[p.bufferView];a=a.bufferViews?.[t.bufferView];if(!g||!e||!a)throw Error("glTF sparse accessor is missing its indices or values");r=(e.byteOffset||0)+(p.byteOffset||0);q=(a.byteOffset||0)+(t.byteOffset||0);if(r%g.BYTES_PER_ELEMENT||q%k||!(r+n.count*g.BYTES_PER_ELEMENT<=(b[e.buffer]?.byteLength??0))||!(q+n.count*f*k<=(b[a.buffer]?.byteLength??0)))throw Error("glTF sparse accessor "+c+" is not aligned or reaches past its buffer");c=new g(b[e.buffer],(e.byteOffset||0)+(p.byteOffset||0),n.count);b=new h(b[a.buffer],(a.byteOffset||0)+(t.byteOffset||0),n.count*f);for(h=0;h<n.count;++h)m.set(b.subarray(h*f,(h+1)*f),c[h]*f)}if(1!==l)for(b=0;b<m.length;++b)m[b]=max(m[b]/l,-1);return{data:m,components:f,count:d.count}}function gltfPart(a,b,c,d,e,f){var g=d.mode??4;if(!(4>g)){var h=d.attributes,k=(B,E)=>{const{data:F,components:G,count:H}=gltfAccessor(a,b,B);B=[];for(let J=0;J<H;++J)B.push(E(F,J*G,G));return B},l=k(h.POSITION,(B,E)=>vec3(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]),3<F?B[E+3]:1)):void 0;d=void 0!==d.indices?Array.from(gltfAccessor(a,b,d.indices).data):l.map((B,E)=>E);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<d);f.pixelated=9728===a.samplers?.[e?.sampler]?.magFilter;f.vertexSource=g;f.unlit=!!n.extensions?.KHR_materials_unlit;e=n.normalTexture;q=n.emissiveTexture;f.normalMap=e&&c[e.index];f.normalScale=e?.scale??1;f.roughness=r.roughnessFactor??1;var[A,C,D]=n.emissiveFactor||[0,0,0];if(A||C||D)n=n.extensions?.KHR_materials_emissive_strength?.emissiveStrength??1,f.emissiveMap=q?c[q.index]:gltfWhiteTexture(),f.emissiveMapColor=rgb(gltfSRGB(A)*n,gltfSRGB(C)*n,gltfSRGB(D)*n);return f}}let gltfWhiteTextureInfo;function gltfWhiteTexture(){if(gltfWhiteTextureInfo||!glContext||!canvasAvailable())return gltfWhiteTextureInfo;const a=createCanvasContext(1);a.fillStyle="#fff";a.fillRect(0,0,1,1);return gltfWhiteTextureInfo=new TextureInfo(a.canvas)}function gltfSRGB(a){return.0031308>=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))}}
|