/*
3DHOP - 3D Heritage Online Presenter
Copyright (c) 2014-2020, Visual Computing Lab, ISTI - CNR
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
var parsePly = (function(){
var canonicTypes = {
"char" : "int8",
"int8" : "int8",
"uchar" : "uint8",
"uint8" : "uint8",
"short" : "int16",
"int16" : "int16",
"ushort" : "uint16",
"uint16" : "uint16",
"int" : "int32",
"int32" : "int32",
"uint" : "uint32",
"uint32" : "uint32",
"float" : "float32",
"float32" : "float32",
"double" : "float64",
"float64" : "float64"
};
function trim(s) {
var r = s;
var n = r.length;
var i = 0;
var blanks = " \n\r\t";
while ((i < n) && (blanks.indexOf(r.charAt(i)) >= 0)) { i++; }
r = r.substring(i, r.length);
i = r.length - 1;
while ((i > 0) && (blanks.indexOf(r.charAt(i)) >= 0)) { i--; }
r = r.substring(0, i+1);
return r;
}
function extractHeader(data) {
if (!data || !data.view || !data.view.buffer) return null;
var u8 = new Uint8Array(data.view.buffer);
var endHeaderToken = "end_header";
var header = "";
var found = false;
var currC = null;
var prevC = null;
var pos = data.pos;
var p = 0;
var n = 0;
for (pos=0, n=u8.byteLength; pos= endHeaderToken.length) {
p = pos - endHeaderToken.length;
if (prevC == "\r") p--;
if (header.substring(p, p + endHeaderToken.length) == endHeaderToken) {
found = true;
break;
}
}
}
prevC = currC;
}
data.pos = pos;
if (!found) {
return null;
}
data.pos++;
return header;
}
function splitHeader(header) {
var lines = header.split("\n");
var trimmed = [ ];
var tokens = null;
var s = null;
for (var i=0, n=lines.length; i 0) {
for (var j=0, m=tokens.length; j= 3) {
info.format = {
name : tokens[1],
version : tokens[2],
binary : (tokens[1].toLowerCase().indexOf("binary") >= 0),
littleEndian : ((tokens[1].toLowerCase()) == "binary_little_endian")
};
}
break;
case "comment":
info.comments.push(tokens.slice(1));
break;
case "element":
if (tn >= 3) {
elem = {
name : tokens[1],
count : parseInt(tokens[2]),
properties : [ ],
propertyMap : { }
};
info.elements.push(elem);
info.elementMap[elem.name.toLowerCase()] = elem;
}
break;
case "property":
if (elem && (tn >= 3)) {
prop = {
name : tokens[tn-1],
type : tokens.slice(1, tn - 1)
};
elem.properties.push(prop);
elem.propertyMap[prop.name.toLowerCase()] = prop;
}
break;
default:
info.others.push(tokens.slice());
break;
}
}
if (!info.format) {
return false;
}
return info;
}
var tabStr = "\t";
function setupLines(lines, tabs) {
for (var i=0, n=lines.length; i 0) {
verticesCount = elem.count;
props = elem.propertyMap;
vertexLines = [ ];
vertexLines.push("function (header, elementInfo, index, element) {");
vertexLines.push(tabStr + "var littleEndian = SpiderGL.Type.LITTLE_ENDIAN;");
vertexLines.push(tabStr + "var sf32 = SpiderGL.Type.SIZEOF_FLOAT32;");
vertexLines.push(tabStr + "var sui8 = SpiderGL.Type.SIZEOF_UINT8;");
vertexLines.push(tabStr + "var offset = index * this._vertexStride;");
vertexLines.push(tabStr + "var view = this._view;");
vertexLines.push("");
ptypes = propertiesTypes(props["x"], props["y"], props["z"]);
if (ptypes.length == 1) {
hasPosition = true;
switch (ptypes[0]) {
case "float32":
vertexLines.push(tabStr + "view.setFloat32(offset, element.x, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, element.y, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, element.z, littleEndian); offset += sf32;");
vertexLines.push("");
vertexAttributes["position"] = {
size : 3,
type : SpiderGL.Type.FLOAT32,
offset : vertexStride
};
vertexStride += 3 * SpiderGL.Type.SIZEOF_FLOAT32;
break;
default: break;
}
}
ptypes = propertiesTypes(props["nx"], props["ny"], props["nz"]);
if (ptypes.length == 1) {
hasNormal = true;
switch (ptypes[0]) {
case "float32":
vertexLines.push(tabStr + "view.setFloat32(offset, element.nx, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, element.ny, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, element.nz, littleEndian); offset += sf32;");
vertexLines.push("");
vertexAttributes["normal"] = {
size : 3,
type : SpiderGL.Type.FLOAT32,
offset : vertexStride
};
vertexStride += 3 * SpiderGL.Type.SIZEOF_FLOAT32;
break;
default: break;
}
}
ptypes = propertiesTypes(props["red"], props["green"], props["blue"]);
if (ptypes.length == 1) {
hasColor = true;
switch (ptypes[0]) {
case "uint8":
vertexLines.push(tabStr + "view.setUint8(offset, element.red ); offset += sui8;");
vertexLines.push(tabStr + "view.setUint8(offset, element.green); offset += sui8;");
vertexLines.push(tabStr + "view.setUint8(offset, element.blue ); offset += sui8;");
vertexLines.push(tabStr + "view.setUint8(offset, 255 ); offset += sui8;");
vertexLines.push("");
vertexAttributes["color"] = {
size : 4,
type : SpiderGL.Type.UINT8,
offset : vertexStride,
normalized : true
};
vertexStride += 4 * SpiderGL.Type.SIZEOF_UINT8;
break;
case "float32":
vertexLines.push(tabStr + "view.setFloat32(offset, element.red, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, element.green, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, element.blue, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, 1.0, littleEndian); offset += sf32;");
vertexLines.push("");
vertexAttributes["color"] = {
size : 4,
type : SpiderGL.Type.FLOAT32,
offset : vertexStride
};
vertexStride += 4 * SpiderGL.Type.SIZEOF_FLOAT32;
break;
default: break;
}
}
ptypes = propertiesTypes(props["texture_u"], props["texture_v"]);
if (ptypes.length == 1) {
hasTexCoord = true;
switch (ptypes[0]) {
case "float32":
vertexLines.push(tabStr + "view.setFloat32(offset, element.texture_u, littleEndian); offset += sf32;");
vertexLines.push(tabStr + "view.setFloat32(offset, element.texture_v, littleEndian); offset += sf32;");
vertexLines.push("");
vertexAttributes["texturecoord"] = {
size : 2,
type : SpiderGL.Type.FLOAT32,
offset : vertexStride
};
vertexStride += 2 * SpiderGL.Type.SIZEOF_FLOAT32;
break;
default: break;
}
}
vertexLines.push("}");
}
var facesCount = 0;
var faceLines = null;
elem = header.elementMap["face"];
if (elem && elem.count > 0) {
facesCount = elem.count;
props = elem.propertyMap;
faceLines = [ ];
faceLines.push("function (header, elementInfo, index, element) {");
faceLines.push(tabStr + "var littleEndian = SpiderGL.Type.LITTLE_ENDIAN;");
faceLines.push(tabStr + "var sui32 = SpiderGL.Type.SIZEOF_UINT32;");
faceLines.push(tabStr + "var offset = index * 3 * sui32;");
faceLines.push(tabStr + "var view = this._view;");
faceLines.push("");
if (props["vertex_indices"]) {
faceLines.push(tabStr + "view.setUint32(offset, element.vertex_indices[0], littleEndian); offset += sui32;");
faceLines.push(tabStr + "view.setUint32(offset, element.vertex_indices[1], littleEndian); offset += sui32;");
faceLines.push(tabStr + "view.setUint32(offset, element.vertex_indices[2], littleEndian); offset += sui32;");
}
else if (props["vertex_index"]) {
faceLines.push(tabStr + "view.setUint32(offset, element.vertex_index[0], littleEndian); offset += sui32;");
faceLines.push(tabStr + "view.setUint32(offset, element.vertex_index[1], littleEndian); offset += sui32;");
faceLines.push(tabStr + "view.setUint32(offset, element.vertex_index[2], littleEndian); offset += sui32;");
}
else {
facesCount = 0;
}
faceLines.push("}");
}
this._mesh = null;
this._hasPosition = hasPosition;
this._hasNormal = hasNormal;
this._hasColor = hasColor;
this._hasTexCoord = hasTexCoord;
this._verticesCount = verticesCount;
this._vertexAttributes = vertexAttributes;
this._vertexStride = vertexStride;
this._vertexBuffer = null;
this._handleVertex = emptyFunction;
if (vertexStride > 0) {
var vertexFuncStr = vertexLines.join("\n");
this._handleVertex = eval("(" + vertexFuncStr + ")");
}
this._facesCount = facesCount;
this._indexBuffer = null;
this._handleFace = emptyFunction;
if (facesCount > 0) {
var faceFuncStr = faceLines.join("\n");
this._handleFace = eval("(" + faceFuncStr + ")");
}
},
onBeginContent : function (header) {
},
onBeginElements : function (header, elementInfo) {
switch (elementInfo.name) {
case "vertex":
this._vertexBuffer = new ArrayBuffer(this._verticesCount * this._vertexStride);
this._view = new DataView(this._vertexBuffer);
this._handleElement = this._handleVertex;
break;
case "face":
this._indexBuffer = new ArrayBuffer(this._facesCount * 3 * SpiderGL.Type.SIZEOF_UINT32);
this._view = new DataView(this._indexBuffer);
this._handleElement = this._handleFace;
break;
default:
this._view = null;
this._handleElement = emptyFunction;
break;
}
},
onElement : function (header, elementInfo, index, element) {
// bounding box calculation
if (elementInfo.name=="vertex"){
if(element.x < this._boundingBox.min[0])
this._boundingBox.min[0] = element.x;
if(element.y < this._boundingBox.min[1])
this._boundingBox.min[1] = element.y;
if(element.z < this._boundingBox.min[2])
this._boundingBox.min[2] = element.z;
if(element.x > this._boundingBox.max[0])
this._boundingBox.max[0] = element.x;
if(element.y > this._boundingBox.max[1])
this._boundingBox.max[1] = element.y;
if(element.z > this._boundingBox.max[2])
this._boundingBox.max[2] = element.z;
}
this._handleElement(header, elementInfo, index, element);
},
onEndElements : function (header, elementInfo) {
this._view = null;
this._handleElement = emptyFunction;
},
onEndContent : function () {
},
onEnd : function () {
if ((this._verticesCount <= 0) && (this._facesCount <= 0)) return;
// var gl = this._gl;
var modelDescriptor = {
version : "0.0.1.0 EXP",
meta : {
},
data : {
vertexBuffers : {
},
indexBuffers : {
}
},
access : {
vertexStreams : {
},
primitiveStreams : {
}
},
semantic : {
bindings : {
},
chunks : {
}
},
logic : {
parts : {
}
},
control : {
},
extra : {
}
};
var modelVertexBuffers = modelDescriptor.data.vertexBuffers;
var modelIndexBuffers = modelDescriptor.data.indexBuffers;
var modelVertexStreams = modelDescriptor.access.vertexStreams;
var modelPrimitiveStreams = modelDescriptor.access.primitiveStreams;
var modelBindings = modelDescriptor.semantic.bindings;
var modelChunks = modelDescriptor.semantic.chunks;
var modelParts = modelDescriptor.logic.parts;
modelDescriptor.extra.boundingBox = this._boundingBox;
modelDescriptor.extra.renderMode = this._renderMode;
modelDescriptor.extra.hasPosition = this._hasPosition;
modelDescriptor.extra.hasNormal = this._hasNormal;
modelDescriptor.extra.hasColor = this._hasColor;
modelDescriptor.extra.hasTexCoord = this._hasTexCoord;
modelDescriptor.extra.textureUrl = this._textureUrl;
var maxVerticesCount = (1 << 16) - 1;
var baseVertexBufferName = "mainVertexBuffer";
var baseIndexBufferName = "mainIndexBuffer";
var baseBindingName = "mainBinding";
var baseChunkName = "mainChunk";
var basePointStreamName = "vertices";
var baseTriStreamName = "triangles";
var basePartName = "mainPart";
if (this._facesCount > 0) {
var littleEndian = SpiderGL.Type.LITTLE_ENDIAN;
var indexStride = SpiderGL.Type.SIZEOF_UINT32;
var wholeSize = Float64Array.BYTES_PER_ELEMENT;
var stride = this._vertexStride;
var partCount = stride % wholeSize;
var wholeCount = (stride - partCount) / wholeSize;
var vertexBufferView = new Uint8Array(this._vertexBuffer);
var indexBufferView = new Uint32Array(this._indexBuffer);
var chunksCount = 0;
var chunkVertexBuffers = [ ];
var chunkVerticesCount = [ ];
var chunkIndexBuffers = [ ];
var chunkIndicesCount = [ ];
var facesLeft = this._facesCount;
var currFaceIndex = 0;
var indicesBuffer = new Uint32Array(this._facesCount * 3);
while (facesLeft > 0) {
var verticesMap = new Uint32Array(this._verticesCount);
var verticesNew = new Uint32Array(maxVerticesCount);
var verticesCount = 0;
var indicesCount = 0;
var facesCount = 0;
while ((verticesCount <= (maxVerticesCount - 3)) && (facesLeft > 0)) {
for (var k=0; k<3; ++k, ++currFaceIndex) {
var v = indexBufferView[currFaceIndex];
var r = verticesMap[v];
if (!r) {
verticesNew[verticesCount++] = v;
verticesMap[v] = verticesCount;
}
indicesBuffer[indicesCount++] = v;
}
facesLeft--;
facesCount++;
}
if (facesCount <= 0) continue;
var chunkVertexBuffer = new ArrayBuffer(verticesCount * stride);
var chunkVertexBufferView = new Uint8Array(chunkVertexBuffer);
var chunkIndexBuffer = new Uint16Array(indicesCount);
for (var i=0; i 0) {
var vertexBufferName = baseVertexBufferName;
modelVertexBuffers[vertexBufferName] = {
typedArray : this._vertexBuffer
};
for (var a in this._vertexAttributes) {
var attr = this._vertexAttributes[a];
modelVertexStreams[a] = {
buffer : vertexBufferName,
size : attr.size,
type : attr.type,
stride : this._vertexStride,
offset : attr.offset,
normalized : !!attr.normalized
};
binding.vertexStreams[a.toUpperCase()] = [a];
}
modelPrimitiveStreams[basePointStreamName] = {
mode : SpiderGL.Type.POINTS,
count : this._verticesCount
};
binding.primitiveStreams["POINT"] = [basePointStreamName];
}
if ((this._verticesCount > 0) || (this._facesCount > 0)) {
modelChunks[baseChunkName] = {
techniques : {
"common" : {
binding : baseBindingName
}
}
};
modelParts[basePartName] = {
chunks : [baseChunkName]
};
}
}
this._modelDescriptor = modelDescriptor;
}
};
function mainImportPly(buffer) {
var handler = new PlyHandler(buffer);
parsePly(buffer, handler);
var modelDescriptor = handler.modelDescriptor;
return modelDescriptor;
};
return mainImportPly;
})();