fix png import
This commit is contained in:
parent
6566c45f9a
commit
1f470555ec
6 changed files with 263 additions and 38 deletions
|
|
@ -4,4 +4,4 @@
|
||||||
import './pngjs.js';
|
import './pngjs.js';
|
||||||
|
|
||||||
// Re-export the PNG object
|
// Re-export the PNG object
|
||||||
export const PNG = self.png;
|
export const PNG = self.png.PNG;
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as STL from './stl.js';
|
import { STL } from './stl.js';
|
||||||
import * as OBJ from './obj.js';
|
import * as OBJ from './obj.js';
|
||||||
import * as TMF from './3mf.js';
|
import * as TMF from './3mf.js';
|
||||||
import * as SVG from './svg.js';
|
import * as SVG from './svg.js';
|
||||||
|
|
@ -39,7 +39,7 @@ const types = {
|
||||||
png(data, file, resolve, reject, opt = {}) {
|
png(data, file, resolve, reject, opt = {}) {
|
||||||
pngLoad.PNG.parse(data, {
|
pngLoad.PNG.parse(data, {
|
||||||
...opt,
|
...opt,
|
||||||
done(vertices) { resolve(vertices) },
|
done(vertices) { resolve({ mesh: vertices, file }) },
|
||||||
error(err) { reject(err) }
|
error(err) { reject(err) }
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -100,5 +100,4 @@ function load_file(file, opt) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export { types, as_buffer, load_data, load_file };
|
export { types, as_buffer, load_data, load_file, load_file as load };
|
||||||
export { load_file as load };
|
|
||||||
|
|
|
||||||
268
src2/load/png.js
268
src2/load/png.js
|
|
@ -4,28 +4,254 @@ import { PNG } from '../ext/pngjs.esm.js';
|
||||||
|
|
||||||
export const load = {
|
export const load = {
|
||||||
PNG: {
|
PNG: {
|
||||||
parse: function(data, opt = {}) {
|
parseAsync,
|
||||||
let img = new PNG();
|
parse
|
||||||
let progress = opt.progress || noop;
|
|
||||||
let ondone = opt.done || noop;
|
|
||||||
let onerror = opt.error || noop;
|
|
||||||
let onmeta = opt.meta || noop;
|
|
||||||
|
|
||||||
img.on('metadata', function(meta) {
|
|
||||||
onmeta(meta);
|
|
||||||
});
|
|
||||||
|
|
||||||
img.on('parsed', function(data) {
|
|
||||||
ondone(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
img.on('error', function(err) {
|
|
||||||
onerror(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
img.parse(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function parseAsync(bin, opt) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
parse(bin, {
|
||||||
|
...opt,
|
||||||
|
done(vertices) { resolve(vertices) }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* opt.outWidth = target output width in mm
|
||||||
|
* opt.outHeight = target output height in mm
|
||||||
|
* opt.inv_image = invert image data 255 - depth
|
||||||
|
* opt.inv_alpha = invert alpha interp 255 - alpha
|
||||||
|
* opt.border = border thickness in mm
|
||||||
|
* opt.blur = blur value in mm
|
||||||
|
* opt.base = base added thickness in mm
|
||||||
|
*/
|
||||||
|
function parse(bin, opt = {}) {
|
||||||
|
let img = new png.PNG();
|
||||||
|
let progress = opt.progress || noop;
|
||||||
|
let ondone = opt.done || noop;
|
||||||
|
img.parse(bin, (err, output) => {
|
||||||
|
let { width, height, data } = output;
|
||||||
|
// let { outHeight, outWidth } = opt;
|
||||||
|
let outHeight = opt.outHeight || height;
|
||||||
|
let outWidth = opt.outWidth || width;
|
||||||
|
let imageAspect = height / width;
|
||||||
|
let deviceAspect = outHeight / outWidth;
|
||||||
|
let div = 1;
|
||||||
|
if (imageAspect < deviceAspect) {
|
||||||
|
div = width / outWidth;
|
||||||
|
} else {
|
||||||
|
div = height / outHeight;
|
||||||
|
}
|
||||||
|
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 = opt.inv_image ? true : false;
|
||||||
|
let inva = opt.inv_alpha ? true : false;
|
||||||
|
let border = opt.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(opt.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(opt.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
// return ArrayBuffer
|
||||||
|
ondone(bigv);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function noop() {}
|
function noop() {}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import { split as meshSplit } from '../mesh/split.js';
|
||||||
import { model as meshModel, materials } from '../mesh/model.js';
|
import { model as meshModel, materials } from '../mesh/model.js';
|
||||||
import { edges as meshEdges } from '../mesh/edges.js';
|
import { edges as meshEdges } from '../mesh/edges.js';
|
||||||
import { load as fileLoad } from '../load/file.js';
|
import { load as fileLoad } from '../load/file.js';
|
||||||
import { $, $d, estop } from '../moto/webui.js';
|
import { $, $d, h, estop } from '../moto/webui.js';
|
||||||
import { THREE } from '../ext/three.js';
|
import { THREE } from '../ext/three.js';
|
||||||
|
|
||||||
const { Quaternion } = THREE;
|
const { Quaternion } = THREE;
|
||||||
|
|
@ -487,7 +487,7 @@ function load_files(files) {
|
||||||
has_gbr = has_gbr || file.name.toLowerCase().endsWith(".gbr") > 0;
|
has_gbr = has_gbr || file.name.toLowerCase().endsWith(".gbr") > 0;
|
||||||
}
|
}
|
||||||
if (sketch && has_gbr) {
|
if (sketch && has_gbr) {
|
||||||
fileLoad.load([...files], { flat: true }).then(layers => {
|
fileLoad([...files], { flat: true }).then(layers => {
|
||||||
for (let layer of layers.flat()) {
|
for (let layer of layers.flat()) {
|
||||||
let { circs, closed, open, rects } = layer;
|
let { circs, closed, open, rects } = layer;
|
||||||
open = open.map(poly => {
|
open = open.map(poly => {
|
||||||
|
|
@ -504,7 +504,7 @@ function load_files(files) {
|
||||||
});
|
});
|
||||||
} else
|
} else
|
||||||
if (sketch && has_svg) {
|
if (sketch && has_svg) {
|
||||||
fileLoad.load([...files], { flat: true })
|
fileLoad([...files], { flat: true })
|
||||||
.then(polys => polys.forEach(set => {
|
.then(polys => polys.forEach(set => {
|
||||||
let group = meshApi.util.uuid();
|
let group = meshApi.util.uuid();
|
||||||
set.forEach(poly => sketch.add.polygon({ poly, group }))
|
set.forEach(poly => sketch.add.polygon({ poly, group }))
|
||||||
|
|
@ -582,7 +582,7 @@ function load_files(files) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function load_files_opt(files, opt) {
|
function load_files_opt(files, opt) {
|
||||||
return fileLoad.load([...files], opt)
|
return fileLoad([...files], opt)
|
||||||
.then(data => call.space_load(data))
|
.then(data => call.space_load(data))
|
||||||
.catch(error => log(error).pin({}) && dbug.error(error))
|
.catch(error => log(error).pin({}) && dbug.error(error))
|
||||||
// .finally(() => meshApi.log.hide());
|
// .finally(() => meshApi.log.hide());
|
||||||
|
|
|
||||||
|
|
@ -399,7 +399,7 @@ const group = {
|
||||||
// @param group {MeshGroup}
|
// @param group {MeshGroup}
|
||||||
add(group) {
|
add(group) {
|
||||||
groups.addOnce(group);
|
groups.addOnce(group);
|
||||||
motoSpace.world.add(group.object);
|
motoSpace.world.add(group.object);
|
||||||
meshUtil.defer(selection.update);
|
meshUtil.defer(selection.update);
|
||||||
motoSpace.update();
|
motoSpace.update();
|
||||||
return group;
|
return group;
|
||||||
|
|
@ -749,7 +749,7 @@ let add = {
|
||||||
const vert = (api.modal.bound.genvrt.value)
|
const vert = (api.modal.bound.genvrt.value)
|
||||||
.split(',').map(v => parseFloat(v)).toFloat32();
|
.split(',').map(v => parseFloat(v)).toFloat32();
|
||||||
const nmdl = new meshModel({ file: "input", mesh: vert });
|
const nmdl = new meshModel({ file: "input", mesh: vert });
|
||||||
const ngrp = group.new([ nmdl ]);
|
const ngrp = api.group.new([ nmdl ]);
|
||||||
api.modal.hide();
|
api.modal.hide();
|
||||||
} })
|
} })
|
||||||
]) ]
|
]) ]
|
||||||
|
|
@ -761,7 +761,7 @@ let add = {
|
||||||
const box = new THREE.BoxGeometry(1,1,1).toNonIndexed();
|
const box = new THREE.BoxGeometry(1,1,1).toNonIndexed();
|
||||||
const vert = box.attributes.position.array;
|
const vert = box.attributes.position.array;
|
||||||
const nmdl = new meshModel({ file: "box", mesh: vert });
|
const nmdl = new meshModel({ file: "box", mesh: vert });
|
||||||
const ngrp = group.new([ nmdl ]);
|
const ngrp = api.group.new([ nmdl ]);
|
||||||
ngrp.scale(10, 10, 10).floor();
|
ngrp.scale(10, 10, 10).floor();
|
||||||
selection.set([ nmdl ]);
|
selection.set([ nmdl ]);
|
||||||
return ngrp;
|
return ngrp;
|
||||||
|
|
@ -781,7 +781,7 @@ let add = {
|
||||||
}
|
}
|
||||||
const vert = cyl.extrude(height, { chamfer }).toFloat32();
|
const vert = cyl.extrude(height, { chamfer }).toFloat32();
|
||||||
const nmdl = new meshModel({ file: "cylinder", mesh: vert });
|
const nmdl = new meshModel({ file: "cylinder", mesh: vert });
|
||||||
const ngrp = group.new([ nmdl ]);
|
const ngrp = api.group.new([ nmdl ]);
|
||||||
selection.set([ nmdl ]);
|
selection.set([ nmdl ]);
|
||||||
ngrp.floor();
|
ngrp.floor();
|
||||||
}
|
}
|
||||||
|
|
@ -1150,7 +1150,7 @@ const tool = {
|
||||||
models = fallback(models, true);
|
models = fallback(models, true);
|
||||||
if (models.length) {
|
if (models.length) {
|
||||||
log(`regrouping ${models.length} model(s)`);
|
log(`regrouping ${models.length} model(s)`);
|
||||||
let group = new meshGroup(models.map(m => m.ungroup()));
|
let group = api.group.new(models.map(m => m.ungroup()));
|
||||||
let bounds = group.bounds;
|
let bounds = group.bounds;
|
||||||
models.forEach(m => m.centerTo(bounds.mid));
|
models.forEach(m => m.centerTo(bounds.mid));
|
||||||
return group;
|
return group;
|
||||||
|
|
@ -1170,7 +1170,7 @@ const tool = {
|
||||||
mesh: area.toFloat32()
|
mesh: area.toFloat32()
|
||||||
})).map( nm => nm.applyMatrix4(mcore.clone().multiply(m.mesh.matrixWorld)) );
|
})).map( nm => nm.applyMatrix4(mcore.clone().multiply(m.mesh.matrixWorld)) );
|
||||||
if (nm.length) {
|
if (nm.length) {
|
||||||
new meshGroup(nm, undefined, "patch");
|
api.group.new(nm, undefined, "patch");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
promises.push(p);
|
promises.push(p);
|
||||||
|
|
@ -1192,7 +1192,7 @@ const tool = {
|
||||||
file: m.file,
|
file: m.file,
|
||||||
mesh: vert.toFloat32()
|
mesh: vert.toFloat32()
|
||||||
})).map( nm => nm.applyMatrix4(mcore.clone().multiply(m.mesh.matrixWorld)) );
|
})).map( nm => nm.applyMatrix4(mcore.clone().multiply(m.mesh.matrixWorld)) );
|
||||||
new meshGroup(bodies, undefined, "isolate");
|
api.group.new(bodies, undefined, "isolate");
|
||||||
});
|
});
|
||||||
promises.push(p);
|
promises.push(p);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@ class MeshModel extends meshObject {
|
||||||
super(id);
|
super(id);
|
||||||
let { file, mesh, vertices } = data;
|
let { file, mesh, vertices } = data;
|
||||||
|
|
||||||
if (!mesh) {
|
if (!(mesh || vertices)) {
|
||||||
dbug.error(`'${file}' missing mesh data`);
|
meshApi.dbug.error(`'${file}' missing mesh data`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue