-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcanvas.min.js
11 lines (11 loc) · 48.6 KB
/
canvas.min.js
1
2
3
4
5
6
7
8
9
10
11
/**
* @copyright Copyright (C) 2019 - 2024 Dorian Thivolle All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE.txt
* @author Dorian Thivolle
* @name canvas
* @package NoxFly/canvas
* @see https://github.com/NoxFly/canvas
* @since 30 Dec 2019
* @version {1.6.10}
*/
let ctx=null,canvas=null,width=0,height=0,mouseX=0,mouseY=0,fps=60,dragPoint=null;var pixels=void 0;const documentWidth=()=>document.documentElement.clientWidth,documentHeight=()=>document.documentElement.clientHeight;let MIN_DOC_SIZE;const PI=Math.PI,isDevice=Object.freeze({mobile:/iPhone|iPad|iPod|Android/i.test(navigator.userAgent),ios:/iPad|iPhone|iPod/.test(navigator.userAgent),android:/Android/.test(navigator.userAgent)}),mouseDirection={x:0,y:0},moveTo=(x,y)=>ctx.moveTo(x,y),lineTo=(x,y)=>ctx.lineTo(x,y),arcTo=(x1,y1,x2,y2,r)=>ctx.arcTo(x1,y1,x2,y2,r),line=(x1,y1,x2,y2)=>{beginPath(),moveTo(x1-NOX_PV.offsetLineBlur,y1-NOX_PV.offsetLineBlur),lineTo(x2-NOX_PV.offsetLineBlur,y2-NOX_PV.offsetLineBlur),closePath(),NOX_PV.bStroke&&ctx.stroke()},polyline=(...values)=>{if(values.length%2!=0)throw new Error("The function polyline must take an even number of values");beginPath(),values.length>0&&moveTo(values[0],values[1]);for(let i=2;i<values.length;i+=2){const x=values[i],y=values[i+1];lineTo(x,y)}NOX_PV.bStroke&&ctx.stroke(),NOX_PV.bFill&&ctx.fill()},arc=(x,y,r,start,end,antiClockwise=!1)=>{beginPath(),ctx.arc(x,y,r,start,end,antiClockwise),closePath(),NOX_PV.bStroke&&ctx.stroke(),NOX_PV.bFill&&ctx.fill()},circle=(x,y,r)=>{arc(x,y,r,0,2*PI)},fillRect=(x,y,w,h)=>{ctx.fillRect(x,y,w,h)},strokeRect=(x,y,w,h)=>{ctx.strokeRect(x,y,w,h)},rect=(x,y,w,h)=>{ctx.rect(x,y,w,h),NOX_PV.bFill&&ctx.fill(),NOX_PV.bStroke&&ctx.stroke()},roundRect=(x=0,y=0,w=0,h=0,radius=0,radiusTR,radiusBR,radiusBL)=>{void 0===radiusTR&&(radiusTR=radius),void 0===radiusBR&&(radiusBR=radius),void 0===radiusBL&&(radiusBL=radius);const x1=x+(radius=min(max(0,radius),50)),y1=y,x2=x+w-(radiusTR=min(max(0,radiusTR),50)),y2=y,x3=x+w,y3=y+h-(radiusBR=min(max(0,radiusBR),50)),x4=x+(radiusBL=min(max(0,radiusBL),50)),y4=y+h,x5=x,y5=y+radius;beginPath(),moveTo(x1,y1),lineTo(x2,y2),arcTo(x2+radiusTR,y2,x2+radiusTR,y2+radiusTR,radiusTR),lineTo(x3,y3),arcTo(x3,y3+radiusBR,x3-radiusBR,y3+radiusBR,radiusBR),lineTo(x4,y4),arcTo(x4-radiusBL,y4,x,y4-radiusBL,radiusBL),lineTo(x5,y5),arcTo(x5,y5-radius,x1,y1,radius),closePath(),NOX_PV.bStroke&&ctx.stroke(),NOX_PV.bFill&&ctx.fill()},path=p=>{if(!(p=p.trim()).startsWith("M"))return;p=p.split(" ");let mode="M";const modes={M:{n:2,f:(x,y)=>moveTo(x,y)},L:{n:2,f:(x,y)=>lineTo(x,y)},H:{n:1,f:(x,y)=>lineTo(x,y)},V:{n:1,f:(y,x)=>lineTo(x,y)},A:{n:6,f:(x,y,r,start,end,antiClockwise)=>ctx.arc(x,y,r,radian(start),radian(end),1===antiClockwise)},Z:{n:0,f:()=>lineTo(parseFloat(p[1]),parseFloat(p[2]))}},reg=new RegExp(`^[${Object.keys(modes).join("")}]|(-?d+(.d+)?)$`,"i");if(0===p.filter(point=>reg.test(point)).length)return;if(p.length<3)return;const d=[],lastIdx=p.length-1;for(let i=0;i<p.length;i++){const point=p[i];if(/[a-z]/i.test(point)){if(mode=point,"Z"===mode){if(i!==lastIdx)return;d.push("Z")}if(["z"].includes(mode))return;const nArg=modes[mode.toUpperCase()].n;if(lastIdx-nArg<i)return;const lastPos={x:0,y:0};if(d.length>0){const prev=d[d.length-1],hv=["H","V"].indexOf(prev[0]);if(-1!==hv)lastPos.x=prev[1+hv],lastPos.y=prev[2-hv];else{const k=1;lastPos.x=prev[k],lastPos.y=prev[k+1]}}const arr=[mode.toUpperCase()],hv=["H","V"].indexOf(arr[0]);for(let j=0;j<nArg;j++){i++;const n=parseFloat(p[i]);if(isNaN(n))return;arr.push(n)}if(-1!==hv&&arr.push(lastPos[Object.keys(lastPos)[1-hv]]),"A"===arr[0]&&(arr[1]-=arr[3]),/[mlhva]/.test(mode)&&("v"===mode?arr[1]+=lastPos.y:"h"===mode?arr[1]+=lastPos.x:(arr[1]+=lastPos.x,arr[2]+=lastPos.y)),d.push(arr),"A"===arr[0]){const angle=radian(arr[5]),x=arr[1]+cos(angle)*arr[3];y=arr[2]+sin(angle)*arr[3],d.push(["M",x,y])}}}beginPath(),d.forEach(step=>{"string"==typeof step?modes[step].f():modes[step[0]].f(...step.slice(1))}),NOX_PV.bFill&&ctx.fill(),NOX_PV.bStroke&&ctx.stroke()},text=(txt,x=0,y=0)=>{if(/\n/.test(txt)){const size=parseInt(NOX_PV.fontSize.replace(/(\d+)(\w+)?/,"$1"));txt=txt.split("\n");for(let i=0;i<txt.length;i++)ctx.fillText(txt[i],x,y+i*size)}else ctx.fillText(txt,x,y)},setFont=(size,font)=>{ctx.font=`${size}px ${font}`,NOX_PV.fontSize=`${size}px`,NOX_PV.fontFamily=font},fontSize=size=>{ctx.font=`${size}px ${NOX_PV.fontFamily}`,NOX_PV.fontSize=`${size}px`},fontFamily=font=>{ctx.font=`${NOX_PV.fontSize} ${font}`,NOX_PV.fontFamily=font},alignText=alignment=>{ctx.textAlign=["left","right","center","start","end"].indexOf(alignment)>-1?alignment:"left"},bezierCurveTo=(cp1x,cp1y,cp2x,cp2y,x,y)=>{ctx.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)},quadraticCurveTo=(cpx,cpy,x,y)=>{ctx.quadraticCurveTo(cpx,cpy,x,y)},setShadow=(shadowColor,shadowBlur=0,shadowOffsetX=0,shadowOffsetY=0)=>{ctx.shadowColor=NOX_PV.colorTreatment(shadowColor),ctx.shadowBlur=shadowBlur,ctx.shadowOffsetX=shadowOffsetX,ctx.shadowOffsetY=shadowOffsetY},removeShadow=()=>{ctx.shadowColor="rgba(0, 0, 0, 0)",ctx.shadowBlur=0,ctx.shadowOffsetX=0,ctx.shadowOffsetY=0},push=()=>ctx.save(),pop=()=>ctx.restore(),translate=(x,y)=>ctx.translate(x,y),rotate=degree=>ctx.rotate(radian(-degree)),clip=(...args)=>ctx.clip(...args),scale=(x,y=x)=>ctx.scale(x,y),noFill=()=>{NOX_PV.bFill=!1},noStroke=()=>{NOX_PV.bStroke=!1},background=(...color)=>{canvas.style.backgroundColor=NOX_PV.colorTreatment(...color)},stroke=(...color)=>{ctx.strokeStyle=NOX_PV.colorTreatment(...color),NOX_PV.bStroke=!0},strokeWeight=weight=>{ctx.lineWidth=weight,NOX_PV.offsetLineBlur=weight%2==0?0:.5},linecap=style=>{ctx.lineCap=["butt","round","square"].indexOf(style)>-1?style:"butt"},fill=(...color)=>{ctx.fillStyle=NOX_PV.colorTreatment(...color),NOX_PV.bFill=!0},createLinearGradient=(x1,y1,x2,y2)=>ctx.createLinearGradient(x1,y1,x2,y2),makeLinearGradient=(x1,y1,x2,y2,...params)=>{if(params.length%2!=0)throw new Error("you have to tell params by pair (offset, color). Odd number of arguments given.");const grad=createLinearGradient(x1,y1,x2,y2);for(let i=0;i<params.length;i+=2){const offset=params[i],color=NOX_PV.colorTreatment(params[i+1]);grad.addColorStop(offset,color)}return grad},clearRect=(x,y,w,h)=>ctx.clearRect(x,y,w,h),beginPath=()=>ctx.beginPath(),closePath=()=>ctx.closePath(),drawFocusIfNeeded=(elementOrPath2D,element=null)=>{null!==element||elementOrPath2D instanceof Path2D?ctx.drawFocusIfNeeded(elementOrPath2D,element):ctx.drawFocusIfNeeded(elementOrPath2D)},setLineDash=array=>{if(!Array.isArray(array))throw new Error("Array type expected. Got "+typeof array);ctx.setLineDash(array)},getLineDash=()=>ctx.getLineDash(),globalAlpha=globalAlpha=>{ctx.globalAlpha=globalAlpha},globalCompositeOperation=type=>{ctx.globalCompositeOperation=type},setSmoothingQuality=quality=>{ctx.imageSmoothingQuality=quality},isPointInPath=function(x,y,fillRule="nonzero"){return ctx.isPointInPath(...arguments)},isPointInStroke=function(x,y){return ctx.isPointInStroke(...arguments)},getTransform=()=>ctx.getTransform(),lineDashOffset=(value=0)=>{ctx.lineDashOffset=value},lineJoin=type=>{ctx.lineJoin=type},measureText=text=>ctx.measureText(text),resetTransform=()=>ctx.resetTransform(),setTransform=(...transform)=>ctx.setTransform(...transform),createPattern=(image,repetition="repeat")=>{ctx.createPattern(image,repetition)},createImageData=function(widthOrImageData,height=null){return ctx.createImageData(...arguments)},putImageData=(imageData,dx,dy,dirtyX=null,dirtyY=null,dirtyWidth=null,dirtyHeight=null)=>{null===dirtyX?ctx.putImageData(imageData,dx,dy):ctx.putImageData(imageData,dx,dy,dirtyX,dirtyY,dirtyWidth,dirtyHeight)},getImageData=(sx,sy,sw,sh)=>ctx.getImageData(sx,sy,sw,sh),drawImage=(image,sx,sy,sWidth=null,sHeight=null,dx=null,dy=null,dWidth=null,dHeight=null)=>{null===sWidth?ctx.drawImage(image,sx,sy):null===dx?ctx.drawImage(image,sx,sy,sWidth,sHeight):ctx.drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight)},radian=deg=>deg*(PI/180),degree=rad=>rad*(180/PI),angleToVector=angle=>{const r=radian(angle);return new Vector(cos(r),sin(r))},vectorToAngle=vec=>{const baseVector=new Vector(1,0);let angle=angleBetweenVectors(baseVector,vec);return vec.y>0&&(angle*=-1),degree(angle)},angleBetweenVectors=(a,b)=>{const ab=a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w,cosO=ab/(a.mag*b.mag)||1,O=acos(cosO);return O},dist=(a,b)=>{const x=b.x-a.x,y=b.y-a.y,z=b.z-a.z;return sqrt(x*x+y*y+z*z)},mag=(a,b)=>new Vector(b.x-a.x,b.y-a.y),map=(arrayOrValue,start1,end1,start2,end2)=>{const m=val=>(val-start1)*(end2-start2)/(end1-start1)+start2;return"number"==typeof arrayOrValue?m(arrayOrValue):arrayOrValue.map(val=>m(val))},pow=(n,p=2)=>Math.pow(n,p),abs=n=>n>=0?n:-n,sqrt=n=>Math.sqrt(n),min=(...values)=>Math.min(...values),max=(...values)=>Math.max(...values),clamp=(a,b,c)=>max(a,min(b,c)),round=n=>Math.round(n),floor=n=>Math.floor(n),ceil=n=>Math.ceil(n),trunc=n=>Math.trunc(n),random=(iMin=null,iMax=0)=>null===iMin?Math.random():floor(random()*(max(iMin,iMax)-min(iMin,iMax)+1))+min(iMin,iMax),sin=x=>Math.sin(x),cos=x=>Math.cos(x),tan=x=>Math.tan(x),asin=x=>Math.asin(x),acos=x=>Math.acos(x),atan=x=>Math.atan(x),atan2=(x,y)=>Math.atan2(y,x),sinh=x=>Math.sinh(x),cosh=x=>Math.cosh(x),exp=x=>Math.exp(x),log=x=>Math.log(x),log10=x=>Math.log10(x),sum=(...values)=>values.reduce((a,b)=>a+b),mean=(...values)=>sum(...values)/values.length,median=(...values)=>{if(0===values.length)return 0;values.sort((a,b)=>a-b);const half=floor(values.length/2);return values.length%2?values[half]:(values[half-1]+values[half])/2},mode=(...values)=>values.reduce((a,b,i,arr)=>arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b,null),variance=(...values)=>values.reduce((a,b)=>a+pow(b-mean(...values)),0),std=(...values)=>sqrt(variance(...values)),easeLinear=(t,b,c,d)=>c*t/d+b,easeInQuad=(t,b,c,d)=>c*(t/=d)*t+b,easeOutQuad=(t,b,c,d)=>-c*(t/=d)*(t-2)+b,easeInOutQuad=(t,b,c,d)=>(t/=d/2)<1?c/2*t*t+b:-c/2*(--t*(t-2)-1)+b,easeInSine=(t,b,c,d)=>-c*cos(t/d*(PI/2))+c+b,easeOutSine=(t,b,c,d)=>c*sin(t/d*(PI/2))+b,easeInOutSine=(t,b,c,d)=>-c/2*(cos(PI*t/d)-1)+b,easeInExpo=(t,b,c,d)=>0===t?b:c*pow(2,10*(t/d-1))+b,easeOutExpo=(t,b,c,d)=>t===d?b+c:c*(1-pow(2,-10*t/d))+b,easeInOutExpo=(t,b,c,d)=>0===t?b:t===d?b+c:(t/=d/2)<1?c/2*pow(2,10*(t-1))+b:c/2*(2-pow(2,-10*--t))+b,easeInCirc=(t,b,c,d)=>-c*(sqrt(1-(t/=d)*t)-1)+b,easeOutCirc=(t,b,c,d)=>c*sqrt(1-(t=t/d-1)*t)+b,easeInOutCirc=(t,b,c,d)=>(t/=d/2)<1?-c/2*(sqrt(1-t*t)-1)+b:c/2*(sqrt(1-(t-=2)*t)+1)+b,easeInCubic=(t,b,c,d)=>c*(t/=d)*t*t+b,easeOutCubic=(t,b,c,d)=>c*((t=t/d-1)*t*t+1)+b,easeInOutCubic=(t,b,c,d)=>(t/=d/2)<1?c/2*t*t*t+b:c/2*((t-=2)*t*t+2)+b,easeInQuart=(t,b,c,d)=>c*(t/=d)*t*t*t+b,easeOutQuart=(t,b,c,d)=>-c*((t=t/d-1)*t*t*t-1)+b,easeInOutQuart=(t,b,c,d)=>(t/=d/2)<1?c/2*t*t*t*t+b:-c/2*((t-=2)*t*t*t-2)+b,easeInQuint=(t,b,c,d)=>c*(t/=d)*t*t*t*t+b,easeOutQuint=(t,b,c,d)=>c*((t=t/d-1)*t*t*t*t+1)+b,easeInOutQuint=(t,b,c,d)=>(t/=d/2)<1?c/2*t*t*t*t*t+b:c/2*((t-=2)*t*t*t*t+2)+b,easeInBack=(t,b,c,d)=>c*(t/=d)*t*(2.7*t-1.7)+b,easeOutBack=(t,b,c,d)=>c*((t=t/d-1)*t*(2.7*t+1.7)+1)+b,easeInOutBack=(t,b,c,d)=>(t/=d/2)<1?c/2*(t*t*(3.5925*t-1.7))+b:c/2*((t-=2)*t*(3.5925*t+1.7)+2)+b,easeInElastic=(t,b,c,d)=>NOX_PV.easeElastic("in",t,b,c,d),easeOutElastic=(t,b,c,d)=>NOX_PV.easeElastic("out",t,b,c,d),easeInOutElastic=(t,b,c,d)=>NOX_PV.easeElastic("inout",t,b,c,d),lerp=(v,t,p)=>v instanceof Vector&&t instanceof Vector?(v.x=lerp(v.x,t.x,p),v.y=lerp(v.y,t.y,p),v):"number"==typeof v&&"number"==typeof t?v+(t-v)*p:0,frameRate=f=>{f>=0&&(NOX_PV.interval=1e3/f)},getSwipe=()=>NOX_PV.lastSwipe,getSecondsPassed=()=>NOX_PV.timer.asSeconds(),getMSPassed=()=>NOX_PV.timer.asMilliseconds(),isKeyDown=key=>NOX_PV.keys[key],isKeyUp=key=>!NOX_PV.keys[key],mouseDir=()=>NOX_PV.isPointerLocked?mouseDirection:mouseX>NOX_PV.oldMouseX&&mouseY>NOX_PV.oldMouseY?"BOTTOM_RIGHT":mouseX>NOX_PV.oldMouseX&&mouseY<NOX_PV.oldMouseY?"TOP_RIGHT":mouseX<NOX_PV.oldMouseX&&mouseY<NOX_PV.oldMouseY?"TOP_LEFT":mouseX<NOX_PV.oldMouseX&&mouseY>NOX_PV.oldMouseY?"BOTTOM_LEFT":mouseX>NOX_PV.oldMouseX&&mouseY===NOX_PV.oldMouseY?"RIGHT":mouseX===NOX_PV.oldMouseX&&mouseY>NOX_PV.oldMouseY?"DOWN":mouseX===NOX_PV.oldMouseX&&mouseY<NOX_PV.oldMouseY?"UP":mouseX<NOX_PV.oldMouseX&&mouseY===NOX_PV.oldMouseY?"LEFT":null,setCanvasSize=(newWidth,newHeight)=>{if(canvas&&ctx){const PIXEL_RATIO=window.devicePixelRatio||1;canvas.style.width=newWidth+"px",canvas.style.height=newHeight+"px",canvas.width=newWidth*PIXEL_RATIO,canvas.height=newHeight*PIXEL_RATIO,width=newWidth,height=newHeight,camera.size.set(width,height)}else console.warn("No canvas created yet, so cannot apply changes for its size.")},setAutoResize=(enable,onceDone=!0)=>{NOX_PV.autoResize=enable?onceDone?2:1:0},createCanvas=(w=null,h=null,bg="#000",requestPointerLock=!1,container=document.body)=>{if(!("inSetup"in NOX_PV))return console.warn("[Warning] createCanvas : usable only inside the setup() function.");if(!container)return console.warn("Canvas container is null. Aborting canvas creation.");if(null==w&&null==h&&(container===document.body?(w=documentWidth(),h=documentHeight()):(w=container.clientWidth,h=container.clientHeight)),w<=0||h<=0)return void console.warn("Canvas size must be higher than 0");null!=canvas&&(canvas.remove(),canvas=null,ctx=null);const PIXEL_RATIO=window.devicePixelRatio||1;return canvas=document.createElement("canvas"),width=w,height=h,canvas.width=width*PIXEL_RATIO,canvas.height=height*PIXEL_RATIO,canvas.style.width=width+"px",canvas.style.height=height+"px",canvas.id="nox-canvas",canvas.style.background=NOX_PV.colorTreatment(bg),camera.size.set(width,height),container.appendChild(canvas),requestPointerLock&&(document.addEventListener("pointerlockchange",()=>{document.pointerLockElement&&"nox-canvas"==document.pointerLockElement.id||(NOX_PV.isPointerLocked=!1)},!1),canvas.addEventListener("click",()=>{NOX_PV.isPointerLocked||(NOX_PV.isPointerLocked=!0,canvas.requestPointerLock())})),ctx=canvas.getContext("2d"),ctx.setTransform(PIXEL_RATIO,0,0,PIXEL_RATIO,0,0),ctx.fontKerning="normal",canvas},showGuideLines=bool=>{NOX_PV.bGuideLines="true"===`${bool}`},setDrawCondition=(condition=null)=>{condition&&(NOX_PV.drawCond=condition)},drawLoop=()=>{if(NOX_PV.hasErrorThrown)return;!0===NOX_PV.loop&&requestAnimationFrame(drawLoop);const t0=performance.now();if(NOX_PV.logPerfs&&0===NOX_PV.drawLoopInfo.it&&(NOX_PV.drawLoopInfo.start=t0),NOX_PV.now=Date.now(),NOX_PV.delta=NOX_PV.now-NOX_PV.then,camera.following)camera.position.set(camera.followPoint.x,camera.followPoint.y);else if(camera.moving){if(camera.moveType in NOX_PV.easeFuncMap==!1)throw new Error("[ERROR] drawLoop : Invalid easing function for camera move ("+camera.moveType+")");const m=NOX_PV.camera.move,f=NOX_PV.easeFuncMap[camera.moveType],t=m.start.asMilliseconds(),x=f(t,m.from.x,m.length.x,m.duration),y=f(t,m.from.y,m.length.y,m.duration);t>=m.duration?(camera.position.set(m.from.x+m.length.x,m.from.y+m.length.y),NOX_PV.camera.move=null):camera.position.set(x,y)}mouseWorldPos.set(mouseX,mouseY).add(camera.x,camera.y);for(const module of NOX_PV.updateModules)module.update(NOX_PV.delta);if(NOX_PV.updateFunc(NOX_PV.delta),NOX_PV.logPerfs&&(NOX_PV.drawLoopInfo.t1+=performance.now()-t0),NOX_PV.delta>NOX_PV.interval&&(NOX_PV.then=NOX_PV.now-NOX_PV.delta%NOX_PV.interval,NOX_PV.then-NOX_PV.firstThen>99999&&(NOX_PV.firstThen=NOX_PV.now,NOX_PV.then=NOX_PV.firstThen,NOX_PV.counter=0),NOX_PV.time_el=(NOX_PV.then-NOX_PV.firstThen)/1e3||1,NOX_PV.counter++,fps=round(NOX_PV.counter/NOX_PV.time_el),ctx&&NOX_PV.drawCond())){const t=performance.now();push(),clearRect(0,0,width,height),push(),translate(camera.size.x/2,camera.size.y/2),rotate(camera.rotation),scale(camera.zoom),translate(-camera.size.x/2-camera.x,-camera.size.y/2-camera.y);for(const module of NOX_PV.renderingModules)module.render();NOX_PV.drawFunc(),pop(),NOX_PV.drawHUDFunc();for(const module of NOX_PV.hudModules)module.hud();if(NOX_PV.bGuideLines){push(),fill("#46eaea"),stroke("#46eaea"),ctx.font="12px Consolas",ctx.textAlign="left",strokeWeight(1),line(0,mouseY,width,mouseY),line(mouseX,0,mouseX,height);const sText=`screen : ${floor(mouseX)}, ${floor(mouseY)}\nworld : ${floor(mouseWorldPos.x)}, ${floor(mouseWorldPos.y)}`,textDim=measureText(sText),textX=mouseX>width/2?mouseX-textDim.width/2-8:mouseX+8,textY=mouseY>height/2?mouseY-20:mouseY+25;text(sText,textX,textY),pop()}pop(),NOX_PV.drawLoopInfo.t2+=performance.now()-t}if(NOX_PV.logPerfs&&(NOX_PV.drawLoopInfo.it=(NOX_PV.drawLoopInfo.it+1)%NOX_PV.drawLoopInfo.freq,0===NOX_PV.drawLoopInfo.it)){NOX_PV.drawLoopInfo.t1/=NOX_PV.drawLoopInfo.freq,NOX_PV.drawLoopInfo.t2/=NOX_PV.drawLoopInfo.freq;const t1=floor(100*NOX_PV.drawLoopInfo.t1)/100,t2=floor(100*NOX_PV.drawLoopInfo.t2)/100,t3=floor(100*(t1+t2))/100;NOX_PV.drawLoopInfo.t1=0,NOX_PV.drawLoopInfo.t2=0;const data={update:{ms:t1},draw:{ms:t2},total:{ms:t3}};console.table(data)}},noLoop=()=>{NOX_PV.loop=!1},enableSmoothing=()=>{ctx&&(ctx.imageSmoothingEnabled=!0)},disableSmoothing=()=>{ctx&&(ctx.imageSmoothingEnabled=!1)},loadPixels=()=>{if(ctx instanceof CanvasRenderingContext2D&&canvas instanceof HTMLCanvasElement){NOX_PV.pixels=ctx.createImageData(canvas.width,canvas.height),pixels=NOX_PV.pixels.data;for(let i=0;i<width*height;i++)pixels[4*i+3]=255}else console.warn("Can't load canvas's pixels : no existing context found.")},updatePixels=()=>{void 0!==pixels&&ctx instanceof CanvasRenderingContext2D&&(NOX_PV.pixels.data=pixels,ctx.putImageData(NOX_PV.pixels,0,0))},perlin=(x,y=0)=>(NOX_PV.perlin.seed&&0!==NOX_PV.perlin.seed.length||(NOX_PV.perlin.seed=NOX_PV.perlin.generateSeed()),NOX_PV.perlin.get(x,y)),noiseDetails=detailLevel=>{"number"==typeof detailLevel&&(NOX_PV.perlin.lod=detailLevel)},generateUUID=()=>{const d0=4294967295*Math.random()|0,d1=4294967295*Math.random()|0,d2=4294967295*Math.random()|0,d3=4294967295*Math.random()|0;return NOX_PV.lut[255&d0]+NOX_PV.lut[d0>>8&255]+NOX_PV.lut[d0>>16&255]+NOX_PV.lut[d0>>24&255]+"-"+NOX_PV.lut[255&d1]+NOX_PV.lut[d1>>8&255]+"-"+NOX_PV.lut[d1>>16&15|64]+NOX_PV.lut[d1>>24&255]+"-"+NOX_PV.lut[63&d2|128]+NOX_PV.lut[d2>>8&255]+"-"+NOX_PV.lut[d2>>16&255]+NOX_PV.lut[d2>>24&255]+NOX_PV.lut[255&d3]+NOX_PV.lut[d3>>8&255]+NOX_PV.lut[d3>>16&255]+NOX_PV.lut[d3>>24&255]};class RGB{constructor(r,g=null,b=null,a=255){this.color={r:0,g:0,b:0},void 0===r&&(r=0),null!==g&&null===b&&(a=g,g=b=r),null===g&&(g=r,b=r),this.r=r,this.g=g,this.b=b,this.a=a}valueInInterval(val){if(val<0||val>255)throw new Error(`Color interval [0 - 255] no repespected (${val} given)`);return val}get r(){return this.color.r}get g(){return this.color.g}get b(){return this.color.b}get a(){return this.color.a}set r(val){this.color.r=this.valueInInterval(val)}set g(val){this.color.g=this.valueInInterval(val)}set b(val){this.color.b=this.valueInInterval(val)}set a(val){this.color.a=this.valueInInterval(val)}set(r,g,b,a=null){return this.r=r,this.g=g,this.b=b,null!==a&&(this.a=a),this}toString(){return`rgb${255!=this.a?"a":""}(${this.r}, ${this.g}, ${this.b}${255!=this.a?`, ${round(this.a/255*10)/10}`:""})`}intVal(){return[this.r,this.g,this.b,this.a]}toHEX(){let r=Number(this.r).toString()(16);r.length<2&&(r="0"+r);let g=Number(this.g).toString()(16);g.length<2&&(g="0"+g);let b=Number(this.b).toString()(16);b.length<2&&(b="0"+b);const rgb="#"+r+g+b;return new HEX(rgb)}toHSL(){const r=this.r/255,g=this.g/255,b=this.b/255,imax=max(r,g,b),imin=min(r,g,b);let h,s,l=(imax+imin)/2;if(imax===imin)h=s=0;else{const d=imax-imin;switch(s=l>.5?d/(2-imax-imin):d/(imax+imin),imax){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4}h/=6}return new HSL(round(10*h)/10,round(10*s)/10,round(10*l)/10)}}class HEX{constructor(hexaColor){this.color={int:0,str:"#000000"},this.set(hexaColor)}toString(){return this.color.str}intVal(){return this.color.int}set(hexaColor){if("number"==typeof hexaColor){this.color.int=hexaColor;const h=hexaColor.toString()(16)+"";this.color.str="#"+(4===h.length?"00":"")+h}else{if("string"!=typeof hexaColor||!/^#?([0-9a-f]{3}){1,2}$/i.test(hexaColor))throw new Error(`Given parameter isn't a recognized hexadecimal number: ${hexaColor}`);3===(hexaColor=hexaColor.replace("#","")).length&&(hexaColor=hexaColor[0].repeat(2)+hexaColor[1].repeat(2)+hexaColor[2].repeat(2)),this.color.str="#"+hexaColor,this.color.int=parseInt(hexaColor,16)}return this}toRGB(){const r=(16711680&this.intVal())>>>16,g=(65280&this.intVal())>>>8,b=255&this.intVal();return new RGB(r,g,b)}toHSL(){return this.toRGB().toHSL()}}class HSL{constructor(hue,saturation=.5,light=.5){if(this.color={h:0,s:0,l:0},"number"!=typeof hue)throw new Error(`Hue given parameter isn't a recognized number value: ${hue}`);this.h=hue,this.s=saturation,this.l=light}get h(){return this.color.h}get s(){return this.color.s}get l(){return this.color.l}set h(hue){this.color.h=hue>=0?hue%360:360-abs(hue)%360}set s(saturation){this.color.s=min(max(saturation,0),1)}set l(luminosity){this.color.l=min(max(luminosity,0),1)}add(hueToAdd){return this.h=this.h+hueToAdd,this}sub(hueToSub){return this.h=this.h-hueToSub,this}lighten(lightToAdd){return this.l=this.l+lightToAdd,this}obscure(lightToSub){return this.l=this.l-lightToSub,this}addSat(saturationToAdd){return this.s=this.s+saturationToAdd,this}subSat(saturationToSub){return this.s=this.s-saturationToSub,this}toString(){return`hsl(${this.h}, ${100*this.s}%, ${100*this.l}%)`}intVal(){return this.toHEX().intVal()}toHEX(){return this.toRGB().toHEX()}toRGB(){const C=(1-abs(2*this.l-1))*this.s,hh=this.h/60,X=C*(1-abs(hh%2-1));let r,g,b;r=g=b=0,hh>=0&&hh<1?[r,g]=[C,X]:hh>=1&&hh<2?[r,g]=[X,C]:hh>=2&&hh<3?[g,b]=[C,X]:hh>=3&&hh<4?[g,b]=[X,C]:[r,b]=hh>=4&&hh<5?[X,C]:[C,X];const m=this.l-C/2;return r=round(255*(r+m)),g=round(255*(g+m)),b=round(255*(b+m)),new RGB(r,g,b)}}class PerlinNoise{static mapnumberTypes=["default","rgb","hsl","bin"];static getMapNumberTypeIndex=typeStr=>PerlinNoise.mapnumberTypes.indexOf(typeStr);static bounds={default:[-1,1],rgb:[0,255],hsl:[0,360],bin:[0,1]};constructor(lod=10,x=0,y=0,w=width,h=height,mapnumber="default"){this.lod=lod,this.seed=NOX_PV.perlin.generateSeed(),this.start={x:x,y:y},this.size={width:w,height:h},this.array=[],this.numberMapStyle=PerlinNoise.getMapNumberTypeIndex(mapnumber),this.generate()}setLOD(lod){const tmp=this.lod;return this.lod=lod,tmp!==lod&&this.generate(),this}regenerateSeed(){return this.seed=NOX_PV.perlin.generateSeed(),this.generate(),this}setMapNumber(mapnumber){if(mapnumber=PerlinNoise.getMapNumberTypeIndex(mapnumber),this.numberMapStyle===mapnumber)return;const[Lmin,Lmax]=PerlinNoise.bounds[this.numberMapStyle],[Rmin,Rmax]=PerlinNoise.bounds[mapnumber];return this.array.forEach((row,i)=>{this.array[i]=map(this.array[i],Lmin,Lmax,Rmin,Rmax)}),this}get(x,y){return this.array[this.start.y+y][this.start.x+x]}calculate(){return this.generate()}generate(){this.array=[];for(let y=this.start.y;y<this.start.y+this.size.height;y++){const row=[];for(let x=this.start.x;x<this.start.x+this.size.width;x++)row.push(NOX_PV.perlin.get(x,y,this.lod,this.seed));this.array.push(row)}return this.numberMapStyle>0&&this.setMapNumber(PerlinNoise.mapnumberTypes[this.numberMapStyle]),this}}class Time{static units={nano:ms=>1e8*ms,micro:ms=>1e3*ms,milli:(t,unit="milli")=>{switch(unit){case"nano":return t/1e8;case"micro":return t/1e3;case"seconds":return 1e3*t;case"minutes":return 6e4*t;default:return t}},seconds:ms=>ms/1e3,minutes:ms=>ms/6e4};constructor(startingTime,unity="milli"){void 0!==startingTime&&Object.keys(Time.units).includes(unity)?(this.start=Time.units.milli(startingTime,unity),this.staticTime=!0):(this.reset(),this.staticTime=!1)}asNanoseconds(){return Time.units.nano(this.asMilliseconds())}asMicroseconds(){return Time.units.micro(this.asMilliseconds())}asMilliseconds(){return Time.units.milli(this.staticTime?this.start:Date.now()-this.start)}asSeconds(){return Time.units.seconds(this.asMilliseconds())}asMinutes(){return Time.units.minutes(this.asMilliseconds())}reset(){return this.start=Date.now(),this}}class Vector{constructor(x,y=null,z=null,w=null){let dimension=1;this.coords={x:0,y:0,z:0,w:0};const tmp={x:0,y:0,z:0,w:0};x instanceof Vector?(dimension=x.dimension,tmp.x=x.x,tmp.y=x.y,tmp.z=x.z,tmp.w=x.w):(dimension=Array.from(arguments).filter(a=>"number"==typeof a).length,tmp.x=x,tmp.y=y,tmp.z=z,tmp.w=w),this.constants=Object.freeze({dimension:dimension}),this.set(tmp.x,tmp.y,tmp.z,tmp.w)}get dimension(){return this.constants.dimension}get mag(){return Math.hypot(this.x,this.y,this.z,this.w)}get x(){return this.coords.x}get y(){return this.coords.y}get z(){return this.coords.z}get w(){return this.coords.w}set x(x){this.coords.x=x}set y(y){if(!(this.dimension>1))throw new Error("Cannot modify the Y of a 1D vector");this.coords.y=y}set z(z){if(!(this.dimension>2))throw new Error(`Cannot modify the Z of a ${this.dimension}D vector`);this.coords.z=z}set w(w){if(!(this.dimension>2))throw new Error(`Cannot modify the W of a ${this.dimension}D vector`);this.coords.w=w}copy(){return new Vector(this)}normalize(apply=!1){const norm=Math.hypot(this.x,this.y,this.z,this.w);return apply?(0!==norm&&(this.x/=norm,this.dimension>1&&(this.y/=norm,3===this.dimension&&(this.z/=norm,4===this.dimension&&(this.w/=norm)))),this):new Vector(this).normalize(!0)}equals(x,y=null,z=null,w=null){let vector;if(vector=x instanceof Vector?x:new Vector(x,y,z,w),this.dimension!==vector.dimension)return!1;for(const coord in this.coords)if(this.coords[coord]!==vector.coords[coord])return!1;return!0}set(x,y=null,z=null,w=null){if(x instanceof Vector)this.x=x.x,2===this.dimension&&(this.y=x.y),3===this.dimension&&(this.z=x.z),4===this.dimension&&(this.w=x.w);else{if("number"!=typeof x)throw new Error("[Error] Vector::set : x parameter must be a number or a Vector");if(this.dimension>1){if(null!==y&&"number"!=typeof y)throw new Error("[Error] Vector::set : y parameter must be a number");if(null!==z&&this.dimension>2&&"number"!=typeof z)throw new Error("[Error] Vector::set : z parameter must be a number");if(null!==w&&this.dimension>3&&"number"!=typeof w)throw new Error("[Error] Vector::set : w parameter must be a number")}this.x=x,this.dimension>1&&(null!==y&&(this.y=y),this.dimension>2&&null!=z&&(this.z=z,this.dimension>3&&null!=w&&(this.w=w)))}return this}add(x,y=null,z=null,w=null){return x instanceof Vector?this.set(this.x+x.x,this.y+x.y,this.z+x.z,this.w+x.w):(null===y&&(y=x),null===z&&(z=x),null===w&&(w=x),this.set(this.x+x,this.y+y,this.z+z,this.w+w))}sub(x,y=null,z=null,w=null){return x instanceof Vector?this.set(this.x-x.x,this.y-x.y,this.z-x.z,this.w-x.w):(null===y&&(y=x),null===z&&(z=x),null===w&&(w=x),this.set(this.x-x,this.y-y,this.z-z,this.w-w))}mult(x,y=null,z=null,w=null){return x instanceof Vector?this.set(this.x*x.x,this.y*x.y,this.z*x.z,this.w*x.w):(null===y&&(y=x),null===z&&(z=x),null===w&&(w=x),this.set(this.x*x,this.y*y,this.z*z,this.w*w))}div(x,y=null,z=null,w=null){return x instanceof Vector?this.set(this.x/x.x,this.y/x.y,this.z/x.z,this.w/x.w):(null===y&&(y=x),null===z&&(z=x),null===w&&(w=x),this.set(this.x/x,this.y/y,this.z/z,this.w/w))}invert(antiClockwise=!1){return this.dimension>1&&(2===this.dimension?[this.x,this.y]=[this.y,this.x]:3===this.dimension?[this.x,this.y,this.z]=antiClockwise?[this.y,this.z,this.x]:[this.z,this.x,this.y]:4===this.dimension&&([this.x,this.y,this.z,this.w]=[this.w,this.x,this.y,this.z])),this}setMag(newMag){return this.x=this.x*newMag/this.mag,this.dimension>1&&(this.y=this.y*newMag/this.mag),this.dimension>2&&(this.z=this.z*newMag/this.mag),this.dimension>3&&(this.w=this.w*newMag/this.mag),this}dot(other){return Object.keys(this.coords).reduce((acc,key)=>acc+this.coords[key]*other.coords[key],0)}heading(){return vectorToAngle(this)}rotate(angle){const radians=angle*Math.PI/180,cosius=cos(radians),sinus=sin(radians);return this.x=this.x*cosius-this.y*sinus,this.dimension>1&&(this.y=this.x*sinus+this.y*cosius,this.dimension>2&&(this.z=this.z*sinus+this.z*cosius,this.dimension>3&&(this.w=this.w*sinus+this.w*cosius))),this}toString(){let str="{";return this.dimension>0&&(str+=` x: ${this.x}`),this.dimension>1&&(str+=`, y: ${this.y}`),this.dimension>2&&(str+=`, z: ${this.z}`),this.dimension>3&&(str+=`, w: ${this.w}`),str+" }"}array(){const arr=[this.x];return this.dimension>1&&arr.push(this.y),this.dimension>2&&arr.push(this.z),this.dimension>3&&arr.push(this.w),arr}object(){const o={x:this.x};return this.dimension>1&&(o.y=this.y,this.dimension>2&&(o.z=this.z),this.dimension>3&&(o.w=this.w)),o}bow(x,y,style={}){if(this.dimension>2)return;style.strokeWeight?strokeWeight(style.strokeWeight):strokeWeight(1),style.stroke?stroke(style.stroke):stroke("#fff");const rotation=degree(vectorToAngle(this));push(),translate(x,y),line(0,0,this.x,this.y),linecap("round"),push(),translate(this.x,this.y),push(),rotate(rotation+25),line(0,0,-min(this.mag/2.5,10),0),rotate(-50),line(0,0,-min(this.mag/2.5,10),0),pop(),pop(),pop()}}class Matrix{properties={array:[],width:0,height:0};constructor(...args){if(args.length>0)if(args[0]instanceof Matrix){this.properties.width=args[0].width,this.properties.height=args[0].height;for(let i=0;i<args[0].height;i++){const row=[];for(let j=0;j<args[0].width;j++)row.push(args[0].at(j,i));this.properties.array.push(row)}}else if("number"==typeof args[0]){let fill=0;const w=args[0];let h=w;args.length>1&&"number"==typeof args[1]&&(h=args[1],args.length>2&&"number"==typeof args[2]&&(fill=args[2]));for(let i=0;i<h;i++){const row=[];for(let j=0;j<w;j++)row.push(fill);this.properties.array.push(row)}this.properties.width=w,this.properties.height=h}else if(1===args.length&&Array.isArray(args[0])&&args[0].every(a=>Array.isArray(a)&&a.length===args[0][0].length&&a.every(e=>"number"==typeof e)))this.properties.array=args[0],args[0].length>0&&(this.properties.width=args[0][0].length),this.properties.height=args[0].length;else{if(!args.every(a=>Array.isArray(a)&&a.length===args[0].length&&a.every(e=>"number"==typeof e)))throw new Error("[Error] Matrix constructor : Unrecognized parameters.");this.properties.array=args,this.properties.width=args[0].length,this.properties.height=args.length}this.properties.size=Object.freeze({x:this.properties.width,y:this.properties.height}),delete this.properties.width,delete this.properties.height}get array(){return this.properties.array}get array1D(){return this.array.reduce((a,b)=>[...a,...b],[])}get width(){return this.properties.size.x}get height(){return this.properties.size.y}get dimension(){return this.properties.size}toString(uncluttered=!1){const sep=this.height>0?"\n":"",brackets_open=uncluttered?"":"[",brackets_close=uncluttered?"":"]",m=uncluttered?max(...this.array.map(a=>max(...a.map(e=>e.toString().length)))):0,_format=uncluttered?arr=>arr.map(e=>" ".repeat(6+m-2*e.toString().length)+e).join(" "):arr=>arr.join(", ");return brackets_open+sep+this.properties.array.map(a=>"\t"+brackets_open+_format(a)+brackets_close).join("\n")+sep+brackets_close}at(x,y){return"number"==typeof x&&"number"==typeof y&&x>-1&&y>-1&&x<this.width&&y<this.height?this.array[y][x]:null}set(x,y,value){return null!==this.at(x,y)&&"number"==typeof value&&(this.array[y][x]=value),this}equals(matrix){if(matrix.width!==this.width||matrix.height!==this.height)return!1;for(let i=0;i<this.height;i++)for(let j=0;j<this.width;j++)if(matrix.at(j,i)!==this.at(j,i))return!1;return!0}get isSymmetrical(){for(let i=0;i<this.width;i++)for(let j=0;j<this.height;j++)if(this.at(i,j)!==this.at(j,i))return!1;return!0}get isSquare(){return this.width===this.height}get isIdentity(){return this.isSquare&&this.array.every((arr,i)=>arr.every((e,j)=>i===j&&1===e||i!==j&&0===e))}get isDiagonal(){return this.isSquare&&this.array.every((arr,i)=>arr.every((e,j)=>i===j&&0!==e||i!==j&&0===e))}get isTriangular(){const a=this.isLowerTri,b=this.isUpperTri;return a?!b:b}get isLowerTri(){if(!this.isSquare)return!1;for(let i=0;i<this.height;i++)for(let j=0;j<this.width;j++){const e=this.at(j,i);if(j>=i&&0!==e)return!1}return!0}get isUpperTri(){if(!this.isSquare)return!1;for(let i=0;i<this.height;i++)for(let j=0;j<this.width;j++){const e=this.at(j,i);if(j<=i&&0!==e)return!1}return!0}get diagonal(){return this.isSquare?this.array.map((arr,i)=>arr[i]):[]}get det(){if(!this.isSquare)return 0;if(this.isIdentity)return 1;if(this.isDiagonal||this.isTriangular){const diag=this.diagonal;return diag.reduce((acc,curr)=>acc*curr,1)}if(2===this.width)return this.at(0,0)*this.at(1,1)-this.at(1,0)*this.at(0,1);if(3===this.width){const[a,b,c,d,e,f,g,h,i]=this.array1D;return a*e*i+d*h*c+b*f*g-(g*e*c+d*b*i+a*h*f)}{const det=m=>1===m.length?m[0][0]:2===m.length?m[0][0]*m[1][1]-m[0][1]*m[1][0]:m[0].reduce((r,e,i)=>r+(-1)**(i+2)*e*det(m.slice(1).map(c=>c.filter((_,j)=>i!=j))),0);return det(this.array)}}add(matrix,onACopy=!1){if("op"in this||(this.op=(a,b)=>a+b),!(matrix instanceof Matrix)&&"number"!=typeof matrix)throw delete this.op,new Error(`[Error] Matrix::add : Matrix expected, ${typeof matrix} given`);if(matrix instanceof Matrix&&(matrix.width!==this.width||matrix.height!==this.height))throw delete this.op,new Error("[Error] Matrix::add : Cannot operate an addition between 2 matrices with different dimensions.");const result=onACopy?new Matrix(this):this,b=matrix instanceof Matrix;for(let i=0;i<result.height;i++)for(let j=0;j<result.width;j++)result.set(j,i,this.op(result.at(j,i),b?matrix.at(j,i):matrix));return delete this.op,result}sub(matrix,onACopy=!1){return this.op=(a,b)=>a-b,this.add(matrix,onACopy)}mult(matrixOrnumber,onACopy=!1){const m=matrixOrnumber;let result=onACopy?new Matrix(this):this;if("number"==typeof m)for(let i=0;i<result.height;i++)for(let j=0;j<result.width;j++)result.set(j,i,result.at(j,i)*m);else{if(!(m instanceof Matrix))throw new Error(`[Error] Matrix::mult : Matrix or number expected, got ${typeof matrixOrnumber}`);if(m.height!==this.width||m.width!==this.height)throw new Error("[Error] Matrix::mult : matrices must have same transposed size.");result=new Matrix(this.height);for(let i=0;i<this.height;i++)for(let j=0;j<this.height;j++){let s=0;for(let k=0;k<this.width;k++)s+=this.at(k,i)*m.at(j,k);result.set(j,i,s)}}return result}transpose(onACopy=!1){let copy=new Matrix(this),me=this;onACopy&&([copy,me]=[me,copy]),me.properties.size=Object.freeze({x:me.properties.size.y,y:me.properties.size.x}),me.properties.array=[];for(let i=0;i<copy.width;i++){const row=[];for(let j=0;j<copy.height;j++)row.push(0);me.properties.array.push(row)}for(let i=0;i<copy.height;i++)for(let j=0;j<copy.width;j++)me.set(i,j,copy.at(j,i));return me}getColumn(x){if(x<0||x>this.width)return[];const column=[];for(let i=0;i<this.height;i++)column.push(this.at(x,i));return column}getRow(y){return y<0||y>this.height?[]:this.properties.array[y]}setColumn(x,column){if(x<0||x>this.width)throw new Error("[Error] Matrix::setColumn : wrong index given.");if(column.length!==this.height)throw new Error("[Error] Matrix::setColumn : column must have the same length as the matrix's height.");for(let i=0;i<this.height;i++)this.set(x,i,column[i]);return this}setRow(y,row){if(y<0||y>this.height)throw new Error("[Error] Matrix::setRow : wrong index given.");if(row.length!==this.height)throw new Error("[Error] Matrix::setRow : row must have the same length as the matrix's width.");return this.properties.array[y]=row,this}}class Camera{uuid=generateUUID();position=new Vector(0,0);followPoint=null;rotation=0;zoom=1;size=new Vector(width,height);moveType="quadInOut";constructor(position=null){position instanceof Vector&&(this.position=position)}get x(){return this.position.x-this.size.x/2}get y(){return this.position.y-this.size.y/2}get following(){return null!==this.followPoint}get moving(){return null!==NOX_PV.camera.move}getBounds(){return{x:this.x,y:this.y,width:this.size.x,height:this.size.y}}setMoveType(moveType){return moveType in NOX_PV.easeFuncMap&&(this.moveType=moveType),this}follow(point){if(point instanceof Vector)this.followPoint=point;else{if(!("object"==typeof point&&point.position instanceof Vector))throw new Error("[Error] Camera::follow : parameter should be a Vector.");this.followPoint=point.position}return this}stopFollow(){return this.followPoint=null,this}move(x,y,duration=1e3){if(this.moving)return;this.following&&this.stopFollow();const length=new Vector(0,0);return x instanceof Vector?(length.set(x),duration=y||1e3):length.set(x,y),NOX_PV.camera.move={from:this.position.copy(),length:length,duration:duration,start:new Time},this}moveTo(x,y,duration=1e3){const v=new Vector(0,0);return x instanceof Vector?(v.set(x.x,x.y),duration=y):v.set(x,y),v.sub(this.position),this.move(v.x,v.y,duration),this}stop(){return NOX_PV.camera.move=null,this}}class Path{constructor(x=null,y=null){this.d=null,this.isClosed=!1,x&&y&&this.MoveTo(x,y)}clear(){this.d=null}draw(){if(null===this.d)throw new Error("Cannot draw it because you didn't make a path");path(this.d+(this.isClosed?" Z":""))}MoveTo(x,y){null===this.d?this.d=`M ${x} ${y}`:this.d+=` M ${x} ${y}`}moveTo(x,y){if(null===this.d)throw new Error("You have to initialize the fist path's position");this.d+=` m ${x} ${y}`}LineTo(x,y){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` L ${x} ${y}`}lineTo(x,y){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` l ${x} ${y}`}Horizontal(x){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` H ${x}`}horizontal(x){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` h ${x}`}Vertical(y){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` V ${y}`}vertical(y){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` v ${y}`}Arc(x,y,r,start,end,antiClockwise=!1){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` A ${x} ${y} ${r} ${start} ${end} ${!0===antiClockwise?1:0}`}arc(x,y,r,start,end,antiClockwise=!1){if(null===this.d)throw new Error("You have to initialize the first path's position");this.d+=` a ${x} ${y} ${r} ${start} ${end} ${!0===antiClockwise?1:0}`}close(){if(null===this.d)throw new Error("You have to initialize the first path's position");this.isClosed=!0}open(){if(null===this.d)throw new Error("You have to initialize the first path's position");this.isClosed=!1}move(x,y=null){null===y&&x instanceof Vector&&([x,y]=[x.x,x.y]),null!==this.d&&(this.d=this.d.replace(/([MLHVA])\s([\d\.]+)(\s([\d\.]+))?/g,(c,p1,p2,p3)=>"H"===p1?`${p1} ${parseFloat(p2)+x}`:"V"===p1?`${p1} ${parseFloat(p2)+y}`:`${p1} ${parseFloat(p2)+x} ${parseFloat(p3)+y}`))}}class Quadtree{static Point=class Point{constructor(x,y,dataPtr){this.x=x,this.y=y,this.dataPtr=dataPtr}};static Rectangle=class Rectangle{constructor(x,y,w,h){this.x=x,this.y=y,this.w=w,this.h=h}contains(point){return this.x<=point.x&&point.x<=this.x+this.w&&this.y<=point.y&&point.y<=this.y+this.h}intersect(rectangle){return!(rectangle.x>this.x+this.w||rectangle.x+rectangle.w<this.x||rectangle.y>this.y+this.h||rectangle.y+rectangle.h<this.y)}wrap(rectangle){return this.x<=rectangle.x&&rectangle.x+rectangle.w<=this.x+this.w&&this.y<=rectangle.y&&rectangle.y+rectangle.h<=this.y+this.h}};constructor(boundary,capacity=5){if(!(boundary instanceof Quadtree.Rectangle))throw new Error("[Quadtree::constructor] boundary must be a Quadtree.Rectangle");this.boundary=boundary,this.capacity=capacity,this.points=[],this.divided=!1}get children(){return this.divided?[this.northwest,this.northeast,this.southwest,this.southeast]:[]}clear(){this.points=[],this.divided=!1,delete this.northeast,delete this.northwest,delete this.southeast,delete this.southwest}subdivide(){if(!this.divided){const{x:x,y:y,w:w,h:h}=this.boundary,ne=new Quadtree.Rectangle(x+w/2,y,w/2,h/2),nw=new Quadtree.Rectangle(x,y,w/2,h/2),se=new Quadtree.Rectangle(x+w/2,y+h/2,w/2,h/2),sw=new Quadtree.Rectangle(x,y+h/2,w/2,h/2);this.northwest=new Quadtree(nw),this.northeast=new Quadtree(ne),this.southwest=new Quadtree(sw),this.southeast=new Quadtree(se),this.divided=!0;for(const p of this.points)this.insert(p);this.points=[]}}insert(...points){for(const point of points){if(!this.boundary.contains(point))return!1;if(this.divided)return this.northeast.insert(point)||this.northwest.insert(point)||this.southeast.insert(point)||this.southwest.insert(point);if(this.points.length<this.capacity)return this.points.push(point),!0;this.subdivide(),this.insert(point)}}getRegion(x,y){if(!this.divided)return this;const index=(x>=this.boundary.x+this.boundary.w/2?1:0)+(y>=this.boundary.y+this.boundary.h/2?2:0);return this.children[index].getRegion(x,y)}getNeighboringRegions(region){if(!(region instanceof Quadtree))throw new Error("[Quadtree::getNeighboringRegions] region must be a Quadtree");const neighbors=[],left=region.x<this.x,right=region.x+region.width>this.x+this.width,top=region.y<this.y,bottom=region.y+region.height>this.y+this.height;return left&&top&&neighbors.push(this.children[0]),right&&top&&neighbors.push(this.children[1]),left&&bottom&&neighbors.push(this.children[2]),right&&bottom&&neighbors.push(this.children[3]),neighbors.filter(neighbor=>neighbor&&neighbor.boundary.intersect(region))}query(range){if(!(range instanceof Quadtree.Rectangle))throw new Error("[Quadtree::query] range must be a Quadtree.Rectangle");if(!this.divided){if(range.wrap(this.boundary))return this.points;if(range.intersect(this.boundary)){const found=[];for(const p of this.points)range.contains(p)&&found.push(p);return found}return[]}if(range.wrap(this.boundary))return this.getAllPoints();const found=[];return found.push(...this.northwest.query(range)),found.push(...this.northeast.query(range)),found.push(...this.southwest.query(range)),found.push(...this.southeast.query(range)),found}show(color=20){noFill(),stroke(color),strokeWeight(1),strokeRect(this.boundary.x,this.boundary.y,this.boundary.w-1,this.boundary.h-1),this.divided&&(this.northeast.show(color),this.northwest.show(color),this.southeast.show(color),this.southwest.show(color))}getAllPoints(){if(!this.divided)return this.points;const points=[];for(const region of this.children)points.push(...region.getAllPoints());return points}size(){let n=this.points.length;for(const region of this.children)n+=region.size();return n}}class NoxCanvasModule{constructor(){if(this.constructor===NoxCanvasModule)throw new Error("[NoxCanvasModule] Object of Abstract Class cannot be created")}}const addModule=module=>{if(!(module instanceof NoxCanvasModule))throw new Error("[addModule] given module does not extends NoxCanvasModule.");"function"==typeof module.update&&NOX_PV.updateModules.push(module),"function"==typeof module.render&&NOX_PV.renderingModules.push(module),"function"==typeof module.hud&&NOX_PV.hudModules.push(module),NOX_PV.modules.push(module)},logPerformances=()=>{NOX_PV.logPerfs=!0},NOX_PV={updateFunc:()=>{},drawFunc:()=>{},drawHUDFunc:()=>{},hasErrorThrown:!1,modules:[],updateModules:[],renderingModules:[],hudModules:[],notSetup:!0,logPerfs:!1,drawLoopInfo:{it:0,t0:0,t1:0,t2:0,freq:720},drawCond:()=>!0,camera:{enabled:!0,move:null},cam:null,lut:[],bFill:!0,bStroke:!0,keys:{},isMouseDown:!1,oldMouseX:0,oldMouseY:0,isPointerLocked:!1,swipexDown:null,swipeyDown:null,autoResize:0,lastSwipe:null,bGuideLines:!1,fontSize:"12px",fontFamily:"Monospace",offsetLineBlur:.5,loop:!0,timer:0,now:0,then:Date.now(),firstThen:Date.now(),interval:1e3/fps,delta:0,counter:0,time_el:0,colorTreatment:(...oColor)=>{const n=oColor.length,color0=oColor[0];if(color0 instanceof CanvasGradient||color0 instanceof CanvasPattern)return color0;if(color0 instanceof HEX||color0 instanceof RGB||color0 instanceof HSL)return color0.toString();if(n>0&&n<5&&oColor.every(c=>"number"==typeof c)){let p="rgb",g=0,b=0,a=0;3!==n&&4!==n||(g=1,b=2),2!==n&&4!==n||(p+="a",a=n-1);let color=`${p}(${color0}, ${oColor[g]}, ${oColor[b]}`;return a>0&&(color+=`, ${oColor[a]}`),color+=")",color}if(1===n&&"string"==typeof color0){oColor=color0.replace(/\s/gi,"");const reg={hex:/^#([0-9a-z]{3}){1,2}$/i,rgb:/^rgba?\((\d{1,3},){2}\d{1,3}(,(0|1|(0?\.\d+)))?\)$/,hsl:/^hsl\(\d{1,3},\d{1,3}%,\d{1,3}%\)$/,hsla:/^hsla\(\d{1,3},\d{1,3}%,\d{1,3}%,(0|1|(0?.\d+))\)$/,name:/^\w{3,30}$/};for(const regex in reg)if(reg[regex].test(oColor))return oColor}return"#000"},perlin:{lod:10,unit:1,gradient:[],seed:[],generateSeed:()=>Array(255).fill(0).map((i,j)=>j).sort(()=>Math.random()-.5),get:(x,y,lod=NOX_PV.perlin.lod,seed=NOX_PV.perlin.seed)=>{x/=lod,y/=lod;const[x0,y0]=[floor(x),floor(y)],[dx,dy,ii,jj]=[x-x0,y-y0,255&x0,255&y0],stuv=[];for(let i=0;i<4;i++){const v=seed[(ii+i%2+seed[jj+floor(i/2)])%255]%NOX_PV.perlin.gradient.length;stuv.push(NOX_PV.perlin.gradient[v][0]*(dx-i%2)+NOX_PV.perlin.gradient[v][1]*(dy-floor(i/2)))}const[Cx,Cy]=[3*dx*dx-2*dx*dx*dx,3*dy*dy-2*dy*dy*dy],[Li1,Li2]=[stuv[0]+Cx*(stuv[1]-stuv[0]),stuv[2]+Cx*(stuv[3]-stuv[2])];return Li1+Cy*(Li2-Li1)}},easeElastic:(type,t,b,c,d)=>{if(0===t)return b;if(1==(t/=d))return b+c;const p=.45*d,s=p/(c<0?4:2*PI*1.57),x=sin(2*PI*(t*d-s)/p);return"in"===type?-c*pow(2,10*--t)*x+b:"out"===type?c*pow(2,-10*t)*x+c+b:t<1?c*pow(2,10*--t)*x*-.5+b:c*pow(2,-10*--t)*x*.5+c+b}};NOX_PV.perlin.gradient=[[NOX_PV.perlin.unit,NOX_PV.perlin.unit],[-NOX_PV.perlin.unit,NOX_PV.perlin.unit],[NOX_PV.perlin.unit,-NOX_PV.perlin.unit],[-NOX_PV.perlin.unit,-NOX_PV.perlin.unit]];for(let i=0;i<256;i++)NOX_PV.lut[i]=(i<16?"0":"")+i.toString(16);NOX_PV.easeFuncMap={linear:easeLinear,quadIn:easeInQuad,quadOut:easeOutQuad,quadInOut:easeInOutQuad,sineIn:easeInSine,sineOut:easeOutSine,sineInOut:easeInOutSine,expoIn:easeInExpo,expoOut:easeOutExpo,expoInOut:easeInOutExpo,circIn:easeInCirc,circOut:easeOutCirc,circInOut:easeInOutCirc,cubicIn:easeInCubic,cubicOut:easeOutCubic,cubicInOut:easeInOutCubic,quartIn:easeInQuart,quartOut:easeOutQuart,quartInOut:easeInOutQuart,quintIn:easeInQuint,quintOut:easeOutQuint,quintInOut:easeInOutQuint,backIn:easeInBack,backOut:easeOutBack,backInOut:easeInOutBack,elasticIn:easeInElastic,elasticOut:easeOutElastic,elasticInOut:easeInOutElastic};const camera=new Camera;NOX_PV.cam=camera;const mouseWorldPos=new Vector(0,0);window&&window.addEventListener("load",()=>{const t0=performance.now();MIN_DOC_SIZE=min(documentWidth(),documentHeight()),"function"==typeof setup&&(NOX_PV.inSetup=!0,setup(),delete NOX_PV.notSetup,void 0===pixels&&delete pixels),window.addEventListener("error",e=>{NOX_PV.hasErrorThrown=!0,console.warn("An error has been thrown, thus, the renderer has stopped to avoid further issues."),console.error(e)});const t1=performance.now();"function"==typeof draw&&(NOX_PV.drawFunc=draw),"function"==typeof drawHUD&&(NOX_PV.drawHUDFunc=drawHUD),"function"==typeof update&&(NOX_PV.updateFunc=update);const offset=elt=>{const rect=elt.getBoundingClientRect();return{top:rect.top+document.body.scrollTop,left:rect.left+document.body.scrollLeft}};canvas&&(canvas.addEventListener("pointerdown",e=>{canvas.setPointerCapture(e.pointerId),NOX_PV.isMouseDown=!0,dragPoint={x:e.clientX-offset(canvas).left,y:e.clientY-offset(canvas).top},"function"==typeof mouseDown&&mouseDown(e),canvas.addEventListener("pointerup",()=>{try{canvas.releasePointerCapture(e.pointerId)}catch(e){}dragPoint=null,NOX_PV.isMouseDown=!1,"function"==typeof mouseUp&&mouseUp(e)},{once:!0})}),canvas.addEventListener("pointermove",e=>{const rect=canvas.getBoundingClientRect();if(mouseX=e.clientX-rect.left,mouseY=e.clientY-rect.top,mouseDirection.x=e.movementX,mouseDirection.y=e.movementY,NOX_PV.isMouseDown){const xUp=e.clientX,yUp=e.clientY,xDiff=dragPoint.x-xUp,yDiff=dragPoint.y-yUp;let swipeDir;swipeDir=abs(xDiff)>abs(yDiff)?xDiff>0?"left":"right":yDiff>0?"up":"down",NOX_PV.lastSwipe=swipeDir,"function"==typeof onSwipe&&onSwipe(swipeDir),"function"==typeof onDrag&&onDrag(e)}else"function"==typeof mouseMove&&mouseMove(e)}),"function"==typeof onClick&&canvas.addEventListener("click",onClick),"function"==typeof mouseEnter&&canvas.addEventListener("mouseenter",mouseEnter),"function"==typeof mouseLeave&&canvas.addEventListener("mouseleave",mouseLeave),"function"==typeof mouseWheel&&canvas.addEventListener("wheel",mouseWheel),"function"==typeof onContextmenu&&canvas.addEventListener("contextmenu",onContextmenu),"function"==typeof onDblClick&&canvas.addEventListener("dblclick",onDblClick)),window.addEventListener("keypress",e=>{NOX_PV.keys[e.code]=!0,"function"==typeof keyPress&&keyPress(e)}),window.addEventListener("keydown",e=>{NOX_PV.keys[e.code]=!0,"function"==typeof keyDown&&keyDown(e)}),window.addEventListener("keyup",e=>{NOX_PV.keys[e.code]=!1,"function"==typeof keyUp&&keyUp(e)}),window.addEventListener("resize",()=>{const newWidth=document.documentElement.clientWidth,newHeight=document.documentElement.clientHeight;clearTimeout(NOX_PV.resizeEndedCallback),NOX_PV.resizeEndedCallback=setTimeout(()=>{MIN_DOC_SIZE=min(newWidth,newHeight),NOX_PV.loop=!0,2===NOX_PV.autoResize&&setCanvasSize(newWidth,newHeight),"function"==typeof onResizeEnded&&onResizeEnd(newWidth,newHeight)},100),1===NOX_PV.autoResize&&setCanvasSize(newWidth,newHeight),"function"==typeof onResize&&onResize(newWidth,newHeight)}),"function"==typeof onBlur&&window.addEventListener("blur",onBlur),"function"==typeof onFocus&&window.addEventListener("focus",onFocus),"function"==typeof onOnline&&window.addEventListener("online",onOnline),"function"==typeof onOffline&&window.addEventListener("offline",onOffline);const t2=performance.now();if(NOX_PV.logPerfs){const perfData={setup:{ms:t1-t0},InitWorld:{ms:t2-t1}};console.info("Performances while initializing the canvas environment :"),console.table(perfData)}NOX_PV.timer=new Time,drawLoop()},{once:!0});