Dynamically determines how to split patch into triangles

This commit is contained in:
Yury Delendik 2014-01-29 09:41:08 -06:00
parent a583c319a1
commit 561683d2e9

View File

@ -380,63 +380,82 @@ Shadings.Mesh = (function MeshClosure() {
}); });
} }
var SPLIT_PATCH_CHUNKS_AMOUNT = 4; var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;
var B = (function buildB() { var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;
var lut = [];
for (var i = 0; i <= SPLIT_PATCH_CHUNKS_AMOUNT; i++) { var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds
var t = i / SPLIT_PATCH_CHUNKS_AMOUNT, t_ = 1 - t;
lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_, var getB = (function getBClosure() {
3 * t * t * t_, t * t * t])); function buildB(count) {
var lut = [];
for (var i = 0; i <= count; i++) {
var t = i / count, t_ = 1 - t;
lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_,
3 * t * t * t_, t * t * t]));
}
return lut;
} }
return lut; var cache = [];
return function getB(count) {
if (!cache[count]) {
cache[count] = buildB(count);
}
return cache[count];
};
})(); })();
function buildFigureFromPatch(mesh, pi, ci) { function buildFigureFromPatch(mesh, index) {
if (SPLIT_PATCH_CHUNKS_AMOUNT < 3) { var figure = mesh.figures[index];
mesh.figures.push({ assert(figure.type === 'patch', 'Unexpected patch mesh figure');
type: 'lattice',
coords: new Int32Array([pi[0], pi[3], pi[12], pi[15]]),
colors: new Int32Array(ci),
verticesPerRow: 2
});
return;
}
var coords = mesh.coords, colors = mesh.colors; var coords = mesh.coords, colors = mesh.colors;
var verticesPerRow = SPLIT_PATCH_CHUNKS_AMOUNT + 1; var pi = figure.coords;
var figureCoords = new Int32Array((SPLIT_PATCH_CHUNKS_AMOUNT + 1) * var ci = figure.colors;
verticesPerRow);
var figureColors = new Int32Array((SPLIT_PATCH_CHUNKS_AMOUNT + 1) * var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0],
verticesPerRow); coords[pi[12]][0], coords[pi[15]][0]);
var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1],
coords[pi[12]][1], coords[pi[15]][1]);
var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0],
coords[pi[12]][0], coords[pi[15]][0]);
var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1],
coords[pi[12]][1], coords[pi[15]][1]);
var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY /
(mesh.bounds[2] - mesh.bounds[0]));
splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));
var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY /
(mesh.bounds[3] - mesh.bounds[1]));
splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));
var verticesPerRow = splitXBy + 1;
var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);
var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);
var k = 0; var k = 0;
var cl = new Uint8Array(3), cr = new Uint8Array(3); var cl = new Uint8Array(3), cr = new Uint8Array(3);
var c0 = colors[ci[0]], c1 = colors[ci[1]], var c0 = colors[ci[0]], c1 = colors[ci[1]],
c2 = colors[ci[2]], c3 = colors[ci[3]]; c2 = colors[ci[2]], c3 = colors[ci[3]];
for (var row = 0; row <= SPLIT_PATCH_CHUNKS_AMOUNT; row++) { var bRow = getB(splitYBy), bCol = getB(splitXBy);
cl[0] = ((c0[0] * (SPLIT_PATCH_CHUNKS_AMOUNT - row) + for (var row = 0; row <= splitYBy; row++) {
c2[0] * row) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0; cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0;
cl[1] = ((c0[1] * (SPLIT_PATCH_CHUNKS_AMOUNT - row) + cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0;
c2[1] * row) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0; cl[2] = ((c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy) | 0;
cl[2] = ((c0[2] * (SPLIT_PATCH_CHUNKS_AMOUNT - row) +
c2[2] * row) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0;
cr[0] = ((c1[0] * (SPLIT_PATCH_CHUNKS_AMOUNT - row) + cr[0] = ((c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy) | 0;
c3[0] * row) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0; cr[1] = ((c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy) | 0;
cr[1] = ((c1[1] * (SPLIT_PATCH_CHUNKS_AMOUNT - row) + cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0;
c3[1] * row) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0;
cr[2] = ((c1[2] * (SPLIT_PATCH_CHUNKS_AMOUNT - row) +
c3[2] * row) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0;
for (var col = 0; col <= SPLIT_PATCH_CHUNKS_AMOUNT; col++, k++) { for (var col = 0; col <= splitXBy; col++, k++) {
if ((row === 0 || row === SPLIT_PATCH_CHUNKS_AMOUNT) && if ((row === 0 || row === splitYBy) &&
(col === 0 || col === SPLIT_PATCH_CHUNKS_AMOUNT)) { (col === 0 || col === splitXBy)) {
continue; continue;
} }
var x = 0, y = 0; var x = 0, y = 0;
var q = 0; var q = 0;
for (var i = 0; i <= 3; i++) { for (var i = 0; i <= 3; i++) {
for (var j = 0; j <= 3; j++, q++) { for (var j = 0; j <= 3; j++, q++) {
var m = B[row][i] * B[col][j]; var m = bRow[row][i] * bCol[col][j];
x += coords[pi[q]][0] * m; x += coords[pi[q]][0] * m;
y += coords[pi[q]][1] * m; y += coords[pi[q]][1] * m;
} }
@ -445,30 +464,27 @@ Shadings.Mesh = (function MeshClosure() {
coords.push([x, y]); coords.push([x, y]);
figureColors[k] = colors.length; figureColors[k] = colors.length;
var newColor = new Uint8Array(3); var newColor = new Uint8Array(3);
newColor[0] = ((cl[0] * (SPLIT_PATCH_CHUNKS_AMOUNT - col) + newColor[0] = ((cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy) | 0;
cr[0] * col) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0; newColor[1] = ((cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy) | 0;
newColor[1] = ((cl[1] * (SPLIT_PATCH_CHUNKS_AMOUNT - col) + newColor[2] = ((cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy) | 0;
cr[1] * col) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0;
newColor[2] = ((cl[2] * (SPLIT_PATCH_CHUNKS_AMOUNT - col) +
cr[2] * col) / SPLIT_PATCH_CHUNKS_AMOUNT) | 0;
colors.push(newColor); colors.push(newColor);
} }
} }
figureCoords[0] = pi[0]; figureCoords[0] = pi[0];
figureColors[0] = ci[0]; figureColors[0] = ci[0];
figureCoords[SPLIT_PATCH_CHUNKS_AMOUNT] = pi[3]; figureCoords[splitXBy] = pi[3];
figureColors[SPLIT_PATCH_CHUNKS_AMOUNT] = ci[1]; figureColors[splitXBy] = ci[1];
figureCoords[verticesPerRow * SPLIT_PATCH_CHUNKS_AMOUNT] = pi[12]; figureCoords[verticesPerRow * splitYBy] = pi[12];
figureColors[verticesPerRow * SPLIT_PATCH_CHUNKS_AMOUNT] = ci[2]; figureColors[verticesPerRow * splitYBy] = ci[2];
figureCoords[verticesPerRow * verticesPerRow - 1] = pi[15]; figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15];
figureColors[verticesPerRow * verticesPerRow - 1] = ci[3]; figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];
mesh.figures.push({ mesh.figures[index] = {
type: 'lattice', type: 'lattice',
coords: figureCoords, coords: figureCoords,
colors: figureColors, colors: figureColors,
verticesPerRow: verticesPerRow verticesPerRow: verticesPerRow
}); };
} }
function decodeType6Shading(mesh, reader) { function decodeType6Shading(mesh, reader) {
@ -571,7 +587,11 @@ Shadings.Mesh = (function MeshClosure() {
2 * (coords[ps[12]][1] + coords[ps[3]][1]) + 2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9
]); ]);
buildFigureFromPatch(mesh, ps, cs); mesh.figures.push({
type: 'patch',
coords: new Int32Array(ps), // making copies of ps and cs
colors: new Int32Array(cs)
});
} }
} }
@ -629,10 +649,27 @@ Shadings.Mesh = (function MeshClosure() {
cs[0] = ci; cs[1] = ci + 1; cs[0] = ci; cs[1] = ci + 1;
break; break;
} }
buildFigureFromPatch(mesh, ps, cs); mesh.figures.push({
type: 'patch',
coords: new Int32Array(ps), // making copies of ps and cs
colors: new Int32Array(cs)
});
} }
} }
function updateBounds(mesh) {
var minX = mesh.coords[0][0], minY = mesh.coords[0][1],
maxX = minX, maxY = minY;
for (var i = 1, ii = mesh.coords.length; i < ii; i++) {
var x = mesh.coords[i][0], y = mesh.coords[i][1];
minX = minX > x ? x : minX;
minY = minY > y ? y : minY;
maxX = maxX < x ? x : maxX;
maxY = maxY < y ? y : maxY;
}
mesh.bounds = [minX, minY, maxX, maxY];
}
function Mesh(stream, matrix, xref, res) { function Mesh(stream, matrix, xref, res) {
assert(isStream(stream), 'Mesh data is not a stream'); assert(isStream(stream), 'Mesh data is not a stream');
var dict = stream.dict; var dict = stream.dict;
@ -688,6 +725,7 @@ Shadings.Mesh = (function MeshClosure() {
}; };
var reader = new MeshStreamReader(stream, decodeContext); var reader = new MeshStreamReader(stream, decodeContext);
var patchMesh = false;
switch (this.shadingType) { switch (this.shadingType) {
case PatternType.FREE_FORM_MESH: case PatternType.FREE_FORM_MESH:
decodeType4Shading(this, reader); decodeType4Shading(this, reader);
@ -699,26 +737,26 @@ Shadings.Mesh = (function MeshClosure() {
break; break;
case PatternType.COONS_PATCH_MESH: case PatternType.COONS_PATCH_MESH:
decodeType6Shading(this, reader); decodeType6Shading(this, reader);
patchMesh = true;
break; break;
case PatternType.TENSOR_PATCH_MESH: case PatternType.TENSOR_PATCH_MESH:
decodeType7Shading(this, reader); decodeType7Shading(this, reader);
patchMesh = true;
break; break;
default: default:
error('Unsupported mesh type.'); error('Unsupported mesh type.');
break; break;
} }
// calculate bounds if (patchMesh) {
var minX = this.coords[0][0], minY = this.coords[0][1], // dirty bounds calculation for determining, how dense shall be triangles
maxX = minX, maxY = minY; updateBounds(this);
for (var i = 1, ii = this.coords.length; i < ii; i++) { for (var i = 0, ii = this.figures.length; i < ii; i++) {
var x = this.coords[i][0], y = this.coords[i][1]; buildFigureFromPatch(this, i);
minX = minX > x ? x : minX; }
minY = minY > y ? y : minY;
maxX = maxX < x ? x : maxX;
maxY = maxY < y ? y : maxY;
} }
this.bounds = [minX, minY, maxX, maxY]; // calculate bounds
updateBounds(this);
} }
Mesh.prototype = { Mesh.prototype = {