/* Nexus Copyright (c) 2012-2020, Visual Computing Lab, ISTI - CNR All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ onmessage = function(job) { if(typeof(job.data) == "string") return; var node = job.data.node; var signature = job.data.signature; var patches = job.data.patches; // var now =new Date().getTime(); var size; if(!node.buffer) return; else size = node.buffer.byteLength; var buffer; for(var i =0 ; i < 1; i++) { var coder = new MeshCoder(signature, node, patches); buffer = coder.decode(node.buffer); } node.buffer = buffer; node.owner = job.owner; // var elapsed = new Date().getTime() - now; // var t = node.nface; // console.log("Z Time: " + elapsed + " Size: " + size + " KT/s " + (t/(elapsed)) + " Mbps " + (8*1000*node.buffer.byteLength/elapsed)/(1<<20)); postMessage(node); } // actually bitstreams expects a little endian uin64 type. convert it to 2 uint32 BitStream = function(array) { this.a = array; for(var i = 0; i < array.length; i += 2) { var s = array[i]; array[i] = array[i+1]; array[i+1] = s; } this.position = 0; this.bitsPending = 0; }; BitStream.prototype = { read: function(bits) { var bitBuffer = 0; while(bits > 0) { var partial; var bitsConsumed; if (this.bitsPending > 0) { var byte = (this.a[this.position - 1] & (0xffffffff >>> (32 - this.bitsPending)))>>>0; bitsConsumed = Math.min(this.bitsPending, bits); this.bitsPending -= bitsConsumed; partial = byte >>> this.bitsPending; } else { bitsConsumed = Math.min(32, bits); this.bitsPending = 32 - bitsConsumed; partial = this.a[this.position++] >>> this.bitsPending; } bits -= bitsConsumed; bitBuffer = ((bitBuffer << bitsConsumed) | partial)>>>0; } return bitBuffer; }, replace: function(bits, value) { //zero last part value = (value & (0xffffffff >>> 32 - bits)) >>> 0; value = (value | read(bits)) >>> 0; return value; } }; Stream = function(buffer) { this.data = buffer; this.buffer = new Uint8Array(buffer); this.pos = 0; } Stream.prototype = { readChar: function() { var c = this.buffer[this.pos++]; if(c > 127) c -= 256; return c; }, readUChar: function() { return this.buffer[this.pos++]; }, readInt: function() { var c = this.buffer[this.pos + 3] c <<= 8; c |= this.buffer[this.pos + 2]; c <<= 8; c |= this.buffer[this.pos + 1]; c <<= 8; c |= this.buffer[this.pos + 0]; this.pos += 4; return c; }, readArray: function(n) { var a = this.buffer.subarray(this.pos, this.pos+n); this.pos += n; return a; }, readBitStream:function() { var n = this.readInt(); var pad = this.pos & 0x3; if(pad != 0) this.pos += 4 - pad; var b = new BitStream(new Uint32Array(this.data, this.pos, n*2)); this.pos += n*8; return b; } }; function Tunstall(wordsize, lookup_size) { this.wordsize = wordsize? wordsize : 8; this.lookup_size = lookup_size? lookup_size : 8; } Tunstall.prototype = { decompress: function(stream) { var nsymbols = stream.readUChar(); this.probabilities = stream.readArray(nsymbols*2); this.createDecodingTables(); var size = stream.readInt(); var data = new Uint8Array(size); var compressed_size = stream.readInt(); var compressed_data = stream.readArray(compressed_size); if(size) this._decompress(compressed_data, compressed_size, data, size); return data; }, createDecodingTables: function() { //read symbol,prob,symbol,prob as uchar. //Here probabilities will range from 0 to 0xffff for better precision var n_symbols = this.probabilities.length/2; if(n_symbols <= 1) return; var queues = []; //array of arrays var buffer = []; //initialize adding all symbols to queues for(var i = 0; i < n_symbols; i++) { var symbol = this.probabilities[i*2]; var s = [(this.probabilities[i*2+1])<<8, buffer.length, 1]; //probability, position in the buffer, length queues[i] = [s]; buffer.push(this.probabilities[i*2]); //symbol } var dictionary_size = 1< max_prob) { best = i; max_prob = p; } } var symbol = queues[best][0]; var pos = buffer.length; for(var i = 0; i < n_symbols; i++) { var sym = this.probabilities[i*2]; var prob = this.probabilities[i*2+1]<<8; var s = [((prob*symbol[0])>>>16), pos, symbol[2]+1]; //combine probabilities, keep track of buffer, keep length of queue for(var k = 0; k < symbol[2]; k++) buffer[pos+k] = buffer[symbol[1] + k]; //copy sequence of symbols pos += symbol[2]; buffer[pos++] = sym; //append symbol queues[i].push(s); } table_length += (n_symbols-1)*(symbol[2] + 1) +1; n_words += n_symbols -1; queues[best].shift(); //remove first thing } this.index = new Uint32Array(n_words); this.lengths = new Uint32Array(n_words); this.table = new Uint8Array(table_length); var word = 0; var pos = 0; for(i = 0; i < queues.length; i++) { var queue = queues[i]; for(var k = 0; k < queue.length; k++) { var s = queue[k]; this.index[word] = pos; this.lengths[word] = s[2]; //length word++; for(var j = 0; j < s[2]; j++) this.table[pos + j] = buffer[s[1] + j]; //buffer of offset pos += s[2]; //length } } }, _decompress: function(input, input_size, output, output_size) { var input_pos = 0; var output_pos = 0; if(this.probabilities.length == 2) { var symbol = this.probabilities[0]; for(var i = 0; i < output_size; i++) output[i] = symbol; return; } while(input_pos < input_size-1) { var symbol = input[input_pos++]; var start = this.index[symbol]; var end = start + this.lengths[symbol]; for(var i = start; i < end; i++) output[output_pos++] = this.table[i]; } //last symbol might override so we check. var symbol = input[input_pos]; var start = this.index[symbol]; var end = start + output_size - output_pos; var length = output_size - output_pos; for(var i = start; i < end; i++) output[output_pos++] = this.table[i]; return output; } } ZPoint = function(h, l) { this.lo = l; this.hi = h; } ZPoint.prototype = { copy: function(z) { this.lo = z.lo; this.hi = z.hi; }, setBit: function(d) { if(d < 32) this.lo = (this.lo | (1<>>0; else this.hi = (this.hi | (1<<(d-32)))>>>0; }, toPoint: function(min, step, buffer, pos) { var x = this.morton3(this.lo, this.hi>>>1); var y = this.morton3(this.lo>>>1, this.hi>>>2); var z = this.morton3((this.lo>>>2 | (this.hi & 0x1)<<30 )>>>0, this.hi>>>3); //first hi bit needs to go into low. buffer[pos+0] = (x + min[0])*step; buffer[pos+1] = (y + min[1])*step; buffer[pos+2] = (z + min[2])*step; }, morton3: function(lo, hi) { lo = ( lo & 0x49249249)>>>0; lo = ((lo | (lo >>> 2 )) & 0xc30c30c3)>>>0; lo = ((lo | (lo >>> 4 )) & 0x0f00f00f)>>>0; lo = ((lo | (lo >>> 8 )) & 0xff0000ff)>>>0; lo = ((lo | (lo >>> 16)) & 0x0000ffff)>>>0; hi = ( hi & 0x49249249)>>>0; hi = ((hi | (hi >> 2 )) & 0xc30c30c3)>>>0; hi = ((hi | (hi >> 4 )) & 0x0f00f00f)>>>0; hi = ((hi | (hi >> 8 )) & 0xff0000ff)>>>0; hi = ((hi | (hi >> 16)) & 0x0000ffff)>>>0; return ((hi<<11) | lo)>>>0; } }; //node is an object with nvert, nface //patches is an array of offsets in the index, triangle are grouped by those offsets //signature tells wether mesh has indices, normals, colors, etc. {'colors': true, 'normals':true, 'indices': true } function MeshCoder(signature, node, patches) { this.sig = signature; this.node = node; this.patches = patches; this.last = new Int32Array(this.node.nvert); this.last_count = 0; } MeshCoder.prototype = { //assumes input is an ArrayBuffer decode: function(input) { var t = this; t.buffer = new ArrayBuffer(t.node.nvert*(12 + t.sig.texcoords*8 + t.sig.normals*6 + t.sig.colors*4) + t.node.nface*t.sig.indices*6); var size = t.node.nvert*12; //float t.coords = new Float32Array(t.buffer, 0, t.node.nvert*3); if(t.sig.texcoords) { t.texcoords = new Float32Array(t.buffer, size, t.node.nvert*2); size += t.node.nvert*8; //float } if(t.sig.normals) { t.normals = new Int16Array(t.buffer, size, t.node.nvert*3); size += t.node.nvert*6; //short } if(t.sig.colors) { t.colors = new Uint8ClampedArray(t.buffer, size, t.node.nvert*4); size += t.node.nvert*4; //chars } if(t.sig.indices) { t.faces = new Uint16Array(t.buffer, size, t.node.nface*3); size += t.node.nface*6; //short } t.stream = new Stream(input); t.stack = new Float32Array(12); //min0, min1, min2, step, tmin0, tmin1, tstep t.stack[3] = t.stream.readInt(); t.stack[4] = t.stream.readInt(); t.stack[5] = t.stream.readInt(); t.coord_q = t.stream.readChar(); t.coord_bits = t.stream.readChar()*3; t.stack[6] = Math.pow(2.0, t.coord_q); if(t.sig.texcoords) { t.stack[9] = t.stream.readInt(); t.stack[10] = t.stream.readInt(); t.texcoord_q = t.stream.readChar(); t.texcoord_bits = t.stream.readChar()*2; t.stack[11] = Math.pow(2.0, t.texcoord_q); } if(t.sig.indices) { t.decodeFaces(); // var faces = window.performance.now() - start; // start += faces; } else { t.decodeCoordinates(); // var coords = window.performance.now() - start; // start += coords; } if(t.sig.normals) t.decodeNormals(); // var normals = window.performance.now() - start; // start += normals; if(t.sig.colors) t.decodeColors(); // var colors = window.performance.now() - start; // start += colors; // console.log("Decode " + (faces + coords + normals + colors) + "ms. C: " + coords + " F: " + faces + " N: " + normals + " C: " + colors); return t.buffer; }, decodeCoordinates: function() { var t = this; t.min = [t.stack[3], t.stack[4], t.stack[5]]; var step = Math.pow(2.0, t.coord_q); var hi_bits = Math.max(t.coord_bits - 32, 0); var lo_bits = Math.min(t.coord_bits, 32); var bitstream = t.stream.readBitStream(); var tunstall = new Tunstall; var diffs = tunstall.decompress(t.stream); var hi = bitstream.read(hi_bits); var lo = bitstream.read(lo_bits); var p = new ZPoint(hi, lo); var count = 0; p.toPoint(t.min, step, t.coords, count); count += 3; for(var i = 1; i < t.node.nvert; i++) { var d = diffs[i-1]; p.setBit(d, 1); if(d > 32) { p.hi = (p.hi & ~((1<<(d-32))-1))>>>0; var e = bitstream.read(d - 32); p.hi = (p.hi | e)>>>0; p.lo = bitstream.read(32); } else { if(d == 32) { p.lo = bitstream.read(d); } else { var e = bitstream.read(d); p.lo = (p.lo & ~((1<>>0; p.lo = (p.lo | e)>>>0; } } p.toPoint(t.min, step, t.coords, count); count += 3; } }, decodeFaces: function() { if(!this.node.nface) return; this.vertex_count = 0; var start = 0; for(var p = 0; p < this.patches.length; p++) { var end = this.patches[p]; this.decodeConnectivity(end - start, start*3); start = end; } //dequantize positions var tot = this.node.nvert*3; var coords = this.coords; var stack = this.stack; for(var i = 0; i < tot; ) { coords[i] = (coords[i] + stack[3])*stack[6]; i++; coords[i] = (coords[i] + stack[4])*stack[6]; i++; coords[i] = (coords[i] + stack[5])*stack[6]; i++; } if(this.sig.texcoords) { var t_tot = this.node.nvert*2; var t_coords = this.texcoords; for(var i = 0; i < tot; ) { t_coords[i] = (t_coords[i] + stack[9])*stack[11]; i++; t_coords[i] = (t_coords[i] + stack[10])*stack[11]; i++; } } }, decodeNormals: function() { var norm_q = this.stream.readChar(); var dtunstall = new Tunstall; var diffs = dtunstall.decompress(this.stream); var stunstall = new Tunstall; var signs = stunstall.decompress(this.stream); var bitstream = this.stream.readBitStream(); var side = (1<<(16 - norm_q))>>>0; var diffcount = 0; var signcount = 0; if(!this.sig.indices) { for(var k = 0; k < 2; k++) { var on = 0; for(var i = 0; i < this.node.nvert; i++) { var d = this.decodeDiff(diffs[diffcount++], bitstream); on = on + d; this.normals[3*i + k] = on*side; } } for(var i = 0; i < this.node.nvert; i++) { var offset = i*3; var x = this.normals[offset + 0]; var y = this.normals[offset + 1]; var z = 32767.0*32767.0 - x*x - y*y; if(z < 0) z = 0; z = Math.sqrt(z); if(z > 32767) z = 32767; if(signs[i] == 0) z = -z; this.normals[offset + 2] = z; } return; } var boundary = this.markBoundary(); this.computeNormals(); if(this.sig.texcoords) //hack, fixing normals makes it worse actually return; var stat = 0; //get difference between original and predicted for(var i = 0; i < this.node.nvert; i++) { if(!boundary[i]) continue; var offset = i*3; var x = (this.normals[offset + 0]/side); var y = (this.normals[offset + 1]/side); var dx = this.decodeDiff(diffs[diffcount++], bitstream); var dy = this.decodeDiff(diffs[diffcount++], bitstream); x = (x + dx)*side; y = (y + dy)*side; var z = 32767.0*32767.0 - x*x - y*y; if(z < 0) z = 0; z = Math.sqrt(z); //sign if(z > 32767.0) z = 32767.0; var signbit = signs[signcount++]; // if(this.normals[offset+2] < 0 != signbit) if((this.normals[offset+2] < 0 && signbit == 0) || (this.normals[offset+2] > 0 && signbit == 1)) z = -z; this.normals[offset + 0] = x; this.normals[offset + 1] = y; this.normals[offset + 2] = z; } }, decodeColors: function() { var color_q = []; for(var k = 0; k < 4; k++) color_q[k] = this.stream.readChar(); var diffs = []; for(var k = 0; k < 4; k++) { var tunstall = new Tunstall;; diffs[k] = tunstall.decompress(this.stream); } var bitstream = this.stream.readBitStream(); var count = 0; if(this.sig.indices) { for(var i = 0; i < this.node.nvert; i++) { var last = this.last[i]*4; var offset = i*4; for(var k = 0; k < 4; k++) { var c = this.decodeDiff(diffs[k][count], bitstream); if(last >= 0) c += this.colors[last + k]; this.colors[offset] = c; offset++; } count++; } } else { for(var k = 0; k < 4; k++) this.colors[k] = this.decodeDiff(diffs[k][count], bitstream); count++; var offset = 4; for(var i = 1; i < this.node.nvert; i++) { for(var k = 0; k < 4; k++) { var d = this.decodeDiff(diffs[k][count], bitstream); this.colors[offset] = this.colors[offset-4] + d; offset ++; } count++; } } var steps = []; for(var k = 0; k < 4; k++) steps[k] = (1<<(8 - color_q[k])); //convert to rgb for(var i = 0; i < this.node.nvert; i++) { var offset = i*4; var e0 = this.colors[offset + 0] * steps[0]; var e1 = this.colors[offset + 1] * steps[1]; var e2 = this.colors[offset + 2] * steps[2]; var e3 = this.colors[offset + 3] * steps[3]; this.colors[offset + 0] = (e2 + e0)&0xff; this.colors[offset + 1] = e0; this.colors[offset + 2] = (e1 + e0)&0xff; this.colors[offset + 3] = e3; } }, //how to determine if a vertex is a boundary without topology: //for each edge a vertex is in, add or subtract the id of the other vertex depending on order //for internal vertices sum is zero. //unless we have strange configurations and a lot of sfiga, zero wont happen. //TODO think about this markBoundary: function() { // var boundary = new Uint8Array(this.node.nvert); var count = new Uint32Array(this.node.nvert); var offset = 0; for(var i = 0; i < this.node.nface; i++) { count[this.faces[offset + 0]] += this.faces[offset + 1] - this.faces[offset + 2]; count[this.faces[offset + 1]] += this.faces[offset + 2] - this.faces[offset + 0]; count[this.faces[offset + 2]] += this.faces[offset + 0] - this.faces[offset + 1]; offset += 3; } return count; // for(var i = 0; i < this.node.nvert; i++) // if(count[i] != 0) // boundary[i] = true; // return boundary; }, norm: function(buffer, a, b, c) { //a b c offsets in the buffer var ba0 = buffer[b+0] - buffer[a+0]; var ba1 = buffer[b+1] - buffer[a+1]; var ba2 = buffer[b+2] - buffer[a+2]; var ca0 = buffer[c+0] - buffer[a+0]; var ca1 = buffer[c+1] - buffer[a+1]; var ca2 = buffer[c+2] - buffer[a+2]; var p = []; p[0] = ba1*ca2 - ba2*ca1; p[1] = ba2*ca0 - ba0*ca2; p[2] = ba0*ca1 - ba1*ca0; return p; }, normalize: function(buffer, offset) { var x = buffer[offset + 0]; var y = buffer[offset + 1]; var z = buffer[offset + 2]; var n = Math.sqrt(x*x + y*y + z*z); if(n > 0) { buffer[offset + 0] = x/n; buffer[offset + 1] = y/n; buffer[offset + 2] = z/n; } }, computeNormals:function() { var tmp_normals = new Float32Array(this.node.nvert*3); var offset = 0; for(var i = 0; i < this.node.nface; i++) { var a = 3*this.faces[offset + 0]; var b = 3*this.faces[offset + 1]; var c = 3*this.faces[offset + 2]; var buffer = this.coords; var ba0 = buffer[b+0] - buffer[a+0]; var ba1 = buffer[b+1] - buffer[a+1]; var ba2 = buffer[b+2] - buffer[a+2]; var ca0 = buffer[c+0] - buffer[a+0]; var ca1 = buffer[c+1] - buffer[a+1]; var ca2 = buffer[c+2] - buffer[a+2]; var n0 = ba1*ca2 - ba2*ca1; var n1 = ba2*ca0 - ba0*ca2; var n2 = ba0*ca1 - ba1*ca0; tmp_normals[a + 0] += n0; tmp_normals[a + 1] += n1; tmp_normals[a + 2] += n2; tmp_normals[b + 0] += n0; tmp_normals[b + 1] += n1; tmp_normals[b + 2] += n2; tmp_normals[c + 0] += n0; tmp_normals[c + 1] += n1; tmp_normals[c + 2] += n2; offset += 3; } //normalize var offset = 0; for(var i = 0; i < this.node.nvert; i++) { var x = tmp_normals[offset + 0]; var y = tmp_normals[offset + 1]; var z = tmp_normals[offset + 2]; var n = Math.sqrt(x*x + y*y + z*z); if(n > 0) { tmp_normals[offset + 0] = x/n; tmp_normals[offset + 1] = y/n; tmp_normals[offset + 2] = z/n; } this.normals[offset + 0] = tmp_normals[offset + 0]*32767; this.normals[offset + 1] = tmp_normals[offset + 1]*32767; this.normals[offset + 2] = tmp_normals[offset + 2]*32767; offset += 3; } }, decodeDiff: function(diff, bitstream) { var val; if(diff == 0) { val = 1; } else { val = 1<<(diff); val |= bitstream.read(diff); }; val--; //vall is always >= 1 if(val & 0x1) val = -((val+1)>>1); else val = val>>1; return val; }, /* an edge is: uint16_t face, uint16_t side, uint32_t prev, next, bool deleted I do not want to create millions of small objects, I will use aUint32Array. Problem is how long, sqrt(nface) we will over blow using nface. */ decodeConnectivity: function(length, start) { var t = this; var ctunstall = new Tunstall; var clers = ctunstall.decompress(this.stream); var cler_count = 0; var dtunstall = new Tunstall; var diffs = dtunstall.decompress(this.stream); var diff_count = 0; var tdiffs; var tdiff_count = 0; if(t.sig.texcoords) { var ttunstall = new Tunstall; tdiffs = ttunstall.decompress(this.stream); } var bitstream = this.stream.readBitStream(bitstream); var current_face = 0; //keep track of connected component start //t.vertex_count = 0; var front = new Uint32Array(this.node.nface*18); var front_count = 0; //count each integer so it's front_back*5 function addFront(_v0, _v1, _v2, _prev, _next) { front[front_count++] = _v0; front[front_count++] = _v1; front[front_count++] = _v2; front[front_count++] = _prev; front[front_count++] = _next; front[front_count++] = 0; //deleted } function _next(t) { t++; if(t == 3) t = 0; return t; } function _prev(t) { t--; if(t == -1) t = 2; return t; } var delayed = []; var faceorder = []; var faces_count = start; //count indices in this.faces array var totfaces = length; // var estimated = [0, 0, 0]; //no! use stack. var stack = this.stack; var coords = this.coords; var texcoords = this.texcoords; var hasTexCoords = t.sig.texcoords; while(totfaces > 0) { if(!faceorder.length && !delayed.length) { if(current_face == this.node.nface) break; //no more faces to encode exiting stack[0] = stack[1] = stack[2] = 0; stack[7] = stack[8] = 0; //texcoords var last_index = -1; var index = []; for(var k = 0; k < 3; k++) { this.last[this.last_count++] = last_index; var diff = diffs[diff_count++]; var tdiff = diff && hasTexCoords? tdiffs[tdiff_count++] : 0; var v = this.decodeVertex(bitstream, diff, tdiff); index[k] = v; this.faces[faces_count++] = v; stack[0] = coords[v*3]; stack[1] = coords[v*3+1]; stack[2] = coords[v*3+2]; if(t.sig.texcoords) { stack[7] = texcoords[v*2]; stack[8] = texcoords[v*2+1]; } last_index = v; } var current_edge = front_count; for(var k = 0; k < 3; k++) { faceorder.push(front_count); front[front_count++] = index[_next(k)]; front[front_count++] = index[_prev(k)]; front[front_count++] = index[k]; front[front_count++] = current_edge + _prev(k)*6; front[front_count++] = current_edge + _next(k)*6; front_count++; // addFront(index[_next(k)], index[_prev(k)], index[k], current_edge + _prev(k)*6, current_edge + _next(k)*6); } current_face++; totfaces--; continue; } var f; if(faceorder.length) f = faceorder.shift(); else f = delayed.pop(); var edge_start = f; if(front[edge_start + 5]) continue; //deleted front[edge_start + 5] = 1; //set edge as deleted anyway var c = clers[cler_count++]; if(c == 4) continue; //BOUNDARY var v0 = front[edge_start + 0]; var v1 = front[edge_start + 1]; var v2 = front[edge_start + 2]; var prev = front[edge_start + 3]; var next = front[edge_start + 4]; var first_edge = front_count; //points to new edge to be inserted var opposite = -1; if(c == 0) { //VERTEX //predict position based on v0, v1 and v2 for(var k = 0; k < 3; k++) stack[k] = coords[v0*3 + k] + coords[v1*3 + k] - coords[v2*3 + k]; if(hasTexCoords) for(var k = 0; k < 2; k++) stack[7+k] = texcoords[v0*2 + k] + texcoords[v1*2 + k] - texcoords[v2*2 + k]; var diff = diffs[diff_count++]; var tdiff = diff && hasTexCoords? tdiffs[tdiff_count++] : 0; opposite = this.decodeVertex(bitstream, diff, tdiff); if(diff != 0) this.last[this.last_count++] = v1; front[prev + 4] = first_edge; front[next + 3] = first_edge + 6; faceorder.unshift(front_count); front[front_count++] = v0; front[front_count++] = opposite; front[front_count++] = v1; front[front_count++] = prev; front[front_count++] = first_edge+6; front_count++; // addFront(v0, opposite, v1, prev, first_edge + 6); faceorder.push(front_count); front[front_count++] = opposite; front[front_count++] = v1; front[front_count++] = v0; front[front_count++] = first_edge; front[front_count++] = next; front_count++; // addFront(opposite, v1, v0, first_edge, next); } else if(c == 3) { //END front[prev + 5] = 1; front[next + 5] = 1; front[front[prev + 3] + 4] = front[next + 4]; front[front[next + 4] + 3] = front[prev + 3]; opposite = front[prev + 0]; } else if(c == 1) { //LEFT front[prev + 5] = 1; //deleted front[front[prev + 3] + 4] = first_edge; front[next + 3] = first_edge; opposite = front[prev + 0]; faceorder.unshift(front_count); front[front_count++] = opposite; front[front_count++] = v1; front[front_count++] = v0; front[front_count++] = front[prev +3]; front[front_count++] = next; front_count++; // addFront(opposite, v1, v0, front[prev + 3], next); } else if(c == 2) { //RIGHT front[next + 5] = 1; front[front[next + 4] + 3] = first_edge; front[prev + 4] = first_edge; opposite = front[next + 1]; faceorder.unshift(front_count); front[front_count++] = v0; front[front_count++] = opposite; front[front_count++] = v1; front[front_count++] = prev; front[front_count++] = front[next+4]; front_count++; // addFront(v0, opposite, v1, prev, front[next + 4]); } else if(c == 5) { //DELAY front[edge_start + 5] = 0; delayed.push(edge_start); continue; } this.faces[faces_count++] = v1; this.faces[faces_count++] = v0; this.faces[faces_count++] = opposite; totfaces--; } }, decodeVertex: function(bitstream, diff, tdiff) { if(diff == 0) return bitstream.read(16); var v = this.vertex_count++; var max = 1<<(diff-1); for(var k = 0; k < 3; k++) { var d = bitstream.read(diff) - max; this.coords[v*3+k] = this.stack[k] + d; //stack 0-3 is used as extimated } if(this.sig.texcoords) { var tmax = 1<<(tdiff-1); for(var k = 0; k < 2; k++) { var d = bitstream.read(tdiff) - tmax; this.texcoords[v*2+k] = this.stack[7+k] + d; //stack 7-9 is used as extimated } } return v; }, decodeDiff: function(diff, bitstream) { var val; if(diff == 0) { return 0; } val = 1<>>= 1; else val = -(val>>>1); return val; } }; var tot = 0;