2019-12-11 16:02:46 +01:00
|
|
|
function fetchDataLength(path, callback) {
|
|
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
|
|
|
|
xhr.open('HEAD', path, true);
|
|
|
|
xhr.onreadystatechange = function() {
|
|
|
|
if (xhr.readyState === 4) {
|
|
|
|
if (xhr.status === 200) {
|
|
|
|
callback(xhr.getResponseHeader('Content-Length'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
xhr.send();
|
|
|
|
}
|
|
|
|
|
2019-12-09 18:41:42 +01:00
|
|
|
function fetchData(path, start, end, callback) {
|
|
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
|
|
|
|
xhr.open('GET', path, true);
|
|
|
|
xhr.setRequestHeader('Range', 'bytes=' + start + "-" + (end - 1));
|
|
|
|
xhr.onreadystatechange = function() {
|
|
|
|
if (xhr.readyState === 4) {
|
|
|
|
if (xhr.status === 206) {
|
|
|
|
callback(xhr.responseText);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
xhr.send();
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseLine(line) {
|
|
|
|
let element = {};
|
|
|
|
let split = line.split(/[ \t]+/);
|
|
|
|
|
|
|
|
if (split.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (split[0]) {
|
|
|
|
case "v":
|
|
|
|
element.type = Element.AddVertex;
|
2019-12-11 14:41:04 +01:00
|
|
|
element.value = new THREE.Vector3(
|
|
|
|
parseFloat(split[1]),
|
|
|
|
parseFloat(split[2]),
|
|
|
|
parseFloat(split[3]),
|
|
|
|
);
|
2019-12-09 18:41:42 +01:00
|
|
|
return element;
|
|
|
|
|
|
|
|
case "f":
|
|
|
|
element.type = Element.AddFace;
|
2019-12-11 14:41:04 +01:00
|
|
|
element.value = new THREE.Face3(
|
|
|
|
parseInt(split[1], 10) - 1,
|
|
|
|
parseInt(split[2], 10) - 1,
|
|
|
|
parseInt(split[3], 10) - 1,
|
|
|
|
);
|
|
|
|
return element;
|
|
|
|
|
2019-12-11 16:48:29 +01:00
|
|
|
case "ts":
|
|
|
|
element.type = Element.AddTriangleStrip;
|
|
|
|
element.value = [];
|
|
|
|
for (let i = 1; i < split.length - 2; i++) {
|
|
|
|
element.value.push(new THREE.Face3(
|
|
|
|
parseInt(split[i] , 10) - 1,
|
|
|
|
i % 2 === 1 ? parseInt(split[i+1], 10) - 1 : parseInt(split[i+2], 10) - 1,
|
|
|
|
i % 2 === 1 ? parseInt(split[i+2], 10) - 1 : parseInt(split[i+1], 10) - 1,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
|
|
|
|
case "tf":
|
|
|
|
element.type = Element.AddTriangleFan;
|
|
|
|
element.value = [];
|
|
|
|
for (let i = 1; i < split.length - 2; i++) {
|
|
|
|
element.value.push(new THREE.Face3(
|
|
|
|
parseInt(split[1] , 10) - 1,
|
|
|
|
parseInt(split[i+1], 10) - 1,
|
|
|
|
parseInt(split[i+2], 10) - 1,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
|
2019-12-11 14:41:04 +01:00
|
|
|
case "ev":
|
|
|
|
element.type = Element.EditVertex;
|
|
|
|
element.id = parseInt(split[1], 10) - 1;
|
|
|
|
element.value = new THREE.Vector3(
|
|
|
|
parseFloat(split[2]),
|
|
|
|
parseFloat(split[3]),
|
|
|
|
parseFloat(split[4]),
|
|
|
|
);
|
2019-12-09 18:41:42 +01:00
|
|
|
return element;
|
|
|
|
|
2019-12-11 15:44:21 +01:00
|
|
|
case "ef":
|
|
|
|
element.type = Element.EditFace;
|
|
|
|
element.id = parseInt(split[1], 10) - 1;
|
|
|
|
element.value = new THREE.Face3(
|
|
|
|
parseInt(split[2], 10) - 1,
|
|
|
|
parseInt(split[3], 10) - 1,
|
|
|
|
parseInt(split[4], 10) - 1,
|
|
|
|
);
|
2019-12-11 16:48:29 +01:00
|
|
|
return element;
|
2019-12-11 15:44:21 +01:00
|
|
|
|
|
|
|
case "df":
|
|
|
|
element.type = Element.DeleteFace;
|
|
|
|
element.id = parseInt(split[1], 10) - 1;
|
|
|
|
return element;
|
|
|
|
|
2019-12-09 18:41:42 +01:00
|
|
|
case "":
|
|
|
|
case "#":
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw new Error(split[0] + " is not a defined macro");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const Element = {};
|
|
|
|
Element.AddVertex = "AddVertex";
|
|
|
|
Element.AddFace = "AddFace";
|
2019-12-11 16:48:29 +01:00
|
|
|
Element.AddTriangleStrip = "AddTriangleStrip";
|
|
|
|
Element.AddTriangleFan = "AddTriangleFan";
|
2019-12-11 14:41:04 +01:00
|
|
|
Element.EditVertex = "EditVertex";
|
2019-12-11 15:44:21 +01:00
|
|
|
Element.EditFace = "EditFace";
|
|
|
|
Element.DeleteFace = "DeleteFace";
|
2019-12-09 18:41:42 +01:00
|
|
|
|
|
|
|
class Loader {
|
|
|
|
constructor(path, chunkSize = 1024, timeout = 20) {
|
|
|
|
this.path = path;
|
|
|
|
this.chunkSize = chunkSize;
|
|
|
|
this.timeout = timeout;
|
|
|
|
this.currentByte = 0;
|
|
|
|
this.remainder = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
start(callback) {
|
2019-12-11 16:02:46 +01:00
|
|
|
fetchDataLength(this.path, (length) => {
|
|
|
|
this.dataLength = length;
|
|
|
|
this.next(callback);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
percentage() {
|
|
|
|
return 100 * this.currentByte / this.dataLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
next(callback) {
|
2019-12-09 18:41:42 +01:00
|
|
|
this.downloadAndParseNextChunk((data) => {
|
|
|
|
callback(data);
|
|
|
|
setTimeout(() => {
|
2019-12-11 16:02:46 +01:00
|
|
|
this.next(callback);
|
2019-12-09 18:41:42 +01:00
|
|
|
}, this.timeout);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
downloadAndParseNextChunk(callback) {
|
|
|
|
|
2019-12-11 16:02:46 +01:00
|
|
|
let upperBound = Math.min(this.currentByte + this.chunkSize, this.dataLength);
|
2019-12-09 18:41:42 +01:00
|
|
|
|
2019-12-11 16:02:46 +01:00
|
|
|
if (upperBound <= this.currentByte) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fetchData(this.path, this.currentByte, upperBound, (data) => {
|
|
|
|
|
|
|
|
this.currentByte = upperBound;
|
2019-12-09 18:41:42 +01:00
|
|
|
|
|
|
|
let elements = [];
|
|
|
|
let split = data.split('\n');
|
|
|
|
split[0] = this.remainder + split[0];
|
|
|
|
this.remainder = split.pop();
|
|
|
|
|
|
|
|
for (let line of split) {
|
|
|
|
elements.push(parseLine(line));
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(elements);
|
2019-12-11 16:02:46 +01:00
|
|
|
|
2019-12-09 18:41:42 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|