@saboit-dev/thomas 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +138 -0
  3. package/index.cjs.js +1 -0
  4. package/index.d.ts +2 -0
  5. package/index.js +6 -0
  6. package/package.json +54 -0
  7. package/text_engine_2d/MSDFTextGeometry/TextLayout.cjs.js +1 -0
  8. package/text_engine_2d/MSDFTextGeometry/TextLayout.d.ts +48 -0
  9. package/text_engine_2d/MSDFTextGeometry/TextLayout.js +357 -0
  10. package/text_engine_2d/MSDFTextGeometry/index.cjs.js +1 -0
  11. package/text_engine_2d/MSDFTextGeometry/index.d.ts +51 -0
  12. package/text_engine_2d/MSDFTextGeometry/index.js +159 -0
  13. package/text_engine_2d/MSDFTextGeometry/utils.cjs.js +1 -0
  14. package/text_engine_2d/MSDFTextGeometry/utils.d.ts +3 -0
  15. package/text_engine_2d/MSDFTextGeometry/utils.js +46 -0
  16. package/text_engine_2d/MSDFTextGeometry/vertices.cjs.js +1 -0
  17. package/text_engine_2d/MSDFTextGeometry/vertices.d.ts +28 -0
  18. package/text_engine_2d/MSDFTextGeometry/vertices.js +84 -0
  19. package/text_engine_2d/MSDFTextMaterial/fragment.glsl.js +3 -0
  20. package/text_engine_2d/MSDFTextMaterial/index.cjs.js +1 -0
  21. package/text_engine_2d/MSDFTextMaterial/index.d.ts +4 -0
  22. package/text_engine_2d/MSDFTextMaterial/index.js +38 -0
  23. package/text_engine_2d/MSDFTextMaterial/vertex.glsl.js +3 -0
  24. package/text_engine_2d/index.cjs.js +1 -0
  25. package/text_engine_2d/index.d.ts +6 -0
  26. package/text_engine_2d/index.js +18 -0
  27. package/text_engine_2d/react/SDFText.cjs.js +1 -0
  28. package/text_engine_2d/react/SDFText.d.ts +9 -0
  29. package/text_engine_2d/react/SDFText.js +63 -0
  30. package/text_engine_2d/react/SDFTextProvider.cjs.js +1 -0
  31. package/text_engine_2d/react/SDFTextProvider.d.ts +6 -0
  32. package/text_engine_2d/react/SDFTextProvider.js +191 -0
  33. package/text_engine_2d/react/context.cjs.js +1 -0
  34. package/text_engine_2d/react/context.d.ts +3 -0
  35. package/text_engine_2d/react/context.js +5 -0
  36. package/text_engine_2d/react/types.cjs.js +1 -0
  37. package/text_engine_2d/react/types.d.ts +33 -0
  38. package/text_engine_2d/react/types.js +1 -0
  39. package/text_engine_2d/react/utils.cjs.js +1 -0
  40. package/text_engine_2d/react/utils.d.ts +2 -0
  41. package/text_engine_2d/react/utils.js +6 -0
  42. package/text_engine_2d/register.cjs.js +1 -0
  43. package/text_engine_2d/register.d.ts +12 -0
  44. package/text_engine_2d/register.js +12 -0
  45. package/text_engine_3d/InstancedText.cjs.js +1 -0
  46. package/text_engine_3d/InstancedText.d.ts +13 -0
  47. package/text_engine_3d/InstancedText.js +127 -0
  48. package/text_engine_3d/InstancedTextPlaceholder.cjs.js +1 -0
  49. package/text_engine_3d/InstancedTextPlaceholder.d.ts +23 -0
  50. package/text_engine_3d/InstancedTextPlaceholder.js +50 -0
  51. package/text_engine_3d/InstancedTextProvider.cjs.js +1 -0
  52. package/text_engine_3d/InstancedTextProvider.d.ts +15 -0
  53. package/text_engine_3d/InstancedTextProvider.js +124 -0
  54. package/text_engine_3d/index.cjs.js +1 -0
  55. package/text_engine_3d/index.d.ts +3 -0
  56. package/text_engine_3d/index.js +11 -0
  57. package/text_engine_3d/instancedTextBuffers.cjs.js +1 -0
  58. package/text_engine_3d/instancedTextBuffers.d.ts +28 -0
  59. package/text_engine_3d/instancedTextBuffers.js +105 -0
  60. package/text_engine_3d/types.cjs.js +1 -0
  61. package/text_engine_3d/types.d.ts +37 -0
  62. package/text_engine_3d/types.js +8 -0
  63. package/text_engine_3d/useInstancedTextMaterial.cjs.js +1 -0
  64. package/text_engine_3d/useInstancedTextMaterial.d.ts +4 -0
  65. package/text_engine_3d/useInstancedTextMaterial.js +73 -0
