From 9df7e6df76aaf6783157e331ca9a001eaacd0776 Mon Sep 17 00:00:00 2001 From: leikareipa Date: Thu, 11 Aug 2022 18:01:14 +0300 Subject: [PATCH] Update experimental paletted rendering stuff These are changes made a while ago but not committed at the time, so I can't remember their exact state of progress. Paletted rendering is still experimental, so these may or may not be production-ready changes. --- distributable/rngon.cat.js | 2 +- js/paletted-canvas/paletted-canvas.js | 160 +++++++++++------- .../rasterize/raster-shader-generic-fill.js | 5 +- .../raster-shader-plain-solid-fill.js | 5 +- .../raster-shader-plain-textured-fill.js | 5 +- js/retro-ngon/core/surface.js | 6 +- 6 files changed, 114 insertions(+), 69 deletions(-) diff --git a/distributable/rngon.cat.js b/distributable/rngon.cat.js index 3f24c20..afb91ce 100644 --- a/distributable/rngon.cat.js +++ b/distributable/rngon.cat.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Rngon=t():e.Rngon=t()}(self,(()=>(()=>{var e={962:()=>{if("function"!=typeof importScripts){class e{#e;#t;#n;#r;constructor(e,t,n,r){if(!(e instanceof Uint8ClampedArray))throw new Error("The data must be a Uint8ClampedArray array.");if("number"!=typeof t||"number"!=typeof n)throw new Error("The width and height must be numbers.");this.#t=t,this.#n=n,this.#r=e,this.palette=r||[[0,0,0,0]]}get palette(){return this.#e}set palette(e){if(!Array.isArray(e))throw new Error("The palette must be an array.");e.forEach((e=>{e.length=4,void 0===e[3]&&(e[3]=255)}));const t={byte:e=e.map((e=>Uint8ClampedArray.from(e))),dword:new Uint32Array(e.map((e=>e[3]<<24|e[2]<<16|e[1]<<8|e[0])))};this.#e=new Proxy(t,{set:(e,t,n)=>(e.byte[t]=n,this.palette=e.byte,!0),get:(e,t)=>e[t]||e.byte[t]})}get data(){return this.#r}get width(){return this.#t}get height(){return this.#n}get colorSpace(){return"indexed"}}class t extends HTMLCanvasElement{#a;#o;constructor(){super()}static get observedAttributes(){return["width","height"]}attributeChangedCallback(e,t,n){t!=n&&["width","height"].includes(e)&&(this.#o=super.getContext("2d"),this.#a=this.#o.createImageData(super.width,super.height))}getContext(e="2d"){if("2d"!==e)throw new Error('Only the "2d" context type is supported.');return{createImageData:this.#i.bind(this),putImageData:this.#s.bind(this)}}#i(){return new e(new Uint8ClampedArray(super.width*super.height),super.width,super.height)}#s(t){if(!(t instanceof e))throw new Error("Only images of type IndexedImageData can be rendered.");if(!(this.#a instanceof ImageData&&this.#o instanceof CanvasRenderingContext2D))throw new Error("Internal error: incomplete state initialization.");{const e=t.palette.dword,n=new Uint32Array(this.#a.data.buffer);for(let r=0;r{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};return(()=>{"use strict";function e(e,t=[Rngon.mesh()],n={}){const r=Rngon.renderShared.setup_render_call_info();n=Object.freeze({...Rngon.renderShared.defaultRenderOptions,...n}),Rngon.renderShared.initialize_internal_render_state(n),"string"==typeof e&&(e=document.getElementById(e)),Rngon.assert?.(e instanceof HTMLElement,"Invalid canvas element for rendering into.");{const a=Rngon.surface(e,n);!a||n.hibernateWhenNotOnScreen&&!a.is_in_view()||(a.display_meshes(t),r.renderWidth=a.width,r.renderHeight=a.height,r.numNgonsRendered=Rngon.internalState.ngonCache.count)}return r.totalRenderTimeMs=performance.now()-r.totalRenderTimeMs,r}async function t(e=[Rngon.mesh()],t={},n=null){return t.modules={rasterize:null,transformClipLight:null},new Promise(((r,o)=>{const i=new Worker(URL.createObjectURL(new Blob([`(${a.toString()})()`],{type:"text/javascript"})));i.onmessage=e=>{if(i.terminate(),"string"==typeof(e=e.data).type)switch(e.type){case"rendering-finished":delete e.type,r(e);break;case"error":o(`A render worker reported the following error: ${e.errorText}`);break;default:o("A render worker sent an unrecognized message.")}else o("A render worker sent an invalid message.")},null===n&&(n=Array.from(document.getElementsByTagName("script")).filter((e=>e.src.endsWith("rngon.cat.js")))[0].src),i.postMessage({type:"render",meshes:e,options:t,rngonUrl:n})}))}function a(){onmessage=e=>{if("string"==typeof(e=e.data).type)if("render"===e.type)try{importScripts(e.rngonUrl),function(e,t){Rngon.assert?.(Array.isArray(e),"Expected meshes to be provided in an array.");const n=Rngon.renderShared.setup_render_call_info(),r=Object.freeze({...Rngon.renderShared.defaultRenderOptions,...t});Rngon.renderShared.initialize_internal_render_state(r),Rngon.internalState.allowWindowAlert=!1;{const t=Rngon.surface(null,r);Rngon.assert?.(t,"Failed to initialize the render surface."),t.display_meshes(e),n.renderWidth=r.width,n.renderHeight=r.height,n.numNgonsRendered=Rngon.internalState.ngonCache.count,n.image=Rngon.internalState.pixelBuffer}n.totalRenderTimeMs=performance.now()-n.totalRenderTimeMs,postMessage({...n,type:"rendering-finished"})}(e.meshes,e.options)}catch(e){postMessage({type:"error",errorText:e.message})}else postMessage({type:"error",errorText:"Received an unrecognized message."});else postMessage({type:"error",errorText:"A render worker received an invalid message."})}}function o({ngon:e,ngonIdx:t,leftEdges:n,rightEdges:r,numLeftEdges:a,numRightEdges:o,pixelBuffer32:i,auxiliaryBuffers:s}){const l=Rngon.internalState.usePixelShader,d=Rngon.internalState.fragmentBuffer.data,h=Rngon.internalState.useDepthBuffer?Rngon.internalState.depthBuffer.data:null,c=Rngon.internalState.pixelBuffer.data,g=Rngon.internalState.pixelBuffer.width,f=e.material,u=f.texture||null;let p=null,m=0;if(u){const t=u.mipLevels.length;m=Math.max(0,Math.min(t-1,Math.round((t-1)*e.mipLevel))),p=u.mipLevels[m]}let x=0,v=0,w=n[x],R=r[v];if(!a||!o)return;const y=n[0].top,b=n[a-1].bottom;for(let e=y;e0){const n=(R.start.depth-w.start.depth)/m;let r=w.start.depth-n;const x=(R.start.shade-w.start.shade)/m;let v=w.start.shade-x;const C=(R.start.u-w.start.u)/m;let W=w.start.u-C;const E=(R.start.v-w.start.v)/m;let P=w.start.v-E;const I=(R.start.invW-w.start.invW)/m;let D=w.start.invW-I;if(l)var S=(R.start.worldX-w.start.worldX)/m,M=w.start.worldX-S,_=(R.start.worldY-w.start.worldY)/m,z=w.start.worldY-_,B=(R.start.worldZ-w.start.worldZ)/m,A=w.start.worldZ-B;let j=a+e*g-1;for(let g=a;g=p.width||w>=p.height){const e=o<0,t=w<0;o=Math.abs(o)%p.width,w=Math.abs(w)%p.height,e&&(o=p.width-o),t&&(w=p.height-w)}break;case"ortho":{const t=b-y,n=e-y+1;o=(g-a+1)*(p.width/m),w=n*(p.height/t),w=p.height-w;break}default:Rngon.$throw("Unknown texture-mapping mode.")}const t=p.pixels[~~o+~~w*p.width];if(!t)continue;if(f.allowAlphaReject&&255!==t.alpha)continue;if(f.allowAlphaBlend&&Rngon.baseModules.rasterize.stipple(f.color.alpha,g,e))continue;X=t.red*f.color.unitRange.red*L,T=t.green*f.color.unitRange.green*L,k=t.blue*f.color.unitRange.blue*L}else{if(f.allowAlphaBlend&&Rngon.baseModules.rasterize.stipple(f.color.alpha,g,e))continue;X=f.color.red*L,T=f.color.green*L,k=f.color.blue*L}if(L>1){const e=4*j;c[e+0]=X,c[e+1]=T,c[e+2]=k,c[e+3]=255}else i[j]=(255<<24)+(k<<16)+(T<<8)+X;if(h&&(h[j]=R),l){const e=d[j];e.ngonIdx=t,e.textureUScaled=~~o,e.textureVScaled=~~w,e.depth=r/D,e.shade=v,e.worldX=M/D,e.worldY=z/D,e.worldZ=A/D,e.w=1/D}for(let e=0;e0){const t=(g.start.depth-c.start.depth)/f;let n=c.start.depth-t;const d=(g.start.invW-c.start.invW)/f;let h=c.start.invW-d,u=r+e*i-1;for(let e=r;e0){const t=(f.start.depth-g.start.depth)/u;let n=g.start.depth-t;const h=(f.start.shade-g.start.shade)/u;let c=g.start.shade-h;const p=(f.start.invW-g.start.invW)/u;let m=g.start.invW-p,x=r+e*s-1;for(let e=r;e1){const e=4*x;i[e+0]=a,i[e+1]=s,i[e+2]=g,i[e+3]=255}else o[x]=(255<<24)+(g<<16)+(s<<8)+a}}g.start.x+=g.delta.x,g.start.depth+=g.delta.depth,g.start.shade+=g.delta.shade,g.start.invW+=g.delta.invW,f.start.x+=f.delta.x,f.start.depth+=f.delta.depth,f.start.shade+=f.delta.shade,f.start.invW+=f.delta.invW,e===g.bottom-1&&(g=t[++h]),e===f.bottom-1&&(f=n[++c])}return!0}function l({ngon:e,leftEdges:t,rightEdges:n,numLeftEdges:r,numRightEdges:a,pixelBuffer32:o}){const i=Rngon.internalState.pixelBuffer.data,s=Rngon.internalState.pixelBuffer.width,l=Rngon.internalState.useDepthBuffer?Rngon.internalState.depthBuffer.data:null,d=e.material,h=d.texture||null;let c=null,g=0;if(h){const t=h.mipLevels.length;g=Math.max(0,Math.min(t-1,Math.round((t-1)*e.mipLevel))),c=h.mipLevels[g]}let f=0,u=0,p=t[f],m=n[u];if(!r||!a)return;const x=t[0].top,v=t[r-1].bottom;for(let e=x;e0){const t=(m.start.depth-p.start.depth)/h;let n=p.start.depth-t;const g=(m.start.shade-p.start.shade)/h;let f=p.start.shade-g;const u=(m.start.u-p.start.u)/h;let x=p.start.u-u;const v=(m.start.v-p.start.v)/h;let w=p.start.v-v;const R=(m.start.invW-p.start.invW)/h;let y=p.start.invW-R,b=r+e*s-1;for(let e=r;e1){const e=4*b;i[e+0]=p,i[e+1]=m,i[e+2]=S,i[e+3]=255}else o[b]=(255<<24)+(S<<16)+(m<<8)+p}}p.start.x+=p.delta.x,p.start.depth+=p.delta.depth,p.start.shade+=p.delta.shade,p.start.u+=p.delta.u,p.start.v+=p.delta.v,p.start.invW+=p.delta.invW,m.start.x+=m.delta.x,m.start.depth+=m.delta.depth,m.start.shade+=m.delta.shade,m.start.u+=m.delta.u,m.start.v+=m.delta.v,m.start.invW+=m.delta.invW,e===p.bottom-1&&(p=t[++f]),e===m.bottom-1&&(m=n[++u])}return!0}n.r(r),n.d(r,{$throw:()=>D,assert:()=>E,baseModules:()=>Y,bilinear_sample:()=>I,color_rgba:()=>x,internalState:()=>v,lerp:()=>P,light:()=>w,log:()=>j,material:()=>R,matrix44:()=>y,mesh:()=>b,ngon:()=>S,render:()=>e,renderShared:()=>z,render_async:()=>t,renderable_height_of:()=>X,renderable_width_of:()=>L,rotation_vector:()=>O,scaling_vector:()=>N,surface:()=>B,texture_rgba:()=>A,translation_vector:()=>k,trig:()=>W,vector3:()=>T,version:()=>V,vertex:()=>U}),n(962);const d=500,h=new Array(d),c=new Array(d),g=new Array(d).fill().map((()=>({top:void 0,bottom:void 0,start:{x:void 0,depth:void 0,shade:void 0,u:void 0,v:void 0,invW:void 0,worldX:void 0,worldY:void 0,worldZ:void 0},delta:{}}))),f=new Array(d).fill().map((()=>({top:void 0,bottom:void 0,start:{x:void 0,depth:void 0,shade:void 0,u:void 0,v:void 0,invW:void 0,worldX:void 0,worldY:void 0,worldZ:void 0},delta:{}}))),u=(e,t)=>e.y===t.y?0:e.y=0&&e<=255&&t>=0&&t<=255&&n>=0&&n<=255&&r>=0&&r<=255,"The given color values are out of range."),Object.freeze({red:e,green:t,blue:n,alpha:r,unitRange:Object.freeze({red:e/255,green:t/255,blue:n/255,alpha:r/255})})}p.polygon=function(e=Rngon.ngon(),t=0,n=[]){Rngon.assert?.(e.vertices.length>=3,"Polygons must have 3 or more vertices"),Rngon.assert?.(e.vertices.length=a?c[S++]=e.vertices[r]:h[b++]=e.vertices[r]}h[b++]=n,c[S++]=n}(),function(){for(let t=1;t!e(r)))){let e=o;w?e=i:!R.texture||!m||a||R.allowAlphaReject||R.allowAlphaBlend||"affine"!==R.textureMapping||255!==R.color.red||255!==R.color.green||255!==R.color.blue?R.texture||!m||a||p||R.allowAlphaReject||R.allowAlphaBlend||(e=s):e=l,e(r)}}if(Rngon.internalState.showGlobalWireframe||R.hasWireframe){for(let e=1;e=c||t>=g)return;const o=e+t*c,i=z/W,f=A/W,u=n.red*f,p=n.green*f,m=n.blue*f;if(a||!l||l[o]>i){if(f>1){const e=4*o;d[e+0]=u,d[e+1]=p,d[e+2]=m,d[e+3]=255}else h[o]=(255<<24)+(m<<16)+(p<<8)+u;if(l&&!a&&(l[o]=i),s){const e=Rngon.internalState.fragmentBuffer.data[o];e.ngonIdx=r,e.textureUScaled=void 0,e.textureVScaled=void 0,e.depth=z/W,e.shade=A/W,e.worldX=P/W,e.worldY=D/W,e.worldZ=L/W,e.w=1/W}}}},p.point=function(e=Rngon.vertex(),t=Rngon.material(),n=0){if(255!=t.color.alpha)return;const r=Rngon.internalState.usePixelShader,a=Rngon.internalState.useDepthBuffer?Rngon.internalState.depthBuffer.data:null,o=Rngon.internalState.pixelBuffer.data,i=new Uint32Array(o.buffer),s=Rngon.internalState.pixelBuffer.width,l=Rngon.internalState.pixelBuffer.height,d=Math.floor(e.x),h=Math.floor(e.y),c=d+h*s;if(d<0||h<0||d>=s||h>=l)return;const g=e.z/Rngon.internalState.farPlaneDistance,f=t.renderVertexShade?e.shade:1,u=t.texture?t.texture.pixels[0]:t.color,p=u.red*f,m=u.green*f,x=u.blue*f;if(!(a&&a[c]<=g)){if(f>1){const e=4*c;o[e+0]=p,o[e+1]=m,o[e+2]=x,o[e+3]=255}else i[c]=(255<<24)+(x<<16)+(m<<8)+p;if(a&&(a[c]=g),r){const t=Rngon.internalState.fragmentBuffer.data[c];t.ngonIdx=n,t.textureUScaled=0,t.textureVScaled=0,t.depth=g,t.shade=f,t.worldX=e.worldX,t.worldY=e.worldY,t.worldZ=e.worldZ,t.w=e.w}}},p.stipple=function(){const e=[{width:8,height:6,pixels:[0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]},{width:4,height:4,pixels:[0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1]},{width:2,height:2,pixels:[1,0,0,1]}];for(let t=e.length-2;t>=0;t--)e.push({width:e[t].width,height:e[t].height,pixels:e[t].pixels.map((e=>Number(!e)))});return function(t,n,r){if(t<=0)return!0;if(t>=255)return!1;{const a=Math.floor(t/(256/e.length)),o=e[a],i=n%o.width+r%o.height*o.width;if(o.pixels[i])return!0}return!1}}();const v={modules:{transform_clip_light:void 0,ngon_fill:void 0,surface_wipe:void 0},useDepthBuffer:!1,depthBuffer:{width:1,height:1,data:new Array(1),clearValue:1/0},depthSortingMode:void 0,auxiliaryBuffers:[],usePalette:!1,palette:void 0,pixelBuffer:new ImageData(1,1),fragmentBuffer:{width:1,height:1,data:new Array(1),clearValue:{ngonIdx:void 0,textureUScaled:void 0,textureVScaled:void 0,textureMipLevelIdx:void 0,worldX:void 0,worldY:void 0,worldZ:void 0,depth:void 0,shade:void 0,w:void 0}},usePixelShader:!1,pixel_shader:void 0,useVertexShader:!1,vertex_shader:void 0,useContextShader:!1,context_shader:void 0,rasterShaders:[],offscreenRenderWidth:1,offscreenRenderHeight:1,renderScale:1,usePerspectiveCorrectInterpolation:!1,showGlobalWireframe:!1,applyViewportClipping:!0,nearPlaneDistance:1,farPlaneDistance:1,fov:45,cameraDirection:void 0,cameraPosition:void 0,allowWindowAlert:!1,ngonCache:{count:0,ngons:[]},vertexCache:{count:0,vertices:[]},lights:[]};function w(e=Rngon.translation_vector(0,0,0),t={}){return w.defaultSettings=w.defaultSettings||{intensity:100,clip:1,attenuation:1},{position:e,...w.defaultSettings,...t}}function R(e={}){return R.default=R.default||{color:Rngon.color_rgba(),wireframeColor:Rngon.color_rgba(),texture:null,textureMapping:"ortho",uvWrapping:"repeat",vertexShading:"none",renderVertexShade:!0,ambientLightLevel:0,hasWireframe:!1,hasFill:!0,isTwoSided:!0,allowTransform:!0,allowAlphaReject:!1,allowAlphaBlend:!1,auxiliary:{}},{...R.default,...e}}const y={scaling:function(e=0,t=0,n=0){return Object.freeze([e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1])},translation:function(e=0,t=0,n=0){return Object.freeze([1,0,0,0,0,1,0,0,0,0,1,0,e,t,n,1])},rotation:function(e=0,t=0,n=0){const r=Rngon.trig.cos,a=Rngon.trig.sin,o=[1,0,0,0,0,r(e),-a(e),0,0,a(e),r(e),0,0,0,0,1],i=[r(t),0,a(t),0,0,1,0,0,-a(t),0,r(t),0,0,0,0,1],s=[r(n),-a(n),0,0,a(n),r(n),0,0,0,0,1,0,0,0,0,1],l=Rngon.matrix44.multiply(i,s),d=Rngon.matrix44.multiply(o,l);return Rngon.assert?.(16===d.length,"Expected a 4 x 4 matrix."),Object.freeze(d)},perspective:function(e=0,t=0,n=0,r=0){const a=Math.tan(e/2),o=n-r;return Object.freeze([1/(a*t),0,0,0,0,1/a,0,0,0,0,(-n-r)/o,1,0,0,2*r*(n/o),0])},ortho:function(e=0,t=0){return Object.freeze([e/2,0,0,0,0,-t/2,0,0,0,0,1,0,e/2-.5,t/2-.5,0,1])},multiply:function(e=[],t=[]){Rngon.assert?.(16===e.length&&16===t.length,"Expected 4 x 4 matrices.");let n=new Array(16);for(let r=0;r<4;r++)for(let a=0;a<4;a++)n[r+4*a]=e[r+0]*t[0+4*a]+e[r+4]*t[1+4*a]+e[r+8]*t[2+4*a]+e[r+12]*t[3+4*a];return Object.freeze(n)}};function b(e=[Rngon.ngon()],t={}){return Rngon.assert?.(e instanceof Array,"Expected a list of ngons for creating an ngon mesh."),Rngon.assert?.(t instanceof Object,"Expected an object with transformation properties."),b.defaultTransform=b.defaultTransform||{translation:Rngon.translation_vector(0,0,0),rotation:Rngon.rotation_vector(0,0,0),scaling:Rngon.scaling_vector(1,1,1)},Rngon.assert?.(void 0!==Rngon.mesh.defaultTransform?.rotation&&void 0!==Rngon.mesh.defaultTransform?.translation&&void 0!==Rngon.mesh.defaultTransform?.scaling,"The default transforms object for mesh() is missing required properties."),{ngons:e,rotation:(t={...Rngon.mesh.defaultTransform,...t}).rotation,translation:t.translation,scale:t.scaling}}function S(e=[Rngon.vertex()],t=Rngon.material(),n=Rngon.vector3(0,1,0)){Rngon.assert?.(e instanceof Array,"Expected an array of vertices to make an ngon."),Rngon.assert?.(t instanceof Object,"Expected an object containing user-supplied options."),t=Rngon.material(t),Array.isArray(n)||(n=new Array(e.length).fill().map((e=>Rngon.vector3(n.x,n.y,n.z))));const r=n.reduce(((e,t)=>(e.x+=t.x,e.y+=t.y,e.z+=t.z,e)),Rngon.vector3(0,0,0));Rngon.vector3.normalize(r);{const t=e.map((e=>e.u)).some((e=>e<0)),n=e.map((e=>e.v)).some((e=>e<0));if(t||n)for(const r of e)t&&0===r.u&&(r.u=-Number.EPSILON),n&&0===r.v&&(r.v=-Number.EPSILON)}return{vertices:e,vertexNormals:n,normal:r,material:t,mipLevel:0}}b.object_space_matrix=function(e){const t=Rngon.matrix44.translation(e.translation.x,e.translation.y,e.translation.z),n=Rngon.matrix44.rotation(e.rotation.x,e.rotation.y,e.rotation.z),r=Rngon.matrix44.scaling(e.scale.x,e.scale.y,e.scale.z);return Rngon.matrix44.multiply(Rngon.matrix44.multiply(t,n),r)},S.perspective_divide=function(e){for(const t of e.vertices)Rngon.vertex.perspective_divide(t)},S.transform=function(e,t){for(const n of e.vertices)Rngon.vertex.transform(n,t)};const M=["x","y","z"],_=[1,-1];S.clip_to_viewport=function(e){for(const t of M)for(const n of _){if(!e.vertices.length)break;if(1==e.vertices.length){if(e.vertices[0].x<=e.vertices[0].w&&-e.vertices[0].x<=e.vertices[0].w&&e.vertices[0].y<=e.vertices[0].w&&-e.vertices[0].y<=e.vertices[0].w&&e.vertices[0].z<=e.vertices[0].w&&-e.vertices[0].z<=e.vertices[0].w)break;e.vertices.length=0;break}let r=e.vertices[e.vertices.length-(2==e.vertices.length?2:1)],a=r[t]*n,o=a<=r.w,i=0,s=e.vertices.length;for(let l=0;l"function"==typeof e)),t.usePalette=Array.isArray(e.palette),t.palette=e.palette,t.modules.rasterize=e.modules.rasterize||Rngon.baseModules.rasterize,t.modules.transform_clip_light=e.modules.transformClipLight||Rngon.baseModules.transform_clip_light,t.modules.surface_wipe=e.modules.surfaceWipe||Rngon.baseModules.surface_wipe},prepare_ngon_cache:function(e=[Rngon.ngon()]){Rngon.assert?.(e instanceof Array,"Invalid arguments to n-gon cache initialization.");const t=Rngon.internalState.ngonCache,n=e.reduce(((e,t)=>e+t.ngons.length),0);if(!t||!t.ngons.length||t.ngons.lengthRngon.ngon())))}t.count=0},prepare_vertex_cache:function(e=[Rngon.ngon()]){Rngon.assert?.(e instanceof Array,"Invalid arguments to n-gon cache initialization.");const t=Rngon.internalState.vertexCache;let n=0;for(const t of e)for(const e of t.ngons)n+=e.vertices.length;if(!t||!t.vertices.length||t.vertices.lengthRngon.vertex())))}t.count=0},depth_sort_ngon_cache:function(e=""){const t=Rngon.internalState.ngonCache.ngons;switch(e){case"none":break;case"painter":t.sort(((e,t)=>{const n=e.isActive?e.vertices.reduce(((e,t)=>e+t.z),0)/e.vertices.length:-Number.MAX_VALUE,r=t.isActive?t.vertices.reduce(((e,t)=>e+t.z),0)/t.vertices.length:-Number.MAX_VALUE;return n===r?0:n{const n=e.isActive?e.vertices.reduce(((e,t)=>e+t.z),0)/e.vertices.length:Number.MAX_VALUE,r=t.isActive?t.vertices.reduce(((e,t)=>e+t.z),0)/t.vertices.length:Number.MAX_VALUE;return n===r?0:n>r?1:-1}))}},mark_npot_textures_in_ngon_cache:function(){for(let e=0;e0&&a>0,"Couldn't retrieve the canvas's dimensions."),e.setAttribute("width",r),e.setAttribute("height",a),{surfaceWidth:r,surfaceHeight:a,canvasElement:e,renderContext:n}})()),t.pixelBuffer.width==r&&t.pixelBuffer.height==a||(t.pixelBuffer=o.createImageData(r,a)),(t.usePixelShader&&t.fragmentBuffer.width!=r||t.fragmentBuffer.height!=a)&&(t.fragmentBuffer.width=r,t.fragmentBuffer.height=a,t.fragmentBuffer.data=new Array(r*a).fill().map((e=>({})))),(t.useDepthBuffer&&t.depthBuffer.width!=r||t.depthBuffer.height!=a||!t.depthBuffer.data.length)&&(t.depthBuffer.width=r,t.depthBuffer.height=a,t.depthBuffer.data=new Array(t.depthBuffer.width*t.depthBuffer.height))}catch(e){return Rngon.log(`Failed to create a render surface. ${e}`),null}const i=Rngon.matrix44.multiply(Rngon.matrix44.rotation(t.cameraDirection.x,t.cameraDirection.y,t.cameraDirection.z),Rngon.matrix44.translation(-t.cameraPosition.x,-t.cameraPosition.y,-t.cameraPosition.z)),s=Rngon.matrix44.perspective(t.fov*(Math.PI/180),r/a,t.nearPlaneDistance,t.farPlaneDistance),l=Rngon.matrix44.ortho(r+1,a+1),d=Object.freeze({width:r,height:a,display_meshes:function(e=[]){t.modules.surface_wipe(),Rngon.renderShared.prepare_vertex_cache(e),Rngon.renderShared.prepare_ngon_cache(e);for(const n of e)t.modules.transform_clip_light(n.ngons,Rngon.mesh.object_space_matrix(n),i,s,l,t.cameraPosition);if(Rngon.renderShared.mark_npot_textures_in_ngon_cache(),Rngon.renderShared.depth_sort_ngon_cache(t.depthSortingMode),t.modules.rasterize(t.auxiliaryBuffers),t.usePixelShader){const e={renderWidth:r,renderHeight:a,fragmentBuffer:t.fragmentBuffer.data,pixelBuffer:t.pixelBuffer.data,ngonCache:t.ngonCache.ngons,cameraPosition:t.cameraPosition},n=`{${Object.keys(e).join(",")}}`;switch(typeof t.pixel_shader){case"function":t.pixel_shader(e);break;case"string":Function(n,`(${t.pixel_shader})(${n})`)(e);break;default:Rngon.$throw("Unrecognized type of pixel shader function.")}}n||(t.useContextShader?t.context_shader({context:o,image:t.pixelBuffer}):(t.pixelBuffer.palette=t.palette,o.putImageData(t.pixelBuffer,0,0)))},is_in_view:function(){if(n)return!0;const t=window.innerHeight,r=e.getBoundingClientRect();return r.top>-r.height&&r.top=0&&e.height>=0,"Expected texture width and height to be no less than zero."),Rngon.assert?.(e.width<=32768&&e.height<=32768,"Expected texture width/height to be no more than 32768/32768."),"none"!==e.encoding&&("base64"===e.encoding?(Rngon.assert?.("rgba:5+5+5+1"===e.channels,"Expected Base64-encoded data to be in RGBA 5551 format."),e.pixels=(()=>{const t=[],n=atob(e.pixels);Rngon.assert?.(n.length===e.width*e.height*2,"Unexpected data length for a Base64-encoded texture.");for(let r=0;r>5&31)),t.push(8*(e>>10&31)),t.push(255*(e>>15&1))}return t})()):"none"!==e.encoding&&Rngon.$throw("Unknown texture data encoding '"+e.encoding+"'.")),Rngon.assert?.(e.pixels.length===e.width*e.height*4,"The texture's pixel array size doesn't match its width and height.");const t=[];for(let n=0;n0,"Failed to generate mip levels for a texture.");break}}return{width:e.width,height:e.height,pixels:t,mipLevels:n}}A.deep_copy=function(e){const t=new Array(e.width*e.height*4);for(let n=0;n{fetch(e).then((e=>e.json())).then((e=>{t(Rngon.texture_rgba(e))})).catch((t=>{Rngon.$throw(`Failed to create a texture with data from file '${e}'. Error: '${t}'.`)}))}))};const C=[0,.0061359,.0122715,.0184067,.0245412,.0306748,.0368072,.0429383,.0490677,.0551952,.0613207,.0674439,.0735646,.0796824,.0857973,.091909,.0980171,.1041216,.1102222,.1163186,.1224107,.1284981,.1345807,.1406582,.1467305,.1527972,.1588581,.1649131,.1709619,.1770042,.1830399,.1890687,.1950903,.2011046,.2071114,.2131103,.2191012,.2250839,.2310581,.2370236,.2429802,.2489276,.2548657,.2607941,.2667128,.2726214,.2785197,.2844075,.2902847,.2961509,.3020059,.3078496,.3136817,.319502,.3253103,.3311063,.3368899,.3426607,.3484187,.3541635,.359895,.365613,.3713172,.3770074,.3826834,.388345,.393992,.3996242,.4052413,.4108432,.4164296,.4220003,.4275551,.4330938,.4386162,.4441221,.4496113,.4550836,.4605387,.4659765,.4713967,.4767992,.4821838,.4875502,.4928982,.4982277,.5035384,.5088301,.5141027,.519356,.5245897,.5298036,.5349976,.5401715,.545325,.550458,.5555702,.5606616,.5657318,.5707807,.5758082,.580814,.5857979,.5907597,.5956993,.6006165,.605511,.6103828,.6152316,.6200572,.6248595,.6296382,.6343933,.6391244,.6438315,.6485144,.6531728,.6578067,.6624158,.6669999,.671559,.6760927,.680601,.6850837,.6895405,.6939715,.6983762,.7027547,.7071068,.7114322,.7157308,.7200025,.7242471,.7284644,.7326543,.7368166,.7409511,.7450578,.7491364,.7531868,.7572088,.7612024,.7651673,.7691033,.7730105,.7768885,.7807372,.7845566,.7883464,.7921066,.7958369,.7995373,.8032075,.8068476,.8104572,.8140363,.8175848,.8211025,.8245893,.828045,.8314696,.8348629,.8382247,.841555,.8448536,.8481203,.8513552,.854558,.8577286,.8608669,.8639729,.8670462,.870087,.873095,.8760701,.8790122,.8819213,.8847971,.8876396,.8904487,.8932243,.8959662,.8986745,.9013488,.9039893,.9065957,.909168,.911706,.9142098,.9166791,.9191139,.921514,.9238795,.9262102,.9285061,.930767,.9329928,.9351835,.937339,.9394592,.9415441,.9435935,.9456073,.9475856,.9495282,.951435,.953306,.9551412,.9569403,.9587035,.9604305,.9621214,.9637761,.9653944,.9669765,.9685221,.9700313,.9715039,.97294,.9743394,.9757021,.9770281,.9783174,.9795698,.9807853,.9819639,.9831055,.9842101,.9852776,.9863081,.9873014,.9882576,.9891765,.9900582,.9909026,.9917098,.9924795,.9932119,.993907,.9945646,.9951847,.9957674,.9963126,.9968203,.9972905,.9977231,.9981181,.9984756,.9987955,.9990777,.9993224,.9995294,.9996988,.9998306,.9999247,.9999812,1,.9999812,.9999247,.9998306,.9996988,.9995294,.9993224,.9990777,.9987955,.9984756,.9981181,.9977231,.9972905,.9968203,.9963126,.9957674,.9951847,.9945646,.993907,.9932119,.9924795,.9917098,.9909026,.9900582,.9891765,.9882576,.9873014,.9863081,.9852776,.9842101,.9831055,.9819639,.9807853,.9795698,.9783174,.9770281,.9757021,.9743394,.97294,.9715039,.9700313,.9685221,.9669765,.9653944,.9637761,.9621214,.9604305,.9587035,.9569403,.9551412,.953306,.951435,.9495282,.9475856,.9456073,.9435935,.9415441,.9394592,.937339,.9351835,.9329928,.930767,.9285061,.9262102,.9238795,.921514,.9191139,.9166791,.9142098,.911706,.909168,.9065957,.9039893,.9013488,.8986745,.8959662,.8932243,.8904487,.8876396,.8847971,.8819213,.8790122,.8760701,.873095,.870087,.8670462,.8639729,.8608669,.8577286,.854558,.8513552,.8481203,.8448536,.841555,.8382247,.8348629,.8314696,.828045,.8245893,.8211025,.8175848,.8140363,.8104572,.8068476,.8032075,.7995373,.7958369,.7921066,.7883464,.7845566,.7807372,.7768885,.7730105,.7691033,.7651673,.7612024,.7572088,.7531868,.7491364,.7450578,.7409511,.7368166,.7326543,.7284644,.7242471,.7200025,.7157308,.7114322,.7071068,.7027547,.6983762,.6939715,.6895405,.6850837,.680601,.6760927,.671559,.6669999,.6624158,.6578067,.6531728,.6485144,.6438315,.6391244,.6343933,.6296382,.6248595,.6200572,.6152316,.6103828,.605511,.6006165,.5956993,.5907597,.5857979,.580814,.5758082,.5707807,.5657318,.5606616,.5555702,.550458,.545325,.5401715,.5349976,.5298036,.5245897,.519356,.5141027,.5088301,.5035384,.4982277,.4928982,.4875502,.4821838,.4767992,.4713967,.4659765,.4605387,.4550836,.4496113,.4441221,.4386162,.4330938,.4275551,.4220003,.4164296,.4108432,.4052413,.3996242,.393992,.388345,.3826834,.3770074,.3713172,.365613,.359895,.3541635,.3484187,.3426607,.3368899,.3311063,.3253103,.319502,.3136817,.3078496,.3020059,.2961509,.2902847,.2844075,.2785197,.2726214,.2667128,.2607941,.2548657,.2489276,.2429802,.2370236,.2310581,.2250839,.2191012,.2131103,.2071114,.2011046,.1950903,.1890687,.1830399,.1770042,.1709619,.1649131,.1588581,.1527972,.1467305,.1406582,.1345807,.1284981,.1224107,.1163186,.1102222,.1041216,.0980171,.091909,.0857973,.0796824,.0735646,.0674439,.0613207,.0551952,.0490677,.0429383,.0368072,.0306748,.0245412,.0184067,.0122715,.0061359,0,-.0061359,-.0122715,-.0184067,-.0245412,-.0306748,-.0368072,-.0429383,-.0490677,-.0551952,-.0613207,-.0674439,-.0735646,-.0796824,-.0857973,-.091909,-.0980171,-.1041216,-.1102222,-.1163186,-.1224107,-.1284981,-.1345807,-.1406582,-.1467305,-.1527972,-.1588581,-.1649131,-.1709619,-.1770042,-.1830399,-.1890687,-.1950903,-.2011046,-.2071114,-.2131103,-.2191012,-.2250839,-.2310581,-.2370236,-.2429802,-.2489276,-.2548657,-.2607941,-.2667128,-.2726214,-.2785197,-.2844075,-.2902847,-.2961509,-.3020059,-.3078496,-.3136817,-.319502,-.3253103,-.3311063,-.3368899,-.3426607,-.3484187,-.3541635,-.359895,-.365613,-.3713172,-.3770074,-.3826834,-.388345,-.393992,-.3996242,-.4052413,-.4108432,-.4164296,-.4220003,-.4275551,-.4330938,-.4386162,-.4441221,-.4496113,-.4550836,-.4605387,-.4659765,-.4713967,-.4767992,-.4821838,-.4875502,-.4928982,-.4982277,-.5035384,-.5088301,-.5141027,-.519356,-.5245897,-.5298036,-.5349976,-.5401715,-.545325,-.550458,-.5555702,-.5606616,-.5657318,-.5707807,-.5758082,-.580814,-.5857979,-.5907597,-.5956993,-.6006165,-.605511,-.6103828,-.6152316,-.6200572,-.6248595,-.6296382,-.6343933,-.6391244,-.6438315,-.6485144,-.6531728,-.6578067,-.6624158,-.6669999,-.671559,-.6760927,-.680601,-.6850837,-.6895405,-.6939715,-.6983762,-.7027547,-.7071068,-.7114322,-.7157308,-.7200025,-.7242471,-.7284644,-.7326543,-.7368166,-.7409511,-.7450578,-.7491364,-.7531868,-.7572088,-.7612024,-.7651673,-.7691033,-.7730105,-.7768885,-.7807372,-.7845566,-.7883464,-.7921066,-.7958369,-.7995373,-.8032075,-.8068476,-.8104572,-.8140363,-.8175848,-.8211025,-.8245893,-.828045,-.8314696,-.8348629,-.8382247,-.841555,-.8448536,-.8481203,-.8513552,-.854558,-.8577286,-.8608669,-.8639729,-.8670462,-.870087,-.873095,-.8760701,-.8790122,-.8819213,-.8847971,-.8876396,-.8904487,-.8932243,-.8959662,-.8986745,-.9013488,-.9039893,-.9065957,-.909168,-.911706,-.9142098,-.9166791,-.9191139,-.921514,-.9238795,-.9262102,-.9285061,-.930767,-.9329928,-.9351835,-.937339,-.9394592,-.9415441,-.9435935,-.9456073,-.9475856,-.9495282,-.951435,-.953306,-.9551412,-.9569403,-.9587035,-.9604305,-.9621214,-.9637761,-.9653944,-.9669765,-.9685221,-.9700313,-.9715039,-.97294,-.9743394,-.9757021,-.9770281,-.9783174,-.9795698,-.9807853,-.9819639,-.9831055,-.9842101,-.9852776,-.9863081,-.9873014,-.9882576,-.9891765,-.9900582,-.9909026,-.9917098,-.9924795,-.9932119,-.993907,-.9945646,-.9951847,-.9957674,-.9963126,-.9968203,-.9972905,-.9977231,-.9981181,-.9984756,-.9987955,-.9990777,-.9993224,-.9995294,-.9996988,-.9998306,-.9999247,-.9999812,-1,-.9999812,-.9999247,-.9998306,-.9996988,-.9995294,-.9993224,-.9990777,-.9987955,-.9984756,-.9981181,-.9977231,-.9972905,-.9968203,-.9963126,-.9957674,-.9951847,-.9945646,-.993907,-.9932119,-.9924795,-.9917098,-.9909026,-.9900582,-.9891765,-.9882576,-.9873014,-.9863081,-.9852776,-.9842101,-.9831055,-.9819639,-.9807853,-.9795698,-.9783174,-.9770281,-.9757021,-.9743394,-.97294,-.9715039,-.9700313,-.9685221,-.9669765,-.9653944,-.9637761,-.9621214,-.9604305,-.9587035,-.9569403,-.9551412,-.953306,-.951435,-.9495282,-.9475856,-.9456073,-.9435935,-.9415441,-.9394592,-.937339,-.9351835,-.9329928,-.930767,-.9285061,-.9262102,-.9238795,-.921514,-.9191139,-.9166791,-.9142098,-.911706,-.909168,-.9065957,-.9039893,-.9013488,-.8986745,-.8959662,-.8932243,-.8904487,-.8876396,-.8847971,-.8819213,-.8790122,-.8760701,-.873095,-.870087,-.8670462,-.8639729,-.8608669,-.8577286,-.854558,-.8513552,-.8481203,-.8448536,-.841555,-.8382247,-.8348629,-.8314696,-.828045,-.8245893,-.8211025,-.8175848,-.8140363,-.8104572,-.8068476,-.8032075,-.7995373,-.7958369,-.7921066,-.7883464,-.7845566,-.7807372,-.7768885,-.7730105,-.7691033,-.7651673,-.7612024,-.7572088,-.7531868,-.7491364,-.7450578,-.7409511,-.7368166,-.7326543,-.7284644,-.7242471,-.7200025,-.7157308,-.7114322,-.7071068,-.7027547,-.6983762,-.6939715,-.6895405,-.6850837,-.680601,-.6760927,-.671559,-.6669999,-.6624158,-.6578067,-.6531728,-.6485144,-.6438315,-.6391244,-.6343933,-.6296382,-.6248595,-.6200572,-.6152316,-.6103828,-.605511,-.6006165,-.5956993,-.5907597,-.5857979,-.580814,-.5758082,-.5707807,-.5657318,-.5606616,-.5555702,-.550458,-.545325,-.5401715,-.5349976,-.5298036,-.5245897,-.519356,-.5141027,-.5088301,-.5035384,-.4982277,-.4928982,-.4875502,-.4821838,-.4767992,-.4713967,-.4659765,-.4605387,-.4550836,-.4496113,-.4441221,-.4386162,-.4330938,-.4275551,-.4220003,-.4164296,-.4108432,-.4052413,-.3996242,-.393992,-.388345,-.3826834,-.3770074,-.3713172,-.365613,-.359895,-.3541635,-.3484187,-.3426607,-.3368899,-.3311063,-.3253103,-.319502,-.3136817,-.3078496,-.3020059,-.2961509,-.2902847,-.2844075,-.2785197,-.2726214,-.2667128,-.2607941,-.2548657,-.2489276,-.2429802,-.2370236,-.2310581,-.2250839,-.2191012,-.2131103,-.2071114,-.2011046,-.1950903,-.1890687,-.1830399,-.1770042,-.1709619,-.1649131,-.1588581,-.1527972,-.1467305,-.1406582,-.1345807,-.1284981,-.1224107,-.1163186,-.1102222,-.1041216,-.0980171,-.091909,-.0857973,-.0796824,-.0735646,-.0674439,-.0613207,-.0551952,-.0490677,-.0429383,-.0368072,-.0306748,-.0245412,-.0184067,-.0122715,-.0061359,-0,.0061359,.0122715,.0184067,.0245412,.0306748,.0368072,.0429383,.0490677,.0551952,.0613207,.0674439,.0735646,.0796824,.0857973,.091909,.0980171,.1041216,.1102222,.1163186,.1224107,.1284981,.1345807,.1406582,.1467305,.1527972,.1588581,.1649131,.1709619,.1770042,.1830399,.1890687,.1950903,.2011046,.2071114,.2131103,.2191012,.2250839,.2310581,.2370236,.2429802,.2489276,.2548657,.2607941,.2667128,.2726214,.2785197,.2844075,.2902847,.2961509,.3020059,.3078496,.3136817,.319502,.3253103,.3311063,.3368899,.3426607,.3484187,.3541635,.359895,.365613,.3713172,.3770074,.3826834,.388345,.393992,.3996242,.4052413,.4108432,.4164296,.4220003,.4275551,.4330938,.4386162,.4441221,.4496113,.4550836,.4605387,.4659765,.4713967,.4767992,.4821838,.4875502,.4928982,.4982277,.5035384,.5088301,.5141027,.519356,.5245897,.5298036,.5349976,.5401715,.545325,.550458,.5555702,.5606616,.5657318,.5707807,.5758082,.580814,.5857979,.5907597,.5956993,.6006165,.605511,.6103828,.6152316,.6200572,.6248595,.6296382,.6343933,.6391244,.6438315,.6485144,.6531728,.6578067,.6624158,.6669999,.671559,.6760927,.680601,.6850837,.6895405,.6939715,.6983762,.7027547,.7071068,.7114322,.7157308,.7200025,.7242471,.7284644,.7326543,.7368166,.7409511,.7450578,.7491364,.7531868,.7572088,.7612024,.7651673,.7691033,.7730105,.7768885,.7807372,.7845566,.7883464,.7921066,.7958369,.7995373,.8032075,.8068476,.8104572,.8140363,.8175848,.8211025,.8245893,.828045,.8314696,.8348629,.8382247,.841555,.8448536,.8481203,.8513552,.854558,.8577286,.8608669,.8639729,.8670462,.870087,.873095,.8760701,.8790122,.8819213,.8847971,.8876396,.8904487,.8932243,.8959662,.8986745,.9013488,.9039893,.9065957,.909168,.911706,.9142098,.9166791,.9191139,.921514,.9238795,.9262102,.9285061,.930767,.9329928,.9351835,.937339,.9394592,.9415441,.9435935,.9456073,.9475856,.9495282,.951435,.953306,.9551412,.9569403,.9587035,.9604305,.9621214,.9637761,.9653944,.9669765,.9685221,.9700313,.9715039,.97294,.9743394,.9757021,.9770281,.9783174,.9795698,.9807853,.9819639,.9831055,.9842101,.9852776,.9863081,.9873014,.9882576,.9891765,.9900582,.9909026,.9917098,.9924795,.9932119,.993907,.9945646,.9951847,.9957674,.9963126,.9968203,.9972905,.9977231,.9981181,.9984756,.9987955,.9990777,.9993224,.9995294,.9996988,.9998306,.9999247,.9999812],W={sin:e=>C[e>>6],cos:e=>C[256+(e>>6)],deg:e=>182.04166666666666*(e>=0?e%360:360-Math.abs(e)%360)};function E(e,t){e||Rngon.$throw(t)}function P(e,t,n){return e+n*(t-e)}function I(e,t=.5,n=t){const r=Rngon.lerp(e(0,0),e(0,1),n),a=Rngon.lerp(e(1,0),e(1,1),n);return Rngon.lerp(r,a,t)}function D(e=""){throw Rngon.internalState.allowWindowAlert&&window.alert("Retro n-gon error: "+e),Error("Retro n-gon error: "+e)}function j(e="Hello there."){console.log("Retro n-gon: "+e)}function L(e,t){return Math.floor(parseInt(window.getComputedStyle(e).getPropertyValue("width"))*t)}function X(e,t){return Math.floor(parseInt(window.getComputedStyle(e).getPropertyValue("height"))*t)}function T(e=0,t=0,n=0){return Rngon.assert?.("number"==typeof e&&"number"==typeof t&&"number"==typeof n,"Expected numbers as parameters to the vector3 factory."),{x:e,y:t,z:n}}const k=T,N=T,O=(e,t,n)=>Rngon.vector3(Rngon.trig.deg(e),Rngon.trig.deg(t),Rngon.trig.deg(n));function U(e=0,t=0,n=0,r=0,a=0,o=1,i=1,s=e,l=t,d=n,h=0,c=1,g=0){return Rngon.assert?.("number"==typeof e&&"number"==typeof t&&"number"==typeof n&&"number"==typeof o&&"number"==typeof r&&"number"==typeof a&&"number"==typeof s&&"number"==typeof l&&"number"==typeof d,"Expected numbers as parameters to the vertex factory."),{x:e,y:t,z:n,u:r,v:a,w:o,shade:i,worldX:s,worldY:l,worldZ:d,normalX:h,normalY:c,normalZ:g}}T.transform=function(e,t=[]){Rngon.assert?.(16===t.length,"Expected a 4 x 4 matrix to transform the vector by.");const n=t[0]*e.x+t[4]*e.y+t[8]*e.z,r=t[1]*e.x+t[5]*e.y+t[9]*e.z,a=t[2]*e.x+t[6]*e.y+t[10]*e.z;e.x=n,e.y=r,e.z=a},T.normalize=function(e){const t=e.x*e.x+e.y*e.y+e.z*e.z;if(0!=t&&1!=t){const n=1/Math.sqrt(t);e.x*=n,e.y*=n,e.z*=n}},T.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z},T.mul_scalar=function(e,t){return Rngon.vector3(e.x*t,e.y*t,e.z*t)},T.add_scalar=function(e,t){return Rngon.vector3(e.x+t,e.y+t,e.z+t)},T.sub_scalar=function(e,t){return Rngon.vector3(e.x-t,e.y-t,e.z-t)},T.mul=function(e,t){return Rngon.vector3(e.x*t.x,e.y*t.y,e.z*t.z)},T.add=function(e,t){return Rngon.vector3(e.x+t.x,e.y+t.y,e.z+t.z)},T.sub=function(e,t){return Rngon.vector3(e.x-t.x,e.y-t.y,e.z-t.z)},T.cross=function(e,t){const n=Rngon.vector3();return n.x=e.y*t.z-e.z*t.y,n.y=e.z*t.x-e.x*t.z,n.z=e.x*t.y-e.y*t.x,n},T.invert=function(e){e.x*=-1,e.y*=-1,e.z*=-1},U.transform=function(e,t=[]){Rngon.assert?.(16===t.length,"Expected a 4 x 4 matrix to transform the vertex by.");const n=t[0]*e.x+t[4]*e.y+t[8]*e.z+t[12]*e.w,r=t[1]*e.x+t[5]*e.y+t[9]*e.z+t[13]*e.w,a=t[2]*e.x+t[6]*e.y+t[10]*e.z+t[14]*e.w,o=t[3]*e.x+t[7]*e.y+t[11]*e.z+t[15]*e.w;e.x=n,e.y=r,e.z=a,e.w=o},U.perspective_divide=function(e){e.x/=e.w,e.y/=e.w};const V={family:"beta",major:"5",minor:"0",dev:!0},Y={rasterize:p,surface_wipe:function(){Rngon.internalState.pixelBuffer.data.fill(0),Rngon.internalState.useDepthBuffer&&Rngon.internalState.depthBuffer.data.fill(Rngon.internalState.depthBuffer.clearValue)},transform_clip_light:function(e=[],t=[],n=[],r=[],a=[],o){const i={x:0,y:0,z:0},s=Rngon.internalState.ngonCache,l=Rngon.internalState.vertexCache,d=Rngon.matrix44.multiply(r,n);for(const n of e){if(!n.material.hasWireframe&&n.material.allowAlphaReject&&n.material.color.alpha<=0)continue;if(!n.material.isTwoSided&&(i.x=n.vertices[0].x-o.x,i.y=n.vertices[0].y-o.y,i.z=n.vertices[0].z-o.z,Rngon.vector3.dot(n.normal,i)>=0))continue;const e=s.ngons[s.count++];e.vertices.length=0;for(let t=0;t(()=>{var e={962:()=>{if("function"!=typeof importScripts){class e{#e;#t;#n;data;constructor(e,t){if(isNaN(e)||isNaN(t))throw new Error("This interface supports only numeric 'width' and 'height' as arguments.");this.#t=e,this.#n=t,this.data=new Array(e*t),this.palette=[[0,0,0,0]]}get palette(){return this.#e}set palette(e){if(!Array.isArray(e))throw new Error("The palette must be an array.");if(e.length<1)throw new Error("A palette must consist of at least one color.");if(!e.every((e=>Array.isArray(e))))throw new Error("Each entry in the palette must be a sub-array of color channel values.");e.forEach((e=>{e.length=4,void 0===e[3]&&(e[3]=255)}));const t={byte:e,dword:new Uint32Array(e.map((e=>e[3]<<24|e[2]<<16|e[1]<<8|e[0])))};this.#e=new Proxy(t,{set:(e,t,n)=>(e.byte[t]=n,this.palette=e.byte,!0),get:(e,t)=>e[t]||e.byte[t]})}get width(){return this.#t}get height(){return this.#n}get colorSpace(){return"indexed"}}class t{#r;#a;#t;#n;constructor(e){if(!(e instanceof CanvasRenderingContext2D))throw new Error("CanvasRenderingContextIndexed requires an instance of CanvasRenderingContext2D as an argument.");if(this.#r=e,this.#t=this.#r.canvas.width,this.#n=this.#r.canvas.height,this.#a=this.#r.createImageData(this.#t,this.#n),this.#a.data.fill(0),isNaN(this.#t)||isNaN(this.#n)||this.#n<1||this.#t<1)throw new Error("Invalid context resolution.")}createImageData(t=this.#t,n=this.#n){if(t instanceof ImageData)throw new Error("This interface supports only 'width' and 'height' as arguments.");if(t!==this.#t||n!==this.#n)throw new Error("This interface can only create images whose resolution matches the size of the canvas.");return new e(t,n)}getImageData(){return this.#a}putImageData(t){if(!(t instanceof e))throw new Error("Only images of type IndexedImageData can be rendered.");if(t.width!==this.#t||t.height!==this.#n)throw new Error("Mismatched image resolution: images must be the size of the canvas.");{const e=t.palette.dword,n=new Uint32Array(this.#a.data.buffer);for(let r=0;r{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};return(()=>{"use strict";function e(e,t=[Rngon.mesh()],n={}){const r=Rngon.renderShared.setup_render_call_info();n=Object.freeze({...Rngon.renderShared.defaultRenderOptions,...n}),Rngon.renderShared.initialize_internal_render_state(n),"string"==typeof e&&(e=document.getElementById(e)),Rngon.assert?.(e instanceof HTMLCanvasElement,"Invalid canvas element for rendering into."),Rngon.assert?.(!Rngon.internalState.usePalette||e instanceof HTMLPalettedCanvasElement,"For paletted rendering, the attribute is='paletted-canvas' must be present on the target .");{const a=Rngon.surface(e,n);!a||n.hibernateWhenNotOnScreen&&!a.is_in_view()||(a.display_meshes(t),r.renderWidth=a.width,r.renderHeight=a.height,r.numNgonsRendered=Rngon.internalState.ngonCache.count)}return r.totalRenderTimeMs=performance.now()-r.totalRenderTimeMs,r}async function t(e=[Rngon.mesh()],t={},n=null){return t.modules={rasterize:null,transformClipLight:null},new Promise(((r,o)=>{const i=new Worker(URL.createObjectURL(new Blob([`(${a.toString()})()`],{type:"text/javascript"})));i.onmessage=e=>{if(i.terminate(),"string"==typeof(e=e.data).type)switch(e.type){case"rendering-finished":delete e.type,r(e);break;case"error":o(`A render worker reported the following error: ${e.errorText}`);break;default:o("A render worker sent an unrecognized message.")}else o("A render worker sent an invalid message.")},null===n&&(n=Array.from(document.getElementsByTagName("script")).filter((e=>e.src.endsWith("rngon.cat.js")))[0].src),i.postMessage({type:"render",meshes:e,options:t,rngonUrl:n})}))}function a(){onmessage=e=>{if("string"==typeof(e=e.data).type)if("render"===e.type)try{importScripts(e.rngonUrl),function(e,t){Rngon.assert?.(Array.isArray(e),"Expected meshes to be provided in an array.");const n=Rngon.renderShared.setup_render_call_info(),r=Object.freeze({...Rngon.renderShared.defaultRenderOptions,...t});Rngon.renderShared.initialize_internal_render_state(r),Rngon.internalState.allowWindowAlert=!1;{const t=Rngon.surface(null,r);Rngon.assert?.(t,"Failed to initialize the render surface."),t.display_meshes(e),n.renderWidth=r.width,n.renderHeight=r.height,n.numNgonsRendered=Rngon.internalState.ngonCache.count,n.image=Rngon.internalState.pixelBuffer}n.totalRenderTimeMs=performance.now()-n.totalRenderTimeMs,postMessage({...n,type:"rendering-finished"})}(e.meshes,e.options)}catch(e){postMessage({type:"error",errorText:e.message})}else postMessage({type:"error",errorText:"Received an unrecognized message."});else postMessage({type:"error",errorText:"A render worker received an invalid message."})}}function o({ngon:e,ngonIdx:t,leftEdges:n,rightEdges:r,numLeftEdges:a,numRightEdges:o,pixelBuffer32:i,auxiliaryBuffers:s}){const l=Rngon.internalState.usePalette,d=Rngon.internalState.usePixelShader,h=Rngon.internalState.fragmentBuffer.data,c=Rngon.internalState.useDepthBuffer?Rngon.internalState.depthBuffer.data:null,g=Rngon.internalState.pixelBuffer,f=g.data,u=g.width,p=e.material,m=p.texture||null;let x=null,v=0;if(m){const t=m.mipLevels.length;v=Math.max(0,Math.min(t-1,Math.round((t-1)*e.mipLevel))),x=m.mipLevels[v]}let w=0,R=0,y=n[w],b=r[R];if(!a||!o)return;const S=n[0].top,M=n[a-1].bottom;for(let e=S;e0){const n=(b.start.depth-y.start.depth)/g;let r=y.start.depth-n;const v=(b.start.shade-y.start.shade)/g;let w=y.start.shade-v;const R=(b.start.u-y.start.u)/g;let P=y.start.u-R;const D=(b.start.v-y.start.v)/g;let W=y.start.v-D;const I=(b.start.invW-y.start.invW)/g;let N=y.start.invW-I;if(d)var _=(b.start.worldX-y.start.worldX)/g,z=y.start.worldX-_,B=(b.start.worldY-y.start.worldY)/g,C=y.start.worldY-B,A=(b.start.worldZ-y.start.worldZ)/g,E=y.start.worldZ-A;let j=a+e*u-1;for(let u=a;u=x.width||y>=x.height){const e=o<0,t=y<0;o=Math.abs(o)%x.width,y=Math.abs(y)%x.height,e&&(o=x.width-o),t&&(y=x.height-y)}break;case"ortho":{const t=M-S,n=e-S+1;o=(u-a+1)*(x.width/g),y=n*(x.height/t),y=x.height-y;break}default:Rngon.$throw("Unknown texture-mapping mode.")}const t=x.pixels[~~o+~~y*x.width];if(!t)continue;if(p.allowAlphaReject&&255!==t.alpha)continue;if(p.allowAlphaBlend&&Rngon.baseModules.rasterize.stipple(p.color.alpha,u,e))continue;O=t.index,T=t.red*p.color.unitRange.red*L,X=t.green*p.color.unitRange.green*L,k=t.blue*p.color.unitRange.blue*L}else{if(p.allowAlphaBlend&&Rngon.baseModules.rasterize.stipple(p.color.alpha,u,e))continue;O=p.color.index,T=p.color.red*L,X=p.color.green*L,k=p.color.blue*L}if(l)f[j]=O;else if(L>1){const e=4*j;f[e+0]=T,f[e+1]=X,f[e+2]=k,f[e+3]=255}else i[j]=(255<<24)+(k<<16)+(X<<8)+T;if(c&&(c[j]=b),d){const e=h[j];e.ngonIdx=t,e.textureUScaled=~~o,e.textureVScaled=~~y,e.depth=r/N,e.shade=w,e.worldX=z/N,e.worldY=C/N,e.worldZ=E/N,e.w=1/N}for(let e=0;e0){const t=(p.start.depth-u.start.depth)/s;let n=u.start.depth-t;const g=(p.start.shade-u.start.shade)/s;let f=u.start.shade-g;const m=(p.start.invW-u.start.invW)/s;let x=u.start.invW-m,v=r+e*d-1;for(let e=r;e1){const e=4*v;l[e+0]=t,l[e+1]=n,l[e+2]=r,l[e+3]=255}else o[v]=(255<<24)+(r<<16)+(n<<8)+t}h[v]=e}}}u.start.x+=u.delta.x,u.start.depth+=u.delta.depth,u.start.shade+=u.delta.shade,u.start.invW+=u.delta.invW,p.start.x+=p.delta.x,p.start.depth+=p.delta.depth,p.start.shade+=p.delta.shade,p.start.invW+=p.delta.invW,e===u.bottom-1&&(u=t[++g]),e===p.bottom-1&&(p=n[++f])}return!0}function s({ngon:e,leftEdges:t,rightEdges:n,numLeftEdges:r,numRightEdges:a,pixelBuffer32:o}){const i=Rngon.internalState.usePalette,s=Rngon.internalState.pixelBuffer,l=s.data,d=s.width,h=Rngon.internalState.useDepthBuffer?Rngon.internalState.depthBuffer.data:null,c=e.material,g=c.texture||null;let f=null,u=0;if(g){const t=g.mipLevels.length;u=Math.max(0,Math.min(t-1,Math.round((t-1)*e.mipLevel))),f=g.mipLevels[u]}let p=0,m=0,x=t[p],v=n[m];if(!r||!a)return;const w=t[0].top,R=t[r-1].bottom;for(let e=w;e0){const t=(v.start.depth-x.start.depth)/s;let n=x.start.depth-t;const g=(v.start.shade-x.start.shade)/s;let u=x.start.shade-g;const p=(v.start.u-x.start.u)/s;let m=x.start.u-p;const w=(v.start.v-x.start.v)/s;let R=x.start.v-w;const y=(v.start.invW-x.start.invW)/s;let b=x.start.invW-y,S=r+e*d-1;for(let e=r;e1){const e=4*S;l[e+0]=t,l[e+1]=n,l[e+2]=r,l[e+3]=255}else o[S]=(255<<24)+(r<<16)+(n<<8)+t}h[S]=e}}}x.start.x+=x.delta.x,x.start.depth+=x.delta.depth,x.start.shade+=x.delta.shade,x.start.u+=x.delta.u,x.start.v+=x.delta.v,x.start.invW+=x.delta.invW,v.start.x+=v.delta.x,v.start.depth+=v.delta.depth,v.start.shade+=v.delta.shade,v.start.u+=v.delta.u,v.start.v+=v.delta.v,v.start.invW+=v.delta.invW,e===x.bottom-1&&(x=t[++p]),e===v.bottom-1&&(v=n[++m])}return!0}n.r(r),n.d(r,{$throw:()=>I,assert:()=>P,baseModules:()=>Z,bilinear_sample:()=>W,color_index:()=>x,color_rgba:()=>m,internalState:()=>v,lerp:()=>D,light:()=>w,log:()=>N,material:()=>R,matrix44:()=>y,mesh:()=>b,ngon:()=>S,render:()=>e,renderShared:()=>z,render_async:()=>t,renderable_height_of:()=>L,renderable_width_of:()=>j,rotation_vector:()=>O,scaling_vector:()=>k,surface:()=>B,texture_rgba:()=>C,translation_vector:()=>X,trig:()=>E,vector3:()=>T,version:()=>Y,vertex:()=>V}),n(962);const l=500,d=new Array(l),h=new Array(l),c=new Array(l).fill().map((()=>({top:void 0,bottom:void 0,start:{x:void 0,depth:void 0,shade:void 0,u:void 0,v:void 0,invW:void 0,worldX:void 0,worldY:void 0,worldZ:void 0},delta:{}}))),g=new Array(l).fill().map((()=>({top:void 0,bottom:void 0,start:{x:void 0,depth:void 0,shade:void 0,u:void 0,v:void 0,invW:void 0,worldX:void 0,worldY:void 0,worldZ:void 0},delta:{}}))),f=(e,t)=>e.y===t.y?0:e.y=0&&e<=255&&t>=0&&t<=255&&n>=0&&n<=255&&r>=0&&r<=255,"The given color values are out of range."),Object.freeze({red:e,green:t,blue:n,alpha:r,unitRange:Object.freeze({red:e/255,green:t/255,blue:n/255,alpha:r/255})})}function x(e=0){return Rngon.assert?.(e>=0&&e<=255,"The given color index is out of range."),Object.freeze({index:e})}u.polygon=function(e=Rngon.ngon(),t=0,n=[]){Rngon.assert?.(e.vertices.length>=3,"Polygons must have 3 or more vertices"),Rngon.assert?.(e.vertices.length=a?h[b++]=e.vertices[r]:d[y++]=e.vertices[r]}d[y++]=n,h[b++]=n}(),function(){for(let t=1;t!e(r)))){let e=o;!w.texture||!p||a||w.allowAlphaReject||w.allowAlphaBlend||"affine"!==w.textureMapping||255!==w.color.red||255!==w.color.green||255!==w.color.blue?w.texture||!p||a||u||w.allowAlphaReject||w.allowAlphaBlend||(e=i):e=s,e(r)}}if(Rngon.internalState.showGlobalWireframe||w.hasWireframe){for(let e=1;e=c||t>=g)return;const o=e+t*c,i=z/E,f=C/E,u=n.red*f,p=n.green*f,m=n.blue*f;if(a||!l||l[o]>i){if(f>1){const e=4*o;d[e+0]=u,d[e+1]=p,d[e+2]=m,d[e+3]=255}else h[o]=(255<<24)+(m<<16)+(p<<8)+u;if(l&&!a&&(l[o]=i),s){const e=Rngon.internalState.fragmentBuffer.data[o];e.ngonIdx=r,e.textureUScaled=void 0,e.textureVScaled=void 0,e.depth=z/E,e.shade=C/E,e.worldX=D/E,e.worldY=I/E,e.worldZ=j/E,e.w=1/E}}}},u.point=function(e=Rngon.vertex(),t=Rngon.material(),n=0){if(255!=t.color.alpha)return;const r=Rngon.internalState.usePixelShader,a=Rngon.internalState.useDepthBuffer?Rngon.internalState.depthBuffer.data:null,o=Rngon.internalState.pixelBuffer.data,i=new Uint32Array(o.buffer),s=Rngon.internalState.pixelBuffer.width,l=Rngon.internalState.pixelBuffer.height,d=Math.floor(e.x),h=Math.floor(e.y),c=d+h*s;if(d<0||h<0||d>=s||h>=l)return;const g=e.z/Rngon.internalState.farPlaneDistance,f=t.renderVertexShade?e.shade:1,u=t.texture?t.texture.pixels[0]:t.color,p=u.red*f,m=u.green*f,x=u.blue*f;if(!(a&&a[c]<=g)){if(f>1){const e=4*c;o[e+0]=p,o[e+1]=m,o[e+2]=x,o[e+3]=255}else i[c]=(255<<24)+(x<<16)+(m<<8)+p;if(a&&(a[c]=g),r){const t=Rngon.internalState.fragmentBuffer.data[c];t.ngonIdx=n,t.textureUScaled=0,t.textureVScaled=0,t.depth=g,t.shade=f,t.worldX=e.worldX,t.worldY=e.worldY,t.worldZ=e.worldZ,t.w=e.w}}},u.stipple=function(){const e=[{width:8,height:6,pixels:[0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]},{width:4,height:4,pixels:[0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1]},{width:2,height:2,pixels:[1,0,0,1]}];for(let t=e.length-2;t>=0;t--)e.push({width:e[t].width,height:e[t].height,pixels:e[t].pixels.map((e=>Number(!e)))});return function(t,n,r){if(t<=0)return!0;if(t>=255)return!1;{const a=Math.floor(t/(256/e.length)),o=e[a],i=n%o.width+r%o.height*o.width;if(o.pixels[i])return!0}return!1}}();const v={modules:{transform_clip_light:void 0,ngon_fill:void 0,surface_wipe:void 0},useDepthBuffer:!1,depthBuffer:{width:1,height:1,data:new Array(1),clearValue:1/0},depthSortingMode:void 0,auxiliaryBuffers:[],usePalette:!1,palette:void 0,pixelBuffer:new ImageData(1,1),fragmentBuffer:{width:1,height:1,data:new Array(1),clearValue:{ngonIdx:void 0,textureUScaled:void 0,textureVScaled:void 0,textureMipLevelIdx:void 0,worldX:void 0,worldY:void 0,worldZ:void 0,depth:void 0,shade:void 0,w:void 0}},usePixelShader:!1,pixel_shader:void 0,useVertexShader:!1,vertex_shader:void 0,useContextShader:!1,context_shader:void 0,rasterShaders:[],offscreenRenderWidth:1,offscreenRenderHeight:1,renderScale:1,usePerspectiveCorrectInterpolation:!1,showGlobalWireframe:!1,applyViewportClipping:!0,nearPlaneDistance:1,farPlaneDistance:1,fov:45,cameraDirection:void 0,cameraPosition:void 0,allowWindowAlert:!1,ngonCache:{count:0,ngons:[]},vertexCache:{count:0,vertices:[]},lights:[]};function w(e=Rngon.translation_vector(0,0,0),t={}){return w.defaultSettings=w.defaultSettings||{intensity:100,clip:1,attenuation:1},{position:e,...w.defaultSettings,...t}}function R(e={}){return R.default=R.default||{color:Rngon.color_rgba(),wireframeColor:Rngon.color_rgba(),texture:null,textureMapping:"ortho",uvWrapping:"repeat",vertexShading:"none",renderVertexShade:!0,ambientLightLevel:0,hasWireframe:!1,hasFill:!0,isTwoSided:!0,allowTransform:!0,allowAlphaReject:!1,allowAlphaBlend:!1,auxiliary:{}},{...R.default,...e}}const y={scaling:function(e=0,t=0,n=0){return Object.freeze([e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1])},translation:function(e=0,t=0,n=0){return Object.freeze([1,0,0,0,0,1,0,0,0,0,1,0,e,t,n,1])},rotation:function(e=0,t=0,n=0){const r=Rngon.trig.cos,a=Rngon.trig.sin,o=[1,0,0,0,0,r(e),-a(e),0,0,a(e),r(e),0,0,0,0,1],i=[r(t),0,a(t),0,0,1,0,0,-a(t),0,r(t),0,0,0,0,1],s=[r(n),-a(n),0,0,a(n),r(n),0,0,0,0,1,0,0,0,0,1],l=Rngon.matrix44.multiply(i,s),d=Rngon.matrix44.multiply(o,l);return Rngon.assert?.(16===d.length,"Expected a 4 x 4 matrix."),Object.freeze(d)},perspective:function(e=0,t=0,n=0,r=0){const a=Math.tan(e/2),o=n-r;return Object.freeze([1/(a*t),0,0,0,0,1/a,0,0,0,0,(-n-r)/o,1,0,0,2*r*(n/o),0])},ortho:function(e=0,t=0){return Object.freeze([e/2,0,0,0,0,-t/2,0,0,0,0,1,0,e/2-.5,t/2-.5,0,1])},multiply:function(e=[],t=[]){Rngon.assert?.(16===e.length&&16===t.length,"Expected 4 x 4 matrices.");let n=new Array(16);for(let r=0;r<4;r++)for(let a=0;a<4;a++)n[r+4*a]=e[r+0]*t[0+4*a]+e[r+4]*t[1+4*a]+e[r+8]*t[2+4*a]+e[r+12]*t[3+4*a];return Object.freeze(n)}};function b(e=[Rngon.ngon()],t={}){return Rngon.assert?.(e instanceof Array,"Expected a list of ngons for creating an ngon mesh."),Rngon.assert?.(t instanceof Object,"Expected an object with transformation properties."),b.defaultTransform=b.defaultTransform||{translation:Rngon.translation_vector(0,0,0),rotation:Rngon.rotation_vector(0,0,0),scaling:Rngon.scaling_vector(1,1,1)},Rngon.assert?.(void 0!==Rngon.mesh.defaultTransform?.rotation&&void 0!==Rngon.mesh.defaultTransform?.translation&&void 0!==Rngon.mesh.defaultTransform?.scaling,"The default transforms object for mesh() is missing required properties."),{ngons:e,rotation:(t={...Rngon.mesh.defaultTransform,...t}).rotation,translation:t.translation,scale:t.scaling}}function S(e=[Rngon.vertex()],t=Rngon.material(),n=Rngon.vector3(0,1,0)){Rngon.assert?.(e instanceof Array,"Expected an array of vertices to make an ngon."),Rngon.assert?.(t instanceof Object,"Expected an object containing user-supplied options."),t=Rngon.material(t),Array.isArray(n)||(n=new Array(e.length).fill().map((e=>Rngon.vector3(n.x,n.y,n.z))));const r=n.reduce(((e,t)=>(e.x+=t.x,e.y+=t.y,e.z+=t.z,e)),Rngon.vector3(0,0,0));Rngon.vector3.normalize(r);{const t=e.map((e=>e.u)).some((e=>e<0)),n=e.map((e=>e.v)).some((e=>e<0));if(t||n)for(const r of e)t&&0===r.u&&(r.u=-Number.EPSILON),n&&0===r.v&&(r.v=-Number.EPSILON)}return{vertices:e,vertexNormals:n,normal:r,material:t,mipLevel:0}}b.object_space_matrix=function(e){const t=Rngon.matrix44.translation(e.translation.x,e.translation.y,e.translation.z),n=Rngon.matrix44.rotation(e.rotation.x,e.rotation.y,e.rotation.z),r=Rngon.matrix44.scaling(e.scale.x,e.scale.y,e.scale.z);return Rngon.matrix44.multiply(Rngon.matrix44.multiply(t,n),r)},S.perspective_divide=function(e){for(const t of e.vertices)Rngon.vertex.perspective_divide(t)},S.transform=function(e,t){for(const n of e.vertices)Rngon.vertex.transform(n,t)};const M=["x","y","z"],_=[1,-1];S.clip_to_viewport=function(e){for(const t of M)for(const n of _){if(!e.vertices.length)break;if(1==e.vertices.length){if(e.vertices[0].x<=e.vertices[0].w&&-e.vertices[0].x<=e.vertices[0].w&&e.vertices[0].y<=e.vertices[0].w&&-e.vertices[0].y<=e.vertices[0].w&&e.vertices[0].z<=e.vertices[0].w&&-e.vertices[0].z<=e.vertices[0].w)break;e.vertices.length=0;break}let r=e.vertices[e.vertices.length-(2==e.vertices.length?2:1)],a=r[t]*n,o=a<=r.w,i=0,s=e.vertices.length;for(let l=0;l"function"==typeof e)),t.usePalette=Array.isArray(e.palette),t.palette=e.palette,t.modules.rasterize=e.modules.rasterize||Rngon.baseModules.rasterize,t.modules.transform_clip_light=e.modules.transformClipLight||Rngon.baseModules.transform_clip_light,t.modules.surface_wipe=e.modules.surfaceWipe||Rngon.baseModules.surface_wipe},prepare_ngon_cache:function(e=[Rngon.ngon()]){Rngon.assert?.(e instanceof Array,"Invalid arguments to n-gon cache initialization.");const t=Rngon.internalState.ngonCache,n=e.reduce(((e,t)=>e+t.ngons.length),0);if(!t||!t.ngons.length||t.ngons.lengthRngon.ngon())))}t.count=0},prepare_vertex_cache:function(e=[Rngon.ngon()]){Rngon.assert?.(e instanceof Array,"Invalid arguments to n-gon cache initialization.");const t=Rngon.internalState.vertexCache;let n=0;for(const t of e)for(const e of t.ngons)n+=e.vertices.length;if(!t||!t.vertices.length||t.vertices.lengthRngon.vertex())))}t.count=0},depth_sort_ngon_cache:function(e=""){const t=Rngon.internalState.ngonCache.ngons;switch(e){case"none":break;case"painter":t.sort(((e,t)=>{const n=e.isActive?e.vertices.reduce(((e,t)=>e+t.z),0)/e.vertices.length:-Number.MAX_VALUE,r=t.isActive?t.vertices.reduce(((e,t)=>e+t.z),0)/t.vertices.length:-Number.MAX_VALUE;return n===r?0:n{const n=e.isActive?e.vertices.reduce(((e,t)=>e+t.z),0)/e.vertices.length:Number.MAX_VALUE,r=t.isActive?t.vertices.reduce(((e,t)=>e+t.z),0)/t.vertices.length:Number.MAX_VALUE;return n===r?0:n>r?1:-1}))}},mark_npot_textures_in_ngon_cache:function(){for(let e=0;e0&&a>0,"Couldn't retrieve the canvas's dimensions."),e.setAttribute("width",r),e.setAttribute("height",a),{surfaceWidth:r,surfaceHeight:a,canvasElement:e,renderContext:n}})()),t.pixelBuffer.width==r&&t.pixelBuffer.height==a||(t.pixelBuffer=o.createImageData(r,a)),(t.usePixelShader&&t.fragmentBuffer.width!=r||t.fragmentBuffer.height!=a)&&(t.fragmentBuffer.width=r,t.fragmentBuffer.height=a,t.fragmentBuffer.data=new Array(r*a).fill().map((e=>({})))),(t.useDepthBuffer&&t.depthBuffer.width!=r||t.depthBuffer.height!=a||!t.depthBuffer.data.length)&&(t.depthBuffer.width=r,t.depthBuffer.height=a,t.depthBuffer.data=new Array(t.depthBuffer.width*t.depthBuffer.height))}catch(e){return Rngon.log(`Failed to create a render surface. ${e}`),null}const i=Rngon.matrix44.multiply(Rngon.matrix44.rotation(t.cameraDirection.x,t.cameraDirection.y,t.cameraDirection.z),Rngon.matrix44.translation(-t.cameraPosition.x,-t.cameraPosition.y,-t.cameraPosition.z)),s=Rngon.matrix44.perspective(t.fov*(Math.PI/180),r/a,t.nearPlaneDistance,t.farPlaneDistance),l=Rngon.matrix44.ortho(r+1,a+1),d=Object.freeze({width:r,height:a,display_meshes:function(e=[]){t.modules.surface_wipe(),Rngon.renderShared.prepare_vertex_cache(e),Rngon.renderShared.prepare_ngon_cache(e);for(const n of e)t.modules.transform_clip_light(n.ngons,Rngon.mesh.object_space_matrix(n),i,s,l,t.cameraPosition);if(Rngon.renderShared.mark_npot_textures_in_ngon_cache(),Rngon.renderShared.depth_sort_ngon_cache(t.depthSortingMode),t.modules.rasterize(t.auxiliaryBuffers),t.usePixelShader){const e={renderWidth:r,renderHeight:a,fragmentBuffer:t.fragmentBuffer.data,pixelBuffer:t.pixelBuffer.data,ngonCache:t.ngonCache.ngons,cameraPosition:t.cameraPosition},n=`{${Object.keys(e).join(",")}}`;switch(typeof t.pixel_shader){case"function":t.pixel_shader(e);break;case"string":Function(n,`(${t.pixel_shader})(${n})`)(e);break;default:Rngon.$throw("Unrecognized type of pixel shader function.")}}n||(t.useContextShader?t.context_shader({context:o,image:t.pixelBuffer}):o.putImageData(t.pixelBuffer,0,0))},is_in_view:function(){if(n)return!0;const t=window.innerHeight,r=e.getBoundingClientRect();return r.top>-r.height&&r.top=0&&e.height>=0,"Expected texture width and height to be no less than zero."),Rngon.assert?.(e.width<=32768&&e.height<=32768,"Expected texture width/height to be no more than 32768/32768."),"none"!==e.encoding&&("base64"===e.encoding?(Rngon.assert?.("rgba:5+5+5+1"===e.channels,"Expected Base64-encoded data to be in RGBA 5551 format."),e.pixels=(()=>{const t=[],n=atob(e.pixels);Rngon.assert?.(n.length===e.width*e.height*2,"Unexpected data length for a Base64-encoded texture.");for(let r=0;r>5&31)),t.push(8*(e>>10&31)),t.push(255*(e>>15&1))}return t})()):"none"!==e.encoding&&Rngon.$throw("Unknown texture data encoding '"+e.encoding+"'.")),Rngon.assert?.(e.pixels.length===e.width*e.height*4,"The texture's pixel array size doesn't match its width and height.");const t=[];for(let n=0;n0,"Failed to generate mip levels for a texture.");break}}return{...e,pixels:t,mipLevels:n}}C.deep_copy=function(e){const t=new Array(e.width*e.height*4);for(let n=0;n{fetch(e).then((e=>e.json())).then((e=>{t(Rngon.texture_rgba(e))})).catch((t=>{Rngon.$throw(`Failed to create a texture with data from file '${e}'. Error: '${t}'.`)}))}))};const A=[0,.0061359,.0122715,.0184067,.0245412,.0306748,.0368072,.0429383,.0490677,.0551952,.0613207,.0674439,.0735646,.0796824,.0857973,.091909,.0980171,.1041216,.1102222,.1163186,.1224107,.1284981,.1345807,.1406582,.1467305,.1527972,.1588581,.1649131,.1709619,.1770042,.1830399,.1890687,.1950903,.2011046,.2071114,.2131103,.2191012,.2250839,.2310581,.2370236,.2429802,.2489276,.2548657,.2607941,.2667128,.2726214,.2785197,.2844075,.2902847,.2961509,.3020059,.3078496,.3136817,.319502,.3253103,.3311063,.3368899,.3426607,.3484187,.3541635,.359895,.365613,.3713172,.3770074,.3826834,.388345,.393992,.3996242,.4052413,.4108432,.4164296,.4220003,.4275551,.4330938,.4386162,.4441221,.4496113,.4550836,.4605387,.4659765,.4713967,.4767992,.4821838,.4875502,.4928982,.4982277,.5035384,.5088301,.5141027,.519356,.5245897,.5298036,.5349976,.5401715,.545325,.550458,.5555702,.5606616,.5657318,.5707807,.5758082,.580814,.5857979,.5907597,.5956993,.6006165,.605511,.6103828,.6152316,.6200572,.6248595,.6296382,.6343933,.6391244,.6438315,.6485144,.6531728,.6578067,.6624158,.6669999,.671559,.6760927,.680601,.6850837,.6895405,.6939715,.6983762,.7027547,.7071068,.7114322,.7157308,.7200025,.7242471,.7284644,.7326543,.7368166,.7409511,.7450578,.7491364,.7531868,.7572088,.7612024,.7651673,.7691033,.7730105,.7768885,.7807372,.7845566,.7883464,.7921066,.7958369,.7995373,.8032075,.8068476,.8104572,.8140363,.8175848,.8211025,.8245893,.828045,.8314696,.8348629,.8382247,.841555,.8448536,.8481203,.8513552,.854558,.8577286,.8608669,.8639729,.8670462,.870087,.873095,.8760701,.8790122,.8819213,.8847971,.8876396,.8904487,.8932243,.8959662,.8986745,.9013488,.9039893,.9065957,.909168,.911706,.9142098,.9166791,.9191139,.921514,.9238795,.9262102,.9285061,.930767,.9329928,.9351835,.937339,.9394592,.9415441,.9435935,.9456073,.9475856,.9495282,.951435,.953306,.9551412,.9569403,.9587035,.9604305,.9621214,.9637761,.9653944,.9669765,.9685221,.9700313,.9715039,.97294,.9743394,.9757021,.9770281,.9783174,.9795698,.9807853,.9819639,.9831055,.9842101,.9852776,.9863081,.9873014,.9882576,.9891765,.9900582,.9909026,.9917098,.9924795,.9932119,.993907,.9945646,.9951847,.9957674,.9963126,.9968203,.9972905,.9977231,.9981181,.9984756,.9987955,.9990777,.9993224,.9995294,.9996988,.9998306,.9999247,.9999812,1,.9999812,.9999247,.9998306,.9996988,.9995294,.9993224,.9990777,.9987955,.9984756,.9981181,.9977231,.9972905,.9968203,.9963126,.9957674,.9951847,.9945646,.993907,.9932119,.9924795,.9917098,.9909026,.9900582,.9891765,.9882576,.9873014,.9863081,.9852776,.9842101,.9831055,.9819639,.9807853,.9795698,.9783174,.9770281,.9757021,.9743394,.97294,.9715039,.9700313,.9685221,.9669765,.9653944,.9637761,.9621214,.9604305,.9587035,.9569403,.9551412,.953306,.951435,.9495282,.9475856,.9456073,.9435935,.9415441,.9394592,.937339,.9351835,.9329928,.930767,.9285061,.9262102,.9238795,.921514,.9191139,.9166791,.9142098,.911706,.909168,.9065957,.9039893,.9013488,.8986745,.8959662,.8932243,.8904487,.8876396,.8847971,.8819213,.8790122,.8760701,.873095,.870087,.8670462,.8639729,.8608669,.8577286,.854558,.8513552,.8481203,.8448536,.841555,.8382247,.8348629,.8314696,.828045,.8245893,.8211025,.8175848,.8140363,.8104572,.8068476,.8032075,.7995373,.7958369,.7921066,.7883464,.7845566,.7807372,.7768885,.7730105,.7691033,.7651673,.7612024,.7572088,.7531868,.7491364,.7450578,.7409511,.7368166,.7326543,.7284644,.7242471,.7200025,.7157308,.7114322,.7071068,.7027547,.6983762,.6939715,.6895405,.6850837,.680601,.6760927,.671559,.6669999,.6624158,.6578067,.6531728,.6485144,.6438315,.6391244,.6343933,.6296382,.6248595,.6200572,.6152316,.6103828,.605511,.6006165,.5956993,.5907597,.5857979,.580814,.5758082,.5707807,.5657318,.5606616,.5555702,.550458,.545325,.5401715,.5349976,.5298036,.5245897,.519356,.5141027,.5088301,.5035384,.4982277,.4928982,.4875502,.4821838,.4767992,.4713967,.4659765,.4605387,.4550836,.4496113,.4441221,.4386162,.4330938,.4275551,.4220003,.4164296,.4108432,.4052413,.3996242,.393992,.388345,.3826834,.3770074,.3713172,.365613,.359895,.3541635,.3484187,.3426607,.3368899,.3311063,.3253103,.319502,.3136817,.3078496,.3020059,.2961509,.2902847,.2844075,.2785197,.2726214,.2667128,.2607941,.2548657,.2489276,.2429802,.2370236,.2310581,.2250839,.2191012,.2131103,.2071114,.2011046,.1950903,.1890687,.1830399,.1770042,.1709619,.1649131,.1588581,.1527972,.1467305,.1406582,.1345807,.1284981,.1224107,.1163186,.1102222,.1041216,.0980171,.091909,.0857973,.0796824,.0735646,.0674439,.0613207,.0551952,.0490677,.0429383,.0368072,.0306748,.0245412,.0184067,.0122715,.0061359,0,-.0061359,-.0122715,-.0184067,-.0245412,-.0306748,-.0368072,-.0429383,-.0490677,-.0551952,-.0613207,-.0674439,-.0735646,-.0796824,-.0857973,-.091909,-.0980171,-.1041216,-.1102222,-.1163186,-.1224107,-.1284981,-.1345807,-.1406582,-.1467305,-.1527972,-.1588581,-.1649131,-.1709619,-.1770042,-.1830399,-.1890687,-.1950903,-.2011046,-.2071114,-.2131103,-.2191012,-.2250839,-.2310581,-.2370236,-.2429802,-.2489276,-.2548657,-.2607941,-.2667128,-.2726214,-.2785197,-.2844075,-.2902847,-.2961509,-.3020059,-.3078496,-.3136817,-.319502,-.3253103,-.3311063,-.3368899,-.3426607,-.3484187,-.3541635,-.359895,-.365613,-.3713172,-.3770074,-.3826834,-.388345,-.393992,-.3996242,-.4052413,-.4108432,-.4164296,-.4220003,-.4275551,-.4330938,-.4386162,-.4441221,-.4496113,-.4550836,-.4605387,-.4659765,-.4713967,-.4767992,-.4821838,-.4875502,-.4928982,-.4982277,-.5035384,-.5088301,-.5141027,-.519356,-.5245897,-.5298036,-.5349976,-.5401715,-.545325,-.550458,-.5555702,-.5606616,-.5657318,-.5707807,-.5758082,-.580814,-.5857979,-.5907597,-.5956993,-.6006165,-.605511,-.6103828,-.6152316,-.6200572,-.6248595,-.6296382,-.6343933,-.6391244,-.6438315,-.6485144,-.6531728,-.6578067,-.6624158,-.6669999,-.671559,-.6760927,-.680601,-.6850837,-.6895405,-.6939715,-.6983762,-.7027547,-.7071068,-.7114322,-.7157308,-.7200025,-.7242471,-.7284644,-.7326543,-.7368166,-.7409511,-.7450578,-.7491364,-.7531868,-.7572088,-.7612024,-.7651673,-.7691033,-.7730105,-.7768885,-.7807372,-.7845566,-.7883464,-.7921066,-.7958369,-.7995373,-.8032075,-.8068476,-.8104572,-.8140363,-.8175848,-.8211025,-.8245893,-.828045,-.8314696,-.8348629,-.8382247,-.841555,-.8448536,-.8481203,-.8513552,-.854558,-.8577286,-.8608669,-.8639729,-.8670462,-.870087,-.873095,-.8760701,-.8790122,-.8819213,-.8847971,-.8876396,-.8904487,-.8932243,-.8959662,-.8986745,-.9013488,-.9039893,-.9065957,-.909168,-.911706,-.9142098,-.9166791,-.9191139,-.921514,-.9238795,-.9262102,-.9285061,-.930767,-.9329928,-.9351835,-.937339,-.9394592,-.9415441,-.9435935,-.9456073,-.9475856,-.9495282,-.951435,-.953306,-.9551412,-.9569403,-.9587035,-.9604305,-.9621214,-.9637761,-.9653944,-.9669765,-.9685221,-.9700313,-.9715039,-.97294,-.9743394,-.9757021,-.9770281,-.9783174,-.9795698,-.9807853,-.9819639,-.9831055,-.9842101,-.9852776,-.9863081,-.9873014,-.9882576,-.9891765,-.9900582,-.9909026,-.9917098,-.9924795,-.9932119,-.993907,-.9945646,-.9951847,-.9957674,-.9963126,-.9968203,-.9972905,-.9977231,-.9981181,-.9984756,-.9987955,-.9990777,-.9993224,-.9995294,-.9996988,-.9998306,-.9999247,-.9999812,-1,-.9999812,-.9999247,-.9998306,-.9996988,-.9995294,-.9993224,-.9990777,-.9987955,-.9984756,-.9981181,-.9977231,-.9972905,-.9968203,-.9963126,-.9957674,-.9951847,-.9945646,-.993907,-.9932119,-.9924795,-.9917098,-.9909026,-.9900582,-.9891765,-.9882576,-.9873014,-.9863081,-.9852776,-.9842101,-.9831055,-.9819639,-.9807853,-.9795698,-.9783174,-.9770281,-.9757021,-.9743394,-.97294,-.9715039,-.9700313,-.9685221,-.9669765,-.9653944,-.9637761,-.9621214,-.9604305,-.9587035,-.9569403,-.9551412,-.953306,-.951435,-.9495282,-.9475856,-.9456073,-.9435935,-.9415441,-.9394592,-.937339,-.9351835,-.9329928,-.930767,-.9285061,-.9262102,-.9238795,-.921514,-.9191139,-.9166791,-.9142098,-.911706,-.909168,-.9065957,-.9039893,-.9013488,-.8986745,-.8959662,-.8932243,-.8904487,-.8876396,-.8847971,-.8819213,-.8790122,-.8760701,-.873095,-.870087,-.8670462,-.8639729,-.8608669,-.8577286,-.854558,-.8513552,-.8481203,-.8448536,-.841555,-.8382247,-.8348629,-.8314696,-.828045,-.8245893,-.8211025,-.8175848,-.8140363,-.8104572,-.8068476,-.8032075,-.7995373,-.7958369,-.7921066,-.7883464,-.7845566,-.7807372,-.7768885,-.7730105,-.7691033,-.7651673,-.7612024,-.7572088,-.7531868,-.7491364,-.7450578,-.7409511,-.7368166,-.7326543,-.7284644,-.7242471,-.7200025,-.7157308,-.7114322,-.7071068,-.7027547,-.6983762,-.6939715,-.6895405,-.6850837,-.680601,-.6760927,-.671559,-.6669999,-.6624158,-.6578067,-.6531728,-.6485144,-.6438315,-.6391244,-.6343933,-.6296382,-.6248595,-.6200572,-.6152316,-.6103828,-.605511,-.6006165,-.5956993,-.5907597,-.5857979,-.580814,-.5758082,-.5707807,-.5657318,-.5606616,-.5555702,-.550458,-.545325,-.5401715,-.5349976,-.5298036,-.5245897,-.519356,-.5141027,-.5088301,-.5035384,-.4982277,-.4928982,-.4875502,-.4821838,-.4767992,-.4713967,-.4659765,-.4605387,-.4550836,-.4496113,-.4441221,-.4386162,-.4330938,-.4275551,-.4220003,-.4164296,-.4108432,-.4052413,-.3996242,-.393992,-.388345,-.3826834,-.3770074,-.3713172,-.365613,-.359895,-.3541635,-.3484187,-.3426607,-.3368899,-.3311063,-.3253103,-.319502,-.3136817,-.3078496,-.3020059,-.2961509,-.2902847,-.2844075,-.2785197,-.2726214,-.2667128,-.2607941,-.2548657,-.2489276,-.2429802,-.2370236,-.2310581,-.2250839,-.2191012,-.2131103,-.2071114,-.2011046,-.1950903,-.1890687,-.1830399,-.1770042,-.1709619,-.1649131,-.1588581,-.1527972,-.1467305,-.1406582,-.1345807,-.1284981,-.1224107,-.1163186,-.1102222,-.1041216,-.0980171,-.091909,-.0857973,-.0796824,-.0735646,-.0674439,-.0613207,-.0551952,-.0490677,-.0429383,-.0368072,-.0306748,-.0245412,-.0184067,-.0122715,-.0061359,-0,.0061359,.0122715,.0184067,.0245412,.0306748,.0368072,.0429383,.0490677,.0551952,.0613207,.0674439,.0735646,.0796824,.0857973,.091909,.0980171,.1041216,.1102222,.1163186,.1224107,.1284981,.1345807,.1406582,.1467305,.1527972,.1588581,.1649131,.1709619,.1770042,.1830399,.1890687,.1950903,.2011046,.2071114,.2131103,.2191012,.2250839,.2310581,.2370236,.2429802,.2489276,.2548657,.2607941,.2667128,.2726214,.2785197,.2844075,.2902847,.2961509,.3020059,.3078496,.3136817,.319502,.3253103,.3311063,.3368899,.3426607,.3484187,.3541635,.359895,.365613,.3713172,.3770074,.3826834,.388345,.393992,.3996242,.4052413,.4108432,.4164296,.4220003,.4275551,.4330938,.4386162,.4441221,.4496113,.4550836,.4605387,.4659765,.4713967,.4767992,.4821838,.4875502,.4928982,.4982277,.5035384,.5088301,.5141027,.519356,.5245897,.5298036,.5349976,.5401715,.545325,.550458,.5555702,.5606616,.5657318,.5707807,.5758082,.580814,.5857979,.5907597,.5956993,.6006165,.605511,.6103828,.6152316,.6200572,.6248595,.6296382,.6343933,.6391244,.6438315,.6485144,.6531728,.6578067,.6624158,.6669999,.671559,.6760927,.680601,.6850837,.6895405,.6939715,.6983762,.7027547,.7071068,.7114322,.7157308,.7200025,.7242471,.7284644,.7326543,.7368166,.7409511,.7450578,.7491364,.7531868,.7572088,.7612024,.7651673,.7691033,.7730105,.7768885,.7807372,.7845566,.7883464,.7921066,.7958369,.7995373,.8032075,.8068476,.8104572,.8140363,.8175848,.8211025,.8245893,.828045,.8314696,.8348629,.8382247,.841555,.8448536,.8481203,.8513552,.854558,.8577286,.8608669,.8639729,.8670462,.870087,.873095,.8760701,.8790122,.8819213,.8847971,.8876396,.8904487,.8932243,.8959662,.8986745,.9013488,.9039893,.9065957,.909168,.911706,.9142098,.9166791,.9191139,.921514,.9238795,.9262102,.9285061,.930767,.9329928,.9351835,.937339,.9394592,.9415441,.9435935,.9456073,.9475856,.9495282,.951435,.953306,.9551412,.9569403,.9587035,.9604305,.9621214,.9637761,.9653944,.9669765,.9685221,.9700313,.9715039,.97294,.9743394,.9757021,.9770281,.9783174,.9795698,.9807853,.9819639,.9831055,.9842101,.9852776,.9863081,.9873014,.9882576,.9891765,.9900582,.9909026,.9917098,.9924795,.9932119,.993907,.9945646,.9951847,.9957674,.9963126,.9968203,.9972905,.9977231,.9981181,.9984756,.9987955,.9990777,.9993224,.9995294,.9996988,.9998306,.9999247,.9999812],E={sin:e=>A[e>>6],cos:e=>A[256+(e>>6)],deg:e=>182.04166666666666*(e>=0?e%360:360-Math.abs(e)%360)};function P(e,t){e||Rngon.$throw(t)}function D(e,t,n){return e+n*(t-e)}function W(e,t=.5,n=t){const r=Rngon.lerp(e(0,0),e(0,1),n),a=Rngon.lerp(e(1,0),e(1,1),n);return Rngon.lerp(r,a,t)}function I(e=""){throw Rngon.internalState.allowWindowAlert&&window.alert("Retro n-gon error: "+e),Error(e)}function N(e="Hello there."){console.log(e)}function j(e,t){return Math.floor(parseInt(window.getComputedStyle(e).getPropertyValue("width"))*t)}function L(e,t){return Math.floor(parseInt(window.getComputedStyle(e).getPropertyValue("height"))*t)}function T(e=0,t=0,n=0){return Rngon.assert?.("number"==typeof e&&"number"==typeof t&&"number"==typeof n,"Expected numbers as parameters to the vector3 factory."),{x:e,y:t,z:n}}const X=T,k=T,O=(e,t,n)=>Rngon.vector3(Rngon.trig.deg(e),Rngon.trig.deg(t),Rngon.trig.deg(n));function V(e=0,t=0,n=0,r=0,a=0,o=1,i=1,s=e,l=t,d=n,h=0,c=1,g=0){return Rngon.assert?.("number"==typeof e&&"number"==typeof t&&"number"==typeof n&&"number"==typeof o&&"number"==typeof r&&"number"==typeof a&&"number"==typeof s&&"number"==typeof l&&"number"==typeof d,"Expected numbers as parameters to the vertex factory."),{x:e,y:t,z:n,u:r,v:a,w:o,shade:i,worldX:s,worldY:l,worldZ:d,normalX:h,normalY:c,normalZ:g}}T.transform=function(e,t=[]){Rngon.assert?.(16===t.length,"Expected a 4 x 4 matrix to transform the vector by.");const n=t[0]*e.x+t[4]*e.y+t[8]*e.z,r=t[1]*e.x+t[5]*e.y+t[9]*e.z,a=t[2]*e.x+t[6]*e.y+t[10]*e.z;e.x=n,e.y=r,e.z=a},T.normalize=function(e){const t=e.x*e.x+e.y*e.y+e.z*e.z;if(0!=t&&1!=t){const n=1/Math.sqrt(t);e.x*=n,e.y*=n,e.z*=n}},T.dot=function(e,t){return e.x*t.x+e.y*t.y+e.z*t.z},T.mul_scalar=function(e,t){return Rngon.vector3(e.x*t,e.y*t,e.z*t)},T.add_scalar=function(e,t){return Rngon.vector3(e.x+t,e.y+t,e.z+t)},T.sub_scalar=function(e,t){return Rngon.vector3(e.x-t,e.y-t,e.z-t)},T.mul=function(e,t){return Rngon.vector3(e.x*t.x,e.y*t.y,e.z*t.z)},T.add=function(e,t){return Rngon.vector3(e.x+t.x,e.y+t.y,e.z+t.z)},T.sub=function(e,t){return Rngon.vector3(e.x-t.x,e.y-t.y,e.z-t.z)},T.cross=function(e,t){const n=Rngon.vector3();return n.x=e.y*t.z-e.z*t.y,n.y=e.z*t.x-e.x*t.z,n.z=e.x*t.y-e.y*t.x,n},T.invert=function(e){e.x*=-1,e.y*=-1,e.z*=-1},V.transform=function(e,t=[]){Rngon.assert?.(16===t.length,"Expected a 4 x 4 matrix to transform the vertex by.");const n=t[0]*e.x+t[4]*e.y+t[8]*e.z+t[12]*e.w,r=t[1]*e.x+t[5]*e.y+t[9]*e.z+t[13]*e.w,a=t[2]*e.x+t[6]*e.y+t[10]*e.z+t[14]*e.w,o=t[3]*e.x+t[7]*e.y+t[11]*e.z+t[15]*e.w;e.x=n,e.y=r,e.z=a,e.w=o},V.perspective_divide=function(e){e.x/=e.w,e.y/=e.w};const Y={family:"beta",major:"5",minor:"0",dev:!0},Z={rasterize:u,surface_wipe:function(){Rngon.internalState.pixelBuffer.data.fill(0),Rngon.internalState.useDepthBuffer&&Rngon.internalState.depthBuffer.data.fill(Rngon.internalState.depthBuffer.clearValue)},transform_clip_light:function(e=[],t=[],n=[],r=[],a=[],o){const i={x:0,y:0,z:0},s=Rngon.internalState.ngonCache,l=Rngon.internalState.vertexCache,d=Rngon.matrix44.multiply(r,n);for(const n of e){if(!n.material.hasWireframe&&n.material.allowAlphaReject&&n.material.color.alpha<=0)continue;if(!n.material.isTwoSided&&(i.x=n.vertices[0].x-o.x,i.y=n.vertices[0].y-o.y,i.z=n.vertices[0].z-o.z,Rngon.vector3.dot(n.normal,i)>=0))continue;const e=s.ngons[s.count++];e.vertices.length=0;for(let t=0;tArray.isArray(element))) { + throw new Error("Each entry in the palette must be a sub-array of color channel values."); + } + newPalette.forEach(color=>{ color.length = 4; if (typeof color[3] === "undefined") { @@ -65,8 +66,6 @@ class IndexedImageData { } }); - newPalette = newPalette.map(color=>Uint8ClampedArray.from(color)); - const palette = { byte: newPalette, dword: new Uint32Array(newPalette.map(color=>((color[3] << 24) | (color[2] << 16) | (color[1] << 8) | color[0]))), @@ -86,10 +85,6 @@ class IndexedImageData { }); } - get data() { - return this.#data; - } - get width() { return this.#width; } @@ -103,72 +98,115 @@ class IndexedImageData { } }; -class HTMLPalettedCanvasElement extends HTMLCanvasElement { - #canvasImage - #canvasContext +// A wrapper interface around CanvasRenderingContext2D for manipulating the drawing surface +// of a element using indexed colors. +class CanvasRenderingContextIndexed { + #underlyingContext2D + #underlyingImageData + #width + #height - constructor() { - super(); - } - - static get observedAttributes() { - return ["width", "height"]; - } + constructor(underlyingContext2D) { + if (!(underlyingContext2D instanceof CanvasRenderingContext2D)) { + throw new Error("CanvasRenderingContextIndexed requires an instance of CanvasRenderingContext2D as an argument."); + } - attributeChangedCallback(name, oldValue, newValue) { - if ((oldValue != newValue) && ["width", "height"].includes(name)) { - this.#canvasContext = super.getContext("2d"); - this.#canvasImage = this.#canvasContext.createImageData(super.width, super.height); + this.#underlyingContext2D = underlyingContext2D; + this.#width = this.#underlyingContext2D.canvas.width; + this.#height = this.#underlyingContext2D.canvas.height; + this.#underlyingImageData = this.#underlyingContext2D.createImageData(this.#width, this.#height); + this.#underlyingImageData.data.fill(0); + + if ( + isNaN(this.#width) || + isNaN(this.#height) || + (this.#height < 1) || + (this.#width < 1) + ){ + throw new Error("Invalid context resolution."); } } + + createImageData( + width = this.#width, + height = this.#height + ) + { + if (width instanceof ImageData) { + throw new Error("This interface supports only 'width' and 'height' as arguments."); + } - getContext(contextType = "2d") { - if (contextType !== "2d") { - throw new Error(`Only the "2d" context type is supported.`); + if ( + (width !== this.#width) || + (height !== this.#height) + ){ + throw new Error("This interface can only create images whose resolution matches the size of the canvas."); } - // Emulates the interface of CanvasRenderingContext2D. - return { - createImageData: this.#createImageData.bind(this), - putImageData: this.#putImageData.bind(this), - }; + return new IndexedImageData(width, height); } - #createImageData() { - return new IndexedImageData( - new Uint8ClampedArray(super.width * super.height), - super.width, - super.height, - ); + // Returns as an ImageData object the RGBA/8888 pixel data as displayed on the canvas. + getImageData() { + return this.#underlyingImageData; } - #putImageData(image) { - if (!(image instanceof IndexedImageData)) { + putImageData(indexedImage) { + if (!(indexedImage instanceof IndexedImageData)) { throw new Error("Only images of type IndexedImageData can be rendered."); } if ( - !(this.#canvasImage instanceof ImageData) || - !(this.#canvasContext instanceof CanvasRenderingContext2D) + (indexedImage.width !== this.#width) || + (indexedImage.height !== this.#height) ){ - throw new Error("Internal error: incomplete state initialization."); + throw new Error("Mismatched image resolution: images must be the size of the canvas."); } // Convert the paletted image into a 32-bit image on the canvas. { - const palette = image.palette.dword; - const pixelBuffer32bit = new Uint32Array(this.#canvasImage.data.buffer); + const palette = indexedImage.palette.dword; + const pixelBuffer32bit = new Uint32Array(this.#underlyingImageData.data.buffer); - for (let i = 0; i < image.data.length; i++) { - pixelBuffer32bit[i] = palette[image.data[i]]; + for (let i = 0; i < indexedImage.data.length; i++) { + pixelBuffer32bit[i] = palette[indexedImage.data[i]]; } } - this.#canvasContext.putImageData(this.#canvasImage, 0, 0); + this.#underlyingContext2D.putImageData(this.#underlyingImageData, 0, 0); + } +} + +class HTMLPalettedCanvasElement extends HTMLCanvasElement { + #underlyingContext + #indexedRenderingContext + + constructor() { + super(); + } + + static get observedAttributes() { + return ["width", "height"]; + } + + attributeChangedCallback(name, oldValue, newValue) { + if ((oldValue != newValue) && ["width", "height"].includes(name)) { + this.#underlyingContext = super.getContext("2d"); + this.#indexedRenderingContext = new CanvasRenderingContextIndexed(this.#underlyingContext); + } + } + + getContext(contextType = "2d") { + if (contextType !== "2d") { + throw new Error("This interface only supports the '2d' context type."); + } + + return this.#indexedRenderingContext; } }; window.IndexedImageData = IndexedImageData; +window.CanvasRenderingContextIndexed = CanvasRenderingContextIndexed; window.HTMLPalettedCanvasElement = HTMLPalettedCanvasElement; customElements.define("paletted-canvas", HTMLPalettedCanvasElement, {extends: "canvas"}); } diff --git a/js/retro-ngon/base-modules/rasterize/raster-shader-generic-fill.js b/js/retro-ngon/base-modules/rasterize/raster-shader-generic-fill.js index 897f7e3..475f3f3 100644 --- a/js/retro-ngon/base-modules/rasterize/raster-shader-generic-fill.js +++ b/js/retro-ngon/base-modules/rasterize/raster-shader-generic-fill.js @@ -22,8 +22,9 @@ export function generic_fill({ const usePixelShader = Rngon.internalState.usePixelShader; const fragmentBuffer = Rngon.internalState.fragmentBuffer.data; const depthBuffer = (Rngon.internalState.useDepthBuffer? Rngon.internalState.depthBuffer.data : null); - const pixelBufferClamped8 = Rngon.internalState.pixelBuffer.data; - const pixelBufferWidth = Rngon.internalState.pixelBuffer.width; + const pixelBufferImage = Rngon.internalState.pixelBuffer; + const pixelBufferClamped8 = pixelBufferImage.data; + const pixelBufferWidth = pixelBufferImage.width; const material = ngon.material; const texture = (material.texture || null); diff --git a/js/retro-ngon/base-modules/rasterize/raster-shader-plain-solid-fill.js b/js/retro-ngon/base-modules/rasterize/raster-shader-plain-solid-fill.js index 6eb7569..1178ec5 100644 --- a/js/retro-ngon/base-modules/rasterize/raster-shader-plain-solid-fill.js +++ b/js/retro-ngon/base-modules/rasterize/raster-shader-plain-solid-fill.js @@ -23,8 +23,9 @@ export function plain_solid_fill({ }) { const usePalette = Rngon.internalState.usePalette; - const pixelBufferClamped8 = Rngon.internalState.pixelBuffer.data; - const pixelBufferWidth = Rngon.internalState.pixelBuffer.width; + const pixelBufferImage = Rngon.internalState.pixelBuffer; + const pixelBufferClamped8 = pixelBufferImage.data; + const pixelBufferWidth = pixelBufferImage.width; const depthBuffer = (Rngon.internalState.useDepthBuffer? Rngon.internalState.depthBuffer.data : null); const material = ngon.material; diff --git a/js/retro-ngon/base-modules/rasterize/raster-shader-plain-textured-fill.js b/js/retro-ngon/base-modules/rasterize/raster-shader-plain-textured-fill.js index dd895ae..1eea766 100644 --- a/js/retro-ngon/base-modules/rasterize/raster-shader-plain-textured-fill.js +++ b/js/retro-ngon/base-modules/rasterize/raster-shader-plain-textured-fill.js @@ -22,8 +22,9 @@ export function plain_textured_fill({ }) { const usePalette = Rngon.internalState.usePalette; - const pixelBufferClamped8 = Rngon.internalState.pixelBuffer.data; - const pixelBufferWidth = Rngon.internalState.pixelBuffer.width; + const pixelBufferImage = Rngon.internalState.pixelBuffer; + const pixelBufferClamped8 = pixelBufferImage.data; + const pixelBufferWidth = pixelBufferImage.width; const depthBuffer = (Rngon.internalState.useDepthBuffer? Rngon.internalState.depthBuffer.data : null); const material = ngon.material; const texture = (material.texture || null); diff --git a/js/retro-ngon/core/surface.js b/js/retro-ngon/core/surface.js index 45420cc..7d6a183 100644 --- a/js/retro-ngon/core/surface.js +++ b/js/retro-ngon/core/surface.js @@ -146,7 +146,6 @@ export function surface(canvasElement) } else { - state.pixelBuffer.palette = state.palette; renderContext.putImageData(state.pixelBuffer, 0, 0); } } @@ -228,6 +227,11 @@ export function surface(canvasElement) "Couldn't establish a canvas render context." ); + if (state.usePalette) + { + state.pixelBuffer.palette = state.palette; + } + // Size the canvas as per the requested render scale. const surfaceWidth = Rngon.renderable_width_of(canvasElement, state.renderScale); const surfaceHeight = Rngon.renderable_height_of(canvasElement, state.renderScale);