@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,357 @@
1
+ import wordWrap from 'word-wrapper';
2
+
3
+ // @ts-ignore
4
+ const X_HEIGHTS = ['x', 'e', 'a', 'o', 'n', 's', 'r', 'c', 'u', 'm', 'v', 'w', 'z'];
5
+ const M_WIDTHS = ['m', 'w'];
6
+ const CAP_HEIGHTS = ['H', 'I', 'N', 'E', 'F', 'K', 'L', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
7
+ const TAB_ID = '\t'.charCodeAt(0);
8
+ const SPACE_ID = ' '.charCodeAt(0);
9
+ const ALIGN_LEFT = 0;
10
+ const ALIGN_CENTER = 1;
11
+ const ALIGN_RIGHT = 2;
12
+ class TextLayout {
13
+ _options = {};
14
+ _width = 0;
15
+ _height = 0;
16
+ _descender = 0;
17
+ _ascender = 0;
18
+ _xHeight = 0;
19
+ _baseline = 0;
20
+ _capHeight = 0;
21
+ _lineHeight = 0;
22
+ _linesTotal = 0;
23
+ _lettersTotal = 0;
24
+ _wordsTotal = 0;
25
+ _fallbackSpaceGlyph = null;
26
+ _fallbackTabGlyph = null;
27
+ constructor(text, options = {}) {
28
+ this.glyphs = [];
29
+ this._text = text;
30
+ this._measure = this.computeMetrics.bind(this);
31
+ this.update(options);
32
+ }
33
+
34
+ /**
35
+ * Getters
36
+ */
37
+ get width() {
38
+ return this._width;
39
+ }
40
+ get height() {
41
+ return this._height;
42
+ }
43
+ get descender() {
44
+ return this._descender;
45
+ }
46
+ get ascender() {
47
+ return this._ascender;
48
+ }
49
+ get xHeight() {
50
+ return this._xHeight;
51
+ }
52
+ get baseline() {
53
+ return this._baseline;
54
+ }
55
+ get capHeight() {
56
+ return this._capHeight;
57
+ }
58
+ get lineHeight() {
59
+ return this._lineHeight;
60
+ }
61
+ get linesTotal() {
62
+ return this._linesTotal;
63
+ }
64
+ get lettersTotal() {
65
+ return this._lettersTotal;
66
+ }
67
+ get wordsTotal() {
68
+ return this._wordsTotal;
69
+ }
70
+ update(options) {
71
+ options = Object.assign({
72
+ measure: this._measure
73
+ }, options);
74
+ this._options = options;
75
+ this._options.tabSize = number(this._options.tabSize, 4);
76
+ if (!options.font) {
77
+ throw new Error('must provide a valid bitmap font');
78
+ }
79
+ const glyphs = this.glyphs;
80
+ const text = this._text || '';
81
+ const font = options.font;
82
+ this._setupSpaceGlyphs(font);
83
+ const lines = wordWrap.lines(text, options);
84
+ const minWidth = options.width || 0;
85
+ const wordsTotal = text.split(' ').filter(word => word !== '\n').length;
86
+ const lettersTotal = text.split('').filter(char => char !== '\n' && char !== ' ').length;
87
+
88
+ // clear glyphs
89
+ glyphs.length = 0;
90
+
91
+ // get max line width
92
+ const maxLineWidth = lines.reduce(function (prev, line) {
93
+ return Math.max(prev, line.width, minWidth);
94
+ }, 0);
95
+
96
+ // the pen position
97
+ let x = 0;
98
+ let y = 0;
99
+ const lineHeight = number(options.lineHeight, font.common.lineHeight);
100
+ const baseline = font.common.base;
101
+ const descender = lineHeight - baseline;
102
+ const letterSpacing = options.letterSpacing || 0;
103
+ const height = lineHeight * lines.length - descender;
104
+ const alignX = getAlignType(this._options.alignX);
105
+
106
+ // draw text along baseline
107
+ y -= height;
108
+
109
+ // the metrics for this text layout
110
+ this._width = maxLineWidth;
111
+ this._height = height;
112
+ this._descender = lineHeight - baseline;
113
+ this._baseline = baseline;
114
+ this._xHeight = getXHeight(font);
115
+ this._capHeight = getCapHeight(font);
116
+ this._lineHeight = lineHeight;
117
+ this._ascender = lineHeight - descender - this._xHeight;
118
+ let wordIndex = 0;
119
+ let letterIndex = 0;
120
+
121
+ // layout each glyph
122
+ lines.forEach((line, lineIndex) => {
123
+ const start = line.start;
124
+ const end = line.end;
125
+ const lineWidth = line.width;
126
+ const lineString = text.slice(start, end);
127
+ const lineWordsTotal = lineString.split(' ').filter(item => item !== '').length;
128
+ const lineLettersTotal = text.slice(start, end).split(' ').join('').length;
129
+ let lineLetterIndex = 0;
130
+ let lineWordIndex = 0;
131
+ let lastGlyph;
132
+
133
+ // for each glyph in that line...
134
+ for (let i = start; i < end; i++) {
135
+ const id = text.charCodeAt(i);
136
+ const glyph = this.getGlyph(font, id);
137
+ if (glyph) {
138
+ if (lastGlyph) {
139
+ x += getKerning(font, lastGlyph.id, glyph.id);
140
+ }
141
+ let tx = x;
142
+ if (alignX === ALIGN_CENTER) {
143
+ tx += (maxLineWidth - lineWidth) / 2;
144
+ } else if (alignX === ALIGN_RIGHT) {
145
+ tx += maxLineWidth - lineWidth;
146
+ }
147
+ glyphs.push({
148
+ position: [tx, y],
149
+ data: glyph,
150
+ index: i,
151
+ // Line
152
+ linesTotal: lines.length,
153
+ lineIndex,
154
+ lineLettersTotal,
155
+ lineLetterIndex,
156
+ lineWordsTotal,
157
+ lineWordIndex,
158
+ // Word
159
+ wordsTotal,
160
+ wordIndex,
161
+ // Letter
162
+ lettersTotal,
163
+ letterIndex
164
+ });
165
+ if (glyph.id === SPACE_ID && lastGlyph.id !== SPACE_ID) {
166
+ lineWordIndex++;
167
+ wordIndex++;
168
+ }
169
+ if (glyph.id !== SPACE_ID) {
170
+ lineLetterIndex++;
171
+ letterIndex++;
172
+ }
173
+
174
+ // move pen forward
175
+ x += glyph.xadvance + letterSpacing;
176
+ lastGlyph = glyph;
177
+ }
178
+ }
179
+
180
+ // next line down
181
+ y += lineHeight;
182
+ x = 0;
183
+ });
184
+ this._lettersTotal = lettersTotal;
185
+ this._wordsTotal = wordsTotal;
186
+ this._linesTotal = lines.length;
187
+ }
188
+ getGlyph(font, id) {
189
+ const glyph = getGlyphById(font, id);
190
+ if (glyph) {
191
+ return glyph;
192
+ } else if (id === TAB_ID) {
193
+ return this._fallbackTabGlyph;
194
+ } else if (id === SPACE_ID) {
195
+ return this._fallbackSpaceGlyph;
196
+ }
197
+ return null;
198
+ }
199
+ computeMetrics(text, start, end, width) {
200
+ const letterSpacing = this._options.letterSpacing || 0;
201
+ const font = this._options.font;
202
+ let curPen = 0;
203
+ let curWidth = 0;
204
+ let count = 0;
205
+ let glyph;
206
+ let lastGlyph;
207
+ if (!font.chars || font.chars.length === 0) {
208
+ return {
209
+ start,
210
+ end: start,
211
+ width: 0
212
+ };
213
+ }
214
+ end = Math.min(text.length, end);
215
+ for (let i = start; i < end; i++) {
216
+ const id = text.charCodeAt(i);
217
+ glyph = this.getGlyph(font, id);
218
+ if (glyph) {
219
+ glyph.char = text[i];
220
+ // move pen forward
221
+ // const xoff = glyph.xoffset;
222
+ const kern = lastGlyph ? getKerning(font, lastGlyph.id, glyph.id) : 0;
223
+ curPen += kern;
224
+ const nextPen = curPen + glyph.xadvance + letterSpacing;
225
+ const nextWidth = curPen + glyph.width;
226
+
227
+ // we've hit our limit; we can't move onto the next glyph
228
+ if (nextWidth >= width || nextPen >= width) {
229
+ break;
230
+ }
231
+
232
+ // otherwise continue along our line
233
+ curPen = nextPen;
234
+ curWidth = nextWidth;
235
+ lastGlyph = glyph;
236
+ }
237
+ count++;
238
+ }
239
+
240
+ // make sure rightmost edge lines up with rendered glyphs
241
+ if (lastGlyph) {
242
+ curWidth += lastGlyph.xoffset;
243
+ }
244
+ return {
245
+ start,
246
+ end: start + count,
247
+ width: curWidth
248
+ };
249
+ }
250
+
251
+ /**
252
+ * Private
253
+ */
254
+ _setupSpaceGlyphs(font) {
255
+ var _this$_options$tabSiz;
256
+ // These are fallbacks, when the font doesn't include
257
+ // ' ' or '\t' glyphs
258
+ this._fallbackSpaceGlyph = null;
259
+ this._fallbackTabGlyph = null;
260
+ if (!font.chars || font.chars.length === 0) return;
261
+
262
+ // try to get space glyph
263
+ // then fall back to the 'm' or 'w' glyphs
264
+ // then fall back to the first glyph available
265
+ const space = getGlyphById(font, SPACE_ID) || getMGlyph(font) || font.chars[0];
266
+
267
+ // and create a fallback for tab
268
+ const tabWidth = ((_this$_options$tabSiz = this._options.tabSize) !== null && _this$_options$tabSiz !== void 0 ? _this$_options$tabSiz : 1) * space.xadvance;
269
+ this._fallbackSpaceGlyph = space;
270
+ const spaceClone = Object.assign({}, space);
271
+ this._fallbackTabGlyph = Object.assign(spaceClone, {
272
+ x: 0,
273
+ y: 0,
274
+ xadvance: tabWidth,
275
+ id: TAB_ID,
276
+ xoffset: 0,
277
+ yoffset: 0,
278
+ width: 0,
279
+ height: 0
280
+ });
281
+ }
282
+ }
283
+ function createLayout(text, options) {
284
+ return new TextLayout(text, options);
285
+ }
286
+ function getGlyphById(font, id) {
287
+ if (!font.chars || font.chars.length === 0) {
288
+ return null;
289
+ }
290
+ const glyphIdx = findChar(font.chars, id);
291
+ if (glyphIdx >= 0) {
292
+ const glyph = font.chars[glyphIdx];
293
+ return glyph;
294
+ }
295
+ return null;
296
+ }
297
+ 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;
305
+ }
306
+ 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;
314
+ }
315
+ 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;
323
+ }
324
+ 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;
335
+ }
336
+ function getAlignType(align) {
337
+ if (align === 'center') {
338
+ return ALIGN_CENTER;
339
+ } else if (align === 'right') {
340
+ return ALIGN_RIGHT;
341
+ }
342
+ return ALIGN_LEFT;
343
+ }
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
+ function number(num, def) {
354
+ return typeof num === 'number' ? num : typeof def === 'number' ? def : 0;
355
+ }
356
+
357
+ export { createLayout, TextLayout as default };
@@ -0,0 +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;
@@ -0,0 +1,51 @@
1
+ import { BufferGeometry, Box3, BufferAttribute, Matrix4 } from 'three';
2
+ import TextLayout from './TextLayout';
3
+ export interface IInstance {
4
+ text: string;
5
+ lineHeight?: number;
6
+ letterSpacing?: number;
7
+ alignX?: string;
8
+ alignY?: string;
9
+ width?: number;
10
+ yShift?: number;
11
+ }
12
+ export interface IOptions {
13
+ texts: IInstance[];
14
+ flipY?: boolean;
15
+ font?: any;
16
+ tabSize?: number;
17
+ width?: number;
18
+ lineHeight?: number;
19
+ letterSpacing?: number;
20
+ alignX?: string;
21
+ alignY?: string;
22
+ yShift?: number;
23
+ }
24
+ export interface IGlyph {
25
+ position: [number, number];
26
+ data: any;
27
+ index: number;
28
+ linesTotal: number;
29
+ lineIndex: number;
30
+ lineLettersTotal: number;
31
+ lineLetterIndex: number;
32
+ lineWordsTotal: number;
33
+ lineWordIndex: number;
34
+ wordsTotal: number;
35
+ wordIndex: number;
36
+ lettersTotal: number;
37
+ letterIndex: number;
38
+ }
39
+ export default class MSDFTextGeometry extends BufferGeometry {
40
+ _layouts: TextLayout[];
41
+ originalPositionsArray: Float32Array;
42
+ positionsArray: Float32Array;
43
+ positionsAttribute: BufferAttribute | null;
44
+ instancesOffsetsCache: number[];
45
+ instancesLengthsCache: number[];
46
+ constructor(options: IOptions);
47
+ setTransform(transform: Matrix4, instance?: number): void;
48
+ update(options: IOptions): void;
49
+ computeBoundingSphere(): void;
50
+ computeBoundingBox(): Box3 | undefined;
51
+ }
@@ -0,0 +1,159 @@
1
+ import createIndices from 'quad-indices';
2
+ import { BufferGeometry, BufferAttribute, Sphere, Box3, Vector3 } from 'three';
3
+ import { createLayout } from './TextLayout.js';
4
+ import { computeSphere, computeBox } from './utils.js';
5
+ import { generateAttributes } from './vertices.js';
6
+
7
+ // @ts-ignore-next-line
8
+ // TEMP for optimizing allocations
9
+ const pointA = new Vector3();
10
+ const pointB = new Vector3();
11
+ const pointC = new Vector3();
12
+ const pointD = new Vector3();
13
+ class MSDFTextGeometry extends BufferGeometry {
14
+ originalPositionsArray = new Float32Array();
15
+ positionsArray = new Float32Array();
16
+ positionsAttribute = null;
17
+ instancesOffsetsCache = [];
18
+ instancesLengthsCache = [];
19
+ constructor(options) {
20
+ super();
21
+ this._layouts = [];
22
+ this.update(options);
23
+ }
24
+ setTransform(transform, instance = 0) {
25
+ const instanceOffset = this.instancesOffsetsCache[instance];
26
+ const instanceLength = this.instancesLengthsCache[instance];
27
+ for (let i = 0; i < instanceLength; i++) {
28
+ const instanceGlyphOffset = instanceOffset * 12 + i * 12;
29
+ const originalXA = this.originalPositionsArray[instanceGlyphOffset];
30
+ const originalYA = this.originalPositionsArray[instanceGlyphOffset + 1];
31
+ const originalZA = this.originalPositionsArray[instanceGlyphOffset + 2];
32
+ const originalXB = this.originalPositionsArray[instanceGlyphOffset + 3];
33
+ const originalYB = this.originalPositionsArray[instanceGlyphOffset + 4];
34
+ const originalZB = this.originalPositionsArray[instanceGlyphOffset + 5];
35
+ const originalXC = this.originalPositionsArray[instanceGlyphOffset + 6];
36
+ const originalYC = this.originalPositionsArray[instanceGlyphOffset + 7];
37
+ const originalZC = this.originalPositionsArray[instanceGlyphOffset + 8];
38
+ const originalXD = this.originalPositionsArray[instanceGlyphOffset + 9];
39
+ const originalYD = this.originalPositionsArray[instanceGlyphOffset + 10];
40
+ const originalZD = this.originalPositionsArray[instanceGlyphOffset + 11];
41
+ pointA.set(originalXA, originalYA, originalZA).applyMatrix4(transform);
42
+ pointB.set(originalXB, originalYB, originalZB).applyMatrix4(transform);
43
+ pointC.set(originalXC, originalYC, originalZC).applyMatrix4(transform);
44
+ pointD.set(originalXD, originalYD, originalZD).applyMatrix4(transform);
45
+ this.positionsArray[instanceGlyphOffset] = pointA.x;
46
+ this.positionsArray[instanceGlyphOffset + 1] = pointA.y;
47
+ this.positionsArray[instanceGlyphOffset + 2] = pointA.z;
48
+ this.positionsArray[instanceGlyphOffset + 3] = pointB.x;
49
+ this.positionsArray[instanceGlyphOffset + 4] = pointB.y;
50
+ this.positionsArray[instanceGlyphOffset + 5] = pointB.z;
51
+ this.positionsArray[instanceGlyphOffset + 6] = pointC.x;
52
+ this.positionsArray[instanceGlyphOffset + 7] = pointC.y;
53
+ this.positionsArray[instanceGlyphOffset + 8] = pointC.z;
54
+ this.positionsArray[instanceGlyphOffset + 9] = pointD.x;
55
+ this.positionsArray[instanceGlyphOffset + 10] = pointD.y;
56
+ this.positionsArray[instanceGlyphOffset + 11] = pointD.z;
57
+ }
58
+ if (this.positionsAttribute) {
59
+ this.positionsAttribute.needsUpdate = true;
60
+ }
61
+ }
62
+ update(options) {
63
+ const {
64
+ texts,
65
+ ...optionsWithoutTexts
66
+ } = options;
67
+ this._layouts = texts.map(txt => createLayout(txt.text, {
68
+ ...optionsWithoutTexts,
69
+ ...txt
70
+ }));
71
+
72
+ // get vec2 texcoords
73
+ const flipY = options.flipY !== false;
74
+
75
+ // the desired BMFont data
76
+ const font = options.font;
77
+
78
+ // determine texture size from font file
79
+ const texWidth = font.common.scaleW;
80
+ 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
+ }));
85
+
86
+ // Keep a cache of each text instance offset and length for attributes
87
+ this.instancesOffsetsCache = [];
88
+ this.instancesLengthsCache = [];
89
+ let offsetSoFar = 0;
90
+ glyphs.forEach((t, i) => {
91
+ this.instancesLengthsCache[i] = t.length;
92
+ this.instancesOffsetsCache[i] = offsetSoFar;
93
+ offsetSoFar += t.length;
94
+ });
95
+ 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;
119
+ });
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));
127
+ }
128
+ computeBoundingSphere() {
129
+ if (this.boundingSphere === null) this.boundingSphere = new Sphere();
130
+ const positions = this.attributes.position.array;
131
+ const itemSize = this.attributes.position.itemSize;
132
+ if (!positions || !itemSize || positions.length < 2) {
133
+ this.boundingSphere.radius = 0;
134
+ this.boundingSphere.center.set(0, 0, 0);
135
+ return;
136
+ }
137
+ computeSphere(positions, this.boundingSphere);
138
+ if (isNaN(this.boundingSphere.radius)) {
139
+ // eslint-disable-next-line no-console
140
+ console.error('BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.');
141
+ }
142
+ }
143
+ computeBoundingBox() {
144
+ if (this.boundingBox === null) {
145
+ this.boundingBox = new Box3();
146
+ }
147
+ const bbox = this.boundingBox;
148
+ const positions = this.attributes.position.array;
149
+ const itemSize = this.attributes.position.itemSize;
150
+ if (!positions || !itemSize || positions.length < 2) {
151
+ bbox.makeEmpty();
152
+ return;
153
+ }
154
+ const box = computeBox(positions, bbox);
155
+ return box;
156
+ }
157
+ }
158
+
159
+ export { MSDFTextGeometry as default };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});const m=3,n={min:[0,0,0],max:[0,0,0]};function t(t){const a=t.length/m;n.min[0]=t[0],n.min[1]=t[1],n.max[0]=t[0],n.max[1]=t[1];for(let i=0;i<a;i++){const a=t[i*m+0],e=t[i*m+1],x=t[i*m+2];n.min[0]=Math.min(a,n.min[0]),n.min[1]=Math.min(e,n.min[1]),n.min[2]=Math.min(x,n.min[2]),n.max[0]=Math.max(a,n.max[0]),n.max[1]=Math.max(e,n.max[1]),n.max[2]=Math.max(x,n.max[2])}}exports.computeBox=function(m,a){return t(m),a.min.set(n.min[0],n.min[1],n.min[2]),a.max.set(n.max[0],n.max[1],n.max[2]),a},exports.computeSphere=function(m,a){t(m);const i=n.min[0],e=n.min[1],x=n.min[2],o=n.max[0]-i,s=n.max[1]-e,r=n.max[2]-x,c=Math.sqrt(o*o+s*s+r*r);a.center.set(i+o/2,e+s/2,x+r/2),a.radius=c/2};
@@ -0,0 +1,3 @@
1
+ import { Box3, Sphere } from 'three';
2
+ export declare function computeBox(positions: ArrayLike<number>, output: Box3): Box3;
3
+ export declare function computeSphere(positions: ArrayLike<number>, output: Sphere): void;
@@ -0,0 +1,46 @@
1
+ const itemSize = 3;
2
+ const box = {
3
+ min: [0, 0, 0],
4
+ max: [0, 0, 0]
5
+ };
6
+ function bounds(positions) {
7
+ const count = positions.length / itemSize;
8
+ box.min[0] = positions[0];
9
+ box.min[1] = positions[1];
10
+ box.max[0] = positions[0];
11
+ box.max[1] = positions[1];
12
+ for (let i = 0; i < count; i++) {
13
+ const x = positions[i * itemSize + 0];
14
+ const y = positions[i * itemSize + 1];
15
+ const z = positions[i * itemSize + 2];
16
+ box.min[0] = Math.min(x, box.min[0]);
17
+ box.min[1] = Math.min(y, box.min[1]);
18
+ box.min[2] = Math.min(z, box.min[2]);
19
+ box.max[0] = Math.max(x, box.max[0]);
20
+ box.max[1] = Math.max(y, box.max[1]);
21
+ box.max[2] = Math.max(z, box.max[2]);
22
+ }
23
+ }
24
+ function computeBox(positions, output) {
25
+ bounds(positions);
26
+ output.min.set(box.min[0], box.min[1], box.min[2]);
27
+ output.max.set(box.max[0], box.max[1], box.max[2]);
28
+ return output;
29
+ }
30
+ function computeSphere(positions, output) {
31
+ bounds(positions);
32
+ const minX = box.min[0];
33
+ const minY = box.min[1];
34
+ const minZ = box.min[2];
35
+ const maxX = box.max[0];
36
+ const maxY = box.max[1];
37
+ const maxZ = box.max[2];
38
+ const width = maxX - minX;
39
+ const height = maxY - minY;
40
+ const depth = maxZ - minZ;
41
+ const length = Math.sqrt(width * width + height * height + depth * depth);
42
+ output.center.set(minX + width / 2, minY + height / 2, minZ + depth / 2);
43
+ output.radius = length / 2;
44
+ }
45
+
46
+ export { computeBox, computeSphere };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.generateAttributes=function(t,e,o,n){const s=new Float32Array(4*t.length*2),r=new Float32Array(4*t.length*3),i=new Float32Array(4*t.length*2);let a=0,l=0,c=0;return t.forEach((function(t){const h=t.data,f=h.x+h.width,u=h.y+h.height,y=h.x/e;let g=h.y/o;const p=f/e;let d=u/o;n&&(g=(o-h.y)/o,d=(o-u)/o),s[a++]=y,s[a++]=g,s[a++]=y,s[a++]=d,s[a++]=p,s[a++]=d,s[a++]=p,s[a++]=g;const w=t.position[0]+h.xoffset,x=t.position[1]+h.yoffset,A=h.width,F=h.height;r[l++]=w,r[l++]=x,r[l++]=0,r[l++]=w,r[l++]=x+F,r[l++]=0,r[l++]=w+A,r[l++]=x+F,r[l++]=0,r[l++]=w+A,r[l++]=x,r[l++]=0,i[c++]=w+A/2,i[c++]=x+F/2,i[c++]=w+A/2,i[c++]=x+F/2,i[c++]=w+A/2,i[c++]=x+F/2,i[c++]=w+A/2,i[c++]=x+F/2})),{uvs:s,positions:r,centers:i}};
@@ -0,0 +1,28 @@
1
+ type Glyph = {
2
+ data: {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ page: number;
8
+ xoffset: number;
9
+ yoffset: number;
10
+ };
11
+ position: [number, number];
12
+ linesTotal: number;
13
+ lineIndex: number;
14
+ lineLettersTotal: number;
15
+ lineLetterIndex: number;
16
+ lineWordsTotal: number;
17
+ lineWordIndex: number;
18
+ wordsTotal: number;
19
+ wordIndex: number;
20
+ lettersTotal: number;
21
+ letterIndex: number;
22
+ };
23
+ export declare function generateAttributes(glyphs: Glyph[], texWidth: number, texHeight: number, flipY: boolean): {
24
+ uvs: Float32Array;
25
+ positions: Float32Array;
26
+ centers: Float32Array;
27
+ };
28
+ export {};