@xviewer.js/core 1.0.4-alpha.7 → 1.0.4-alpha.9
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/dist/main.cjs +695 -3
- package/dist/main.cjs.map +1 -1
- package/dist/module.js +693 -5
- package/dist/module.js.map +1 -1
- package/package.json +1 -1
- package/types/bmfont/BMFontAtlas.d.ts +44 -0
- package/types/bmfont/BMFontTextGeometry.d.ts +9 -0
- package/types/bmfont/BMFontTextLayout.d.ts +93 -0
- package/types/bmfont/index.d.ts +3 -0
- package/types/bmfont/utils.d.ts +2 -0
- package/types/bmfont/wordwrap.d.ts +8 -0
- package/types/components/Label.d.ts +26 -0
- package/types/components/index.d.ts +1 -0
- package/types/index.d.ts +1 -0
- package/types/materials/MSDFMaterial.d.ts +20 -0
package/dist/main.cjs
CHANGED
|
@@ -2807,14 +2807,16 @@ class DeviceInput extends Component {
|
|
|
2807
2807
|
const isDocument = target instanceof Document;
|
|
2808
2808
|
const width = isDocument ? window.innerWidth : target.offsetWidth;
|
|
2809
2809
|
const height = isDocument ? window.innerHeight : target.offsetHeight;
|
|
2810
|
-
this._pointer.x = e.
|
|
2811
|
-
this._pointer.y = 1 - e.
|
|
2812
|
-
this._pointerPixel.set(e.
|
|
2810
|
+
this._pointer.x = e.pageX / width * 2 - 1;
|
|
2811
|
+
this._pointer.y = 1 - e.pageY / height * 2;
|
|
2812
|
+
this._pointerPixel.set(e.pageX, e.pageY);
|
|
2813
2813
|
}
|
|
2814
2814
|
_onPointerDown(e) {
|
|
2815
2815
|
e = this._remapPointer(e);
|
|
2816
2816
|
this._pointerButton = e.button;
|
|
2817
2817
|
this._computePointer(e);
|
|
2818
|
+
this._prePointer.copy(this._pointer);
|
|
2819
|
+
this._prePointerPixel.copy(this._pointerPixel);
|
|
2818
2820
|
this._pressability.pointerDown(this._pointer, this.viewer.camera);
|
|
2819
2821
|
this.viewer.emit(DeviceInput.POINTER_DOWN, e);
|
|
2820
2822
|
}
|
|
@@ -2861,6 +2863,7 @@ class DeviceInput extends Component {
|
|
|
2861
2863
|
preTouches[i].position.copy(touches[i].position);
|
|
2862
2864
|
}
|
|
2863
2865
|
}
|
|
2866
|
+
this._touchCount = curr.length;
|
|
2864
2867
|
this.viewer.emit(DeviceInput.TOUCH_START, e);
|
|
2865
2868
|
}
|
|
2866
2869
|
_onTouchEnd(e) {
|
|
@@ -5886,10 +5889,698 @@ function getFilesFromItemList(items, onDone) {
|
|
|
5886
5889
|
}
|
|
5887
5890
|
}
|
|
5888
5891
|
|
|
5892
|
+
const newline = /\n/;
|
|
5893
|
+
const newlineChar = '\n';
|
|
5894
|
+
const whitespace = /\s/;
|
|
5895
|
+
function wordwrap(text, opt) {
|
|
5896
|
+
opt = opt || {};
|
|
5897
|
+
//zero width results in nothing visible
|
|
5898
|
+
if (opt.width === 0 && opt.mode !== 'nowrap') return [];
|
|
5899
|
+
text = text || '';
|
|
5900
|
+
const width = typeof opt.width === 'number' ? opt.width : Number.MAX_VALUE;
|
|
5901
|
+
const start = Math.max(0, opt.start || 0);
|
|
5902
|
+
const end = typeof opt.end === 'number' ? opt.end : text.length;
|
|
5903
|
+
const mode = opt.mode;
|
|
5904
|
+
const letterSpacing = opt.letterSpacing || 0;
|
|
5905
|
+
const measure = opt.measure || monospace;
|
|
5906
|
+
if (mode === 'pre') return pre(measure, text, start, end, width, letterSpacing);
|
|
5907
|
+
else return greedy(measure, text, start, end, width, mode, letterSpacing);
|
|
5908
|
+
}
|
|
5909
|
+
function idxOf(text, chr, start, end) {
|
|
5910
|
+
var idx = text.indexOf(chr, start);
|
|
5911
|
+
if (idx === -1 || idx > end) return end;
|
|
5912
|
+
return idx;
|
|
5913
|
+
}
|
|
5914
|
+
function isWhitespace(chr) {
|
|
5915
|
+
return whitespace.test(chr);
|
|
5916
|
+
}
|
|
5917
|
+
function pre(measure, text, start, end, width, letterSpacing) {
|
|
5918
|
+
var lines = [];
|
|
5919
|
+
var lineStart = start;
|
|
5920
|
+
for(var i = start; i < end && i < text.length; i++){
|
|
5921
|
+
var chr = text.charAt(i);
|
|
5922
|
+
var isNewline = newline.test(chr);
|
|
5923
|
+
//If we've reached a newline, then step down a line
|
|
5924
|
+
//Or if we've reached the EOF
|
|
5925
|
+
if (isNewline || i === end - 1) {
|
|
5926
|
+
var lineEnd = isNewline ? i : i + 1;
|
|
5927
|
+
var measured = measure(text, lineStart, lineEnd, width, letterSpacing);
|
|
5928
|
+
lines.push(measured);
|
|
5929
|
+
lineStart = i + 1;
|
|
5930
|
+
}
|
|
5931
|
+
}
|
|
5932
|
+
return lines;
|
|
5933
|
+
}
|
|
5934
|
+
function greedy(measure, text, start, end, width, mode, letterSpacing) {
|
|
5935
|
+
//A greedy word wrapper based on LibGDX algorithm
|
|
5936
|
+
//https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/BitmapFontCache.java
|
|
5937
|
+
var lines = [];
|
|
5938
|
+
var testWidth = width;
|
|
5939
|
+
//if 'nowrap' is specified, we only wrap on newline chars
|
|
5940
|
+
if (mode === 'nowrap') testWidth = Number.MAX_VALUE;
|
|
5941
|
+
while(start < end && start < text.length){
|
|
5942
|
+
//get next newline position
|
|
5943
|
+
var newLine = idxOf(text, newlineChar, start, end);
|
|
5944
|
+
//eat whitespace at start of line
|
|
5945
|
+
while(start < newLine){
|
|
5946
|
+
if (!isWhitespace(text.charAt(start))) break;
|
|
5947
|
+
start++;
|
|
5948
|
+
}
|
|
5949
|
+
//determine visible # of glyphs for the available width
|
|
5950
|
+
var measured = measure(text, start, newLine, testWidth, letterSpacing);
|
|
5951
|
+
var lineEnd = start + (measured.end - measured.start);
|
|
5952
|
+
var nextStart = lineEnd + newlineChar.length;
|
|
5953
|
+
//if we had to cut the line before the next newline...
|
|
5954
|
+
if (lineEnd < newLine) {
|
|
5955
|
+
//find char to break on
|
|
5956
|
+
while(lineEnd > start){
|
|
5957
|
+
if (isWhitespace(text.charAt(lineEnd))) break;
|
|
5958
|
+
lineEnd--;
|
|
5959
|
+
}
|
|
5960
|
+
if (lineEnd === start) {
|
|
5961
|
+
if (nextStart > start + newlineChar.length) nextStart--;
|
|
5962
|
+
lineEnd = nextStart; // If no characters to break, show all.
|
|
5963
|
+
} else {
|
|
5964
|
+
nextStart = lineEnd;
|
|
5965
|
+
//eat whitespace at end of line
|
|
5966
|
+
while(lineEnd > start){
|
|
5967
|
+
if (!isWhitespace(text.charAt(lineEnd - newlineChar.length))) break;
|
|
5968
|
+
lineEnd--;
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
}
|
|
5972
|
+
if (lineEnd >= start) {
|
|
5973
|
+
var result = measure(text, start, lineEnd, testWidth);
|
|
5974
|
+
lines.push(result);
|
|
5975
|
+
}
|
|
5976
|
+
start = nextStart;
|
|
5977
|
+
}
|
|
5978
|
+
return lines;
|
|
5979
|
+
}
|
|
5980
|
+
//determines the visible number of glyphs within a given width
|
|
5981
|
+
function monospace(text, start, end, width) {
|
|
5982
|
+
var glyphs = Math.min(width, end - start);
|
|
5983
|
+
return {
|
|
5984
|
+
start: start,
|
|
5985
|
+
end: start + glyphs
|
|
5986
|
+
};
|
|
5987
|
+
}
|
|
5988
|
+
|
|
5989
|
+
const X_HEIGHTS = [
|
|
5990
|
+
'x',
|
|
5991
|
+
'e',
|
|
5992
|
+
'a',
|
|
5993
|
+
'o',
|
|
5994
|
+
'n',
|
|
5995
|
+
's',
|
|
5996
|
+
'r',
|
|
5997
|
+
'c',
|
|
5998
|
+
'u',
|
|
5999
|
+
'm',
|
|
6000
|
+
'v',
|
|
6001
|
+
'w',
|
|
6002
|
+
'z'
|
|
6003
|
+
];
|
|
6004
|
+
const M_WIDTHS = [
|
|
6005
|
+
'm',
|
|
6006
|
+
'w'
|
|
6007
|
+
];
|
|
6008
|
+
const CAP_HEIGHTS = [
|
|
6009
|
+
'H',
|
|
6010
|
+
'I',
|
|
6011
|
+
'N',
|
|
6012
|
+
'E',
|
|
6013
|
+
'F',
|
|
6014
|
+
'K',
|
|
6015
|
+
'L',
|
|
6016
|
+
'T',
|
|
6017
|
+
'U',
|
|
6018
|
+
'V',
|
|
6019
|
+
'W',
|
|
6020
|
+
'X',
|
|
6021
|
+
'Y',
|
|
6022
|
+
'Z'
|
|
6023
|
+
];
|
|
6024
|
+
const TAB_ID = '\t'.charCodeAt(0);
|
|
6025
|
+
const SPACE_ID = ' '.charCodeAt(0);
|
|
6026
|
+
const ALIGN_LEFT = 0, ALIGN_CENTER = 1, ALIGN_RIGHT = 2;
|
|
6027
|
+
function findChar(array, value, start) {
|
|
6028
|
+
start = start || 0;
|
|
6029
|
+
for(let i = start; i < array.length; i++){
|
|
6030
|
+
if (array[i].id === value) {
|
|
6031
|
+
return i;
|
|
6032
|
+
}
|
|
6033
|
+
}
|
|
6034
|
+
return -1;
|
|
6035
|
+
}
|
|
6036
|
+
function getGlyphById(font, id) {
|
|
6037
|
+
if (!font.chars || font.chars.length === 0) return null;
|
|
6038
|
+
let glyphIdx = findChar(font.chars, id);
|
|
6039
|
+
if (glyphIdx >= 0) return font.chars[glyphIdx];
|
|
6040
|
+
return null;
|
|
6041
|
+
}
|
|
6042
|
+
function getXHeight(font) {
|
|
6043
|
+
for(let i = 0; i < X_HEIGHTS.length; i++){
|
|
6044
|
+
let id = X_HEIGHTS[i].charCodeAt(0);
|
|
6045
|
+
let idx = findChar(font.chars, id);
|
|
6046
|
+
if (idx >= 0) return font.chars[idx].height;
|
|
6047
|
+
}
|
|
6048
|
+
return 0;
|
|
6049
|
+
}
|
|
6050
|
+
function getMGlyph(font) {
|
|
6051
|
+
for(let i = 0; i < M_WIDTHS.length; i++){
|
|
6052
|
+
let id = M_WIDTHS[i].charCodeAt(0);
|
|
6053
|
+
let idx = findChar(font.chars, id);
|
|
6054
|
+
if (idx >= 0) return font.chars[idx];
|
|
6055
|
+
}
|
|
6056
|
+
return 0;
|
|
6057
|
+
}
|
|
6058
|
+
function getCapHeight(font) {
|
|
6059
|
+
for(let i = 0; i < CAP_HEIGHTS.length; i++){
|
|
6060
|
+
let id = CAP_HEIGHTS[i].charCodeAt(0);
|
|
6061
|
+
let idx = findChar(font.chars, id);
|
|
6062
|
+
if (idx >= 0) return font.chars[idx].height;
|
|
6063
|
+
}
|
|
6064
|
+
return 0;
|
|
6065
|
+
}
|
|
6066
|
+
function getKerning(font, left, right) {
|
|
6067
|
+
if (!font.kernings || font.kernings.length === 0) return 0;
|
|
6068
|
+
let table = font.kernings;
|
|
6069
|
+
for(let i = 0; i < table.length; i++){
|
|
6070
|
+
let kern = table[i];
|
|
6071
|
+
if (kern.first === left && kern.second === right) return kern.amount;
|
|
6072
|
+
}
|
|
6073
|
+
return 0;
|
|
6074
|
+
}
|
|
6075
|
+
function getAlignType(align) {
|
|
6076
|
+
if (align === 'center') return ALIGN_CENTER;
|
|
6077
|
+
else if (align === 'right') return ALIGN_RIGHT;
|
|
6078
|
+
return ALIGN_LEFT;
|
|
6079
|
+
}
|
|
6080
|
+
class BMFontTextLayout {
|
|
6081
|
+
get width() {
|
|
6082
|
+
return this._width;
|
|
6083
|
+
}
|
|
6084
|
+
get height() {
|
|
6085
|
+
return this._height;
|
|
6086
|
+
}
|
|
6087
|
+
get descender() {
|
|
6088
|
+
return this._descender;
|
|
6089
|
+
}
|
|
6090
|
+
get ascender() {
|
|
6091
|
+
return this._ascender;
|
|
6092
|
+
}
|
|
6093
|
+
get xHeight() {
|
|
6094
|
+
return this._xHeight;
|
|
6095
|
+
}
|
|
6096
|
+
get baseline() {
|
|
6097
|
+
return this._baseline;
|
|
6098
|
+
}
|
|
6099
|
+
get capHeight() {
|
|
6100
|
+
return this._capHeight;
|
|
6101
|
+
}
|
|
6102
|
+
get lineHeight() {
|
|
6103
|
+
return this._lineHeight;
|
|
6104
|
+
}
|
|
6105
|
+
get glyphs() {
|
|
6106
|
+
return this._glyphs;
|
|
6107
|
+
}
|
|
6108
|
+
get linesTotal() {
|
|
6109
|
+
return this._linesTotal;
|
|
6110
|
+
}
|
|
6111
|
+
update(font, text, setting) {
|
|
6112
|
+
setting = Object.assign({
|
|
6113
|
+
tabSize: 4,
|
|
6114
|
+
width: 0,
|
|
6115
|
+
letterSpacing: 0,
|
|
6116
|
+
mode: "nowrap",
|
|
6117
|
+
align: "left"
|
|
6118
|
+
}, setting);
|
|
6119
|
+
this._font = font;
|
|
6120
|
+
const measure = this._computeMetrics.bind(this);
|
|
6121
|
+
const lines = wordwrap(text, {
|
|
6122
|
+
measure,
|
|
6123
|
+
...setting
|
|
6124
|
+
});
|
|
6125
|
+
const minWidth = setting.width || 0;
|
|
6126
|
+
const glyphs = this._glyphs;
|
|
6127
|
+
const maxLineWidth = lines.reduce((prev, line)=>Math.max(prev, line.width, minWidth), 0);
|
|
6128
|
+
var _setting_lineHeight;
|
|
6129
|
+
//the pen position
|
|
6130
|
+
const lineHeight = (_setting_lineHeight = setting.lineHeight) != null ? _setting_lineHeight : font.common.lineHeight;
|
|
6131
|
+
const baseline = font.common.base;
|
|
6132
|
+
const descender = lineHeight - baseline;
|
|
6133
|
+
const letterSpacing = setting.letterSpacing || 0;
|
|
6134
|
+
const height = lineHeight * lines.length - descender;
|
|
6135
|
+
const align = getAlignType(setting.align);
|
|
6136
|
+
var _setting_anchor;
|
|
6137
|
+
const anchor = (_setting_anchor = setting.anchor) != null ? _setting_anchor : [
|
|
6138
|
+
0.5,
|
|
6139
|
+
0.5
|
|
6140
|
+
];
|
|
6141
|
+
this._setupSpaceGlyphs(font, setting);
|
|
6142
|
+
//the metrics for this text layout
|
|
6143
|
+
this._width = maxLineWidth;
|
|
6144
|
+
this._height = height;
|
|
6145
|
+
this._descender = descender;
|
|
6146
|
+
this._baseline = baseline;
|
|
6147
|
+
this._xHeight = getXHeight(font);
|
|
6148
|
+
this._capHeight = getCapHeight(font);
|
|
6149
|
+
this._lineHeight = lineHeight;
|
|
6150
|
+
this._ascender = baseline - this._xHeight; //lineHeight - descender - this._xHeight
|
|
6151
|
+
const anchorOffset = [
|
|
6152
|
+
-maxLineWidth * anchor[0],
|
|
6153
|
+
2 * lineHeight * anchor[1] - baseline
|
|
6154
|
+
];
|
|
6155
|
+
let x = 0, y = 0;
|
|
6156
|
+
//draw text along baseline
|
|
6157
|
+
y -= height;
|
|
6158
|
+
glyphs.length = 0;
|
|
6159
|
+
for(let k = 0; k < lines.length; k++){
|
|
6160
|
+
const line = lines[k];
|
|
6161
|
+
let start = line.start;
|
|
6162
|
+
let end = line.end;
|
|
6163
|
+
let lineWidth = line.width;
|
|
6164
|
+
let lastGlyph;
|
|
6165
|
+
//for each glyph in that line...
|
|
6166
|
+
for(let i = start; i < end; i++){
|
|
6167
|
+
let id = text.charCodeAt(i);
|
|
6168
|
+
let glyph = this._getGlyph(font, id);
|
|
6169
|
+
if (glyph) {
|
|
6170
|
+
if (lastGlyph) x += getKerning(font, lastGlyph.id, glyph.id);
|
|
6171
|
+
let tx = x;
|
|
6172
|
+
if (align === ALIGN_CENTER) tx += (maxLineWidth - lineWidth) / 2;
|
|
6173
|
+
else if (align === ALIGN_RIGHT) tx += maxLineWidth - lineWidth;
|
|
6174
|
+
glyphs.push({
|
|
6175
|
+
position: [
|
|
6176
|
+
tx + anchorOffset[0],
|
|
6177
|
+
y + anchorOffset[1]
|
|
6178
|
+
],
|
|
6179
|
+
data: glyph,
|
|
6180
|
+
index: i,
|
|
6181
|
+
line: k
|
|
6182
|
+
});
|
|
6183
|
+
//move pen forward
|
|
6184
|
+
x += glyph.xadvance + letterSpacing;
|
|
6185
|
+
lastGlyph = glyph;
|
|
6186
|
+
}
|
|
6187
|
+
}
|
|
6188
|
+
//next line down
|
|
6189
|
+
y += lineHeight;
|
|
6190
|
+
x = 0;
|
|
6191
|
+
}
|
|
6192
|
+
this._linesTotal = lines.length;
|
|
6193
|
+
}
|
|
6194
|
+
_setupSpaceGlyphs(font, setting) {
|
|
6195
|
+
//These are fallbacks, when the font doesn't include
|
|
6196
|
+
//' ' or '\t' glyphs
|
|
6197
|
+
if (!font.chars || font.chars.length === 0) return;
|
|
6198
|
+
//try to get space glyph
|
|
6199
|
+
//then fall back to the 'm' or 'w' glyphs
|
|
6200
|
+
//then fall back to the first glyph available
|
|
6201
|
+
const space = Object.assign({}, getGlyphById(font, SPACE_ID) || getMGlyph(font) || font.chars[0]);
|
|
6202
|
+
//and create a fallback for tab
|
|
6203
|
+
const tabWidth = setting.tabSize * space.xadvance;
|
|
6204
|
+
this._fallbackSpaceGlyph = space;
|
|
6205
|
+
this._fallbackTabGlyph = Object.assign(space, {
|
|
6206
|
+
x: 0,
|
|
6207
|
+
y: 0,
|
|
6208
|
+
xadvance: tabWidth,
|
|
6209
|
+
id: TAB_ID,
|
|
6210
|
+
xoffset: 0,
|
|
6211
|
+
yoffset: 0,
|
|
6212
|
+
width: 0,
|
|
6213
|
+
height: 0
|
|
6214
|
+
});
|
|
6215
|
+
}
|
|
6216
|
+
_getGlyph(font, id) {
|
|
6217
|
+
let glyph = getGlyphById(font, id);
|
|
6218
|
+
if (glyph) return glyph;
|
|
6219
|
+
else if (id === TAB_ID) return this._fallbackTabGlyph;
|
|
6220
|
+
else if (id === SPACE_ID) return this._fallbackSpaceGlyph;
|
|
6221
|
+
return null;
|
|
6222
|
+
}
|
|
6223
|
+
_computeMetrics(text, start, end, width, letterSpacing = 0) {
|
|
6224
|
+
let font = this._font;
|
|
6225
|
+
let curPen = 0;
|
|
6226
|
+
let curWidth = 0;
|
|
6227
|
+
let count = 0;
|
|
6228
|
+
let lastGlyph;
|
|
6229
|
+
if (!font.chars || font.chars.length === 0) {
|
|
6230
|
+
return {
|
|
6231
|
+
start: start,
|
|
6232
|
+
end: start,
|
|
6233
|
+
width: 0
|
|
6234
|
+
};
|
|
6235
|
+
}
|
|
6236
|
+
end = Math.min(text.length, end);
|
|
6237
|
+
for(let i = start; i < end; i++){
|
|
6238
|
+
let id = text.charCodeAt(i);
|
|
6239
|
+
let glyph = this._getGlyph(font, id);
|
|
6240
|
+
if (glyph) {
|
|
6241
|
+
//move pen forward
|
|
6242
|
+
glyph.xoffset;
|
|
6243
|
+
let kern = lastGlyph ? getKerning(font, lastGlyph.id, glyph.id) : 0;
|
|
6244
|
+
curPen += kern;
|
|
6245
|
+
let nextPen = curPen + glyph.xadvance + letterSpacing;
|
|
6246
|
+
let nextWidth = curPen + glyph.width;
|
|
6247
|
+
//we've hit our limit; we can't move onto the next glyph
|
|
6248
|
+
if (nextWidth >= width || nextPen >= width) break;
|
|
6249
|
+
//otherwise continue along our line
|
|
6250
|
+
curPen = nextPen;
|
|
6251
|
+
curWidth = nextWidth;
|
|
6252
|
+
lastGlyph = glyph;
|
|
6253
|
+
}
|
|
6254
|
+
count++;
|
|
6255
|
+
}
|
|
6256
|
+
//make sure rightmost edge lines up with rendered glyphs
|
|
6257
|
+
if (lastGlyph) curWidth += lastGlyph.xoffset;
|
|
6258
|
+
return {
|
|
6259
|
+
start: start,
|
|
6260
|
+
end: start + count,
|
|
6261
|
+
width: curWidth
|
|
6262
|
+
};
|
|
6263
|
+
}
|
|
6264
|
+
constructor(){
|
|
6265
|
+
this._width = 0;
|
|
6266
|
+
this._height = 0;
|
|
6267
|
+
this._descender = 0;
|
|
6268
|
+
this._ascender = 0;
|
|
6269
|
+
this._xHeight = 0;
|
|
6270
|
+
this._baseline = 0;
|
|
6271
|
+
this._capHeight = 0;
|
|
6272
|
+
this._lineHeight = 0;
|
|
6273
|
+
this._linesTotal = 0;
|
|
6274
|
+
this._glyphs = [];
|
|
6275
|
+
this._fallbackSpaceGlyph = null;
|
|
6276
|
+
this._fallbackTabGlyph = null;
|
|
6277
|
+
this._font = null;
|
|
6278
|
+
}
|
|
6279
|
+
}
|
|
6280
|
+
|
|
6281
|
+
const itemSize = 2;
|
|
6282
|
+
const box = {
|
|
6283
|
+
min: [
|
|
6284
|
+
0,
|
|
6285
|
+
0
|
|
6286
|
+
],
|
|
6287
|
+
max: [
|
|
6288
|
+
0,
|
|
6289
|
+
0
|
|
6290
|
+
]
|
|
6291
|
+
};
|
|
6292
|
+
function bounds(positions) {
|
|
6293
|
+
const count = positions.length / itemSize;
|
|
6294
|
+
box.min[0] = positions[0];
|
|
6295
|
+
box.min[1] = positions[1];
|
|
6296
|
+
box.max[0] = positions[0];
|
|
6297
|
+
box.max[1] = positions[1];
|
|
6298
|
+
for(let i = 0; i < count; i++){
|
|
6299
|
+
const x = positions[i * itemSize + 0];
|
|
6300
|
+
const y = positions[i * itemSize + 1];
|
|
6301
|
+
box.min[0] = Math.min(x, box.min[0]);
|
|
6302
|
+
box.min[1] = Math.min(y, box.min[1]);
|
|
6303
|
+
box.max[0] = Math.max(x, box.max[0]);
|
|
6304
|
+
box.max[1] = Math.max(y, box.max[1]);
|
|
6305
|
+
}
|
|
6306
|
+
}
|
|
6307
|
+
function computeBox(positions, output) {
|
|
6308
|
+
bounds(positions);
|
|
6309
|
+
output.min.set(box.min[0], box.min[1], 0);
|
|
6310
|
+
output.max.set(box.max[0], box.max[1], 0);
|
|
6311
|
+
}
|
|
6312
|
+
function computeSphere(positions, output) {
|
|
6313
|
+
bounds(positions);
|
|
6314
|
+
const minX = box.min[0];
|
|
6315
|
+
const minY = box.min[1];
|
|
6316
|
+
const maxX = box.max[0];
|
|
6317
|
+
const maxY = box.max[1];
|
|
6318
|
+
const width = maxX - minX;
|
|
6319
|
+
const height = maxY - minY;
|
|
6320
|
+
const length = Math.sqrt(width * width + height * height);
|
|
6321
|
+
output.center.set(minX + width / 2, minY + height / 2, 0);
|
|
6322
|
+
output.radius = length / 2;
|
|
6323
|
+
}
|
|
6324
|
+
|
|
6325
|
+
class BMFontTextGeometry extends THREE.BufferGeometry {
|
|
6326
|
+
update(fontAtlas, text, setting) {
|
|
6327
|
+
this.layout.update(fontAtlas.info, text, setting);
|
|
6328
|
+
const { indice, position, uv } = fontAtlas.build(this.layout, setting);
|
|
6329
|
+
this.setIndex(new THREE.BufferAttribute(indice, 1));
|
|
6330
|
+
this.setAttribute("position", new THREE.BufferAttribute(position, 2));
|
|
6331
|
+
this.setAttribute("uv", new THREE.BufferAttribute(uv, 2));
|
|
6332
|
+
}
|
|
6333
|
+
computeBoundingSphere() {
|
|
6334
|
+
if (this.boundingSphere === null) {
|
|
6335
|
+
this.boundingSphere = new THREE.Sphere();
|
|
6336
|
+
}
|
|
6337
|
+
const positions = this.attributes.position.array;
|
|
6338
|
+
const itemSize = this.attributes.position.itemSize;
|
|
6339
|
+
if (!positions || !itemSize || positions.length < 2) {
|
|
6340
|
+
this.boundingSphere.radius = 0;
|
|
6341
|
+
this.boundingSphere.center.set(0, 0, 0);
|
|
6342
|
+
return;
|
|
6343
|
+
}
|
|
6344
|
+
computeSphere(positions, this.boundingSphere);
|
|
6345
|
+
if (isNaN(this.boundingSphere.radius)) {
|
|
6346
|
+
console.error('THREE.BufferGeometry.computeBoundingSphere(): ' + 'Computed radius is NaN. The ' + '"position" attribute is likely to have NaN values.');
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6349
|
+
computeBoundingBox() {
|
|
6350
|
+
if (this.boundingBox === null) {
|
|
6351
|
+
this.boundingBox = new THREE.Box3();
|
|
6352
|
+
}
|
|
6353
|
+
const bbox = this.boundingBox;
|
|
6354
|
+
const positions = this.attributes.position["array"];
|
|
6355
|
+
const itemSize = this.attributes.position.itemSize;
|
|
6356
|
+
if (!positions || !itemSize || positions.length < 2) {
|
|
6357
|
+
bbox.makeEmpty();
|
|
6358
|
+
return;
|
|
6359
|
+
}
|
|
6360
|
+
computeBox(positions, bbox);
|
|
6361
|
+
}
|
|
6362
|
+
constructor(...args){
|
|
6363
|
+
super(...args), this.layout = new BMFontTextLayout();
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6366
|
+
|
|
6367
|
+
class Label extends Component {
|
|
6368
|
+
get text() {
|
|
6369
|
+
return this._text;
|
|
6370
|
+
}
|
|
6371
|
+
set text(v) {
|
|
6372
|
+
if (this._text !== v) {
|
|
6373
|
+
this._text = v;
|
|
6374
|
+
this.needsUpdate = true;
|
|
6375
|
+
}
|
|
6376
|
+
}
|
|
6377
|
+
get font() {
|
|
6378
|
+
return this._font;
|
|
6379
|
+
}
|
|
6380
|
+
set font(v) {
|
|
6381
|
+
if (this._font !== v) {
|
|
6382
|
+
this._font = v;
|
|
6383
|
+
this.needsUpdate = true;
|
|
6384
|
+
}
|
|
6385
|
+
}
|
|
6386
|
+
get setting() {
|
|
6387
|
+
return this._setting;
|
|
6388
|
+
}
|
|
6389
|
+
set setting(v) {
|
|
6390
|
+
if (JSON.stringify(this._setting) !== JSON.stringify(v)) {
|
|
6391
|
+
this._setting = v;
|
|
6392
|
+
this.needsUpdate = true;
|
|
6393
|
+
}
|
|
6394
|
+
}
|
|
6395
|
+
get layout() {
|
|
6396
|
+
return this.node.geometry.layout;
|
|
6397
|
+
}
|
|
6398
|
+
forceUpdate() {
|
|
6399
|
+
this.node.geometry.update(this.font, this.text, this.setting);
|
|
6400
|
+
}
|
|
6401
|
+
update(dt) {
|
|
6402
|
+
if (this.needsUpdate) {
|
|
6403
|
+
this.needsUpdate = false;
|
|
6404
|
+
this.forceUpdate();
|
|
6405
|
+
}
|
|
6406
|
+
}
|
|
6407
|
+
constructor({ text = "", font, material, ...setting }){
|
|
6408
|
+
super(), this.needsUpdate = false, this._text = "", this._font = null, this._setting = null;
|
|
6409
|
+
this.text = text;
|
|
6410
|
+
this.font = font;
|
|
6411
|
+
this.setting = setting;
|
|
6412
|
+
this.node = new THREE.Mesh(new BMFontTextGeometry(), material || font.material);
|
|
6413
|
+
this.node.geometry.update(this.font, this.text, this.setting);
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
6416
|
+
|
|
6417
|
+
const vert_MSDF = `
|
|
6418
|
+
varying vec2 v_uv;
|
|
6419
|
+
|
|
6420
|
+
void main() {
|
|
6421
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
6422
|
+
v_uv = uv;
|
|
6423
|
+
}
|
|
6424
|
+
`;
|
|
6425
|
+
const frag_MSDF = `
|
|
6426
|
+
uniform sampler2D u_fontTexture;
|
|
6427
|
+
varying vec2 v_uv;
|
|
6428
|
+
|
|
6429
|
+
uniform vec3 u_color;
|
|
6430
|
+
uniform float u_opacity;
|
|
6431
|
+
uniform vec3 u_strokeColor;
|
|
6432
|
+
uniform float u_strokeWidth;
|
|
6433
|
+
uniform vec3 u_shadowColor;
|
|
6434
|
+
uniform float u_shadowBlur;
|
|
6435
|
+
uniform vec2 u_shadowOffset;
|
|
6436
|
+
uniform float u_weight;
|
|
6437
|
+
|
|
6438
|
+
float median(in float r, in float g, in float b) {
|
|
6439
|
+
return max(min(r, g), min(max(r, g), b));
|
|
6440
|
+
}
|
|
6441
|
+
|
|
6442
|
+
float signedDistance(in vec2 uv) {
|
|
6443
|
+
vec4 texel = texture2D(u_fontTexture, uv);
|
|
6444
|
+
return median(texel.r, texel.g, texel.b) - 0.5;
|
|
6445
|
+
}
|
|
6446
|
+
|
|
6447
|
+
void main() {
|
|
6448
|
+
vec4 color = vec4(u_color, 1.);
|
|
6449
|
+
float d = signedDistance(v_uv) + u_weight;
|
|
6450
|
+
float w = fwidth(d);
|
|
6451
|
+
|
|
6452
|
+
vec4 stroke = vec4(u_strokeColor, smoothstep(-w, w, d));
|
|
6453
|
+
color.a *= smoothstep(-w, w, d - u_strokeWidth);
|
|
6454
|
+
color = mix(stroke, color, color.a);
|
|
6455
|
+
|
|
6456
|
+
float sd = signedDistance(v_uv + u_shadowOffset) + u_weight;
|
|
6457
|
+
vec4 shadow = vec4(u_shadowColor, smoothstep(-w - u_shadowBlur, w + u_shadowBlur, sd));
|
|
6458
|
+
color = mix(shadow, color, color.a);
|
|
6459
|
+
|
|
6460
|
+
color.a *= u_opacity;
|
|
6461
|
+
gl_FragColor = color;
|
|
6462
|
+
}
|
|
6463
|
+
`;
|
|
6464
|
+
class BMFontAtlas {
|
|
6465
|
+
build(layout, setting) {
|
|
6466
|
+
const info = this.info;
|
|
6467
|
+
const texWidth = info.common.scaleW;
|
|
6468
|
+
const texHeight = info.common.scaleH;
|
|
6469
|
+
const glyphs = layout.glyphs.filter((glyph)=>glyph.data.width * glyph.data.height > 0);
|
|
6470
|
+
const flipY = setting.flipY !== false;
|
|
6471
|
+
const position = new Float32Array(glyphs.length * 8);
|
|
6472
|
+
const uv = new Float32Array(glyphs.length * 8);
|
|
6473
|
+
const indice = new Uint16Array(glyphs.length * 6);
|
|
6474
|
+
for(let k = 0, i0 = 0, i1 = 0, i2 = 0, i = 0; i < glyphs.length; i++, k += 4){
|
|
6475
|
+
const glyph = glyphs[i];
|
|
6476
|
+
const bitmap = glyph.data;
|
|
6477
|
+
// bottom left position
|
|
6478
|
+
let x = glyph.position[0] + bitmap.xoffset;
|
|
6479
|
+
let y = glyph.position[1] + bitmap.yoffset;
|
|
6480
|
+
// quad size
|
|
6481
|
+
let w = bitmap.width;
|
|
6482
|
+
let h = bitmap.height;
|
|
6483
|
+
// BL
|
|
6484
|
+
position[i0++] = x;
|
|
6485
|
+
position[i0++] = y;
|
|
6486
|
+
// BR
|
|
6487
|
+
position[i0++] = x + w;
|
|
6488
|
+
position[i0++] = y;
|
|
6489
|
+
// TR
|
|
6490
|
+
position[i0++] = x + w;
|
|
6491
|
+
position[i0++] = y + h;
|
|
6492
|
+
// TL
|
|
6493
|
+
position[i0++] = x;
|
|
6494
|
+
position[i0++] = y + h;
|
|
6495
|
+
let bw = bitmap.x + bitmap.width;
|
|
6496
|
+
let bh = bitmap.y + bitmap.height;
|
|
6497
|
+
// top left position
|
|
6498
|
+
let u0 = bitmap.x / texWidth;
|
|
6499
|
+
let v0 = bitmap.y / texHeight;
|
|
6500
|
+
let u1 = bw / texWidth;
|
|
6501
|
+
let v1 = bh / texHeight;
|
|
6502
|
+
if (flipY) {
|
|
6503
|
+
v0 = 1 - v0;
|
|
6504
|
+
v1 = 1 - v1;
|
|
6505
|
+
}
|
|
6506
|
+
// BL
|
|
6507
|
+
uv[i1++] = u0;
|
|
6508
|
+
uv[i1++] = v0;
|
|
6509
|
+
// BR
|
|
6510
|
+
uv[i1++] = u1;
|
|
6511
|
+
uv[i1++] = v0;
|
|
6512
|
+
// TR
|
|
6513
|
+
uv[i1++] = u1;
|
|
6514
|
+
uv[i1++] = v1;
|
|
6515
|
+
// TL
|
|
6516
|
+
uv[i1++] = u0;
|
|
6517
|
+
uv[i1++] = v1;
|
|
6518
|
+
indice[i2++] = k + 0;
|
|
6519
|
+
indice[i2++] = k + 1;
|
|
6520
|
+
indice[i2++] = k + 2;
|
|
6521
|
+
indice[i2++] = k + 0;
|
|
6522
|
+
indice[i2++] = k + 2;
|
|
6523
|
+
indice[i2++] = k + 3;
|
|
6524
|
+
}
|
|
6525
|
+
return {
|
|
6526
|
+
position,
|
|
6527
|
+
uv,
|
|
6528
|
+
indice
|
|
6529
|
+
};
|
|
6530
|
+
}
|
|
6531
|
+
constructor({ info, texture, uniforms, ...props }){
|
|
6532
|
+
this.uniforms = {
|
|
6533
|
+
u_color: {
|
|
6534
|
+
value: new THREE.Color(0xffffff)
|
|
6535
|
+
},
|
|
6536
|
+
u_opacity: {
|
|
6537
|
+
value: 1
|
|
6538
|
+
},
|
|
6539
|
+
u_weight: {
|
|
6540
|
+
value: 0.2
|
|
6541
|
+
},
|
|
6542
|
+
u_strokeColor: {
|
|
6543
|
+
value: new THREE.Color(0xff0000)
|
|
6544
|
+
},
|
|
6545
|
+
u_strokeWidth: {
|
|
6546
|
+
value: 0
|
|
6547
|
+
},
|
|
6548
|
+
u_shadowColor: {
|
|
6549
|
+
value: new THREE.Color(0xff0000)
|
|
6550
|
+
},
|
|
6551
|
+
u_shadowBlur: {
|
|
6552
|
+
value: 0
|
|
6553
|
+
},
|
|
6554
|
+
u_shadowOffset: {
|
|
6555
|
+
value: new THREE.Vector2()
|
|
6556
|
+
},
|
|
6557
|
+
u_fontTexture: {
|
|
6558
|
+
value: null
|
|
6559
|
+
}
|
|
6560
|
+
};
|
|
6561
|
+
this.info = info;
|
|
6562
|
+
this.uniforms.u_fontTexture.value = texture;
|
|
6563
|
+
this.material = new THREE.ShaderMaterial(Object.assign({
|
|
6564
|
+
vertexShader: vert_MSDF,
|
|
6565
|
+
fragmentShader: frag_MSDF,
|
|
6566
|
+
transparent: true,
|
|
6567
|
+
depthWrite: false,
|
|
6568
|
+
blending: THREE.NormalBlending,
|
|
6569
|
+
uniforms: {
|
|
6570
|
+
...this.uniforms,
|
|
6571
|
+
...uniforms
|
|
6572
|
+
}
|
|
6573
|
+
}, props));
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
|
|
5889
6577
|
exports.AccumulativeShadows = AccumulativeShadows;
|
|
5890
6578
|
exports.Animation = Animation;
|
|
5891
6579
|
exports.AnimationCurve = AnimationCurve;
|
|
5892
6580
|
exports.BINLoader = BINLoader;
|
|
6581
|
+
exports.BMFontAtlas = BMFontAtlas;
|
|
6582
|
+
exports.BMFontTextGeometry = BMFontTextGeometry;
|
|
6583
|
+
exports.BMFontTextLayout = BMFontTextLayout;
|
|
5893
6584
|
exports.Box = Box;
|
|
5894
6585
|
exports.BoxProjection = BoxProjection;
|
|
5895
6586
|
exports.Center = Center;
|
|
@@ -5910,6 +6601,7 @@ exports.GLTFLoader = GLTFLoader;
|
|
|
5910
6601
|
exports.HDRLoader = HDRLoader;
|
|
5911
6602
|
exports.JSONLoader = JSONLoader;
|
|
5912
6603
|
exports.KTX2Loader = KTX2Loader;
|
|
6604
|
+
exports.Label = Label;
|
|
5913
6605
|
exports.Loader = Loader;
|
|
5914
6606
|
exports.Logger = Logger;
|
|
5915
6607
|
exports.ObjectInstance = ObjectInstance;
|