tela.js 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.yml +8 -0
- package/LICENSE +201 -0
- package/README.md +54 -0
- package/assets/bunny.obj +7474 -0
- package/assets/expand.svg +1 -0
- package/assets/great.jpg +0 -0
- package/assets/kakashi.jpg +0 -0
- package/assets/spot.obj +11999 -0
- package/assets/spot.png +0 -0
- package/assets/torus.obj +3137 -0
- package/assets/x.svg +1 -0
- package/bun.lockb +0 -0
- package/bundle.js +39 -0
- package/dist/node/index.js +37048 -0
- package/dist/web/index.js +1511 -0
- package/index.css +129 -0
- package/index.html +19 -0
- package/index.js +534 -0
- package/package.json +40 -0
- package/src/Animation/Animation.js +61 -0
- package/src/Box/Box.js +105 -0
- package/src/Camera/Camera.js +133 -0
- package/src/Canvas/Canvas.js +203 -0
- package/src/Canvas/README.md +83 -0
- package/src/Color/Color.js +77 -0
- package/src/DomBuilder/DomBuilder.js +126 -0
- package/src/IO/IO.js +120 -0
- package/src/Image/Image.js +138 -0
- package/src/Image/README.md +33 -0
- package/src/Monads/Monads.js +28 -0
- package/src/Ray/Ray.js +7 -0
- package/src/Scene/Mesh.js +103 -0
- package/src/Scene/NaiveScene.js +77 -0
- package/src/Scene/Point.js +109 -0
- package/src/Scene/PointCloud.js +51 -0
- package/src/Scene/Scene.js +200 -0
- package/src/Stream/Stream.js +10 -0
- package/src/Utils/Constants.js +1 -0
- package/src/Utils/Math.js +65 -0
- package/src/Utils/Utils.js +39 -0
- package/src/Vector/Vector.js +495 -0
- package/src/index.js +32 -0
- package/src/index.node.js +5 -0
- package/test/node/amazing_shader.js +56 -0
- package/test/node/bunny.js +55 -0
- package/test/node/bunny_parallel.js +102 -0
- package/test/node/image2rgb.js +57 -0
- package/test/node/image_test.js +38 -0
- package/test/node/lorentz.js +0 -0
- package/test/web/amazing_shader.js +60 -0
- package/test/web/amazing_shader_2.js +54 -0
- package/test/web/bunny.js +72 -0
- package/test/web/image2rgb.js +77 -0
- package/test/web/interactive_wave.js +108 -0
- package/test/web/lorenz.js +60 -0
- package/test/web/mandelbrot.js +59 -0
- package/test/web/rotating_grid.js +62 -0
- package/test/web/signed_bunny.js +139 -0
- package/test/web/signed_distance.js +95 -0
- package/test/web/simple_animation.js +39 -0
- package/test/web/simple_shader.js +14 -0
- package/test/web/six_spheres.js +102 -0
- package/test/web/wave_equation.js +93 -0
- package/vs-monaco/package/LICENSE +21 -0
- package/vs-monaco/package/ThirdPartyNotices.txt +448 -0
- package/vs-monaco/package/min/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.de.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.es.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.fr.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.it.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.ja.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.ko.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.ru.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.zh-cn.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.zh-tw.js +8 -0
- package/vs-monaco/package/min/vs/base/worker/workerMain.js +27 -0
- package/vs-monaco/package/min/vs/basic-languages/abap/abap.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/apex/apex.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/azcli/azcli.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/bat/bat.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/bicep/bicep.js +11 -0
- package/vs-monaco/package/min/vs/basic-languages/cameligo/cameligo.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/clojure/clojure.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/coffee/coffee.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/cpp/cpp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/csharp/csharp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/csp/csp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/css/css.js +12 -0
- package/vs-monaco/package/min/vs/basic-languages/cypher/cypher.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/dart/dart.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/dockerfile/dockerfile.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/ecl/ecl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/elixir/elixir.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/flow9/flow9.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/freemarker2/freemarker2.js +12 -0
- package/vs-monaco/package/min/vs/basic-languages/fsharp/fsharp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/go/go.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/graphql/graphql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/handlebars/handlebars.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/hcl/hcl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/html/html.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/ini/ini.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/java/java.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/javascript/javascript.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/julia/julia.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/kotlin/kotlin.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/less/less.js +11 -0
- package/vs-monaco/package/min/vs/basic-languages/lexon/lexon.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/liquid/liquid.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/lua/lua.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/m3/m3.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/markdown/markdown.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/mdx/mdx.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/mips/mips.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/msdax/msdax.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/mysql/mysql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/objective-c/objective-c.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pascal/pascal.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pascaligo/pascaligo.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/perl/perl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pgsql/pgsql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/php/php.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pla/pla.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/postiats/postiats.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/powerquery/powerquery.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/powershell/powershell.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/protobuf/protobuf.js +11 -0
- package/vs-monaco/package/min/vs/basic-languages/pug/pug.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/python/python.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/qsharp/qsharp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/r/r.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/razor/razor.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/redis/redis.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/redshift/redshift.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/restructuredtext/restructuredtext.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/ruby/ruby.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/rust/rust.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sb/sb.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/scala/scala.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/scheme/scheme.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/scss/scss.js +12 -0
- package/vs-monaco/package/min/vs/basic-languages/shell/shell.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/solidity/solidity.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sophia/sophia.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sparql/sparql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sql/sql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/st/st.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/swift/swift.js +13 -0
- package/vs-monaco/package/min/vs/basic-languages/systemverilog/systemverilog.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/tcl/tcl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/twig/twig.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/typescript/typescript.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/vb/vb.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/wgsl/wgsl.js +307 -0
- package/vs-monaco/package/min/vs/basic-languages/xml/xml.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/yaml/yaml.js +10 -0
- package/vs-monaco/package/min/vs/editor/editor.main.css +6 -0
- package/vs-monaco/package/min/vs/editor/editor.main.js +745 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.de.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.es.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.fr.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.it.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.ja.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.ko.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.ru.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.zh-cn.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.zh-tw.js +29 -0
- package/vs-monaco/package/min/vs/language/css/cssMode.js +13 -0
- package/vs-monaco/package/min/vs/language/css/cssWorker.js +81 -0
- package/vs-monaco/package/min/vs/language/html/htmlMode.js +13 -0
- package/vs-monaco/package/min/vs/language/html/htmlWorker.js +453 -0
- package/vs-monaco/package/min/vs/language/json/jsonMode.js +15 -0
- package/vs-monaco/package/min/vs/language/json/jsonWorker.js +36 -0
- package/vs-monaco/package/min/vs/language/typescript/tsMode.js +20 -0
- package/vs-monaco/package/min/vs/language/typescript/tsWorker.js +37016 -0
- package/vs-monaco/package/min/vs/loader.js +11 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const SVG_URL = "http://www.w3.org/2000/svg";
|
|
2
|
+
const SVG_TAGS = [
|
|
3
|
+
"svg",
|
|
4
|
+
"g",
|
|
5
|
+
"circle",
|
|
6
|
+
"ellipse",
|
|
7
|
+
"line",
|
|
8
|
+
"path",
|
|
9
|
+
"polygon",
|
|
10
|
+
"polyline",
|
|
11
|
+
"rect",
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
class DomBuilder {
|
|
15
|
+
constructor(element) {
|
|
16
|
+
this.element = element;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
attr(name, value) {
|
|
20
|
+
this.element.setAttribute(name, value);
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
style(styleStr) {
|
|
25
|
+
this.element.setAttribute("style", styleStr);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {Array<DOM | DOMBuilder>} element
|
|
31
|
+
*/
|
|
32
|
+
appendChild(...elements) {
|
|
33
|
+
elements.forEach(e => {
|
|
34
|
+
if (isElement(e)) {
|
|
35
|
+
this.element.appendChild(e);
|
|
36
|
+
} else if (isPromise(e)) {
|
|
37
|
+
e.then(actualElem => this.appendChild(actualElem));
|
|
38
|
+
} else {
|
|
39
|
+
this.element.appendChild(e.build());
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* @param {String || Promise<String>} value
|
|
48
|
+
* @returns DOMBuilder
|
|
49
|
+
*/
|
|
50
|
+
inner(value) {
|
|
51
|
+
if (isPromise(value)) {
|
|
52
|
+
value.then(v => this.element.innerHTML = v);
|
|
53
|
+
} else {
|
|
54
|
+
this.element.innerHTML = value;
|
|
55
|
+
}
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
removeChildren() {
|
|
60
|
+
while (this.element.firstChild) {
|
|
61
|
+
this.element.removeChild(this.element.lastChild);
|
|
62
|
+
}
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
html(value) {
|
|
67
|
+
return this.inner(value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
event(eventName, lambda) {
|
|
71
|
+
this.element.addEventListener(eventName, lambda);
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
build() {
|
|
76
|
+
return this.element;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
addClass(className) {
|
|
80
|
+
if (!className || className === "") return this;
|
|
81
|
+
this.element.classList.add(...className.split(" "));
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
removeClass(className) {
|
|
86
|
+
this.element.classList.remove(className);
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {String | DOM} elem
|
|
93
|
+
*/
|
|
94
|
+
static of(elem) {
|
|
95
|
+
if (isElement(elem)) {
|
|
96
|
+
return new DomBuilder(elem);
|
|
97
|
+
}
|
|
98
|
+
const isSvg = SVG_TAGS.includes(elem);
|
|
99
|
+
const element = isSvg ?
|
|
100
|
+
document.createElementNS(SVG_URL, elem) :
|
|
101
|
+
document.createElement(elem);
|
|
102
|
+
// if (isSvg) element.setAttribute("xmlns", SVG_URL);
|
|
103
|
+
return new DomBuilder(element);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static ofId(id) {
|
|
107
|
+
return new DomBuilder(document.getElementById(id));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//Returns true if it is a DOM element
|
|
112
|
+
function isElement(o) {
|
|
113
|
+
return typeof HTMLElement === "object"
|
|
114
|
+
? o instanceof HTMLElement //DOM2
|
|
115
|
+
: o &&
|
|
116
|
+
typeof o === "object" &&
|
|
117
|
+
o !== null &&
|
|
118
|
+
o.nodeType === 1 &&
|
|
119
|
+
typeof o.nodeName === "string";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isPromise(o) {
|
|
123
|
+
return o instanceof Promise;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default DomBuilder;
|
package/src/IO/IO.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { writeFileSync, unlinkSync } from "fs";
|
|
2
|
+
import { execSync, spawn } from "child_process";
|
|
3
|
+
import Jimp from "jimp";
|
|
4
|
+
import Image from "../Image/Image";
|
|
5
|
+
import Color from "../Color/Color";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export function saveImageToFile(fileAddress, image) {
|
|
9
|
+
const { fileName, extension } = getFileNameAndExtensionFromAddress(fileAddress);
|
|
10
|
+
const ppmName = `${fileName}.ppm`;
|
|
11
|
+
writeFileSync(ppmName, createPPMFromFromImage(image));
|
|
12
|
+
if (extension !== "ppm") {
|
|
13
|
+
execSync(`ffmpeg -i ${ppmName} ${fileName}.${extension}`);
|
|
14
|
+
unlinkSync(ppmName)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getFileNameAndExtensionFromAddress(address) {
|
|
19
|
+
const lastDotIndex = address.lastIndexOf(".");
|
|
20
|
+
const fileName = address.slice(0, lastDotIndex);
|
|
21
|
+
const extension = address.slice(lastDotIndex + 1);
|
|
22
|
+
return { fileName, extension };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function readImageFrom(src) {
|
|
26
|
+
const { fileName, extension } = getFileNameAndExtensionFromAddress(src);
|
|
27
|
+
execSync(`ffmpeg -i ${src} ${fileName}.${extension}`);
|
|
28
|
+
readFileSync()
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
Jimp.read(src, (error, image) => {
|
|
31
|
+
if (error) {
|
|
32
|
+
return reject(error);
|
|
33
|
+
}
|
|
34
|
+
const width = image.bitmap.width;
|
|
35
|
+
const height = image.bitmap.height;
|
|
36
|
+
|
|
37
|
+
const img = Image.ofSize(width, height);
|
|
38
|
+
|
|
39
|
+
img.map((i, j) => {
|
|
40
|
+
|
|
41
|
+
const color = Jimp.intToRGBA(image.getPixelColor(x, y));
|
|
42
|
+
return Color.ofRGB(color.r, color.g, color.b);
|
|
43
|
+
})
|
|
44
|
+
resolve(img);
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function createPPMFromFromImage(image) {
|
|
50
|
+
const width = image.width;
|
|
51
|
+
const height = image.height;
|
|
52
|
+
const pixelData = image.toArray();
|
|
53
|
+
const MAX_8_BIT = 255;
|
|
54
|
+
let file = `P3\n${width} ${height}\n${MAX_8_BIT}\n`;
|
|
55
|
+
for (let i = 0; i < pixelData.length; i += 4) {
|
|
56
|
+
file += `${pixelData[i]} ${pixelData[i + 1]} ${pixelData[i + 2]}\n`;
|
|
57
|
+
}
|
|
58
|
+
return file;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function saveStreamToFile(fileAddress, streamWithImages, { imageGetter = s => s.image, fps }) {
|
|
62
|
+
const { fileName, extension } = getFileNameAndExtensionFromAddress(fileAddress);
|
|
63
|
+
let ite = 0;
|
|
64
|
+
let time = 0;
|
|
65
|
+
let timeCheck = performance.now();
|
|
66
|
+
return {
|
|
67
|
+
until: streamStatePredicate => {
|
|
68
|
+
let s = streamWithImages;
|
|
69
|
+
while (streamStatePredicate(s.head)) {
|
|
70
|
+
const image = imageGetter(s.head);
|
|
71
|
+
writeFileSync(`${fileName}_${ite++}.ppm`, createPPMFromFromImage(image));
|
|
72
|
+
const newTimeCheck = performance.now();
|
|
73
|
+
time += (newTimeCheck - timeCheck) * 1e-3;
|
|
74
|
+
timeCheck = performance.now();
|
|
75
|
+
s = s.tail;
|
|
76
|
+
}
|
|
77
|
+
if (!fps) fps = ite / time;
|
|
78
|
+
execSync(`ffmpeg -framerate ${fps} -i ${fileName}_%d.ppm ${fileName}.${extension}`);
|
|
79
|
+
for (let i = 0; i < ite; i++) {
|
|
80
|
+
unlinkSync(`${fileName}_${i}.ppm`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function saveParallelToFile(fileAddress, arrayWithImageProducers, { fps }) {
|
|
87
|
+
const { fileName, extension } = getFileNameAndExtensionFromAddress(fileAddress);
|
|
88
|
+
const times = [];
|
|
89
|
+
const promises = arrayWithImageProducers.map((imageProducers, i) => {
|
|
90
|
+
const spawnFile = "IO_parallel" + i + ".js";
|
|
91
|
+
writeFileSync(spawnFile, `
|
|
92
|
+
import { writeFileSync, unlinkSync } from "fs";
|
|
93
|
+
${createPPMFromFromImage.toString()}
|
|
94
|
+
${imageProducers}
|
|
95
|
+
images.forEach()
|
|
96
|
+
|
|
97
|
+
`);
|
|
98
|
+
return new Promise(resolve => {
|
|
99
|
+
const process = spawn(`bun ${spawnFile}`)
|
|
100
|
+
process.on("exit", () => {
|
|
101
|
+
resolve();
|
|
102
|
+
})
|
|
103
|
+
});
|
|
104
|
+
})
|
|
105
|
+
Promise.all(promises)
|
|
106
|
+
.then(groupOfImages => {
|
|
107
|
+
let n = 0;
|
|
108
|
+
groupOfImages.forEach(images =>
|
|
109
|
+
images.forEach(image => {
|
|
110
|
+
console.log("Image generated", n)
|
|
111
|
+
writeFileSync(`${fileName}_${n++}.ppm`, createPPMFromFromImage(image));
|
|
112
|
+
})
|
|
113
|
+
)
|
|
114
|
+
if (!fps) fps = Math.floor(1 / (times.reduce((e, t) => e + t, 0) / n));
|
|
115
|
+
execSync(`ffmpeg -framerate ${fps} -i ${fileName}_%d.ppm ${fileName}.${extension}`);
|
|
116
|
+
for (let i = 0; i < n; i++) {
|
|
117
|
+
unlinkSync(`${fileName}_${i}.ppm`);
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import Color from "../Color/Color.js";
|
|
2
|
+
import Jimp from "jimp";
|
|
3
|
+
|
|
4
|
+
export default class Image {
|
|
5
|
+
|
|
6
|
+
constructor(width, height) {
|
|
7
|
+
this._width = width;
|
|
8
|
+
this._height = height;
|
|
9
|
+
this._image = new Array(this._width * this._height)
|
|
10
|
+
.fill(() => Color.ofRGB());
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get width() {
|
|
14
|
+
return this._width;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get height() {
|
|
18
|
+
return this._height;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* color: Color
|
|
23
|
+
*/
|
|
24
|
+
fill(color) {
|
|
25
|
+
return this._image.map(() => color);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
paint() {
|
|
29
|
+
// to implement the same interface as canvas
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* lambda: (x: Number, y: Number) => Color
|
|
35
|
+
*/
|
|
36
|
+
map(lambda) {
|
|
37
|
+
const n = this._image.length;
|
|
38
|
+
const w = this._width;
|
|
39
|
+
const h = this._height;
|
|
40
|
+
for (let k = 0; k < n; k++) {
|
|
41
|
+
const i = Math.floor(k / w);
|
|
42
|
+
const j = k % w;
|
|
43
|
+
const x = j;
|
|
44
|
+
const y = h - 1 - i;
|
|
45
|
+
this._image[k] = lambda(x, y);
|
|
46
|
+
}
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setPxl(x, y, color) {
|
|
51
|
+
const w = this._width;
|
|
52
|
+
const h = this._height;
|
|
53
|
+
const i = h - 1 - y;
|
|
54
|
+
const j = x;
|
|
55
|
+
let index = w * i + j;
|
|
56
|
+
this._image[index] = color;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getPxl(x, y) {
|
|
61
|
+
const w = this._width;
|
|
62
|
+
const h = this._height;
|
|
63
|
+
const i = h - 1 - y;
|
|
64
|
+
const j = x;
|
|
65
|
+
let index = w * i + j;
|
|
66
|
+
return this._image[index];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
array() {
|
|
70
|
+
return this.toArray();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
toArray() {
|
|
74
|
+
const w = this._width;
|
|
75
|
+
const h = this._height;
|
|
76
|
+
const imageData = new Uint8Array(this._width * this._height * 4);
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < h; i++) {
|
|
79
|
+
for (let j = 0; j < w; j++) {
|
|
80
|
+
let index = (w * i + j);
|
|
81
|
+
const color = this._image[index];
|
|
82
|
+
index <<= 2; // multiply by 4
|
|
83
|
+
imageData[index] = color.red * 255;
|
|
84
|
+
imageData[index + 1] = color.green * 255;
|
|
85
|
+
imageData[index + 2] = color.blue * 255;
|
|
86
|
+
imageData[index + 3] = 255;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return imageData;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static ofUrl(url) {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
Jimp.read(src, (error, image) => {
|
|
95
|
+
if (error) {
|
|
96
|
+
return reject(error);
|
|
97
|
+
}
|
|
98
|
+
const width = image.bitmap.width;
|
|
99
|
+
const height = image.bitmap.height;
|
|
100
|
+
|
|
101
|
+
const img = Image.ofSize(width, height);
|
|
102
|
+
|
|
103
|
+
img.map((i, j) => {
|
|
104
|
+
|
|
105
|
+
const color = Jimp.intToRGBA(image.getPixelColor(x, y));
|
|
106
|
+
return Color.ofRGB(color.r, color.g, color.b);
|
|
107
|
+
})
|
|
108
|
+
resolve(img);
|
|
109
|
+
})
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static ofSize(width, height) {
|
|
114
|
+
return new Image(width, height);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static ofDOM(canvasDOM) {
|
|
118
|
+
const ctx = canvasDOM.getContext("2d", { willReadFrequently: true });
|
|
119
|
+
const w = canvasDOM.width;
|
|
120
|
+
const h = canvasDOM.height;
|
|
121
|
+
const imageData = ctx.getImageData(0, 0, w, h);
|
|
122
|
+
const data = imageData.data;
|
|
123
|
+
const image = Image.ofSize(w, h)
|
|
124
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
125
|
+
const color = Color.ofRGB(data[i] / 255, data[i + 1] / 255, data[i + 2] / 255);
|
|
126
|
+
image._image[Math.floor(i / 4)] = color;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static ofCanvas(canvas) {
|
|
131
|
+
const w = canvas.width;
|
|
132
|
+
const h = canvas.height;
|
|
133
|
+
return Image.ofSize(w, h)
|
|
134
|
+
.map((x, y) => {
|
|
135
|
+
return canvas.get(x, y);
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Image.js
|
|
2
|
+
Image is a object that represents a single image
|
|
3
|
+
|
|
4
|
+
```
|
|
5
|
+
Image: Array<Color>
|
|
6
|
+
```
|
|
7
|
+
Image original coordinates:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
0 W-1
|
|
11
|
+
+-------------> y
|
|
12
|
+
|
|
|
13
|
+
|
|
|
14
|
+
| *
|
|
15
|
+
|
|
|
16
|
+
|
|
|
17
|
+
v x
|
|
18
|
+
|
|
19
|
+
H-1
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The client side coordinates are:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
^ y H-1
|
|
27
|
+
|
|
|
28
|
+
| *
|
|
29
|
+
|
|
|
30
|
+
|
|
|
31
|
+
|
|
|
32
|
+
0-------------> x W-1
|
|
33
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function some(x) {
|
|
2
|
+
const object = {
|
|
3
|
+
map: f => maybe(f(x)),
|
|
4
|
+
orElse: () => x,
|
|
5
|
+
forEach: (f) => f(x),
|
|
6
|
+
flatMap: f => f(x),
|
|
7
|
+
isSome: () => true,
|
|
8
|
+
};
|
|
9
|
+
return object;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function none() {
|
|
13
|
+
const object = {
|
|
14
|
+
map: () => object,
|
|
15
|
+
orElse: (f = () => { }) => f(),
|
|
16
|
+
forEach: () => { },
|
|
17
|
+
flatMap: () => object,
|
|
18
|
+
isSome: () => false,
|
|
19
|
+
};
|
|
20
|
+
return object
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function maybe(x) {
|
|
24
|
+
if (x) {
|
|
25
|
+
return some(x);
|
|
26
|
+
}
|
|
27
|
+
return none(x)
|
|
28
|
+
}
|
package/src/Ray/Ray.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Vec3, Vec2 } from "../Vector/Vector.js";
|
|
2
|
+
import Point from "./Point.js"
|
|
3
|
+
import Box from "../Box/Box.js";
|
|
4
|
+
import Color from "../Color/Color.js";
|
|
5
|
+
|
|
6
|
+
const RADIUS = 0.001;
|
|
7
|
+
export default class Mesh {
|
|
8
|
+
constructor({ vertices, normals, textureCoords, faces, colors }) {
|
|
9
|
+
this.vertices = vertices || [];
|
|
10
|
+
this.normals = normals || [];
|
|
11
|
+
this.textureCoords = textureCoords || [];
|
|
12
|
+
this.faces = faces || [];
|
|
13
|
+
this.colors = colors || [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
mapVertices(lambda) {
|
|
17
|
+
const newVertices = [];
|
|
18
|
+
for (let i = 0; i < this.vertices.length; i++) {
|
|
19
|
+
newVertices.push(lambda(this.vertices[i]));
|
|
20
|
+
}
|
|
21
|
+
return new Mesh({
|
|
22
|
+
vertices: newVertices,
|
|
23
|
+
normals: this.normals,
|
|
24
|
+
textureCoords: this.textureCoords,
|
|
25
|
+
faces: this.faces
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
mapColors(lambda) {
|
|
30
|
+
const newColors = [];
|
|
31
|
+
for (let i = 0; i < this.vertices.length; i++) {
|
|
32
|
+
newColors.push(lambda(this.vertices[i]));
|
|
33
|
+
}
|
|
34
|
+
return new Mesh({
|
|
35
|
+
vertices: this.vertices,
|
|
36
|
+
normals: this.normals,
|
|
37
|
+
textureCoords: this.textureCoords,
|
|
38
|
+
faces: this.faces,
|
|
39
|
+
colors: newColors
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getBoundingBox() {
|
|
44
|
+
if (this.boundingBox) return this.boundingBox;
|
|
45
|
+
this.boundingBox = new Box();
|
|
46
|
+
for (let i = 0; i < this.vertices.length; i++) {
|
|
47
|
+
this.boundingBox = this.boundingBox.add(new Box(
|
|
48
|
+
this.vertices[i].add(Vec3(1, 1, 1).scale(RADIUS)),
|
|
49
|
+
this.vertices[i].add(Vec3(1, 1, 1).scale(RADIUS))
|
|
50
|
+
));
|
|
51
|
+
}
|
|
52
|
+
return this.boundingBox;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
asPoints(name, radius = RADIUS) {
|
|
56
|
+
const points = [];
|
|
57
|
+
for (let i = 0; i < this.vertices.length; i++) {
|
|
58
|
+
points.push(
|
|
59
|
+
Point
|
|
60
|
+
.builder()
|
|
61
|
+
.radius(radius)
|
|
62
|
+
.name(`${name}_${i}`)
|
|
63
|
+
.color(this.colors[i])
|
|
64
|
+
.position(this.vertices[i])
|
|
65
|
+
.normal(this.normals[i] || Vec3(1, 0, 0))
|
|
66
|
+
.build()
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
return points;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
static readObj(objFile) {
|
|
74
|
+
const vertices = [];
|
|
75
|
+
const normals = [];
|
|
76
|
+
const texture = [];
|
|
77
|
+
const faces = [];
|
|
78
|
+
objFile.split("\n")
|
|
79
|
+
.forEach((lines) => {
|
|
80
|
+
const spaces = lines.split(" ")
|
|
81
|
+
const type = spaces[0];
|
|
82
|
+
if (type === "v") {
|
|
83
|
+
const v = spaces.slice(1, 4)
|
|
84
|
+
.map(x => Number.parseFloat(x));
|
|
85
|
+
vertices.push(Vec3(...v));
|
|
86
|
+
}
|
|
87
|
+
if (type === "vn") {
|
|
88
|
+
const v = spaces.slice(1, 4)
|
|
89
|
+
.map(x => Number.parseFloat(x));
|
|
90
|
+
normals.push(Vec3(...v));
|
|
91
|
+
}
|
|
92
|
+
if (type === "vt") {
|
|
93
|
+
const v = spaces.slice(1, 3)
|
|
94
|
+
.map(x => Number.parseFloat(x));
|
|
95
|
+
texture.push(Vec2(...v));
|
|
96
|
+
}
|
|
97
|
+
if (type === "f") {
|
|
98
|
+
// TODO
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
return new Mesh({ vertices, normals, texture, faces })
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
|
|
2
|
+
import { none, some } from "../Monads/Monads.js";
|
|
3
|
+
import Point from "./Point.js";
|
|
4
|
+
import Vec from "../Vector/Vector.js";
|
|
5
|
+
import { smin } from "../Utils/Math.js";
|
|
6
|
+
|
|
7
|
+
export default class NaiveScene {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.id2ElemMap = {};
|
|
10
|
+
this.sceneElements = [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
add(...elements) {
|
|
14
|
+
return this.addList(elements);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
addList(elements) {
|
|
18
|
+
for (let i = 0; i < elements.length; i++) {
|
|
19
|
+
const elem = elements[i];
|
|
20
|
+
const classes = [Point];
|
|
21
|
+
if (!classes.some((c) => elem instanceof c)) return this;
|
|
22
|
+
const { name } = elem;
|
|
23
|
+
this.id2ElemMap[name] = elem;
|
|
24
|
+
this.sceneElements.push(elem);
|
|
25
|
+
}
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
clear() {
|
|
30
|
+
this.id2ElemMap = {};
|
|
31
|
+
this.sceneElements = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getElements() {
|
|
35
|
+
return this.sceneElements;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
distanceToPoint(p) {
|
|
39
|
+
const elements = this.sceneElements;
|
|
40
|
+
let distance = Number.MAX_VALUE;
|
|
41
|
+
for (let i = 0; i < elements.length; i++) {
|
|
42
|
+
distance = smin(distance, elements[i].distanceToPoint(p));
|
|
43
|
+
}
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
estimateNormal(p) {
|
|
48
|
+
const epsilon = 1e-3;
|
|
49
|
+
const n = p.dim;
|
|
50
|
+
const grad = [];
|
|
51
|
+
const d = this.distanceToPoint(p);
|
|
52
|
+
for (let i = 0; i < n; i++) {
|
|
53
|
+
grad.push(this.distanceToPoint(p.add(Vec.e(n)(i).scale(epsilon))) - d);
|
|
54
|
+
}
|
|
55
|
+
return Vec.fromArray(grad).scale(Math.sign(d)).normalize();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interceptWith(ray) {
|
|
59
|
+
const points = this.sceneElements;
|
|
60
|
+
let closestDistance = Number.MAX_VALUE;
|
|
61
|
+
let closest = none();
|
|
62
|
+
for (let i = 0; i < points.length; i++) {
|
|
63
|
+
points[i].interceptWith(ray)
|
|
64
|
+
.map(([pos, normal]) => {
|
|
65
|
+
const distance = ray
|
|
66
|
+
.init
|
|
67
|
+
.sub(pos)
|
|
68
|
+
.length();
|
|
69
|
+
if (distance < closestDistance) {
|
|
70
|
+
closest = some([pos, normal]);
|
|
71
|
+
closestDistance = distance;
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
return closest;
|
|
76
|
+
}
|
|
77
|
+
}
|