@saboit-dev/thomas 1.1.0-alpha.1 → 1.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("three"),t=require("quad-indices"),n=require("word-wrapper"),r=require("react"),i=require("@babel/runtime/helpers/extends"),o=require("@react-three/drei"),s=require("@react-three/fiber"),a=require("three/examples/jsm/loaders/FontLoader");function l(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function u(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var c=l(t),h=l(n),f=u(r),d=l(i);const p=["x","e","a","o","n","s","r","c","u","m","v","w","z"],g=["m","w"],x=["H","I","N","E","F","K","L","T","U","V","W","X","Y","Z"],m="\t".charCodeAt(0),y=" ".charCodeAt(0),v=1,b=2;class S{_options={};_width=0;_height=0;_descender=0;_ascender=0;_xHeight=0;_baseline=0;_capHeight=0;_lineHeight=0;_linesTotal=0;_lettersTotal=0;_wordsTotal=0;_fallbackSpaceGlyph=null;_fallbackTabGlyph=null;constructor(e,t={}){this.glyphs=[],this._text=e,this._measure=this.computeMetrics.bind(this),this.update(t)}get width(){return this._width}get height(){return this._height}get descender(){return this._descender}get ascender(){return this._ascender}get xHeight(){return this._xHeight}get baseline(){return this._baseline}get capHeight(){return this._capHeight}get lineHeight(){return this._lineHeight}get linesTotal(){return this._linesTotal}get lettersTotal(){return this._lettersTotal}get wordsTotal(){return this._wordsTotal}update(e){if(e=Object.assign({measure:this._measure},e),this._options=e,this._options.tabSize=_(this._options.tabSize,4),!e.font)throw new Error("must provide a valid bitmap font");const t=this.glyphs,n=this._text||"",r=e.font;this._setupSpaceGlyphs(r);const i=h.default.lines(n,e),o=e.width||0,s=n.split(" ").filter((e=>"\n"!==e)).length,a=n.split("").filter((e=>"\n"!==e&&" "!==e)).length;t.length=0;const l=i.reduce((function(e,t){return Math.max(e,t.width,o)}),0);let u=0,c=0;const f=_(e.lineHeight,r.common.lineHeight),d=r.common.base,g=f-d,m=e.letterSpacing||0,S=f*i.length-g,w=function(e){if("center"===e)return v;if("right"===e)return b;return 0}(this._options.alignX);c-=S,this._width=l,this._height=S,this._descender=f-d,this._baseline=d,this._xHeight=function(e){for(const t of p){const n=M(e.chars,t.charCodeAt(0));if(n>=0)return e.chars[n].height}return 0}(r),this._capHeight=function(e){for(const t of x){const n=M(e.chars,t.charCodeAt(0));if(n>=0)return e.chars[n].height}return 0}(r),this._lineHeight=f,this._ascender=f-g-this._xHeight;let B=0,C=0;i.forEach(((e,o)=>{const h=e.start,d=e.end,p=e.width,g=n.slice(h,d).split(" ").filter((e=>""!==e)).length,x=n.slice(h,d).split(" ").join("").length;let S,M=0,_=0;for(let e=h;e<d;e++){const h=n.charCodeAt(e),f=this.getGlyph(r,h);if(f){S&&(u+=A(r,S.id,f.id));let n=u;w===v?n+=(l-p)/2:w===b&&(n+=l-p),t.push({position:[n,c],data:f,index:e,linesTotal:i.length,lineIndex:o,lineLettersTotal:x,lineLetterIndex:M,lineWordsTotal:g,lineWordIndex:_,wordsTotal:s,wordIndex:B,lettersTotal:a,letterIndex:C}),f.id===y&&S.id!==y&&(_++,B++),f.id!==y&&(M++,C++),u+=f.xadvance+m,S=f}}c+=f,u=0})),this._lettersTotal=a,this._wordsTotal=s,this._linesTotal=i.length}getGlyph(e,t){const n=w(e,t);return n||(t===m?this._fallbackTabGlyph:t===y?this._fallbackSpaceGlyph:null)}computeMetrics(e,t,n,r){const i=this._options.letterSpacing||0,o=this._options.font;let s,a,l=0,u=0,c=0;if(!o.chars||0===o.chars.length)return{start:t,end:t,width:0};n=Math.min(e.length,n);for(let h=t;h<n;h++){const t=e.charCodeAt(h);if(s=this.getGlyph(o,t),s){s.char=e[h];l+=a?A(o,a.id,s.id):0;const t=l+s.xadvance+i,n=l+s.width;if(n>=r||t>=r)break;l=t,u=n,a=s}c++}return a&&(u+=a.xoffset),{start:t,end:t+c,width:u}}_setupSpaceGlyphs(e){var t;if(this._fallbackSpaceGlyph=null,this._fallbackTabGlyph=null,!e.chars||0===e.chars.length)return;const n=w(e,y)||function(e){for(const t of g){const n=M(e.chars,t.charCodeAt(0));if(n>=0)return e.chars[n]}return 0}(e)||e.chars[0],r=(null!==(t=this._options.tabSize)&&void 0!==t?t:1)*n.xadvance;this._fallbackSpaceGlyph=n;const i=Object.assign({},n);this._fallbackTabGlyph=Object.assign(i,{x:0,y:0,xadvance:r,id:m,xoffset:0,yoffset:0,width:0,height:0})}}function w(e,t){if(!e.chars||0===e.chars.length)return null;const n=M(e.chars,t);if(n>=0){return e.chars[n]}return null}function A(e,t,n){if(!e.kernings||0===e.kernings.length)return 0;const r=e.kernings;for(const e of r)if(e.first===t&&e.second===n)return e.amount;return 0}function M(e,t,n){for(let r=n=n||0;r<e.length;r++)if(e[r].id===t)return r;return-1}function _(e,t){return"number"==typeof e?e:"number"==typeof t?t:0}const B=3,C={min:[0,0,0],max:[0,0,0]};function I(e){const t=e.length/B;C.min[0]=e[0],C.min[1]=e[1],C.max[0]=e[0],C.max[1]=e[1];for(let n=0;n<t;n++){const t=e[n*B+0],r=e[n*B+1],i=e[n*B+2];C.min[0]=Math.min(t,C.min[0]),C.min[1]=Math.min(r,C.min[1]),C.min[2]=Math.min(i,C.min[2]),C.max[0]=Math.max(t,C.max[0]),C.max[1]=Math.max(r,C.max[1]),C.max[2]=Math.max(i,C.max[2])}}function T(e,t){return I(e),t.min.set(C.min[0],C.min[1],C.min[2]),t.max.set(C.max[0],C.max[1],C.max[2]),t}const G=new e.Vector3,P=new e.Vector3,F=new e.Vector3,O=new e.Vector3;class E extends e.BufferGeometry{originalPositionsArray=new Float32Array;positionsArray=new Float32Array;positionsAttribute=null;instancesOffsetsCache=[];instancesLengthsCache=[];constructor(e){super(),this._layouts=[],this.update(e)}setTransform(e,t=0){const n=this.instancesOffsetsCache[t],r=this.instancesLengthsCache[t];for(let t=0;t<r;t++){const r=12*n+12*t,i=this.originalPositionsArray[r],o=this.originalPositionsArray[r+1],s=this.originalPositionsArray[r+2],a=this.originalPositionsArray[r+3],l=this.originalPositionsArray[r+4],u=this.originalPositionsArray[r+5],c=this.originalPositionsArray[r+6],h=this.originalPositionsArray[r+7],f=this.originalPositionsArray[r+8],d=this.originalPositionsArray[r+9],p=this.originalPositionsArray[r+10],g=this.originalPositionsArray[r+11];G.set(i,o,s).applyMatrix4(e),P.set(a,l,u).applyMatrix4(e),F.set(c,h,f).applyMatrix4(e),O.set(d,p,g).applyMatrix4(e),this.positionsArray[r]=G.x,this.positionsArray[r+1]=G.y,this.positionsArray[r+2]=G.z,this.positionsArray[r+3]=P.x,this.positionsArray[r+4]=P.y,this.positionsArray[r+5]=P.z,this.positionsArray[r+6]=F.x,this.positionsArray[r+7]=F.y,this.positionsArray[r+8]=F.z,this.positionsArray[r+9]=O.x,this.positionsArray[r+10]=O.y,this.positionsArray[r+11]=O.z}this.positionsAttribute&&(this.positionsAttribute.needsUpdate=!0)}update(t){const{texts:n,...r}=t;this._layouts=n.map((e=>function(e,t){return new S(e,t)}(e.text,{...r,...e})));const i=!1!==t.flipY,o=t.font,s=o.common.scaleW,a=o.common.scaleH,l=this._layouts.map((e=>e.glyphs.filter((e=>{const t=e.data;return t.width*t.height>0}))));this.instancesOffsetsCache=[],this.instancesLengthsCache=[];let u=0;l.forEach(((e,t)=>{this.instancesLengthsCache[t]=e.length,this.instancesOffsetsCache[t]=u,u+=e.length}));const h=u,f=c.default([],{clockwise:!0,type:"uint16",count:h});this.setIndex(f);const d=l.map((e=>function(e,t,n,r){const i=new Float32Array(4*e.length*2),o=new Float32Array(4*e.length*3),s=new Float32Array(4*e.length*2);let a=0,l=0,u=0;return e.forEach((function(e){const c=e.data,h=c.x+c.width,f=c.y+c.height,d=c.x/t;let p=c.y/n;const g=h/t;let x=f/n;r&&(p=(n-c.y)/n,x=(n-f)/n),i[a++]=d,i[a++]=p,i[a++]=d,i[a++]=x,i[a++]=g,i[a++]=x,i[a++]=g,i[a++]=p;const m=e.position[0]+c.xoffset,y=e.position[1]+c.yoffset,v=c.width,b=c.height;o[l++]=m,o[l++]=y,o[l++]=0,o[l++]=m,o[l++]=y+b,o[l++]=0,o[l++]=m+v,o[l++]=y+b,o[l++]=0,o[l++]=m+v,o[l++]=y,o[l++]=0,s[u++]=m+v/2,s[u++]=y+b/2,s[u++]=m+v/2,s[u++]=y+b/2,s[u++]=m+v/2,s[u++]=y+b/2,s[u++]=m+v/2,s[u++]=y+b/2})),{uvs:i,positions:o,centers:s}}(e,s,a,i))),p=d.reduce(((e,t)=>e+t.positions.length),0),g=d.reduce(((e,t)=>e+t.centers.length),0),x=d.reduce(((e,t)=>e+t.uvs.length),0),m=new Float32Array(p),y=new Float32Array(g),v=new Float32Array(x);let b=0,w=0,A=0;d.forEach((e=>{m.set(e.positions,b),b+=e.positions.length,y.set(e.centers,w),w+=e.centers.length,v.set(e.uvs,A),A+=e.uvs.length})),this.positionsArray=m,this.originalPositionsArray=new Float32Array(p),this.originalPositionsArray.set(m),this.positionsAttribute=new e.BufferAttribute(m,3),this.setAttribute("position",this.positionsAttribute),this.setAttribute("center",new e.BufferAttribute(y,2)),this.setAttribute("uv",new e.BufferAttribute(v,2))}computeBoundingSphere(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere);const t=this.attributes.position.array,n=this.attributes.position.itemSize;if(!t||!n||t.length<2)return this.boundingSphere.radius=0,void this.boundingSphere.center.set(0,0,0);!function(e,t){I(e);const n=C.min[0],r=C.min[1],i=C.min[2],o=C.max[0]-n,s=C.max[1]-r,a=C.max[2]-i,l=Math.sqrt(o*o+s*s+a*a);t.center.set(n+o/2,r+s/2,i+a/2),t.radius=l/2}(t,this.boundingSphere),isNaN(this.boundingSphere.radius)&&console.error('BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.')}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new e.Box3);const t=this.boundingBox,n=this.attributes.position.array,r=this.attributes.position.itemSize;if(!n||!r||n.length<2)return void t.makeEmpty();return T(n,t)}}class k extends e.ShaderMaterial{constructor(t={}){super(t={...{side:e.FrontSide,transparent:!0,extensions:{derivatives:!0},uniforms:{uOpacity:{value:1},uOffset:{value:0},uColor:{value:new e.Color("#ffffff")},uMap:{value:null}},vertexShader:"#define GLSLIFY 1\nvarying vec2 vUv;void main(){vec4 mvPosition=vec4(position,1.0);mvPosition=modelViewMatrix*mvPosition;gl_Position=projectionMatrix*mvPosition;vUv=uv;}",fragmentShader:"#define GLSLIFY 1\nvarying vec2 vUv;uniform float uOpacity;uniform float uOffset;uniform vec3 uColor;uniform sampler2D uMap;float median(float r,float g,float b){return max(min(r,g),min(max(r,g),b));}void main(){vec3 s=texture2D(uMap,vUv).rgb;float sigDist=median(s.r,s.g,s.b)-0.5+uOffset;float alpha=clamp(sigDist/fwidth(sigDist)+0.5,0.0,1.0);if(alpha<0.01)discard;gl_FragColor=vec4(uColor,uOpacity*alpha);}"},...t})}}const H=r.createContext(null),V=e=>{var t,n;return[e.bold,null==(t=e.color)?void 0:t.getHexString(),e.opacity,e.outlineWidth,e.outlineOpacity,null==(n=e.outlineColor)?void 0:n.getHexString()].join("_")},L=r.forwardRef((function({instanceKey:e,bold:t,color:n,opacity:i,outlineWidth:o,outlineOpacity:s,outlineColor:a,text:l,alignX:u,alignY:c,letterSpacing:h,yShift:d,width:p,lineHeight:g,onBeforeUpdate:x},m){const y=r.useContext(H);if(!y)throw new Error("No SDFTextProvider");const v=r.useRef(null),b=r.useRef(null);return r.useImperativeHandle(m,(()=>({setTransform(e){b.current&&(b.current.transform=e)}})),[]),r.useLayoutEffect((()=>{var r;const f={bold:t,color:n,opacity:i,outlineWidth:o,outlineOpacity:s,outlineColor:a},m={text:l,alignX:u,alignY:c,letterSpacing:h,yShift:d,width:p,lineHeight:g,onBeforeUpdate:x},S=V(f);return b.current=y.insertInstance(S,f,e,m,null!==(r=v.current)&&void 0!==r?r:void 0),()=>y.removeInstance(S,e)}),[y,e,l,u,c,h,d,p,g,t,n,i,o,s,a,x]),f.createElement("group",{ref:v})}));function D(){s.extend({MSDFTextMaterial:k,MSDFTextGeometry:E})}const j=99999,U=99998,W=new e.Matrix4,z=new e.Matrix4,N=new e.Color("#ffffff"),R=new e.Color("#000000"),q=.01;function Y({instances:e,textStyle:t,atlas:n,font:i,atlasBold:o,fontBold:a,...l}){var u;const c=o&&a&&t.bold,h=c?a.data:i.data,p=r.useState((()=>new E({font:h,texts:[]})))[0];r.useLayoutEffect((()=>()=>p.dispose()),[p]),r.useLayoutEffect((()=>{const t=e.map((e=>e.config));p.update({font:h,texts:t})}),[p,e,h]),s.useFrame((()=>{e.forEach(((t,n)=>{null==t.config.onBeforeUpdate||t.config.onBeforeUpdate(),z.identity();const r=e[n].object;r&&(r.updateMatrixWorld(),z.multiply(r.matrixWorld)),z.multiply(t.transform),W.makeScale(q,q,q),z.multiply(W);const i=p._layouts[n];if(i){var o,s,a,l;const e=null!==(o=i.width)&&void 0!==o?o:0,t=null!==(s=i.height)&&void 0!==s?s:0,n=null!==(a=i.lineHeight)&&void 0!==a?a:0,r=null!==(l=i._options.yShift)&&void 0!==l?l:0,u=n/4-t,c=n/2;let h=0;"center"===i._options.alignX&&(h=-e/2),"right"===i._options.alignX&&(h=-e);let f=u+r;"middle"===i._options.alignY&&(f=(u+c)/2-i.ascender+r),"bottom"===i._options.alignY&&(f=c+r),W.makeTranslation(h,f,0),z.multiply(W)}W.makeRotationX(Math.PI),z.multiply(W),p.setTransform(z,n)}))}));const g=r.useMemo((()=>{var e,r;return{uMap:{value:c?o:n},uColor:{value:null!==(e=t.color)&&void 0!==e?e:N},uOpacity:{value:null!==(r=t.opacity)&&void 0!==r?r:1},uOffset:{value:0}}}),[c,t.opacity,t.color,n,o]),x=r.useMemo((()=>{var e,r;return{uMap:{value:c?o:n},uColor:{value:null!==(e=t.outlineColor)&&void 0!==e?e:R},uOpacity:{value:null!==(r=t.outlineOpacity)&&void 0!==r?r:.4},uOffset:{value:t.outlineWidth}}}),[c,t.outlineOpacity,t.outlineColor,t.outlineWidth,n,o]);return f.createElement(f.Fragment,null,f.createElement("mesh",d.default({geometry:p,frustumCulled:!1,renderOrder:j},l),f.createElement("mSDFTextMaterial",{uniforms:g})),(null!==(u=t.outlineWidth)&&void 0!==u?u:0)>0&&f.createElement("mesh",d.default({geometry:p,frustumCulled:!1,renderOrder:U},l),f.createElement("mSDFTextMaterial",{uniforms:x,depthWrite:!1})))}const X=new e.Matrix4,K=new e.Matrix4;function Z(){s.extend({InstancedTextPlaceholder:ne})}class J{boundingBox=null;boundingSphere=null;computeBoundingBox(){this.boundingBox||(this.boundingBox=new e.Box3)}computeBoundingSphere(){this.boundingSphere||(this.boundingSphere=new e.Sphere)}}const Q=new e.Matrix4,$=new e.Ray,ee=new e.Sphere,te=new e.Vector3;class ne extends e.Group{textAPI=void 0;geometry=new J;raycast(e,t){const n=this.geometry,r=this.matrixWorld;null===n.boundingSphere&&n.computeBoundingSphere(),ee.copy(n.boundingSphere),ee.applyMatrix4(r),!1!==e.ray.intersectsSphere(ee)&&(Q.copy(r).invert(),$.copy(e.ray).applyMatrix4(Q),null!==n.boundingBox&&null===$.intersectBox(n.boundingBox,te)||t.push({distance:te.distanceTo(e.ray.origin),point:te.clone(),object:this}))}}const re=()=>new e.MeshPhongMaterial;function ie(t,n,i,o=re){return r.useMemo((()=>{const r=o();return r.onBeforeCompile=r=>{r.uniforms={...r.uniforms,offsets:{value:t},normals:{value:n},shift:{value:new e.Vector3(i.xShift,i.yShift,i.zShift)},scale:{value:new e.Vector3(i.xScale,i.yScale,i.zScale)}},r.vertexShader=r.vertexShader.replace(/#include <morphtarget_pars_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <morphtarget_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <morphcolor_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <morphnormal_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinning_pars_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinbase_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinning_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinnormal_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <displacementmap_pars_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <displacementmap_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/>[\n]*void/,">\n uniform sampler2D offsets;\n uniform sampler2D normals;\n uniform vec3 shift;\n uniform vec3 scale;\n in float instanceGIndex;\n\n void"),r.vertexShader=r.vertexShader.replace(/void main\(\) {/,"void main() { vec3 offset = texelFetch(offsets, ivec2(gl_VertexID, instanceGIndex), 0).rgb * scale + shift;"),r.vertexShader=r.vertexShader.replace(/#include <beginnormal_vertex>/,"vec3 objectNormal = (texelFetch(normals, ivec2(gl_VertexID, instanceGIndex), 0).rgb) - 0.5;"),r.vertexShader=r.vertexShader.replace(/#include <begin_vertex>/,"vec3 transformed = offset;")},r}),[t,n,i,o])}function oe(t){const n=o.useTexture(t);return n.flipY=!1,n.magFilter=e.NearestFilter,n.minFilter=e.NearestFilter,n}const se=r.createContext(null);const ae=r.forwardRef((function({font:t},n){const i=ie(oe(t.offsetsPath),oe(t.normalsPath),t.fontMetadata),[{instanceAllocated:o,geometry:a},l]=r.useState({instanceAllocated:0,geometry:null}),u=r.useRef(null),c=r.useCallback((n=>(u.current=function(t,n,r){var i,o,s,a;null==t||t.geometry.dispose();const l=new e.InstancedBufferGeometry;l.instanceCount=n;const u=new Float32Array(3*r),c=new e.Float32BufferAttribute(u,3,!1);l.setAttribute("position",c);const h=new Float32Array(16*l.instanceCount),f=new e.InstancedBufferAttribute(h,16,!1,1);l.setAttribute("instanceMatrix",f);const d=new Float32Array(l.instanceCount);t&&d.set(t.currentGlyphs);const p=new e.InstancedBufferAttribute(d,1,!1,1);l.setAttribute("instanceGIndex",p);const g=new Float32Array(4*l.instanceCount);t&&g.set(t.currentColors);const x=new e.InstancedBufferAttribute(g,4,!0,1);return l.setAttribute("instanceColor",x),{instanceAllocated:n,geometry:l,currentInstances:null!==(i=null==t?void 0:t.currentInstances)&&void 0!==i?i:[],currentGlyphs:null!==(o=null==t?void 0:t.currentGlyphs)&&void 0!==o?o:[],currentShifts:null!==(s=null==t?void 0:t.currentShifts)&&void 0!==s?s:[],currentColors:null!==(a=null==t?void 0:t.currentColors)&&void 0!==a?a:[],instanceMatrixBuffer:h,instanceMatrixBufferAttribute:f,instanceGIndexBuffer:d,instanceGIndexBufferAttribute:p,instanceColorBuffer:g,instanceColorBufferAttribute:x}}(u.current,n,t.fontMetadata.maxVertices),l({instanceAllocated:n,geometry:u.current.geometry}),u.current)),[t.fontMetadata.maxVertices]);return r.useImperativeHandle(n,(()=>({font:t,addInstances:(e,t,n,r,i)=>{var o;const s=null!==(o=u.current)&&void 0!==o?o:c(2*e.length),a=function(e,t,n,r,i,o,s){const a=e.currentGlyphs.length,l=n.length,u=Array.from(n).map((e=>t[e])),c=Array.from(n).flatMap((()=>[i.r,i.g,i.b,1]));e.currentGlyphs.push(...u),e.currentShifts.push(...o),e.currentColors.push(...c);const h={start:a,length:l,text:n,parentGroup:s,font:r};return e.currentInstances.push(h),h}(s,t.fontMetadata.charToIndex,e,t,n,r,i);return s.currentGlyphs.length>s.instanceAllocated?c(2*s.currentGlyphs.length):function(e){e.instanceGIndexBuffer.set(e.currentGlyphs),e.instanceGIndexBufferAttribute.needsUpdate=!0,e.instanceColorBuffer.set(e.currentColors),e.instanceColorBufferAttribute.needsUpdate=!0}(s),a},removeInstances:e=>{const t=u.current;t&&function(e,t){const n=e.currentInstances.indexOf(t);if(-1!==n){for(let r=0;r<e.currentInstances.length;r++)r>n&&(e.currentInstances[r].start-=t.length);e.currentInstances.splice(n,1),e.currentGlyphs.splice(t.start,t.length),e.currentShifts.splice(2*t.start,2*t.length),e.currentColors.splice(4*t.start,4*t.length),e.instanceGIndexBuffer.fill(0),e.instanceGIndexBuffer.set(e.currentGlyphs),e.instanceGIndexBufferAttribute.needsUpdate=!0,e.instanceColorBuffer.fill(0),e.instanceColorBuffer.set(e.currentColors),e.instanceColorBufferAttribute.needsUpdate=!0,e.instanceMatrixBuffer.fill(0),e.instanceMatrixBufferAttribute.needsUpdate=!0}}(t,e)},setOpacity:(e,t)=>{const n=u.current;if(n&&n.instanceColorBuffer&&n.instanceColorBufferAttribute){for(let r=0;r<e.length;r++)n.currentColors[4*(e.start+r)+3]=t,n.instanceColorBuffer[4*(e.start+r)+3]=t;n.instanceColorBufferAttribute.needsUpdate=!0}},getBuffers:()=>u.current})),[t,c]),s.useFrame((()=>{const e=u.current;e&&function(e){e.currentInstances.forEach((t=>{for(let n=0;n<t.length;n++){const r=e.currentShifts[2*(t.start+n)],i=e.currentShifts[2*(t.start+n)+1];K.copy(t.parentGroup.matrixWorld),X.identity().setPosition(r,i,0),K.multiply(X),K.toArray(e.instanceMatrixBuffer,16*(t.start+n))}})),e.instanceMatrixBufferAttribute.needsUpdate=!0}(e)})),a?f.createElement("instancedMesh",{frustumCulled:!1,args:[a,i,o]}):null}));let le=function(e){return e.left="left",e.right="right",e.center="center",e}({});const ue=new e.Color("white");exports.InstancedText=function({text:t,thickness:n,fontSize:i,textAlign:o,scale:s,color:a,opacity:l,font:u,...c}){var h,p,g;const x=u.fontMetadata.charToIndex["?"],m=function(){const e=r.useContext(se);if(!e)throw new Error("No instanced text context");return e}(),y=r.useRef(null),v=r.useRef(null);r.useLayoutEffect((()=>{const r=y.current;if(!r)return;const i=u.fontMetadata.fontScale,s=(u.fontMetadata.boundingBox.yMax-u.fontMetadata.boundingBox.yMin+u.fontMetadata.underlineThickness)*i,l=new Float32Array(t.length),c=new Float32Array(2*t.length);let h=0,f=0;const d=[];Array.from(t).forEach(((e,t)=>{if("\n"===e)d.push(h),h=0,f-=s;else{var n;const r=u.fontMetadata.charToIndex[e],o=null!==(n=u.fontMetadata.advances[r])&&void 0!==n?n:u.fontMetadata.advances[x];l[t]=i,c[2*t]=h,c[2*t+1]=f,h+=o*i}})),d.push(h);const p=Math.max(...d),g=-((u.fontMetadata.boundingBox.yMax-u.fontMetadata.boundingBox.yMin)/2+u.fontMetadata.boundingBox.yMin)*i;Array.from(t).forEach(((e,t)=>{l[t]>0&&(o===le.left&&(c[2*t+1]+=g),o===le.right&&(c[2*t]-=p,c[2*t+1]+=g),o===le.center&&(c[2*t]-=p/2,c[2*t+1]+=g))})),r.geometry.boundingBox||(r.geometry.boundingBox=new e.Box3),r.geometry.boundingSphere||(r.geometry.boundingSphere=new e.Sphere),r.geometry.boundingBox.setFromPoints([new e.Vector3(0,u.fontMetadata.boundingBox.yMin*i,0),new e.Vector3(p,u.fontMetadata.boundingBox.yMax*i,n)]),r.geometry.boundingSphere.setFromPoints([new e.Vector3(0,u.fontMetadata.boundingBox.yMin*i,0),new e.Vector3(p,u.fontMetadata.boundingBox.yMax*i,n)]),o===le.left&&(r.geometry.boundingBox.translate(new e.Vector3(0,g,0)),r.geometry.boundingSphere.translate(new e.Vector3(0,g,0))),o===le.right&&(r.geometry.boundingBox.translate(new e.Vector3(-p,g,0)),r.geometry.boundingSphere.translate(new e.Vector3(-p,g,0))),o===le.center&&(r.geometry.boundingBox.translate(new e.Vector3(-p/2,g,0)),r.geometry.boundingSphere.translate(new e.Vector3(-p/2,g,0)));const b=m.addInstances(t,u,null!=a?a:ue,c,r);return b?(v.current=b,()=>m.removeInstances(b)):void 0}),[t,a,u.fontMetadata,x,n,o,m]),r.useEffect((()=>{v.current&&m.setOpacity(v.current,null!=l?l:1)}),[m,l]);const b=r.useMemo((()=>({getBuffers:()=>v.current&&m.getBuffers(v.current),getPtr:()=>v.current,setGlyphs:e=>{if(!v.current)return;const t=m.getBuffers(v.current);if(!t)return;const n=Array.from(e).map((e=>u.fontMetadata.charToIndex[e]));t.instanceGIndexBuffer.set(n,v.current.start),t.instanceGIndexBufferAttribute.needsUpdate=!0}})),[u.fontMetadata.charToIndex]);return f.createElement("instancedTextPlaceholder",d.default({scale:[i*(null!==(h=null==s?void 0:s.x)&&void 0!==h?h:1),i*(null!==(p=null==s?void 0:s.y)&&void 0!==p?p:1),n*(null!==(g=null==s?void 0:s.z)&&void 0!==g?g:1)]},c,{textAPI:b,ref:y,frustumCulled:!1}))},exports.InstancedTextProvider=function({children:e,styles:t}){r.useMemo(Z,[]);const n=r.useRef(new WeakMap),i=r.useCallback((e=>{e&&n.current.set(e.font,e)}),[]),o=r.useMemo((()=>({addInstances:(e,t,r,i,o)=>{const s=n.current.get(t);return null==s?void 0:s.addInstances(e,t,r,i,o)},removeInstances:e=>{const t=n.current.get(e.font);null==t||t.removeInstances(e)},setOpacity:(e,t)=>{const r=n.current.get(e.font);null==r||r.setOpacity(e,t)},getBuffers:e=>{var t;const r=n.current.get(e.font);return null!==(t=null==r?void 0:r.getBuffers(e))&&void 0!==t?t:null}})),[]);return f.createElement(se.Provider,{value:o},t.map((e=>f.createElement(ae,{key:e.offsetsPath,font:e,ref:i}))),e)},exports.MSDFTextGeometry=E,exports.MSDFTextMaterial=k,exports.SDFText=L,exports.SDFTextProvider=function({children:t,fontPathRegular:n,fontPathBold:i}){r.useMemo(D,[]),f.useEffect((()=>{console.log("Hello, World! This is a SABO fork of thomas engine.")}),[]);const l=o.useTexture(n.sdfPath),u=s.useLoader(a.FontLoader,n.fontPath),c=o.useTexture(i?i.sdfPath:[]),h=s.useLoader(a.FontLoader,i?i.fontPath:[]),d=r.useState((()=>new Map))[0],p=r.useState(0)[1],g=r.useMemo((()=>({insertInstance(t,n,r,i,o){var s;const a={instanceKey:r,config:i,object:o,transform:new e.Matrix4},l=d.get(t);return d.set(t,{textStyle:n,instances:[...null!==(s=null==l?void 0:l.instances)&&void 0!==s?s:[],a]}),p((e=>e+1)),a},removeInstance(e,t){const n=d.get(e);if(n){const r=n.instances.filter((e=>e.instanceKey!==t));0===r.length?d.delete(e):d.set(e,{textStyle:n.textStyle,instances:r}),p((e=>e+1))}}})),[]);return f.createElement(H.Provider,{value:g},f.createElement(f.Fragment,null,t,Array.from(d.values()).map((e=>f.createElement(Y,{key:V(e.textStyle),textStyle:e.textStyle,instances:e.instances,atlas:l,font:u,atlasBold:Array.isArray(c)?void 0:c,fontBold:Array.isArray(h)?void 0:h})))))};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("three"),t=require("quad-indices"),n=require("word-wrapper"),r=require("react"),i=require("@babel/runtime/helpers/extends"),o=require("@react-three/drei"),s=require("@react-three/fiber"),a=require("three/examples/jsm/loaders/FontLoader");function l(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function u(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var c=l(t),h=l(n),d=u(r),f=l(i);const p=["x","e","a","o","n","s","r","c","u","m","v","w","z"],g=["m","w"],m=["H","I","N","E","F","K","L","T","U","V","W","X","Y","Z"],y="\t".charCodeAt(0),x=" ".charCodeAt(0),v=1,b=2;class S{_options={};_width=0;_height=0;_descender=0;_ascender=0;_xHeight=0;_baseline=0;_capHeight=0;_lineHeight=0;_linesTotal=0;_lettersTotal=0;_wordsTotal=0;_fallbackSpaceGlyph=null;_fallbackTabGlyph=null;constructor(e,t={}){this.glyphs=[],this._text=e,this._measure=this.computeMetrics.bind(this),this.update(t)}get width(){return this._width}get height(){return this._height}get descender(){return this._descender}get ascender(){return this._ascender}get xHeight(){return this._xHeight}get baseline(){return this._baseline}get capHeight(){return this._capHeight}get lineHeight(){return this._lineHeight}get linesTotal(){return this._linesTotal}get lettersTotal(){return this._lettersTotal}get wordsTotal(){return this._wordsTotal}update(e){if(e=Object.assign({measure:this._measure},e),this._options=e,this._options.tabSize=I(this._options.tabSize,4),!e.font)throw new Error("must provide a valid bitmap font");const t=this.glyphs,n=this._text||"",r=e.font;this._setupSpaceGlyphs(r);const i=h.default.lines(n,e),o=e.width||0,s=n.split(" ").filter((e=>"\n"!==e)).length,a=n.split("").filter((e=>"\n"!==e&&" "!==e)).length;t.length=0;const l=i.reduce((function(e,t){return Math.max(e,t.width,o)}),0);let u=0,c=0;const d=I(e.lineHeight,r.common.lineHeight),f=r.common.base,g=d-f,y=e.letterSpacing||0,S=d*i.length-g,A=function(e){if("center"===e)return v;if("right"===e)return b;return 0}(this._options.alignX);c-=S,this._width=l,this._height=S,this._descender=d-f,this._baseline=f,this._xHeight=function(e){var t,n;return null!==(t=null==(n=_(e,p))?void 0:n.height)&&void 0!==t?t:0}(r),this._capHeight=function(e){var t,n;return null!==(t=null==(n=_(e,m))?void 0:n.height)&&void 0!==t?t:0}(r),this._lineHeight=d,this._ascender=d-g-this._xHeight;let w=0,M=0;i.forEach(((e,o)=>{const h=e.start,f=e.end,p=e.width,g=n.slice(h,f).split(" ").filter((e=>""!==e)).length,m=n.slice(h,f).split(" ").join("").length;let S,B=0,_=0;for(let e=h;e<f;e++){const h=n.charCodeAt(e),d=this.getGlyph(r,h);if(d){S&&(u+=C(r,S.id,d.id));let n=u;A===v?n+=(l-p)/2:A===b&&(n+=l-p),t.push({position:[n,c],data:d,index:e,linesTotal:i.length,lineIndex:o,lineLettersTotal:m,lineLetterIndex:B,lineWordsTotal:g,lineWordIndex:_,wordsTotal:s,wordIndex:w,lettersTotal:a,letterIndex:M}),d.id===x&&S.id!==x&&(_++,w++),d.id!==x&&(B++,M++),u+=d.xadvance+y,S=d}}c+=d,u=0})),this._lettersTotal=a,this._wordsTotal=s,this._linesTotal=i.length}getGlyph(e,t){const n=B(e,t);return n||(t===y?this._fallbackTabGlyph:t===x?this._fallbackSpaceGlyph:null)}computeMetrics(e,t,n,r){const i=this._options.letterSpacing||0,o=this._options.font;let s,a,l=0,u=0,c=0;if(!o.chars||0===o.chars.length)return{start:t,end:t,width:0};n=Math.min(e.length,n);for(let h=t;h<n;h++){const t=e.charCodeAt(h);if(s=this.getGlyph(o,t),s){s.char=e[h];l+=a?C(o,a.id,s.id):0;const t=l+s.xadvance+i,n=l+s.width;if(n>=r||t>=r)break;l=t,u=n,a=s}c++}return a&&(u+=a.xoffset),{start:t,end:t+c,width:u}}_setupSpaceGlyphs(e){var t;if(this._fallbackSpaceGlyph=null,this._fallbackTabGlyph=null,!e.chars||0===e.chars.length)return;const n=B(e,x)||function(e){var t;return null!==(t=_(e,g))&&void 0!==t?t:0}(e)||e.chars[0],r=(null!==(t=this._options.tabSize)&&void 0!==t?t:1)*n.xadvance;this._fallbackSpaceGlyph=n;const i=Object.assign({},n);this._fallbackTabGlyph=Object.assign(i,{x:0,y:0,xadvance:r,id:y,xoffset:0,yoffset:0,width:0,height:0})}}const A=1114112,w=new WeakMap;function M(e){let t=w.get(e);if(t)return t;t={glyphs:new Map,kernings:new Map};for(const r of null!==(n=e.chars)&&void 0!==n?n:[]){var n;t.glyphs.has(r.id)||t.glyphs.set(r.id,r)}for(const n of null!==(r=e.kernings)&&void 0!==r?r:[]){var r;const e=n.first*A+n.second;t.kernings.has(e)||t.kernings.set(e,n.amount)}return w.set(e,t),t}function B(e,t){var n;return null!==(n=M(e).glyphs.get(t))&&void 0!==n?n:null}function _(e,t){const{glyphs:n}=M(e);for(const e of t){const t=n.get(e.charCodeAt(0));if(t)return t}return null}function C(e,t,n){var r;return null!==(r=M(e).kernings.get(t*A+n))&&void 0!==r?r:0}function I(e,t){return"number"==typeof e?e:"number"==typeof t?t:0}const T=3,F={min:[0,0,0],max:[0,0,0]};function G(e){const t=e.length/T;F.min[0]=e[0],F.min[1]=e[1],F.max[0]=e[0],F.max[1]=e[1];for(let n=0;n<t;n++){const t=e[n*T+0],r=e[n*T+1],i=e[n*T+2];F.min[0]=Math.min(t,F.min[0]),F.min[1]=Math.min(r,F.min[1]),F.min[2]=Math.min(i,F.min[2]),F.max[0]=Math.max(t,F.max[0]),F.max[1]=Math.max(r,F.max[1]),F.max[2]=Math.max(i,F.max[2])}}function P(e,t){return G(e),t.min.set(F.min[0],F.min[1],F.min[2]),t.max.set(F.max[0],F.max[1],F.max[2]),t}function O(e,t,n,r){const i=new Float32Array(4*e.length*2),o=new Float32Array(4*e.length*3),s=new Float32Array(4*e.length*2);let a=0,l=0,u=0;return e.forEach((function(e){const c=e.data,h=c.x+c.width,d=c.y+c.height,f=c.x/t;let p=c.y/n;const g=h/t;let m=d/n;r&&(p=(n-c.y)/n,m=(n-d)/n),i[a++]=f,i[a++]=p,i[a++]=f,i[a++]=m,i[a++]=g,i[a++]=m,i[a++]=g,i[a++]=p;const y=e.position[0]+c.xoffset,x=e.position[1]+c.yoffset,v=c.width,b=c.height;o[l++]=y,o[l++]=x,o[l++]=0,o[l++]=y,o[l++]=x+b,o[l++]=0,o[l++]=y+v,o[l++]=x+b,o[l++]=0,o[l++]=y+v,o[l++]=x,o[l++]=0,s[u++]=y+v/2,s[u++]=x+b/2,s[u++]=y+v/2,s[u++]=x+b/2,s[u++]=y+v/2,s[u++]=x+b/2,s[u++]=y+v/2,s[u++]=x+b/2})),{uvs:i,positions:o,centers:s}}const k=new e.Vector3,E=new e.Vector3,H=new e.Vector3,V=new e.Vector3,L=["text","width","lineHeight","letterSpacing","alignX","alignY","yShift","tabSize"];function j(e){return JSON.stringify(L.map((t=>e[t])))}function D(e,t,n,r){const i=function(e,t){return new S(e,t)}(e.text,e),o=i.glyphs.filter((({data:e})=>e.width*e.height>0));return{layout:i,glyphCount:o.length,...O(o,t,n,r)}}class U extends e.BufferGeometry{originalPositionsArray=new Float32Array;positionsArray=new Float32Array;centersArray=new Float32Array;uvsArray=new Float32Array;positionsAttribute=null;instancesOffsetsCache=[];instancesLengthsCache=[];cache=new Map;cacheFont=null;cacheFlipY=!0;signature=null;glyphsTotal=-1;appliedTransforms=[];constructor(e){super(),this._layouts=[],this.update(e)}setTransform(t,n=0){const r=this.instancesOffsetsCache[n],i=this.instancesLengthsCache[n],o=this.appliedTransforms[n];if(void 0===i||null!=o&&o.equals(t))return!1;for(let e=0;e<i;e++){const n=12*r+12*e,i=this.originalPositionsArray[n],o=this.originalPositionsArray[n+1],s=this.originalPositionsArray[n+2],a=this.originalPositionsArray[n+3],l=this.originalPositionsArray[n+4],u=this.originalPositionsArray[n+5],c=this.originalPositionsArray[n+6],h=this.originalPositionsArray[n+7],d=this.originalPositionsArray[n+8],f=this.originalPositionsArray[n+9],p=this.originalPositionsArray[n+10],g=this.originalPositionsArray[n+11];k.set(i,o,s).applyMatrix4(t),E.set(a,l,u).applyMatrix4(t),H.set(c,h,d).applyMatrix4(t),V.set(f,p,g).applyMatrix4(t),this.positionsArray[n]=k.x,this.positionsArray[n+1]=k.y,this.positionsArray[n+2]=k.z,this.positionsArray[n+3]=E.x,this.positionsArray[n+4]=E.y,this.positionsArray[n+5]=E.z,this.positionsArray[n+6]=H.x,this.positionsArray[n+7]=H.y,this.positionsArray[n+8]=H.z,this.positionsArray[n+9]=V.x,this.positionsArray[n+10]=V.y,this.positionsArray[n+11]=V.z}return this.appliedTransforms[n]=(null!=o?o:new e.Matrix4).copy(t),this.positionsAttribute&&(this.positionsAttribute.needsUpdate=!0),!0}update(t){const{texts:n,...r}=t,i=t.font,o=!1!==t.flipY;i===this.cacheFont&&o===this.cacheFlipY||(this.cache.clear(),this.cacheFont=i,this.cacheFlipY=o,this.signature=null);const s=n.map((e=>({...r,...e}))),a=s.map(j),l=a.join("\n");if(l===this.signature)return;this.signature=l;const u=i.common.scaleW,h=i.common.scaleH,d=s.map(((e,t)=>{var n;const r=a[t],i=null!==(n=this.cache.get(r))&&void 0!==n?n:D(e,u,h,o);return this.cache.delete(r),this.cache.set(r,i),i}));for(const e of this.cache.keys()){if(this.cache.size<=n.length+256)break;this.cache.delete(e)}this._layouts=d.map((e=>e.layout)),this.instancesOffsetsCache=[],this.instancesLengthsCache=[];let f=0;d.forEach((({glyphCount:e},t)=>{this.instancesLengthsCache[t]=e,this.instancesOffsetsCache[t]=f,f+=e}));const p=f;this.appliedTransforms=[],p!==this.glyphsTotal&&(this.glyphsTotal=p,this.setIndex(c.default([],{clockwise:!0,type:"uint16",count:p})),this.positionsArray=new Float32Array(12*p),this.originalPositionsArray=new Float32Array(12*p),this.centersArray=new Float32Array(8*p),this.uvsArray=new Float32Array(8*p),this.positionsAttribute=new e.BufferAttribute(this.positionsArray,3),this.setAttribute("position",this.positionsAttribute),this.setAttribute("center",new e.BufferAttribute(this.centersArray,2)),this.setAttribute("uv",new e.BufferAttribute(this.uvsArray,2))),d.forEach(((e,t)=>{const n=this.instancesOffsetsCache[t];this.positionsArray.set(e.positions,12*n),this.centersArray.set(e.centers,8*n),this.uvsArray.set(e.uvs,8*n)})),this.originalPositionsArray.set(this.positionsArray);for(const e of["position","center","uv"])this.attributes[e].needsUpdate=!0}dispose(){this.cache.clear(),this.appliedTransforms=[],this.signature=null,super.dispose()}computeBoundingSphere(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere);const t=this.attributes.position.array,n=this.attributes.position.itemSize;if(!t||!n||t.length<2)return this.boundingSphere.radius=0,void this.boundingSphere.center.set(0,0,0);!function(e,t){G(e);const n=F.min[0],r=F.min[1],i=F.min[2],o=F.max[0]-n,s=F.max[1]-r,a=F.max[2]-i,l=Math.sqrt(o*o+s*s+a*a);t.center.set(n+o/2,r+s/2,i+a/2),t.radius=l/2}(t,this.boundingSphere),isNaN(this.boundingSphere.radius)&&console.error('BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.')}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new e.Box3);const t=this.boundingBox,n=this.attributes.position.array,r=this.attributes.position.itemSize;if(!n||!r||n.length<2)return void t.makeEmpty();return P(n,t)}}class W extends e.ShaderMaterial{constructor(t={}){super(t={...{side:e.FrontSide,transparent:!0,extensions:{derivatives:!0},uniforms:{uOpacity:{value:1},uOffset:{value:0},uColor:{value:new e.Color("#ffffff")},uMap:{value:null}},vertexShader:"#define GLSLIFY 1\nvarying vec2 vUv;void main(){vec4 mvPosition=vec4(position,1.0);mvPosition=modelViewMatrix*mvPosition;gl_Position=projectionMatrix*mvPosition;vUv=uv;}",fragmentShader:"#define GLSLIFY 1\nvarying vec2 vUv;uniform float uOpacity;uniform float uOffset;uniform vec3 uColor;uniform sampler2D uMap;float median(float r,float g,float b){return max(min(r,g),min(max(r,g),b));}void main(){vec3 s=texture2D(uMap,vUv).rgb;float sigDist=median(s.r,s.g,s.b)-0.5+uOffset;float alpha=clamp(sigDist/fwidth(sigDist)+0.5,0.0,1.0);if(alpha<0.01)discard;gl_FragColor=vec4(uColor,uOpacity*alpha);}"},...t})}}const z=r.createContext(null),N=e=>{var t,n;return[e.bold,null==(t=e.color)?void 0:t.getHexString(),e.opacity,e.outlineWidth,e.outlineOpacity,null==(n=e.outlineColor)?void 0:n.getHexString()].join("_")},Y=r.forwardRef((function({instanceKey:e,bold:t,color:n,opacity:i,outlineWidth:o,outlineOpacity:s,outlineColor:a,text:l,alignX:u,alignY:c,letterSpacing:h,yShift:f,width:p,lineHeight:g,onBeforeUpdate:m},y){const x=r.useContext(z);if(!x)throw new Error("No SDFTextProvider");const v=r.useRef(null),b=r.useRef(null);return r.useImperativeHandle(y,(()=>({setTransform(e){b.current&&(b.current.transform=e)}})),[]),r.useLayoutEffect((()=>{var r;const d={bold:t,color:n,opacity:i,outlineWidth:o,outlineOpacity:s,outlineColor:a},y={text:l,alignX:u,alignY:c,letterSpacing:h,yShift:f,width:p,lineHeight:g,onBeforeUpdate:m},S=N(d);return b.current=x.insertInstance(S,d,e,y,null!==(r=v.current)&&void 0!==r?r:void 0),()=>x.removeInstance(S,e)}),[x,e,l,u,c,h,f,p,g,t,n,i,o,s,a,m]),d.createElement("group",{ref:v})}));function q(){s.extend({MSDFTextMaterial:W,MSDFTextGeometry:U})}const R=99999,X=99998,K=new e.Matrix4,J=new e.Matrix4,Z=new e.Color("#ffffff"),Q=new e.Color("#000000"),$=.01;function ee({instances:e,textStyle:t,atlas:n,font:i,atlasBold:o,fontBold:a,...l}){var u;const c=o&&a&&t.bold,h=c?a.data:i.data,p=r.useState((()=>new U({font:h,texts:[]})))[0];r.useLayoutEffect((()=>()=>p.dispose()),[p]),r.useLayoutEffect((()=>{const t=e.map((e=>e.config));p.update({font:h,texts:t})}),[p,e,h]),s.useFrame((()=>{e.forEach(((t,n)=>{null==t.config.onBeforeUpdate||t.config.onBeforeUpdate(),J.identity();const r=e[n].object;r&&(r.updateMatrixWorld(),J.multiply(r.matrixWorld)),J.multiply(t.transform),K.makeScale($,$,$),J.multiply(K);const i=p._layouts[n];if(i){var o,s,a,l;const e=null!==(o=i.width)&&void 0!==o?o:0,t=null!==(s=i.height)&&void 0!==s?s:0,n=null!==(a=i.lineHeight)&&void 0!==a?a:0,r=null!==(l=i._options.yShift)&&void 0!==l?l:0,u=n/4-t,c=n/2;let h=0;"center"===i._options.alignX&&(h=-e/2),"right"===i._options.alignX&&(h=-e);let d=u+r;"middle"===i._options.alignY&&(d=(u+c)/2-i.ascender+r),"bottom"===i._options.alignY&&(d=c+r),K.makeTranslation(h,d,0),J.multiply(K)}K.makeRotationX(Math.PI),J.multiply(K),p.setTransform(J,n)}))}));const g=r.useMemo((()=>{var e,r;return{uMap:{value:c?o:n},uColor:{value:null!==(e=t.color)&&void 0!==e?e:Z},uOpacity:{value:null!==(r=t.opacity)&&void 0!==r?r:1},uOffset:{value:0}}}),[c,t.opacity,t.color,n,o]),m=r.useMemo((()=>{var e,r;return{uMap:{value:c?o:n},uColor:{value:null!==(e=t.outlineColor)&&void 0!==e?e:Q},uOpacity:{value:null!==(r=t.outlineOpacity)&&void 0!==r?r:.4},uOffset:{value:t.outlineWidth}}}),[c,t.outlineOpacity,t.outlineColor,t.outlineWidth,n,o]);return d.createElement(d.Fragment,null,d.createElement("mesh",f.default({geometry:p,frustumCulled:!1,renderOrder:R},l),d.createElement("mSDFTextMaterial",{uniforms:g})),(null!==(u=t.outlineWidth)&&void 0!==u?u:0)>0&&d.createElement("mesh",f.default({geometry:p,frustumCulled:!1,renderOrder:X},l),d.createElement("mSDFTextMaterial",{uniforms:m,depthWrite:!1})))}const te=new e.Matrix4,ne=new e.Matrix4;function re(){s.extend({InstancedTextPlaceholder:ue})}class ie{boundingBox=null;boundingSphere=null;computeBoundingBox(){this.boundingBox||(this.boundingBox=new e.Box3)}computeBoundingSphere(){this.boundingSphere||(this.boundingSphere=new e.Sphere)}}const oe=new e.Matrix4,se=new e.Ray,ae=new e.Sphere,le=new e.Vector3;class ue extends e.Group{textAPI=void 0;geometry=new ie;raycast(e,t){const n=this.geometry,r=this.matrixWorld;null===n.boundingSphere&&n.computeBoundingSphere(),ae.copy(n.boundingSphere),ae.applyMatrix4(r),!1!==e.ray.intersectsSphere(ae)&&(oe.copy(r).invert(),se.copy(e.ray).applyMatrix4(oe),null!==n.boundingBox&&null===se.intersectBox(n.boundingBox,le)||t.push({distance:le.distanceTo(e.ray.origin),point:le.clone(),object:this}))}}const ce=()=>new e.MeshPhongMaterial;function he(t,n,i,o=ce){return r.useMemo((()=>{const r=o();return r.onBeforeCompile=r=>{r.uniforms={...r.uniforms,offsets:{value:t},normals:{value:n},shift:{value:new e.Vector3(i.xShift,i.yShift,i.zShift)},scale:{value:new e.Vector3(i.xScale,i.yScale,i.zScale)}},r.vertexShader=r.vertexShader.replace(/#include <morphtarget_pars_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <morphtarget_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <morphcolor_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <morphnormal_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinning_pars_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinbase_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinning_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <skinnormal_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <displacementmap_pars_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/#include <displacementmap_vertex>/gi,""),r.vertexShader=r.vertexShader.replace(/>[\n]*void/,">\n uniform sampler2D offsets;\n uniform sampler2D normals;\n uniform vec3 shift;\n uniform vec3 scale;\n in float instanceGIndex;\n\n void"),r.vertexShader=r.vertexShader.replace(/void main\(\) {/,"void main() { vec3 offset = texelFetch(offsets, ivec2(gl_VertexID, instanceGIndex), 0).rgb * scale + shift;"),r.vertexShader=r.vertexShader.replace(/#include <beginnormal_vertex>/,"vec3 objectNormal = (texelFetch(normals, ivec2(gl_VertexID, instanceGIndex), 0).rgb) - 0.5;"),r.vertexShader=r.vertexShader.replace(/#include <begin_vertex>/,"vec3 transformed = offset;")},r}),[t,n,i,o])}function de(t){const n=o.useTexture(t);return n.flipY=!1,n.magFilter=e.NearestFilter,n.minFilter=e.NearestFilter,n}const fe=r.createContext(null);const pe=r.forwardRef((function({font:t},n){const i=he(de(t.offsetsPath),de(t.normalsPath),t.fontMetadata),[{instanceAllocated:o,geometry:a},l]=r.useState({instanceAllocated:0,geometry:null}),u=r.useRef(null),c=r.useCallback((n=>(u.current=function(t,n,r){var i,o,s,a;null==t||t.geometry.dispose();const l=new e.InstancedBufferGeometry;l.instanceCount=n;const u=new Float32Array(3*r),c=new e.Float32BufferAttribute(u,3,!1);l.setAttribute("position",c);const h=new Float32Array(16*l.instanceCount),d=new e.InstancedBufferAttribute(h,16,!1,1);l.setAttribute("instanceMatrix",d);const f=new Float32Array(l.instanceCount);t&&f.set(t.currentGlyphs);const p=new e.InstancedBufferAttribute(f,1,!1,1);l.setAttribute("instanceGIndex",p);const g=new Float32Array(4*l.instanceCount);t&&g.set(t.currentColors);const m=new e.InstancedBufferAttribute(g,4,!0,1);return l.setAttribute("instanceColor",m),{instanceAllocated:n,geometry:l,currentInstances:null!==(i=null==t?void 0:t.currentInstances)&&void 0!==i?i:[],currentGlyphs:null!==(o=null==t?void 0:t.currentGlyphs)&&void 0!==o?o:[],currentShifts:null!==(s=null==t?void 0:t.currentShifts)&&void 0!==s?s:[],currentColors:null!==(a=null==t?void 0:t.currentColors)&&void 0!==a?a:[],instanceMatrixBuffer:h,instanceMatrixBufferAttribute:d,instanceGIndexBuffer:f,instanceGIndexBufferAttribute:p,instanceColorBuffer:g,instanceColorBufferAttribute:m}}(u.current,n,t.fontMetadata.maxVertices),l({instanceAllocated:n,geometry:u.current.geometry}),u.current)),[t.fontMetadata.maxVertices]);return r.useImperativeHandle(n,(()=>({font:t,addInstances:(e,t,n,r,i)=>{var o;const s=null!==(o=u.current)&&void 0!==o?o:c(2*e.length),a=function(e,t,n,r,i,o,s){const a=e.currentGlyphs.length,l=n.length,u=Array.from(n).map((e=>t[e])),c=Array.from(n).flatMap((()=>[i.r,i.g,i.b,1]));e.currentGlyphs.push(...u),e.currentShifts.push(...o),e.currentColors.push(...c);const h={start:a,length:l,text:n,parentGroup:s,font:r};return e.currentInstances.push(h),h}(s,t.fontMetadata.charToIndex,e,t,n,r,i);return s.currentGlyphs.length>s.instanceAllocated?c(2*s.currentGlyphs.length):function(e){e.instanceGIndexBuffer.set(e.currentGlyphs),e.instanceGIndexBufferAttribute.needsUpdate=!0,e.instanceColorBuffer.set(e.currentColors),e.instanceColorBufferAttribute.needsUpdate=!0}(s),a},removeInstances:e=>{const t=u.current;t&&function(e,t){const n=e.currentInstances.indexOf(t);if(-1!==n){for(let r=0;r<e.currentInstances.length;r++)r>n&&(e.currentInstances[r].start-=t.length);e.currentInstances.splice(n,1),e.currentGlyphs.splice(t.start,t.length),e.currentShifts.splice(2*t.start,2*t.length),e.currentColors.splice(4*t.start,4*t.length),e.instanceGIndexBuffer.fill(0),e.instanceGIndexBuffer.set(e.currentGlyphs),e.instanceGIndexBufferAttribute.needsUpdate=!0,e.instanceColorBuffer.fill(0),e.instanceColorBuffer.set(e.currentColors),e.instanceColorBufferAttribute.needsUpdate=!0,e.instanceMatrixBuffer.fill(0),e.instanceMatrixBufferAttribute.needsUpdate=!0}}(t,e)},setOpacity:(e,t)=>{const n=u.current;if(n&&n.instanceColorBuffer&&n.instanceColorBufferAttribute){for(let r=0;r<e.length;r++)n.currentColors[4*(e.start+r)+3]=t,n.instanceColorBuffer[4*(e.start+r)+3]=t;n.instanceColorBufferAttribute.needsUpdate=!0}},getBuffers:()=>u.current})),[t,c]),s.useFrame((()=>{const e=u.current;e&&function(e){e.currentInstances.forEach((t=>{for(let n=0;n<t.length;n++){const r=e.currentShifts[2*(t.start+n)],i=e.currentShifts[2*(t.start+n)+1];ne.copy(t.parentGroup.matrixWorld),te.identity().setPosition(r,i,0),ne.multiply(te),ne.toArray(e.instanceMatrixBuffer,16*(t.start+n))}})),e.instanceMatrixBufferAttribute.needsUpdate=!0}(e)})),a?d.createElement("instancedMesh",{frustumCulled:!1,args:[a,i,o]}):null}));let ge=function(e){return e.left="left",e.right="right",e.center="center",e}({});const me=new e.Color("white");exports.InstancedText=function({text:t,thickness:n,fontSize:i,textAlign:o,scale:s,color:a,opacity:l,font:u,...c}){var h,p,g;const m=u.fontMetadata.charToIndex["?"],y=function(){const e=r.useContext(fe);if(!e)throw new Error("No instanced text context");return e}(),x=r.useRef(null),v=r.useRef(null);r.useLayoutEffect((()=>{const r=x.current;if(!r)return;const i=u.fontMetadata.fontScale,s=(u.fontMetadata.boundingBox.yMax-u.fontMetadata.boundingBox.yMin+u.fontMetadata.underlineThickness)*i,l=new Float32Array(t.length),c=new Float32Array(2*t.length);let h=0,d=0;const f=[];Array.from(t).forEach(((e,t)=>{if("\n"===e)f.push(h),h=0,d-=s;else{var n;const r=u.fontMetadata.charToIndex[e],o=null!==(n=u.fontMetadata.advances[r])&&void 0!==n?n:u.fontMetadata.advances[m];l[t]=i,c[2*t]=h,c[2*t+1]=d,h+=o*i}})),f.push(h);const p=Math.max(...f),g=-((u.fontMetadata.boundingBox.yMax-u.fontMetadata.boundingBox.yMin)/2+u.fontMetadata.boundingBox.yMin)*i;Array.from(t).forEach(((e,t)=>{l[t]>0&&(o===ge.left&&(c[2*t+1]+=g),o===ge.right&&(c[2*t]-=p,c[2*t+1]+=g),o===ge.center&&(c[2*t]-=p/2,c[2*t+1]+=g))})),r.geometry.boundingBox||(r.geometry.boundingBox=new e.Box3),r.geometry.boundingSphere||(r.geometry.boundingSphere=new e.Sphere),r.geometry.boundingBox.setFromPoints([new e.Vector3(0,u.fontMetadata.boundingBox.yMin*i,0),new e.Vector3(p,u.fontMetadata.boundingBox.yMax*i,n)]),r.geometry.boundingSphere.setFromPoints([new e.Vector3(0,u.fontMetadata.boundingBox.yMin*i,0),new e.Vector3(p,u.fontMetadata.boundingBox.yMax*i,n)]),o===ge.left&&(r.geometry.boundingBox.translate(new e.Vector3(0,g,0)),r.geometry.boundingSphere.translate(new e.Vector3(0,g,0))),o===ge.right&&(r.geometry.boundingBox.translate(new e.Vector3(-p,g,0)),r.geometry.boundingSphere.translate(new e.Vector3(-p,g,0))),o===ge.center&&(r.geometry.boundingBox.translate(new e.Vector3(-p/2,g,0)),r.geometry.boundingSphere.translate(new e.Vector3(-p/2,g,0)));const b=y.addInstances(t,u,null!=a?a:me,c,r);return b?(v.current=b,()=>y.removeInstances(b)):void 0}),[t,a,u.fontMetadata,m,n,o,y]),r.useEffect((()=>{v.current&&y.setOpacity(v.current,null!=l?l:1)}),[y,l]);const b=r.useMemo((()=>({getBuffers:()=>v.current&&y.getBuffers(v.current),getPtr:()=>v.current,setGlyphs:e=>{if(!v.current)return;const t=y.getBuffers(v.current);if(!t)return;const n=Array.from(e).map((e=>u.fontMetadata.charToIndex[e]));t.instanceGIndexBuffer.set(n,v.current.start),t.instanceGIndexBufferAttribute.needsUpdate=!0}})),[u.fontMetadata.charToIndex]);return d.createElement("instancedTextPlaceholder",f.default({scale:[i*(null!==(h=null==s?void 0:s.x)&&void 0!==h?h:1),i*(null!==(p=null==s?void 0:s.y)&&void 0!==p?p:1),n*(null!==(g=null==s?void 0:s.z)&&void 0!==g?g:1)]},c,{textAPI:b,ref:x,frustumCulled:!1}))},exports.InstancedTextProvider=function({children:e,styles:t}){r.useMemo(re,[]);const n=r.useRef(new WeakMap),i=r.useCallback((e=>{e&&n.current.set(e.font,e)}),[]),o=r.useMemo((()=>({addInstances:(e,t,r,i,o)=>{const s=n.current.get(t);return null==s?void 0:s.addInstances(e,t,r,i,o)},removeInstances:e=>{const t=n.current.get(e.font);null==t||t.removeInstances(e)},setOpacity:(e,t)=>{const r=n.current.get(e.font);null==r||r.setOpacity(e,t)},getBuffers:e=>{var t;const r=n.current.get(e.font);return null!==(t=null==r?void 0:r.getBuffers(e))&&void 0!==t?t:null}})),[]);return d.createElement(fe.Provider,{value:o},t.map((e=>d.createElement(pe,{key:e.offsetsPath,font:e,ref:i}))),e)},exports.MSDFTextGeometry=U,exports.MSDFTextMaterial=W,exports.SDFText=Y,exports.SDFTextProvider=function({children:t,fontPathRegular:n,fontPathBold:i}){r.useMemo(q,[]),d.useEffect((()=>{console.log("Hello, World! This is a SABO fork of thomas engine.")}),[]);const l=o.useTexture(n.sdfPath),u=s.useLoader(a.FontLoader,n.fontPath),c=o.useTexture(i?i.sdfPath:[]),h=s.useLoader(a.FontLoader,i?i.fontPath:[]),f=r.useState((()=>new Map))[0],p=r.useState(0)[1],g=r.useMemo((()=>({insertInstance(t,n,r,i,o){var s;const a={instanceKey:r,config:i,object:o,transform:new e.Matrix4},l=f.get(t);return f.set(t,{textStyle:n,instances:[...null!==(s=null==l?void 0:l.instances)&&void 0!==s?s:[],a]}),p((e=>e+1)),a},removeInstance(e,t){const n=f.get(e);if(n){const r=n.instances.filter((e=>e.instanceKey!==t));0===r.length?f.delete(e):f.set(e,{textStyle:n.textStyle,instances:r}),p((e=>e+1))}}})),[]);return d.createElement(z.Provider,{value:g},d.createElement(d.Fragment,null,t,Array.from(f.values()).map((e=>d.createElement(ee,{key:N(e.textStyle),textStyle:e.textStyle,instances:e.instances,atlas:l,font:u,atlasBold:Array.isArray(c)?void 0:c,fontBold:Array.isArray(h)?void 0:h})))))};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saboit-dev/thomas",
3
- "version": "1.1.0-alpha.1",
3
+ "version": "1.1.0-alpha.2",
4
4
  "private": false,
5
5
  "description": "",
6
6
  "keywords": [],
@@ -1 +1 @@
1
- "use strict";function t(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}Object.defineProperty(exports,"__esModule",{value:!0});var e=t(require("word-wrapper"));const n=["x","e","a","o","n","s","r","c","u","m","v","w","z"],i=["m","w"],r=["H","I","N","E","F","K","L","T","U","V","W","X","Y","Z"],s="\t".charCodeAt(0),h=" ".charCodeAt(0),l=1,o=2;class a{_options={};_width=0;_height=0;_descender=0;_ascender=0;_xHeight=0;_baseline=0;_capHeight=0;_lineHeight=0;_linesTotal=0;_lettersTotal=0;_wordsTotal=0;_fallbackSpaceGlyph=null;_fallbackTabGlyph=null;constructor(t,e={}){this.glyphs=[],this._text=t,this._measure=this.computeMetrics.bind(this),this.update(e)}get width(){return this._width}get height(){return this._height}get descender(){return this._descender}get ascender(){return this._ascender}get xHeight(){return this._xHeight}get baseline(){return this._baseline}get capHeight(){return this._capHeight}get lineHeight(){return this._lineHeight}get linesTotal(){return this._linesTotal}get lettersTotal(){return this._lettersTotal}get wordsTotal(){return this._wordsTotal}update(t){if(t=Object.assign({measure:this._measure},t),this._options=t,this._options.tabSize=f(this._options.tabSize,4),!t.font)throw new Error("must provide a valid bitmap font");const i=this.glyphs,s=this._text||"",a=t.font;this._setupSpaceGlyphs(a);const c=e.default.lines(s,t),g=t.width||0,p=s.split(" ").filter((t=>"\n"!==t)).length,_=s.split("").filter((t=>"\n"!==t&&" "!==t)).length;i.length=0;const b=c.reduce((function(t,e){return Math.max(t,e.width,g)}),0);let x=0,w=0;const y=f(t.lineHeight,a.common.lineHeight),T=a.common.base,m=y-T,H=t.letterSpacing||0,G=y*c.length-m,k=function(t){if("center"===t)return l;if("right"===t)return o;return 0}(this._options.alignX);w-=G,this._width=b,this._height=G,this._descender=y-T,this._baseline=T,this._xHeight=function(t){for(const e of n){const n=d(t.chars,e.charCodeAt(0));if(n>=0)return t.chars[n].height}return 0}(a),this._capHeight=function(t){for(const e of r){const n=d(t.chars,e.charCodeAt(0));if(n>=0)return t.chars[n].height}return 0}(a),this._lineHeight=y,this._ascender=y-m-this._xHeight;let v=0,S=0;c.forEach(((t,e)=>{const n=t.start,r=t.end,d=t.width,f=s.slice(n,r).split(" ").filter((t=>""!==t)).length,g=s.slice(n,r).split(" ").join("").length;let T,m=0,G=0;for(let t=n;t<r;t++){const n=s.charCodeAt(t),r=this.getGlyph(a,n);if(r){T&&(x+=u(a,T.id,r.id));let n=x;k===l?n+=(b-d)/2:k===o&&(n+=b-d),i.push({position:[n,w],data:r,index:t,linesTotal:c.length,lineIndex:e,lineLettersTotal:g,lineLetterIndex:m,lineWordsTotal:f,lineWordIndex:G,wordsTotal:p,wordIndex:v,lettersTotal:_,letterIndex:S}),r.id===h&&T.id!==h&&(G++,v++),r.id!==h&&(m++,S++),x+=r.xadvance+H,T=r}}w+=y,x=0})),this._lettersTotal=_,this._wordsTotal=p,this._linesTotal=c.length}getGlyph(t,e){const n=c(t,e);return n||(e===s?this._fallbackTabGlyph:e===h?this._fallbackSpaceGlyph:null)}computeMetrics(t,e,n,i){const r=this._options.letterSpacing||0,s=this._options.font;let h,l,o=0,a=0,c=0;if(!s.chars||0===s.chars.length)return{start:e,end:e,width:0};n=Math.min(t.length,n);for(let d=e;d<n;d++){const e=t.charCodeAt(d);if(h=this.getGlyph(s,e),h){h.char=t[d];o+=l?u(s,l.id,h.id):0;const e=o+h.xadvance+r,n=o+h.width;if(n>=i||e>=i)break;o=e,a=n,l=h}c++}return l&&(a+=l.xoffset),{start:e,end:e+c,width:a}}_setupSpaceGlyphs(t){var e;if(this._fallbackSpaceGlyph=null,this._fallbackTabGlyph=null,!t.chars||0===t.chars.length)return;const n=c(t,h)||function(t){for(const e of i){const n=d(t.chars,e.charCodeAt(0));if(n>=0)return t.chars[n]}return 0}(t)||t.chars[0],r=(null!==(e=this._options.tabSize)&&void 0!==e?e:1)*n.xadvance;this._fallbackSpaceGlyph=n;const l=Object.assign({},n);this._fallbackTabGlyph=Object.assign(l,{x:0,y:0,xadvance:r,id:s,xoffset:0,yoffset:0,width:0,height:0})}}function c(t,e){if(!t.chars||0===t.chars.length)return null;const n=d(t.chars,e);if(n>=0){return t.chars[n]}return null}function u(t,e,n){if(!t.kernings||0===t.kernings.length)return 0;const i=t.kernings;for(const t of i)if(t.first===e&&t.second===n)return t.amount;return 0}function d(t,e,n){for(let i=n=n||0;i<t.length;i++)if(t[i].id===e)return i;return-1}function f(t,e){return"number"==typeof t?t:"number"==typeof e?e:0}exports.createLayout=function(t,e){return new a(t,e)},exports.default=a;
1
+ "use strict";function t(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}Object.defineProperty(exports,"__esModule",{value:!0});var e=t(require("word-wrapper"));const n=["x","e","a","o","n","s","r","c","u","m","v","w","z"],i=["m","w"],s=["H","I","N","E","F","K","L","T","U","V","W","X","Y","Z"],r="\t".charCodeAt(0),l=" ".charCodeAt(0),h=1,o=2;class a{_options={};_width=0;_height=0;_descender=0;_ascender=0;_xHeight=0;_baseline=0;_capHeight=0;_lineHeight=0;_linesTotal=0;_lettersTotal=0;_wordsTotal=0;_fallbackSpaceGlyph=null;_fallbackTabGlyph=null;constructor(t,e={}){this.glyphs=[],this._text=t,this._measure=this.computeMetrics.bind(this),this.update(e)}get width(){return this._width}get height(){return this._height}get descender(){return this._descender}get ascender(){return this._ascender}get xHeight(){return this._xHeight}get baseline(){return this._baseline}get capHeight(){return this._capHeight}get lineHeight(){return this._lineHeight}get linesTotal(){return this._linesTotal}get lettersTotal(){return this._lettersTotal}get wordsTotal(){return this._wordsTotal}update(t){if(t=Object.assign({measure:this._measure},t),this._options=t,this._options.tabSize=_(this._options.tabSize,4),!t.font)throw new Error("must provide a valid bitmap font");const i=this.glyphs,r=this._text||"",a=t.font;this._setupSpaceGlyphs(a);const c=e.default.lines(r,t),u=t.width||0,d=r.split(" ").filter((t=>"\n"!==t)).length,g=r.split("").filter((t=>"\n"!==t&&" "!==t)).length;i.length=0;const b=c.reduce((function(t,e){return Math.max(t,e.width,u)}),0);let v=0,w=0;const y=_(t.lineHeight,a.common.lineHeight),x=a.common.base,T=y-x,m=t.letterSpacing||0,H=y*c.length-T,k=function(t){if("center"===t)return h;if("right"===t)return o;return 0}(this._options.alignX);w-=H,this._width=b,this._height=H,this._descender=y-x,this._baseline=x,this._xHeight=function(t){var e,i;return null!==(e=null==(i=p(t,n))?void 0:i.height)&&void 0!==e?e:0}(a),this._capHeight=function(t){var e,n;return null!==(e=null==(n=p(t,s))?void 0:n.height)&&void 0!==e?e:0}(a),this._lineHeight=y,this._ascender=y-T-this._xHeight;let G=0,S=0;c.forEach(((t,e)=>{const n=t.start,s=t.end,u=t.width,p=r.slice(n,s).split(" ").filter((t=>""!==t)).length,_=r.slice(n,s).split(" ").join("").length;let x,T=0,H=0;for(let t=n;t<s;t++){const n=r.charCodeAt(t),s=this.getGlyph(a,n);if(s){x&&(v+=f(a,x.id,s.id));let n=v;k===h?n+=(b-u)/2:k===o&&(n+=b-u),i.push({position:[n,w],data:s,index:t,linesTotal:c.length,lineIndex:e,lineLettersTotal:_,lineLetterIndex:T,lineWordsTotal:p,lineWordIndex:H,wordsTotal:d,wordIndex:G,lettersTotal:g,letterIndex:S}),s.id===l&&x.id!==l&&(H++,G++),s.id!==l&&(T++,S++),v+=s.xadvance+m,x=s}}w+=y,v=0})),this._lettersTotal=g,this._wordsTotal=d,this._linesTotal=c.length}getGlyph(t,e){const n=g(t,e);return n||(e===r?this._fallbackTabGlyph:e===l?this._fallbackSpaceGlyph:null)}computeMetrics(t,e,n,i){const s=this._options.letterSpacing||0,r=this._options.font;let l,h,o=0,a=0,c=0;if(!r.chars||0===r.chars.length)return{start:e,end:e,width:0};n=Math.min(t.length,n);for(let u=e;u<n;u++){const e=t.charCodeAt(u);if(l=this.getGlyph(r,e),l){l.char=t[u];o+=h?f(r,h.id,l.id):0;const e=o+l.xadvance+s,n=o+l.width;if(n>=i||e>=i)break;o=e,a=n,h=l}c++}return h&&(a+=h.xoffset),{start:e,end:e+c,width:a}}_setupSpaceGlyphs(t){var e;if(this._fallbackSpaceGlyph=null,this._fallbackTabGlyph=null,!t.chars||0===t.chars.length)return;const n=g(t,l)||function(t){var e;return null!==(e=p(t,i))&&void 0!==e?e:0}(t)||t.chars[0],s=(null!==(e=this._options.tabSize)&&void 0!==e?e:1)*n.xadvance;this._fallbackSpaceGlyph=n;const h=Object.assign({},n);this._fallbackTabGlyph=Object.assign(h,{x:0,y:0,xadvance:s,id:r,xoffset:0,yoffset:0,width:0,height:0})}}const c=1114112,u=new WeakMap;function d(t){let e=u.get(t);if(e)return e;e={glyphs:new Map,kernings:new Map};for(const i of null!==(n=t.chars)&&void 0!==n?n:[]){var n;e.glyphs.has(i.id)||e.glyphs.set(i.id,i)}for(const n of null!==(i=t.kernings)&&void 0!==i?i:[]){var i;const t=n.first*c+n.second;e.kernings.has(t)||e.kernings.set(t,n.amount)}return u.set(t,e),e}function g(t,e){var n;return null!==(n=d(t).glyphs.get(e))&&void 0!==n?n:null}function p(t,e){const{glyphs:n}=d(t);for(const t of e){const e=n.get(t.charCodeAt(0));if(e)return e}return null}function f(t,e,n){var i;return null!==(i=d(t).kernings.get(e*c+n))&&void 0!==i?i:0}function _(t,e){return"number"==typeof t?t:"number"==typeof e?e:0}exports.createLayout=function(t,e){return new a(t,e)},exports.default=a;
@@ -283,55 +283,67 @@ class TextLayout {
283
283
  function createLayout(text, options) {
284
284
  return new TextLayout(text, options);
285
285
  }
286
- function getGlyphById(font, id) {
287
- if (!font.chars || font.chars.length === 0) {
288
- return null;
286
+
287
+ /** Glyph ids are code points, so a kerning pair packs into one number. */
288
+ const KERNING_STRIDE = 0x110000;
289
+ const fontIndexes = new WeakMap();
290
+
291
+ /**
292
+ * Index a font's glyphs and kerning pairs once.
293
+ *
294
+ * The layout looks up every character and every adjacent pair. A linear scan over a few thousand
295
+ * kerning pairs made that the hottest loop of the engine. The index assumes that font data does
296
+ * not change after it is loaded.
297
+ */
298
+ function indexFont(font) {
299
+ let index = fontIndexes.get(font);
300
+ if (index) return index;
301
+ index = {
302
+ glyphs: new Map(),
303
+ kernings: new Map()
304
+ };
305
+ // The first entry wins, as it did with the linear scan
306
+ for (const glyph of (_font$chars = font.chars) !== null && _font$chars !== void 0 ? _font$chars : []) {
307
+ var _font$chars;
308
+ if (!index.glyphs.has(glyph.id)) index.glyphs.set(glyph.id, glyph);
309
+ }
310
+ for (const kern of (_font$kernings = font.kernings) !== null && _font$kernings !== void 0 ? _font$kernings : []) {
311
+ var _font$kernings;
312
+ const pair = kern.first * KERNING_STRIDE + kern.second;
313
+ if (!index.kernings.has(pair)) index.kernings.set(pair, kern.amount);
289
314
  }
290
- const glyphIdx = findChar(font.chars, id);
291
- if (glyphIdx >= 0) {
292
- const glyph = font.chars[glyphIdx];
293
- return glyph;
315
+ fontIndexes.set(font, index);
316
+ return index;
317
+ }
318
+ function getGlyphById(font, id) {
319
+ var _indexFont$glyphs$get;
320
+ return (_indexFont$glyphs$get = indexFont(font).glyphs.get(id)) !== null && _indexFont$glyphs$get !== void 0 ? _indexFont$glyphs$get : null;
321
+ }
322
+ function getFirstGlyph(font, chars) {
323
+ const {
324
+ glyphs
325
+ } = indexFont(font);
326
+ for (const char of chars) {
327
+ const glyph = glyphs.get(char.charCodeAt(0));
328
+ if (glyph) return glyph;
294
329
  }
295
330
  return null;
296
331
  }
297
332
  function getXHeight(font) {
298
- for (const id of X_HEIGHTS) {
299
- const idx = findChar(font.chars, id.charCodeAt(0));
300
- if (idx >= 0) {
301
- return font.chars[idx].height;
302
- }
303
- }
304
- return 0;
333
+ var _getFirstGlyph$height, _getFirstGlyph;
334
+ return (_getFirstGlyph$height = (_getFirstGlyph = getFirstGlyph(font, X_HEIGHTS)) == null ? void 0 : _getFirstGlyph.height) !== null && _getFirstGlyph$height !== void 0 ? _getFirstGlyph$height : 0;
305
335
  }
306
336
  function getMGlyph(font) {
307
- for (const id of M_WIDTHS) {
308
- const idx = findChar(font.chars, id.charCodeAt(0));
309
- if (idx >= 0) {
310
- return font.chars[idx];
311
- }
312
- }
313
- return 0;
337
+ var _getFirstGlyph2;
338
+ return (_getFirstGlyph2 = getFirstGlyph(font, M_WIDTHS)) !== null && _getFirstGlyph2 !== void 0 ? _getFirstGlyph2 : 0;
314
339
  }
315
340
  function getCapHeight(font) {
316
- for (const id of CAP_HEIGHTS) {
317
- const idx = findChar(font.chars, id.charCodeAt(0));
318
- if (idx >= 0) {
319
- return font.chars[idx].height;
320
- }
321
- }
322
- return 0;
341
+ var _getFirstGlyph$height2, _getFirstGlyph3;
342
+ return (_getFirstGlyph$height2 = (_getFirstGlyph3 = getFirstGlyph(font, CAP_HEIGHTS)) == null ? void 0 : _getFirstGlyph3.height) !== null && _getFirstGlyph$height2 !== void 0 ? _getFirstGlyph$height2 : 0;
323
343
  }
324
344
  function getKerning(font, left, right) {
325
- if (!font.kernings || font.kernings.length === 0) {
326
- return 0;
327
- }
328
- const table = font.kernings;
329
- for (const kern of table) {
330
- if (kern.first === left && kern.second === right) {
331
- return kern.amount;
332
- }
333
- }
334
- return 0;
345
+ var _indexFont$kernings$g;
346
+ return (_indexFont$kernings$g = indexFont(font).kernings.get(left * KERNING_STRIDE + right)) !== null && _indexFont$kernings$g !== void 0 ? _indexFont$kernings$g : 0;
335
347
  }
336
348
  function getAlignType(align) {
337
349
  if (align === 'center') {
@@ -341,15 +353,6 @@ function getAlignType(align) {
341
353
  }
342
354
  return ALIGN_LEFT;
343
355
  }
344
- function findChar(array, value, start) {
345
- start = start || 0;
346
- for (let i = start; i < array.length; i++) {
347
- if (array[i].id === value) {
348
- return i;
349
- }
350
- }
351
- return -1;
352
- }
353
356
  function number(num, def) {
354
357
  return typeof num === 'number' ? num : typeof def === 'number' ? def : 0;
355
358
  }
@@ -1 +1 @@
1
- "use strict";var t=require("quad-indices"),i=require("three"),s=require("./TextLayout.cjs.js"),e=require("./utils.cjs.js"),r=require("./vertices.cjs.js");function o(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}require("word-wrapper");var n=o(t);const a=new i.Vector3,h=new i.Vector3,u=new i.Vector3,p=new i.Vector3;class c extends i.BufferGeometry{originalPositionsArray=new Float32Array;positionsArray=new Float32Array;positionsAttribute=null;instancesOffsetsCache=[];instancesLengthsCache=[];constructor(t){super(),this._layouts=[],this.update(t)}setTransform(t,i=0){const s=this.instancesOffsetsCache[i],e=this.instancesLengthsCache[i];for(let i=0;i<e;i++){const e=12*s+12*i,r=this.originalPositionsArray[e],o=this.originalPositionsArray[e+1],n=this.originalPositionsArray[e+2],c=this.originalPositionsArray[e+3],l=this.originalPositionsArray[e+4],y=this.originalPositionsArray[e+5],A=this.originalPositionsArray[e+6],g=this.originalPositionsArray[e+7],d=this.originalPositionsArray[e+8],f=this.originalPositionsArray[e+9],b=this.originalPositionsArray[e+10],m=this.originalPositionsArray[e+11];a.set(r,o,n).applyMatrix4(t),h.set(c,l,y).applyMatrix4(t),u.set(A,g,d).applyMatrix4(t),p.set(f,b,m).applyMatrix4(t),this.positionsArray[e]=a.x,this.positionsArray[e+1]=a.y,this.positionsArray[e+2]=a.z,this.positionsArray[e+3]=h.x,this.positionsArray[e+4]=h.y,this.positionsArray[e+5]=h.z,this.positionsArray[e+6]=u.x,this.positionsArray[e+7]=u.y,this.positionsArray[e+8]=u.z,this.positionsArray[e+9]=p.x,this.positionsArray[e+10]=p.y,this.positionsArray[e+11]=p.z}this.positionsAttribute&&(this.positionsAttribute.needsUpdate=!0)}update(t){const{texts:e,...o}=t;this._layouts=e.map((t=>s.createLayout(t.text,{...o,...t})));const a=!1!==t.flipY,h=t.font,u=h.common.scaleW,p=h.common.scaleH,c=this._layouts.map((t=>t.glyphs.filter((t=>{const i=t.data;return i.width*i.height>0}))));this.instancesOffsetsCache=[],this.instancesLengthsCache=[];let l=0;c.forEach(((t,i)=>{this.instancesLengthsCache[i]=t.length,this.instancesOffsetsCache[i]=l,l+=t.length}));const y=l,A=n.default([],{clockwise:!0,type:"uint16",count:y});this.setIndex(A);const g=c.map((t=>r.generateAttributes(t,u,p,a))),d=g.reduce(((t,i)=>t+i.positions.length),0),f=g.reduce(((t,i)=>t+i.centers.length),0),b=g.reduce(((t,i)=>t+i.uvs.length),0),m=new Float32Array(d),x=new Float32Array(f),w=new Float32Array(b);let P=0,B=0,S=0;g.forEach((t=>{m.set(t.positions,P),P+=t.positions.length,x.set(t.centers,B),B+=t.centers.length,w.set(t.uvs,S),S+=t.uvs.length})),this.positionsArray=m,this.originalPositionsArray=new Float32Array(d),this.originalPositionsArray.set(m),this.positionsAttribute=new i.BufferAttribute(m,3),this.setAttribute("position",this.positionsAttribute),this.setAttribute("center",new i.BufferAttribute(x,2)),this.setAttribute("uv",new i.BufferAttribute(w,2))}computeBoundingSphere(){null===this.boundingSphere&&(this.boundingSphere=new i.Sphere);const t=this.attributes.position.array,s=this.attributes.position.itemSize;if(!t||!s||t.length<2)return this.boundingSphere.radius=0,void this.boundingSphere.center.set(0,0,0);e.computeSphere(t,this.boundingSphere),isNaN(this.boundingSphere.radius)&&console.error('BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.')}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new i.Box3);const t=this.boundingBox,s=this.attributes.position.array,r=this.attributes.position.itemSize;if(!s||!r||s.length<2)return void t.makeEmpty();return e.computeBox(s,t)}}module.exports=c;
1
+ "use strict";var t=require("quad-indices"),i=require("three"),s=require("./TextLayout.cjs.js"),e=require("./utils.cjs.js"),r=require("./vertices.cjs.js");function n(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}require("word-wrapper");var o=n(t);const a=new i.Vector3,h=new i.Vector3,u=new i.Vector3,c=new i.Vector3,l=["text","width","lineHeight","letterSpacing","alignX","alignY","yShift","tabSize"];function p(t){return JSON.stringify(l.map((i=>t[i])))}class y extends i.BufferGeometry{originalPositionsArray=new Float32Array;positionsArray=new Float32Array;centersArray=new Float32Array;uvsArray=new Float32Array;positionsAttribute=null;instancesOffsetsCache=[];instancesLengthsCache=[];cache=new Map;cacheFont=null;cacheFlipY=!0;signature=null;glyphsTotal=-1;appliedTransforms=[];constructor(t){super(),this._layouts=[],this.update(t)}setTransform(t,s=0){const e=this.instancesOffsetsCache[s],r=this.instancesLengthsCache[s],n=this.appliedTransforms[s];if(void 0===r||null!=n&&n.equals(t))return!1;for(let i=0;i<r;i++){const s=12*e+12*i,r=this.originalPositionsArray[s],n=this.originalPositionsArray[s+1],o=this.originalPositionsArray[s+2],l=this.originalPositionsArray[s+3],p=this.originalPositionsArray[s+4],y=this.originalPositionsArray[s+5],A=this.originalPositionsArray[s+6],g=this.originalPositionsArray[s+7],f=this.originalPositionsArray[s+8],d=this.originalPositionsArray[s+9],b=this.originalPositionsArray[s+10],m=this.originalPositionsArray[s+11];a.set(r,n,o).applyMatrix4(t),h.set(l,p,y).applyMatrix4(t),u.set(A,g,f).applyMatrix4(t),c.set(d,b,m).applyMatrix4(t),this.positionsArray[s]=a.x,this.positionsArray[s+1]=a.y,this.positionsArray[s+2]=a.z,this.positionsArray[s+3]=h.x,this.positionsArray[s+4]=h.y,this.positionsArray[s+5]=h.z,this.positionsArray[s+6]=u.x,this.positionsArray[s+7]=u.y,this.positionsArray[s+8]=u.z,this.positionsArray[s+9]=c.x,this.positionsArray[s+10]=c.y,this.positionsArray[s+11]=c.z}return this.appliedTransforms[s]=(null!=n?n:new i.Matrix4).copy(t),this.positionsAttribute&&(this.positionsAttribute.needsUpdate=!0),!0}update(t){const{texts:e,...n}=t,a=t.font,h=!1!==t.flipY;a===this.cacheFont&&h===this.cacheFlipY||(this.cache.clear(),this.cacheFont=a,this.cacheFlipY=h,this.signature=null);const u=e.map((t=>({...n,...t}))),c=u.map(p),l=c.join("\n");if(l===this.signature)return;this.signature=l;const y=a.common.scaleW,A=a.common.scaleH,g=u.map(((t,i)=>{var e;const n=c[i],o=null!==(e=this.cache.get(n))&&void 0!==e?e:function(t,i,e,n){const o=s.createLayout(t.text,t),a=o.glyphs.filter((({data:t})=>t.width*t.height>0));return{layout:o,glyphCount:a.length,...r.generateAttributes(a,i,e,n)}}(t,y,A,h);return this.cache.delete(n),this.cache.set(n,o),o}));for(const t of this.cache.keys()){if(this.cache.size<=e.length+256)break;this.cache.delete(t)}this._layouts=g.map((t=>t.layout)),this.instancesOffsetsCache=[],this.instancesLengthsCache=[];let f=0;g.forEach((({glyphCount:t},i)=>{this.instancesLengthsCache[i]=t,this.instancesOffsetsCache[i]=f,f+=t}));const d=f;this.appliedTransforms=[],d!==this.glyphsTotal&&(this.glyphsTotal=d,this.setIndex(o.default([],{clockwise:!0,type:"uint16",count:d})),this.positionsArray=new Float32Array(12*d),this.originalPositionsArray=new Float32Array(12*d),this.centersArray=new Float32Array(8*d),this.uvsArray=new Float32Array(8*d),this.positionsAttribute=new i.BufferAttribute(this.positionsArray,3),this.setAttribute("position",this.positionsAttribute),this.setAttribute("center",new i.BufferAttribute(this.centersArray,2)),this.setAttribute("uv",new i.BufferAttribute(this.uvsArray,2))),g.forEach(((t,i)=>{const s=this.instancesOffsetsCache[i];this.positionsArray.set(t.positions,12*s),this.centersArray.set(t.centers,8*s),this.uvsArray.set(t.uvs,8*s)})),this.originalPositionsArray.set(this.positionsArray);for(const t of["position","center","uv"])this.attributes[t].needsUpdate=!0}dispose(){this.cache.clear(),this.appliedTransforms=[],this.signature=null,super.dispose()}computeBoundingSphere(){null===this.boundingSphere&&(this.boundingSphere=new i.Sphere);const t=this.attributes.position.array,s=this.attributes.position.itemSize;if(!t||!s||t.length<2)return this.boundingSphere.radius=0,void this.boundingSphere.center.set(0,0,0);e.computeSphere(t,this.boundingSphere),isNaN(this.boundingSphere.radius)&&console.error('BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.')}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new i.Box3);const t=this.boundingBox,s=this.attributes.position.array,r=this.attributes.position.itemSize;if(!s||!r||s.length<2)return void t.makeEmpty();return e.computeBox(s,t)}}module.exports=y;
@@ -40,12 +40,21 @@ export default class MSDFTextGeometry extends BufferGeometry {
40
40
  _layouts: TextLayout[];
41
41
  originalPositionsArray: Float32Array;
42
42
  positionsArray: Float32Array;
43
+ centersArray: Float32Array;
44
+ uvsArray: Float32Array;
43
45
  positionsAttribute: BufferAttribute | null;
44
46
  instancesOffsetsCache: number[];
45
47
  instancesLengthsCache: number[];
48
+ private cache;
49
+ private cacheFont;
50
+ private cacheFlipY;
51
+ private signature;
52
+ private glyphsTotal;
53
+ private appliedTransforms;
46
54
  constructor(options: IOptions);
47
- setTransform(transform: Matrix4, instance?: number): void;
55
+ setTransform(transform: Matrix4, instance?: number): boolean;
48
56
  update(options: IOptions): void;
57
+ dispose(): void;
49
58
  computeBoundingSphere(): void;
50
59
  computeBoundingBox(): Box3 | undefined;
51
60
  }
@@ -1,5 +1,5 @@
1
1
  import createIndices from 'quad-indices';
2
- import { BufferGeometry, BufferAttribute, Sphere, Box3, Vector3 } from 'three';
2
+ import { BufferGeometry, Matrix4, BufferAttribute, Sphere, Box3, Vector3 } from 'three';
3
3
  import { createLayout } from './TextLayout.js';
4
4
  import { computeSphere, computeBox } from './utils.js';
5
5
  import { generateAttributes } from './vertices.js';
@@ -10,20 +10,75 @@ const pointA = new Vector3();
10
10
  const pointB = new Vector3();
11
11
  const pointC = new Vector3();
12
12
  const pointD = new Vector3();
13
+
14
+ /**
15
+ * The options that decide how one instance looks.
16
+ *
17
+ * Instances with equal values share a layout and its vertices, so the cache is keyed on them. An
18
+ * option that changes the layout but is missing here makes the cache return a stale layout.
19
+ * `alignY` and `yShift` do not move glyphs, but consumers read them from `_layouts[i]._options`.
20
+ */
21
+ const LAYOUT_KEYS = ['text', 'width', 'lineHeight', 'letterSpacing', 'alignX', 'alignY', 'yShift', 'tabSize'];
22
+
23
+ /**
24
+ * How many unused instances the cache keeps.
25
+ *
26
+ * A drag removes and adds the same labels many times, so an unused instance is likely to come back.
27
+ */
28
+ const CACHE_HEADROOM = 256;
29
+ function signatureOf(options) {
30
+ return JSON.stringify(LAYOUT_KEYS.map(key => options[key]));
31
+ }
32
+ function layOut(options, texWidth, texHeight, flipY) {
33
+ const layout = createLayout(options.text, options);
34
+ // A glyph with no area draws nothing
35
+ const glyphs = layout.glyphs.filter(({
36
+ data
37
+ }) => data.width * data.height > 0);
38
+ return {
39
+ layout,
40
+ glyphCount: glyphs.length,
41
+ ...generateAttributes(glyphs, texWidth, texHeight, flipY)
42
+ };
43
+ }
13
44
  class MSDFTextGeometry extends BufferGeometry {
14
45
  originalPositionsArray = new Float32Array();
15
46
  positionsArray = new Float32Array();
47
+ centersArray = new Float32Array();
48
+ uvsArray = new Float32Array();
16
49
  positionsAttribute = null;
17
50
  instancesOffsetsCache = [];
18
51
  instancesLengthsCache = [];
52
+
53
+ /** Laid-out instances by signature, in least-recently-used order. */
54
+ cache = new Map();
55
+ cacheFont = null;
56
+ cacheFlipY = true;
57
+ /** The signatures of the last update. `null` makes the next update run. */
58
+ signature = null;
59
+ /** `-1` makes the first update build the index and the attributes, also for zero glyphs. */
60
+ glyphsTotal = -1;
61
+ /** The last matrix written per instance. */
62
+ appliedTransforms = [];
19
63
  constructor(options) {
20
64
  super();
21
65
  this._layouts = [];
22
66
  this.update(options);
23
67
  }
68
+
69
+ /**
70
+ * Write the glyph positions of one instance. Returns whether anything was written.
71
+ *
72
+ * Consumers call this for every instance on every frame, and most instances do not move. A write
73
+ * marks the whole shared buffer for upload to the GPU, so an unchanged matrix is skipped.
74
+ */
24
75
  setTransform(transform, instance = 0) {
25
76
  const instanceOffset = this.instancesOffsetsCache[instance];
26
77
  const instanceLength = this.instancesLengthsCache[instance];
78
+ const applied = this.appliedTransforms[instance];
79
+ if (instanceLength === undefined || applied != null && applied.equals(transform)) {
80
+ return false;
81
+ }
27
82
  for (let i = 0; i < instanceLength; i++) {
28
83
  const instanceGlyphOffset = instanceOffset * 12 + i * 12;
29
84
  const originalXA = this.originalPositionsArray[instanceGlyphOffset];
@@ -55,75 +110,114 @@ class MSDFTextGeometry extends BufferGeometry {
55
110
  this.positionsArray[instanceGlyphOffset + 10] = pointD.y;
56
111
  this.positionsArray[instanceGlyphOffset + 11] = pointD.z;
57
112
  }
113
+
114
+ // Callers reuse one matrix for all instances, so keep a copy
115
+ this.appliedTransforms[instance] = (applied !== null && applied !== void 0 ? applied : new Matrix4()).copy(transform);
58
116
  if (this.positionsAttribute) {
59
117
  this.positionsAttribute.needsUpdate = true;
60
118
  }
119
+ return true;
61
120
  }
62
121
  update(options) {
63
122
  const {
64
123
  texts,
65
124
  ...optionsWithoutTexts
66
125
  } = options;
67
- this._layouts = texts.map(txt => createLayout(txt.text, {
68
- ...optionsWithoutTexts,
69
- ...txt
70
- }));
126
+
127
+ // the desired BMFont data
128
+ const font = options.font;
71
129
 
72
130
  // get vec2 texcoords
73
131
  const flipY = options.flipY !== false;
74
132
 
75
- // the desired BMFont data
76
- const font = options.font;
133
+ // A cached layout belongs to the font and the atlas orientation that produced it
134
+ if (font !== this.cacheFont || flipY !== this.cacheFlipY) {
135
+ this.cache.clear();
136
+ this.cacheFont = font;
137
+ this.cacheFlipY = flipY;
138
+ this.signature = null;
139
+ }
140
+ const instancesOptions = texts.map(txt => ({
141
+ ...optionsWithoutTexts,
142
+ ...txt
143
+ }));
144
+ const signatures = instancesOptions.map(signatureOf);
145
+
146
+ // Consumers call update on every insert and remove, far more often than the content changes
147
+ const signature = signatures.join('\n');
148
+ if (signature === this.signature) {
149
+ return;
150
+ }
151
+ this.signature = signature;
77
152
 
78
153
  // determine texture size from font file
79
154
  const texWidth = font.common.scaleW;
80
155
  const texHeight = font.common.scaleH;
81
- const glyphs = this._layouts.map(lay => lay.glyphs.filter(glyph => {
82
- const bitmap = glyph.data;
83
- return bitmap.width * bitmap.height > 0;
84
- }));
156
+ const instances = instancesOptions.map((instanceOptions, i) => {
157
+ var _this$cache$get;
158
+ const key = signatures[i];
159
+ const instance = (_this$cache$get = this.cache.get(key)) !== null && _this$cache$get !== void 0 ? _this$cache$get : layOut(instanceOptions, texWidth, texHeight, flipY);
160
+ // Re-insert, so the instances in use move to the end of the map
161
+ this.cache.delete(key);
162
+ this.cache.set(key, instance);
163
+ return instance;
164
+ });
165
+ for (const key of this.cache.keys()) {
166
+ if (this.cache.size <= texts.length + CACHE_HEADROOM) break;
167
+ this.cache.delete(key);
168
+ }
169
+ this._layouts = instances.map(instance => instance.layout);
85
170
 
86
171
  // Keep a cache of each text instance offset and length for attributes
87
172
  this.instancesOffsetsCache = [];
88
173
  this.instancesLengthsCache = [];
89
174
  let offsetSoFar = 0;
90
- glyphs.forEach((t, i) => {
91
- this.instancesLengthsCache[i] = t.length;
175
+ instances.forEach(({
176
+ glyphCount
177
+ }, i) => {
178
+ this.instancesLengthsCache[i] = glyphCount;
92
179
  this.instancesOffsetsCache[i] = offsetSoFar;
93
- offsetSoFar += t.length;
180
+ offsetSoFar += glyphCount;
94
181
  });
95
182
  const totalGlyphsLength = offsetSoFar;
96
- const indices = createIndices([], {
97
- clockwise: true,
98
- type: 'uint16',
99
- count: totalGlyphsLength
100
- });
101
- this.setIndex(indices);
102
- const attributes = glyphs.map(glyph => generateAttributes(glyph, texWidth, texHeight, flipY));
103
- const positionsTotalLength = attributes.reduce((sum, at) => sum + at.positions.length, 0);
104
- const centersTotalLength = attributes.reduce((sum, at) => sum + at.centers.length, 0);
105
- const uvsTotalLength = attributes.reduce((sum, at) => sum + at.uvs.length, 0);
106
- const positions = new Float32Array(positionsTotalLength);
107
- const centers = new Float32Array(centersTotalLength);
108
- const uvs = new Float32Array(uvsTotalLength);
109
- let positionsPos = 0;
110
- let centersPos = 0;
111
- let uvsPos = 0;
112
- attributes.forEach(at => {
113
- positions.set(at.positions, positionsPos);
114
- positionsPos += at.positions.length;
115
- centers.set(at.centers, centersPos);
116
- centersPos += at.centers.length;
117
- uvs.set(at.uvs, uvsPos);
118
- uvsPos += at.uvs.length;
183
+
184
+ // Instances move inside the shared buffers, so no applied matrix still holds
185
+ this.appliedTransforms = [];
186
+
187
+ // The index and the buffer sizes follow from the glyph count. While it stays the same, refill the
188
+ // buffers in place and keep the attributes and the GPU buffers behind them.
189
+ if (totalGlyphsLength !== this.glyphsTotal) {
190
+ this.glyphsTotal = totalGlyphsLength;
191
+ this.setIndex(createIndices([], {
192
+ clockwise: true,
193
+ type: 'uint16',
194
+ count: totalGlyphsLength
195
+ }));
196
+ this.positionsArray = new Float32Array(totalGlyphsLength * 12);
197
+ this.originalPositionsArray = new Float32Array(totalGlyphsLength * 12);
198
+ this.centersArray = new Float32Array(totalGlyphsLength * 8);
199
+ this.uvsArray = new Float32Array(totalGlyphsLength * 8);
200
+ this.positionsAttribute = new BufferAttribute(this.positionsArray, 3);
201
+ this.setAttribute('position', this.positionsAttribute);
202
+ this.setAttribute('center', new BufferAttribute(this.centersArray, 2));
203
+ this.setAttribute('uv', new BufferAttribute(this.uvsArray, 2));
204
+ }
205
+ instances.forEach((instance, i) => {
206
+ const offset = this.instancesOffsetsCache[i];
207
+ this.positionsArray.set(instance.positions, offset * 12);
208
+ this.centersArray.set(instance.centers, offset * 8);
209
+ this.uvsArray.set(instance.uvs, offset * 8);
119
210
  });
120
- this.positionsArray = positions;
121
- this.originalPositionsArray = new Float32Array(positionsTotalLength);
122
- this.originalPositionsArray.set(positions);
123
- this.positionsAttribute = new BufferAttribute(positions, 3);
124
- this.setAttribute('position', this.positionsAttribute);
125
- this.setAttribute('center', new BufferAttribute(centers, 2));
126
- this.setAttribute('uv', new BufferAttribute(uvs, 2));
211
+ this.originalPositionsArray.set(this.positionsArray);
212
+ for (const name of ['position', 'center', 'uv']) {
213
+ this.attributes[name].needsUpdate = true;
214
+ }
215
+ }
216
+ dispose() {
217
+ this.cache.clear();
218
+ this.appliedTransforms = [];
219
+ this.signature = null;
220
+ super.dispose();
127
221
  }
128
222
  computeBoundingSphere() {
129
223
  if (this.boundingSphere === null) this.boundingSphere = new Sphere();