src/plugins/XML3DLoaderPlugin/XML3DSceneGraphLoader.js
- import {Node} from "../../viewer/scene/nodes/Node.js";
- import {Mesh} from "../../viewer/scene/mesh/Mesh.js";
- import {ReadableGeometry} from "../../viewer/scene/geometry/ReadableGeometry.js";
- import {PhongMaterial} from "../../viewer/scene/materials/PhongMaterial.js";
- import {MetallicMaterial} from "../../viewer/scene/materials/MetallicMaterial.js";
- import {SpecularMaterial} from "../../viewer/scene/materials/SpecularMaterial.js";
- import {LambertMaterial} from "../../viewer/scene/materials/LambertMaterial.js";
- import {math} from "../../viewer/scene/math/math.js";
-
- import {zipLib} from "./zipjs/zip.js";
- import {zipExt} from "./zipjs/zip-ext.js";
-
- const zip = zipLib.zip;
- zipExt(zip);
-
- const supportedSchemas = ["4.2"];
-
- /**
- * @private
- */
- class XML3DSceneGraphLoader {
-
- constructor(plugin, cfg = {}) {
-
- /**
- * Supported 3DXML schema versions
- * @property supportedSchemas
- * @type {string[]}
- */
- this.supportedSchemas = supportedSchemas;
-
- this._xrayOpacity = 0.7;
- this._src = null;
- this._options = cfg;
-
- /**
- * Default viewpoint, containing eye, look and up vectors.
- * Only defined if found in the 3DXML file.
- * @property viewpoint
- * @type {Number[]}
- */
- this.viewpoint = null;
-
- if (!cfg.workerScriptsPath) {
- plugin.error("Config expected: workerScriptsPath");
- return
- }
- zip.workerScriptsPath = cfg.workerScriptsPath;
-
- this.src = cfg.src;
- this.xrayOpacity = 0.7;
- this.displayEffect = cfg.displayEffect;
- this.createMetaModel = cfg.createMetaModel;
- }
-
- load(plugin, modelNode, src, options, ok, error) {
-
- switch (options.materialType) {
- case "MetallicMaterial":
- modelNode._defaultMaterial = new MetallicMaterial(modelNode, {
- baseColor: [1, 1, 1],
- metallic: 0.6,
- roughness: 0.6
- });
- break;
-
- case "SpecularMaterial":
- modelNode._defaultMaterial = new SpecularMaterial(modelNode, {
- diffuse: [1, 1, 1],
- specular: math.vec3([1.0, 1.0, 1.0]),
- glossiness: 0.5
- });
- break;
-
- default:
- modelNode._defaultMaterial = new PhongMaterial(modelNode, {
- reflectivity: 0.75,
- shiness: 100,
- diffuse: [1, 1, 1]
- });
- }
-
- modelNode._wireframeMaterial = new LambertMaterial(modelNode, {
- color: [0, 0, 0],
- lineWidth: 2
- });
-
- var spinner = modelNode.scene.canvas.spinner;
- spinner.processes++;
-
- load3DXML(plugin, modelNode, src, options, function () {
- spinner.processes--;
- if (ok) {
- ok();
- }
- modelNode.fire("loaded", true, false);
- },
- function (msg) {
- spinner.processes--;
- modelNode.error(msg);
- if (error) {
- error(msg);
- }
- /**
- Fired whenever this XML3D fails to load the 3DXML file
- specified by {@link XML3D/src}.
- @event error
- @param msg {String} Description of the error
- */
- modelNode.fire("error", msg);
- },
- function (err) {
- console.log("Error, Will Robinson: " + err);
- });
- }
- }
-
- var load3DXML = (function () {
- return function (plugin, modelNode, src, options, ok, error) {
- loadZIP(src, function (zip) { // OK
- parse3DXML(plugin, zip, options, modelNode, ok, error);
- },
- error);
- };
- })();
-
- var parse3DXML = (function () {
- return function (plugin, zip, options, modelNode, ok) {
- var ctx = {
- plugin: plugin,
- zip: zip,
- edgeThreshold: 30, // Guess at degrees of normal deviation between adjacent tris below which we remove edge between them
- materialType: options.materialType,
- scene: modelNode.scene,
- modelNode: modelNode,
- info: {
- references: {}
- },
- materials: {}
- };
-
- if (options.createMetaModel) {
- ctx.metaModelData = {
- modelId: modelNode.id,
- metaObjects: [{
- name: modelNode.id,
- type: "Default",
- id: modelNode.id
- }]
- };
- }
- modelNode.scene.loading++; // Disables (re)compilation
-
- parseDocument(ctx, function () {
- if (ctx.metaModelData) {
- plugin.viewer.metaScene.createMetaModel(modelNode.id, ctx.metaModelData);
- }
- modelNode.scene.loading--; // Re-enables (re)compilation
- ok();
- });
- };
-
- function parseDocument(ctx, ok) {
- ctx.zip.getFile("Manifest.xml", function (xmlDoc, json) {
- var node = json;
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Manifest":
- parseManifest(ctx, child, ok);
- break;
- }
- }
- });
- }
-
- function parseManifest(ctx, manifest, ok) {
- var children = manifest.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Root":
- var rootFileSrc = child.children[0];
- ctx.zip.getFile(rootFileSrc, function (xmlDoc, json) {
- parseRoot(ctx, json, ok);
- });
- break;
- }
- }
- }
-
- function parseRoot(ctx, node, ok) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Model_3dxml":
- parseModel(ctx, child, ok);
- break;
- }
- }
- }
-
- function parseModel(ctx, node, ok) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Header":
- parseHeader(ctx, child);
- break;
- case "ProductStructure":
- parseProductStructure(ctx, child, ok);
- break;
- case "DefaultView":
- parseDefaultView(ctx, child);
- break;
- }
- }
- }
-
- function parseHeader(ctx, node) {
- var children = node.children;
- var metaData = {};
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "SchemaVersion":
- metaData.schemaVersion = child.children[0];
- if (!isSchemaVersionSupported(ctx, metaData.schemaVersion)) {
- ctx.plugin.error("Schema version not supported: " + metaData.schemaVersion + " - supported versions are: " + supportedSchemas.join(","));
- } else {
- //ctx.plugin.log("Parsing schema version: " + metaData.schemaVersion);
- }
- break;
- case "Title":
- metaData.title = child.children[0];
- break;
- case "Author":
- metaData.author = child.children[0];
- break;
- case "Created":
- metaData.created = child.children[0];
- break;
- }
- }
- ctx.modelNode.meta = metaData;
- }
-
- function isSchemaVersionSupported(ctx, schemaVersion) {
- for (var i = 0, len = supportedSchemas.length; i < len; i++) {
- if (schemaVersion === supportedSchemas[i]) {
- return true;
- }
- }
- return false;
- }
-
- function parseProductStructure(ctx, productStructureNode, ok) {
-
- parseReferenceReps(ctx, productStructureNode, function (referenceReps) {
-
- // Parse out an intermediate scene DAG representation, that we can then
- // recursive descend through to build a xeokit Object hierarchy.
-
- var children = productStructureNode.children;
-
- var reference3Ds = {};
- var instanceReps = {};
- var instance3Ds = {};
-
- var rootNode;
- var nodes = {};
-
- // Map all the elements
-
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
-
- case "Reference3D":
- reference3Ds[child.id] = {
- type: "Reference3D",
- id: child.id,
- name: child.name,
- instance3Ds: {},
- instanceReps: {}
- };
- break;
-
- case "InstanceRep":
- var isAggregatedBy;
- var isInstanceOf;
- var relativeMatrix;
- for (var j = 0, lenj = child.children.length; j < lenj; j++) {
- var child2 = child.children[j];
- switch (child2.type) {
- case "IsAggregatedBy":
- isAggregatedBy = child2.children[0];
- break;
- case "IsInstanceOf":
- isInstanceOf = child2.children[0];
- break;
- }
- }
- instanceReps[child.id] = {
- type: "InstanceRep",
- id: child.id,
- name: child.name,
- isAggregatedBy: isAggregatedBy,
- isInstanceOf: isInstanceOf,
- referenceReps: {}
- };
- break;
-
- case "Instance3D":
- var isAggregatedBy;
- var isInstanceOf;
- var relativeMatrix;
- for (var j = 0, lenj = child.children.length; j < lenj; j++) {
- var child2 = child.children[j];
- switch (child2.type) {
- case "IsAggregatedBy":
- isAggregatedBy = child2.children[0];
- break;
- case "IsInstanceOf":
- isInstanceOf = child2.children[0];
- break;
- case "RelativeMatrix":
- relativeMatrix = child2.children[0];
- break;
- }
- }
- instance3Ds[child.id] = {
- type: "Instance3D",
- id: child.id,
- name: child.name,
- isAggregatedBy: isAggregatedBy,
- isInstanceOf: isInstanceOf,
- relativeMatrix: relativeMatrix,
- reference3Ds: {}
- };
- break;
- }
- }
-
- // Connect Reference3Ds to the Instance3Ds they aggregate
-
- for (var id in instance3Ds) {
- var instance3D = instance3Ds[id];
- var reference3D = reference3Ds[instance3D.isAggregatedBy];
- if (reference3D) {
- reference3D.instance3Ds[instance3D.id] = instance3D;
- } else {
- alert("foo")
- }
- }
-
- // Connect Instance3Ds to the Reference3Ds they instantiate
-
- for (var id in instance3Ds) {
- var instance3D = instance3Ds[id];
- var reference3D = reference3Ds[instance3D.isInstanceOf];
- instance3D.reference3Ds[reference3D.id] = reference3D;
- reference3D.instance3D = instance3D;
- }
-
- // Connect InstanceReps to the ReferenceReps they instantiate
-
- for (var id in instanceReps) {
- var instanceRep = instanceReps[id];
- var referenceRep = referenceReps[instanceRep.isInstanceOf];
- if (referenceRep) {
- instanceRep.referenceReps[referenceRep.id] = referenceRep;
- }
- }
-
- // Connect Reference3Ds to the InstanceReps they aggregate
-
- for (var id in instanceReps) {
- var instanceRep = instanceReps[id];
- var reference3D = reference3Ds[instanceRep.isAggregatedBy];
- if (reference3D) {
- reference3D.instanceReps[instanceRep.id] = instanceRep;
- }
- }
-
- function parseReference3D(ctx, reference3D, group) {
- //ctx.plugin.log("parseReference3D( " + reference3D.id + " )");
- for (var id in reference3D.instance3Ds) {
- parseInstance3D(ctx, reference3D.instance3Ds[id], group);
- }
- for (var id in reference3D.instanceReps) {
- parseInstanceRep(ctx, reference3D.instanceReps[id], group);
- }
- }
-
- function parseInstance3D(ctx, instance3D, group) {
- //ctx.plugin.log("parseInstance3D( " + instance3D.id + " )");
-
- if (instance3D.relativeMatrix) {
- var matrix = parseFloatArray(instance3D.relativeMatrix, 12);
- var translate = [matrix[9], matrix[10], matrix[11]];
- var mat3 = matrix.slice(0, 9); // Rotation matrix
- var mat4 = math.mat3ToMat4(mat3, math.identityMat4()); // Convert rotation matrix to 4x4
- var childGroup = new Node(ctx.modelNode, {
- position: translate
- });
- if (ctx.metaModelData) {
- ctx.metaModelData.metaObjects.push({
- id: childGroup.id,
- type: "Default",
- name: instance3D.name,
- parent: group ? group.id : ctx.modelNode.id
- });
- }
- if (group) {
- group.addChild(childGroup, true);
- } else {
- ctx.modelNode.addChild(childGroup, true);
- }
- group = childGroup;
- childGroup = new Node(ctx.modelNode, {
- matrix: mat4
- });
- if (ctx.metaModelData) {
- ctx.metaModelData.metaObjects.push({
- id: childGroup.id,
- type: "Default",
- name: instance3D.name,
- parent: group ? group.id : ctx.modelNode.id
- });
- }
- group.addChild(childGroup, true);
- group = childGroup;
- } else {
- var childGroup = new Node(ctx.modelNode, {});
- if (ctx.metaModelData) {
- ctx.metaModelData.metaObjects.push({
- id: childGroup.id,
- type: "Default",
- name: instance3D.name,
- parent: group ? group.id : ctx.modelNode.id
- });
- }
- if (group) {
- group.addChild(childGroup, true);
- } else {
- ctx.modelNode.addChild(childGroup, true);
- }
- group = childGroup;
- }
- for (var id in instance3D.reference3Ds) {
- parseReference3D(ctx, instance3D.reference3Ds[id], group);
- }
- }
-
- function parseInstanceRep(ctx, instanceRep, group) {
- //ctx.plugin.log("parseInstanceRep( " + instanceRep.id + " )");
- if (instanceRep.referenceReps) {
- for (var id in instanceRep.referenceReps) {
- var referenceRep = instanceRep.referenceReps[id];
- for (var id2 in referenceRep) {
- if (id2 === "id") {
- continue; // HACK
- }
- var meshCfg = referenceRep[id2];
- var lines = meshCfg.geometry.primitive === "lines";
- var material = lines ? ctx.modelNode._wireframeMaterial : (meshCfg.materialId ? ctx.materials[meshCfg.materialId] : null);
- var colorize = meshCfg.color;
- var mesh = new Mesh(ctx.modelNode, {
- isObject: true,
- geometry: meshCfg.geometry,
- material: material || ctx.modelNode._defaultMaterial,
- colorize: colorize,
- backfaces: false
- });
- if (ctx.metaModelData) {
- ctx.metaModelData.metaObjects.push({
- id: mesh.id,
- type: "Default",
- name: instanceRep.name,
- parent: group ? group.id : ctx.modelNode.id
- });
- }
- if (group) {
- group.addChild(mesh, true);
- } else {
- ctx.modelNode.addChild(mesh, true);
- }
- mesh.colorize = colorize; // HACK: Mesh has inherited modelNode's colorize state, so we need to restore it (we'd better not modify colorize on the modelNode).
- }
- }
- }
- }
-
- // Find the root Reference3D
-
- for (var id in reference3Ds) {
- var reference3D = reference3Ds[id];
- if (!reference3D.instance3D) {
- parseReference3D(ctx, reference3D, null); // HACK: Assuming that root has id == "1"
- ok();
- return;
- }
- }
-
- alert("No root Reference3D element found in this modelNode - can't load.");
-
- ok();
- });
- }
-
- function parseIntArray(str) {
- var parts = str.trim().split(" ");
- var result = new Int32Array(parts.length);
- for (var i = 0; i < parts.length; i++) {
- result[i] = parseInt(parts[i]);
- }
- return result;
- }
-
- function parseReferenceReps(ctx, node, ok) {
- var referenceReps = {};
- var children = node.children;
- var numToLoad = 0;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- if (child.type === "ReferenceRep") {
- numToLoad++;
- }
- }
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "ReferenceRep":
- if (child.associatedFile) {
- var src = stripURN(child.associatedFile);
- (function () {
- var childId = child.id;
- ctx.zip.getFile(src, function (xmlDoc, json) {
-
- var materialIds = xmlDoc.getElementsByTagName("MaterialId");
-
- loadCATMaterialRefDocuments(ctx, materialIds, function () {
-
- // ctx.plugin.log("reference loaded: " + src);
- var referenceRep = {
- id: childId
- };
- parse3DRepDocument(ctx, json, referenceRep);
- referenceReps[childId] = referenceRep;
- if (--numToLoad === 0) {
- ok(referenceReps);
- }
- });
- },
- function (error) {
- // TODO:
- });
- })();
- }
- break;
- }
- }
- }
-
-
- function parseDefaultView(ctx, node) {
- // ctx.plugin.log("parseDefaultView");
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Viewpoint":
- var children2 = child.children;
- ctx.modelNode.viewpoint = {};
- for (var i2 = 0, len2 = children2.length; i2 < len2; i2++) {
- var child2 = children2[i];
- switch (child2.type) {
- case "Position":
- ctx.modelNode.viewpoint.eye = parseFloatArray(child2.children[0], 3);
- break;
- case "Sight":
- ctx.modelNode.viewpoint.look = parseFloatArray(child2.children[0], 3);
- break;
- case "Up":
- ctx.modelNode.viewpoint.up = parseFloatArray(child2.children[0], 3);
- break;
- }
- }
- break;
- case "DefaultViewProperty":
- break;
- }
- }
- }
-
- function parse3DRepDocument(ctx, node, result) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "XMLRepresentation":
- parseXMLRepresentation(ctx, child, result);
- break;
- }
- }
- }
-
- function parseXMLRepresentation(ctx, node, result) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Root":
- parse3DRepRoot(ctx, child, result);
- break;
- }
- }
- }
-
- function parse3DRepRoot(ctx, node, result) {
- switch (node["xsi:type"]) {
- case "BagRepType":
- break;
- case "PolygonalRepType":
- break;
- }
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Rep":
- parse3DRepRep(ctx, child, result);
- break;
- }
- }
- }
-
- function parse3DRepRep(ctx, node, result) {
- switch (node["xsi:type"]) {
- case "BagRepType":
- break;
- case "PolygonalRepType":
- break;
- }
- var meshesResult = {
- edgeThreshold: ctx.edgeThreshold || 30,
- compressGeometry: true
- };
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Rep":
- parse3DRepRep(ctx, child, result);
- break;
- case "Edges":
- // Ignoring edges because we auto-generate our own using xeokit
- break;
- case "Faces":
- meshesResult.primitive = "triangles";
- parseFaces(ctx, child, meshesResult);
- break;
- case "VertexBuffer":
- parseVertexBuffer(ctx, child, meshesResult);
- break;
- case "SurfaceAttributes":
- parseSurfaceAttributes(ctx, child, meshesResult);
- break;
- }
- }
- if (meshesResult.positions) {
- var geometry = new ReadableGeometry(ctx.modelNode, meshesResult);
- result[geometry.id] = {
- geometry: geometry,
- color: meshesResult.color || [1.0, 1.0, 1.0, 1.0],
- materialId: meshesResult.materialId
- };
- }
- }
-
- function parseEdges(ctx, node, result) {
- result.positions = [];
- result.indices = [];
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Polyline":
- parsePolyline(ctx, child, result);
- break;
- }
- }
- }
-
- function parsePolyline(ctx, node, result) {
- var vertices = node.vertices;
- if (vertices) {
- var positions = parseFloatArray(vertices, 3);
- if (positions.length > 0) {
- var positionsOffset = result.positions.length / 3;
- for (var i = 0, len = positions.length; i < len; i++) {
- result.positions.push(positions[i]);
- }
- for (var i = 0, len = (positions.length / 3) - 1; i < len; i++) {
- result.indices.push(positionsOffset + i);
- result.indices.push(positionsOffset + i + 1);
- }
- }
- }
- }
-
- function parseFaces(ctx, node, result) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Face":
- parseFace(ctx, child, result);
- break;
- }
- }
- }
-
- function parseFace(ctx, node, result) {
- var strips = node.strips;
- if (strips) {
- // Triangle strips
- var arrays = parseIntArrays(strips);
- if (arrays.length > 0) {
- result.primitive = "triangles";
- var indices = [];
- for (var i = 0, len = arrays.length; i < len; i++) {
- var array = convertTriangleStrip(arrays[i]);
- for (var j = 0, lenj = array.length; j < lenj; j++) {
- indices.push(array[j]);
- }
- }
- result.indices = indices; // TODO
- }
- } else {
- // Triangle meshes
- var triangles = node.triangles;
- if (triangles) {
- result.primitive = "triangles";
- result.indices = parseIntArray(triangles);
- }
- }
- // Material
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "SurfaceAttributes":
- parseSurfaceAttributes(ctx, child, result);
- break;
- }
- }
- }
-
- function convertTriangleStrip(indices) {
- var ccw = false;
- var indices2 = [];
- for (var i = 0, len = indices.length; i < len - 2; i++) {
- if (ccw) {
- if (i & 1) { //
- indices2.push(indices[i]);
- indices2.push(indices[i + 1]);
- indices2.push(indices[i + 2]);
- } else {
- indices2.push(indices[i]);
- indices2.push(indices[i + 2]);
- indices2.push(indices[i + 1]);
- }
- } else {
- if (i & 1) { //
- indices2.push(indices[i]);
- indices2.push(indices[i + 2]);
- indices2.push(indices[i + 1]);
- } else {
- indices2.push(indices[i]);
- indices2.push(indices[i + 1]);
- indices2.push(indices[i + 2]);
- }
- }
- }
- return indices2;
- }
-
- function parseVertexBuffer(ctx, node, result) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Positions":
- result.positions = parseFloatArray(child.children[0], 3);
- break;
- case "Normals":
- result.normals = parseFloatArray(child.children[0], 3);
- break;
- case "TextureCoordinates": // TODO: Support dimension and channel?
- result.uv = parseFloatArray(child.children[0], 2);
- break;
- }
- }
- }
-
- function parseIntArrays(str) {
- var coordStrings = str.split(",");
- var array = [];
- for (var i = 0, len = coordStrings.length; i < len; i++) {
- var coordStr = coordStrings[i].trim();
- if (coordStr.length > 0) {
- var elemStrings = coordStr.trim().split(" ");
- var arr = new Int16Array(elemStrings.length);
- var arrIdx = 0;
- for (var j = 0, lenj = elemStrings.length; j < lenj; j++) {
- if (elemStrings[j] !== "") {
- arr[arrIdx++] = parseInt(elemStrings[j]);
- }
- }
- array.push(arr);
- }
- }
- return array;
- }
-
- function parseFloatArray(str, numElems) {
- str = str.split(",");
- var arr = new Float32Array(str.length * numElems);
- var arrIdx = 0;
- for (var i = 0, len = str.length; i < len; i++) {
- var value = str[i];
- value = value.split(" ");
- for (var j = 0, lenj = value.length; j < lenj; j++) {
- if (value[j] !== "") {
- arr[arrIdx++] = parseFloat(value[j]);
- }
- }
- }
- return arr;
- }
-
- function parseIntArray(str) {
- str = str.trim().split(" ");
- var arr = new Int32Array(str.length);
- var arrIdx = 0;
- for (var i = 0, len = str.length; i < len; i++) {
- var value = str[i];
- arr[i] = parseInt(value);
- }
- return arr;
- }
-
- function parseSurfaceAttributes(ctx, node, result) {
- result.color = [1, 1, 1, 1];
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Color":
- result.color[0] = child.red;
- result.color[1] = child.green;
- result.color[2] = child.blue;
- result.color[3] = child.alpha;
- break;
- case "MaterialApplication":
- var children2 = child.children;
- for (var j = 0, lenj = children2.length; j < lenj; j++) {
- var child2 = children2[j];
- switch (child2.type) {
- case "MaterialId":
- var materialId = getIDFromURI(child2.id);
- var material = ctx.materials[materialId];
- if (!material) {
- ctx.plugin.error("material not found: " + materialId);
- }
- result.materialId = materialId;
- break;
- }
- }
- break;
- }
- }
- }
- })();
-
- function loadCATMaterialRefDocuments(ctx, materialIds, ok) {
- var loaded = {};
-
- function load(i, done) {
- if (i >= materialIds.length) {
- ok();
- return;
- }
- var materialId = materialIds[i];
- var src = materialId.id;
- var colonIdx = src.lastIndexOf(":");
- if (colonIdx > 0) {
- src = src.substring(colonIdx + 1);
- }
- var hashIdx = src.lastIndexOf("#");
- if (hashIdx > 0) {
- src = src.substring(0, hashIdx);
- }
- if (!loaded[src]) {
- loadCATMaterialRefDocument(ctx, src, function () {
- loaded[src] = true;
- load(i + 1, done);
- });
- } else {
- load(i + 1, done);
- }
- }
-
- load(0, ok);
- }
-
- function loadCATMaterialRefDocument(ctx, src, ok) { // Loads CATMaterialRef.3dxml
- ctx.zip.getFile(src, function (xmlDoc, json) {
- parseCATMaterialRefDocument(ctx, json, ok);
- });
- }
-
- function parseCATMaterialRefDocument(ctx, node, ok) { // Parse CATMaterialRef.3dxml
- // ctx.plugin.log("parseCATMaterialRefDocument");
- var children = node.children;
- var child;
- for (var i = 0, len = children.length; i < len; i++) {
- child = children[i];
- if (child.type === "Model_3dxml") {
- parseModel_3dxml(ctx, child, ok);
- }
- }
- }
-
- function parseModel_3dxml(ctx, node, ok) { // Parse CATMaterialRef.3dxml
- // ctx.plugin.log("parseModel_3dxml");
- var children = node.children;
- var child;
- for (var i = 0, len = children.length; i < len; i++) {
- child = children[i];
- if (child.type === "CATMaterialRef") {
- parseCATMaterialRef(ctx, child, ok);
- }
- }
- }
-
- function parseCATMaterialRef(ctx, node, ok) {
- var domainToReferenceMap = {};
- var materials = {};
- var result = {};
- var children = node.children;
- var child;
- var numToLoad = 0;
- for (var j = 0, lenj = children.length; j < lenj; j++) {
- var child2 = children[j];
- switch (child2.type) {
- case "MaterialDomainInstance":
- var isAggregatedBy;
- var isInstanceOf;
- for (var k = 0, lenk = child2.children.length; k < lenk; k++) {
- var child3 = child2.children[k];
- switch (child3.type) {
- case "IsAggregatedBy":
- isAggregatedBy = child3.children[0];
- break;
- case "IsInstanceOf":
- isInstanceOf = child3.children[0];
- break;
- }
- }
- domainToReferenceMap[isInstanceOf] = isAggregatedBy;
- break;
- }
- }
- for (var j = 0, lenj = children.length; j < lenj; j++) {
- var child2 = children[j];
- switch (child2.type) {
- case "MaterialDomain":
- numToLoad++;
- break;
- }
- }
- // Now load them
- for (var j = 0, lenj = children.length; j < lenj; j++) {
- var child2 = children[j];
- switch (child2.type) {
- case "MaterialDomain":
- if (child2.associatedFile) {
- (function () {
- var childId = child2.id;
- var src = stripURN(child2.associatedFile);
- ctx.zip.getFile(src, function (xmlDoc, json) {
- // ctx.plugin.log("Material def loaded: " + src);
- ctx.materials[domainToReferenceMap[childId]] = parseMaterialDefDocument(ctx, json);
-
- if (--numToLoad === 0) {
- // console.log("All ReferenceReps loaded.");
- ok();
- }
- },
- function (error) {
- // TODO:
- });
- })();
- }
- break;
- }
- }
- }
-
- function parseMaterialDefDocument(ctx, node) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "Osm":
- return parseMaterialDefDocumentOsm(ctx, child);
- break;
- }
- }
- }
-
- function parseMaterialDefDocumentOsm(ctx, node) {
- var children = node.children;
- for (var i = 0, len = children.length; i < len; i++) {
- var child = children[i];
- switch (child.type) {
- case "RenderingRootFeature":
- //..
- break;
- case "Feature":
-
- if (child.Alias === "RenderingFeature") {
- // Parse the coefficients, then parse the colors, scaling those by their coefficients.
- var coeffs = {};
- var materialCfg = {};
- var children2 = child.children;
- var j;
- var lenj;
- var child2;
- for (j = 0, lenj = children2.length; j < lenj; j++) {
- child2 = children2[j];
- switch (child2.Name) {
- case "AmbientCoef":
- coeffs.ambient = parseFloat(child2.Value);
- break;
- case "DiffuseCoef":
- coeffs.diffuse = parseFloat(child2.Value);
- break;
- case "EmissiveCoef":
- coeffs.emissive = parseFloat(child2.Value);
- break;
- case "SpecularExponent":
- coeffs.specular = parseFloat(child2.Value);
- break;
- }
- }
- for (j = 0, lenj = children2.length; j < lenj; j++) {
- child2 = children2[j];
- switch (child2.Name) {
- case "AmbientColor":
- materialCfg.ambient = parseRGB(child2.Value, coeffs.ambient);
- break;
- case "DiffuseColor":
- materialCfg.diffuse = parseRGB(child2.Value, coeffs.diffuse);
- break;
- case "EmissiveColor":
- materialCfg.emissive = parseRGB(child2.Value, coeffs.emissive);
- break;
- case "SpecularColor":
- materialCfg.specular = parseRGB(child2.Value, coeffs.specular);
- break;
- case "Transparency":
- var alpha = 1.0 - parseFloat(child2.Value); // GOTCHA: Degree of transparency, not degree of opacity
- if (alpha < 1.0) {
- materialCfg.alpha = alpha;
- materialCfg.alphaMode = "blend";
- }
- break;
- }
- }
-
- var material;
-
- switch (ctx.materialType) {
- case "MetallicMaterial":
- material = new MetallicMaterial(ctx.modelNode, {
- baseColor: materialCfg.diffuse,
- metallic: 0.7,
- roughness: 0.5,
- emissive: materialCfg.emissive,
- alpha: materialCfg.alpha,
- alphaMode: materialCfg.alphaMode
- });
- break;
-
- case "SpecularMaterial":
- material = new SpecularMaterial(ctx.modelNode, {
- diffuse: materialCfg.diffuse,
- specular: materialCfg.specular,
- glossiness: 0.5,
- emissive: materialCfg.emissive,
- alpha: materialCfg.alpha,
- alphaMode: materialCfg.alphaMode
- });
- break;
-
- default:
- material = new PhongMaterial(ctx.modelNode, {
- reflectivity: 0.5,
- ambient: materialCfg.ambient,
- diffuse: materialCfg.diffuse,
- specular: materialCfg.specular,
- // shininess: node.shine,
- emissive: materialCfg.emissive,
- alphaMode: materialCfg.alphaMode,
- alpha: node.alpha
- });
- }
- return material;
- }
- break;
- }
- }
- }
-
- function parseRGB(str, coeff) {
- coeff = (coeff !== undefined) ? coeff : 0.5;
- var openBracketIndex = str.indexOf("[");
- var closeBracketIndex = str.indexOf("]");
- str = str.substring(openBracketIndex + 1, closeBracketIndex - openBracketIndex);
- str = str.split(",");
- var arr = new Float32Array(str.length);
- var arrIdx = 0;
- for (var i = 0, len = str.length; i < len; i++) {
- var value = str[i];
- value = value.trim().split(" ");
- for (var j = 0, lenj = value.length; j < lenj; j++) {
- if (value[j] !== "") {
- arr[arrIdx++] = parseFloat(value[j]) * coeff;
- }
- }
- }
- return arr;
- }
-
-
- //----------------------------------------------------------------------------------------------------
-
- /**
- * Wraps zip.js to provide an in-memory ZIP archive representing the 3DXML file bundle.
- *
- * Allows us to pluck each file from it as XML and JSON.
- *
- * @constructor
- */
- var ZIP = function () {
-
- var reader;
- var files = {};
-
- /**
- Loads this ZIP
-
- @param src
- @param ok
- @param error
- */
- this.load = function (src, ok, error) {
- var self = this;
- zip.createReader(new zip.HttpReader(src), function (reader) {
- reader.getEntries(function (entries) {
- if (entries.length > 0) {
- for (var i = 0, len = entries.length; i < len; i++) {
- var entry = entries[i];
- files[entry.filename] = entry;
- }
- }
- ok();
- });
- }, error);
- };
-
- /**
- Gets a file as XML and JSON from this ZIP
- @param src
- @param ok
- @param error
- */
- this.getFile = function (src, ok, error) {
- var entry = files[src];
- if (!entry) {
- var errMsg = "ZIP entry not found: " + src;
- console.error(errMsg);
- if (error) {
- error(errMsg);
- }
- return;
- }
- entry.getData(new zip.TextWriter(), function (text) {
-
- // Parse to XML
- var parser = new DOMParser();
- var xmlDoc = parser.parseFromString(text, "text/xml");
-
- // Parse to JSON
- var json = xmlToJSON(xmlDoc, {});
-
- ok(xmlDoc, json);
- });
- };
-
- function xmlToJSON(node, attributeRenamer) {
- if (node.nodeType === node.TEXT_NODE) {
- var v = node.nodeValue;
- if (v.match(/^\s+$/) === null) {
- return v;
- }
- } else if (node.nodeType === node.ELEMENT_NODE ||
- node.nodeType === node.DOCUMENT_NODE) {
- var json = {type: node.nodeName, children: []};
- if (node.nodeType === node.ELEMENT_NODE) {
- for (var j = 0; j < node.attributes.length; j++) {
- var attribute = node.attributes[j];
- var nm = attributeRenamer[attribute.nodeName] || attribute.nodeName;
- json[nm] = attribute.nodeValue;
- }
- }
- for (var i = 0; i < node.childNodes.length; i++) {
- var item = node.childNodes[i];
- var j = xmlToJSON(item, attributeRenamer);
- if (j) json.children.push(j);
- }
- return json;
- }
- }
-
- /**
- Disposes of this ZIP
- */
- this.destroy = function () {
- reader.close(function () {
- // onclose callback
- });
- };
- };
-
- function
-
- loadZIP(src, ok, err) {
- var zip = new ZIP();
- zip.load(src, function () {
- ok(zip);
- }, function (errMsg) {
- err("Error loading ZIP archive: " + errMsg);
- })
- }
-
- function
-
- stripURN(str) {
- var subStr = "urn:3DXML:";
- return (str.indexOf(subStr) === 0) ? str.substring(subStr.length) : str;
- }
-
-
- function
-
- getIDFromURI(str) {
- var hashIdx = str.lastIndexOf("#");
- return hashIdx !== -1 ? str.substring(hashIdx + 1) : str;
- }
-
- export {XML3DSceneGraphLoader};