├── .gitignore
├── LICENSE.md
├── README.md
├── assets
└── sdf.png
├── examples
├── basic
│ ├── .gitignore
│ ├── blend.js
│ ├── elongate.js
│ ├── map.js
│ ├── operations.js
│ ├── package-lock.json
│ ├── package.json
│ └── shapes.js
└── obj-export
│ ├── .gitignore
│ ├── export-cpu-threaded.js
│ ├── export-cpu-threaded.sh
│ ├── export-cpu.js
│ ├── export-cpu.sh
│ ├── export-gpu.js
│ ├── export-gpu.sh
│ ├── package-lock.json
│ ├── package.json
│ └── shared.js
├── lerna.json
├── package-lock.json
├── package.json
└── packages
├── display-sdf
├── .gitignore
├── LICENSE.md
├── README.md
├── assets
│ └── screen.png
├── display-mesh.js
├── display-raw.js
├── implicit-mesh.js
├── index.js
├── package-lock.json
└── package.json
├── hiccup-sdf-to-obj
├── .gitignore
├── LICENSE.md
├── README.md
├── assets
│ └── screen.png
├── gpu.js
├── gpu
│ ├── electron.js
│ ├── index.html
│ ├── index.js
│ ├── spawn.js
│ └── test.js
├── index.js
├── package-lock.json
├── package.json
├── test
│ ├── map-gpu.js
│ ├── map.js
│ ├── sphere.js
│ └── union.js
├── threaded.js
└── threaded
│ ├── implicit-mesh.js
│ └── worker.js
└── hiccup-sdf
├── .gitignore
├── LICENSE.md
├── README.md
├── assets
└── screen.png
├── dsl.js
├── glsl-helpers.js
├── glsl-stl.js
├── index.js
├── package-lock.json
├── package.json
└── test
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | *.tgz
4 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Szymon Kaliski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hiccup-sdf
2 |
3 | Monorepository holding tools for modeling with signed distance functions using hiccup-like language, works both on CPU and GPU.
4 | Provides multiple primitives, basic operations, and custom `map` function for working over large amounts of data efficiently.
5 |
6 |
7 |
8 |
9 |
10 | ## Projects
11 |
12 | Each project contains detailed README file.
13 |
14 | - [`hiccup-sdf`](./packages/hiccup-sdf) - main library
15 | - [`display-sdf`](./packages/display-sdf) - utility for displaying SDFs
16 | - [`hiccup-sdf-to-obj`](./packages/hiccup-sdf-to-obj) - utility for exporting `hiccup-sdf` models to OBJs
17 |
18 | ## Examples
19 |
20 | - [`basic`](./examples/basic) - example usage of `hiccup-sdf` and `display-sdf`
21 | - [`obj-export`](./examples/obj-export) - examples of exporting `hiccup-sdf` models to OBJs
22 |
23 | ## Future Work
24 |
25 | PRs welcome!
26 |
27 | - [ ] consistent `map` function for CPU and GPU
28 | - [ ] threaded meshing for model trees containing functions
29 | - [ ] support for custom user-defined functions
30 |
31 | ## Acknowledgements
32 |
33 | This project was developed in part at Laboratory, an artist residency for interactive arts: [https://laboratoryspokane.com](https://laboratoryspokane.com).
34 |
35 |
--------------------------------------------------------------------------------
/assets/sdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/szymonkaliski/hiccup-sdf/715089e16fbfcfbacd85ca5249709cf6d1ca2a9e/assets/sdf.png
--------------------------------------------------------------------------------
/examples/basic/.gitignore:
--------------------------------------------------------------------------------
1 | .sketchbook_cli
2 |
--------------------------------------------------------------------------------
/examples/basic/blend.js:
--------------------------------------------------------------------------------
1 | const { displayRaw } = require("display-sdf");
2 | const { compileShader, glslHelpers } = require("hiccup-sdf");
3 |
4 | const range = length => Array.from({ length }, (_, i) => i);
5 |
6 | const steps = range(10).map(i => {
7 | return [
8 | "translate",
9 | { t: [i / 10 - 0.5, 0, 0] },
10 | [
11 | [
12 | "blend",
13 | { k: i / 10 },
14 | [["torus", { r1: 0.01, r2: 0.03 }], ["box", { s: [0.03, 0.03, 0.03] }]]
15 | ]
16 | ]
17 | ];
18 | });
19 |
20 | const tree = [
21 | "scale",
22 | { s: 2.0 },
23 | [["rotate", { r: [0.1, 0.25, 0.5] }, [["union", steps]]]]
24 | ];
25 |
26 | const { inject, model } = compileShader(tree);
27 | const shader = glslHelpers.createShaderFull(model, inject);
28 |
29 | displayRaw(shader);
30 |
--------------------------------------------------------------------------------
/examples/basic/elongate.js:
--------------------------------------------------------------------------------
1 | const { displayRaw } = require("display-sdf");
2 | const { compileShader, glslHelpers } = require("hiccup-sdf");
3 |
4 | const range = length => Array.from({ length }, (_, i) => i);
5 |
6 | const steps = range(10).map(i => {
7 | return [
8 | "translate",
9 | { t: [i / 10 - 0.5, 0, 0] },
10 | [
11 | [
12 | "elongate",
13 | { s: [0.0, (i / 10) * 0.5, 0.0] },
14 | [["torus", { r1: 0.001, r2: 0.03 }]]
15 | ]
16 | ]
17 | ];
18 | });
19 |
20 | const tree = [
21 | "scale",
22 | { s: 1.5 },
23 | [["rotate", { r: [0.1, 0, -0.25] }, [["union", steps]]]]
24 | ];
25 |
26 | const { inject, model } = compileShader(tree);
27 | const shader = glslHelpers.createShaderFull(model, inject);
28 |
29 | displayRaw(shader);
30 |
--------------------------------------------------------------------------------
/examples/basic/map.js:
--------------------------------------------------------------------------------
1 | const { displayMesh } = require("display-sdf");
2 | const { compileShader, glslHelpers } = require("hiccup-sdf");
3 | const SimplexNoise = require("simplex-noise");
4 | const simplex = new SimplexNoise();
5 |
6 | const position = [];
7 |
8 | const size = 32;
9 |
10 | for (let x = -size / 2; x < size / 2; x = ++x) {
11 | for (let z = -size / 2; z < size / 2; z = ++z) {
12 | for (let y = -size / 2; y < size / 2; y = ++y) {
13 | const nMod = 0.05;
14 | const n = simplex.noise3D(x * nMod, y * nMod, z * nMod);
15 | const d = Math.sqrt(x * x + y * y + z * z);
16 |
17 | if (n > 0.5 && d < size * 0.49) {
18 | position.push([x / size, y / size, z / size]);
19 | }
20 | }
21 | }
22 | }
23 |
24 | const tree = [
25 | "map",
26 | {
27 | data: { position },
28 | map: props => [
29 | "translate",
30 | { t: `${props.position}.xyz` },
31 | [["box", { s: [0.02, 0.02, 0.02] }]]
32 | ],
33 | reduce: ["union", { r: 0.0 }]
34 | }
35 | ];
36 |
37 | const { inject, uniforms, model } = compileShader(tree);
38 | const shader = glslHelpers.createShaderModel(model, inject);
39 |
40 | displayMesh(shader, { textures: uniforms, size: 128, refine: false });
41 |
--------------------------------------------------------------------------------
/examples/basic/operations.js:
--------------------------------------------------------------------------------
1 | const { displayRaw } = require("display-sdf");
2 | const { compileShader, glslHelpers } = require("hiccup-sdf");
3 |
4 | const t = ([x, y], children) => ["translate", { t: [x, 0, y] }, [children]];
5 | const b = ["box", { s: [0.05, 0.05, 0.05] }];
6 |
7 | const b2 = [
8 | t([-0.04, 0], b),
9 | t([0.04, 0], ["rotate", { r: [0, 0, 0.25] }, [b]])
10 | ];
11 |
12 | const shapes = [
13 | t([-0.6, -0.6], ["union", b2]),
14 | t([-0.6, -0.3], ["union", { r: 0.05 }, b2]),
15 | t([-0.6, 0.0], ["intersection", b2]),
16 | t([-0.6, 0.3], ["difference", b2]),
17 |
18 | t([-0.2, -0.3], ["scale", { s: 0.5 }, [b]]),
19 | t([-0.2, 0.0], ["rotate", { r: [0.25, 0.25, 0] }, [b]]),
20 | t([-0.2, 0.3], ["mirror", { m: [0.075, 0, 0] }, [b]]),
21 |
22 | t([0.3, 0.0], ["repeat", { r: [0.0, 0.0, 0.25] }, [b]]),
23 | t([0.7, 0.0], ["repeatPolar", { r: 6 }, [t([0.25, 0], b)]])
24 | ];
25 |
26 | const tree = ["rotate", { r: [0, 0, 0.25] }, [["union", shapes]]];
27 |
28 | const { inject, model } = compileShader(tree);
29 | const shader = glslHelpers.createShaderFull(model, inject);
30 |
31 | displayRaw(shader);
32 |
--------------------------------------------------------------------------------
/examples/basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-basic",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "sketchbook-cli . --port 3000"
7 | },
8 | "author": "Szymon Kaliski (http://szymonkaliski.com)",
9 | "license": "MIT",
10 | "dependencies": {
11 | "display-sdf": "latest",
12 | "hiccup-sdf": "0.0.9",
13 | "simplex-noise": "^2.4.0"
14 | },
15 | "devDependencies": {
16 | "sketchbook-cli": "^1.4.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/basic/shapes.js:
--------------------------------------------------------------------------------
1 | const { displayRaw } = require("display-sdf");
2 | const { compileShader, glslHelpers } = require("hiccup-sdf");
3 |
4 | const t = ([x, y], children) => ["translate", { t: [x, 0, y] }, [children]];
5 |
6 | const shapes = [
7 | t([0, -0.2], ["box", { s: [0.05, 0.05, 0.05] }]),
8 | t([0, 0], ["sphere", { r: 0.05 }]),
9 | t([0, 0.2], ["torus", { r1: 0.025, r2: 0.05 }]),
10 | t([0.2, -0.2], ["hex", { r: 0.05, h: 0.025 }]),
11 | t([0.2, 0], ["triangle", { r: 0.05, h: 0.025 }]),
12 | t([0.2, 0.2], ["capsule", { a: [-0.025, 0, 0], b: [0.025, 0, 0], r: 0.025 }]),
13 | t([-0.2, -0.2], ["cylinder", { r: 0.05, h: 0.025 }])
14 | ];
15 |
16 | const tree = [
17 | "scale",
18 | { s: 2.0 },
19 | [["rotate", { r: [0, 0, 0.25] }, [["union", shapes]]]]
20 | ];
21 |
22 | const { inject, model } = compileShader(tree);
23 | const shader = glslHelpers.createShaderFull(model, inject);
24 |
25 | displayRaw(shader);
26 |
--------------------------------------------------------------------------------
/examples/obj-export/.gitignore:
--------------------------------------------------------------------------------
1 | *.obj
2 |
--------------------------------------------------------------------------------
/examples/obj-export/export-cpu-threaded.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 | const sdfToObj = require("hiccup-sdf-to-obj/threaded");
4 |
5 | const { points } = require("./shared");
6 |
7 | // map function is currently not supported for threaded cpu export,
8 | // use gpu export, or flatten the tree:
9 |
10 | const tree = [
11 | "difference",
12 | {},
13 | [
14 | ["sphere", { r: 0.4 }],
15 | [
16 | "union",
17 | { r: 0.05 },
18 | points.map(t => ["translate", { t }, [["sphere", { r: 0.1 }]]])
19 | ]
20 | ]
21 | ];
22 |
23 | sdfToObj(tree, { size: 256 }, objStr => {
24 | fs.writeFileSync(path.join(__dirname, "export-cpu-threaded.obj"), objStr);
25 | });
26 |
--------------------------------------------------------------------------------
/examples/obj-export/export-cpu-threaded.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | time node --experimental-worker ./export-cpu-threaded.js
4 |
--------------------------------------------------------------------------------
/examples/obj-export/export-cpu.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 | const sdfToObj = require("hiccup-sdf-to-obj");
4 |
5 | const { points } = require("./shared");
6 |
7 | const tree = [
8 | "difference",
9 | {},
10 | [
11 | ["sphere", { r: 0.4 }],
12 | [
13 | "map",
14 | {
15 | data: { points },
16 | map: props => [
17 | "translate",
18 | { t: props.points },
19 | [["sphere", { r: 0.1 }]]
20 | ],
21 | reduce: ["union", { r: 0.05 }]
22 | }
23 | ]
24 | ]
25 | ];
26 |
27 | sdfToObj(tree, { size: 64 }, objStr => {
28 | fs.writeFileSync(path.join(__dirname, "export-cpu.obj"), objStr);
29 | });
30 |
--------------------------------------------------------------------------------
/examples/obj-export/export-cpu.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | time node ./export-cpu.js
4 |
--------------------------------------------------------------------------------
/examples/obj-export/export-gpu.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 | const sdfToObj = require("hiccup-sdf-to-obj/gpu");
4 |
5 | const { points } = require("./shared");
6 |
7 | const tree = [
8 | "difference",
9 | {},
10 | [
11 | ["sphere", { r: 0.4 }],
12 | [
13 | "map",
14 | {
15 | data: { points },
16 | map: props => [
17 | "translate",
18 | { t: `${props.points}.xyz` },
19 | [["sphere", { r: 0.1 }]]
20 | ],
21 | reduce: ["union", { r: 0.05 }]
22 | }
23 | ]
24 | ]
25 | ];
26 |
27 | sdfToObj(tree, { size: 256 }, objStr => {
28 | fs.writeFileSync(path.join(__dirname, "export-gpu.obj"), objStr);
29 | });
30 |
--------------------------------------------------------------------------------
/examples/obj-export/export-gpu.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | time node ./export-gpu.js
4 |
5 |
--------------------------------------------------------------------------------
/examples/obj-export/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exammple-obj",
3 | "version": "1.0.0",
4 | "private": true,
5 | "author": "Szymon Kaliski (http://szymonkaliski.com)",
6 | "license": "MIT",
7 | "dependencies": {
8 | "display-sdf": "latest",
9 | "hiccup-sdf": "latest",
10 | "hiccup-sdf-to-obj": "latest",
11 | "simplex-noise": "^2.4.0"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/obj-export/shared.js:
--------------------------------------------------------------------------------
1 | const randomSpherePosition = r => {
2 | const u = Math.random();
3 | const v = Math.random();
4 |
5 | const theta = 2 * Math.PI * u;
6 | const phi = Math.acos(2 * v - 1);
7 |
8 | const x = r * Math.sin(phi) * Math.cos(theta);
9 | const y = r * Math.sin(phi) * Math.sin(theta);
10 | const z = r * Math.cos(phi);
11 |
12 | return [x, y, z];
13 | };
14 |
15 | const range = length => Array.from({ length }, (_, i) => i);
16 |
17 | const points = range(100).map(() => randomSpherePosition(0.4));
18 |
19 | module.exports = { points };
20 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*"
4 | ],
5 | "version": "independent"
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "bootstrap": "lerna bootstrap",
5 | "publish:init": "lerna exec 'npm publish --access public'",
6 | "publish": "lerna publish"
7 | },
8 | "dependencies": {
9 | "lerna": "^3.4.3"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/display-sdf/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/packages/display-sdf/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Szymon Kaliski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/display-sdf/README.md:
--------------------------------------------------------------------------------
1 | # display-sdf
2 |
3 | Helper library for displaying SDFs, supports rendering "straight" from GPU, or meshing with surface-nets and displaying as a mesh.
4 |
5 |
6 |
7 |
8 |
9 | ## Installation
10 |
11 | `npm install display-sdf --save`
12 |
13 | ## Basic Usage
14 |
15 | ```js
16 | const { displayRaw } = require("display-sdf");
17 |
18 | // generate shaderCode
19 |
20 | displayRaw(shaderCode);
21 | ```
22 |
23 | In combination with `hiccup-sdf`:
24 |
25 | ```js
26 | const { displayRaw } = require("display-sdf");
27 | const { compileShader, glslHelpers } = require("hiccup-sdf");
28 |
29 | const tree = ["box"]
30 |
31 | const { inject, model } = compileShader(tree);
32 | const shader = glslHelpers.createShaderFull(model, inject);
33 |
34 | displayRaw(shader);
35 | ```
36 |
37 | ## Meshing
38 |
39 | Sometimes working with "straight" GPU rendering is not ideal, so `display-sdf` provides an option to mesh the SDF using surface-nets, and display afterwards:
40 |
41 | ```js
42 | const { displayRaw } = require("display-sdf");
43 |
44 | // generate shaderCode
45 |
46 | displayMesh(shader, { size: 128 });
47 | ```
48 |
49 | ## API
50 |
51 | All options are optional.
52 |
53 | ### `displayRaw(shaderCode, [options])`
54 |
55 | - `shaderCode` - stringified SDF GLSL code
56 | - `options.textures` - custom data textures to pass to the shader, used by `hiccup-sdf` `map` function to work over large amounts of data
57 |
58 | ### `displayMesh(shaderCode, [options])`
59 |
60 | - `shaderCode` - stringified SDF GLSL code
61 | - `options.size` - size of the surface-nets field (uniform box, so `128` becomes `[128, 128, 128]`)
62 | - `options.textures` - custom data textures to pass to the shader, used by `hiccup-sdf` `map` function to work over large amounts of data
63 | - `options.refine` - should [`refine-mesh`](https://github.com/mikolalysenko/refine-mesh) be executed after meshing, this usually makes the output look nicer (`true`/`false`)
64 | - `options.refineOptions` - [custom options to pass to `refine-mesh`](https://github.com/mikolalysenko/refine-mesh#api)
65 |
66 | ## Acknowledgements
67 |
68 | This project was developed in part at Laboratory, an artist residency for interactive arts: [https://laboratoryspokane.com](https://laboratoryspokane.com).
69 |
70 |
--------------------------------------------------------------------------------
/packages/display-sdf/assets/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/szymonkaliski/hiccup-sdf/715089e16fbfcfbacd85ca5249709cf6d1ca2a9e/packages/display-sdf/assets/screen.png
--------------------------------------------------------------------------------
/packages/display-sdf/display-mesh.js:
--------------------------------------------------------------------------------
1 | const angleNormals = require("angle-normals");
2 | const createCamera = require("regl-camera");
3 | const createRegl = require("regl");
4 | const memoSync = require("persistent-memo/memo-sync");
5 | const refineMesh = require("refine-mesh");
6 |
7 | const implicitMesh = require("./implicit-mesh");
8 |
9 | module.exports = (
10 | sdfShader,
11 | {
12 | size = 128,
13 | textures = {},
14 | memoize = false,
15 | refine = false,
16 | refineOptions = {}
17 | } = {}
18 | ) => {
19 | const memo = memoize ? memoSync : fn => (...args) => fn(...args);
20 |
21 | const generateMesh = memo((size, sdfShader, textures) => {
22 | const makeUniforms = regl =>
23 | Object.keys(textures).reduce(
24 | (memo, key) =>
25 | Object.assign({}, memo, {
26 | [key]: regl.texture({
27 | data: textures[key],
28 | type: "float"
29 | })
30 | }),
31 | {}
32 | );
33 |
34 | let mesh = implicitMesh(size, sdfShader, makeUniforms);
35 | mesh.normals = angleNormals(mesh.cells, mesh.positions);
36 |
37 | if (refine) {
38 | mesh = refineMesh(
39 | mesh.cells,
40 | mesh.positions,
41 | mesh.normals,
42 | refineOptions
43 | );
44 | mesh.normals = angleNormals(mesh.cells, mesh.positions);
45 | }
46 |
47 | return mesh;
48 | });
49 |
50 | const mesh = generateMesh(size, sdfShader, textures);
51 |
52 | const regl = createRegl();
53 | const camera = createCamera(regl, { distance: 3 });
54 |
55 | const vert = `
56 | precision highp float;
57 |
58 | uniform mat4 projection, view;
59 | attribute vec3 position, normal;
60 | varying vec3 vNormal, vPosition;
61 | varying mat4 vView;
62 |
63 | void main () {
64 | vNormal = normal;
65 | vPosition = position;
66 | vView = view;
67 |
68 | gl_Position = projection * view * vec4(position, 1.0);
69 | }
70 | `;
71 |
72 | const frag = `
73 | precision highp float;
74 |
75 | varying vec3 vNormal, vPosition;
76 | uniform vec3 lightPosition;
77 | varying mat4 vView;
78 |
79 | float lambert(vec3 lightDirection, vec3 surfaceNormal) {
80 | return max(0.1, dot(lightDirection, surfaceNormal));
81 | }
82 |
83 | void main() {
84 | vec3 lightDirection = normalize(lightPosition - vPosition);
85 | vec3 normal = (vView * vec4(normalize(vNormal), 0.0)).xyz;
86 | float power = lambert(lightDirection, normal);
87 |
88 | gl_FragColor = vec4(power, power, power, 1.0);
89 | }
90 | `;
91 |
92 | const draw = regl({
93 | vert,
94 | frag,
95 | attributes: {
96 | position: mesh.positions,
97 | normal: mesh.normals
98 | },
99 | uniforms: {
100 | lightPosition: [0, 10, 10]
101 | },
102 | elements: mesh.cells,
103 | primitive: "triangles"
104 | });
105 |
106 | regl.frame(() => {
107 | camera(({ dirty }) => {
108 | if (!dirty) return;
109 |
110 | regl.clear({
111 | color: [0.2, 0.2, 0.2, 1.0]
112 | });
113 |
114 | draw();
115 | });
116 | });
117 |
118 | return regl;
119 | };
120 |
--------------------------------------------------------------------------------
/packages/display-sdf/display-raw.js:
--------------------------------------------------------------------------------
1 | const regl = require("regl")({
2 | extensions: ["OES_texture_float"]
3 | });
4 | const camera = createCamera(regl);
5 |
6 | function createCamera(regl) {
7 | const element = regl._gl.canvas;
8 |
9 | const state = {
10 | theta: 0,
11 | phi: 0,
12 | distance: 2
13 | };
14 |
15 | element.addEventListener("mousedown", e => {
16 | const clickX = e.clientX;
17 | const clickY = e.clientY;
18 |
19 | const startTheta = state.theta;
20 | const startPhi = state.phi;
21 |
22 | const onDrag = e => {
23 | const dx = clickX - e.clientX;
24 | const dy = clickY - e.clientY;
25 |
26 | const theta = startTheta + dx;
27 | const phi = Math.min(179.9, Math.max(-179.9, startPhi - dy));
28 |
29 | state.theta = theta;
30 | state.phi = phi;
31 | };
32 |
33 | const onUp = () => {
34 | element.removeEventListener("mousemove", onDrag);
35 | element.removeEventListener("mouseup", onUp);
36 | };
37 |
38 | element.addEventListener("mousemove", onDrag);
39 | element.addEventListener("mouseup", onUp);
40 | });
41 |
42 | const onScroll = e => {
43 | e.preventDefault();
44 |
45 | state.distance = Math.max(0, state.distance + e.deltaY / 100);
46 | };
47 |
48 | element.addEventListener("mousewheel", onScroll);
49 |
50 | return { state };
51 | }
52 |
53 | module.exports = (sdfShader, { textures = {} } = {}) => {
54 | const textureUniforms = Object.keys(textures).reduce(
55 | (memo, key) =>
56 | Object.assign({}, memo, {
57 | [key]: regl.texture({
58 | data: textures[key],
59 | type: "float"
60 | })
61 | }),
62 | {}
63 | );
64 |
65 | const uniforms = Object.assign(
66 | {
67 | width: regl.context("viewportWidth"),
68 | height: regl.context("viewportHeight"),
69 | camTheta: regl.prop("theta"),
70 | camPhi: regl.prop("phi"),
71 | camDistance: regl.prop("distance")
72 | },
73 | textureUniforms
74 | );
75 |
76 | const draw = regl({
77 | vert: `
78 | precision highp float;
79 | attribute vec2 position;
80 | void main () {
81 | gl_Position = vec4(position, 0.0, 1.0);
82 | }
83 | `,
84 | frag: sdfShader,
85 | attributes: {
86 | position: [-4, -4, 4, -4, 0, 4]
87 | },
88 | count: 3,
89 | depth: {
90 | enable: false
91 | },
92 | uniforms
93 | });
94 |
95 | regl.frame(() => {
96 | regl.clear({
97 | color: [0.2, 0.2, 0.2, 1.0]
98 | });
99 |
100 | draw(camera.state);
101 | });
102 |
103 | return regl;
104 | };
105 |
--------------------------------------------------------------------------------
/packages/display-sdf/implicit-mesh.js:
--------------------------------------------------------------------------------
1 | // adapted from https://github.com/substack/implicit-mesh
2 |
3 | const createRegl = require("regl");
4 | const ndarray = require("ndarray");
5 | const surfaceNets = require("surface-nets");
6 |
7 | const scale = (size, mesh) => {
8 | const sx = 2 / size[0];
9 | const sy = 2 / size[1];
10 | const sz = 2 / size[2];
11 |
12 | let p = mesh.positions;
13 |
14 | for (let i = 0; i < p.length; i++) {
15 | p[i][0] = p[i][0] * sx - 1;
16 | p[i][1] = p[i][1] * sy - 1;
17 | p[i][2] = p[i][2] * sz - 1;
18 | }
19 |
20 | return mesh;
21 | };
22 |
23 | const st = n => String(n).replace(/^(\d+)$/, "$1.0");
24 |
25 | module.exports = (s, src, makeUniforms) => {
26 | const size = Array.isArray(s) ? s : [s, s, s];
27 | const len = size[0] * size[1] * size[2];
28 |
29 | const sx = st(size[0]);
30 | const sy = st(size[1]);
31 | const sz = st(size[2]);
32 |
33 | const isx = st(2 / (size[0] - 1));
34 | const isy = st(2 / (size[1] - 1));
35 | const isz = st(2 / (size[2] - 1));
36 |
37 | const isxy = st(1 / (size[0] * size[1]));
38 |
39 | const sq = Math.ceil(Math.sqrt(len));
40 |
41 | const canvas = document.createElement("canvas");
42 | const regl = createRegl({
43 | canvas,
44 | extensions: ["oes_texture_float"]
45 | });
46 |
47 | const magic = {
48 | "64,64,64": (sq + size[0] * 4) * 4,
49 | "128,128,128": (sq + size[0] * 16) * 4,
50 | "100,100,100": (sq + size[0] * 10) * 4,
51 | "50,50,50": (sq + size[0] * 2 + 18) * 4
52 | };
53 |
54 | const draw = regl({
55 | framebuffer: regl.prop("framebuffer"),
56 | frag: `
57 | precision highp float;
58 |
59 | ${src}
60 |
61 | float isurface(float i) {
62 | float x = mod(i, ${sx}) * ${isx} - 1.0;
63 | float y = mod(i / ${sx}, ${sy}) * ${isy} - 1.0;
64 | float z = mod(i * ${isxy}, ${sz}) * ${isz} - 1.0;
65 |
66 | return clamp(0.5 + doModel(vec3(x, y, z)).x, 0.0, 1.0);
67 | }
68 |
69 | void main() {
70 | float i = (gl_FragCoord.x + gl_FragCoord.y * ${st(sq)})
71 | * 4.0 + ${st(magic[size] || 0)};
72 |
73 | gl_FragColor = vec4(
74 | isurface(i + 0.0),
75 | isurface(i + 1.0),
76 | isurface(i + 2.0),
77 | isurface(i + 3.0)
78 | );
79 | }
80 | `,
81 | vert: `
82 | precision highp float;
83 | attribute vec2 position;
84 |
85 | void main () {
86 | gl_Position = vec4(position, 0.0, 1.0);
87 | }
88 | `,
89 | attributes: {
90 | position: [-4, 4, 4, 4, 0, -4]
91 | },
92 | uniforms: makeUniforms ? makeUniforms(regl) : {},
93 | count: 3,
94 | depth: {
95 | enable: false
96 | }
97 | });
98 |
99 | regl.clear({ color: [0, 0, 0, 1], depth: true });
100 |
101 | const framebuffer = regl.framebuffer({
102 | width: sq,
103 | height: sq,
104 | colorFormat: "rgba",
105 | colorType: "uint8"
106 | });
107 |
108 | let mesh = {};
109 |
110 | draw({ framebuffer }, function() {
111 | regl.draw();
112 |
113 | const data = regl.read();
114 | const iv = 1 / 127.5;
115 | const ndata = new Float32Array(len);
116 |
117 | for (let i = 0; i < data.length; i++) {
118 | ndata[i] = (data[i] - 127.5) * iv;
119 | }
120 |
121 | mesh = scale(size, surfaceNets(ndarray(ndata, size)));
122 | });
123 |
124 | regl.destroy();
125 |
126 | return mesh;
127 | };
128 |
--------------------------------------------------------------------------------
/packages/display-sdf/index.js:
--------------------------------------------------------------------------------
1 | const displayRaw = require("./display-raw")
2 | const displayMesh = require("./display-mesh")
3 |
4 | module.exports = { displayRaw, displayMesh }
5 |
--------------------------------------------------------------------------------
/packages/display-sdf/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "display-sdf",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "angle-normals": {
8 | "version": "1.0.0",
9 | "resolved": "https://registry.npmjs.org/angle-normals/-/angle-normals-1.0.0.tgz",
10 | "integrity": "sha1-lYV0mGqj8ClGpFzRCMsqO4kHyaw="
11 | },
12 | "bit-twiddle": {
13 | "version": "1.0.2",
14 | "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz",
15 | "integrity": "sha1-DGwfq+KyPRcXPZpht7cJPrnhdp4="
16 | },
17 | "cwise-compiler": {
18 | "version": "1.1.3",
19 | "resolved": "https://registry.npmjs.org/cwise-compiler/-/cwise-compiler-1.1.3.tgz",
20 | "integrity": "sha1-9NZnQQ6FDToxOn0tt7HlBbsDTMU=",
21 | "requires": {
22 | "uniq": "^1.0.0"
23 | }
24 | },
25 | "dup": {
26 | "version": "1.0.0",
27 | "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz",
28 | "integrity": "sha1-UfxaxoX4GWRp3wuQXpNLIK9bQCk="
29 | },
30 | "gamma": {
31 | "version": "0.1.0",
32 | "resolved": "https://registry.npmjs.org/gamma/-/gamma-0.1.0.tgz",
33 | "integrity": "sha1-MxVkNAO/J5BsqAqzfDbs6UQO8zA="
34 | },
35 | "gl-mat4": {
36 | "version": "1.2.0",
37 | "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.2.0.tgz",
38 | "integrity": "sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA=="
39 | },
40 | "invert-permutation": {
41 | "version": "1.0.0",
42 | "resolved": "https://registry.npmjs.org/invert-permutation/-/invert-permutation-1.0.0.tgz",
43 | "integrity": "sha1-oKeAQurbNrwXVR54fv0UOa3VSTM="
44 | },
45 | "iota-array": {
46 | "version": "1.0.0",
47 | "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
48 | "integrity": "sha1-ge9X/l0FgUzVjCSDYyqZwwoOgIc="
49 | },
50 | "is-buffer": {
51 | "version": "1.1.6",
52 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
53 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
54 | },
55 | "json-fn": {
56 | "version": "1.1.1",
57 | "resolved": "https://registry.npmjs.org/json-fn/-/json-fn-1.1.1.tgz",
58 | "integrity": "sha1-QpPJGYpILWaX0zSm4yzQ0iESHoA="
59 | },
60 | "mouse-change": {
61 | "version": "1.4.0",
62 | "resolved": "https://registry.npmjs.org/mouse-change/-/mouse-change-1.4.0.tgz",
63 | "integrity": "sha1-wrd+W/o0pDzhRFyBV6Tk3JiVwU8=",
64 | "requires": {
65 | "mouse-event": "^1.0.0"
66 | }
67 | },
68 | "mouse-event": {
69 | "version": "1.0.5",
70 | "resolved": "https://registry.npmjs.org/mouse-event/-/mouse-event-1.0.5.tgz",
71 | "integrity": "sha1-s3ie23EJmX1aky0dAdqhVDpQFzI="
72 | },
73 | "mouse-wheel": {
74 | "version": "1.2.0",
75 | "resolved": "https://registry.npmjs.org/mouse-wheel/-/mouse-wheel-1.2.0.tgz",
76 | "integrity": "sha1-bSkDseqPtI5h8bU7kDZ3PwQs21w=",
77 | "requires": {
78 | "right-now": "^1.0.0",
79 | "signum": "^1.0.0",
80 | "to-px": "^1.0.1"
81 | }
82 | },
83 | "ndarray": {
84 | "version": "1.0.18",
85 | "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.18.tgz",
86 | "integrity": "sha1-tg06cyJOxVXQ+qeXEeUCRI/T95M=",
87 | "requires": {
88 | "iota-array": "^1.0.0",
89 | "is-buffer": "^1.0.2"
90 | }
91 | },
92 | "ndarray-extract-contour": {
93 | "version": "1.0.1",
94 | "resolved": "https://registry.npmjs.org/ndarray-extract-contour/-/ndarray-extract-contour-1.0.1.tgz",
95 | "integrity": "sha1-Cu4ROjozsia5DEiIz4d79HUTBeQ=",
96 | "requires": {
97 | "typedarray-pool": "^1.0.0"
98 | }
99 | },
100 | "ndarray-sort": {
101 | "version": "1.0.1",
102 | "resolved": "https://registry.npmjs.org/ndarray-sort/-/ndarray-sort-1.0.1.tgz",
103 | "integrity": "sha1-/qBbTLg0x/TgIWo1TzynUTAN/Wo=",
104 | "requires": {
105 | "typedarray-pool": "^1.0.0"
106 | }
107 | },
108 | "next-pow-2": {
109 | "version": "1.0.0",
110 | "resolved": "https://registry.npmjs.org/next-pow-2/-/next-pow-2-1.0.0.tgz",
111 | "integrity": "sha1-y1wvHa4EDFbN1c2h3FxqOjOPQ2c="
112 | },
113 | "parse-unit": {
114 | "version": "1.0.1",
115 | "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz",
116 | "integrity": "sha1-fhu21b7zh0wo45JSaiVBFwKR7s8="
117 | },
118 | "permutation-parity": {
119 | "version": "1.0.0",
120 | "resolved": "https://registry.npmjs.org/permutation-parity/-/permutation-parity-1.0.0.tgz",
121 | "integrity": "sha1-AXTVH8pwSxG5pLFSsj1Tf9xrXvQ=",
122 | "requires": {
123 | "typedarray-pool": "^1.0.0"
124 | }
125 | },
126 | "permutation-rank": {
127 | "version": "1.0.0",
128 | "resolved": "https://registry.npmjs.org/permutation-rank/-/permutation-rank-1.0.0.tgz",
129 | "integrity": "sha1-n9mLvOzwj79ZlLXq3JSmLmeUg7U=",
130 | "requires": {
131 | "invert-permutation": "^1.0.0",
132 | "typedarray-pool": "^1.0.0"
133 | }
134 | },
135 | "persistent-memo": {
136 | "version": "0.0.1",
137 | "resolved": "https://registry.npmjs.org/persistent-memo/-/persistent-memo-0.0.1.tgz",
138 | "integrity": "sha512-6dzU8xOZzve4Wq1FV5yVlcz9pztuRFh5q2wTsA4DYWxnzAXaoKynB64krrR+z6OydFG9DngWBrUOd3Rzuiqqyg==",
139 | "requires": {
140 | "json-fn": "^1.1.1"
141 | }
142 | },
143 | "refine-mesh": {
144 | "version": "1.0.1",
145 | "resolved": "https://registry.npmjs.org/refine-mesh/-/refine-mesh-1.0.1.tgz",
146 | "integrity": "sha1-u8FfSPevGwLAFLFrmqxipNXT4EA=",
147 | "requires": {
148 | "ndarray": "^1.0.18",
149 | "ndarray-sort": "^1.0.1",
150 | "next-pow-2": "^1.0.0",
151 | "typedarray-pool": "^1.1.0"
152 | }
153 | },
154 | "regl": {
155 | "version": "1.3.9",
156 | "resolved": "https://registry.npmjs.org/regl/-/regl-1.3.9.tgz",
157 | "integrity": "sha512-CungQSUBsZNYZJWJlb2sPe4iwBjmxrgl1Yxt91HN3VuuEL7lJ5k03O3T1xEXVOCMN1q8wncddwJsxozuyzzmrA=="
158 | },
159 | "regl-camera": {
160 | "version": "2.1.1",
161 | "resolved": "https://registry.npmjs.org/regl-camera/-/regl-camera-2.1.1.tgz",
162 | "integrity": "sha1-aXmm0cm4DF2Ri4CfoFdmSDzM5UY=",
163 | "requires": {
164 | "gl-mat4": "^1.1.4",
165 | "mouse-change": "^1.3.0",
166 | "mouse-wheel": "^1.2.0"
167 | }
168 | },
169 | "right-now": {
170 | "version": "1.0.0",
171 | "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz",
172 | "integrity": "sha1-bolgne69fc2vja7Mmuo5z1haCRg="
173 | },
174 | "signum": {
175 | "version": "1.0.0",
176 | "resolved": "https://registry.npmjs.org/signum/-/signum-1.0.0.tgz",
177 | "integrity": "sha1-dKfSvyogtA66FqkrFSEk8dVZ+nc="
178 | },
179 | "surface-nets": {
180 | "version": "1.0.2",
181 | "resolved": "https://registry.npmjs.org/surface-nets/-/surface-nets-1.0.2.tgz",
182 | "integrity": "sha1-5DPIy7qUpydMb0yZVStGG/H8eks=",
183 | "requires": {
184 | "ndarray-extract-contour": "^1.0.0",
185 | "triangulate-hypercube": "^1.0.0",
186 | "zero-crossings": "^1.0.0"
187 | }
188 | },
189 | "to-px": {
190 | "version": "1.0.1",
191 | "resolved": "https://registry.npmjs.org/to-px/-/to-px-1.0.1.tgz",
192 | "integrity": "sha1-W7rtXl1PdkRbzJA8KTojB90yRkY=",
193 | "requires": {
194 | "parse-unit": "^1.0.1"
195 | }
196 | },
197 | "triangulate-hypercube": {
198 | "version": "1.0.1",
199 | "resolved": "https://registry.npmjs.org/triangulate-hypercube/-/triangulate-hypercube-1.0.1.tgz",
200 | "integrity": "sha1-2Acdsuv8/VHzCNC88qXEils20Tc=",
201 | "requires": {
202 | "gamma": "^0.1.0",
203 | "permutation-parity": "^1.0.0",
204 | "permutation-rank": "^1.0.0"
205 | }
206 | },
207 | "typedarray-pool": {
208 | "version": "1.1.0",
209 | "resolved": "https://registry.npmjs.org/typedarray-pool/-/typedarray-pool-1.1.0.tgz",
210 | "integrity": "sha1-0RT0hIAUifU+yrXoCIqiMET0mNk=",
211 | "requires": {
212 | "bit-twiddle": "^1.0.0",
213 | "dup": "^1.0.0"
214 | }
215 | },
216 | "uniq": {
217 | "version": "1.0.1",
218 | "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
219 | "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
220 | },
221 | "zero-crossings": {
222 | "version": "1.0.1",
223 | "resolved": "https://registry.npmjs.org/zero-crossings/-/zero-crossings-1.0.1.tgz",
224 | "integrity": "sha1-xWK9MRNkPzRDokXRJAa4i2m5qf8=",
225 | "requires": {
226 | "cwise-compiler": "^1.0.0"
227 | }
228 | }
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/packages/display-sdf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "display-sdf",
3 | "version": "0.0.9",
4 | "description": "simple fullscreen SDF shader visualizer",
5 | "main": "index.js",
6 | "author": "Szymon Kaliski (http://szymonkaliski.com)",
7 | "license": "MIT",
8 | "dependencies": {
9 | "angle-normals": "^1.0.0",
10 | "ndarray": "^1.0.18",
11 | "persistent-memo": "^0.0.1",
12 | "refine-mesh": "^1.0.1",
13 | "regl": "^1.3.7",
14 | "regl-camera": "^2.1.1",
15 | "surface-nets": "^1.0.2"
16 | },
17 | "gitHead": "e7f441600f1b472fcf0ef1396399c465ea258d0e"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .git
3 | *.obj
4 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Szymon Kaliski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/README.md:
--------------------------------------------------------------------------------
1 | # hiccup-sdf-to-obj
2 |
3 | Tools for exporting `hiccup-sdf` models to OBJs. Supports single CPU, threaded CPU and GPU mashing. Designed for offline export in node.js.
4 |
5 |
6 |
7 |
8 |
9 | ## Installation
10 |
11 | `npm install hiccup-sdf-to-obj --save`
12 |
13 | ## Usage
14 |
15 | ### CPU meshing
16 |
17 | ```js
18 | const fs = require("fs")
19 | const sdfToObj = require("hiccup-sdf-to-obj")
20 |
21 | const tree = ["sphere"];
22 |
23 | sdfToObj(tree, obj => {
24 | fs.writeFileSync(path.join(__dirname, "sphere.obj"), obj);
25 | });
26 | ```
27 |
28 | `$ node export-obj.js`
29 |
30 | ### Threaded CPU meshing
31 |
32 | Uses [worker threads](https://nodejs.org/api/worker_threads.html):
33 |
34 | ```js
35 | const fs = require("fs")
36 | const sdfToObj = require("hiccup-sdf-to-obj/threaded")
37 |
38 | const tree = ["sphere"];
39 |
40 | sdfToObj(tree, obj => {
41 | fs.writeFileSync(path.join(__dirname, "sphere.obj"), obj);
42 | });
43 | ```
44 |
45 | `$ node --experimental-worker export-obj.js`
46 |
47 | **Warning:** currently `map` from `hiccup-sdf` is not supported in threaded export!
48 |
49 | ### GPU meshing
50 |
51 | Uses offscreen Electron to render on GPU and mesh to OBJ.
52 |
53 | ```js
54 | const fs = require("fs")
55 | const sdfToObj = require("hiccup-sdf-to-obj/gpu")
56 |
57 | const tree = ["sphere"];
58 |
59 | sdfToObj(tree, obj => {
60 | fs.writeFileSync(path.join(__dirname, "sphere.obj"), obj);
61 | });
62 | ```
63 |
64 | `$ node export-obj.js`
65 |
66 | ## API
67 |
68 | All options are optional.
69 |
70 | ### `sdfToObj(tree, [options], callback)`
71 |
72 | - `tree` - `hiccup-sdf` model tree
73 | - `options.size` - resolution for meshing, `128` is the default, for GPU meshing `256` usually gives nicer results, for single CPU `64` is recommended for speed (but ugly exports)
74 | - `options.threads` - number of threads to spawn, works only with `threaded` exports, defaults to `4`
75 | - `callback(obj)` - callback called with obj string if succeeded, otherwise `null`
76 |
77 | ## Acknowledgements
78 |
79 | This project was developed in part at Laboratory, an artist residency for interactive arts: [https://laboratoryspokane.com](https://laboratoryspokane.com).
80 |
81 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/assets/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/szymonkaliski/hiccup-sdf/715089e16fbfcfbacd85ca5249709cf6d1ca2a9e/packages/hiccup-sdf-to-obj/assets/screen.png
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/gpu.js:
--------------------------------------------------------------------------------
1 | const serializeObj = require("serialize-wavefront-obj");
2 | const spawnGPU = require("./gpu/spawn");
3 | const { compileShader, glslHelpers } = require("hiccup-sdf");
4 |
5 | module.exports = (tree, options, callback) => {
6 | if (!callback) {
7 | callback = options;
8 | options = { size: 128 };
9 | }
10 |
11 | const { inject, uniforms, model } = compileShader(tree);
12 | const shader = glslHelpers.createShaderModel(model, inject);
13 |
14 | spawnGPU({ shader, uniforms }, options, data => {
15 | if (data) {
16 | const { cells, positions } = data;
17 | const str = serializeObj(cells, positions);
18 | return callback(str);
19 | }
20 |
21 | callback();
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/gpu/electron.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const { app, BrowserWindow, ipcMain } = require("electron");
3 | const ipc = require("node-ipc");
4 |
5 | ipc.config.id = "child";
6 | ipc.config.retry = 2000;
7 | ipc.config.silent = true;
8 | ipc.config.sync = true;
9 |
10 | ipc.connectTo("server", () => {
11 | ipc.of.server.on("connect", () => {
12 | app.dock.hide();
13 |
14 | app.on("ready", () => {
15 | const win = new BrowserWindow({
16 | show: false,
17 | webPreferences: {
18 | webgl: true,
19 | offscreen: true
20 | }
21 | });
22 |
23 | win.loadURL("file://" + path.join(__dirname, "index.html"));
24 |
25 | ipcMain.on("mesh", (_, mesh) => {
26 | ipc.of.server.emit("mesh", mesh);
27 | });
28 |
29 | ipc.of.server.on("close", () => {
30 | ipc.disconnect("server");
31 | app.exit();
32 | });
33 |
34 | win.webContents.on("did-finish-load", () => {
35 | ipc.of.server.emit("did-finish-load");
36 | });
37 |
38 | ipc.of.server.on("shader", data => {
39 | win.webContents.send("shader", data);
40 | });
41 | });
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/gpu/index.html:
--------------------------------------------------------------------------------
1 |
27 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/gpu/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/szymonkaliski/hiccup-sdf/715089e16fbfcfbacd85ca5249709cf6d1ca2a9e/packages/hiccup-sdf-to-obj/gpu/index.js
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/gpu/spawn.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const { spawn } = require("child_process");
3 | const ipc = require("node-ipc");
4 |
5 | ipc.config.id = "server";
6 | ipc.config.retry = 2000;
7 | ipc.config.silent = true;
8 | ipc.config.sync = true;
9 |
10 | module.exports = ({ shader, uniforms }, options, callback) => {
11 | ipc.serve(() => {
12 | const spawned = spawn(
13 | path.join(__dirname, "../node_modules/.bin/electron"),
14 | [path.join(__dirname, "electron.js")],
15 | {
16 | env: Object.assign(
17 | {
18 | ELECTRON_DISABLE_SECURITY_WARNINGS: true
19 | },
20 | process.env
21 | )
22 | }
23 | );
24 |
25 | spawned.stderr.on("data", data => {
26 | console.log("[gpu err]", data.toString());
27 | });
28 |
29 | spawned.stdout.on("data", data => {
30 | console.log("[gpu]", data.toString());
31 | });
32 |
33 | ipc.server.on("mesh", (mesh, socket) => {
34 | ipc.server.emit(socket, "close");
35 | ipc.server.stop();
36 | callback(mesh);
37 | });
38 |
39 | ipc.server.on("did-finish-load", (_, socket) => {
40 | ipc.server.emit(socket, "shader", { shader, uniforms, options });
41 | });
42 | });
43 |
44 | ipc.server.start();
45 | };
46 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/gpu/test.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const spawnMesher = require("./spawn");
3 |
4 | console.time("mesher");
5 | spawnMesher(path.join(__dirname, "../objects/01.js"), (err, data) => {
6 | console.timeEnd("mesher");
7 |
8 | // if (err) {
9 | // console.error("err", err);
10 | // }
11 |
12 | // if (data) {
13 | // console.log(data);
14 | // }
15 | });
16 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/index.js:
--------------------------------------------------------------------------------
1 | const implicitMesh = require("implicit-mesh");
2 | const serializeObj = require("serialize-wavefront-obj");
3 | const { compileFunction } = require("hiccup-sdf");
4 |
5 | module.exports = (tree, options, callback) => {
6 | if (!callback) {
7 | callback = options;
8 | options = { size: 128 };
9 | }
10 |
11 | const compiled = compileFunction(tree);
12 |
13 | const { cells, positions } = implicitMesh(options.size, (x, y, z) =>
14 | compiled([x, y, z])
15 | );
16 |
17 | const str = serializeObj(cells, positions);
18 |
19 | callback(str);
20 | };
21 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hiccup-sdf-to-obj",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@types/node": {
8 | "version": "8.10.37",
9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.37.tgz",
10 | "integrity": "sha512-Jp39foY8Euv/PG4OGPyzxis82mnjcUtXLEMA8oFMCE4ilmuJgZPdV2nZNV1moz+99EJTtcpOSgDCgATUwABKig=="
11 | },
12 | "acorn": {
13 | "version": "5.7.3",
14 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
15 | "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
16 | },
17 | "ajv": {
18 | "version": "5.5.2",
19 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
20 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
21 | "requires": {
22 | "co": "^4.6.0",
23 | "fast-deep-equal": "^1.0.0",
24 | "fast-json-stable-stringify": "^2.0.0",
25 | "json-schema-traverse": "^0.3.0"
26 | }
27 | },
28 | "align-text": {
29 | "version": "0.1.4",
30 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
31 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
32 | "requires": {
33 | "kind-of": "^3.0.2",
34 | "longest": "^1.0.1",
35 | "repeat-string": "^1.5.2"
36 | }
37 | },
38 | "amdefine": {
39 | "version": "1.0.1",
40 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
41 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
42 | "optional": true
43 | },
44 | "ansi-regex": {
45 | "version": "2.1.1",
46 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
47 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
48 | },
49 | "array-find-index": {
50 | "version": "1.0.2",
51 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
52 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
53 | },
54 | "asn1": {
55 | "version": "0.2.4",
56 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
57 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
58 | "requires": {
59 | "safer-buffer": "~2.1.0"
60 | }
61 | },
62 | "assert-plus": {
63 | "version": "1.0.0",
64 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
65 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
66 | },
67 | "asynckit": {
68 | "version": "0.4.0",
69 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
70 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
71 | },
72 | "aws-sign2": {
73 | "version": "0.7.0",
74 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
75 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
76 | },
77 | "aws4": {
78 | "version": "1.8.0",
79 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
80 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
81 | },
82 | "balanced-match": {
83 | "version": "1.0.0",
84 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
85 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
86 | },
87 | "bcrypt-pbkdf": {
88 | "version": "1.0.2",
89 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
90 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
91 | "requires": {
92 | "tweetnacl": "^0.14.3"
93 | }
94 | },
95 | "bit-twiddle": {
96 | "version": "1.0.2",
97 | "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz",
98 | "integrity": "sha1-DGwfq+KyPRcXPZpht7cJPrnhdp4="
99 | },
100 | "brace-expansion": {
101 | "version": "1.1.11",
102 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
103 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
104 | "requires": {
105 | "balanced-match": "^1.0.0",
106 | "concat-map": "0.0.1"
107 | }
108 | },
109 | "buffer-from": {
110 | "version": "1.1.1",
111 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
112 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
113 | },
114 | "builtin-modules": {
115 | "version": "1.1.1",
116 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
117 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
118 | },
119 | "camelcase": {
120 | "version": "2.1.1",
121 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
122 | "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
123 | },
124 | "camelcase-keys": {
125 | "version": "2.1.0",
126 | "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
127 | "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
128 | "requires": {
129 | "camelcase": "^2.0.0",
130 | "map-obj": "^1.0.0"
131 | }
132 | },
133 | "caseless": {
134 | "version": "0.12.0",
135 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
136 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
137 | },
138 | "center-align": {
139 | "version": "0.1.3",
140 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
141 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
142 | "requires": {
143 | "align-text": "^0.1.3",
144 | "lazy-cache": "^1.0.3"
145 | }
146 | },
147 | "cliui": {
148 | "version": "2.1.0",
149 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
150 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
151 | "requires": {
152 | "center-align": "^0.1.1",
153 | "right-align": "^0.1.1",
154 | "wordwrap": "0.0.2"
155 | }
156 | },
157 | "co": {
158 | "version": "4.6.0",
159 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
160 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
161 | },
162 | "code-point-at": {
163 | "version": "1.1.0",
164 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
165 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
166 | },
167 | "combined-stream": {
168 | "version": "1.0.7",
169 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
170 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
171 | "requires": {
172 | "delayed-stream": "~1.0.0"
173 | }
174 | },
175 | "concat-map": {
176 | "version": "0.0.1",
177 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
178 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
179 | },
180 | "concat-stream": {
181 | "version": "1.6.2",
182 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
183 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
184 | "requires": {
185 | "buffer-from": "^1.0.0",
186 | "inherits": "^2.0.3",
187 | "readable-stream": "^2.2.2",
188 | "typedarray": "^0.0.6"
189 | },
190 | "dependencies": {
191 | "isarray": {
192 | "version": "1.0.0",
193 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
194 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
195 | },
196 | "readable-stream": {
197 | "version": "2.3.6",
198 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
199 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
200 | "requires": {
201 | "core-util-is": "~1.0.0",
202 | "inherits": "~2.0.3",
203 | "isarray": "~1.0.0",
204 | "process-nextick-args": "~2.0.0",
205 | "safe-buffer": "~5.1.1",
206 | "string_decoder": "~1.1.1",
207 | "util-deprecate": "~1.0.1"
208 | }
209 | },
210 | "string_decoder": {
211 | "version": "1.1.1",
212 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
213 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
214 | "requires": {
215 | "safe-buffer": "~5.1.0"
216 | }
217 | }
218 | }
219 | },
220 | "core-util-is": {
221 | "version": "1.0.2",
222 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
223 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
224 | },
225 | "currently-unhandled": {
226 | "version": "0.4.1",
227 | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
228 | "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
229 | "requires": {
230 | "array-find-index": "^1.0.1"
231 | }
232 | },
233 | "cwise": {
234 | "version": "1.0.10",
235 | "resolved": "https://registry.npmjs.org/cwise/-/cwise-1.0.10.tgz",
236 | "integrity": "sha1-JO7mBy69/WuMb12tsXCQtkmxK+8=",
237 | "requires": {
238 | "cwise-compiler": "^1.1.1",
239 | "cwise-parser": "^1.0.0",
240 | "static-module": "^1.0.0",
241 | "uglify-js": "^2.6.0"
242 | }
243 | },
244 | "cwise-compiler": {
245 | "version": "1.1.3",
246 | "resolved": "https://registry.npmjs.org/cwise-compiler/-/cwise-compiler-1.1.3.tgz",
247 | "integrity": "sha1-9NZnQQ6FDToxOn0tt7HlBbsDTMU=",
248 | "requires": {
249 | "uniq": "^1.0.0"
250 | }
251 | },
252 | "cwise-parser": {
253 | "version": "1.0.3",
254 | "resolved": "https://registry.npmjs.org/cwise-parser/-/cwise-parser-1.0.3.tgz",
255 | "integrity": "sha1-jkk8F9VPl8sDCp6YVLyGyd+zVP4=",
256 | "requires": {
257 | "esprima": "^1.0.3",
258 | "uniq": "^1.0.0"
259 | }
260 | },
261 | "dashdash": {
262 | "version": "1.14.1",
263 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
264 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
265 | "requires": {
266 | "assert-plus": "^1.0.0"
267 | }
268 | },
269 | "debug": {
270 | "version": "2.6.9",
271 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
272 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
273 | "requires": {
274 | "ms": "2.0.0"
275 | }
276 | },
277 | "decamelize": {
278 | "version": "1.2.0",
279 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
280 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
281 | },
282 | "deep-extend": {
283 | "version": "0.6.0",
284 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
285 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
286 | },
287 | "delayed-stream": {
288 | "version": "1.0.0",
289 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
290 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
291 | },
292 | "dup": {
293 | "version": "1.0.0",
294 | "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz",
295 | "integrity": "sha1-UfxaxoX4GWRp3wuQXpNLIK9bQCk="
296 | },
297 | "duplexer2": {
298 | "version": "0.0.2",
299 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
300 | "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
301 | "requires": {
302 | "readable-stream": "~1.1.9"
303 | }
304 | },
305 | "easy-stack": {
306 | "version": "1.0.0",
307 | "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz",
308 | "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g="
309 | },
310 | "ecc-jsbn": {
311 | "version": "0.1.2",
312 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
313 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
314 | "requires": {
315 | "jsbn": "~0.1.0",
316 | "safer-buffer": "^2.1.0"
317 | }
318 | },
319 | "electron": {
320 | "version": "2.0.13",
321 | "resolved": "https://registry.npmjs.org/electron/-/electron-2.0.13.tgz",
322 | "integrity": "sha512-8ouYaLsp0F4sPI7QKgJkkJhrwj1JPSnBwbz6HHA9l6u7WofEt94lV+gHw71KJrDl7UaIkFwlSjyhIjG8lIZqxw==",
323 | "requires": {
324 | "@types/node": "^8.0.24",
325 | "electron-download": "^3.0.1",
326 | "extract-zip": "^1.0.3"
327 | }
328 | },
329 | "electron-download": {
330 | "version": "3.3.0",
331 | "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz",
332 | "integrity": "sha1-LP1U1pZsAZxNSa1l++Zcyc3vaMg=",
333 | "requires": {
334 | "debug": "^2.2.0",
335 | "fs-extra": "^0.30.0",
336 | "home-path": "^1.0.1",
337 | "minimist": "^1.2.0",
338 | "nugget": "^2.0.0",
339 | "path-exists": "^2.1.0",
340 | "rc": "^1.1.2",
341 | "semver": "^5.3.0",
342 | "sumchecker": "^1.2.0"
343 | }
344 | },
345 | "error-ex": {
346 | "version": "1.3.2",
347 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
348 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
349 | "requires": {
350 | "is-arrayish": "^0.2.1"
351 | }
352 | },
353 | "es6-promise": {
354 | "version": "4.2.5",
355 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz",
356 | "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg=="
357 | },
358 | "escodegen": {
359 | "version": "1.3.3",
360 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.3.3.tgz",
361 | "integrity": "sha1-8CQBb1qI4Eb9EgBQVek5gC5sXyM=",
362 | "requires": {
363 | "esprima": "~1.1.1",
364 | "estraverse": "~1.5.0",
365 | "esutils": "~1.0.0",
366 | "source-map": "~0.1.33"
367 | },
368 | "dependencies": {
369 | "esprima": {
370 | "version": "1.1.1",
371 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz",
372 | "integrity": "sha1-W28VR/TRAuZw4UDFCb5ncdautUk="
373 | }
374 | }
375 | },
376 | "esprima": {
377 | "version": "1.2.5",
378 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
379 | "integrity": "sha1-CZNQL+r2aBODJXVvMPmlH+7sEek="
380 | },
381 | "estraverse": {
382 | "version": "1.5.1",
383 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz",
384 | "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E="
385 | },
386 | "esutils": {
387 | "version": "1.0.0",
388 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz",
389 | "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA="
390 | },
391 | "event-pubsub": {
392 | "version": "4.3.0",
393 | "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz",
394 | "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ=="
395 | },
396 | "extend": {
397 | "version": "3.0.2",
398 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
399 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
400 | },
401 | "extract-zip": {
402 | "version": "1.6.7",
403 | "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
404 | "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
405 | "requires": {
406 | "concat-stream": "1.6.2",
407 | "debug": "2.6.9",
408 | "mkdirp": "0.5.1",
409 | "yauzl": "2.4.1"
410 | }
411 | },
412 | "extsprintf": {
413 | "version": "1.3.0",
414 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
415 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
416 | },
417 | "falafel": {
418 | "version": "2.1.0",
419 | "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.1.0.tgz",
420 | "integrity": "sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw=",
421 | "requires": {
422 | "acorn": "^5.0.0",
423 | "foreach": "^2.0.5",
424 | "isarray": "0.0.1",
425 | "object-keys": "^1.0.6"
426 | },
427 | "dependencies": {
428 | "object-keys": {
429 | "version": "1.0.12",
430 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
431 | "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
432 | }
433 | }
434 | },
435 | "fast-deep-equal": {
436 | "version": "1.1.0",
437 | "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
438 | "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
439 | },
440 | "fast-json-stable-stringify": {
441 | "version": "2.0.0",
442 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
443 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
444 | },
445 | "fd-slicer": {
446 | "version": "1.0.1",
447 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
448 | "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
449 | "requires": {
450 | "pend": "~1.2.0"
451 | }
452 | },
453 | "find-up": {
454 | "version": "1.1.2",
455 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
456 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
457 | "requires": {
458 | "path-exists": "^2.0.0",
459 | "pinkie-promise": "^2.0.0"
460 | }
461 | },
462 | "foreach": {
463 | "version": "2.0.5",
464 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
465 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
466 | },
467 | "forever-agent": {
468 | "version": "0.6.1",
469 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
470 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
471 | },
472 | "form-data": {
473 | "version": "2.3.3",
474 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
475 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
476 | "requires": {
477 | "asynckit": "^0.4.0",
478 | "combined-stream": "^1.0.6",
479 | "mime-types": "^2.1.12"
480 | }
481 | },
482 | "fs-extra": {
483 | "version": "0.30.0",
484 | "resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
485 | "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
486 | "requires": {
487 | "graceful-fs": "^4.1.2",
488 | "jsonfile": "^2.1.0",
489 | "klaw": "^1.0.0",
490 | "path-is-absolute": "^1.0.0",
491 | "rimraf": "^2.2.8"
492 | }
493 | },
494 | "fs.realpath": {
495 | "version": "1.0.0",
496 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
497 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
498 | },
499 | "function-bind": {
500 | "version": "1.1.1",
501 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
502 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
503 | },
504 | "gamma": {
505 | "version": "0.1.0",
506 | "resolved": "https://registry.npmjs.org/gamma/-/gamma-0.1.0.tgz",
507 | "integrity": "sha1-MxVkNAO/J5BsqAqzfDbs6UQO8zA="
508 | },
509 | "get-stdin": {
510 | "version": "4.0.1",
511 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
512 | "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
513 | },
514 | "getpass": {
515 | "version": "0.1.7",
516 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
517 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
518 | "requires": {
519 | "assert-plus": "^1.0.0"
520 | }
521 | },
522 | "glob": {
523 | "version": "7.1.3",
524 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
525 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
526 | "requires": {
527 | "fs.realpath": "^1.0.0",
528 | "inflight": "^1.0.4",
529 | "inherits": "2",
530 | "minimatch": "^3.0.4",
531 | "once": "^1.3.0",
532 | "path-is-absolute": "^1.0.0"
533 | }
534 | },
535 | "graceful-fs": {
536 | "version": "4.1.15",
537 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
538 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
539 | },
540 | "har-schema": {
541 | "version": "2.0.0",
542 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
543 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
544 | },
545 | "har-validator": {
546 | "version": "5.1.0",
547 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
548 | "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
549 | "requires": {
550 | "ajv": "^5.3.0",
551 | "har-schema": "^2.0.0"
552 | }
553 | },
554 | "has": {
555 | "version": "1.0.3",
556 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
557 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
558 | "requires": {
559 | "function-bind": "^1.1.1"
560 | }
561 | },
562 | "home-path": {
563 | "version": "1.0.6",
564 | "resolved": "https://registry.npmjs.org/home-path/-/home-path-1.0.6.tgz",
565 | "integrity": "sha512-wo+yjrdAtoXt43Vy92a+0IPCYViiyLAHyp0QVS4xL/tfvVz5sXIW1ubLZk3nhVkD92fQpUMKX+fzMjr5F489vw=="
566 | },
567 | "hosted-git-info": {
568 | "version": "2.7.1",
569 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
570 | "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w=="
571 | },
572 | "http-signature": {
573 | "version": "1.2.0",
574 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
575 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
576 | "requires": {
577 | "assert-plus": "^1.0.0",
578 | "jsprim": "^1.2.2",
579 | "sshpk": "^1.7.0"
580 | }
581 | },
582 | "implicit-mesh": {
583 | "version": "1.1.1",
584 | "resolved": "https://registry.npmjs.org/implicit-mesh/-/implicit-mesh-1.1.1.tgz",
585 | "integrity": "sha1-yv7qHUF1LPwMIVxr+5bIUoGWtXo=",
586 | "requires": {
587 | "ndarray": "^1.0.18",
588 | "ndarray-fill": "^1.0.1",
589 | "regl": "^1.2.1",
590 | "surface-nets": "^1.0.2"
591 | }
592 | },
593 | "indent-string": {
594 | "version": "2.1.0",
595 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
596 | "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
597 | "requires": {
598 | "repeating": "^2.0.0"
599 | }
600 | },
601 | "inflight": {
602 | "version": "1.0.6",
603 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
604 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
605 | "requires": {
606 | "once": "^1.3.0",
607 | "wrappy": "1"
608 | }
609 | },
610 | "inherits": {
611 | "version": "2.0.3",
612 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
613 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
614 | },
615 | "ini": {
616 | "version": "1.3.5",
617 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
618 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
619 | },
620 | "invert-permutation": {
621 | "version": "1.0.0",
622 | "resolved": "https://registry.npmjs.org/invert-permutation/-/invert-permutation-1.0.0.tgz",
623 | "integrity": "sha1-oKeAQurbNrwXVR54fv0UOa3VSTM="
624 | },
625 | "iota-array": {
626 | "version": "1.0.0",
627 | "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
628 | "integrity": "sha1-ge9X/l0FgUzVjCSDYyqZwwoOgIc="
629 | },
630 | "is-arrayish": {
631 | "version": "0.2.1",
632 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
633 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
634 | },
635 | "is-buffer": {
636 | "version": "1.1.6",
637 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
638 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
639 | },
640 | "is-builtin-module": {
641 | "version": "1.0.0",
642 | "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
643 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
644 | "requires": {
645 | "builtin-modules": "^1.0.0"
646 | }
647 | },
648 | "is-finite": {
649 | "version": "1.0.2",
650 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
651 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
652 | "requires": {
653 | "number-is-nan": "^1.0.0"
654 | }
655 | },
656 | "is-fullwidth-code-point": {
657 | "version": "1.0.0",
658 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
659 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
660 | "requires": {
661 | "number-is-nan": "^1.0.0"
662 | }
663 | },
664 | "is-typedarray": {
665 | "version": "1.0.0",
666 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
667 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
668 | },
669 | "is-utf8": {
670 | "version": "0.2.1",
671 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
672 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
673 | },
674 | "isarray": {
675 | "version": "0.0.1",
676 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
677 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
678 | },
679 | "isstream": {
680 | "version": "0.1.2",
681 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
682 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
683 | },
684 | "js-message": {
685 | "version": "1.0.5",
686 | "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
687 | "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU="
688 | },
689 | "js-queue": {
690 | "version": "2.0.0",
691 | "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz",
692 | "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=",
693 | "requires": {
694 | "easy-stack": "^1.0.0"
695 | }
696 | },
697 | "jsbn": {
698 | "version": "0.1.1",
699 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
700 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
701 | },
702 | "json-schema": {
703 | "version": "0.2.3",
704 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
705 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
706 | },
707 | "json-schema-traverse": {
708 | "version": "0.3.1",
709 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
710 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
711 | },
712 | "json-stringify-safe": {
713 | "version": "5.0.1",
714 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
715 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
716 | },
717 | "jsonfile": {
718 | "version": "2.4.0",
719 | "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
720 | "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
721 | "requires": {
722 | "graceful-fs": "^4.1.6"
723 | }
724 | },
725 | "jsprim": {
726 | "version": "1.4.1",
727 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
728 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
729 | "requires": {
730 | "assert-plus": "1.0.0",
731 | "extsprintf": "1.3.0",
732 | "json-schema": "0.2.3",
733 | "verror": "1.10.0"
734 | }
735 | },
736 | "kind-of": {
737 | "version": "3.2.2",
738 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
739 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
740 | "requires": {
741 | "is-buffer": "^1.1.5"
742 | }
743 | },
744 | "klaw": {
745 | "version": "1.3.1",
746 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
747 | "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
748 | "requires": {
749 | "graceful-fs": "^4.1.9"
750 | }
751 | },
752 | "lazy-cache": {
753 | "version": "1.0.4",
754 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
755 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
756 | },
757 | "load-json-file": {
758 | "version": "1.1.0",
759 | "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
760 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
761 | "requires": {
762 | "graceful-fs": "^4.1.2",
763 | "parse-json": "^2.2.0",
764 | "pify": "^2.0.0",
765 | "pinkie-promise": "^2.0.0",
766 | "strip-bom": "^2.0.0"
767 | }
768 | },
769 | "longest": {
770 | "version": "1.0.1",
771 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
772 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
773 | },
774 | "loud-rejection": {
775 | "version": "1.6.0",
776 | "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
777 | "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
778 | "requires": {
779 | "currently-unhandled": "^0.4.1",
780 | "signal-exit": "^3.0.0"
781 | }
782 | },
783 | "map-obj": {
784 | "version": "1.0.1",
785 | "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
786 | "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
787 | },
788 | "meow": {
789 | "version": "3.7.0",
790 | "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
791 | "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
792 | "requires": {
793 | "camelcase-keys": "^2.0.0",
794 | "decamelize": "^1.1.2",
795 | "loud-rejection": "^1.0.0",
796 | "map-obj": "^1.0.1",
797 | "minimist": "^1.1.3",
798 | "normalize-package-data": "^2.3.4",
799 | "object-assign": "^4.0.1",
800 | "read-pkg-up": "^1.0.1",
801 | "redent": "^1.0.0",
802 | "trim-newlines": "^1.0.0"
803 | }
804 | },
805 | "mime-db": {
806 | "version": "1.37.0",
807 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
808 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
809 | },
810 | "mime-types": {
811 | "version": "2.1.21",
812 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
813 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
814 | "requires": {
815 | "mime-db": "~1.37.0"
816 | }
817 | },
818 | "minimatch": {
819 | "version": "3.0.4",
820 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
821 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
822 | "requires": {
823 | "brace-expansion": "^1.1.7"
824 | }
825 | },
826 | "minimist": {
827 | "version": "1.2.0",
828 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
829 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
830 | },
831 | "mkdirp": {
832 | "version": "0.5.1",
833 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
834 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
835 | "requires": {
836 | "minimist": "0.0.8"
837 | },
838 | "dependencies": {
839 | "minimist": {
840 | "version": "0.0.8",
841 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
842 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
843 | }
844 | }
845 | },
846 | "ms": {
847 | "version": "2.0.0",
848 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
849 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
850 | },
851 | "ndarray": {
852 | "version": "1.0.18",
853 | "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.18.tgz",
854 | "integrity": "sha1-tg06cyJOxVXQ+qeXEeUCRI/T95M=",
855 | "requires": {
856 | "iota-array": "^1.0.0",
857 | "is-buffer": "^1.0.2"
858 | }
859 | },
860 | "ndarray-extract-contour": {
861 | "version": "1.0.1",
862 | "resolved": "https://registry.npmjs.org/ndarray-extract-contour/-/ndarray-extract-contour-1.0.1.tgz",
863 | "integrity": "sha1-Cu4ROjozsia5DEiIz4d79HUTBeQ=",
864 | "requires": {
865 | "typedarray-pool": "^1.0.0"
866 | }
867 | },
868 | "ndarray-fill": {
869 | "version": "1.0.2",
870 | "resolved": "https://registry.npmjs.org/ndarray-fill/-/ndarray-fill-1.0.2.tgz",
871 | "integrity": "sha1-owpg9xiODJWC/N1YiWrNy1IqHtY=",
872 | "requires": {
873 | "cwise": "^1.0.10"
874 | }
875 | },
876 | "node-ipc": {
877 | "version": "9.1.1",
878 | "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz",
879 | "integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==",
880 | "requires": {
881 | "event-pubsub": "4.3.0",
882 | "js-message": "1.0.5",
883 | "js-queue": "2.0.0"
884 | }
885 | },
886 | "normalize-package-data": {
887 | "version": "2.4.0",
888 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
889 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
890 | "requires": {
891 | "hosted-git-info": "^2.1.4",
892 | "is-builtin-module": "^1.0.0",
893 | "semver": "2 || 3 || 4 || 5",
894 | "validate-npm-package-license": "^3.0.1"
895 | }
896 | },
897 | "nugget": {
898 | "version": "2.0.1",
899 | "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz",
900 | "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=",
901 | "requires": {
902 | "debug": "^2.1.3",
903 | "minimist": "^1.1.0",
904 | "pretty-bytes": "^1.0.2",
905 | "progress-stream": "^1.1.0",
906 | "request": "^2.45.0",
907 | "single-line-log": "^1.1.2",
908 | "throttleit": "0.0.2"
909 | }
910 | },
911 | "number-is-nan": {
912 | "version": "1.0.1",
913 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
914 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
915 | },
916 | "oauth-sign": {
917 | "version": "0.9.0",
918 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
919 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
920 | },
921 | "object-assign": {
922 | "version": "4.1.1",
923 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
924 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
925 | },
926 | "object-inspect": {
927 | "version": "0.4.0",
928 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-0.4.0.tgz",
929 | "integrity": "sha1-9RV8EWwUVbJDsG7pdwM5LFrYn+w="
930 | },
931 | "object-keys": {
932 | "version": "0.4.0",
933 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
934 | "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY="
935 | },
936 | "once": {
937 | "version": "1.4.0",
938 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
939 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
940 | "requires": {
941 | "wrappy": "1"
942 | }
943 | },
944 | "parse-json": {
945 | "version": "2.2.0",
946 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
947 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
948 | "requires": {
949 | "error-ex": "^1.2.0"
950 | }
951 | },
952 | "path-exists": {
953 | "version": "2.1.0",
954 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
955 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
956 | "requires": {
957 | "pinkie-promise": "^2.0.0"
958 | }
959 | },
960 | "path-is-absolute": {
961 | "version": "1.0.1",
962 | "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
963 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
964 | },
965 | "path-type": {
966 | "version": "1.1.0",
967 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
968 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
969 | "requires": {
970 | "graceful-fs": "^4.1.2",
971 | "pify": "^2.0.0",
972 | "pinkie-promise": "^2.0.0"
973 | }
974 | },
975 | "pend": {
976 | "version": "1.2.0",
977 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
978 | "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
979 | },
980 | "performance-now": {
981 | "version": "2.1.0",
982 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
983 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
984 | },
985 | "permutation-parity": {
986 | "version": "1.0.0",
987 | "resolved": "https://registry.npmjs.org/permutation-parity/-/permutation-parity-1.0.0.tgz",
988 | "integrity": "sha1-AXTVH8pwSxG5pLFSsj1Tf9xrXvQ=",
989 | "requires": {
990 | "typedarray-pool": "^1.0.0"
991 | }
992 | },
993 | "permutation-rank": {
994 | "version": "1.0.0",
995 | "resolved": "https://registry.npmjs.org/permutation-rank/-/permutation-rank-1.0.0.tgz",
996 | "integrity": "sha1-n9mLvOzwj79ZlLXq3JSmLmeUg7U=",
997 | "requires": {
998 | "invert-permutation": "^1.0.0",
999 | "typedarray-pool": "^1.0.0"
1000 | }
1001 | },
1002 | "pify": {
1003 | "version": "2.3.0",
1004 | "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
1005 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
1006 | },
1007 | "pinkie": {
1008 | "version": "2.0.4",
1009 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
1010 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
1011 | },
1012 | "pinkie-promise": {
1013 | "version": "2.0.1",
1014 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
1015 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
1016 | "requires": {
1017 | "pinkie": "^2.0.0"
1018 | }
1019 | },
1020 | "pretty-bytes": {
1021 | "version": "1.0.4",
1022 | "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz",
1023 | "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=",
1024 | "requires": {
1025 | "get-stdin": "^4.0.1",
1026 | "meow": "^3.1.0"
1027 | }
1028 | },
1029 | "process-nextick-args": {
1030 | "version": "2.0.0",
1031 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
1032 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
1033 | },
1034 | "progress-stream": {
1035 | "version": "1.2.0",
1036 | "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz",
1037 | "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=",
1038 | "requires": {
1039 | "speedometer": "~0.1.2",
1040 | "through2": "~0.2.3"
1041 | }
1042 | },
1043 | "psl": {
1044 | "version": "1.1.29",
1045 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
1046 | "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
1047 | },
1048 | "punycode": {
1049 | "version": "1.4.1",
1050 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
1051 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
1052 | },
1053 | "qs": {
1054 | "version": "6.5.2",
1055 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
1056 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
1057 | },
1058 | "quote-stream": {
1059 | "version": "0.0.0",
1060 | "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-0.0.0.tgz",
1061 | "integrity": "sha1-zeKelMQJsW4Z3HCYuJtmWPlyHTs=",
1062 | "requires": {
1063 | "minimist": "0.0.8",
1064 | "through2": "~0.4.1"
1065 | },
1066 | "dependencies": {
1067 | "minimist": {
1068 | "version": "0.0.8",
1069 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
1070 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
1071 | },
1072 | "readable-stream": {
1073 | "version": "1.0.34",
1074 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
1075 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
1076 | "requires": {
1077 | "core-util-is": "~1.0.0",
1078 | "inherits": "~2.0.1",
1079 | "isarray": "0.0.1",
1080 | "string_decoder": "~0.10.x"
1081 | }
1082 | },
1083 | "through2": {
1084 | "version": "0.4.2",
1085 | "resolved": "http://registry.npmjs.org/through2/-/through2-0.4.2.tgz",
1086 | "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=",
1087 | "requires": {
1088 | "readable-stream": "~1.0.17",
1089 | "xtend": "~2.1.1"
1090 | }
1091 | }
1092 | }
1093 | },
1094 | "rc": {
1095 | "version": "1.2.8",
1096 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
1097 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
1098 | "requires": {
1099 | "deep-extend": "^0.6.0",
1100 | "ini": "~1.3.0",
1101 | "minimist": "^1.2.0",
1102 | "strip-json-comments": "~2.0.1"
1103 | }
1104 | },
1105 | "read-pkg": {
1106 | "version": "1.1.0",
1107 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
1108 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
1109 | "requires": {
1110 | "load-json-file": "^1.0.0",
1111 | "normalize-package-data": "^2.3.2",
1112 | "path-type": "^1.0.0"
1113 | }
1114 | },
1115 | "read-pkg-up": {
1116 | "version": "1.0.1",
1117 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
1118 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
1119 | "requires": {
1120 | "find-up": "^1.0.0",
1121 | "read-pkg": "^1.0.0"
1122 | }
1123 | },
1124 | "readable-stream": {
1125 | "version": "1.1.14",
1126 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
1127 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
1128 | "requires": {
1129 | "core-util-is": "~1.0.0",
1130 | "inherits": "~2.0.1",
1131 | "isarray": "0.0.1",
1132 | "string_decoder": "~0.10.x"
1133 | }
1134 | },
1135 | "redent": {
1136 | "version": "1.0.0",
1137 | "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
1138 | "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
1139 | "requires": {
1140 | "indent-string": "^2.1.0",
1141 | "strip-indent": "^1.0.1"
1142 | }
1143 | },
1144 | "regl": {
1145 | "version": "1.3.9",
1146 | "resolved": "https://registry.npmjs.org/regl/-/regl-1.3.9.tgz",
1147 | "integrity": "sha512-CungQSUBsZNYZJWJlb2sPe4iwBjmxrgl1Yxt91HN3VuuEL7lJ5k03O3T1xEXVOCMN1q8wncddwJsxozuyzzmrA=="
1148 | },
1149 | "repeat-string": {
1150 | "version": "1.6.1",
1151 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
1152 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
1153 | },
1154 | "repeating": {
1155 | "version": "2.0.1",
1156 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
1157 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
1158 | "requires": {
1159 | "is-finite": "^1.0.0"
1160 | }
1161 | },
1162 | "request": {
1163 | "version": "2.88.0",
1164 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
1165 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
1166 | "requires": {
1167 | "aws-sign2": "~0.7.0",
1168 | "aws4": "^1.8.0",
1169 | "caseless": "~0.12.0",
1170 | "combined-stream": "~1.0.6",
1171 | "extend": "~3.0.2",
1172 | "forever-agent": "~0.6.1",
1173 | "form-data": "~2.3.2",
1174 | "har-validator": "~5.1.0",
1175 | "http-signature": "~1.2.0",
1176 | "is-typedarray": "~1.0.0",
1177 | "isstream": "~0.1.2",
1178 | "json-stringify-safe": "~5.0.1",
1179 | "mime-types": "~2.1.19",
1180 | "oauth-sign": "~0.9.0",
1181 | "performance-now": "^2.1.0",
1182 | "qs": "~6.5.2",
1183 | "safe-buffer": "^5.1.2",
1184 | "tough-cookie": "~2.4.3",
1185 | "tunnel-agent": "^0.6.0",
1186 | "uuid": "^3.3.2"
1187 | }
1188 | },
1189 | "right-align": {
1190 | "version": "0.1.3",
1191 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
1192 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
1193 | "requires": {
1194 | "align-text": "^0.1.1"
1195 | }
1196 | },
1197 | "rimraf": {
1198 | "version": "2.6.2",
1199 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
1200 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
1201 | "requires": {
1202 | "glob": "^7.0.5"
1203 | }
1204 | },
1205 | "safe-buffer": {
1206 | "version": "5.1.2",
1207 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1208 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
1209 | },
1210 | "safer-buffer": {
1211 | "version": "2.1.2",
1212 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1213 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1214 | },
1215 | "semver": {
1216 | "version": "5.6.0",
1217 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
1218 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
1219 | },
1220 | "serialize-wavefront-obj": {
1221 | "version": "1.0.0",
1222 | "resolved": "https://registry.npmjs.org/serialize-wavefront-obj/-/serialize-wavefront-obj-1.0.0.tgz",
1223 | "integrity": "sha1-fhyq6CeCqDae45sK1CPwavdkH6c="
1224 | },
1225 | "shallow-copy": {
1226 | "version": "0.0.1",
1227 | "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz",
1228 | "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA="
1229 | },
1230 | "signal-exit": {
1231 | "version": "3.0.2",
1232 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
1233 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
1234 | },
1235 | "single-line-log": {
1236 | "version": "1.1.2",
1237 | "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz",
1238 | "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=",
1239 | "requires": {
1240 | "string-width": "^1.0.1"
1241 | }
1242 | },
1243 | "source-map": {
1244 | "version": "0.1.43",
1245 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
1246 | "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
1247 | "optional": true,
1248 | "requires": {
1249 | "amdefine": ">=0.0.4"
1250 | }
1251 | },
1252 | "spdx-correct": {
1253 | "version": "3.0.2",
1254 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz",
1255 | "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==",
1256 | "requires": {
1257 | "spdx-expression-parse": "^3.0.0",
1258 | "spdx-license-ids": "^3.0.0"
1259 | }
1260 | },
1261 | "spdx-exceptions": {
1262 | "version": "2.2.0",
1263 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
1264 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA=="
1265 | },
1266 | "spdx-expression-parse": {
1267 | "version": "3.0.0",
1268 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
1269 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
1270 | "requires": {
1271 | "spdx-exceptions": "^2.1.0",
1272 | "spdx-license-ids": "^3.0.0"
1273 | }
1274 | },
1275 | "spdx-license-ids": {
1276 | "version": "3.0.2",
1277 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz",
1278 | "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg=="
1279 | },
1280 | "speedometer": {
1281 | "version": "0.1.4",
1282 | "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz",
1283 | "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0="
1284 | },
1285 | "sshpk": {
1286 | "version": "1.15.2",
1287 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz",
1288 | "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==",
1289 | "requires": {
1290 | "asn1": "~0.2.3",
1291 | "assert-plus": "^1.0.0",
1292 | "bcrypt-pbkdf": "^1.0.0",
1293 | "dashdash": "^1.12.0",
1294 | "ecc-jsbn": "~0.1.1",
1295 | "getpass": "^0.1.1",
1296 | "jsbn": "~0.1.0",
1297 | "safer-buffer": "^2.0.2",
1298 | "tweetnacl": "~0.14.0"
1299 | }
1300 | },
1301 | "static-eval": {
1302 | "version": "0.2.4",
1303 | "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-0.2.4.tgz",
1304 | "integrity": "sha1-t9NNg4k3uWn5ZBygfUj47eJj6ns=",
1305 | "requires": {
1306 | "escodegen": "~0.0.24"
1307 | },
1308 | "dependencies": {
1309 | "escodegen": {
1310 | "version": "0.0.28",
1311 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.28.tgz",
1312 | "integrity": "sha1-Dk/xcV8yh3XWyrUaxEpAbNer/9M=",
1313 | "requires": {
1314 | "esprima": "~1.0.2",
1315 | "estraverse": "~1.3.0",
1316 | "source-map": ">= 0.1.2"
1317 | }
1318 | },
1319 | "esprima": {
1320 | "version": "1.0.4",
1321 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
1322 | "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0="
1323 | },
1324 | "estraverse": {
1325 | "version": "1.3.2",
1326 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.3.2.tgz",
1327 | "integrity": "sha1-N8K4k+8T1yPydth41g2FNRUqbEI="
1328 | }
1329 | }
1330 | },
1331 | "static-module": {
1332 | "version": "1.5.0",
1333 | "resolved": "https://registry.npmjs.org/static-module/-/static-module-1.5.0.tgz",
1334 | "integrity": "sha1-J9qYg8QajNCSNvhC8MHrxu32PYY=",
1335 | "requires": {
1336 | "concat-stream": "~1.6.0",
1337 | "duplexer2": "~0.0.2",
1338 | "escodegen": "~1.3.2",
1339 | "falafel": "^2.1.0",
1340 | "has": "^1.0.0",
1341 | "object-inspect": "~0.4.0",
1342 | "quote-stream": "~0.0.0",
1343 | "readable-stream": "~1.0.27-1",
1344 | "shallow-copy": "~0.0.1",
1345 | "static-eval": "~0.2.0",
1346 | "through2": "~0.4.1"
1347 | },
1348 | "dependencies": {
1349 | "readable-stream": {
1350 | "version": "1.0.34",
1351 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
1352 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
1353 | "requires": {
1354 | "core-util-is": "~1.0.0",
1355 | "inherits": "~2.0.1",
1356 | "isarray": "0.0.1",
1357 | "string_decoder": "~0.10.x"
1358 | }
1359 | },
1360 | "through2": {
1361 | "version": "0.4.2",
1362 | "resolved": "http://registry.npmjs.org/through2/-/through2-0.4.2.tgz",
1363 | "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=",
1364 | "requires": {
1365 | "readable-stream": "~1.0.17",
1366 | "xtend": "~2.1.1"
1367 | }
1368 | }
1369 | }
1370 | },
1371 | "string-width": {
1372 | "version": "1.0.2",
1373 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
1374 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
1375 | "requires": {
1376 | "code-point-at": "^1.0.0",
1377 | "is-fullwidth-code-point": "^1.0.0",
1378 | "strip-ansi": "^3.0.0"
1379 | }
1380 | },
1381 | "string_decoder": {
1382 | "version": "0.10.31",
1383 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
1384 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
1385 | },
1386 | "strip-ansi": {
1387 | "version": "3.0.1",
1388 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1389 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
1390 | "requires": {
1391 | "ansi-regex": "^2.0.0"
1392 | }
1393 | },
1394 | "strip-bom": {
1395 | "version": "2.0.0",
1396 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
1397 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
1398 | "requires": {
1399 | "is-utf8": "^0.2.0"
1400 | }
1401 | },
1402 | "strip-indent": {
1403 | "version": "1.0.1",
1404 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
1405 | "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
1406 | "requires": {
1407 | "get-stdin": "^4.0.1"
1408 | }
1409 | },
1410 | "strip-json-comments": {
1411 | "version": "2.0.1",
1412 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
1413 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
1414 | },
1415 | "sumchecker": {
1416 | "version": "1.3.1",
1417 | "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-1.3.1.tgz",
1418 | "integrity": "sha1-ebs7RFbdBPGOvbwNcDodHa7FEF0=",
1419 | "requires": {
1420 | "debug": "^2.2.0",
1421 | "es6-promise": "^4.0.5"
1422 | }
1423 | },
1424 | "surface-nets": {
1425 | "version": "1.0.2",
1426 | "resolved": "https://registry.npmjs.org/surface-nets/-/surface-nets-1.0.2.tgz",
1427 | "integrity": "sha1-5DPIy7qUpydMb0yZVStGG/H8eks=",
1428 | "requires": {
1429 | "ndarray-extract-contour": "^1.0.0",
1430 | "triangulate-hypercube": "^1.0.0",
1431 | "zero-crossings": "^1.0.0"
1432 | }
1433 | },
1434 | "throttleit": {
1435 | "version": "0.0.2",
1436 | "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz",
1437 | "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8="
1438 | },
1439 | "through2": {
1440 | "version": "0.2.3",
1441 | "resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
1442 | "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
1443 | "requires": {
1444 | "readable-stream": "~1.1.9",
1445 | "xtend": "~2.1.1"
1446 | }
1447 | },
1448 | "tough-cookie": {
1449 | "version": "2.4.3",
1450 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
1451 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
1452 | "requires": {
1453 | "psl": "^1.1.24",
1454 | "punycode": "^1.4.1"
1455 | }
1456 | },
1457 | "triangulate-hypercube": {
1458 | "version": "1.0.1",
1459 | "resolved": "https://registry.npmjs.org/triangulate-hypercube/-/triangulate-hypercube-1.0.1.tgz",
1460 | "integrity": "sha1-2Acdsuv8/VHzCNC88qXEils20Tc=",
1461 | "requires": {
1462 | "gamma": "^0.1.0",
1463 | "permutation-parity": "^1.0.0",
1464 | "permutation-rank": "^1.0.0"
1465 | }
1466 | },
1467 | "trim-newlines": {
1468 | "version": "1.0.0",
1469 | "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
1470 | "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM="
1471 | },
1472 | "tunnel-agent": {
1473 | "version": "0.6.0",
1474 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
1475 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
1476 | "requires": {
1477 | "safe-buffer": "^5.0.1"
1478 | }
1479 | },
1480 | "tweetnacl": {
1481 | "version": "0.14.5",
1482 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
1483 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
1484 | },
1485 | "typedarray": {
1486 | "version": "0.0.6",
1487 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
1488 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
1489 | },
1490 | "typedarray-pool": {
1491 | "version": "1.1.0",
1492 | "resolved": "https://registry.npmjs.org/typedarray-pool/-/typedarray-pool-1.1.0.tgz",
1493 | "integrity": "sha1-0RT0hIAUifU+yrXoCIqiMET0mNk=",
1494 | "requires": {
1495 | "bit-twiddle": "^1.0.0",
1496 | "dup": "^1.0.0"
1497 | }
1498 | },
1499 | "uglify-js": {
1500 | "version": "2.8.29",
1501 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
1502 | "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
1503 | "requires": {
1504 | "source-map": "~0.5.1",
1505 | "uglify-to-browserify": "~1.0.0",
1506 | "yargs": "~3.10.0"
1507 | },
1508 | "dependencies": {
1509 | "source-map": {
1510 | "version": "0.5.7",
1511 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
1512 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
1513 | }
1514 | }
1515 | },
1516 | "uglify-to-browserify": {
1517 | "version": "1.0.2",
1518 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
1519 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
1520 | "optional": true
1521 | },
1522 | "uniq": {
1523 | "version": "1.0.1",
1524 | "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
1525 | "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
1526 | },
1527 | "util-deprecate": {
1528 | "version": "1.0.2",
1529 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1530 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
1531 | },
1532 | "uuid": {
1533 | "version": "3.3.2",
1534 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
1535 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
1536 | },
1537 | "validate-npm-package-license": {
1538 | "version": "3.0.4",
1539 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
1540 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
1541 | "requires": {
1542 | "spdx-correct": "^3.0.0",
1543 | "spdx-expression-parse": "^3.0.0"
1544 | }
1545 | },
1546 | "verror": {
1547 | "version": "1.10.0",
1548 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
1549 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
1550 | "requires": {
1551 | "assert-plus": "^1.0.0",
1552 | "core-util-is": "1.0.2",
1553 | "extsprintf": "^1.2.0"
1554 | }
1555 | },
1556 | "window-size": {
1557 | "version": "0.1.0",
1558 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
1559 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
1560 | },
1561 | "wordwrap": {
1562 | "version": "0.0.2",
1563 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
1564 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
1565 | },
1566 | "wrappy": {
1567 | "version": "1.0.2",
1568 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1569 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
1570 | },
1571 | "xtend": {
1572 | "version": "2.1.2",
1573 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
1574 | "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
1575 | "requires": {
1576 | "object-keys": "~0.4.0"
1577 | }
1578 | },
1579 | "yargs": {
1580 | "version": "3.10.0",
1581 | "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
1582 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
1583 | "requires": {
1584 | "camelcase": "^1.0.2",
1585 | "cliui": "^2.1.0",
1586 | "decamelize": "^1.0.0",
1587 | "window-size": "0.1.0"
1588 | },
1589 | "dependencies": {
1590 | "camelcase": {
1591 | "version": "1.2.1",
1592 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
1593 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
1594 | }
1595 | }
1596 | },
1597 | "yauzl": {
1598 | "version": "2.4.1",
1599 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
1600 | "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
1601 | "requires": {
1602 | "fd-slicer": "~1.0.1"
1603 | }
1604 | },
1605 | "zero-crossings": {
1606 | "version": "1.0.1",
1607 | "resolved": "https://registry.npmjs.org/zero-crossings/-/zero-crossings-1.0.1.tgz",
1608 | "integrity": "sha1-xWK9MRNkPzRDokXRJAa4i2m5qf8=",
1609 | "requires": {
1610 | "cwise-compiler": "^1.0.0"
1611 | }
1612 | }
1613 | }
1614 | }
1615 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hiccup-sdf-to-obj",
3 | "version": "0.0.10",
4 | "description": "export hiccup-sdf models to OBJ",
5 | "main": "index.js",
6 | "author": "Szymon Kaliski (http://szymonkaliski.com)",
7 | "license": "MIT",
8 | "dependencies": {
9 | "display-sdf": "^0.0.9",
10 | "electron": "^2.0.8",
11 | "hiccup-sdf": "^0.0.10",
12 | "implicit-mesh": "^1.1.1",
13 | "ndarray": "^1.0.18",
14 | "node-ipc": "^9.1.1",
15 | "serialize-wavefront-obj": "^1.0.0",
16 | "surface-nets": "^1.0.2"
17 | },
18 | "gitHead": "e7f441600f1b472fcf0ef1396399c465ea258d0e"
19 | }
20 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/test/map-gpu.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs");
3 |
4 | const sdfToObj = require("../gpu");
5 |
6 | const randomSpherePosition = r => {
7 | const u = Math.random();
8 | const v = Math.random();
9 |
10 | const theta = 2 * Math.PI * u;
11 | const phi = Math.acos(2 * v - 1);
12 |
13 | const x = r * Math.sin(phi) * Math.cos(theta);
14 | const y = r * Math.sin(phi) * Math.sin(theta);
15 | const z = r * Math.cos(phi);
16 |
17 | return [x, y, z];
18 | };
19 |
20 | const range = length => Array.from({ length }, (_, i) => i);
21 |
22 | const points = range(100).map(() => randomSpherePosition(0.4));
23 |
24 | const tree = [
25 | "map",
26 | {
27 | data: { points },
28 | map: props => [
29 | "translate",
30 | { t: `${props.points}.xyz` },
31 | [["sphere", { r: 0.05 }]]
32 | ],
33 | reduce: ["union", { r: 0.01 }]
34 | }
35 | ];
36 |
37 | console.time("hiccup-sdf-to-obj");
38 | sdfToObj(tree, { size: 256 }, objStr => {
39 | console.timeEnd("hiccup-sdf-to-obj");
40 |
41 | fs.writeFileSync(path.join(__dirname, "map-gpu.obj"), objStr);
42 | });
43 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/test/map.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs");
3 |
4 | const sdfToObj = require("../");
5 |
6 | const randomSpherePosition = r => {
7 | const u = Math.random();
8 | const v = Math.random();
9 |
10 | const theta = 2 * Math.PI * u;
11 | const phi = Math.acos(2 * v - 1);
12 |
13 | const x = r * Math.sin(phi) * Math.cos(theta);
14 | const y = r * Math.sin(phi) * Math.sin(theta);
15 | const z = r * Math.cos(phi);
16 |
17 | return [x, y, z];
18 | };
19 |
20 | const range = length => Array.from({ length }, (_, i) => i);
21 |
22 | const points = range(100).map(() => randomSpherePosition(0.4));
23 |
24 | const tree = [
25 | "map",
26 | {
27 | data: { points },
28 | map: props => ["translate", { t: props.points }, [["sphere", { r: 0.05 }]]],
29 | reduce: ["union", { r: 0.01 }]
30 | }
31 | ];
32 |
33 | console.time("hiccup-sdf-to-obj");
34 | sdfToObj(tree, { size: 128 }, objStr => {
35 | console.timeEnd("hiccup-sdf-to-obj");
36 |
37 | fs.writeFileSync(path.join(__dirname, "map.obj"), objStr);
38 | });
39 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/test/sphere.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs");
3 |
4 | const sdfToObj = require("../threaded");
5 |
6 | const tree = ["sphere"];
7 |
8 | sdfToObj(tree, objStr => {
9 | fs.writeFileSync(path.join(__dirname, "sphere.obj"), objStr);
10 | });
11 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/test/union.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs");
3 |
4 | const sdfToObj = require("../threaded");
5 |
6 | const translatedSphere = (t, r) => ["translate", { t }, [["sphere", { r }]]];
7 |
8 | // prettier-ignore
9 | const tree = [
10 | "union",
11 | { r: 0.01 },
12 | [
13 | translatedSphere([-0.1, 0, 0], 0.2),
14 | translatedSphere([0.1, 0, 0], 0.2)
15 | ]
16 | ];
17 |
18 | sdfToObj(tree, { size: 256 }, objStr => {
19 | fs.writeFileSync(path.join(__dirname, "union.obj"), objStr);
20 | });
21 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/threaded.js:
--------------------------------------------------------------------------------
1 | const serializeObj = require("serialize-wavefront-obj");
2 | const threadedImplicitMesh = require("./threaded/implicit-mesh");
3 |
4 | module.exports = (tree, options, callback) => {
5 | if (!callback) {
6 | callback = options;
7 | options = { size: 128, threads: 4 };
8 | }
9 |
10 | threadedImplicitMesh(tree, options, ({ cells, positions }) => {
11 | const str = serializeObj(cells, positions);
12 | callback(str);
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/threaded/implicit-mesh.js:
--------------------------------------------------------------------------------
1 | const ndarray = require("ndarray");
2 | const path = require("path");
3 | const surfaceNets = require("surface-nets");
4 |
5 | const { Worker } = require("worker_threads");
6 |
7 | const range = length => Array.from({ length }).map((_, i) => i);
8 |
9 | const scale = (size, mesh) => {
10 | const sx = 2 / size[0];
11 | const sy = 2 / size[1];
12 | const sz = 2 / size[2];
13 |
14 | const p = mesh.positions;
15 |
16 | for (let i = 0; i < p.length; i++) {
17 | p[i][0] = p[i][0] * sx - 1;
18 | p[i][1] = p[i][1] * sy - 1;
19 | p[i][2] = p[i][2] * sz - 1;
20 | }
21 |
22 | return mesh;
23 | };
24 |
25 | module.exports = (tree, { size = 64, threads = 4 }, callback) => {
26 | const data = ndarray(new Float64Array(size * size * size), [
27 | size,
28 | size,
29 | size
30 | ]);
31 |
32 | const doneStatus = range(threads).map(() => false);
33 | const allDone = () => doneStatus.every(done => done);
34 |
35 | range(threads).map(i => {
36 | console.time(`worker[${i}]`);
37 |
38 | const worker = new Worker(path.join(__dirname, "worker.js"), {
39 | workerData: {
40 | id: i,
41 | size,
42 | xs: [
43 | Math.floor((i * size) / threads),
44 | Math.floor(((i + 1) * size) / threads)
45 | ],
46 | tree
47 | }
48 | });
49 |
50 | worker.on("message", msg => {
51 | console.timeEnd(`worker[${i}]`);
52 |
53 | worker.unref();
54 |
55 | doneStatus[i] = true;
56 |
57 | const { xs } = msg;
58 |
59 | let ii = 0;
60 |
61 | for (let x = xs[0]; x < xs[1]; x++) {
62 | for (let y = 0; y < size; y++) {
63 | for (let z = 0; z < size; z++) {
64 | data.set(x, y, z, msg.data[ii][y][z]);
65 | }
66 | }
67 |
68 | ii++;
69 | }
70 |
71 | if (allDone()) {
72 | console.time("surfaceNets");
73 | const mesh = scale([size, size, size], surfaceNets(data));
74 | console.timeEnd("surfaceNets");
75 | callback(mesh);
76 | }
77 | });
78 | });
79 | };
80 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf-to-obj/threaded/worker.js:
--------------------------------------------------------------------------------
1 | const { workerData, parentPort } = require("worker_threads");
2 | const dsl = require("hiccup-sdf");
3 |
4 | const { id, size, xs, tree } = workerData;
5 |
6 | console.log(`worker[${id}]`, size, xs);
7 |
8 | let data = [];
9 |
10 | const sdfFunction = dsl.compileFunction(tree);
11 |
12 | let x = 0;
13 | for (let i = xs[0]; i < xs[1]; i++) {
14 | if (!data[x]) {
15 | data[x] = [];
16 | }
17 |
18 | for (let y = 0; y < size; y++) {
19 | if (!data[x][y]) {
20 | data[x][y] = [];
21 | }
22 |
23 | for (let z = 0; z < size; z++) {
24 | const j = y;
25 | const k = z;
26 |
27 | const value = sdfFunction([
28 | (i / size) * 2 - 1,
29 | (j / size) * 2 - 1,
30 | (k / size) * 2 - 1
31 | ]);
32 |
33 | data[x][y][z] = value;
34 | }
35 | }
36 |
37 | x++;
38 | }
39 |
40 | parentPort.postMessage({ data, xs, id });
41 | parentPort.unref();
42 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/szymonkaliski/hiccup-sdf/715089e16fbfcfbacd85ca5249709cf6d1ca2a9e/packages/hiccup-sdf/.gitignore
--------------------------------------------------------------------------------
/packages/hiccup-sdf/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Szymon Kaliski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/README.md:
--------------------------------------------------------------------------------
1 | # hiccup-sdf
2 |
3 | Library for building signed distance function models using hiccup-like language.
4 |
5 |
6 |
7 |
8 |
9 | ## Installation
10 |
11 | `npm install hiccup-sdf --save`
12 |
13 | ## Basic usage
14 |
15 | ```js
16 | const { displayRaw } = require("display-sdf");
17 | const { compileShader, glslHelpers } = require("hiccup-sdf");
18 |
19 | const tree = [
20 | "difference",
21 | [
22 | ["box", { s: [0.5, 0.5, 0.5] }],
23 | ["sphere", { r: 0.4 }]
24 | ]
25 | ];
26 |
27 | const { inject, model } = compileShader(tree);
28 | const shader = glslHelpers.createShaderFull(model, inject);
29 |
30 | displayRaw(shader);
31 | ```
32 |
33 | ## Language
34 |
35 | ### Shapes
36 |
37 | - `["sphere", { r: float }]`
38 | - `["box", { s: [float, float, float] }]`
39 | - `["torus", { r1: float, r2: float }]`
40 | - `["hex", { h: float, r: float }]`
41 | - `["triangle", { h: float, r: float }]`
42 | - `["capsule", { a: float, b: float, r: float }]`
43 | - `["cylinder", { h: float, r: float }]`
44 |
45 | ### Operations
46 |
47 | - `["translate", { t: [float, float, float] }, [subtree]]`
48 | - `["scale", { s: float }, [subtree]]`
49 | - `["rotate", { r: [float, float, float] }, [subtree]]`
50 | - `["mirror", { m: [float, float, float] }, [subtree]]`
51 | - `["elongate", { s: [float, float, float] }, [subtree]]`
52 | - `["repeat", { r: [float, float, float] }, [subtree]]`
53 | - `["repeatPolar", { r: float }, [subtree]]`
54 | - `["union", { r: float }, [subtree]]`
55 | - `["intersection", { r: float }, [subtree]]`
56 | - `["difference", { r: float }, [subtree]]`
57 | - `["blend", { k: float }, [subtree]]`
58 |
59 | ### `Map`
60 |
61 | Map is bit more complex operation allowing map-reduce style mapping over huge datasets. This works around instruction/complexity limitations for GPU shaders, and provides nicer API to work with. Unfortunately there are some differences in `map` usage on CPU/GPU (all the other functions/operations should work the same regardless of the backend).
62 |
63 | ```js
64 | const randomPositions = range(1000).map(() => randomPosition()); // random array of [x,y,z] positions
65 |
66 | const tree = [
67 | "map",
68 | {
69 | // data points to map over, an object mapping key to value, multiple datasets can be supplied
70 | data: { position: randomPositions },
71 |
72 | // mapping function, runs for each of the data points, `props` contains a single data point for each of `data` keys
73 | map: props => [
74 | "translate",
75 | {
76 | t: `${props.position}.xyz` // fragment of GLSL code that will be injected when mapping over the texture when ran on GPU, if used on CPU this should be `{ t: props.position }` as we can use the js array directly
77 | },
78 | [
79 | ["sphere", { r: 0.1 }]
80 | ]
81 | ],
82 |
83 | // reducing function, generated subtree will be inserted as last parameter,
84 | // usually `union` / `interesction` / `difference`
85 | reduce: ["union", { r: 0.02 }]
86 | }
87 | ]
88 | ```
89 |
90 | When ran on GPU this operation is turned into efficient texture traversal, and `compileShader()` returns `uniforms` with matching textures.
91 | For full example open [`examples/basic/map.js`](../../examples/basic/map.js).
92 |
93 | ## Public API
94 |
95 | ### `const dsl = require("hiccup-sdf")`
96 |
97 | - `dsl.compileShader(tree)` - generates SDF shader, returns an object: `{ model, uniforms, inject }`:
98 | - `model` - modeling part of SDF shader on GPU
99 | - `inject` - SDF shader code necessary to run the modeling shader
100 | - `uniforms` - data values if the tree is using `map` function
101 | - `dsl.compileFunction(tree)` - generate SDF function to be used on CPU, returns a function:
102 | - `fn([x, y, z])` - returns SDF value for given point
103 |
104 | - `dsl.glslHelpers` - helper utils for generating GLSL code:
105 | - `dsl.glslHelpers.createShaderFull(model, inject)` - creates full SDF shader that can be used without any modifications
106 | - `dsl.glslHelpers.createShaderModel(model, inject)` - creates only the `vec2 doModel(vec3 p)` part of the shader
107 |
108 | ## Acknowledgements
109 |
110 | This project was developed in part at Laboratory, an artist residency for interactive arts: [https://laboratoryspokane.com](https://laboratoryspokane.com).
111 |
112 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/assets/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/szymonkaliski/hiccup-sdf/715089e16fbfcfbacd85ca5249709cf6d1ca2a9e/packages/hiccup-sdf/assets/screen.png
--------------------------------------------------------------------------------
/packages/hiccup-sdf/dsl.js:
--------------------------------------------------------------------------------
1 | const v = require("@thi.ng/vectors");
2 | const { uniq, flatten, without } = require("lodash");
3 |
4 | const GLSL_STL = require("./glsl-stl");
5 |
6 | const GLSL = "GLSL";
7 | const CPU = "CPU";
8 |
9 | const copy = a => a.slice(0);
10 | const clamp = (v, min, max) => Math.max(Math.min(v, max), min);
11 | const length2 = ([x, y]) => Math.sqrt(x * x + y * y);
12 | const length3 = ([x, y, z]) => Math.sqrt(x * x + y * y + z * z);
13 | const range = length => Array.from({ length }).map((_, i) => i);
14 | const flatArray = t => (Array.isArray(t) ? flatten(t) : [t]);
15 | const formatNonString = (t, format) => (typeof t !== "string" ? format(t) : t);
16 |
17 | const GL = {
18 | vec3: v =>
19 | formatNonString(
20 | v,
21 | ([x, y, z]) => `vec3(${GL.f(x)}, ${GL.f(y)}, ${GL.f(z)})`
22 | ),
23 | f: n => formatNonString(n, n => n.toFixed(8)),
24 | i: n => formatNonString(n, n => Math.round(n))
25 | };
26 |
27 | const SHAPE = {
28 | sphere: {
29 | defaultProps: {
30 | r: 0.5
31 | },
32 | [CPU]: { generate: props => p => length3(p) - props.r },
33 | [GLSL]: {
34 | generate: props => p => `sdSphere(${p}, ${GL.f(props.r)})`,
35 | inject: () => GLSL_STL.SD_SPHERE
36 | }
37 | },
38 |
39 | box: {
40 | defaultProps: {
41 | s: [0.1, 0.1, 0.1]
42 | },
43 | [CPU]: {
44 | generate: props => p => {
45 | const d = v.sub3(v.abs3(p), props.s);
46 |
47 | return (
48 | Math.min(Math.max(d[0], Math.max(d[1], d[2])), 0.0) +
49 | length3(v.max3(d, [0, 0, 0]))
50 | );
51 | }
52 | },
53 | [GLSL]: {
54 | generate: props => p => `sdBox(${p}, ${GL.vec3(props.s)})`,
55 | inject: () => GLSL_STL.SD_BOX
56 | }
57 | },
58 |
59 | torus: {
60 | defaultProps: {
61 | r1: 0.1,
62 | r2: 0.2
63 | },
64 | [CPU]: {
65 | generate: props => p => {
66 | const q = [length2([p[0], p[2]]) - props.r2, p[1]];
67 | return length2(q) - props.r1;
68 | }
69 | },
70 | [GLSL]: {
71 | generate: props => p =>
72 | `sdTorus(${p}, ${GL.f(props.r1)}, ${GL.f(props.r2)})`,
73 | inject: () => GLSL_STL.SD_TORUS
74 | }
75 | },
76 |
77 | hex: {
78 | defaultProps: {
79 | h: 0.01,
80 | r: 0.2
81 | },
82 | [CPU]: {
83 | generate: props => p => {
84 | const q = v.abs3(p);
85 |
86 | return Math.max(
87 | q[2] - props.h,
88 | Math.max(q[0] * 0.866025 + q[1] * 0.5, q[1]) - props.r
89 | );
90 | }
91 | },
92 | [GLSL]: {
93 | generate: props => p => `sdHex(${p}, ${GL.f(props.r)}, ${GL.f(props.h)})`,
94 | inject: () => GLSL_STL.SD_HEX
95 | }
96 | },
97 |
98 | triangle: {
99 | defaultProps: {
100 | h: 0.01,
101 | r: 0.2
102 | },
103 | [CPU]: {
104 | generate: props => p => {
105 | const q = v.abs3(p);
106 |
107 | // FIXME: not a triangle?
108 | return Math.max(
109 | q[2] - props.h,
110 | Math.max(q[0] * 0.866025 + p[1] * 0.5, -p[1]) - props.r * 0.5
111 | );
112 | }
113 | },
114 | [GLSL]: {
115 | generate: props => p =>
116 | `sdTriangle(${p}, ${GL.f(props.r)}, ${GL.f(props.h)})`,
117 | inject: () => GLSL_STL.SD_TRIANGLE
118 | }
119 | },
120 |
121 | capsule: {
122 | defaultProps: {
123 | a: [0, 0, 0],
124 | b: [0, 0, 0.2],
125 | r: 0.1
126 | },
127 | [CPU]: {
128 | generate: props => p => {
129 | const pa = v.sub3(copy(p), props.a);
130 | const ba = v.sub3(copy(props.b), props.a);
131 |
132 | const h = clamp(v.dot3(pa, ba) / v.dot3(ba, ba), 0.0, 1.0);
133 |
134 | return length3(v.sub3(pa, v.mulN3(ba, h))) - props.r;
135 | }
136 | },
137 | [GLSL]: {
138 | generate: props => p =>
139 | `sdCapsule(
140 | ${p},
141 | ${GL.vec3(props.a)},
142 | ${GL.vec3(props.b)},
143 | ${GL.f(props.r)}
144 | )`,
145 | inject: () => GLSL_STL.SD_CAPSULE
146 | }
147 | },
148 |
149 | cylinder: {
150 | defaultProps: {
151 | r: 0.1,
152 | h: 0.3
153 | },
154 | [CPU]: {
155 | generate: props => p => {
156 | const d = v.sub2(v.abs2([length2([p[0], p[2]]), p[1]]), [
157 | props.r,
158 | props.h
159 | ]);
160 |
161 | return (
162 | Math.min(Math.max(d[0], d[1]), 0.0) + length2(v.max2(d, [0.0, 0.0]))
163 | );
164 | }
165 | },
166 | [GLSL]: {
167 | generate: props => p =>
168 | `sdCylinder(${p}, ${GL.f(props.r)}, ${GL.f(props.h)})`,
169 | inject: () => GLSL_STL.SD_CYLINDER
170 | }
171 | }
172 | };
173 |
174 | const OP = {
175 | translate: {
176 | defaultProps: {
177 | t: [0, 0, 0]
178 | },
179 | [CPU]: {
180 | generate: (props, children) =>
181 | reduceChildrenCPU(children, { process: p => v.sub3(copy(p), props.t) })
182 | },
183 | [GLSL]: {
184 | generate: (props, children) =>
185 | reduceChildrenGLSL(children, {
186 | process: p => `${p} - ${GL.vec3(props.t)}`
187 | })
188 | }
189 | },
190 |
191 | scale: {
192 | defaultProps: {
193 | s: 0.5
194 | },
195 | [CPU]: {
196 | generate: (props, children) => {
197 | return o => {
198 | const p = v.divN3(o, props.s);
199 |
200 | let d = children[0](p) * props.s;
201 |
202 | for (let i = 1; i < children.length; i++) {
203 | d = Math.min(d, children[i](p)) * props.s;
204 | }
205 |
206 | return d;
207 | };
208 | }
209 | },
210 | [GLSL]: {
211 | generate: (props, children) => o => {
212 | const { s } = props;
213 | const p = `${o} / ${GL.f(s)}`;
214 |
215 | return children
216 | .slice(1)
217 | .reduce(
218 | (memo, child) => reducer(memo, `${child(p)} * ${GL.f(s)}`),
219 | `${children[0](p)} * ${GL.f(s)}`
220 | );
221 | }
222 | }
223 | },
224 |
225 | rotate: {
226 | defaultProps: {
227 | r: [0.0, 0.0, 0.0]
228 | },
229 | [CPU]: {
230 | generate: (props, children) =>
231 | reduceChildrenCPU(children, {
232 | process: p => {
233 | const { r } = props;
234 | const { sin, cos } = Math;
235 | const TAU = Math.PI * 2;
236 |
237 | const rxz = p => [
238 | cos(r[0] * TAU) * p[0] + sin(r[0] * TAU) * p[2],
239 | p[1],
240 | cos(r[0] * TAU) * p[2] + sin(r[0] * TAU) * -p[0]
241 | ];
242 |
243 | const rxy = p => [
244 | cos(r[1] * TAU) * p[0] + sin(r[1] * TAU) * p[1],
245 | cos(r[1] * TAU) * p[1] + sin(r[1] * TAU) * -p[0],
246 | p[2]
247 | ];
248 |
249 | const ryz = p => [
250 | p[0],
251 | cos(r[2] * TAU) * p[1] + sin(r[2] * TAU) * p[2],
252 | cos(r[2] * TAU) * p[2] + sin(r[2] * TAU) * -p[1]
253 | ];
254 |
255 | return ryz(rxy(rxz(p)));
256 | }
257 | })
258 | },
259 | [GLSL]: {
260 | generate: (props, children) =>
261 | reduceChildrenGLSL(children, {
262 | process: p => `opRotate(${p}, ${GL.vec3(props.r)})`
263 | }),
264 | inject: () => GLSL_STL.OP_ROTATE
265 | }
266 | },
267 |
268 | elongate: {
269 | defaultProps: {
270 | s: [0.1, 0.1, 0.1]
271 | },
272 | [CPU]: {
273 | generate: () =>
274 | reduceChildrenCPU(children, {
275 | process: p => v.max3(v.sub3(v.abs3(p), props.s), [0, 0, 0])
276 | })
277 | },
278 | [GLSL]: {
279 | generate: (props, children) =>
280 | reduceChildrenGLSL(children, {
281 | process: p => `opElongate(${p}, ${GL.vec3(props.s)})`
282 | }),
283 | inject: () => GLSL_STL.OP_ELONGATE
284 | }
285 | },
286 |
287 | mirror: {
288 | defaultProps: {
289 | m: [0.5, 0.0, 0]
290 | },
291 | [CPU]: {
292 | generate: (props, children) =>
293 | reduceChildrenCPU(children, {
294 | process: p => [
295 | props.m[0] > 0 ? Math.abs(p[0]) - props.m[0] : p[0],
296 | props.m[1] > 0 ? Math.abs(p[1]) - props.m[1] : p[1],
297 | props.m[2] > 0 ? Math.abs(p[2]) - props.m[2] : p[2]
298 | ]
299 | })
300 | },
301 | [GLSL]: {
302 | generate: (props, children) =>
303 | reduceChildrenGLSL(children, {
304 | process: p => `opMirror(${p}, ${GL.vec3(props.m)})`
305 | }),
306 | inject: () => GLSL_STL.OP_MIRROR
307 | }
308 | },
309 |
310 | repeat: {
311 | defaultProps: {
312 | r: [1.0, 0.0, 0.0]
313 | },
314 | [CPU]: {
315 | generate: (props, children) =>
316 | reduceChildrenCPU(children, {
317 | process: p => [
318 | props.r[0] > 0
319 | ? ((p[0] + props.r[0] / 2) % props.r[0]) - props.r[0] / 2
320 | : p[0],
321 | props.r[1] > 0
322 | ? ((p[1] + props.r[1] / 2) % props.r[1]) - props.r[1] / 2
323 | : p[1],
324 | props.r[2] > 0
325 | ? ((p[2] + props.r[2] / 2) % props.r[2]) - props.r[2] / 2
326 | : p[2]
327 | ]
328 | })
329 | },
330 | [GLSL]: {
331 | generate: (props, children) =>
332 | reduceChildrenGLSL(children, {
333 | process: p => `opRepeat(${p}, ${GL.vec3(props.r)})`
334 | }),
335 | inject: () => GLSL_STL.OP_REPEAT
336 | }
337 | },
338 |
339 | repeatPolar: {
340 | defaultProps: {
341 | r: 6
342 | },
343 | [CPU]: {
344 | generate: (props, children) =>
345 | reduceChildrenCPU(children, {
346 | process: p => {
347 | // FIXME: this is broken
348 |
349 | const angle = (Math.PI * 2.0) / props.r;
350 | const a = Math.atan2(p[1], p[0]) + angle / 2.0;
351 | const l = length2([p[0], p[1]]);
352 |
353 | const aa = (a % angle) - angle / 2.0;
354 |
355 | return [Math.cos(aa) * l, Math.sin(aa) * l, p[2]];
356 | }
357 | })
358 | },
359 | [GLSL]: {
360 | generate: (props, children) =>
361 | reduceChildrenGLSL(children, {
362 | process: p => `opRepeatPolar(${p}, ${GL.f(props.r)})`
363 | }),
364 | inject: () => GLSL_STL.OP_REPEAT_POLAR
365 | }
366 | },
367 |
368 | union: {
369 | defaultProps: {
370 | r: 0
371 | },
372 | [CPU]: {
373 | generate: (props, children) => {
374 | const unionRound = (a, b) => {
375 | const u = v.max2([props.r - a, props.r - b], [0, 0]);
376 | return Math.max(props.r, Math.min(a, b)) - length2(u);
377 | };
378 |
379 | const union = props.r > 0 ? unionRound : Math.min;
380 |
381 | return reduceChildrenCPU(children, { reducer: union });
382 | }
383 | },
384 | [GLSL]: {
385 | generate: (props, children) =>
386 | reduceChildrenGLSL(children, {
387 | reducer: (a, b) =>
388 | props.r > 0
389 | ? `opUnionRound(${a}, ${b}, ${GL.f(props.r)})`
390 | : `opUnion(${a}, ${b})`
391 | }),
392 | inject: props =>
393 | props.r > 0 ? GLSL_STL.OP_UNION_ROUND : GLSL_STL.OP_UNION
394 | }
395 | },
396 |
397 | intersection: {
398 | defaultProps: {
399 | r: 0
400 | },
401 | [CPU]: {
402 | generate: (props, children) => {
403 | const intersectionRound = (a, b) => {
404 | const u = v.max2([props.r + a, props.r + b], [0, 0]);
405 | return Math.min(-props.r, Math.max(a, b)) + length2(u);
406 | };
407 |
408 | const intersection = props.r > 0 ? intersectionRound : Math.max;
409 |
410 | return reduceChildrenCPU(children, { reducer: intersection });
411 | }
412 | },
413 | [GLSL]: {
414 | generate: (props, children) =>
415 | reduceChildrenGLSL(children, {
416 | reducer: (a, b) =>
417 | props.r > 0
418 | ? `opIntersectionRound(${a}, ${b}, ${GL.f(props.r)})`
419 | : `opIntersection(${a}, ${b})`
420 | }),
421 | inject: props =>
422 | props.r > 0 ? GLSL_STL.OP_INTERSECTION_ROUND : GLSL_STL.OP_INTERSECTION
423 | }
424 | },
425 |
426 | difference: {
427 | defaultProps: {
428 | r: 0
429 | },
430 | [CPU]: {
431 | generate: (props, children) => {
432 | const differenceRound = (a, b) => {
433 | const u = v.max2([props.r + a, props.r - b], [0, 0]);
434 | return Math.min(-props.r, Math.max(a, -b)) + length2(u);
435 | };
436 |
437 | const difference =
438 | props.r > 0 ? differenceRound : (a, b) => Math.max(a, -b);
439 |
440 | return reduceChildrenCPU(children, { reducer: difference });
441 | }
442 | },
443 | [GLSL]: {
444 | generate: (props, children) =>
445 | reduceChildrenGLSL(children, {
446 | reducer: (a, b) =>
447 | props.r > 0
448 | ? `opDifferenceRound(${a}, ${b}, ${GL.f(props.r)})`
449 | : `opDifference(${a}, ${b})`
450 | }),
451 | inject: props =>
452 | props.r > 0 ? GLSL_STL.OP_DIFFERENCE_ROUND : GLSL_STL.OP_DIFFERENCE
453 | }
454 | },
455 |
456 | blend: {
457 | defaultProps: {
458 | k: 0.5
459 | },
460 | [CPU]: {
461 | generate: (props, children) => {
462 | const blend = (a, b) => (1.0 - props.k) * a + props.k * b;
463 | return reduceChildrenCPU(children, { reducer: blend });
464 | }
465 | },
466 | [GLSL]: {
467 | generate: (props, children) =>
468 | reduceChildrenGLSL(children, {
469 | reducer: (a, b) => `opBlend(${a}, ${b}, ${GL.f(props.k)})`
470 | }),
471 |
472 | inject: () => GLSL_STL.OP_BLEND
473 | }
474 | },
475 |
476 | map: {
477 | defaultProps: {
478 | reduce: ["union", { r: 0.0 }]
479 | },
480 | [CPU]: {
481 | generate: props => {
482 | const largestLength = Object.keys(props.data).reduce(
483 | (memo, key) => Math.max(memo, props.data[key].length),
484 | 0
485 | );
486 |
487 | const reducer = children =>
488 | OP[props.reduce[0]][CPU].generate(props.reduce[1], children);
489 |
490 | return p => {
491 | let d;
492 |
493 | for (let i = 0; i < largestLength; i++) {
494 | const currentData = Object.keys(props.data).reduce((memo, key) => {
495 | return Object.assign(memo, { [key]: props.data[key][i] });
496 | }, {});
497 |
498 | const mapD = compile(props.map(currentData), { type: CPU }).model;
499 |
500 | if (!d) {
501 | d = mapD(p);
502 | } else {
503 | d = reducer([() => d, p => mapD(p)])(p);
504 | }
505 | }
506 |
507 | return d;
508 | };
509 | }
510 | },
511 | [GLSL]: {
512 | generate: props => p => `map${props.key}(${p})`,
513 |
514 | uniforms: props => {
515 | const largestTexLength = Object.keys(props.data).reduce(
516 | (memo, key) => Math.max(memo, props.data[key].length),
517 | 0
518 | );
519 |
520 | const texSize = Math.ceil(Math.sqrt(largestTexLength));
521 |
522 | const ensureArraySize = (arr, length, empty = 0) =>
523 | range(length).map(i => (arr[i] !== undefined ? arr[i] : empty));
524 |
525 | const squareArray = (arr, size, empty = 0) => {
526 | return range(size).map(i =>
527 | range(size).map(j => {
528 | const idx = i * size + j;
529 |
530 | return ensureArraySize(
531 | idx < arr.length ? arr[idx] : empty,
532 | 4,
533 | empty
534 | );
535 | })
536 | );
537 | };
538 |
539 | return Object.keys(props.data).reduce(
540 | (memo, key) =>
541 | Object.assign(memo, {
542 | [`${key}${props.key}Tex`]: squareArray(props.data[key], texSize)
543 | }),
544 | {}
545 | );
546 | },
547 |
548 | inject: props => {
549 | const largestTexLength = Object.keys(props.data).reduce(
550 | (memo, key) => Math.max(memo, props.data[key].length),
551 | 0
552 | );
553 |
554 | const texSize = Math.ceil(Math.sqrt(largestTexLength));
555 |
556 | const [reduceOp, reduceProps] = props.reduce;
557 |
558 | const { generate: reduceGenerate, inject: reduceInject } = OP[reduceOp][
559 | GLSL
560 | ];
561 |
562 | const childTree = props.map(
563 | Object.keys(props.data).reduce(
564 | (memo, key) => Object.assign(memo, { [key]: key }),
565 | {}
566 | )
567 | );
568 |
569 | const { model: childModel, inject: childInject } = compile(childTree, {
570 | type: GLSL
571 | });
572 |
573 | const reduceChildren = [() => "value", childModel];
574 |
575 | return [
576 | reduceInject(reduceProps),
577 | childInject,
578 | `
579 | ${Object.keys(props.data)
580 | .map(key => `uniform sampler2D ${key}${props.key}Tex;`)
581 | .join("\n")}
582 |
583 | float map${props.key}(vec3 p) {
584 | float value = 0.0;
585 |
586 | for (int i = 0; i < ${GL.i(texSize)}; i++) {
587 | for (int j = 0; j < ${GL.i(texSize)}; j++) {
588 | if (i + j * ${GL.i(texSize)} >= ${GL.i(largestTexLength)}) {
589 | break;
590 | }
591 |
592 | vec2 uv = vec2(
593 | float(i) / ${GL.f(texSize)},
594 | float(j) / ${GL.f(texSize)}
595 | );
596 |
597 | ${Object.keys(props.data)
598 | .map(key => ` vec4 ${key} = texture2D(${key}${props.key}Tex, uv);`)
599 | .join("\n")}
600 |
601 | if (i == 0 && j == 0) {
602 | value = ${childModel("p")};
603 | }
604 | else {
605 | value = ${reduceGenerate(reduceProps, reduceChildren)("p")};
606 | }
607 | }
608 | }
609 |
610 | return value;
611 | }`
612 | ];
613 | }
614 | }
615 | }
616 | };
617 |
618 | const isShape = shape => Object.keys(SHAPE).includes(shape);
619 | const isOp = op => Object.keys(OP).includes(op);
620 |
621 | function reduceChildrenCPU(children, { reducer = Math.min, process = p => p }) {
622 | return o => {
623 | const p = process(o);
624 |
625 | let d = children[0](p);
626 |
627 | for (let i = 1; i < children.length; i++) {
628 | d = reducer(d, children[i](p));
629 | }
630 |
631 | return d;
632 | };
633 | }
634 |
635 | function reduceChildrenGLSL(
636 | children,
637 | { reducer = (a, b) => `min(${a}, ${b})`, process = p => p }
638 | ) {
639 | return o => {
640 | const p = process(o);
641 |
642 | if (children.length === 1) {
643 | return children[0](p);
644 | }
645 |
646 | return children
647 | .slice(1)
648 | .reduce((memo, child) => reducer(memo, child(p)), children[0](p));
649 | };
650 | }
651 |
652 | function preProcessTree(tree) {
653 | let counter = 0;
654 |
655 | const preProcess = tree => {
656 | counter++;
657 |
658 | if (Array.isArray(tree)) {
659 | if (Array.isArray(tree[1])) {
660 | tree[2] = tree[1];
661 | tree[1] = undefined;
662 | }
663 |
664 | if (!tree[1]) {
665 | tree[1] = {};
666 | }
667 |
668 | if (tree[1].key === undefined) {
669 | tree[1].key = counter;
670 | }
671 |
672 | if (tree[2]) {
673 | tree[2].forEach(child => preProcessTree(child));
674 | }
675 | }
676 | };
677 |
678 | const output = tree.slice(0);
679 |
680 | preProcess(output);
681 |
682 | return output;
683 | }
684 |
685 | function compile(inputTree, { type = GLSL }) {
686 | tree = preProcessTree(inputTree);
687 |
688 | if (Array.isArray(tree)) {
689 | const id = tree[0];
690 |
691 | if (isShape(id)) {
692 | const { defaultProps } = SHAPE[id];
693 | const { generate, inject } = SHAPE[id][type];
694 |
695 | const props = Object.assign({}, defaultProps, tree[1]);
696 |
697 | return {
698 | model: generate ? generate(props) : undefined,
699 | inject: inject ? inject(props) : undefined
700 | };
701 | }
702 |
703 | if (isOp(id)) {
704 | const { defaultProps } = OP[id];
705 | const { generate, inject, uniforms } = OP[id][type];
706 |
707 | const props = Object.assign({}, defaultProps, tree[1]);
708 | const children = (tree[2] || []).map(child => compile(child, { type }));
709 |
710 | const finalInject = flatArray([
711 | inject ? inject(props) : undefined,
712 | ...children.map(({ inject }) => inject)
713 | ]);
714 |
715 | const finalUniforms = flatArray([
716 | uniforms ? uniforms(props) : undefined,
717 | ...children.map(({ uniforms }) => uniforms)
718 | ]);
719 |
720 | return {
721 | model: generate
722 | ? generate(props, children.map(({ model }) => model))
723 | : undefined,
724 | uniforms: finalUniforms,
725 | inject: finalInject
726 | };
727 | }
728 | }
729 |
730 | if (typeof args === "function") {
731 | return compile(args(), { type });
732 | }
733 |
734 | console.warn("tree not recognized", tree);
735 | return;
736 | }
737 |
738 | const compileFunction = tree => {
739 | return compile(tree, { type: CPU }).model;
740 | };
741 |
742 | const compileShader = tree => {
743 | const result = compile(tree, { type: GLSL });
744 |
745 | return {
746 | model: result.model("p"),
747 | uniforms: without(result.uniforms, undefined).reduce(
748 | (a, b) => Object.assign(a, b),
749 | {}
750 | ),
751 | inject: without(uniq(flatArray(result.inject)), undefined).join("\n")
752 | };
753 | };
754 |
755 | module.exports = { preProcessTree, compile, compileFunction, compileShader };
756 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/glsl-helpers.js:
--------------------------------------------------------------------------------
1 | const createShaderModel = (sdfFragment, sdfLibrary) => `
2 | ${sdfLibrary}
3 |
4 | vec2 doModel(vec3 p) {
5 | return vec2(${sdfFragment}, 0.0);
6 | }
7 | `;
8 |
9 | const createShaderFull = (sdfFragment, sdfLibrary) => `
10 | precision mediump float;
11 |
12 | const int SDF_STEPS = 50;
13 |
14 | uniform float width;
15 | uniform float height;
16 |
17 | uniform float camTheta;
18 | uniform float camPhi;
19 | uniform float camDistance;
20 |
21 | ${createShaderModel(sdfFragment, sdfLibrary)}
22 |
23 | vec2 calcRayIntersection(vec3 rayOrigin, vec3 rayDirection, float maxDistance, float prec) {
24 | float latest = prec * 2.0;
25 | float dist = +0.0;
26 | float type = -1.0;
27 | vec2 res = vec2(-1.0, -1.0);
28 |
29 | for (int i = 0; i < SDF_STEPS; i++) {
30 | if (latest < prec || dist > maxDistance) {
31 | break;
32 | }
33 |
34 | vec2 result = doModel(rayOrigin + rayDirection * dist);
35 |
36 | latest = result.x;
37 | type = result.y;
38 | dist += latest;
39 | }
40 |
41 | if (dist < maxDistance) {
42 | res = vec2(dist, type);
43 | }
44 |
45 | return res;
46 | }
47 |
48 | vec2 raytrace(vec3 rayOrigin, vec3 rayDirection) {
49 | return calcRayIntersection(rayOrigin, rayDirection, 100.0, 0.0001);
50 | }
51 |
52 | vec3 calcNormal(vec3 pos, float eps) {
53 | const vec3 v1 = vec3( 1.0, -1.0, -1.0);
54 | const vec3 v2 = vec3(-1.0, -1.0, 1.0);
55 | const vec3 v3 = vec3(-1.0, 1.0, -1.0);
56 | const vec3 v4 = vec3( 1.0, 1.0, 1.0);
57 |
58 | return normalize(
59 | v1 * doModel(pos + v1 * eps).x +
60 | v2 * doModel(pos + v2 * eps).x +
61 | v3 * doModel(pos + v3 * eps).x +
62 | v4 * doModel(pos + v4 * eps).x
63 | );
64 | }
65 |
66 | vec3 normal(vec3 pos) {
67 | return calcNormal(pos, 0.001);
68 | }
69 |
70 | mat3 calcLookAtMatrix(vec3 origin, vec3 target, float roll) {
71 | vec3 rr = vec3(sin(roll), cos(roll), 0.0);
72 | vec3 ww = normalize(target - origin);
73 | vec3 uu = normalize(cross(ww, rr));
74 | vec3 vv = normalize(cross(uu, ww));
75 |
76 | return mat3(uu, vv, ww);
77 | }
78 |
79 | vec3 getRay(mat3 camMat, vec2 screenPos, float lensLength) {
80 | return normalize(camMat * vec3(screenPos, lensLength));
81 | }
82 |
83 | vec3 getRay(vec3 origin, vec3 target, vec2 screenPos, float lensLength) {
84 | mat3 camMat = calcLookAtMatrix(origin, target, 0.0);
85 | return getRay(camMat, screenPos, lensLength);
86 | }
87 |
88 | vec2 square(vec2 screenSize) {
89 | vec2 position = 2.0 * (gl_FragCoord.xy / screenSize.xy) - 1.0;
90 | position.x *= screenSize.x / screenSize.y;
91 | return position;
92 | }
93 |
94 | void orbitCamera(out vec3 rayOrigin, out vec3 rayDirection) {
95 | float PI = 3.14159265359;
96 |
97 | vec2 screenPos = square(vec2(width, height));
98 | vec3 rayTarget = vec3(0.0);
99 |
100 | rayOrigin = vec3(
101 | camDistance * sin(camTheta * PI / 360.0) * cos(camPhi * PI / 360.0),
102 | camDistance * sin(camPhi * PI / 360.0),
103 | camDistance * cos(camTheta * PI / 360.0) * cos(camPhi * PI / 360.0)
104 | );
105 |
106 | rayDirection = getRay(rayOrigin, rayTarget, screenPos, 2.0);
107 | }
108 |
109 | vec3 lighting(vec3 pos, vec3 nor, vec3 rayOrigin, vec3 rayDirection) {
110 | vec3 dir = normalize(vec3(-10.0, 10.0, 10.0));
111 | vec3 col = vec3(1.0);
112 | vec3 dif = col * max(0.05, dot(dir, nor));
113 |
114 | vec3 ambient = vec3(0.1);
115 |
116 | return dif + ambient;
117 | }
118 |
119 | void main () {
120 | vec3 color = vec3(0.2);
121 | vec3 rayOrigin, rayDirection;
122 |
123 | orbitCamera(rayOrigin, rayDirection);
124 |
125 | vec2 t = raytrace(rayOrigin, rayDirection);
126 |
127 | if (t.x > -0.5) {
128 | vec3 pos = rayOrigin + rayDirection * t.x;
129 | vec3 nor = normal(pos);
130 |
131 | color = lighting(pos, nor, rayOrigin, rayDirection);
132 | }
133 |
134 | gl_FragColor = vec4(color, 1.0);
135 | }
136 | `;
137 |
138 | module.exports = {
139 | createShader: createShaderFull,
140 | createShaderFull,
141 | createShaderModel
142 | };
143 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/glsl-stl.js:
--------------------------------------------------------------------------------
1 | const SD_SPHERE = `
2 | float sdSphere(vec3 p, float r) {
3 | return length(p) - r;
4 | }`;
5 |
6 | const SD_BOX = `
7 | float sdBox(vec3 p, vec3 s) {
8 | vec3 d = abs(p) - s;
9 | return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0));
10 | }`;
11 |
12 | const SD_TORUS = `
13 | float sdTorus(vec3 p, float r1, float r2) {
14 | vec2 q = vec2(length(p.xz) - r2, p.y);
15 | return length(q) - r1;
16 | }`;
17 |
18 | const SD_HEX = `
19 | float sdHex(vec3 p, float r, float h) {
20 | vec3 q = abs(p);
21 | return max(q.z - h, max((q.x * 0.866025 + q.y * 0.5), q.y) - r);
22 | }`;
23 |
24 | const SD_TRIANGLE = `
25 | float sdTriangle(vec3 p, float r, float h) {
26 | vec3 q = abs(p);
27 | return max(q.z - h, max(q.x * 0.866025 + p.y * 0.5, -p.y) - r * 0.5);
28 | }`;
29 |
30 | const SD_CAPSULE = `
31 | float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
32 | vec3 pa = p - a;
33 | vec3 ba = b - a;
34 |
35 | float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
36 |
37 | return length(pa - ba * h) - r;
38 | }`;
39 |
40 | const SD_CYLINDER = `
41 | float sdCylinder(vec3 p, float r, float h) {
42 | vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(r, h);
43 | return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
44 | }`;
45 |
46 | const OP_ROTATE = `
47 | vec3 opRotate(vec3 p, vec3 r) {
48 | float PI = 3.14159265359;
49 |
50 | p.xz = cos(r.x * PI) * p.xz + sin(r.x * PI) * vec2(p.z, -p.x);
51 | p.xy = cos(r.y * PI) * p.xy + sin(r.y * PI) * vec2(p.y, -p.x);
52 | p.yz = cos(r.z * PI) * p.yz + sin(r.z * PI) * vec2(p.z, -p.y);
53 |
54 | return p;
55 | }`;
56 |
57 | const OP_MIRROR = `
58 | vec3 opMirror(vec3 p, vec3 m) {
59 | if (abs(m.x) > 0.0) { p.x = abs(p.x) - m.x; }
60 | if (abs(m.y) > 0.0) { p.y = abs(p.y) - m.y; }
61 | if (abs(m.z) > 0.0) { p.z = abs(p.z) - m.z; }
62 |
63 | return p;
64 | }`;
65 |
66 | const OP_REPEAT = `
67 | vec3 opRepeat(vec3 p, vec3 r) {
68 | vec3 halfR = r * 0.5;
69 |
70 | if (r.x > 0.0) { p.x = mod(p.x + halfR.x, r.x) - halfR.x; }
71 | if (r.y > 0.0) { p.y = mod(p.y + halfR.y, r.y) - halfR.y; }
72 | if (r.z > 0.0) { p.z = mod(p.z + halfR.z, r.z) - halfR.z; }
73 |
74 | return p;
75 | }`;
76 |
77 | const OP_REPEAT_POLAR = `
78 | vec3 opRepeatPolar(vec3 p, float r) {
79 | float PI = 3.14159265359;
80 |
81 | float angle = 2.0 * PI / r;
82 |
83 | float a = atan(p.y, p.x) + angle / 2.0;
84 | float l = length(p.xy);
85 |
86 | a = mod(a, angle) - angle / 2.0;
87 |
88 | p.xy = vec2(cos(a), sin(a)) * l;
89 |
90 | return p;
91 | }`;
92 |
93 | const OP_UNION = `
94 | float opUnion(float a, float b) {
95 | return min(a, b);
96 | }`;
97 |
98 | const OP_UNION_ROUND = `
99 | float opUnionRound(float a, float b, float r) {
100 | vec2 u = max(vec2(r - a, r - b), vec2(0.0));
101 | return max(r, min(a, b)) - length(u);
102 | }`;
103 |
104 | const OP_INTERSECTION = `
105 | float opIntersection(float a, float b) {
106 | return max(a, b);
107 | }`;
108 |
109 | const OP_INTERSECTION_ROUND = `
110 | float opIntersectionRound(float a, float b, float r) {
111 | vec2 u = max(vec2(r + a, r + b), vec2(0.0));
112 | return min(-r, max(a, b)) + length(u);
113 | }`;
114 |
115 | const OP_DIFFERENCE = `
116 | float opDifference(float a, float b) {
117 | return max(a, -b);
118 | }`;
119 |
120 | const OP_DIFFERENCE_ROUND = `
121 | float opDifferenceRound(float a, float b, float r) {
122 | vec2 u = max(vec2(r + a, r - b), vec2(0.0));
123 | return min(-r, max(a, -b)) + length(u);
124 | }`;
125 |
126 | const OP_BLEND = `
127 | float opBlend(float a, float b, float k) {
128 | return (1.0 - k) * a + k * b;
129 | }`;
130 |
131 | const OP_ELONGATE = `
132 | vec3 opElongate(vec3 p, vec3 s) {
133 | vec3 q = abs(p) - s;
134 | return vec3(max(q, 0.0));
135 | }`;
136 |
137 | module.exports = {
138 | SD_SPHERE,
139 | SD_BOX,
140 | SD_TORUS,
141 | SD_HEX,
142 | SD_TRIANGLE,
143 | SD_CAPSULE,
144 | SD_CYLINDER,
145 | OP_ROTATE,
146 | OP_MIRROR,
147 | OP_REPEAT,
148 | OP_REPEAT_POLAR,
149 | OP_UNION,
150 | OP_UNION_ROUND,
151 | OP_INTERSECTION,
152 | OP_INTERSECTION_ROUND,
153 | OP_DIFFERENCE,
154 | OP_DIFFERENCE_ROUND,
155 | OP_BLEND,
156 | OP_ELONGATE
157 | };
158 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/index.js:
--------------------------------------------------------------------------------
1 | const dsl = require("./dsl");
2 | const glslHelpers = require("./glsl-helpers");
3 | const glslStl = require("./glsl-stl");
4 |
5 | module.exports = dsl
6 | module.exports.glslHelpers = glslHelpers;
7 | module.exports.glslStl = glslStl;
8 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hiccup-sdf",
3 | "version": "0.0.1",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@thi.ng/api": {
8 | "version": "4.2.3",
9 | "resolved": "https://registry.npmjs.org/@thi.ng/api/-/api-4.2.3.tgz",
10 | "integrity": "sha512-futpLOGn7yL4YTruWdwmmfFm3Rq0Vj8qiZv5imjrL2f8SztY7+73mw16fUSo9XKq45MLZnntMjhAcfHI0kHqHA==",
11 | "requires": {
12 | "@thi.ng/errors": "^0.1.11"
13 | }
14 | },
15 | "@thi.ng/checks": {
16 | "version": "1.5.13",
17 | "resolved": "https://registry.npmjs.org/@thi.ng/checks/-/checks-1.5.13.tgz",
18 | "integrity": "sha512-RvWQ0gwz8+GC6nifuM1o2bUaWEMfKud3nzBqhMGapks68cuJpmBcLjW1QIubDvR05jLMU+ubgXeypU0+1C7NXA=="
19 | },
20 | "@thi.ng/errors": {
21 | "version": "0.1.11",
22 | "resolved": "https://registry.npmjs.org/@thi.ng/errors/-/errors-0.1.11.tgz",
23 | "integrity": "sha512-SFV69GvN1Tuvy8x1zHUPkyWn91KfCEVXIEnZSXgJTGdPabopheQjeOo/Yd4ta83lzhLbtopumu0O9gkZYtkgxw=="
24 | },
25 | "@thi.ng/vectors": {
26 | "version": "0.2.1",
27 | "resolved": "https://registry.npmjs.org/@thi.ng/vectors/-/vectors-0.2.1.tgz",
28 | "integrity": "sha512-/KqSXN1CiB/pWKuJ4u8lafiFfVurpYM6mGIvLy8PrLxt4Riy5F5llAEtEGOgbAIBDs1y6ZBfScWh3AcNQwOwNw==",
29 | "requires": {
30 | "@thi.ng/api": "^4.1.0",
31 | "@thi.ng/checks": "^1.5.7"
32 | }
33 | },
34 | "lodash": {
35 | "version": "4.17.11",
36 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
37 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hiccup-sdf",
3 | "version": "0.0.10",
4 | "description": "hiccup-like syntax for generating SDFs on CPU and GPU",
5 | "main": "index.js",
6 | "author": "Szymon Kaliski (http://szymonkaliski.com)",
7 | "license": "MIT",
8 | "dependencies": {
9 | "@thi.ng/vectors": "^0.2.0",
10 | "lodash": "^4.17.10"
11 | },
12 | "gitHead": "e7f441600f1b472fcf0ef1396399c465ea258d0e"
13 | }
14 |
--------------------------------------------------------------------------------
/packages/hiccup-sdf/test/test.js:
--------------------------------------------------------------------------------
1 | const dsl = require("../");
2 |
3 | const points = Array.from({ length: 10 }).map(() => [
4 | Math.random(),
5 | Math.random(),
6 | Math.random()
7 | ]);
8 |
9 | const treeGLSL = [
10 | "union",
11 | { r: 0.0 },
12 | [
13 | [
14 | "map",
15 | {
16 | data: { points },
17 | map: props => [
18 | "translate",
19 | { t: `${props.points}.xyz` },
20 | [["sphere", { r: 0.2 }]]
21 | ],
22 | reduce: ["union", { r: 0.1 }]
23 | }
24 | ],
25 | ["sphere", { r: 1.0 }]
26 | ]
27 | ];
28 |
29 | const { inject, uniforms, model } = dsl.compileShader(treeGLSL);
30 |
31 | console.log("- inject\n");
32 | console.log(inject);
33 | console.log();
34 | console.log("- uniforms\n");
35 | console.log(uniforms);
36 | console.log();
37 | console.log("- model\n");
38 | console.log(model);
39 | console.log();
40 |
41 | // prettier-ignore
42 | const treeCPU = [
43 | "union",
44 | {},
45 | [
46 | ["sphere"],
47 | ["box"],
48 | [
49 | "translate",
50 | { t: [0, 0, -1] },
51 | [
52 | ["box"]
53 | ]
54 | ]
55 | ]
56 | ];
57 |
58 | const cpuFn = dsl.compileFunction(treeCPU);
59 |
60 | console.log("- cpuFn\n");
61 | console.log(cpuFn.toString());
62 | console.log("\n- cpuFn([0, 0, 0])\n");
63 | console.log(cpuFn([0, 0, 0]));
64 | console.log();
65 |
--------------------------------------------------------------------------------