@lingbi/studio 0.3.2 → 0.3.3
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/Application.d.ts +3 -0
- package/ModelResourceListSource.d.ts +3 -0
- package/ModelResourceSceneSource.d.ts +5 -0
- package/ObjImportResult.d.ts +7 -0
- package/index.d.ts +4 -1
- package/index.js +1223 -128
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -5,6 +5,10 @@ var ObjImportFailureCode$1 = /* @__PURE__ */ ((ObjImportFailureCode2) => {
|
|
|
5
5
|
ObjImportFailureCode2["RenderFailed"] = "render-failed";
|
|
6
6
|
return ObjImportFailureCode2;
|
|
7
7
|
})(ObjImportFailureCode$1 || {});
|
|
8
|
+
var ObjImportWarningCode$1 = /* @__PURE__ */ ((ObjImportWarningCode2) => {
|
|
9
|
+
ObjImportWarningCode2["IncompleteMaterial"] = "incomplete-material";
|
|
10
|
+
return ObjImportWarningCode2;
|
|
11
|
+
})(ObjImportWarningCode$1 || {});
|
|
8
12
|
const REVISION = "185";
|
|
9
13
|
const CullFaceNone = 0;
|
|
10
14
|
const CullFaceBack = 1;
|
|
@@ -7778,8 +7782,8 @@ class Color {
|
|
|
7778
7782
|
* @return {number} The hexadecimal value.
|
|
7779
7783
|
*/
|
|
7780
7784
|
getHex(colorSpace = SRGBColorSpace) {
|
|
7781
|
-
ColorManagement.workingToColorSpace(_color$
|
|
7782
|
-
return Math.round(clamp(_color$
|
|
7785
|
+
ColorManagement.workingToColorSpace(_color$2.copy(this), colorSpace);
|
|
7786
|
+
return Math.round(clamp(_color$2.r * 255, 0, 255)) * 65536 + Math.round(clamp(_color$2.g * 255, 0, 255)) * 256 + Math.round(clamp(_color$2.b * 255, 0, 255));
|
|
7783
7787
|
}
|
|
7784
7788
|
/**
|
|
7785
7789
|
* Returns the hexadecimal value of this color as a string (for example, 'FFFFFF').
|
|
@@ -7799,8 +7803,8 @@ class Color {
|
|
|
7799
7803
|
* @return {{h:number,s:number,l:number}} The HSL representation of this color.
|
|
7800
7804
|
*/
|
|
7801
7805
|
getHSL(target, colorSpace = ColorManagement.workingColorSpace) {
|
|
7802
|
-
ColorManagement.workingToColorSpace(_color$
|
|
7803
|
-
const r = _color$
|
|
7806
|
+
ColorManagement.workingToColorSpace(_color$2.copy(this), colorSpace);
|
|
7807
|
+
const r = _color$2.r, g = _color$2.g, b = _color$2.b;
|
|
7804
7808
|
const max = Math.max(r, g, b);
|
|
7805
7809
|
const min = Math.min(r, g, b);
|
|
7806
7810
|
let hue, saturation;
|
|
@@ -7837,10 +7841,10 @@ class Color {
|
|
|
7837
7841
|
* @return {Color} The RGB representation of this color.
|
|
7838
7842
|
*/
|
|
7839
7843
|
getRGB(target, colorSpace = ColorManagement.workingColorSpace) {
|
|
7840
|
-
ColorManagement.workingToColorSpace(_color$
|
|
7841
|
-
target.r = _color$
|
|
7842
|
-
target.g = _color$
|
|
7843
|
-
target.b = _color$
|
|
7844
|
+
ColorManagement.workingToColorSpace(_color$2.copy(this), colorSpace);
|
|
7845
|
+
target.r = _color$2.r;
|
|
7846
|
+
target.g = _color$2.g;
|
|
7847
|
+
target.b = _color$2.b;
|
|
7844
7848
|
return target;
|
|
7845
7849
|
}
|
|
7846
7850
|
/**
|
|
@@ -7850,8 +7854,8 @@ class Color {
|
|
|
7850
7854
|
* @return {string} The CSS representation of this color.
|
|
7851
7855
|
*/
|
|
7852
7856
|
getStyle(colorSpace = SRGBColorSpace) {
|
|
7853
|
-
ColorManagement.workingToColorSpace(_color$
|
|
7854
|
-
const r = _color$
|
|
7857
|
+
ColorManagement.workingToColorSpace(_color$2.copy(this), colorSpace);
|
|
7858
|
+
const r = _color$2.r, g = _color$2.g, b = _color$2.b;
|
|
7855
7859
|
if (colorSpace !== SRGBColorSpace) {
|
|
7856
7860
|
return `color(${colorSpace} ${r.toFixed(3)} ${g.toFixed(3)} ${b.toFixed(3)})`;
|
|
7857
7861
|
}
|
|
@@ -8085,7 +8089,7 @@ class Color {
|
|
|
8085
8089
|
yield this.b;
|
|
8086
8090
|
}
|
|
8087
8091
|
}
|
|
8088
|
-
const _color$
|
|
8092
|
+
const _color$2 = /* @__PURE__ */ new Color();
|
|
8089
8093
|
Color.NAMES = _colorKeywords;
|
|
8090
8094
|
class Scene extends Object3D {
|
|
8091
8095
|
/**
|
|
@@ -9468,6 +9472,42 @@ class BufferAttribute extends EventDispatcher {
|
|
|
9468
9472
|
this.dispatchEvent({ type: "dispose" });
|
|
9469
9473
|
}
|
|
9470
9474
|
}
|
|
9475
|
+
class Int8BufferAttribute extends BufferAttribute {
|
|
9476
|
+
/**
|
|
9477
|
+
* Constructs a new buffer attribute.
|
|
9478
|
+
*
|
|
9479
|
+
* @param {(Array<number>|Int8Array)} array - The array holding the attribute data.
|
|
9480
|
+
* @param {number} itemSize - The item size.
|
|
9481
|
+
* @param {boolean} [normalized=false] - Whether the data are normalized or not.
|
|
9482
|
+
*/
|
|
9483
|
+
constructor(array, itemSize, normalized) {
|
|
9484
|
+
super(new Int8Array(array), itemSize, normalized);
|
|
9485
|
+
}
|
|
9486
|
+
}
|
|
9487
|
+
class Uint8BufferAttribute extends BufferAttribute {
|
|
9488
|
+
/**
|
|
9489
|
+
* Constructs a new buffer attribute.
|
|
9490
|
+
*
|
|
9491
|
+
* @param {(Array<number>|Uint8Array)} array - The array holding the attribute data.
|
|
9492
|
+
* @param {number} itemSize - The item size.
|
|
9493
|
+
* @param {boolean} [normalized=false] - Whether the data are normalized or not.
|
|
9494
|
+
*/
|
|
9495
|
+
constructor(array, itemSize, normalized) {
|
|
9496
|
+
super(new Uint8Array(array), itemSize, normalized);
|
|
9497
|
+
}
|
|
9498
|
+
}
|
|
9499
|
+
class Int16BufferAttribute extends BufferAttribute {
|
|
9500
|
+
/**
|
|
9501
|
+
* Constructs a new buffer attribute.
|
|
9502
|
+
*
|
|
9503
|
+
* @param {(Array<number>|Int16Array)} array - The array holding the attribute data.
|
|
9504
|
+
* @param {number} itemSize - The item size.
|
|
9505
|
+
* @param {boolean} [normalized=false] - Whether the data are normalized or not.
|
|
9506
|
+
*/
|
|
9507
|
+
constructor(array, itemSize, normalized) {
|
|
9508
|
+
super(new Int16Array(array), itemSize, normalized);
|
|
9509
|
+
}
|
|
9510
|
+
}
|
|
9471
9511
|
class Uint16BufferAttribute extends BufferAttribute {
|
|
9472
9512
|
/**
|
|
9473
9513
|
* Constructs a new buffer attribute.
|
|
@@ -9480,6 +9520,18 @@ class Uint16BufferAttribute extends BufferAttribute {
|
|
|
9480
9520
|
super(new Uint16Array(array), itemSize, normalized);
|
|
9481
9521
|
}
|
|
9482
9522
|
}
|
|
9523
|
+
class Int32BufferAttribute extends BufferAttribute {
|
|
9524
|
+
/**
|
|
9525
|
+
* Constructs a new buffer attribute.
|
|
9526
|
+
*
|
|
9527
|
+
* @param {(Array<number>|Int32Array)} array - The array holding the attribute data.
|
|
9528
|
+
* @param {number} itemSize - The item size.
|
|
9529
|
+
* @param {boolean} [normalized=false] - Whether the data are normalized or not.
|
|
9530
|
+
*/
|
|
9531
|
+
constructor(array, itemSize, normalized) {
|
|
9532
|
+
super(new Int32Array(array), itemSize, normalized);
|
|
9533
|
+
}
|
|
9534
|
+
}
|
|
9483
9535
|
class Uint32BufferAttribute extends BufferAttribute {
|
|
9484
9536
|
/**
|
|
9485
9537
|
* Constructs a new buffer attribute.
|
|
@@ -29535,6 +29587,179 @@ class CanvasController {
|
|
|
29535
29587
|
}
|
|
29536
29588
|
}
|
|
29537
29589
|
}
|
|
29590
|
+
class ObjResourceList {
|
|
29591
|
+
mtlUrl;
|
|
29592
|
+
objUrl;
|
|
29593
|
+
mtlFileName;
|
|
29594
|
+
textureUrls = /* @__PURE__ */ new Set();
|
|
29595
|
+
textureUrlsByFileName = /* @__PURE__ */ new Map();
|
|
29596
|
+
constructor(fileUrls) {
|
|
29597
|
+
let mtlFileName;
|
|
29598
|
+
let mtlUrl;
|
|
29599
|
+
let objUrl;
|
|
29600
|
+
const seenFileNames = /* @__PURE__ */ new Set();
|
|
29601
|
+
const seenUrls = /* @__PURE__ */ new Set();
|
|
29602
|
+
for (const fileUrl of fileUrls) {
|
|
29603
|
+
const resource = this.createResourceEntry(fileUrl);
|
|
29604
|
+
if (seenUrls.has(resource.url) || seenFileNames.has(resource.fileName)) {
|
|
29605
|
+
throw new Error("The OBJ resource list contains a duplicate resource.");
|
|
29606
|
+
}
|
|
29607
|
+
seenUrls.add(resource.url);
|
|
29608
|
+
seenFileNames.add(resource.fileName);
|
|
29609
|
+
if (this.isObjUrl(resource.url)) {
|
|
29610
|
+
if (objUrl !== void 0) {
|
|
29611
|
+
throw new Error("The OBJ resource list must contain exactly one OBJ file.");
|
|
29612
|
+
}
|
|
29613
|
+
objUrl = resource.url;
|
|
29614
|
+
continue;
|
|
29615
|
+
}
|
|
29616
|
+
if (this.isMtlUrl(resource.url)) {
|
|
29617
|
+
if (mtlUrl !== void 0) {
|
|
29618
|
+
throw new Error("The OBJ resource list cannot contain multiple MTL files.");
|
|
29619
|
+
}
|
|
29620
|
+
mtlFileName = resource.fileName;
|
|
29621
|
+
mtlUrl = resource.url;
|
|
29622
|
+
continue;
|
|
29623
|
+
}
|
|
29624
|
+
this.textureUrls.add(resource.url);
|
|
29625
|
+
this.textureUrlsByFileName.set(resource.fileName, resource.url);
|
|
29626
|
+
}
|
|
29627
|
+
if (objUrl === void 0) {
|
|
29628
|
+
throw new Error("The OBJ resource list must contain an OBJ file.");
|
|
29629
|
+
}
|
|
29630
|
+
this.mtlFileName = mtlFileName;
|
|
29631
|
+
this.mtlUrl = mtlUrl;
|
|
29632
|
+
this.objUrl = objUrl;
|
|
29633
|
+
}
|
|
29634
|
+
matchesMaterialLibraries(materialReferences) {
|
|
29635
|
+
if (materialReferences.length === 0) {
|
|
29636
|
+
return true;
|
|
29637
|
+
}
|
|
29638
|
+
const mtlUrl = this.mtlUrl;
|
|
29639
|
+
const mtlFileName = this.mtlFileName;
|
|
29640
|
+
const [materialReference, ...remainingReferences] = materialReferences;
|
|
29641
|
+
if (materialReference === void 0 || remainingReferences.length > 0 || mtlUrl === void 0 || mtlFileName === void 0) {
|
|
29642
|
+
return false;
|
|
29643
|
+
}
|
|
29644
|
+
const referenceUrl = new URL(materialReference, this.objUrl).href;
|
|
29645
|
+
if (referenceUrl === mtlUrl || this.getFileName(new URL(referenceUrl)) === mtlFileName) {
|
|
29646
|
+
return true;
|
|
29647
|
+
}
|
|
29648
|
+
return false;
|
|
29649
|
+
}
|
|
29650
|
+
resolveTextureUrl(materialBaseUrl, textureUrl) {
|
|
29651
|
+
const resolvedUrl = new URL(textureUrl, materialBaseUrl).href;
|
|
29652
|
+
if (this.textureUrls.has(resolvedUrl)) {
|
|
29653
|
+
return resolvedUrl;
|
|
29654
|
+
}
|
|
29655
|
+
const mappedUrl = this.textureUrlsByFileName.get(this.getFileName(new URL(resolvedUrl)));
|
|
29656
|
+
if (mappedUrl === void 0) {
|
|
29657
|
+
throw new Error("The MTL texture is not present in the resource list.");
|
|
29658
|
+
}
|
|
29659
|
+
return mappedUrl;
|
|
29660
|
+
}
|
|
29661
|
+
createResourceEntry(fileUrl) {
|
|
29662
|
+
const url = new URL(fileUrl);
|
|
29663
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
29664
|
+
throw new Error("The OBJ resource list only accepts HTTP URLs.");
|
|
29665
|
+
}
|
|
29666
|
+
return {
|
|
29667
|
+
fileName: this.getFileName(url),
|
|
29668
|
+
url: url.href
|
|
29669
|
+
};
|
|
29670
|
+
}
|
|
29671
|
+
getFileName(url) {
|
|
29672
|
+
const fileName = decodeURIComponent(url.pathname.slice(url.pathname.lastIndexOf("/") + 1));
|
|
29673
|
+
if (fileName.length === 0) {
|
|
29674
|
+
throw new Error("The OBJ resource URL must include a file name.");
|
|
29675
|
+
}
|
|
29676
|
+
return fileName;
|
|
29677
|
+
}
|
|
29678
|
+
isMtlUrl(url) {
|
|
29679
|
+
return new URL(url).pathname.toLowerCase().endsWith(".mtl");
|
|
29680
|
+
}
|
|
29681
|
+
isObjUrl(url) {
|
|
29682
|
+
return new URL(url).pathname.toLowerCase().endsWith(".obj");
|
|
29683
|
+
}
|
|
29684
|
+
}
|
|
29685
|
+
class PlyResourceList {
|
|
29686
|
+
plyUrl;
|
|
29687
|
+
resourceUrlsByFileName = /* @__PURE__ */ new Map();
|
|
29688
|
+
constructor(fileUrls) {
|
|
29689
|
+
let plyUrl;
|
|
29690
|
+
const seenFileNames = /* @__PURE__ */ new Set();
|
|
29691
|
+
const seenUrls = /* @__PURE__ */ new Set();
|
|
29692
|
+
for (const fileUrl of fileUrls) {
|
|
29693
|
+
const resource = this.createResourceEntry(fileUrl);
|
|
29694
|
+
if (seenUrls.has(resource.url) || seenFileNames.has(resource.fileName)) {
|
|
29695
|
+
throw new Error("The PLY resource list contains a duplicate resource.");
|
|
29696
|
+
}
|
|
29697
|
+
seenUrls.add(resource.url);
|
|
29698
|
+
seenFileNames.add(resource.fileName);
|
|
29699
|
+
this.resourceUrlsByFileName.set(resource.fileName, resource.url);
|
|
29700
|
+
if (this.isPlyUrl(resource.url)) {
|
|
29701
|
+
if (plyUrl !== void 0) {
|
|
29702
|
+
throw new Error("The PLY resource list must contain exactly one PLY file.");
|
|
29703
|
+
}
|
|
29704
|
+
plyUrl = resource.url;
|
|
29705
|
+
}
|
|
29706
|
+
}
|
|
29707
|
+
if (plyUrl === void 0) {
|
|
29708
|
+
throw new Error("The PLY resource list must contain a PLY file.");
|
|
29709
|
+
}
|
|
29710
|
+
this.plyUrl = plyUrl;
|
|
29711
|
+
}
|
|
29712
|
+
resolveTextureUrl(reference) {
|
|
29713
|
+
const normalizedReference = reference.replaceAll("\\", "/");
|
|
29714
|
+
const resolvedUrl = new URL(normalizedReference, this.plyUrl);
|
|
29715
|
+
const mappedUrl = this.resourceUrlsByFileName.get(this.getFileName(resolvedUrl));
|
|
29716
|
+
return mappedUrl ?? resolvedUrl.href;
|
|
29717
|
+
}
|
|
29718
|
+
createResourceEntry(fileUrl) {
|
|
29719
|
+
const url = new URL(fileUrl);
|
|
29720
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
29721
|
+
throw new Error("The PLY resource list only accepts HTTP URLs.");
|
|
29722
|
+
}
|
|
29723
|
+
return {
|
|
29724
|
+
fileName: this.getFileName(url),
|
|
29725
|
+
url: url.href
|
|
29726
|
+
};
|
|
29727
|
+
}
|
|
29728
|
+
getFileName(url) {
|
|
29729
|
+
const fileName = decodeURIComponent(url.pathname.slice(url.pathname.lastIndexOf("/") + 1));
|
|
29730
|
+
if (fileName.length === 0) {
|
|
29731
|
+
throw new Error("The PLY resource URL must include a file name.");
|
|
29732
|
+
}
|
|
29733
|
+
return fileName;
|
|
29734
|
+
}
|
|
29735
|
+
isPlyUrl(url) {
|
|
29736
|
+
return new URL(url).pathname.toLowerCase().endsWith(".ply");
|
|
29737
|
+
}
|
|
29738
|
+
}
|
|
29739
|
+
class ModelResourceList {
|
|
29740
|
+
resources;
|
|
29741
|
+
constructor(fileUrls) {
|
|
29742
|
+
let modelFileCount = 0;
|
|
29743
|
+
let modelFormat;
|
|
29744
|
+
for (const fileUrl of fileUrls) {
|
|
29745
|
+
const path = new URL(fileUrl).pathname.toLowerCase();
|
|
29746
|
+
if (path.endsWith(".obj")) {
|
|
29747
|
+
modelFileCount += 1;
|
|
29748
|
+
modelFormat = "obj";
|
|
29749
|
+
} else if (path.endsWith(".ply")) {
|
|
29750
|
+
modelFileCount += 1;
|
|
29751
|
+
modelFormat = "ply";
|
|
29752
|
+
}
|
|
29753
|
+
}
|
|
29754
|
+
if (modelFileCount !== 1 || modelFormat === void 0) {
|
|
29755
|
+
throw new Error("A model resource list must contain exactly one OBJ or PLY file.");
|
|
29756
|
+
}
|
|
29757
|
+
this.resources = modelFormat === "obj" ? new ObjResourceList(fileUrls) : new PlyResourceList(fileUrls);
|
|
29758
|
+
}
|
|
29759
|
+
isObj() {
|
|
29760
|
+
return this.resources instanceof ObjResourceList;
|
|
29761
|
+
}
|
|
29762
|
+
}
|
|
29538
29763
|
class MTLLoader extends Loader {
|
|
29539
29764
|
constructor(manager) {
|
|
29540
29765
|
super(manager);
|
|
@@ -29840,7 +30065,7 @@ const _vB = new Vector3();
|
|
|
29840
30065
|
const _vC = new Vector3();
|
|
29841
30066
|
const _ab = new Vector3();
|
|
29842
30067
|
const _cb = new Vector3();
|
|
29843
|
-
const _color = new Color();
|
|
30068
|
+
const _color$1 = new Color();
|
|
29844
30069
|
function ParserState() {
|
|
29845
30070
|
const state = {
|
|
29846
30071
|
objects: [],
|
|
@@ -30151,13 +30376,13 @@ class OBJLoader extends Loader {
|
|
|
30151
30376
|
parseFloat(data[3])
|
|
30152
30377
|
);
|
|
30153
30378
|
if (data.length >= 7) {
|
|
30154
|
-
_color.setRGB(
|
|
30379
|
+
_color$1.setRGB(
|
|
30155
30380
|
parseFloat(data[4]),
|
|
30156
30381
|
parseFloat(data[5]),
|
|
30157
30382
|
parseFloat(data[6]),
|
|
30158
30383
|
SRGBColorSpace
|
|
30159
30384
|
);
|
|
30160
|
-
state.colors.push(_color.r, _color.g, _color.b);
|
|
30385
|
+
state.colors.push(_color$1.r, _color$1.g, _color$1.b);
|
|
30161
30386
|
} else {
|
|
30162
30387
|
state.colors.push(void 0, void 0, void 0);
|
|
30163
30388
|
}
|
|
@@ -30464,8 +30689,8 @@ class Model {
|
|
|
30464
30689
|
return Array.isArray(values);
|
|
30465
30690
|
}
|
|
30466
30691
|
}
|
|
30467
|
-
const DEFAULT_MODEL_COLOR = 10265519;
|
|
30468
|
-
const DEFAULT_POINT_SIZE = 3;
|
|
30692
|
+
const DEFAULT_MODEL_COLOR$1 = 10265519;
|
|
30693
|
+
const DEFAULT_POINT_SIZE$1 = 3;
|
|
30469
30694
|
class TextureLoadMonitor {
|
|
30470
30695
|
completionResolver;
|
|
30471
30696
|
completionPromise;
|
|
@@ -30573,24 +30798,33 @@ class ObjLoader {
|
|
|
30573
30798
|
}
|
|
30574
30799
|
let materialContext;
|
|
30575
30800
|
let model;
|
|
30801
|
+
let warnings = [];
|
|
30576
30802
|
try {
|
|
30577
30803
|
const objSource = await this.loadText(source.objUrl, signal);
|
|
30578
30804
|
this.assertNotCancelled(signal);
|
|
30579
30805
|
const materialReferences = this.getMaterialLibraryReferences(objSource);
|
|
30580
|
-
resources
|
|
30581
|
-
|
|
30806
|
+
const hasMatchingMaterialLibrary = resources === void 0 || resources.matchesMaterialLibraries(materialReferences);
|
|
30807
|
+
if (materialReferences.length > 0 && !hasMatchingMaterialLibrary) {
|
|
30808
|
+
warnings = [this.createIncompleteMaterialWarning()];
|
|
30809
|
+
}
|
|
30810
|
+
const materialUrl = resources === void 0 ? this.getMaterialUrl(source, materialReferences) : hasMatchingMaterialLibrary ? resources.mtlUrl : void 0;
|
|
30582
30811
|
if (materialUrl !== void 0) {
|
|
30583
|
-
|
|
30584
|
-
|
|
30585
|
-
|
|
30586
|
-
|
|
30587
|
-
|
|
30588
|
-
|
|
30812
|
+
try {
|
|
30813
|
+
materialContext = await this.loadMaterialContext(
|
|
30814
|
+
materialUrl,
|
|
30815
|
+
source.textureUrls,
|
|
30816
|
+
signal,
|
|
30817
|
+
resources
|
|
30818
|
+
);
|
|
30819
|
+
} catch {
|
|
30820
|
+
this.assertNotCancelled(signal);
|
|
30821
|
+
warnings = [this.createIncompleteMaterialWarning()];
|
|
30822
|
+
}
|
|
30589
30823
|
}
|
|
30590
30824
|
this.assertNotCancelled(signal);
|
|
30591
|
-
|
|
30592
|
-
|
|
30593
|
-
|
|
30825
|
+
let group = this.parseObj(objSource, materialContext?.creator);
|
|
30826
|
+
let additionalMaterials = this.getMaterialArray(materialContext);
|
|
30827
|
+
let additionalTextures = this.getTextureArray(materialContext);
|
|
30594
30828
|
model = new Model(group, additionalMaterials, additionalTextures);
|
|
30595
30829
|
if (!this.hasRenderablePrimitive(group) || !model.hasFiniteBounds()) {
|
|
30596
30830
|
model.dispose();
|
|
@@ -30599,22 +30833,37 @@ class ObjLoader {
|
|
|
30599
30833
|
success: false
|
|
30600
30834
|
};
|
|
30601
30835
|
}
|
|
30602
|
-
if (materialContext
|
|
30603
|
-
this.normalizeMaterials(group);
|
|
30604
|
-
} else {
|
|
30836
|
+
if (materialContext !== void 0) {
|
|
30605
30837
|
const textureLoadOutcome = await materialContext.monitor.wait(signal);
|
|
30606
|
-
if (textureLoadOutcome
|
|
30838
|
+
if (textureLoadOutcome === "cancelled") {
|
|
30839
|
+
this.assertNotCancelled(signal);
|
|
30840
|
+
}
|
|
30841
|
+
if (textureLoadOutcome === "failed") {
|
|
30607
30842
|
model.dispose();
|
|
30608
|
-
|
|
30609
|
-
|
|
30610
|
-
|
|
30611
|
-
|
|
30843
|
+
model = void 0;
|
|
30844
|
+
materialContext = void 0;
|
|
30845
|
+
warnings = [this.createIncompleteMaterialWarning()];
|
|
30846
|
+
group = this.parseObj(objSource, void 0);
|
|
30847
|
+
additionalMaterials = [];
|
|
30848
|
+
additionalTextures = [];
|
|
30849
|
+
model = new Model(group, additionalMaterials, additionalTextures);
|
|
30850
|
+
if (!this.hasRenderablePrimitive(group) || !model.hasFiniteBounds()) {
|
|
30851
|
+
model.dispose();
|
|
30852
|
+
return {
|
|
30853
|
+
code: ObjImportFailureCode$1.InvalidSource,
|
|
30854
|
+
success: false
|
|
30855
|
+
};
|
|
30856
|
+
}
|
|
30612
30857
|
}
|
|
30613
30858
|
}
|
|
30859
|
+
if (materialContext === void 0) {
|
|
30860
|
+
this.normalizeMaterials(group);
|
|
30861
|
+
}
|
|
30614
30862
|
this.assertNotCancelled(signal);
|
|
30615
30863
|
return {
|
|
30616
30864
|
model,
|
|
30617
|
-
success: true
|
|
30865
|
+
success: true,
|
|
30866
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
30618
30867
|
};
|
|
30619
30868
|
} catch {
|
|
30620
30869
|
this.disposeFailedModel(model);
|
|
@@ -30704,9 +30953,6 @@ class ObjLoader {
|
|
|
30704
30953
|
}
|
|
30705
30954
|
return objectTree;
|
|
30706
30955
|
}
|
|
30707
|
-
getTextureFailureCode(outcome) {
|
|
30708
|
-
return outcome === "cancelled" ? ObjImportFailureCode$1.Cancelled : ObjImportFailureCode$1.InvalidSource;
|
|
30709
|
-
}
|
|
30710
30956
|
getMaterialLibraryReferences(objSource) {
|
|
30711
30957
|
const materialReferences = [];
|
|
30712
30958
|
for (const line of objSource.split(/\r?\n/u)) {
|
|
@@ -30717,6 +30963,11 @@ class ObjLoader {
|
|
|
30717
30963
|
}
|
|
30718
30964
|
return materialReferences;
|
|
30719
30965
|
}
|
|
30966
|
+
createIncompleteMaterialWarning() {
|
|
30967
|
+
return {
|
|
30968
|
+
code: ObjImportWarningCode$1.IncompleteMaterial
|
|
30969
|
+
};
|
|
30970
|
+
}
|
|
30720
30971
|
getMaterialTextureReferences(materialSource, creator) {
|
|
30721
30972
|
const textureReferences = [];
|
|
30722
30973
|
for (const line of materialSource.split(/\r?\n/u)) {
|
|
@@ -30776,14 +31027,14 @@ class ObjLoader {
|
|
|
30776
31027
|
side: DoubleSide
|
|
30777
31028
|
});
|
|
30778
31029
|
const creator = materialLoader.parse(materialSource, materialBaseUrl);
|
|
30779
|
-
const pbrMaterialReferences = this.parsePbrMaterialReferences(materialSource);
|
|
30780
|
-
if (resources !== void 0) {
|
|
30781
|
-
this.assertMaterialTextures(resources, materialSource, materialBaseUrl, creator);
|
|
30782
|
-
}
|
|
30783
|
-
this.validateTextureOverrides(textureUrls);
|
|
30784
|
-
this.removeLegacyPbrTextureMappings(creator);
|
|
30785
31030
|
const monitor = new TextureLoadMonitor(manager, creator);
|
|
30786
31031
|
try {
|
|
31032
|
+
const pbrMaterialReferences = this.parsePbrMaterialReferences(materialSource);
|
|
31033
|
+
if (resources !== void 0) {
|
|
31034
|
+
this.assertMaterialTextures(resources, materialSource, materialBaseUrl, creator);
|
|
31035
|
+
}
|
|
31036
|
+
this.validateTextureOverrides(textureUrls);
|
|
31037
|
+
this.removeLegacyPbrTextureMappings(creator);
|
|
30787
31038
|
creator.preload();
|
|
30788
31039
|
this.replaceMaterialsWithPbr(creator, pbrMaterialReferences, materialBaseUrl);
|
|
30789
31040
|
monitor.finishScheduling();
|
|
@@ -30817,21 +31068,21 @@ class ObjLoader {
|
|
|
30817
31068
|
for (const object of this.getObjectTree(group)) {
|
|
30818
31069
|
if (this.isMesh(object)) {
|
|
30819
31070
|
meshMaterial ??= new MeshBasicMaterial({
|
|
30820
|
-
color: DEFAULT_MODEL_COLOR,
|
|
31071
|
+
color: DEFAULT_MODEL_COLOR$1,
|
|
30821
31072
|
side: DoubleSide
|
|
30822
31073
|
});
|
|
30823
31074
|
this.collectMaterials(object.material, materialsToDispose);
|
|
30824
31075
|
object.material = meshMaterial;
|
|
30825
31076
|
} else if (this.isLine(object)) {
|
|
30826
31077
|
lineMaterial ??= new LineBasicMaterial({
|
|
30827
|
-
color: DEFAULT_MODEL_COLOR
|
|
31078
|
+
color: DEFAULT_MODEL_COLOR$1
|
|
30828
31079
|
});
|
|
30829
31080
|
this.collectMaterials(object.material, materialsToDispose);
|
|
30830
31081
|
object.material = lineMaterial;
|
|
30831
31082
|
} else if (this.isPoints(object)) {
|
|
30832
31083
|
pointMaterial ??= new PointsMaterial({
|
|
30833
|
-
color: DEFAULT_MODEL_COLOR,
|
|
30834
|
-
size: DEFAULT_POINT_SIZE,
|
|
31084
|
+
color: DEFAULT_MODEL_COLOR$1,
|
|
31085
|
+
size: DEFAULT_POINT_SIZE$1,
|
|
30835
31086
|
sizeAttenuation: false
|
|
30836
31087
|
});
|
|
30837
31088
|
this.collectMaterials(object.material, materialsToDispose);
|
|
@@ -31019,99 +31270,868 @@ class ObjLoader {
|
|
|
31019
31270
|
}
|
|
31020
31271
|
}
|
|
31021
31272
|
}
|
|
31022
|
-
|
|
31023
|
-
|
|
31024
|
-
|
|
31025
|
-
|
|
31026
|
-
|
|
31027
|
-
|
|
31028
|
-
|
|
31029
|
-
|
|
31030
|
-
|
|
31031
|
-
|
|
31032
|
-
|
|
31033
|
-
|
|
31034
|
-
|
|
31035
|
-
|
|
31036
|
-
|
|
31037
|
-
|
|
31038
|
-
|
|
31039
|
-
|
|
31040
|
-
|
|
31041
|
-
|
|
31042
|
-
|
|
31043
|
-
|
|
31044
|
-
|
|
31045
|
-
|
|
31046
|
-
|
|
31047
|
-
|
|
31048
|
-
|
|
31049
|
-
|
|
31050
|
-
|
|
31273
|
+
const _color = new Color();
|
|
31274
|
+
class PLYLoader extends Loader {
|
|
31275
|
+
/**
|
|
31276
|
+
* Constructs a new PLY loader.
|
|
31277
|
+
*
|
|
31278
|
+
* @param {LoadingManager} [manager] - The loading manager.
|
|
31279
|
+
*/
|
|
31280
|
+
constructor(manager) {
|
|
31281
|
+
super(manager);
|
|
31282
|
+
this.propertyNameMapping = {};
|
|
31283
|
+
this.customPropertyMapping = {};
|
|
31284
|
+
}
|
|
31285
|
+
/**
|
|
31286
|
+
* Starts loading from the given URL and passes the loaded PLY asset
|
|
31287
|
+
* to the `onLoad()` callback.
|
|
31288
|
+
*
|
|
31289
|
+
* @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
|
|
31290
|
+
* @param {function(BufferGeometry)} onLoad - Executed when the loading process has been finished.
|
|
31291
|
+
* @param {onProgressCallback} onProgress - Executed while the loading is in progress.
|
|
31292
|
+
* @param {onErrorCallback} onError - Executed when errors occur.
|
|
31293
|
+
*/
|
|
31294
|
+
load(url, onLoad, onProgress, onError) {
|
|
31295
|
+
const scope = this;
|
|
31296
|
+
const loader = new FileLoader(this.manager);
|
|
31297
|
+
loader.setPath(this.path);
|
|
31298
|
+
loader.setResponseType("arraybuffer");
|
|
31299
|
+
loader.setRequestHeader(this.requestHeader);
|
|
31300
|
+
loader.setWithCredentials(this.withCredentials);
|
|
31301
|
+
loader.load(url, function(text) {
|
|
31302
|
+
try {
|
|
31303
|
+
onLoad(scope.parse(text));
|
|
31304
|
+
} catch (e) {
|
|
31305
|
+
if (onError) {
|
|
31306
|
+
onError(e);
|
|
31307
|
+
} else {
|
|
31308
|
+
console.error(e);
|
|
31051
31309
|
}
|
|
31052
|
-
|
|
31053
|
-
|
|
31054
|
-
|
|
31310
|
+
scope.manager.itemError(url);
|
|
31311
|
+
}
|
|
31312
|
+
}, onProgress, onError);
|
|
31313
|
+
}
|
|
31314
|
+
/**
|
|
31315
|
+
* Sets a property name mapping that maps default property names
|
|
31316
|
+
* to custom ones. For example, the following maps the properties
|
|
31317
|
+
* “diffuse_(red|green|blue)” in the file to standard color names.
|
|
31318
|
+
*
|
|
31319
|
+
* ```js
|
|
31320
|
+
* loader.setPropertyNameMapping( {
|
|
31321
|
+
* diffuse_red: 'red',
|
|
31322
|
+
* diffuse_green: 'green',
|
|
31323
|
+
* diffuse_blue: 'blue'
|
|
31324
|
+
* } );
|
|
31325
|
+
* ```
|
|
31326
|
+
*
|
|
31327
|
+
* @param {Object} mapping - The mapping dictionary.
|
|
31328
|
+
*/
|
|
31329
|
+
setPropertyNameMapping(mapping) {
|
|
31330
|
+
this.propertyNameMapping = mapping;
|
|
31331
|
+
}
|
|
31332
|
+
/**
|
|
31333
|
+
* Custom properties outside of the defaults for position, uv, normal
|
|
31334
|
+
* and color attributes can be added using the setCustomPropertyNameMapping method.
|
|
31335
|
+
* For example, the following maps the element properties “custom_property_a”
|
|
31336
|
+
* and “custom_property_b” to an attribute “customAttribute” with an item size of 2.
|
|
31337
|
+
* Attribute item sizes are set from the number of element properties in the property array.
|
|
31338
|
+
*
|
|
31339
|
+
* ```js
|
|
31340
|
+
* loader.setCustomPropertyNameMapping( {
|
|
31341
|
+
* customAttribute: ['custom_property_a', 'custom_property_b'],
|
|
31342
|
+
* } );
|
|
31343
|
+
* ```
|
|
31344
|
+
* @param {Object} mapping - The mapping dictionary.
|
|
31345
|
+
*/
|
|
31346
|
+
setCustomPropertyNameMapping(mapping) {
|
|
31347
|
+
this.customPropertyMapping = mapping;
|
|
31348
|
+
}
|
|
31349
|
+
/**
|
|
31350
|
+
* Parses the given PLY data and returns the resulting geometry.
|
|
31351
|
+
*
|
|
31352
|
+
* @param {ArrayBuffer} data - The raw PLY data as an array buffer.
|
|
31353
|
+
* @return {BufferGeometry} The parsed geometry.
|
|
31354
|
+
*/
|
|
31355
|
+
parse(data) {
|
|
31356
|
+
function parseHeader(data2, headerLength = 0) {
|
|
31357
|
+
const patternHeader = /^ply([\s\S]*)end_header(\r\n|\r|\n)/;
|
|
31358
|
+
let headerText = "";
|
|
31359
|
+
const result = patternHeader.exec(data2);
|
|
31360
|
+
if (result !== null) {
|
|
31361
|
+
headerText = result[1];
|
|
31362
|
+
}
|
|
31363
|
+
const header = {
|
|
31364
|
+
comments: [],
|
|
31365
|
+
elements: [],
|
|
31366
|
+
headerLength,
|
|
31367
|
+
objInfo: ""
|
|
31368
|
+
};
|
|
31369
|
+
const lines = headerText.split(/\r\n|\r|\n/);
|
|
31370
|
+
let currentElement;
|
|
31371
|
+
function make_ply_element_property(propertyValues, propertyNameMapping) {
|
|
31372
|
+
const property = { type: propertyValues[0] };
|
|
31373
|
+
if (property.type === "list") {
|
|
31374
|
+
property.name = propertyValues[3];
|
|
31375
|
+
property.countType = propertyValues[1];
|
|
31376
|
+
property.itemType = propertyValues[2];
|
|
31377
|
+
} else {
|
|
31378
|
+
property.name = propertyValues[1];
|
|
31379
|
+
}
|
|
31380
|
+
if (property.name in propertyNameMapping) {
|
|
31381
|
+
property.name = propertyNameMapping[property.name];
|
|
31382
|
+
}
|
|
31383
|
+
return property;
|
|
31384
|
+
}
|
|
31385
|
+
for (let i = 0; i < lines.length; i++) {
|
|
31386
|
+
let line = lines[i];
|
|
31387
|
+
line = line.trim();
|
|
31388
|
+
if (line === "") continue;
|
|
31389
|
+
const lineValues = line.split(/\s+/);
|
|
31390
|
+
const lineType = lineValues.shift();
|
|
31391
|
+
line = lineValues.join(" ");
|
|
31392
|
+
switch (lineType) {
|
|
31393
|
+
case "format":
|
|
31394
|
+
header.format = lineValues[0];
|
|
31395
|
+
header.version = lineValues[1];
|
|
31396
|
+
break;
|
|
31397
|
+
case "comment":
|
|
31398
|
+
header.comments.push(line);
|
|
31399
|
+
break;
|
|
31400
|
+
case "element":
|
|
31401
|
+
if (currentElement !== void 0) {
|
|
31402
|
+
header.elements.push(currentElement);
|
|
31403
|
+
}
|
|
31404
|
+
currentElement = {};
|
|
31405
|
+
currentElement.name = lineValues[0];
|
|
31406
|
+
currentElement.count = parseInt(lineValues[1]);
|
|
31407
|
+
currentElement.properties = [];
|
|
31408
|
+
break;
|
|
31409
|
+
case "property":
|
|
31410
|
+
currentElement.properties.push(make_ply_element_property(lineValues, scope.propertyNameMapping));
|
|
31411
|
+
break;
|
|
31412
|
+
case "obj_info":
|
|
31413
|
+
header.objInfo = line;
|
|
31414
|
+
break;
|
|
31415
|
+
default:
|
|
31416
|
+
console.log("unhandled", lineType, lineValues);
|
|
31417
|
+
}
|
|
31418
|
+
}
|
|
31419
|
+
if (currentElement !== void 0) {
|
|
31420
|
+
header.elements.push(currentElement);
|
|
31421
|
+
}
|
|
31422
|
+
return header;
|
|
31423
|
+
}
|
|
31424
|
+
function parseASCIINumber(n, type) {
|
|
31425
|
+
switch (type) {
|
|
31426
|
+
case "char":
|
|
31427
|
+
case "uchar":
|
|
31428
|
+
case "short":
|
|
31429
|
+
case "ushort":
|
|
31430
|
+
case "int":
|
|
31431
|
+
case "uint":
|
|
31432
|
+
case "int8":
|
|
31433
|
+
case "uint8":
|
|
31434
|
+
case "int16":
|
|
31435
|
+
case "uint16":
|
|
31436
|
+
case "int32":
|
|
31437
|
+
case "uint32":
|
|
31438
|
+
return parseInt(n);
|
|
31439
|
+
case "float":
|
|
31440
|
+
case "double":
|
|
31441
|
+
case "float32":
|
|
31442
|
+
case "float64":
|
|
31443
|
+
return parseFloat(n);
|
|
31444
|
+
}
|
|
31445
|
+
}
|
|
31446
|
+
function parseASCIIElement(properties, tokens) {
|
|
31447
|
+
const element = {};
|
|
31448
|
+
for (let i = 0; i < properties.length; i++) {
|
|
31449
|
+
if (tokens.empty()) return null;
|
|
31450
|
+
if (properties[i].type === "list") {
|
|
31451
|
+
const list = [];
|
|
31452
|
+
const n = parseASCIINumber(tokens.next(), properties[i].countType);
|
|
31453
|
+
for (let j = 0; j < n; j++) {
|
|
31454
|
+
if (tokens.empty()) return null;
|
|
31455
|
+
list.push(parseASCIINumber(tokens.next(), properties[i].itemType));
|
|
31456
|
+
}
|
|
31457
|
+
element[properties[i].name] = list;
|
|
31458
|
+
} else {
|
|
31459
|
+
element[properties[i].name] = parseASCIINumber(tokens.next(), properties[i].type);
|
|
31460
|
+
}
|
|
31461
|
+
}
|
|
31462
|
+
return element;
|
|
31463
|
+
}
|
|
31464
|
+
function createBuffer() {
|
|
31465
|
+
const buffer = {
|
|
31466
|
+
indices: [],
|
|
31467
|
+
vertices: [],
|
|
31468
|
+
normals: [],
|
|
31469
|
+
uvs: [],
|
|
31470
|
+
faceVertexUvs: [],
|
|
31471
|
+
colors: [],
|
|
31472
|
+
faceVertexColors: [],
|
|
31473
|
+
descriptors: {}
|
|
31474
|
+
};
|
|
31475
|
+
for (const customProperty of Object.keys(scope.customPropertyMapping)) {
|
|
31476
|
+
buffer[customProperty] = [];
|
|
31477
|
+
}
|
|
31478
|
+
return buffer;
|
|
31479
|
+
}
|
|
31480
|
+
function getBufferAttributeClass(type) {
|
|
31481
|
+
switch (type) {
|
|
31482
|
+
case "int8":
|
|
31483
|
+
case "char":
|
|
31484
|
+
return Int8BufferAttribute;
|
|
31485
|
+
case "uint8":
|
|
31486
|
+
case "uchar":
|
|
31487
|
+
return Uint8BufferAttribute;
|
|
31488
|
+
case "int16":
|
|
31489
|
+
case "short":
|
|
31490
|
+
return Int16BufferAttribute;
|
|
31491
|
+
case "uint16":
|
|
31492
|
+
case "ushort":
|
|
31493
|
+
return Uint16BufferAttribute;
|
|
31494
|
+
case "int32":
|
|
31495
|
+
case "int":
|
|
31496
|
+
return Int32BufferAttribute;
|
|
31497
|
+
case "uint32":
|
|
31498
|
+
case "uint":
|
|
31499
|
+
return Uint32BufferAttribute;
|
|
31500
|
+
case "float32":
|
|
31501
|
+
case "float":
|
|
31502
|
+
return Float32BufferAttribute;
|
|
31503
|
+
case "float64":
|
|
31504
|
+
case "double":
|
|
31505
|
+
return Float64BufferAttribute;
|
|
31506
|
+
}
|
|
31507
|
+
}
|
|
31508
|
+
function getColorScale(type) {
|
|
31509
|
+
switch (type) {
|
|
31510
|
+
case "uchar":
|
|
31511
|
+
case "uint8":
|
|
31512
|
+
return 1 / 255;
|
|
31513
|
+
case "ushort":
|
|
31514
|
+
case "uint16":
|
|
31515
|
+
return 1 / 65535;
|
|
31516
|
+
case "float":
|
|
31517
|
+
case "float32":
|
|
31518
|
+
case "double":
|
|
31519
|
+
case "float64":
|
|
31520
|
+
return 1;
|
|
31521
|
+
default:
|
|
31522
|
+
return 1 / 255;
|
|
31055
31523
|
}
|
|
31056
|
-
this.textureUrls.add(resource.url);
|
|
31057
|
-
this.textureUrlsByFileName.set(resource.fileName, resource.url);
|
|
31058
31524
|
}
|
|
31059
|
-
|
|
31060
|
-
|
|
31525
|
+
function isFloatType(type) {
|
|
31526
|
+
return type === "float" || type === "float32" || type === "double" || type === "float64";
|
|
31061
31527
|
}
|
|
31062
|
-
|
|
31063
|
-
|
|
31064
|
-
|
|
31528
|
+
function getAttributeDescriptor(properties) {
|
|
31529
|
+
function findProperty(names) {
|
|
31530
|
+
for (const name of names) {
|
|
31531
|
+
const property = properties.find((p) => p.name === name);
|
|
31532
|
+
if (property) return property;
|
|
31533
|
+
}
|
|
31534
|
+
return null;
|
|
31535
|
+
}
|
|
31536
|
+
const x = findProperty(["x", "px", "posx"]);
|
|
31537
|
+
const y = findProperty(["y", "py", "posy"]);
|
|
31538
|
+
const z = findProperty(["z", "pz", "posz"]);
|
|
31539
|
+
const nx = findProperty(["nx", "normalx"]);
|
|
31540
|
+
const ny = findProperty(["ny", "normaly"]);
|
|
31541
|
+
const nz = findProperty(["nz", "normalz"]);
|
|
31542
|
+
const s = findProperty(["s", "u", "texture_u", "tx"]);
|
|
31543
|
+
const t = findProperty(["t", "v", "texture_v", "ty"]);
|
|
31544
|
+
const r = findProperty(["red", "diffuse_red", "r", "diffuse_r"]);
|
|
31545
|
+
const g = findProperty(["green", "diffuse_green", "g", "diffuse_g"]);
|
|
31546
|
+
const b = findProperty(["blue", "diffuse_blue", "b", "diffuse_b"]);
|
|
31547
|
+
const texcoord = findProperty(["texcoord"]);
|
|
31548
|
+
const custom = {};
|
|
31549
|
+
for (const customAttr of Object.keys(scope.customPropertyMapping)) {
|
|
31550
|
+
const propNames = scope.customPropertyMapping[customAttr];
|
|
31551
|
+
const matched = propNames.map((name) => properties.find((p) => p.name === name));
|
|
31552
|
+
const types = matched.filter((p) => p).map((p) => p.type);
|
|
31553
|
+
const uniform = types.length > 0 && types.every((type) => type === types[0]);
|
|
31554
|
+
custom[customAttr] = {
|
|
31555
|
+
type: uniform ? types[0] : "float32",
|
|
31556
|
+
usage: matched.every((p) => p !== void 0)
|
|
31557
|
+
};
|
|
31558
|
+
}
|
|
31559
|
+
return {
|
|
31560
|
+
position: {
|
|
31561
|
+
names: [x ? x.name : "x", y ? y.name : "y", z ? z.name : "z"],
|
|
31562
|
+
type: x ? x.type : "float32",
|
|
31563
|
+
usage: !!(x && y && z)
|
|
31564
|
+
},
|
|
31565
|
+
normal: {
|
|
31566
|
+
names: [nx ? nx.name : "nx", ny ? ny.name : "ny", nz ? nz.name : "nz"],
|
|
31567
|
+
type: nx ? nx.type : "float32",
|
|
31568
|
+
usage: !!(nx && ny && nz)
|
|
31569
|
+
},
|
|
31570
|
+
uv: {
|
|
31571
|
+
names: [s ? s.name : "s", t ? t.name : "t"],
|
|
31572
|
+
type: s ? s.type : "float32",
|
|
31573
|
+
usage: !!(s && t)
|
|
31574
|
+
},
|
|
31575
|
+
texcoord: {
|
|
31576
|
+
type: texcoord ? texcoord.itemType : "float32",
|
|
31577
|
+
usage: !!texcoord
|
|
31578
|
+
},
|
|
31579
|
+
color: {
|
|
31580
|
+
names: [r ? r.name : "red", g ? g.name : "green", b ? b.name : "blue"],
|
|
31581
|
+
type: r ? r.type : "uchar",
|
|
31582
|
+
usage: !!(r && g && b)
|
|
31583
|
+
},
|
|
31584
|
+
custom
|
|
31585
|
+
};
|
|
31586
|
+
}
|
|
31587
|
+
function parseASCII(data2, header) {
|
|
31588
|
+
const buffer = createBuffer();
|
|
31589
|
+
const patternBody = /end_header\s+(\S[\s\S]*\S|\S)\s*$/;
|
|
31590
|
+
let body, matches;
|
|
31591
|
+
if ((matches = patternBody.exec(data2)) !== null) {
|
|
31592
|
+
body = matches[1].split(/\s+/);
|
|
31593
|
+
} else {
|
|
31594
|
+
body = [];
|
|
31595
|
+
}
|
|
31596
|
+
const tokens = new ArrayStream(body);
|
|
31597
|
+
loop: for (let i = 0; i < header.elements.length; i++) {
|
|
31598
|
+
const elementDesc = header.elements[i];
|
|
31599
|
+
const attributeDescriptor = getAttributeDescriptor(elementDesc.properties);
|
|
31600
|
+
buffer.descriptors[elementDesc.name] = attributeDescriptor;
|
|
31601
|
+
for (let j = 0; j < elementDesc.count; j++) {
|
|
31602
|
+
const element = parseASCIIElement(elementDesc.properties, tokens);
|
|
31603
|
+
if (!element) break loop;
|
|
31604
|
+
handleElement(buffer, elementDesc.name, element, attributeDescriptor);
|
|
31605
|
+
}
|
|
31606
|
+
}
|
|
31607
|
+
return postProcess(buffer);
|
|
31608
|
+
}
|
|
31609
|
+
function postProcess(buffer) {
|
|
31610
|
+
let geometry2 = new BufferGeometry();
|
|
31611
|
+
const vertexDescriptor = buffer.descriptors.vertex;
|
|
31612
|
+
if (buffer.indices.length > 0) {
|
|
31613
|
+
geometry2.setIndex(buffer.indices);
|
|
31614
|
+
}
|
|
31615
|
+
const PositionClass = getBufferAttributeClass(vertexDescriptor ? vertexDescriptor.position.type : "float32");
|
|
31616
|
+
geometry2.setAttribute("position", new PositionClass(buffer.vertices, 3));
|
|
31617
|
+
if (buffer.normals.length > 0) {
|
|
31618
|
+
const NormalClass = getBufferAttributeClass(vertexDescriptor.normal.type);
|
|
31619
|
+
geometry2.setAttribute("normal", new NormalClass(buffer.normals, 3));
|
|
31620
|
+
}
|
|
31621
|
+
if (buffer.uvs.length > 0) {
|
|
31622
|
+
const UvClass = getBufferAttributeClass(vertexDescriptor.uv.type);
|
|
31623
|
+
geometry2.setAttribute("uv", new UvClass(buffer.uvs, 2));
|
|
31624
|
+
}
|
|
31625
|
+
if (buffer.colors.length > 0) {
|
|
31626
|
+
const colorType = vertexDescriptor.color.type;
|
|
31627
|
+
const normalized = !isFloatType(colorType);
|
|
31628
|
+
const ColorClass = getBufferAttributeClass(colorType);
|
|
31629
|
+
geometry2.setAttribute("color", new ColorClass(buffer.colors, 3, normalized));
|
|
31630
|
+
}
|
|
31631
|
+
if (buffer.faceVertexUvs.length > 0 || buffer.faceVertexColors.length > 0) {
|
|
31632
|
+
geometry2 = geometry2.toNonIndexed();
|
|
31633
|
+
if (buffer.faceVertexUvs.length > 0) {
|
|
31634
|
+
const UvClass = getBufferAttributeClass(buffer.descriptors.face.texcoord.type);
|
|
31635
|
+
geometry2.setAttribute("uv", new UvClass(buffer.faceVertexUvs, 2));
|
|
31636
|
+
}
|
|
31637
|
+
if (buffer.faceVertexColors.length > 0) {
|
|
31638
|
+
const colorType = buffer.descriptors.face.color.type;
|
|
31639
|
+
const normalized = !isFloatType(colorType);
|
|
31640
|
+
const ColorClass = getBufferAttributeClass(colorType);
|
|
31641
|
+
geometry2.setAttribute("color", new ColorClass(buffer.faceVertexColors, 3, normalized));
|
|
31642
|
+
}
|
|
31643
|
+
}
|
|
31644
|
+
for (const customProperty of Object.keys(scope.customPropertyMapping)) {
|
|
31645
|
+
if (buffer[customProperty].length > 0) {
|
|
31646
|
+
const CustomClass = getBufferAttributeClass(vertexDescriptor.custom[customProperty].type);
|
|
31647
|
+
geometry2.setAttribute(customProperty, new CustomClass(buffer[customProperty], scope.customPropertyMapping[customProperty].length));
|
|
31648
|
+
}
|
|
31649
|
+
}
|
|
31650
|
+
geometry2.computeBoundingSphere();
|
|
31651
|
+
return geometry2;
|
|
31652
|
+
}
|
|
31653
|
+
function handleElement(buffer, elementName, element, attributeDescriptor) {
|
|
31654
|
+
if (elementName === "vertex") {
|
|
31655
|
+
const { position, normal, uv, color } = attributeDescriptor;
|
|
31656
|
+
if (position.usage) {
|
|
31657
|
+
buffer.vertices.push(
|
|
31658
|
+
element[position.names[0]],
|
|
31659
|
+
element[position.names[1]],
|
|
31660
|
+
element[position.names[2]]
|
|
31661
|
+
);
|
|
31662
|
+
}
|
|
31663
|
+
if (normal.usage) {
|
|
31664
|
+
buffer.normals.push(
|
|
31665
|
+
element[normal.names[0]],
|
|
31666
|
+
element[normal.names[1]],
|
|
31667
|
+
element[normal.names[2]]
|
|
31668
|
+
);
|
|
31669
|
+
}
|
|
31670
|
+
if (uv.usage) {
|
|
31671
|
+
buffer.uvs.push(
|
|
31672
|
+
element[uv.names[0]],
|
|
31673
|
+
element[uv.names[1]]
|
|
31674
|
+
);
|
|
31675
|
+
}
|
|
31676
|
+
if (color.usage) {
|
|
31677
|
+
const scale = getColorScale(color.type);
|
|
31678
|
+
const isFloat = isFloatType(color.type);
|
|
31679
|
+
_color.setRGB(
|
|
31680
|
+
element[color.names[0]] * scale,
|
|
31681
|
+
element[color.names[1]] * scale,
|
|
31682
|
+
element[color.names[2]] * scale,
|
|
31683
|
+
SRGBColorSpace
|
|
31684
|
+
);
|
|
31685
|
+
const invScale = 1 / scale;
|
|
31686
|
+
buffer.colors.push(
|
|
31687
|
+
isFloat ? _color.r : Math.round(_color.r * invScale),
|
|
31688
|
+
isFloat ? _color.g : Math.round(_color.g * invScale),
|
|
31689
|
+
isFloat ? _color.b : Math.round(_color.b * invScale)
|
|
31690
|
+
);
|
|
31691
|
+
}
|
|
31692
|
+
for (const customProperty of Object.keys(scope.customPropertyMapping)) {
|
|
31693
|
+
for (const elementProperty of scope.customPropertyMapping[customProperty]) {
|
|
31694
|
+
buffer[customProperty].push(element[elementProperty]);
|
|
31695
|
+
}
|
|
31696
|
+
}
|
|
31697
|
+
} else if (elementName === "face") {
|
|
31698
|
+
const vertex_indices = element.vertex_indices || element.vertex_index;
|
|
31699
|
+
const texcoord = element.texcoord;
|
|
31700
|
+
if (vertex_indices.length === 3) {
|
|
31701
|
+
buffer.indices.push(vertex_indices[0], vertex_indices[1], vertex_indices[2]);
|
|
31702
|
+
if (texcoord && texcoord.length === 6) {
|
|
31703
|
+
buffer.faceVertexUvs.push(texcoord[0], texcoord[1]);
|
|
31704
|
+
buffer.faceVertexUvs.push(texcoord[2], texcoord[3]);
|
|
31705
|
+
buffer.faceVertexUvs.push(texcoord[4], texcoord[5]);
|
|
31706
|
+
}
|
|
31707
|
+
} else if (vertex_indices.length === 4) {
|
|
31708
|
+
buffer.indices.push(vertex_indices[0], vertex_indices[1], vertex_indices[3]);
|
|
31709
|
+
buffer.indices.push(vertex_indices[1], vertex_indices[2], vertex_indices[3]);
|
|
31710
|
+
}
|
|
31711
|
+
const { color } = attributeDescriptor;
|
|
31712
|
+
if (color.usage) {
|
|
31713
|
+
const scale = getColorScale(color.type);
|
|
31714
|
+
_color.setRGB(
|
|
31715
|
+
element[color.names[0]] * scale,
|
|
31716
|
+
element[color.names[1]] * scale,
|
|
31717
|
+
element[color.names[2]] * scale,
|
|
31718
|
+
SRGBColorSpace
|
|
31719
|
+
);
|
|
31720
|
+
const invScale = 1 / scale;
|
|
31721
|
+
const r = _color.r * invScale;
|
|
31722
|
+
const g = _color.g * invScale;
|
|
31723
|
+
const b = _color.b * invScale;
|
|
31724
|
+
buffer.faceVertexColors.push(r, g, b);
|
|
31725
|
+
buffer.faceVertexColors.push(r, g, b);
|
|
31726
|
+
buffer.faceVertexColors.push(r, g, b);
|
|
31727
|
+
}
|
|
31728
|
+
}
|
|
31729
|
+
}
|
|
31730
|
+
function binaryReadElement(at, properties) {
|
|
31731
|
+
const element = {};
|
|
31732
|
+
let read = 0;
|
|
31733
|
+
for (let i = 0; i < properties.length; i++) {
|
|
31734
|
+
const property = properties[i];
|
|
31735
|
+
const valueReader = property.valueReader;
|
|
31736
|
+
if (property.type === "list") {
|
|
31737
|
+
const list = [];
|
|
31738
|
+
const n = property.countReader.read(at + read);
|
|
31739
|
+
read += property.countReader.size;
|
|
31740
|
+
for (let j = 0; j < n; j++) {
|
|
31741
|
+
list.push(valueReader.read(at + read));
|
|
31742
|
+
read += valueReader.size;
|
|
31743
|
+
}
|
|
31744
|
+
element[property.name] = list;
|
|
31745
|
+
} else {
|
|
31746
|
+
element[property.name] = valueReader.read(at + read);
|
|
31747
|
+
read += valueReader.size;
|
|
31748
|
+
}
|
|
31749
|
+
}
|
|
31750
|
+
return [element, read];
|
|
31751
|
+
}
|
|
31752
|
+
function setPropertyBinaryReaders(properties, body, little_endian) {
|
|
31753
|
+
function getBinaryReader(dataview, type, little_endian2) {
|
|
31754
|
+
switch (type) {
|
|
31755
|
+
// correspondences for non-specific length types here match rply:
|
|
31756
|
+
case "int8":
|
|
31757
|
+
case "char":
|
|
31758
|
+
return { read: (at) => {
|
|
31759
|
+
return dataview.getInt8(at);
|
|
31760
|
+
}, size: 1 };
|
|
31761
|
+
case "uint8":
|
|
31762
|
+
case "uchar":
|
|
31763
|
+
return { read: (at) => {
|
|
31764
|
+
return dataview.getUint8(at);
|
|
31765
|
+
}, size: 1 };
|
|
31766
|
+
case "int16":
|
|
31767
|
+
case "short":
|
|
31768
|
+
return { read: (at) => {
|
|
31769
|
+
return dataview.getInt16(at, little_endian2);
|
|
31770
|
+
}, size: 2 };
|
|
31771
|
+
case "uint16":
|
|
31772
|
+
case "ushort":
|
|
31773
|
+
return { read: (at) => {
|
|
31774
|
+
return dataview.getUint16(at, little_endian2);
|
|
31775
|
+
}, size: 2 };
|
|
31776
|
+
case "int32":
|
|
31777
|
+
case "int":
|
|
31778
|
+
return { read: (at) => {
|
|
31779
|
+
return dataview.getInt32(at, little_endian2);
|
|
31780
|
+
}, size: 4 };
|
|
31781
|
+
case "uint32":
|
|
31782
|
+
case "uint":
|
|
31783
|
+
return { read: (at) => {
|
|
31784
|
+
return dataview.getUint32(at, little_endian2);
|
|
31785
|
+
}, size: 4 };
|
|
31786
|
+
case "float32":
|
|
31787
|
+
case "float":
|
|
31788
|
+
return { read: (at) => {
|
|
31789
|
+
return dataview.getFloat32(at, little_endian2);
|
|
31790
|
+
}, size: 4 };
|
|
31791
|
+
case "float64":
|
|
31792
|
+
case "double":
|
|
31793
|
+
return { read: (at) => {
|
|
31794
|
+
return dataview.getFloat64(at, little_endian2);
|
|
31795
|
+
}, size: 8 };
|
|
31796
|
+
}
|
|
31797
|
+
}
|
|
31798
|
+
for (let i = 0, l = properties.length; i < l; i++) {
|
|
31799
|
+
const property = properties[i];
|
|
31800
|
+
if (property.type === "list") {
|
|
31801
|
+
property.countReader = getBinaryReader(body, property.countType, little_endian);
|
|
31802
|
+
property.valueReader = getBinaryReader(body, property.itemType, little_endian);
|
|
31803
|
+
} else {
|
|
31804
|
+
property.valueReader = getBinaryReader(body, property.type, little_endian);
|
|
31805
|
+
}
|
|
31806
|
+
}
|
|
31807
|
+
}
|
|
31808
|
+
function parseBinary(data2, header) {
|
|
31809
|
+
const buffer = createBuffer();
|
|
31810
|
+
const little_endian = header.format === "binary_little_endian";
|
|
31811
|
+
const body = new DataView(data2, header.headerLength);
|
|
31812
|
+
let result, loc = 0;
|
|
31813
|
+
for (let currentElement = 0; currentElement < header.elements.length; currentElement++) {
|
|
31814
|
+
const elementDesc = header.elements[currentElement];
|
|
31815
|
+
const properties = elementDesc.properties;
|
|
31816
|
+
const attributeDescriptor = getAttributeDescriptor(properties);
|
|
31817
|
+
buffer.descriptors[elementDesc.name] = attributeDescriptor;
|
|
31818
|
+
setPropertyBinaryReaders(properties, body, little_endian);
|
|
31819
|
+
for (let currentElementCount = 0; currentElementCount < elementDesc.count; currentElementCount++) {
|
|
31820
|
+
result = binaryReadElement(loc, properties);
|
|
31821
|
+
loc += result[1];
|
|
31822
|
+
const element = result[0];
|
|
31823
|
+
handleElement(buffer, elementDesc.name, element, attributeDescriptor);
|
|
31824
|
+
}
|
|
31825
|
+
}
|
|
31826
|
+
return postProcess(buffer);
|
|
31827
|
+
}
|
|
31828
|
+
function extractHeaderText(bytes) {
|
|
31829
|
+
let i = 0;
|
|
31830
|
+
let cont = true;
|
|
31831
|
+
let line = "";
|
|
31832
|
+
const lines = [];
|
|
31833
|
+
const startLine = new TextDecoder().decode(bytes.subarray(0, 5));
|
|
31834
|
+
const hasCRNL = /^ply\r\n/.test(startLine);
|
|
31835
|
+
do {
|
|
31836
|
+
const c = String.fromCharCode(bytes[i++]);
|
|
31837
|
+
if (c !== "\n" && c !== "\r") {
|
|
31838
|
+
line += c;
|
|
31839
|
+
} else {
|
|
31840
|
+
if (line === "end_header") cont = false;
|
|
31841
|
+
if (line !== "") {
|
|
31842
|
+
lines.push(line);
|
|
31843
|
+
line = "";
|
|
31844
|
+
}
|
|
31845
|
+
}
|
|
31846
|
+
} while (cont && i < bytes.length);
|
|
31847
|
+
if (hasCRNL === true) i++;
|
|
31848
|
+
return { headerText: lines.join("\r") + "\r", headerLength: i };
|
|
31849
|
+
}
|
|
31850
|
+
let geometry;
|
|
31851
|
+
const scope = this;
|
|
31852
|
+
if (data instanceof ArrayBuffer) {
|
|
31853
|
+
const bytes = new Uint8Array(data);
|
|
31854
|
+
const { headerText, headerLength } = extractHeaderText(bytes);
|
|
31855
|
+
const header = parseHeader(headerText, headerLength);
|
|
31856
|
+
if (header.format === "ascii") {
|
|
31857
|
+
const text = new TextDecoder().decode(bytes);
|
|
31858
|
+
geometry = parseASCII(text, header);
|
|
31859
|
+
} else {
|
|
31860
|
+
geometry = parseBinary(data, header);
|
|
31861
|
+
}
|
|
31862
|
+
} else {
|
|
31863
|
+
geometry = parseASCII(data, parseHeader(data));
|
|
31864
|
+
}
|
|
31865
|
+
return geometry;
|
|
31065
31866
|
}
|
|
31066
|
-
|
|
31067
|
-
|
|
31867
|
+
}
|
|
31868
|
+
class Float64BufferAttribute extends BufferAttribute {
|
|
31869
|
+
constructor(array, itemSize, normalized) {
|
|
31870
|
+
super(new Float64Array(array), itemSize, normalized);
|
|
31871
|
+
}
|
|
31872
|
+
}
|
|
31873
|
+
class ArrayStream {
|
|
31874
|
+
constructor(arr) {
|
|
31875
|
+
this.arr = arr;
|
|
31876
|
+
this.i = 0;
|
|
31877
|
+
}
|
|
31878
|
+
empty() {
|
|
31879
|
+
return this.i >= this.arr.length;
|
|
31880
|
+
}
|
|
31881
|
+
next() {
|
|
31882
|
+
return this.arr[this.i++];
|
|
31883
|
+
}
|
|
31884
|
+
}
|
|
31885
|
+
class PlyTextureLoadOperation {
|
|
31886
|
+
abortListener;
|
|
31887
|
+
loader;
|
|
31888
|
+
signal;
|
|
31889
|
+
url;
|
|
31890
|
+
resolveResult;
|
|
31891
|
+
settled = false;
|
|
31892
|
+
texture;
|
|
31893
|
+
constructor(loader, url, signal) {
|
|
31894
|
+
this.abortListener = this.handleAbort.bind(this);
|
|
31895
|
+
this.loader = loader;
|
|
31896
|
+
this.signal = signal;
|
|
31897
|
+
this.url = url;
|
|
31898
|
+
}
|
|
31899
|
+
start() {
|
|
31900
|
+
return new Promise(this.begin.bind(this));
|
|
31901
|
+
}
|
|
31902
|
+
begin(resolve) {
|
|
31903
|
+
this.resolveResult = resolve;
|
|
31904
|
+
this.signal.addEventListener("abort", this.abortListener, { once: true });
|
|
31905
|
+
if (this.signal.aborted) {
|
|
31906
|
+
this.handleAbort();
|
|
31068
31907
|
return;
|
|
31069
31908
|
}
|
|
31070
|
-
|
|
31071
|
-
|
|
31072
|
-
|
|
31073
|
-
|
|
31074
|
-
|
|
31909
|
+
try {
|
|
31910
|
+
const requestedTexture = this.loader.load(
|
|
31911
|
+
this.url,
|
|
31912
|
+
this.handleLoad.bind(this),
|
|
31913
|
+
void 0,
|
|
31914
|
+
this.handleError.bind(this)
|
|
31915
|
+
);
|
|
31916
|
+
if (this.settled) {
|
|
31917
|
+
if (this.texture !== requestedTexture) {
|
|
31918
|
+
requestedTexture.dispose();
|
|
31919
|
+
}
|
|
31920
|
+
return;
|
|
31921
|
+
}
|
|
31922
|
+
this.texture = requestedTexture;
|
|
31923
|
+
} catch {
|
|
31924
|
+
this.handleError();
|
|
31075
31925
|
}
|
|
31076
|
-
|
|
31077
|
-
|
|
31926
|
+
}
|
|
31927
|
+
finish(result) {
|
|
31928
|
+
if (this.settled) {
|
|
31078
31929
|
return;
|
|
31079
31930
|
}
|
|
31080
|
-
|
|
31931
|
+
this.settled = true;
|
|
31932
|
+
this.signal.removeEventListener("abort", this.abortListener);
|
|
31933
|
+
this.resolveResult?.(result);
|
|
31934
|
+
this.resolveResult = void 0;
|
|
31081
31935
|
}
|
|
31082
|
-
|
|
31083
|
-
|
|
31084
|
-
|
|
31085
|
-
|
|
31936
|
+
handleAbort() {
|
|
31937
|
+
this.texture?.dispose();
|
|
31938
|
+
this.texture = void 0;
|
|
31939
|
+
this.finish({ outcome: "cancelled" });
|
|
31940
|
+
}
|
|
31941
|
+
handleError() {
|
|
31942
|
+
this.texture?.dispose();
|
|
31943
|
+
this.texture = void 0;
|
|
31944
|
+
this.finish({ outcome: "failed" });
|
|
31945
|
+
}
|
|
31946
|
+
handleLoad(texture) {
|
|
31947
|
+
if (this.settled) {
|
|
31948
|
+
texture.dispose();
|
|
31949
|
+
return;
|
|
31086
31950
|
}
|
|
31087
|
-
|
|
31088
|
-
|
|
31089
|
-
|
|
31951
|
+
this.texture = texture;
|
|
31952
|
+
this.finish({
|
|
31953
|
+
outcome: "succeeded",
|
|
31954
|
+
texture
|
|
31955
|
+
});
|
|
31956
|
+
}
|
|
31957
|
+
}
|
|
31958
|
+
class PlyTextureLoader {
|
|
31959
|
+
loader;
|
|
31960
|
+
constructor(loader = new TextureLoader()) {
|
|
31961
|
+
this.loader = loader;
|
|
31962
|
+
}
|
|
31963
|
+
load(url, signal) {
|
|
31964
|
+
return new PlyTextureLoadOperation(this.loader, url, signal).start();
|
|
31965
|
+
}
|
|
31966
|
+
}
|
|
31967
|
+
const DEFAULT_MODEL_COLOR = 10265519;
|
|
31968
|
+
const DEFAULT_POINT_SIZE = 3;
|
|
31969
|
+
const MAX_HEADER_BYTES = 65536;
|
|
31970
|
+
class PlyLoader {
|
|
31971
|
+
parser;
|
|
31972
|
+
textureLoader;
|
|
31973
|
+
constructor(parser = new PLYLoader(), textureLoader = new PlyTextureLoader()) {
|
|
31974
|
+
this.parser = parser;
|
|
31975
|
+
this.textureLoader = textureLoader;
|
|
31976
|
+
}
|
|
31977
|
+
async load(resources, signal) {
|
|
31978
|
+
if (signal.aborted) {
|
|
31979
|
+
return {
|
|
31980
|
+
code: ObjImportFailureCode$1.Cancelled,
|
|
31981
|
+
success: false
|
|
31982
|
+
};
|
|
31090
31983
|
}
|
|
31091
|
-
|
|
31984
|
+
const source = await this.fetchSource(resources.plyUrl, signal);
|
|
31985
|
+
if (!(source instanceof ArrayBuffer)) {
|
|
31986
|
+
return source;
|
|
31987
|
+
}
|
|
31988
|
+
let geometry;
|
|
31989
|
+
let metadata;
|
|
31990
|
+
try {
|
|
31991
|
+
metadata = this.parseMetadata(source);
|
|
31992
|
+
geometry = this.parser.parse(source);
|
|
31993
|
+
} catch {
|
|
31994
|
+
return {
|
|
31995
|
+
code: ObjImportFailureCode$1.InvalidSource,
|
|
31996
|
+
success: false
|
|
31997
|
+
};
|
|
31998
|
+
}
|
|
31999
|
+
if (this.isCancelled(signal)) {
|
|
32000
|
+
geometry.dispose();
|
|
32001
|
+
return {
|
|
32002
|
+
code: ObjImportFailureCode$1.Cancelled,
|
|
32003
|
+
success: false
|
|
32004
|
+
};
|
|
32005
|
+
}
|
|
32006
|
+
if (!geometry.hasAttribute("position")) {
|
|
32007
|
+
geometry.dispose();
|
|
32008
|
+
return {
|
|
32009
|
+
code: ObjImportFailureCode$1.InvalidSource,
|
|
32010
|
+
success: false
|
|
32011
|
+
};
|
|
32012
|
+
}
|
|
32013
|
+
const modelResult = metadata.hasFaces ? await this.createMeshModel(geometry, metadata.textureReference, resources, signal) : this.createPointsModel(geometry);
|
|
32014
|
+
if ("success" in modelResult) {
|
|
32015
|
+
return modelResult;
|
|
32016
|
+
}
|
|
32017
|
+
if (!modelResult.model.hasFiniteBounds()) {
|
|
32018
|
+
modelResult.model.dispose();
|
|
32019
|
+
return {
|
|
32020
|
+
code: ObjImportFailureCode$1.InvalidSource,
|
|
32021
|
+
success: false
|
|
32022
|
+
};
|
|
32023
|
+
}
|
|
32024
|
+
return {
|
|
32025
|
+
success: true,
|
|
32026
|
+
...modelResult.warnings.length === 0 ? {} : { warnings: modelResult.warnings },
|
|
32027
|
+
model: modelResult.model
|
|
32028
|
+
};
|
|
31092
32029
|
}
|
|
31093
|
-
|
|
31094
|
-
|
|
31095
|
-
|
|
31096
|
-
throw new Error("The OBJ resource list only accepts HTTP URLs.");
|
|
32030
|
+
createMeshMaterial(geometry, texture) {
|
|
32031
|
+
if (texture !== void 0) {
|
|
32032
|
+
texture.colorSpace = SRGBColorSpace;
|
|
31097
32033
|
}
|
|
32034
|
+
return new MeshStandardMaterial({
|
|
32035
|
+
color: texture !== void 0 || geometry.hasAttribute("color") ? 16777215 : DEFAULT_MODEL_COLOR,
|
|
32036
|
+
map: texture ?? null,
|
|
32037
|
+
side: DoubleSide,
|
|
32038
|
+
vertexColors: geometry.hasAttribute("color")
|
|
32039
|
+
});
|
|
32040
|
+
}
|
|
32041
|
+
async createMeshModel(geometry, textureReference, resources, signal) {
|
|
32042
|
+
if (!geometry.hasAttribute("normal")) {
|
|
32043
|
+
geometry.computeVertexNormals();
|
|
32044
|
+
}
|
|
32045
|
+
const warnings = [];
|
|
32046
|
+
let texture;
|
|
32047
|
+
if (textureReference !== void 0 && geometry.hasAttribute("uv")) {
|
|
32048
|
+
const textureResult = await this.textureLoader.load(
|
|
32049
|
+
resources.resolveTextureUrl(textureReference),
|
|
32050
|
+
signal
|
|
32051
|
+
);
|
|
32052
|
+
if (textureResult.outcome === "cancelled") {
|
|
32053
|
+
geometry.dispose();
|
|
32054
|
+
return {
|
|
32055
|
+
code: ObjImportFailureCode$1.Cancelled,
|
|
32056
|
+
success: false
|
|
32057
|
+
};
|
|
32058
|
+
}
|
|
32059
|
+
if (textureResult.outcome === "succeeded") {
|
|
32060
|
+
texture = textureResult.texture;
|
|
32061
|
+
} else {
|
|
32062
|
+
warnings.push({ code: ObjImportWarningCode$1.IncompleteMaterial });
|
|
32063
|
+
}
|
|
32064
|
+
} else if (textureReference !== void 0) {
|
|
32065
|
+
warnings.push({ code: ObjImportWarningCode$1.IncompleteMaterial });
|
|
32066
|
+
}
|
|
32067
|
+
if (signal.aborted) {
|
|
32068
|
+
texture?.dispose();
|
|
32069
|
+
geometry.dispose();
|
|
32070
|
+
return {
|
|
32071
|
+
code: ObjImportFailureCode$1.Cancelled,
|
|
32072
|
+
success: false
|
|
32073
|
+
};
|
|
32074
|
+
}
|
|
32075
|
+
const material = this.createMeshMaterial(geometry, texture);
|
|
31098
32076
|
return {
|
|
31099
|
-
|
|
31100
|
-
|
|
32077
|
+
model: new Model(new Mesh(geometry, material)),
|
|
32078
|
+
warnings
|
|
31101
32079
|
};
|
|
31102
32080
|
}
|
|
31103
|
-
|
|
31104
|
-
const
|
|
31105
|
-
|
|
31106
|
-
|
|
32081
|
+
createPointsModel(geometry) {
|
|
32082
|
+
const material = new PointsMaterial({
|
|
32083
|
+
color: geometry.hasAttribute("color") ? 16777215 : DEFAULT_MODEL_COLOR,
|
|
32084
|
+
size: DEFAULT_POINT_SIZE,
|
|
32085
|
+
sizeAttenuation: false,
|
|
32086
|
+
vertexColors: geometry.hasAttribute("color")
|
|
32087
|
+
});
|
|
32088
|
+
return {
|
|
32089
|
+
model: new Model(new Points(geometry, material)),
|
|
32090
|
+
warnings: []
|
|
32091
|
+
};
|
|
32092
|
+
}
|
|
32093
|
+
async fetchSource(url, signal) {
|
|
32094
|
+
try {
|
|
32095
|
+
const response = await fetch(url, { signal });
|
|
32096
|
+
if (!response.ok) {
|
|
32097
|
+
return {
|
|
32098
|
+
code: ObjImportFailureCode$1.InvalidSource,
|
|
32099
|
+
success: false
|
|
32100
|
+
};
|
|
32101
|
+
}
|
|
32102
|
+
return await response.arrayBuffer();
|
|
32103
|
+
} catch {
|
|
32104
|
+
return {
|
|
32105
|
+
code: signal.aborted ? ObjImportFailureCode$1.Cancelled : ObjImportFailureCode$1.InvalidSource,
|
|
32106
|
+
success: false
|
|
32107
|
+
};
|
|
31107
32108
|
}
|
|
31108
|
-
return fileName;
|
|
31109
32109
|
}
|
|
31110
|
-
|
|
31111
|
-
|
|
32110
|
+
parseMetadata(source) {
|
|
32111
|
+
const headerLength = Math.min(source.byteLength, MAX_HEADER_BYTES);
|
|
32112
|
+
const header = new TextDecoder().decode(new Uint8Array(source, 0, headerLength));
|
|
32113
|
+
const endHeaderMatch = /end_header(?:\r\n|\r|\n)/u.exec(header);
|
|
32114
|
+
if (endHeaderMatch === null) {
|
|
32115
|
+
throw new Error("The PLY header is incomplete.");
|
|
32116
|
+
}
|
|
32117
|
+
const headerSource = header.slice(0, endHeaderMatch.index);
|
|
32118
|
+
const faceCount = /^element\s+face\s+(\d+)\s*$/imu.exec(headerSource)?.[1];
|
|
32119
|
+
const rawTextureReference = /^comment\s+TextureFile\s+(.+?)\s*$/imu.exec(headerSource)?.[1];
|
|
32120
|
+
return {
|
|
32121
|
+
hasFaces: faceCount !== void 0 && Number.parseInt(faceCount, 10) > 0,
|
|
32122
|
+
textureReference: rawTextureReference === void 0 ? void 0 : this.removeSurroundingQuotes(rawTextureReference.trim())
|
|
32123
|
+
};
|
|
31112
32124
|
}
|
|
31113
|
-
|
|
31114
|
-
return
|
|
32125
|
+
isCancelled(signal) {
|
|
32126
|
+
return signal.aborted;
|
|
32127
|
+
}
|
|
32128
|
+
removeSurroundingQuotes(value) {
|
|
32129
|
+
const firstCharacter = value.at(0);
|
|
32130
|
+
const lastCharacter = value.at(-1);
|
|
32131
|
+
if (value.length >= 2 && (firstCharacter === '"' && lastCharacter === '"' || firstCharacter === "'" && lastCharacter === "'")) {
|
|
32132
|
+
return value.slice(1, -1);
|
|
32133
|
+
}
|
|
32134
|
+
return value;
|
|
31115
32135
|
}
|
|
31116
32136
|
}
|
|
31117
32137
|
const DEFAULT_BACKGROUND_COLOR = 3355443;
|
|
@@ -31131,6 +32151,7 @@ class Renderer {
|
|
|
31131
32151
|
frameHandle;
|
|
31132
32152
|
hemisphereLight;
|
|
31133
32153
|
modelLoader;
|
|
32154
|
+
plyLoader;
|
|
31134
32155
|
previousScissor = new Vector4();
|
|
31135
32156
|
previousViewport = new Vector4();
|
|
31136
32157
|
renderer;
|
|
@@ -31172,6 +32193,7 @@ class Renderer {
|
|
|
31172
32193
|
this.fillLight.position.set(4, 2, 3);
|
|
31173
32194
|
this.scene.add(this.hemisphereLight, this.directionalLight, this.fillLight);
|
|
31174
32195
|
this.modelLoader = new ObjLoader();
|
|
32196
|
+
this.plyLoader = new PlyLoader();
|
|
31175
32197
|
controller = new CameraController(this.camera, this.requestRender.bind(this));
|
|
31176
32198
|
this.controller = controller;
|
|
31177
32199
|
viewCube = new ViewCube(this.requestRender.bind(this));
|
|
@@ -31285,6 +32307,30 @@ class Renderer {
|
|
|
31285
32307
|
stone: source
|
|
31286
32308
|
});
|
|
31287
32309
|
}
|
|
32310
|
+
importModelResourceScene(source) {
|
|
32311
|
+
this.assertNotDisposed();
|
|
32312
|
+
if (this.contextLost) {
|
|
32313
|
+
return Promise.resolve({
|
|
32314
|
+
code: ObjImportFailureCode$1.RenderFailed,
|
|
32315
|
+
success: false
|
|
32316
|
+
});
|
|
32317
|
+
}
|
|
32318
|
+
try {
|
|
32319
|
+
const resources = {
|
|
32320
|
+
base: source.base === void 0 ? void 0 : new ModelResourceList(source.base.fileUrls),
|
|
32321
|
+
stone: source.stone === void 0 ? void 0 : new ModelResourceList(source.stone.fileUrls)
|
|
32322
|
+
};
|
|
32323
|
+
if (this.containsOnlyObjResources(resources)) {
|
|
32324
|
+
return this.importObjResourceScene(source);
|
|
32325
|
+
}
|
|
32326
|
+
return this.completeSceneImport(this.startImportSession(), resources);
|
|
32327
|
+
} catch {
|
|
32328
|
+
return Promise.resolve({
|
|
32329
|
+
code: ObjImportFailureCode$1.InvalidSource,
|
|
32330
|
+
success: false
|
|
32331
|
+
});
|
|
32332
|
+
}
|
|
32333
|
+
}
|
|
31288
32334
|
importObjResources(source) {
|
|
31289
32335
|
this.assertNotDisposed();
|
|
31290
32336
|
if (this.contextLost) {
|
|
@@ -31378,6 +32424,12 @@ class Renderer {
|
|
|
31378
32424
|
window.cancelAnimationFrame(this.frameHandle);
|
|
31379
32425
|
this.frameHandle = void 0;
|
|
31380
32426
|
}
|
|
32427
|
+
containsOnlyObjResources(source) {
|
|
32428
|
+
const resources = [source.stone, source.base];
|
|
32429
|
+
return resources.every(
|
|
32430
|
+
(resource) => resource === void 0 || resource instanceof ObjResourceList || resource.isObj()
|
|
32431
|
+
);
|
|
32432
|
+
}
|
|
31381
32433
|
async completeSceneImport(session, source) {
|
|
31382
32434
|
const stoneSource = source.stone;
|
|
31383
32435
|
const baseSource = source.base;
|
|
@@ -31399,7 +32451,7 @@ class Renderer {
|
|
|
31399
32451
|
}
|
|
31400
32452
|
const secondCandidate = await this.loadModel(session, baseSource);
|
|
31401
32453
|
if (this.isImportResult(secondCandidate)) {
|
|
31402
|
-
this.
|
|
32454
|
+
this.releaseLoadedModels(candidateModels);
|
|
31403
32455
|
return secondCandidate;
|
|
31404
32456
|
}
|
|
31405
32457
|
candidateModels.push(secondCandidate);
|
|
@@ -31415,7 +32467,14 @@ class Renderer {
|
|
|
31415
32467
|
async loadModel(session, source) {
|
|
31416
32468
|
let result;
|
|
31417
32469
|
try {
|
|
31418
|
-
|
|
32470
|
+
if (source instanceof ModelResourceList) {
|
|
32471
|
+
result = source.resources instanceof ObjResourceList ? await this.modelLoader.loadResources(
|
|
32472
|
+
source.resources,
|
|
32473
|
+
session.controller.signal
|
|
32474
|
+
) : await this.plyLoader.load(source.resources, session.controller.signal);
|
|
32475
|
+
} else {
|
|
32476
|
+
result = source instanceof ObjResourceList ? await this.modelLoader.loadResources(source, session.controller.signal) : await this.modelLoader.load(source, session.controller.signal);
|
|
32477
|
+
}
|
|
31419
32478
|
} catch {
|
|
31420
32479
|
return this.completeUnexpectedImportFailure(session);
|
|
31421
32480
|
}
|
|
@@ -31450,7 +32509,10 @@ class Renderer {
|
|
|
31450
32509
|
success: false
|
|
31451
32510
|
};
|
|
31452
32511
|
}
|
|
31453
|
-
return
|
|
32512
|
+
return {
|
|
32513
|
+
model: result.model,
|
|
32514
|
+
warnings: result.warnings ?? []
|
|
32515
|
+
};
|
|
31454
32516
|
}
|
|
31455
32517
|
completeUnexpectedImportFailure(session) {
|
|
31456
32518
|
const invalidationCode = session.invalidationCode;
|
|
@@ -31525,6 +32587,9 @@ class Renderer {
|
|
|
31525
32587
|
throw errors[0];
|
|
31526
32588
|
}
|
|
31527
32589
|
}
|
|
32590
|
+
releaseLoadedModels(models) {
|
|
32591
|
+
this.releaseModels(models.map(({ model }) => model));
|
|
32592
|
+
}
|
|
31528
32593
|
releaseImportedModel(result) {
|
|
31529
32594
|
if (result.model !== void 0) {
|
|
31530
32595
|
this.releaseModel(result.model);
|
|
@@ -31577,7 +32642,12 @@ class Renderer {
|
|
|
31577
32642
|
this.renderer.setScissorTest(previousScissorTest);
|
|
31578
32643
|
}
|
|
31579
32644
|
}
|
|
31580
|
-
replaceActiveModels(session,
|
|
32645
|
+
replaceActiveModels(session, loadedModels) {
|
|
32646
|
+
const [firstLoadedModel, ...remainingLoadedModels] = loadedModels;
|
|
32647
|
+
const models = [
|
|
32648
|
+
firstLoadedModel.model,
|
|
32649
|
+
...remainingLoadedModels.map(({ model }) => model)
|
|
32650
|
+
];
|
|
31581
32651
|
const invalidationCode = session.invalidationCode;
|
|
31582
32652
|
if (invalidationCode !== void 0) {
|
|
31583
32653
|
this.finishImportSession(session);
|
|
@@ -31607,10 +32677,16 @@ class Renderer {
|
|
|
31607
32677
|
this.activeModels = [...models];
|
|
31608
32678
|
this.releaseModels(previousModels);
|
|
31609
32679
|
this.requestRender();
|
|
32680
|
+
const warnings = this.mergeWarnings(loadedModels);
|
|
31610
32681
|
return {
|
|
31611
|
-
success: true
|
|
32682
|
+
success: true,
|
|
32683
|
+
...warnings === void 0 ? {} : { warnings }
|
|
31612
32684
|
};
|
|
31613
32685
|
}
|
|
32686
|
+
mergeWarnings(models) {
|
|
32687
|
+
const warnings = models.flatMap(({ warnings: modelWarnings }) => modelWarnings);
|
|
32688
|
+
return warnings.length > 0 ? warnings : void 0;
|
|
32689
|
+
}
|
|
31614
32690
|
mergeBounds(models) {
|
|
31615
32691
|
const [firstModel, ...remainingModels] = models;
|
|
31616
32692
|
let minX = firstModel.bounds.min.x;
|
|
@@ -31694,6 +32770,10 @@ var ObjImportFailureCode = /* @__PURE__ */ ((ObjImportFailureCode2) => {
|
|
|
31694
32770
|
ObjImportFailureCode2["Unavailable"] = "unavailable";
|
|
31695
32771
|
return ObjImportFailureCode2;
|
|
31696
32772
|
})(ObjImportFailureCode || {});
|
|
32773
|
+
var ObjImportWarningCode = /* @__PURE__ */ ((ObjImportWarningCode2) => {
|
|
32774
|
+
ObjImportWarningCode2["IncompleteMaterial"] = "incomplete-material";
|
|
32775
|
+
return ObjImportWarningCode2;
|
|
32776
|
+
})(ObjImportWarningCode || {});
|
|
31697
32777
|
class Application {
|
|
31698
32778
|
disposed = false;
|
|
31699
32779
|
renderer;
|
|
@@ -31708,6 +32788,10 @@ class Application {
|
|
|
31708
32788
|
this.assertNotDisposed();
|
|
31709
32789
|
return this.mapAsyncObjImportResult(this.getRenderer().importObj(source));
|
|
31710
32790
|
}
|
|
32791
|
+
importModelResourceScene(source) {
|
|
32792
|
+
this.assertNotDisposed();
|
|
32793
|
+
return this.mapAsyncObjImportResult(this.getRenderer().importModelResourceScene(source));
|
|
32794
|
+
}
|
|
31711
32795
|
importObjResources(source) {
|
|
31712
32796
|
this.assertNotDisposed();
|
|
31713
32797
|
return this.mapAsyncObjImportResult(this.getRenderer().importObjResources(source));
|
|
@@ -31754,8 +32838,10 @@ class Application {
|
|
|
31754
32838
|
}
|
|
31755
32839
|
mapObjImportResult(result) {
|
|
31756
32840
|
if (result.success) {
|
|
32841
|
+
const warnings = this.mapWarnings(result.warnings);
|
|
31757
32842
|
return {
|
|
31758
|
-
success: true
|
|
32843
|
+
success: true,
|
|
32844
|
+
...warnings === void 0 ? {} : { warnings }
|
|
31759
32845
|
};
|
|
31760
32846
|
}
|
|
31761
32847
|
switch (result.code) {
|
|
@@ -31781,8 +32867,17 @@ class Application {
|
|
|
31781
32867
|
async mapAsyncObjImportResult(resultPromise) {
|
|
31782
32868
|
return this.mapObjImportResult(await resultPromise);
|
|
31783
32869
|
}
|
|
32870
|
+
mapWarnings(warnings) {
|
|
32871
|
+
if (warnings === void 0 || warnings.length === 0) {
|
|
32872
|
+
return void 0;
|
|
32873
|
+
}
|
|
32874
|
+
return warnings.map(() => ({
|
|
32875
|
+
code: ObjImportWarningCode.IncompleteMaterial
|
|
32876
|
+
}));
|
|
32877
|
+
}
|
|
31784
32878
|
}
|
|
31785
32879
|
export {
|
|
31786
32880
|
Application,
|
|
31787
|
-
ObjImportFailureCode
|
|
32881
|
+
ObjImportFailureCode,
|
|
32882
|
+
ObjImportWarningCode
|
|
31788
32883
|
};
|