diff --git a/js/kiri-conf.js b/js/kiri-conf.js index 9faf91bc..d14a706a 100644 --- a/js/kiri-conf.js +++ b/js/kiri-conf.js @@ -302,13 +302,16 @@ let gs_kiri_conf = exports; slaShell: 1.00, slaOpenTop: false, slaOpenBase: false, + slaLayerOff: 0.1, slaLayerOn: 8, - slaLayerOff: 1, - slaBaseLayers: 8, - slaBaseOn: 90, slaPeelDist: 6, - slaPeelLift: 3, - slaPeelDrop: 3 + slaPeelLiftRate: 3, + slaPeelDropRate: 3, + slaBaseLayers: 8, + slaBaseOff: 0.2, + slaBaseOn: 90, + slaBasePeelDist: 6, + slaBasePeelLiftRate: 3, } }, cam:{ diff --git a/js/kiri-driver-sla.js b/js/kiri-driver-sla.js index 8492a089..dbc33e2f 100644 --- a/js/kiri-driver-sla.js +++ b/js/kiri-driver-sla.js @@ -24,7 +24,10 @@ let gs_kiri_sla = exports; printRender }, SLICER = KIRI.slicer, - newPoint = BASE.newPoint; + newPoint = BASE.newPoint, + preview, + previewSmall, + previewLarge; /** * DRIVER SLICE CONTRACT - runs in worker @@ -53,14 +56,16 @@ let gs_kiri_sla = exports; let b64 = atob(currentSnap); let bin = Uint8Array.from(b64, c => c.charCodeAt(0)); - let img = new png.PNG().parse(bin); - console.log({img}) + let img = new png.PNG().parse(bin, (err, data) => { + preview = img; + previewSmall = samplePNG(img, 200, 125); + previewLarge = samplePNG(img, 400, 300); + }); SLICER.sliceWidget(widget, { height: process.slaSlice || 0.05 }, function(slices) { - slices = slices.filter(slice => slice.tops.length); - widget.slices = slices; + widget.slices = slices.filter(slice => slice.tops.length); // reset for solids and support projections slices.forEach(function(slice) { slice.invalidateFill(); @@ -69,22 +74,22 @@ let gs_kiri_sla = exports; slice.isSolidFill = false; }); let solidLayers = Math.round(process.slaShell / process.slaSlice); - forSlices(slices, 0.0, 0.2, (slice,index) => { + forSlices(slices, 0.1, 0.3, (slice,index) => { if (process.slaShell) { slice.doShells(2, 0, process.slaShell); } else { slice.doShells(1, 0); } }, "slice"); - forSlices(slices, 0.2, 0.4, (slice) => { + forSlices(slices, 0.3, 0.6, (slice) => { slice.doDiff(0.00001, 0.005, true); }, "delta"); if (solidLayers) { - forSlices(slices, 0.4, 0.5, (slice) => { + forSlices(slices, 0.6, 0.7, (slice) => { slice.projectFlats(solidLayers); slice.projectBridges(solidLayers); }, "project"); - forSlices(slices, 0.5, 0.6, (slice) => { + forSlices(slices, 0.7, 0.9, (slice) => { slice.doSolidsFill(undefined, undefined, 0.001); let traces = POLY.nest(POLY.flatten(slice.gatherTraces([]))); let trims = slice.solids.trimmed || []; @@ -93,7 +98,7 @@ let gs_kiri_sla = exports; slice.solids.unioned = union; }, "solid"); } else { - forSlices(slices, 0.4, 0.6, (slice) => { + forSlices(slices, 0.6, 0.9, (slice) => { slice.solids.unioned = slice.gatherTopPolys([]); }) } @@ -185,8 +190,15 @@ let gs_kiri_sla = exports; print.images.forEach(image => { online(image.data, [image.data.buffer]); }); - - ondone({width:2560,height:1440}); + ondone({ + width:2560, + height:1440, + small:previewSmall.data, + large:previewLarge.data + },[ + previewSmall.data.buffer, + previewLarge.data.buffer + ]); }; // runs in browser main @@ -268,7 +280,9 @@ let gs_kiri_sla = exports; width = print.sla.done.width, height = print.sla.done.height, layerCount = print.sla.lines.length, - layerBytes = width * height; + layerBytes = width * height, + small = print.sla.done.small, + large = print.sla.done.large; let converted = print.sla.lines.map((line, index) => { let count = line.length / 4; @@ -289,7 +303,8 @@ let gs_kiri_sla = exports; }); let coded = encodeLayers(converted, "photon"); - let filebuf = new ArrayBuffer(3000 + coded.length + layerCount * 28); + let buflen = 3000 + coded.length + layerCount * 28 + small.byteLength + large.byteLength; + let filebuf = new ArrayBuffer(buflen); let filedat = new DataWriter(new DataView(filebuf)); let printtime = (process.slaBaseLayers * process.slaBaseOn) + (coded.layers.length - process.slaBaseLayers) * process.slaLayerOn; @@ -322,31 +337,27 @@ let gs_kiri_sla = exports; filedat.writeU16(0x00ff, true); // light pwm bottom (TODO); filedat.view.setUint32(hirez, filedat.pos, true); - // write hirez preview header - filedat.writeU32(0, true); // res x - filedat.writeU32(0, true); // res y - filedat.writeU32(filedat.pos + 4, true); // data pos - filedat.writeU32(0, true); // data len - filedat.skip(16); // padding - // write hirez preview data + writePhotonImage({ + width: 400, + height: 300, + data: print.sla.done.large + }, filedat); filedat.view.setUint32(lorez, filedat.pos, true); - // write lorez preview header - filedat.writeU32(0, true); // res x - filedat.writeU32(0, true); // res y - filedat.writeU32(filedat.pos + 4, true); // data pos - filedat.writeU32(0, true); // data len - filedat.skip(16); // padding - // write lorez preview data + writePhotonImage({ + width: 200, + height: 125, + data: print.sla.done.small + }, filedat); let propstart = filedat.pos; filedat.view.setUint32(proppos, filedat.pos, true); // write print properties - filedat.writeF32(process.slaPeelDist, true); // default or base? - filedat.writeF32(process.slaPeelLift * 60 , true); // speed - filedat.writeF32(process.slaPeelDist, true); // default or base? - filedat.writeF32(process.slaPeelLift * 60 , true); // speed - filedat.writeF32(process.slaPeelDrop * 60, true); // speed + filedat.writeF32(process.slaBasePeelDist, true); + filedat.writeF32(process.slaBasePeelLiftRate * 60 , true); + filedat.writeF32(process.slaPeelDist, true); + filedat.writeF32(process.slaPeelLiftRate * 60 , true); + filedat.writeF32(process.slaPeelDropRate * 60, true); filedat.writeF32(0, true); // volume of used filedat.writeF32(0, true); // weight of used filedat.writeF32(0, true); // cost of used @@ -365,23 +376,20 @@ let gs_kiri_sla = exports; let layerat = []; for (let l=0; l 4/3) { + div = png.height / tw; + xoff = Math.round((png.width - (th * div)) / 2); + yoff = 0; + } else { + div = png.width / th; + xoff = 0; + yoff = Math.round((png.height - (tw * div)) / 2); + } + + for (let y=0; y png.height) continue; + ey = Math.round((y+1) * div + yoff); + for (let x=0; x png.width) continue; + ex = Math.round((x+1) * div + xoff); + bidx = (y * th + x) * 4; + pixval = averageBlock(png,dx,dy,ex,ey); + buf[bidx+0] = pixval[0]; + buf[bidx+1] = pixval[1]; + buf[bidx+2] = pixval[2]; + buf[bidx+3] = pixval[3]; + } + } + + return {width, height, data:buf, png}; + } + + function writePhotonImage(preview, writer) { + let data = new Uint8Array(preview.data), len = data.byteLength; + writer.writeU32(preview.width, true); + writer.writeU32(preview.height, true); + let hpos = writer.skip(4); + writer.writeU32(len/2, true); + writer.view.setUint32(hpos, writer.pos, true); + let pos = 0; + while (pos < len) { + let r = data[pos++], + g = data[pos++], + b = data[pos++], + a = data[pos++], + v = (((r/4)&0x1f) << 11) | + (((g/4)&0x1f) << 6) | + (((b/4)&0x1f) << 0) ; + writer.writeU16(v, true); + } + } + })(); class DataWriter { diff --git a/js/kiri-init.js b/js/kiri-init.js index 757e340f..10e7c891 100644 --- a/js/kiri-init.js +++ b/js/kiri-init.js @@ -1441,14 +1441,21 @@ var gs_kiri_init = exports; slaShell: UC.newInput('hollow shell', {title:'shell thickness in mm\nuse multiple of layer height\nuse 0 for solid', convert:UC.toFloat, modes:SLA}), slaOpenTop: UC.newBoolean('open top', onBooleanClick, {title:'solid layers', modes:SLA}), slaOpenBase: UC.newBoolean('open base', onBooleanClick, {title:'bottom layers', modes:SLA}), - slaOutput: UC.newGroup('output', null, {modes:SLA, group:"sla-output"}), - slaLayerOn: UC.newInput('layer on', {title:'layer light on\ntime in seconds', convert:UC.toFloat, modes:SLA}), - slaLayerOff: UC.newInput('layer off', {title:'layer light off\ntime in seconds', convert:UC.toFloat, modes:SLA}), - slaBaseLayers: UC.newInput('base count', {title:'number of\nbase layers', convert:UC.toInt, modes:SLA}), - slaBaseOn: UC.newInput('base on', {title:'base layer light on\ntime in seconds', convert:UC.toFloat, modes:SLA}), - slaPeelDist: UC.newInput('peel dist', {title:'peel distance\nin millimeters', convert:UC.toFloat, modes:SLA}), - slaPeelLift: UC.newInput('peel lift', {title:'peel lift speed\nin mm/sec', convert:UC.toFloat, modes:SLA}), - slaPeelDrop: UC.newInput('peel drop', {title:'peel drop speed\nin mm/sec', convert:UC.toFloat, modes:SLA}), + + // SLA + slaOutput: UC.newGroup('layers', null, {modes:SLA, group:"sla-layers"}), + slaLayerOn: UC.newInput('light on time', {title:'layer light on\ntime in seconds', convert:UC.toFloat, modes:SLA}), + slaLayerOff: UC.newInput('light off time', {title:'layer light off\ntime in seconds', convert:UC.toFloat, modes:SLA}), + slaPeelDist: UC.newInput('peel distance', {title:'peel distance\nin millimeters', convert:UC.toFloat, modes:SLA}), + slaPeelLiftRate: UC.newInput('peel lift rate', {title:'peel lift speed\nin mm/sec', convert:UC.toFloat, modes:SLA}), + slaPeelDropRate: UC.newInput('peel drop rate', {title:'peel drop speed\nin mm/sec', convert:UC.toFloat, modes:SLA}), + + slaOutput: UC.newGroup('base layers', null, {modes:SLA, group:"sla-base"}), + slaBaseLayers: UC.newInput('layer count', {title:'number of\nbase layers', convert:UC.toInt, modes:SLA}), + slaBaseOn: UC.newInput('light on time', {title:'base layer light on\ntime in seconds', convert:UC.toFloat, modes:SLA}), + slaBaseOff: UC.newInput('light off time', {title:'base layer light on\ntime in seconds', convert:UC.toFloat, modes:SLA}), + slaBasePeelDist: UC.newInput('peel distance', {title:'peel distance\nin millimeters', convert:UC.toFloat, modes:SLA}), + slaBasePeelLiftRate: UC.newInput('peel lift rate', {title:'peel lift speed\nin mm/sec', convert:UC.toFloat, modes:SLA}), }); if (!LOCAL) {