three-stdlib
Version:
stand-alone library of threejs examples
1,483 lines • 83.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
const TGALoader = require("./TGALoader.cjs");
const uv1 = require("../_polyfill/uv1.cjs");
class ColladaLoader extends THREE.Loader {
constructor(manager) {
super(manager);
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const path = scope.path === "" ? THREE.LoaderUtils.extractUrlBase(url) : scope.path;
const loader = new THREE.FileLoader(scope.manager);
loader.setPath(scope.path);
loader.setRequestHeader(scope.requestHeader);
loader.setWithCredentials(scope.withCredentials);
loader.load(
url,
function(text) {
try {
onLoad(scope.parse(text, path));
} catch (e) {
if (onError) {
onError(e);
} else {
console.error(e);
}
scope.manager.itemError(url);
}
},
onProgress,
onError
);
}
parse(text, path) {
function getElementsByTagName(xml2, name) {
const array = [];
const childNodes = xml2.childNodes;
for (let i = 0, l = childNodes.length; i < l; i++) {
const child = childNodes[i];
if (child.nodeName === name) {
array.push(child);
}
}
return array;
}
function parseStrings(text2) {
if (text2.length === 0)
return [];
const parts = text2.trim().split(/\s+/);
const array = new Array(parts.length);
for (let i = 0, l = parts.length; i < l; i++) {
array[i] = parts[i];
}
return array;
}
function parseFloats(text2) {
if (text2.length === 0)
return [];
const parts = text2.trim().split(/\s+/);
const array = new Array(parts.length);
for (let i = 0, l = parts.length; i < l; i++) {
array[i] = parseFloat(parts[i]);
}
return array;
}
function parseInts(text2) {
if (text2.length === 0)
return [];
const parts = text2.trim().split(/\s+/);
const array = new Array(parts.length);
for (let i = 0, l = parts.length; i < l; i++) {
array[i] = parseInt(parts[i]);
}
return array;
}
function parseId(text2) {
return text2.substring(1);
}
function generateId() {
return "three_default_" + count++;
}
function isEmpty(object) {
return Object.keys(object).length === 0;
}
function parseAsset(xml2) {
return {
unit: parseAssetUnit(getElementsByTagName(xml2, "unit")[0]),
upAxis: parseAssetUpAxis(getElementsByTagName(xml2, "up_axis")[0])
};
}
function parseAssetUnit(xml2) {
if (xml2 !== void 0 && xml2.hasAttribute("meter") === true) {
return parseFloat(xml2.getAttribute("meter"));
} else {
return 1;
}
}
function parseAssetUpAxis(xml2) {
return xml2 !== void 0 ? xml2.textContent : "Y_UP";
}
function parseLibrary(xml2, libraryName, nodeName, parser) {
const library2 = getElementsByTagName(xml2, libraryName)[0];
if (library2 !== void 0) {
const elements = getElementsByTagName(library2, nodeName);
for (let i = 0; i < elements.length; i++) {
parser(elements[i]);
}
}
}
function buildLibrary(data, builder) {
for (const name in data) {
const object = data[name];
object.build = builder(data[name]);
}
}
function getBuild(data, builder) {
if (data.build !== void 0)
return data.build;
data.build = builder(data);
return data.build;
}
function parseAnimation(xml2) {
const data = {
sources: {},
samplers: {},
channels: {}
};
let hasChildren = false;
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
let id;
switch (child.nodeName) {
case "source":
id = child.getAttribute("id");
data.sources[id] = parseSource(child);
break;
case "sampler":
id = child.getAttribute("id");
data.samplers[id] = parseAnimationSampler(child);
break;
case "channel":
id = child.getAttribute("target");
data.channels[id] = parseAnimationChannel(child);
break;
case "animation":
parseAnimation(child);
hasChildren = true;
break;
default:
console.log(child);
}
}
if (hasChildren === false) {
library.animations[xml2.getAttribute("id") || THREE.MathUtils.generateUUID()] = data;
}
}
function parseAnimationSampler(xml2) {
const data = {
inputs: {}
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "input":
const id = parseId(child.getAttribute("source"));
const semantic = child.getAttribute("semantic");
data.inputs[semantic] = id;
break;
}
}
return data;
}
function parseAnimationChannel(xml2) {
const data = {};
const target = xml2.getAttribute("target");
let parts = target.split("/");
const id = parts.shift();
let sid = parts.shift();
const arraySyntax = sid.indexOf("(") !== -1;
const memberSyntax = sid.indexOf(".") !== -1;
if (memberSyntax) {
parts = sid.split(".");
sid = parts.shift();
data.member = parts.shift();
} else if (arraySyntax) {
const indices = sid.split("(");
sid = indices.shift();
for (let i = 0; i < indices.length; i++) {
indices[i] = parseInt(indices[i].replace(/\)/, ""));
}
data.indices = indices;
}
data.id = id;
data.sid = sid;
data.arraySyntax = arraySyntax;
data.memberSyntax = memberSyntax;
data.sampler = parseId(xml2.getAttribute("source"));
return data;
}
function buildAnimation(data) {
const tracks = [];
const channels = data.channels;
const samplers = data.samplers;
const sources = data.sources;
for (const target in channels) {
if (channels.hasOwnProperty(target)) {
const channel = channels[target];
const sampler = samplers[channel.sampler];
const inputId = sampler.inputs.INPUT;
const outputId = sampler.inputs.OUTPUT;
const inputSource = sources[inputId];
const outputSource = sources[outputId];
const animation = buildAnimationChannel(channel, inputSource, outputSource);
createKeyframeTracks(animation, tracks);
}
}
return tracks;
}
function getAnimation(id) {
return getBuild(library.animations[id], buildAnimation);
}
function buildAnimationChannel(channel, inputSource, outputSource) {
const node = library.nodes[channel.id];
const object3D = getNode(node.id);
const transform = node.transforms[channel.sid];
const defaultMatrix = node.matrix.clone().transpose();
let time, stride;
let i, il, j, jl;
const data = {};
switch (transform) {
case "matrix":
for (i = 0, il = inputSource.array.length; i < il; i++) {
time = inputSource.array[i];
stride = i * outputSource.stride;
if (data[time] === void 0)
data[time] = {};
if (channel.arraySyntax === true) {
const value = outputSource.array[stride];
const index = channel.indices[0] + 4 * channel.indices[1];
data[time][index] = value;
} else {
for (j = 0, jl = outputSource.stride; j < jl; j++) {
data[time][j] = outputSource.array[stride + j];
}
}
}
break;
case "translate":
console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform);
break;
case "rotate":
console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform);
break;
case "scale":
console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform);
break;
}
const keyframes = prepareAnimationData(data, defaultMatrix);
const animation = {
name: object3D.uuid,
keyframes
};
return animation;
}
function prepareAnimationData(data, defaultMatrix) {
const keyframes = [];
for (const time in data) {
keyframes.push({ time: parseFloat(time), value: data[time] });
}
keyframes.sort(ascending);
for (let i = 0; i < 16; i++) {
transformAnimationData(keyframes, i, defaultMatrix.elements[i]);
}
return keyframes;
function ascending(a, b) {
return a.time - b.time;
}
}
const position = new THREE.Vector3();
const scale = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
function createKeyframeTracks(animation, tracks) {
const keyframes = animation.keyframes;
const name = animation.name;
const times = [];
const positionData = [];
const quaternionData = [];
const scaleData = [];
for (let i = 0, l = keyframes.length; i < l; i++) {
const keyframe = keyframes[i];
const time = keyframe.time;
const value = keyframe.value;
matrix.fromArray(value).transpose();
matrix.decompose(position, quaternion, scale);
times.push(time);
positionData.push(position.x, position.y, position.z);
quaternionData.push(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
scaleData.push(scale.x, scale.y, scale.z);
}
if (positionData.length > 0)
tracks.push(new THREE.VectorKeyframeTrack(name + ".position", times, positionData));
if (quaternionData.length > 0) {
tracks.push(new THREE.QuaternionKeyframeTrack(name + ".quaternion", times, quaternionData));
}
if (scaleData.length > 0)
tracks.push(new THREE.VectorKeyframeTrack(name + ".scale", times, scaleData));
return tracks;
}
function transformAnimationData(keyframes, property, defaultValue) {
let keyframe;
let empty = true;
let i, l;
for (i = 0, l = keyframes.length; i < l; i++) {
keyframe = keyframes[i];
if (keyframe.value[property] === void 0) {
keyframe.value[property] = null;
} else {
empty = false;
}
}
if (empty === true) {
for (i = 0, l = keyframes.length; i < l; i++) {
keyframe = keyframes[i];
keyframe.value[property] = defaultValue;
}
} else {
createMissingKeyframes(keyframes, property);
}
}
function createMissingKeyframes(keyframes, property) {
let prev, next;
for (let i = 0, l = keyframes.length; i < l; i++) {
const keyframe = keyframes[i];
if (keyframe.value[property] === null) {
prev = getPrev(keyframes, i, property);
next = getNext(keyframes, i, property);
if (prev === null) {
keyframe.value[property] = next.value[property];
continue;
}
if (next === null) {
keyframe.value[property] = prev.value[property];
continue;
}
interpolate(keyframe, prev, next, property);
}
}
}
function getPrev(keyframes, i, property) {
while (i >= 0) {
const keyframe = keyframes[i];
if (keyframe.value[property] !== null)
return keyframe;
i--;
}
return null;
}
function getNext(keyframes, i, property) {
while (i < keyframes.length) {
const keyframe = keyframes[i];
if (keyframe.value[property] !== null)
return keyframe;
i++;
}
return null;
}
function interpolate(key, prev, next, property) {
if (next.time - prev.time === 0) {
key.value[property] = prev.value[property];
return;
}
key.value[property] = (key.time - prev.time) * (next.value[property] - prev.value[property]) / (next.time - prev.time) + prev.value[property];
}
function parseAnimationClip(xml2) {
const data = {
name: xml2.getAttribute("id") || "default",
start: parseFloat(xml2.getAttribute("start") || 0),
end: parseFloat(xml2.getAttribute("end") || 0),
animations: []
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "instance_animation":
data.animations.push(parseId(child.getAttribute("url")));
break;
}
}
library.clips[xml2.getAttribute("id")] = data;
}
function buildAnimationClip(data) {
const tracks = [];
const name = data.name;
const duration = data.end - data.start || -1;
const animations2 = data.animations;
for (let i = 0, il = animations2.length; i < il; i++) {
const animationTracks = getAnimation(animations2[i]);
for (let j = 0, jl = animationTracks.length; j < jl; j++) {
tracks.push(animationTracks[j]);
}
}
return new THREE.AnimationClip(name, duration, tracks);
}
function getAnimationClip(id) {
return getBuild(library.clips[id], buildAnimationClip);
}
function parseController(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "skin":
data.id = parseId(child.getAttribute("source"));
data.skin = parseSkin(child);
break;
case "morph":
data.id = parseId(child.getAttribute("source"));
console.warn("THREE.ColladaLoader: Morph target animation not supported yet.");
break;
}
}
library.controllers[xml2.getAttribute("id")] = data;
}
function parseSkin(xml2) {
const data = {
sources: {}
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "bind_shape_matrix":
data.bindShapeMatrix = parseFloats(child.textContent);
break;
case "source":
const id = child.getAttribute("id");
data.sources[id] = parseSource(child);
break;
case "joints":
data.joints = parseJoints(child);
break;
case "vertex_weights":
data.vertexWeights = parseVertexWeights(child);
break;
}
}
return data;
}
function parseJoints(xml2) {
const data = {
inputs: {}
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "input":
const semantic = child.getAttribute("semantic");
const id = parseId(child.getAttribute("source"));
data.inputs[semantic] = id;
break;
}
}
return data;
}
function parseVertexWeights(xml2) {
const data = {
inputs: {}
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "input":
const semantic = child.getAttribute("semantic");
const id = parseId(child.getAttribute("source"));
const offset = parseInt(child.getAttribute("offset"));
data.inputs[semantic] = { id, offset };
break;
case "vcount":
data.vcount = parseInts(child.textContent);
break;
case "v":
data.v = parseInts(child.textContent);
break;
}
}
return data;
}
function buildController(data) {
const build = {
id: data.id
};
const geometry = library.geometries[build.id];
if (data.skin !== void 0) {
build.skin = buildSkin(data.skin);
geometry.sources.skinIndices = build.skin.indices;
geometry.sources.skinWeights = build.skin.weights;
}
return build;
}
function buildSkin(data) {
const BONE_LIMIT = 4;
const build = {
joints: [],
// this must be an array to preserve the joint order
indices: {
array: [],
stride: BONE_LIMIT
},
weights: {
array: [],
stride: BONE_LIMIT
}
};
const sources = data.sources;
const vertexWeights = data.vertexWeights;
const vcount = vertexWeights.vcount;
const v = vertexWeights.v;
const jointOffset = vertexWeights.inputs.JOINT.offset;
const weightOffset = vertexWeights.inputs.WEIGHT.offset;
const jointSource = data.sources[data.joints.inputs.JOINT];
const inverseSource = data.sources[data.joints.inputs.INV_BIND_MATRIX];
const weights = sources[vertexWeights.inputs.WEIGHT.id].array;
let stride = 0;
let i, j, l;
for (i = 0, l = vcount.length; i < l; i++) {
const jointCount = vcount[i];
const vertexSkinData = [];
for (j = 0; j < jointCount; j++) {
const skinIndex = v[stride + jointOffset];
const weightId = v[stride + weightOffset];
const skinWeight = weights[weightId];
vertexSkinData.push({ index: skinIndex, weight: skinWeight });
stride += 2;
}
vertexSkinData.sort(descending);
for (j = 0; j < BONE_LIMIT; j++) {
const d = vertexSkinData[j];
if (d !== void 0) {
build.indices.array.push(d.index);
build.weights.array.push(d.weight);
} else {
build.indices.array.push(0);
build.weights.array.push(0);
}
}
}
if (data.bindShapeMatrix) {
build.bindMatrix = new THREE.Matrix4().fromArray(data.bindShapeMatrix).transpose();
} else {
build.bindMatrix = new THREE.Matrix4().identity();
}
for (i = 0, l = jointSource.array.length; i < l; i++) {
const name = jointSource.array[i];
const boneInverse = new THREE.Matrix4().fromArray(inverseSource.array, i * inverseSource.stride).transpose();
build.joints.push({ name, boneInverse });
}
return build;
function descending(a, b) {
return b.weight - a.weight;
}
}
function getController(id) {
return getBuild(library.controllers[id], buildController);
}
function parseImage(xml2) {
const data = {
init_from: getElementsByTagName(xml2, "init_from")[0].textContent
};
library.images[xml2.getAttribute("id")] = data;
}
function buildImage(data) {
if (data.build !== void 0)
return data.build;
return data.init_from;
}
function getImage(id) {
const data = library.images[id];
if (data !== void 0) {
return getBuild(data, buildImage);
}
console.warn("THREE.ColladaLoader: Couldn't find image with ID:", id);
return null;
}
function parseEffect(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "profile_COMMON":
data.profile = parseEffectProfileCOMMON(child);
break;
}
}
library.effects[xml2.getAttribute("id")] = data;
}
function parseEffectProfileCOMMON(xml2) {
const data = {
surfaces: {},
samplers: {}
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "newparam":
parseEffectNewparam(child, data);
break;
case "technique":
data.technique = parseEffectTechnique(child);
break;
case "extra":
data.extra = parseEffectExtra(child);
break;
}
}
return data;
}
function parseEffectNewparam(xml2, data) {
const sid = xml2.getAttribute("sid");
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "surface":
data.surfaces[sid] = parseEffectSurface(child);
break;
case "sampler2D":
data.samplers[sid] = parseEffectSampler(child);
break;
}
}
}
function parseEffectSurface(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "init_from":
data.init_from = child.textContent;
break;
}
}
return data;
}
function parseEffectSampler(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "source":
data.source = child.textContent;
break;
}
}
return data;
}
function parseEffectTechnique(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "constant":
case "lambert":
case "blinn":
case "phong":
data.type = child.nodeName;
data.parameters = parseEffectParameters(child);
break;
case "extra":
data.extra = parseEffectExtra(child);
break;
}
}
return data;
}
function parseEffectParameters(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "emission":
case "diffuse":
case "specular":
case "bump":
case "ambient":
case "shininess":
case "transparency":
data[child.nodeName] = parseEffectParameter(child);
break;
case "transparent":
data[child.nodeName] = {
opaque: child.hasAttribute("opaque") ? child.getAttribute("opaque") : "A_ONE",
data: parseEffectParameter(child)
};
break;
}
}
return data;
}
function parseEffectParameter(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "color":
data[child.nodeName] = parseFloats(child.textContent);
break;
case "float":
data[child.nodeName] = parseFloat(child.textContent);
break;
case "texture":
data[child.nodeName] = { id: child.getAttribute("texture"), extra: parseEffectParameterTexture(child) };
break;
}
}
return data;
}
function parseEffectParameterTexture(xml2) {
const data = {
technique: {}
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "extra":
parseEffectParameterTextureExtra(child, data);
break;
}
}
return data;
}
function parseEffectParameterTextureExtra(xml2, data) {
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "technique":
parseEffectParameterTextureExtraTechnique(child, data);
break;
}
}
}
function parseEffectParameterTextureExtraTechnique(xml2, data) {
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "repeatU":
case "repeatV":
case "offsetU":
case "offsetV":
data.technique[child.nodeName] = parseFloat(child.textContent);
break;
case "wrapU":
case "wrapV":
if (child.textContent.toUpperCase() === "TRUE") {
data.technique[child.nodeName] = 1;
} else if (child.textContent.toUpperCase() === "FALSE") {
data.technique[child.nodeName] = 0;
} else {
data.technique[child.nodeName] = parseInt(child.textContent);
}
break;
case "bump":
data[child.nodeName] = parseEffectExtraTechniqueBump(child);
break;
}
}
}
function parseEffectExtra(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "technique":
data.technique = parseEffectExtraTechnique(child);
break;
}
}
return data;
}
function parseEffectExtraTechnique(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "double_sided":
data[child.nodeName] = parseInt(child.textContent);
break;
case "bump":
data[child.nodeName] = parseEffectExtraTechniqueBump(child);
break;
}
}
return data;
}
function parseEffectExtraTechniqueBump(xml2) {
var data = {};
for (var i = 0, l = xml2.childNodes.length; i < l; i++) {
var child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "texture":
data[child.nodeName] = {
id: child.getAttribute("texture"),
texcoord: child.getAttribute("texcoord"),
extra: parseEffectParameterTexture(child)
};
break;
}
}
return data;
}
function buildEffect(data) {
return data;
}
function getEffect(id) {
return getBuild(library.effects[id], buildEffect);
}
function parseMaterial(xml2) {
const data = {
name: xml2.getAttribute("name")
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "instance_effect":
data.url = parseId(child.getAttribute("url"));
break;
}
}
library.materials[xml2.getAttribute("id")] = data;
}
function getTextureLoader(image) {
let loader;
let extension = image.slice((image.lastIndexOf(".") - 1 >>> 0) + 2);
extension = extension.toLowerCase();
switch (extension) {
case "tga":
loader = tgaLoader;
break;
default:
loader = textureLoader;
}
return loader;
}
function buildMaterial(data) {
const effect = getEffect(data.url);
const technique = effect.profile.technique;
let material;
switch (technique.type) {
case "phong":
case "blinn":
material = new THREE.MeshPhongMaterial();
break;
case "lambert":
material = new THREE.MeshLambertMaterial();
break;
default:
material = new THREE.MeshBasicMaterial();
break;
}
material.name = data.name || "";
function getTexture(textureObject) {
const sampler = effect.profile.samplers[textureObject.id];
let image = null;
if (sampler !== void 0) {
const surface = effect.profile.surfaces[sampler.source];
image = getImage(surface.init_from);
} else {
console.warn("THREE.ColladaLoader: Undefined sampler. Access image directly (see #12530).");
image = getImage(textureObject.id);
}
if (image !== null) {
const loader = getTextureLoader(image);
if (loader !== void 0) {
const texture = loader.load(image);
const extra = textureObject.extra;
if (extra !== void 0 && extra.technique !== void 0 && isEmpty(extra.technique) === false) {
const technique2 = extra.technique;
texture.wrapS = technique2.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
texture.wrapT = technique2.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
texture.offset.set(technique2.offsetU || 0, technique2.offsetV || 0);
texture.repeat.set(technique2.repeatU || 1, technique2.repeatV || 1);
} else {
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
}
return texture;
} else {
console.warn("THREE.ColladaLoader: Loader for texture %s not found.", image);
return null;
}
} else {
console.warn("THREE.ColladaLoader: Couldn't create texture with ID:", textureObject.id);
return null;
}
}
const parameters = technique.parameters;
for (const key in parameters) {
const parameter = parameters[key];
switch (key) {
case "diffuse":
if (parameter.color)
material.color.fromArray(parameter.color);
if (parameter.texture)
material.map = getTexture(parameter.texture);
break;
case "specular":
if (parameter.color && material.specular)
material.specular.fromArray(parameter.color);
if (parameter.texture)
material.specularMap = getTexture(parameter.texture);
break;
case "bump":
if (parameter.texture)
material.normalMap = getTexture(parameter.texture);
break;
case "ambient":
if (parameter.texture)
material.lightMap = getTexture(parameter.texture);
break;
case "shininess":
if (parameter.float && material.shininess)
material.shininess = parameter.float;
break;
case "emission":
if (parameter.color && material.emissive)
material.emissive.fromArray(parameter.color);
if (parameter.texture)
material.emissiveMap = getTexture(parameter.texture);
break;
}
}
let transparent = parameters["transparent"];
let transparency = parameters["transparency"];
if (transparency === void 0 && transparent) {
transparency = {
float: 1
};
}
if (transparent === void 0 && transparency) {
transparent = {
opaque: "A_ONE",
data: {
color: [1, 1, 1, 1]
}
};
}
if (transparent && transparency) {
if (transparent.data.texture) {
material.transparent = true;
} else {
const color = transparent.data.color;
switch (transparent.opaque) {
case "A_ONE":
material.opacity = color[3] * transparency.float;
break;
case "RGB_ZERO":
material.opacity = 1 - color[0] * transparency.float;
break;
case "A_ZERO":
material.opacity = 1 - color[3] * transparency.float;
break;
case "RGB_ONE":
material.opacity = color[0] * transparency.float;
break;
default:
console.warn('THREE.ColladaLoader: Invalid opaque type "%s" of transparent tag.', transparent.opaque);
}
if (material.opacity < 1)
material.transparent = true;
}
}
if (technique.extra !== void 0 && technique.extra.technique !== void 0) {
const techniques = technique.extra.technique;
for (const k in techniques) {
const v = techniques[k];
switch (k) {
case "double_sided":
material.side = v === 1 ? THREE.DoubleSide : THREE.FrontSide;
break;
case "bump":
material.normalMap = getTexture(v.texture);
material.normalScale = new THREE.Vector2(1, 1);
break;
}
}
}
return material;
}
function getMaterial(id) {
return getBuild(library.materials[id], buildMaterial);
}
function parseCamera(xml2) {
const data = {
name: xml2.getAttribute("name")
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "optics":
data.optics = parseCameraOptics(child);
break;
}
}
library.cameras[xml2.getAttribute("id")] = data;
}
function parseCameraOptics(xml2) {
for (let i = 0; i < xml2.childNodes.length; i++) {
const child = xml2.childNodes[i];
switch (child.nodeName) {
case "technique_common":
return parseCameraTechnique(child);
}
}
return {};
}
function parseCameraTechnique(xml2) {
const data = {};
for (let i = 0; i < xml2.childNodes.length; i++) {
const child = xml2.childNodes[i];
switch (child.nodeName) {
case "perspective":
case "orthographic":
data.technique = child.nodeName;
data.parameters = parseCameraParameters(child);
break;
}
}
return data;
}
function parseCameraParameters(xml2) {
const data = {};
for (let i = 0; i < xml2.childNodes.length; i++) {
const child = xml2.childNodes[i];
switch (child.nodeName) {
case "xfov":
case "yfov":
case "xmag":
case "ymag":
case "znear":
case "zfar":
case "aspect_ratio":
data[child.nodeName] = parseFloat(child.textContent);
break;
}
}
return data;
}
function buildCamera(data) {
let camera;
switch (data.optics.technique) {
case "perspective":
camera = new THREE.PerspectiveCamera(
data.optics.parameters.yfov,
data.optics.parameters.aspect_ratio,
data.optics.parameters.znear,
data.optics.parameters.zfar
);
break;
case "orthographic":
let ymag = data.optics.parameters.ymag;
let xmag = data.optics.parameters.xmag;
const aspectRatio = data.optics.parameters.aspect_ratio;
xmag = xmag === void 0 ? ymag * aspectRatio : xmag;
ymag = ymag === void 0 ? xmag / aspectRatio : ymag;
xmag *= 0.5;
ymag *= 0.5;
camera = new THREE.OrthographicCamera(
-xmag,
xmag,
ymag,
-ymag,
// left, right, top, bottom
data.optics.parameters.znear,
data.optics.parameters.zfar
);
break;
default:
camera = new THREE.PerspectiveCamera();
break;
}
camera.name = data.name || "";
return camera;
}
function getCamera(id) {
const data = library.cameras[id];
if (data !== void 0) {
return getBuild(data, buildCamera);
}
console.warn("THREE.ColladaLoader: Couldn't find camera with ID:", id);
return null;
}
function parseLight(xml2) {
let data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "technique_common":
data = parseLightTechnique(child);
break;
}
}
library.lights[xml2.getAttribute("id")] = data;
}
function parseLightTechnique(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "directional":
case "point":
case "spot":
case "ambient":
data.technique = child.nodeName;
data.parameters = parseLightParameters(child);
}
}
return data;
}
function parseLightParameters(xml2) {
const data = {};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "color":
const array = parseFloats(child.textContent);
data.color = new THREE.Color().fromArray(array);
break;
case "falloff_angle":
data.falloffAngle = parseFloat(child.textContent);
break;
case "quadratic_attenuation":
const f = parseFloat(child.textContent);
data.distance = f ? Math.sqrt(1 / f) : 0;
break;
}
}
return data;
}
function buildLight(data) {
let light;
switch (data.technique) {
case "directional":
light = new THREE.DirectionalLight();
break;
case "point":
light = new THREE.PointLight();
break;
case "spot":
light = new THREE.SpotLight();
break;
case "ambient":
light = new THREE.AmbientLight();
break;
}
if (data.parameters.color)
light.color.copy(data.parameters.color);
if (data.parameters.distance)
light.distance = data.parameters.distance;
return light;
}
function getLight(id) {
const data = library.lights[id];
if (data !== void 0) {
return getBuild(data, buildLight);
}
console.warn("THREE.ColladaLoader: Couldn't find light with ID:", id);
return null;
}
function parseGeometry(xml2) {
const data = {
name: xml2.getAttribute("name"),
sources: {},
vertices: {},
primitives: []
};
const mesh = getElementsByTagName(xml2, "mesh")[0];
if (mesh === void 0)
return;
for (let i = 0; i < mesh.childNodes.length; i++) {
const child = mesh.childNodes[i];
if (child.nodeType !== 1)
continue;
const id = child.getAttribute("id");
switch (child.nodeName) {
case "source":
data.sources[id] = parseSource(child);
break;
case "vertices":
data.vertices = parseGeometryVertices(child);
break;
case "polygons":
console.warn("THREE.ColladaLoader: Unsupported primitive type: ", child.nodeName);
break;
case "lines":
case "linestrips":
case "polylist":
case "triangles":
data.primitives.push(parseGeometryPrimitive(child));
break;
default:
console.log(child);
}
}
library.geometries[xml2.getAttribute("id")] = data;
}
function parseSource(xml2) {
const data = {
array: [],
stride: 3
};
for (let i = 0; i < xml2.childNodes.length; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "float_array":
data.array = parseFloats(child.textContent);
break;
case "Name_array":
data.array = parseStrings(child.textContent);
break;
case "technique_common":
const accessor = getElementsByTagName(child, "accessor")[0];
if (accessor !== void 0) {
data.stride = parseInt(accessor.getAttribute("stride"));
}
break;
}
}
return data;
}
function parseGeometryVertices(xml2) {
const data = {};
for (let i = 0; i < xml2.childNodes.length; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
data[child.getAttribute("semantic")] = parseId(child.getAttribute("source"));
}
return data;
}
function parseGeometryPrimitive(xml2) {
const primitive = {
type: xml2.nodeName,
material: xml2.getAttribute("material"),
count: parseInt(xml2.getAttribute("count")),
inputs: {},
stride: 0,
hasUV: false
};
for (let i = 0, l = xml2.childNodes.length; i < l; i++) {
const child = xml2.childNodes[i];
if (child.nodeType !== 1)
continue;
switch (child.nodeName) {
case "input":
const id = parseId(child.getAttribute("source"));
const semantic = child.getAttribute("semantic");
const offset = parseInt(child.getAttribute("offset"));
const set = parseInt(child.getAttribute("set"));
const inputname = set > 0 ? semantic + set : semantic;
primitive.inputs[inputname] = { id, offset };
primitive.stride = Math.max(primitive.stride, offset + 1);
if (semantic === "TEXCOORD")
primitive.hasUV = true;
break;
case "vcount":
primitive.vcount = parseInts(child.textContent);
break;
case "p":
primitive.p = parseInts(child.textContent);
break;
}
}
return primitive;
}
function groupPrimitives(primitives) {
const build = {};
for (let i = 0; i < primitives.length; i++) {
const primitive = primitives[i];
if (build[primitive.type] === void 0)
build[primitive.type] = [];
build[primitive.type].push(primitive);
}
return build;
}
function checkUVCoordinates(primitives) {
let count2 = 0;
for (let i = 0, l = primitives.length; i < l; i++) {
const primitive = primitives[i];
if (primitive.hasUV === true) {
count2++;
}
}
if (count2 > 0 && count2 < primitives.length) {
primitives.uvsNeedsFix = true;
}
}
function buildGeometry(data) {
const build = {};
const sources = data.sources;
const vertices = data.vertices;
const primitives = data.primitives;
if (primitives.length === 0)
return {};
const groupedPrimitives = groupPrimitives(primitives);
for (const type in groupedPrimitives) {
const primitiveType = groupedPrimitives[type];
checkUVCoordinates(primitiveType);
build[type] = buildGeometryType(primitiveType, sources, vertices);
}
return build;
}
function buildGeometryType(primitives, sources, vertices) {
const build = {};
const position2 = { array: [], stride: 0 };
const normal = { array: [], stride: 0 };
const uv = { array: [], stride: 0 };
const uv1$1 = { array: [], stride: 0 };
const color = { array: [], stride: 0 };
const skinIndex = { array: [], stride: 4 };
const skinWeight = { array: [], stride: 4 };
const geometry = new THREE.BufferGeometry();
const materialKeys = [];
let start = 0;
for (let p = 0; p < primitives.length; p++) {
const primitive = primitives[p];
const inputs = primitive.inputs;
let count2 = 0;
switch (primitive.type) {
case "lines":
case "linestrips":
count2 = primitive.count * 2;
break;
case "triangles":
count2 = primitive.count * 3;
break;
case "polylist":
for (let g = 0; g < primitive.count; g++) {
const vc = primitive.vcount[g];
switch (vc) {
case 3:
count2 += 3;
break;
case 4:
count2 += 6;
break;
default:
count2 += (vc - 2) * 3;
break;
}
}
break;
default:
console.warn("THREE.ColladaLoader: Unknow primitive type:", primitive.type);
}
geometry.addGroup(start, count2, p);
start += count2;
if (primitive.material) {
materialKeys.push(primitive.material);
}
for (const name in inputs) {
const input = inputs[name];
switch (name) {
case "VERTEX":
for (const key in vertices) {
const id = vertices[key];
switch (key) {
case "POSITION":
const prevLength = position2.array.length;
buildGeometryData(primitive, sources[id], input.offset, position2.array);
position2.stride = sources[id].stride;
if (sources.skinWeights && sources.skinIndices) {
buildGeometryData(primitive, sources.skinIndices, input.offset, skinIndex.array);
buildGeometryData(primitive, sources.skinWeights, input.offset, skinWeight.array);
}
if (primitive.hasUV === false && primitives.uvsNeedsFix === true) {
const count3 = (position2.array.length - prevLength) / position2.stride;
for (let i = 0; i < count3; i++) {
uv.array.push(0, 0);
}
}
break;
case "NORMAL":
buildGeometryData(primitive, sources[id], input.offset, normal.array);
normal.stride = sources[id].stride;
break;
case "COLOR":
buildGeometryData(primitive, sources[id], input.offset, color.array);
color.stride = sources[id].stride;
break;
case "TEXCOORD":
buildGeometryData(primitive, sources[id], input.offset, uv.array);
uv.stride = sources[id].stride;
break;
case "TEXCOORD1":
buildGeometryData(primitive, sources[id], input.offset, uv1$1.array);
uv.stride = sources[id].stride;
break;
default:
console.warn('THREE.ColladaLoader: Semantic "%s" not handled in geometry build process.', key);
}
}
break;
case "NORMAL":
buildGeometryData(primitive, sources[input.id], input.offset, normal.array);
normal.stride = sources[input.id].stride;
break;
case "COLOR":
buildGeometryData(primitive, sources[input.id], input.offset, color.array);
color.stride = sources[input.id].stride;
break;
case "TEXCOORD":
buildGeometryData(primitive, sources[input.id], input.offset, uv.array);
uv.stride = sources[input.id].stride;
break;
case "TEXCOORD1":
buildGeometryData(primitive, sources[input.id], input.offset, uv1$1.array);
uv1$1.stride = sources[input.id].stride;
break;
}
}
}
if (position2.array.length > 0) {
geometry.setAttribute("position", new THREE.Float32BufferAttribute(position2.array, position2.stride));
}
if (normal.array.length > 0) {
geometry.setAttribute("normal", new THREE.Float32BufferAttribute(normal.array, normal.stride));
}
if (color.array.length > 0)
geometry.setAttribute("color", new THREE.Float32BufferAttribute(color.array, color.stride));
if (uv.array.length > 0)
geometry.setAttribute("uv