extract png loader from kiri worker so it can be shared with mesh

This commit is contained in:
Stewart Allen 2022-02-25 23:49:51 -05:00
commit 87df96d23f
6 changed files with 280 additions and 245 deletions

View file

@ -8,6 +8,7 @@
// dep: kiri.codec
// dep: kiri.slice
// dep: moto.license
// use: load.png
// use: kiri.render
// use: kiri-mode.cam.animate
// use: kiri-mode.cam.slice
@ -594,225 +595,17 @@ kiri.worker = {
},
image2mesh(info, send) {
let img = new png.PNG();
img.parse(info.png, (err, output) => {
let { width, height, data } = output;
let { bedDepth, bedWidth } = info.settings.device;
let imageAspect = height / width;
let deviceAspect = bedDepth / bedWidth;
let div = 1;
if (imageAspect < deviceAspect) {
div = width / bedWidth;
} else {
div = height / bedDepth;
}
let points =
width * height + // grid
height * 2 + 0 + // left/right
width * 2 + 0; // top/bottom
let flats =
((height-1) * (width-1)) + // surface
((height-1) * 2) + // left/right
((width-1) * 2) + // top/bottom
1; // base
// convert png to grayscale
let gray = new Uint8Array(width * height);
let alpha = new Uint8Array(width * height);
let gi = 0;
let invi = info.inv_image ? true : false;
let inva = info.inv_alpha ? true : false;
let border = info.border || 0;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let di = (x + width * y) * 4;
let r = data[di];
let g = data[di+1];
let b = data[di+2];
let a = data[di+3];
let v = ((r + g + b) / 3);
if (inva) a = 255 - a;
if (invi) v = 255 - v;
if (border) {
if (x < border || y < border || x > width-border-1 || y > height-border-1) {
v = 255;
}
}
alpha[gi] = a;
gray[gi++] = v * (a / 255);
}
}
let blur = parseInt(info.blur || 0);
while (blur-- > 0) {
let blur = new Uint8Array(width * height);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let xl = Math.max(x-1,0);
let xr = Math.min(x+1,width-1);
let yu = Math.max(y-1,0);
let yd = Math.min(y+1,height-1);
let id = x + width * y;
blur[id] = ((
gray[xl + (width * yu)] +
gray[x + (width * yu)] +
gray[xr + (width * yu)] +
gray[xl + (width * y)] +
gray[x + (width * y)] * 8 + // self
gray[xr + (width * y)] +
gray[xl + (width * yd)] +
gray[x + (width * yd)] +
gray[xr + (width * yd)]
) / 16);
}
}
gray = blur;
}
// create indexed mesh output
let base = parseInt(info.base || 0);
let verts = new Float32Array(points * 3);
let faces = new Uint32Array(flats * 6);
let w2 = width / 2;
let h2 = height / 2;
let vi = 0;
let ii = 0;
let VI = 0;
let VB = 0;
// create surface vertices & faces
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
let id = x + width * y;
let v = gray[id];
// create vertex @ x,y
verts[vi++] = (-w2 + x) / div;
verts[vi++] = (h2 - y) / div;
verts[vi++] = (v / 50) + (base * alpha[id] / 255);
VI++;
// create two surface faces on the rect between x-1,y-1 and x,y
if (x > 0 && y > 0) {
let p1 = (x - 1) * height + (y - 0);
let p2 = (x - 0) * height + (y - 1);
let p3 = (x - 0) * height + (y - 0);
let p4 = (x - 1) * height + (y - 1);
faces[ii++] = p1;
faces[ii++] = p3;
faces[ii++] = p2;
faces[ii++] = p1;
faces[ii++] = p2;
faces[ii++] = p4;
}
}
send.data({progress: x / width});
}
// create top vertices & faces
VB = VI;
let TL = VI;
for (let x = 0; x < width; x++) {
let y = 0;
verts[vi++] = (-w2 + x) / div;
verts[vi++] = (h2 - y) / div;
verts[vi++] = 0;
VI++;
// create two top faces on the rect x-1,0, x,z
if (x > 0) {
let p1 = VB + (x - 1);
let p2 = VB + (x - 0);
let p3 = (x * height);
let p4 = (x - 1) * height;
faces[ii++] = p1;
faces[ii++] = p3;
faces[ii++] = p2;
faces[ii++] = p1;
faces[ii++] = p4;
faces[ii++] = p3;
}
}
// create bottom vertices & faces
VB = VI;
let BL = VI;
for (let x = 0; x < width; x++) {
let y = height - 1;
verts[vi++] = (-w2 + x) / div;
verts[vi++] = (h2 - y) / div;
verts[vi++] = 0;
VI++;
// create two top faces on the rect x-1,0, x,z
if (x > 0) {
let p1 = VB + (x - 1);
let p2 = VB + (x - 0);
let p3 = (x * height) + y;
let p4 = (x - 1) * height + y;
faces[ii++] = p1;
faces[ii++] = p2;
faces[ii++] = p3;
faces[ii++] = p1;
faces[ii++] = p3;
faces[ii++] = p4;
}
}
// create left vertices & faces
VB = VI;
for (let y=0; y < height; y++) {
let x = 0;
verts[vi++] = (-w2 + x) / div;
verts[vi++] = (h2 - y) / div;
verts[vi++] = 0;
VI++;
// create two left faces on the rect y-1,0, y,z
if (y > 0) {
let p1 = VB + (y + 0);
let p2 = VB + (y - 1);
let p3 = 0 + (y - 1);
let p4 = 0 + (y - 0);
faces[ii++] = p1;
faces[ii++] = p3;
faces[ii++] = p2;
faces[ii++] = p1;
faces[ii++] = p4;
faces[ii++] = p3;
}
}
// create right vertices & faces
VB = VI;
let TR = VI;
for (let y=0; y < height; y++) {
let x = width - 1;
verts[vi++] = (-w2 + x) / div;
verts[vi++] = (h2 - y) / div;
verts[vi++] = 0;
VI++;
// create two right faces on the rect y-1,0, y,z
if (y > 0) {
let p1 = VB + (y + 0);
let p2 = VB + (y - 1);
let p3 = (x * height) + (y - 1);
let p4 = (x * height) + (y - 0);
faces[ii++] = p1;
faces[ii++] = p2;
faces[ii++] = p3;
faces[ii++] = p1;
faces[ii++] = p3;
faces[ii++] = p4;
}
}
let BR = VI-1;
// create base two faces
faces[ii++] = TL;
faces[ii++] = TR;
faces[ii++] = BR;
faces[ii++] = TL;
faces[ii++] = BR;
faces[ii++] = BL;
// flatten for now until we support indexed mesh
// throughout KM (widget, storage, decimation)
let bigv = new Float32Array(ii * 3);
let bgi = 0;
for (let i=0; i<ii; i++) {
let iv = faces[i] * 3;
bigv[bgi++] = verts[iv];
bigv[bgi++] = verts[iv+1];
bigv[bgi++] = verts[iv+2];
}
// send.done({done: {verts, faces, bigv, vi, ii}}, [ bigv.buffer ]);
send.done({done: {bigv}}, [ bigv.buffer ]);
let { device } = info.settings;
load.PNG.parse(info.png, {
outWidth: device.bedDepth,
outHeight: device.bedWidth,
inv_image: info.inv_image,
inv_alpha: info.inv_alpha,
border: info.border,
blur: info.blur,
base: info.base,
progress(progress) { send.data({ progress }) },
done(vertices) { send.done({ vertices }, [ vertices.buffer ])}
});
},