@@ -0,0 +1,84 @@
1
+ function generateAttributes(glyphs, texWidth, texHeight, flipY) {
2
+ const uvs = new Float32Array(glyphs.length * 4 * 2);
3
+ const positions = new Float32Array(glyphs.length * 4 * 3);
4
+ const centers = new Float32Array(glyphs.length * 4 * 2);
5
+ let i = 0;
6
+ let j = 0;
7
+ let k = 0;
8
+ glyphs.forEach(function (glyph) {
9
+ const bitmap = glyph.data;
10
+
11
+ // UV
12
+ const bw = bitmap.x + bitmap.width;
13
+ const bh = bitmap.y + bitmap.height;
14
+
15
+ // top left position
16
+ const u0 = bitmap.x / texWidth;
17
+ let v1 = bitmap.y / texHeight;
18
+ const u1 = bw / texWidth;
19
+ let v0 = bh / texHeight;
20
+ if (flipY) {
21
+ v1 = (texHeight - bitmap.y) / texHeight;
22
+ v0 = (texHeight - bh) / texHeight;
23
+ }
24
+
25
+ // BL
26
+ uvs[i++] = u0;
27
+ uvs[i++] = v1;
28
+ // TL
29
+ uvs[i++] = u0;
30
+ uvs[i++] = v0;
31
+ // TR
32
+ uvs[i++] = u1;
33
+ uvs[i++] = v0;
34
+ // BR
35
+ uvs[i++] = u1;
36
+ uvs[i++] = v1;
37
+
38
+ /// Positions, Centers
39
+
40
+ // bottom left position
41
+ const x = glyph.position[0] + bitmap.xoffset;
42
+ const y = glyph.position[1] + bitmap.yoffset;
43
+
44
+ // quad size
45
+ const w = bitmap.width;
46
+ const h = bitmap.height;
47
+
48
+ // Position
49
+
50
+ // BL
51
+ positions[j++] = x;
52
+ positions[j++] = y;
53
+ positions[j++] = 0;
54
+ // TL
55
+ positions[j++] = x;
56
+ positions[j++] = y + h;
57
+ positions[j++] = 0;
58
+ // TR
59
+ positions[j++] = x + w;
60
+ positions[j++] = y + h;
61
+ positions[j++] = 0;
62
+ // BR
63
+ positions[j++] = x + w;
64
+ positions[j++] = y;
65
+ positions[j++] = 0;
66
+
67
+ // Center
68
+ centers[k++] = x + w / 2;
69
+ centers[k++] = y + h / 2;
70
+ centers[k++] = x + w / 2;
71
+ centers[k++] = y + h / 2;
72
+ centers[k++] = x + w / 2;
73
+ centers[k++] = y + h / 2;
74
+ centers[k++] = x + w / 2;
75
+ centers[k++] = y + h / 2;
76
+ });
77
+ return {
78
+ uvs,
79
+ positions,
80
+ centers
81
+ };
82
+ }
83
+
84
+ export { generateAttributes };
@@ -0,0 +1,3 @@
1
+ var 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);}"; // eslint-disable-line
2
+
3
+ export { fragmentShader as default };
@@ -0,0 +1 @@
1
+ "use strict";var i=require("three");class e extends i.ShaderMaterial{constructor(e={}){super(e={...{side:i.FrontSide,transparent:!0,extensions:{derivatives:!0},uniforms:{uOpacity:{value:1},uOffset:{value:0},uColor:{value:new i.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);}"},...e})}}module.exports=e;
@@ -0,0 +1,4 @@
1
+ import { ShaderMaterial } from 'three';
2
+ export default class MSDFTextMaterial extends ShaderMaterial {
3
+ constructor(options?: {});
4
+ }
@@ -0,0 +1,38 @@
1
+ import { ShaderMaterial, FrontSide, Color } from 'three';
2
+ import fragmentShader from './fragment.glsl.js';
3
+ import vertexShader from './vertex.glsl.js';
4
+
5
+ class MSDFTextMaterial extends ShaderMaterial {
6
+ constructor(options = {}) {
7
+ const defaultOptions = {
8
+ side: FrontSide,
9
+ transparent: true,
10
+ extensions: {
11
+ derivatives: true
12
+ },
13
+ uniforms: {
14
+ uOpacity: {
15
+ value: 1
16
+ },
17
+ uOffset: {
18
+ value: 0
19
+ },
20
+ uColor: {
21
+ value: new Color('#ffffff')
22
+ },
23
+ uMap: {
24
+ value: null
25
+ }
26
+ },
27
+ vertexShader,
28
+ fragmentShader
29
+ };
30
+ options = {
31
+ ...defaultOptions,
32
+ ...options
33
+ };
34
+ super(options);
35
+ }
36
+ }
37
+
38
+ export { MSDFTextMaterial as default };
@@ -0,0 +1,3 @@
1
+ var vertexShader = "#define GLSLIFY 1\nvarying vec2 vUv;void main(){vec4 mvPosition=vec4(position,1.0);mvPosition=modelViewMatrix*mvPosition;gl_Position=projectionMatrix*mvPosition;vUv=uv;}"; // eslint-disable-line
2
+
3
+ export { vertexShader as default };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./MSDFTextGeometry/index.cjs.js"),r=require("./MSDFTextMaterial/index.cjs.js"),t=require("./react/SDFText.cjs.js"),s=require("./react/SDFTextProvider.cjs.js");require("quad-indices"),require("three"),require("./MSDFTextGeometry/TextLayout.cjs.js"),require("word-wrapper"),require("./MSDFTextGeometry/utils.cjs.js"),require("./MSDFTextGeometry/vertices.cjs.js"),require("react"),require("./react/context.cjs.js"),require("./react/utils.cjs.js"),require("@babel/runtime/helpers/extends"),require("@react-three/drei"),require("@react-three/fiber"),require("three/examples/jsm/loaders/FontLoader"),require("./register.cjs.js"),exports.MSDFTextGeometry=e,exports.MSDFTextMaterial=r,exports.SDFText=t.SDFText,exports.SDFTextProvider=s.SDFTextProvider;
@@ -0,0 +1,6 @@
1
+ import MSDFTextGeometry from './MSDFTextGeometry';
2
+ import MSDFTextMaterial from './MSDFTextMaterial';
3
+ export { MSDFTextMaterial, MSDFTextGeometry };
4
+ export { SDFText } from './react/SDFText';
5
+ export type { SDFTextRefType } from './react/SDFText';
6
+ export { SDFTextProvider } from './react/SDFTextProvider';
@@ -0,0 +1,18 @@
1
+ export { default as MSDFTextGeometry } from './MSDFTextGeometry/index.js';
2
+ export { default as MSDFTextMaterial } from './MSDFTextMaterial/index.js';
3
+ export { SDFText } from './react/SDFText.js';
4
+ export { SDFTextProvider } from './react/SDFTextProvider.js';
5
+ import 'quad-indices';
6
+ import 'three';
7
+ import './MSDFTextGeometry/TextLayout.js';
8
+ import 'word-wrapper';
9
+ import './MSDFTextGeometry/utils.js';
10
+ import './MSDFTextGeometry/vertices.js';
11
+ import 'react';
12
+ import './react/context.js';
13
+ import './react/utils.js';
14
+ import '@babel/runtime/helpers/esm/extends';
15
+ import '@react-three/drei';
16
+ import '@react-three/fiber';
17
+ import 'three/examples/jsm/loaders/FontLoader';
18
+ import './register.js';
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("./context.cjs.js"),r=require("./utils.cjs.js");function n(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var o=n(e);const i=e.forwardRef((function({instanceKey:n,bold:i,color:u,opacity:c,outlineWidth:l,outlineOpacity:a,outlineColor:s,text:f,alignX:d,alignY:p,letterSpacing:y,yShift:g,width:v,lineHeight:h,onBeforeUpdate:j},x){const b=e.useContext(t.SDFTextProviderContext);if(!b)throw new Error("No SDFTextProvider");const O=e.useRef(null),S=e.useRef(null);return e.useImperativeHandle(x,(()=>({setTransform(e){S.current&&(S.current.transform=e)}})),[]),e.useLayoutEffect((()=>{var e;const t={bold:i,color:u,opacity:c,outlineWidth:l,outlineOpacity:a,outlineColor:s},o={text:f,alignX:d,alignY:p,letterSpacing:y,yShift:g,width:v,lineHeight:h,onBeforeUpdate:j},x=r.makeStyleId(t);return S.current=b.insertInstance(x,t,n,o,null!==(e=O.current)&&void 0!==e?e:void 0),()=>b.removeInstance(x,n)}),[b,n,f,d,p,y,g,v,h,i,u,c,l,a,s,j]),o.createElement("group",{ref:O})}));exports.SDFText=i;
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+ import { Matrix4 } from 'three';
3
+ import { ISDFTextConfig, ISDFTextStyle } from './types';
4
+ export type SDFTextRefType = {
5
+ setTransform(transform: Matrix4): void;
6
+ };
7
+ export declare const SDFText: React.ForwardRefExoticComponent<{
8
+ instanceKey: string;
9
+ } & ISDFTextConfig & ISDFTextStyle & React.RefAttributes<SDFTextRefType>>;
@@ -0,0 +1,63 @@
1
+ import * as React from 'react';
2
+ import { forwardRef, useContext, useRef, useImperativeHandle, useLayoutEffect } from 'react';
3
+ import { SDFTextProviderContext } from './context.js';
4
+ import { makeStyleId } from './utils.js';
5
+
6
+ const SDFText = /*#__PURE__*/forwardRef(function SDFText({
7
+ instanceKey,
8
+ bold,
9
+ color,
10
+ opacity,
11
+ outlineWidth,
12
+ outlineOpacity,
13
+ outlineColor,
14
+ text,
15
+ alignX,
16
+ alignY,
17
+ letterSpacing,
18
+ yShift,
19
+ width,
20
+ lineHeight,
21
+ onBeforeUpdate
22
+ }, ref) {
23
+ const services = useContext(SDFTextProviderContext);
24
+ if (!services) throw new Error('No SDFTextProvider');
25
+ const groupRef = useRef(null);
26
+ const instanceRef = useRef(null);
27
+ useImperativeHandle(ref, () => ({
28
+ setTransform(transform) {
29
+ if (instanceRef.current) {
30
+ instanceRef.current.transform = transform;
31
+ }
32
+ }
33
+ }), []);
34
+ useLayoutEffect(() => {
35
+ var _groupRef$current;
36
+ const textStyle = {
37
+ bold,
38
+ color,
39
+ opacity,
40
+ outlineWidth,
41
+ outlineOpacity,
42
+ outlineColor
43
+ };
44
+ const textConfig = {
45
+ text,
46
+ alignX,
47
+ alignY,
48
+ letterSpacing,
49
+ yShift,
50
+ width,
51
+ lineHeight,
52
+ onBeforeUpdate
53
+ };
54
+ const styleId = makeStyleId(textStyle);
55
+ instanceRef.current = services.insertInstance(styleId, textStyle, instanceKey, textConfig, (_groupRef$current = groupRef.current) !== null && _groupRef$current !== void 0 ? _groupRef$current : undefined);
56
+ return () => services.removeInstance(styleId, instanceKey);
57
+ }, [services, instanceKey, text, alignX, alignY, letterSpacing, yShift, width, lineHeight, bold, color, opacity, outlineWidth, outlineOpacity, outlineColor, onBeforeUpdate]);
58
+ return /*#__PURE__*/React.createElement("group", {
59
+ ref: groupRef
60
+ });
61
+ });
62
+
63
+ export { SDFText };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("@react-three/drei"),r=require("@react-three/fiber"),n=require("react"),o=require("three"),a=require("three/examples/jsm/loaders/FontLoader"),l=require("../MSDFTextGeometry/index.cjs.js"),i=require("../register.cjs.js"),u=require("./context.cjs.js"),s=require("./utils.cjs.js");function c(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function d(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}require("quad-indices"),require("../MSDFTextGeometry/TextLayout.cjs.js"),require("word-wrapper"),require("../MSDFTextGeometry/utils.cjs.js"),require("../MSDFTextGeometry/vertices.cjs.js"),require("../MSDFTextMaterial/index.cjs.js");var f=c(e),m=d(n);const y=99999,p=99998,v=new o.Matrix4,x=new o.Matrix4,h=new o.Color("#ffffff"),j=new o.Color("#000000"),g=.01;function M({instances:e,textStyle:t,atlas:o,font:a,atlasBold:i,fontBold:u,...s}){var c;const d=i&&u&&t.bold,M=d?u.data:a.data,S=n.useState((()=>new l({font:M,texts:[]})))[0];n.useLayoutEffect((()=>()=>S.dispose()),[S]),n.useLayoutEffect((()=>{const t=e.map((e=>e.config));S.update({font:M,texts:t})}),[S,e,M]),r.useFrame((()=>{e.forEach(((t,r)=>{null==t.config.onBeforeUpdate||t.config.onBeforeUpdate(),x.identity();const n=e[r].object;n&&(n.updateMatrixWorld(),x.multiply(n.matrixWorld)),x.multiply(t.transform),v.makeScale(g,g,g),x.multiply(v);const o=S._layouts[r];if(o){var a,l,i,u;const e=null!==(a=o.width)&&void 0!==a?a:0,t=null!==(l=o.height)&&void 0!==l?l:0,r=null!==(i=o.lineHeight)&&void 0!==i?i:0,n=null!==(u=o._options.yShift)&&void 0!==u?u:0,s=r/4-t,c=r/2;let d=0;"center"===o._options.alignX&&(d=-e/2),"right"===o._options.alignX&&(d=-e);let f=s+n;"middle"===o._options.alignY&&(f=(s+c)/2-o.ascender+n),"bottom"===o._options.alignY&&(f=c+n),v.makeTranslation(d,f,0),x.multiply(v)}v.makeRotationX(Math.PI),x.multiply(v),S.setTransform(x,r)}))}));const q=n.useMemo((()=>{var e,r;return{uMap:{value:d?i:o},uColor:{value:null!==(e=t.color)&&void 0!==e?e:h},uOpacity:{value:null!==(r=t.opacity)&&void 0!==r?r:1},uOffset:{value:0}}}),[d,t.opacity,t.color,o,i]),F=n.useMemo((()=>{var e,r;return{uMap:{value:d?i:o},uColor:{value:null!==(e=t.outlineColor)&&void 0!==e?e:j},uOpacity:{value:null!==(r=t.outlineOpacity)&&void 0!==r?r:.4},uOffset:{value:t.outlineWidth}}}),[d,t.outlineOpacity,t.outlineColor,t.outlineWidth,o,i]);return m.createElement(m.Fragment,null,m.createElement("mesh",f.default({geometry:S,frustumCulled:!1,renderOrder:y},s),m.createElement("mSDFTextMaterial",{uniforms:q})),(null!==(c=t.outlineWidth)&&void 0!==c?c:0)>0&&m.createElement("mesh",f.default({geometry:S,frustumCulled:!1,renderOrder:p},s),m.createElement("mSDFTextMaterial",{uniforms:F,depthWrite:!1})))}exports.SDFTextProvider=function({children:e,fontPathRegular:l,fontPathBold:c}){n.useMemo(i.registerTextEngineToR3F,[]);const d=t.useTexture(l.sdfPath),f=r.useLoader(a.FontLoader,l.fontPath),y=t.useTexture(c?c.sdfPath:[]),p=r.useLoader(a.FontLoader,c?c.fontPath:[]),v=n.useState((()=>new Map))[0],x=n.useState(0)[1],h=n.useMemo((()=>({insertInstance(e,t,r,n,a){var l;const i={instanceKey:r,config:n,object:a,transform:new o.Matrix4},u=v.get(e);return v.set(e,{textStyle:t,instances:[...null!==(l=null==u?void 0:u.instances)&&void 0!==l?l:[],i]}),x((e=>e+1)),i},removeInstance(e,t){const r=v.get(e);if(r){const n=r.instances.filter((e=>e.instanceKey!==t));0===n.length?v.delete(e):v.set(e,{textStyle:r.textStyle,instances:n}),x((e=>e+1))}}})),[]);return m.createElement(u.SDFTextProviderContext.Provider,{value:h},m.createElement(m.Fragment,null,e,Array.from(v.values()).map((e=>m.createElement(M,{key:s.makeStyleId(e.textStyle),textStyle:e.textStyle,instances:e.instances,atlas:d,font:f,atlasBold:Array.isArray(y)?void 0:y,fontBold:Array.isArray(p)?void 0:p})))))};
@@ -0,0 +1,6 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { ISDFFont } from './types';
3
+ export declare function SDFTextProvider({ children, fontPathRegular, fontPathBold, }: PropsWithChildren<{
4
+ fontPathRegular: ISDFFont;
5
+ fontPathBold?: ISDFFont;
6
+ }>): JSX.Element;
@@ -0,0 +1,191 @@
1
+ import _extends from '@babel/runtime/helpers/esm/extends';
2
+ import { useTexture } from '@react-three/drei';
3
+ import { useLoader, useFrame } from '@react-three/fiber';
4
+ import * as React from 'react';
5
+ import { useMemo, useState, useLayoutEffect } from 'react';
6
+ import { Matrix4, Color } from 'three';
7
+ import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
8
+ import MSDFTextGeometry from '../MSDFTextGeometry/index.js';
9
+ import { registerTextEngineToR3F } from '../register.js';
10
+ import { SDFTextProviderContext } from './context.js';
11
+ import { makeStyleId } from './utils.js';
12
+
13
+ // Since the outline is done with two meshes, we hardcode two render order values
14
+ // to ensure the foreground is rendered after the outline
15
+ const foreRenderOrder = 99999;
16
+ const outlineRenderOrder = 99998;
17
+ const temp = new Matrix4();
18
+ const transformFinal = new Matrix4();
19
+ const white = new Color('#ffffff');
20
+ const black = new Color('#000000');
21
+ const scaleFactor = 0.01;
22
+ function StyleGroupRenderer({
23
+ instances,
24
+ textStyle,
25
+ atlas,
26
+ font,
27
+ atlasBold,
28
+ fontBold,
29
+ ...rest
30
+ }) {
31
+ var _textStyle$outlineWid;
32
+ const shouldDoBold = atlasBold && fontBold && textStyle.bold;
33
+ const fontData = shouldDoBold ? fontBold.data : font.data;
34
+ const geometry = useState(() => new MSDFTextGeometry({
35
+ font: fontData,
36
+ texts: []
37
+ }))[0];
38
+ useLayoutEffect(() => () => geometry.dispose(), [geometry]);
39
+ useLayoutEffect(() => {
40
+ const texts = instances.map(is => is.config);
41
+ geometry.update({
42
+ font: fontData,
43
+ texts
44
+ });
45
+ }, [geometry, instances, fontData]);
46
+ useFrame(() => {
47
+ // TODO: Revisit this to avoid calculating the matrix every frame
48
+ instances.forEach((inst, index) => {
49
+ inst.config.onBeforeUpdate == null ? void 0 : inst.config.onBeforeUpdate();
50
+ transformFinal.identity();
51
+ const placeholder = instances[index].object;
52
+ if (placeholder) {
53
+ placeholder.updateMatrixWorld();
54
+ transformFinal.multiply(placeholder.matrixWorld);
55
+ }
56
+ transformFinal.multiply(inst.transform);
57
+ temp.makeScale(scaleFactor, scaleFactor, scaleFactor);
58
+ transformFinal.multiply(temp);
59
+ const layout = geometry._layouts[index];
60
+ if (layout) {
61
+ var _layout$width, _layout$height, _layout$lineHeight, _layout$_options$yShi;
62
+ const width = (_layout$width = layout.width) !== null && _layout$width !== void 0 ? _layout$width : 0;
63
+ const height = (_layout$height = layout.height) !== null && _layout$height !== void 0 ? _layout$height : 0;
64
+ const lineHeight = (_layout$lineHeight = layout.lineHeight) !== null && _layout$lineHeight !== void 0 ? _layout$lineHeight : 0;
65
+ const optYShift = (_layout$_options$yShi = layout._options.yShift) !== null && _layout$_options$yShi !== void 0 ? _layout$_options$yShi : 0;
66
+ const bottomShift = -height + lineHeight / 4;
67
+ const topShift = lineHeight / 2;
68
+ let xShift = 0;
69
+ if (layout._options.alignX === 'center') xShift = -width / 2;
70
+ if (layout._options.alignX === 'right') xShift = -width;
71
+ let yShift = bottomShift + optYShift;
72
+ if (layout._options.alignY === 'middle') yShift = (bottomShift + topShift) / 2 - layout.ascender + optYShift;
73
+ if (layout._options.alignY === 'bottom') yShift = topShift + optYShift;
74
+ temp.makeTranslation(xShift, yShift, 0);
75
+ transformFinal.multiply(temp);
76
+ }
77
+ temp.makeRotationX(Math.PI);
78
+ transformFinal.multiply(temp);
79
+ geometry.setTransform(transformFinal, index);
80
+ });
81
+ });
82
+ const uniforms = useMemo(() => {
83
+ var _textStyle$color, _textStyle$opacity;
84
+ return {
85
+ uMap: {
86
+ value: shouldDoBold ? atlasBold : atlas
87
+ },
88
+ uColor: {
89
+ value: (_textStyle$color = textStyle.color) !== null && _textStyle$color !== void 0 ? _textStyle$color : white
90
+ },
91
+ uOpacity: {
92
+ value: (_textStyle$opacity = textStyle.opacity) !== null && _textStyle$opacity !== void 0 ? _textStyle$opacity : 1.0
93
+ },
94
+ uOffset: {
95
+ value: 0
96
+ }
97
+ };
98
+ }, [shouldDoBold, textStyle.opacity, textStyle.color, atlas, atlasBold]);
99
+ const uniformsOutline = useMemo(() => {
100
+ var _textStyle$outlineCol, _textStyle$outlineOpa;
101
+ return {
102
+ uMap: {
103
+ value: shouldDoBold ? atlasBold : atlas
104
+ },
105
+ uColor: {
106
+ value: (_textStyle$outlineCol = textStyle.outlineColor) !== null && _textStyle$outlineCol !== void 0 ? _textStyle$outlineCol : black
107
+ },
108
+ uOpacity: {
109
+ value: (_textStyle$outlineOpa = textStyle.outlineOpacity) !== null && _textStyle$outlineOpa !== void 0 ? _textStyle$outlineOpa : 0.4
110
+ },
111
+ uOffset: {
112
+ value: textStyle.outlineWidth
113
+ }
114
+ };
115
+ }, [shouldDoBold, textStyle.outlineOpacity, textStyle.outlineColor, textStyle.outlineWidth, atlas, atlasBold]);
116
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("mesh", _extends({
117
+ geometry: geometry,
118
+ frustumCulled: false,
119
+ renderOrder: foreRenderOrder
120
+ }, rest), /*#__PURE__*/React.createElement("mSDFTextMaterial", {
121
+ uniforms: uniforms
122
+ })), ((_textStyle$outlineWid = textStyle.outlineWidth) !== null && _textStyle$outlineWid !== void 0 ? _textStyle$outlineWid : 0) > 0 && /*#__PURE__*/React.createElement("mesh", _extends({
123
+ geometry: geometry,
124
+ frustumCulled: false,
125
+ renderOrder: outlineRenderOrder
126
+ }, rest), /*#__PURE__*/React.createElement("mSDFTextMaterial", {
127
+ uniforms: uniformsOutline,
128
+ depthWrite: false
129
+ })));
130
+ }
131
+ function SDFTextProvider({
132
+ children,
133
+ fontPathRegular,
134
+ fontPathBold
135
+ }) {
136
+ useMemo(registerTextEngineToR3F, []);
137
+ const atlas = useTexture(fontPathRegular.sdfPath);
138
+ const font = useLoader(FontLoader, fontPathRegular.fontPath);
139
+ const atlasBold = useTexture(fontPathBold ? fontPathBold.sdfPath : []);
140
+ const fontBold = useLoader(FontLoader, fontPathBold ? fontPathBold.fontPath : []);
141
+
142
+ // We have a mutable map of immutable arrays, so we are using a force update
143
+ const instancesGroups = useState(() => new Map())[0];
144
+ const forceUpdate = useState(0)[1];
145
+ const api = useMemo(() => ({
146
+ insertInstance(styleId, textStyle, instanceKey, config, object) {
147
+ var _prevRecord$instances;
148
+ const newInst = {
149
+ instanceKey,
150
+ config,
151
+ object,
152
+ transform: new Matrix4()
153
+ };
154
+ const prevRecord = instancesGroups.get(styleId);
155
+ instancesGroups.set(styleId, {
156
+ textStyle,
157
+ instances: [...((_prevRecord$instances = prevRecord == null ? void 0 : prevRecord.instances) !== null && _prevRecord$instances !== void 0 ? _prevRecord$instances : []), newInst]
158
+ });
159
+ forceUpdate(i => i + 1);
160
+ return newInst;
161
+ },
162
+ removeInstance(styleId, instanceKey) {
163
+ const prevRecord = instancesGroups.get(styleId);
164
+ if (prevRecord) {
165
+ const without = prevRecord.instances.filter(inst => inst.instanceKey !== instanceKey);
166
+ if (without.length === 0) {
167
+ instancesGroups.delete(styleId);
168
+ } else {
169
+ instancesGroups.set(styleId, {
170
+ textStyle: prevRecord.textStyle,
171
+ instances: without
172
+ });
173
+ }
174
+ forceUpdate(i => i + 1);
175
+ }
176
+ }
177
+ }), []);
178
+ return /*#__PURE__*/React.createElement(SDFTextProviderContext.Provider, {
179
+ value: api
180
+ }, /*#__PURE__*/React.createElement(React.Fragment, null, children, Array.from(instancesGroups.values()).map(ig => /*#__PURE__*/React.createElement(StyleGroupRenderer, {
181
+ key: makeStyleId(ig.textStyle),
182
+ textStyle: ig.textStyle,
183
+ instances: ig.instances,
184
+ atlas: atlas,
185
+ font: font,
186
+ atlasBold: Array.isArray(atlasBold) ? undefined : atlasBold,
187
+ fontBold: Array.isArray(fontBold) ? undefined : fontBold
188
+ }))));
189
+ }
190
+
191
+ export { SDFTextProvider };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e=require("react").createContext(null);exports.SDFTextProviderContext=e;
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { ISDFTextServices } from './types';
3
+ export declare const SDFTextProviderContext: import("react").Context<ISDFTextServices | null>;
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'react';
2
+
3
+ const SDFTextProviderContext = /*#__PURE__*/createContext(null);
4
+
5
+ export { SDFTextProviderContext };
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,33 @@
1
+ import { Color, Matrix4, Object3D } from 'three';
2
+ export interface ISDFTextStyle {
3
+ bold?: boolean;
4
+ color?: Color;
5
+ opacity?: number;
6
+ outlineWidth?: number;
7
+ outlineOpacity?: number;
8
+ outlineColor?: Color;
9
+ }
10
+ export interface ISDFTextInstance {
11
+ config: ISDFTextConfig;
12
+ instanceKey: string;
13
+ object?: Object3D;
14
+ transform: Matrix4;
15
+ }
16
+ export interface ISDFTextConfig {
17
+ text: string;
18
+ alignX?: 'left' | 'center' | 'right';
19
+ alignY?: 'top' | 'middle' | 'bottom';
20
+ letterSpacing?: number;
21
+ width?: number;
22
+ lineHeight?: number;
23
+ yShift?: number;
24
+ onBeforeUpdate?: () => void;
25
+ }
26
+ export interface ISDFTextServices {
27
+ insertInstance(styleId: string, textStyle: ISDFTextStyle, instanceKey: string, config: ISDFTextConfig, object?: Object3D): ISDFTextInstance;
28
+ removeInstance(styleId: string, instanceKey: string): void;
29
+ }
30
+ export interface ISDFFont {
31
+ sdfPath: string;
32
+ fontPath: string;
33
+ }
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});exports.makeStyleId=e=>{var t,o;return[e.bold,null==(t=e.color)?void 0:t.getHexString(),e.opacity,e.outlineWidth,e.outlineOpacity,null==(o=e.outlineColor)?void 0:o.getHexString()].join("_")};
@@ -0,0 +1,2 @@
1
+ import { ISDFTextStyle } from './types';
2
+ export declare const makeStyleId: (style: ISDFTextStyle) => string;
@@ -0,0 +1,6 @@
1
+ const makeStyleId = style => {
2
+ var _style$color, _style$outlineColor;
3
+ return [style.bold, (_style$color = style.color) == null ? void 0 : _style$color.getHexString(), style.opacity, style.outlineWidth, style.outlineOpacity, (_style$outlineColor = style.outlineColor) == null ? void 0 : _style$outlineColor.getHexString()].join('_');
4
+ };
5
+
6
+ export { makeStyleId };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@react-three/fiber"),r=require("./MSDFTextGeometry/index.cjs.js"),t=require("./MSDFTextMaterial/index.cjs.js");require("quad-indices"),require("three"),require("./MSDFTextGeometry/TextLayout.cjs.js"),require("word-wrapper"),require("./MSDFTextGeometry/utils.cjs.js"),require("./MSDFTextGeometry/vertices.cjs.js"),exports.registerTextEngineToR3F=function(){e.extend({MSDFTextMaterial:t,MSDFTextGeometry:r})};
@@ -0,0 +1,12 @@
1
+ import { ReactThreeFiber } from '@react-three/fiber';
2
+ import MSDFTextGeometry from './MSDFTextGeometry';
3
+ import MSDFTextMaterial from './MSDFTextMaterial';
4
+ export declare function registerTextEngineToR3F(): void;
5
+ declare global {
6
+ namespace JSX {
7
+ interface IntrinsicElements {
8
+ mSDFTextMaterial: ReactThreeFiber.MaterialNode<MSDFTextMaterial, typeof MSDFTextMaterial>;
9
+ mSDFTextGeometry: ReactThreeFiber.BufferGeometryNode<MSDFTextGeometry, typeof MSDFTextGeometry>;
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ import { extend } from '@react-three/fiber';
2
+ import MSDFTextGeometry from './MSDFTextGeometry/index.js';
3
+ import MSDFTextMaterial from './MSDFTextMaterial/index.js';
4
+
5
+ function registerTextEngineToR3F() {
6
+ extend({
7
+ MSDFTextMaterial,
8
+ MSDFTextGeometry
9
+ });
10
+ }
11
+
12
+ export { registerTextEngineToR3F };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("react"),n=require("three"),r=require("./InstancedTextProvider.cjs.js"),o=require("./types.cjs.js");function a(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)}require("@react-three/fiber"),require("./instancedTextBuffers.cjs.js"),require("./InstancedTextPlaceholder.cjs.js"),require("./useInstancedTextMaterial.cjs.js"),require("@react-three/drei");var c=a(e),i=u(t);const s=new n.Color("white");exports.InstancedText=function({text:e,thickness:a,fontSize:u,textAlign:d,scale:l,color:f,opacity:g,font:x,...y}){var b,M,h;const m=x.fontMetadata.charToIndex["?"],p=r.useInstancedTextAPI(),B=t.useRef(null),v=t.useRef(null);t.useLayoutEffect((()=>{const t=B.current;if(!t)return;const r=x.fontMetadata.fontScale,u=(x.fontMetadata.boundingBox.yMax-x.fontMetadata.boundingBox.yMin+x.fontMetadata.underlineThickness)*r,c=new Float32Array(e.length),i=new Float32Array(2*e.length);let l=0,g=0;const y=[];Array.from(e).forEach(((e,t)=>{if("\n"===e)y.push(l),l=0,g-=u;else{var n;const o=x.fontMetadata.charToIndex[e],a=null!==(n=x.fontMetadata.advances[o])&&void 0!==n?n:x.fontMetadata.advances[m];c[t]=r,i[2*t]=l,i[2*t+1]=g,l+=a*r}})),y.push(l);const b=Math.max(...y),M=-((x.fontMetadata.boundingBox.yMax-x.fontMetadata.boundingBox.yMin)/2+x.fontMetadata.boundingBox.yMin)*r;Array.from(e).forEach(((e,t)=>{c[t]>0&&(d===o.TextAlignment.left&&(i[2*t+1]+=M),d===o.TextAlignment.right&&(i[2*t]-=b,i[2*t+1]+=M),d===o.TextAlignment.center&&(i[2*t]-=b/2,i[2*t+1]+=M))})),t.geometry.boundingBox||(t.geometry.boundingBox=new n.Box3),t.geometry.boundingSphere||(t.geometry.boundingSphere=new n.Sphere),t.geometry.boundingBox.setFromPoints([new n.Vector3(0,x.fontMetadata.boundingBox.yMin*r,0),new n.Vector3(b,x.fontMetadata.boundingBox.yMax*r,a)]),t.geometry.boundingSphere.setFromPoints([new n.Vector3(0,x.fontMetadata.boundingBox.yMin*r,0),new n.Vector3(b,x.fontMetadata.boundingBox.yMax*r,a)]),d===o.TextAlignment.left&&(t.geometry.boundingBox.translate(new n.Vector3(0,M,0)),t.geometry.boundingSphere.translate(new n.Vector3(0,M,0))),d===o.TextAlignment.right&&(t.geometry.boundingBox.translate(new n.Vector3(-b,M,0)),t.geometry.boundingSphere.translate(new n.Vector3(-b,M,0))),d===o.TextAlignment.center&&(t.geometry.boundingBox.translate(new n.Vector3(-b/2,M,0)),t.geometry.boundingSphere.translate(new n.Vector3(-b/2,M,0)));const h=p.addInstances(e,x,null!=f?f:s,i,t);return h?(v.current=h,()=>p.removeInstances(h)):void 0}),[e,f,x.fontMetadata,m,a,d,p]),t.useEffect((()=>{v.current&&p.setOpacity(v.current,null!=g?g:1)}),[p,g]);const T=t.useMemo((()=>({getBuffers:()=>v.current&&p.getBuffers(v.current),getPtr:()=>v.current,setGlyphs:e=>{if(!v.current)return;const t=p.getBuffers(v.current);if(!t)return;const n=Array.from(e).map((e=>x.fontMetadata.charToIndex[e]));t.instanceGIndexBuffer.set(n,v.current.start),t.instanceGIndexBufferAttribute.needsUpdate=!0}})),[x.fontMetadata.charToIndex]);return i.createElement("instancedTextPlaceholder",c.default({scale:[u*(null!==(b=null==l?void 0:l.x)&&void 0!==b?b:1),u*(null!==(M=null==l?void 0:l.y)&&void 0!==M?M:1),a*(null!==(h=null==l?void 0:l.z)&&void 0!==h?h:1)]},y,{textAPI:T,ref:B,frustumCulled:!1}))};
@@ -0,0 +1,13 @@
1
+ import { GroupProps } from '@react-three/fiber';
2
+ import { Color, Vector3 } from 'three';
3
+ import { Font3D, TextAlignment } from './types';
4
+ export declare function InstancedText({ text, thickness, fontSize, textAlign, scale, color, opacity, font, ...rest }: {
5
+ text: string;
6
+ thickness: number;
7
+ fontSize: number;
8
+ textAlign?: TextAlignment;
9
+ scale?: Vector3;
10
+ color?: Color;
11
+ opacity?: number;
12
+ font: Font3D;
13
+ } & GroupProps): JSX.Element;