@genocode/render 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +8 -2
- package/dist/geometry.d.ts +15 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +79 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/look.d.ts +39 -0
- package/dist/look.d.ts.map +1 -0
- package/dist/look.js +77 -0
- package/dist/look.js.map +1 -0
- package/dist/software.d.ts +17 -0
- package/dist/software.d.ts.map +1 -0
- package/dist/software.js +184 -0
- package/dist/software.js.map +1 -0
- package/dist/webgl.d.ts +26 -0
- package/dist/webgl.d.ts.map +1 -0
- package/dist/webgl.js +179 -0
- package/dist/webgl.js.map +1 -0
- package/package.json +35 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jan Piorek
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @genocode/render
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Draws [GenoCode](https://github.com/genocode-org/GenoCode) creatures, textures and backgrounds:
|
|
4
|
+
in the browser with three.js (`CreatureView`), or into an image without a browser (`rasterize`),
|
|
5
|
+
with the same shapes, camera and lights.
|
|
6
|
+
|
|
7
|
+
While the version is 0.x, any minor release may change the API.
|
|
8
|
+
|
|
9
|
+
MIT licensed.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LaidShape, ShapeName } from "@genocode/core";
|
|
2
|
+
import { BufferGeometry } from "three";
|
|
3
|
+
export type Detail = "high" | "low";
|
|
4
|
+
/**
|
|
5
|
+
* The geometry for a shape. Mirrored shapes need their triangles wound the other way, so that
|
|
6
|
+
* their outsides still face outwards after the mirroring in their placement.
|
|
7
|
+
*/
|
|
8
|
+
export declare function shapeGeometry(shape: ShapeName, mirrored: boolean, detail?: Detail): BufferGeometry;
|
|
9
|
+
export interface Bounds {
|
|
10
|
+
centre: [number, number, number];
|
|
11
|
+
radius: number;
|
|
12
|
+
}
|
|
13
|
+
/** A sphere around all the shapes, from the corners of each shape's 1×1×1 box. */
|
|
14
|
+
export declare function creatureBounds(shapes: readonly LaidShape[]): Bounds;
|
|
15
|
+
//# sourceMappingURL=geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAEL,cAAc,EAIf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAuCpC;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,OAAO,EACjB,MAAM,GAAE,MAAe,GACtB,cAAc,CAQhB;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAyBnE"}
|
package/dist/geometry.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// The six shapes, exactly as docs/LANGUAGE.md section 12 defines them: each fits a 1×1×1 box
|
|
2
|
+
// centred on the turtle, with its length along the heading (+z).
|
|
3
|
+
import { BoxGeometry, BufferGeometry, CylinderGeometry, SphereGeometry, TorusGeometry, } from "three";
|
|
4
|
+
function make(shape, detail) {
|
|
5
|
+
const high = detail === "high";
|
|
6
|
+
switch (shape) {
|
|
7
|
+
case "cube":
|
|
8
|
+
return new BoxGeometry(1, 1, 1);
|
|
9
|
+
case "ball":
|
|
10
|
+
return new SphereGeometry(0.5, high ? 32 : 16, high ? 20 : 10);
|
|
11
|
+
case "tube":
|
|
12
|
+
// three's cylinders run along y; turning them about x points them along +z.
|
|
13
|
+
return new CylinderGeometry(0.5, 0.5, 1, high ? 32 : 16, 1).rotateX(Math.PI / 2);
|
|
14
|
+
case "cone":
|
|
15
|
+
return new CylinderGeometry(0, 0.5, 1, high ? 32 : 16, 1).rotateX(Math.PI / 2);
|
|
16
|
+
case "ring":
|
|
17
|
+
return new TorusGeometry(0.4, 0.1, high ? 12 : 8, high ? 48 : 24);
|
|
18
|
+
case "donut":
|
|
19
|
+
return new TorusGeometry(1 / 3, 1 / 6, high ? 16 : 10, high ? 48 : 24);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** The same geometry with each triangle's corners in the opposite order, for mirrored shapes. */
|
|
23
|
+
function flipWinding(g) {
|
|
24
|
+
const flipped = g.clone();
|
|
25
|
+
const index = flipped.getIndex();
|
|
26
|
+
if (index) {
|
|
27
|
+
const a = index.array;
|
|
28
|
+
for (let i = 0; i < a.length; i += 3) {
|
|
29
|
+
const t = a[i + 1];
|
|
30
|
+
a[i + 1] = a[i + 2];
|
|
31
|
+
a[i + 2] = t;
|
|
32
|
+
}
|
|
33
|
+
index.needsUpdate = true;
|
|
34
|
+
}
|
|
35
|
+
return flipped;
|
|
36
|
+
}
|
|
37
|
+
const cache = new Map();
|
|
38
|
+
/**
|
|
39
|
+
* The geometry for a shape. Mirrored shapes need their triangles wound the other way, so that
|
|
40
|
+
* their outsides still face outwards after the mirroring in their placement.
|
|
41
|
+
*/
|
|
42
|
+
export function shapeGeometry(shape, mirrored, detail = "high") {
|
|
43
|
+
const key = `${shape}/${mirrored}/${detail}`;
|
|
44
|
+
let g = cache.get(key);
|
|
45
|
+
if (!g) {
|
|
46
|
+
g = mirrored ? flipWinding(shapeGeometry(shape, false, detail)) : make(shape, detail);
|
|
47
|
+
cache.set(key, g);
|
|
48
|
+
}
|
|
49
|
+
return g;
|
|
50
|
+
}
|
|
51
|
+
/** A sphere around all the shapes, from the corners of each shape's 1×1×1 box. */
|
|
52
|
+
export function creatureBounds(shapes) {
|
|
53
|
+
if (shapes.length === 0)
|
|
54
|
+
return { centre: [0, 0, 0], radius: 1 };
|
|
55
|
+
const lo = [Infinity, Infinity, Infinity];
|
|
56
|
+
const hi = [-Infinity, -Infinity, -Infinity];
|
|
57
|
+
for (const s of shapes) {
|
|
58
|
+
const m = s.matrix;
|
|
59
|
+
for (const x of [-0.5, 0.5]) {
|
|
60
|
+
for (const y of [-0.5, 0.5]) {
|
|
61
|
+
for (const z of [-0.5, 0.5]) {
|
|
62
|
+
for (let i = 0; i < 3; i++) {
|
|
63
|
+
const v = m[i] * x + m[4 + i] * y + m[8 + i] * z + m[12 + i];
|
|
64
|
+
lo[i] = Math.min(lo[i], v);
|
|
65
|
+
hi[i] = Math.max(hi[i], v);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const centre = [
|
|
72
|
+
(lo[0] + hi[0]) / 2,
|
|
73
|
+
(lo[1] + hi[1]) / 2,
|
|
74
|
+
(lo[2] + hi[2]) / 2,
|
|
75
|
+
];
|
|
76
|
+
const radius = Math.max(1e-3, Math.hypot(hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]) / 2);
|
|
77
|
+
return { centre, radius };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { creatureBounds, shapeGeometry, type Bounds, type Detail } from "./geometry.js";
|
|
2
|
+
export { backgroundRamp, DEFAULT_BACKGROUND, FIELD_OF_VIEW, frameCamera, LIGHTS, type CameraPlacement, } from "./look.js";
|
|
3
|
+
export { rasterize, type Image, type RasterOptions } from "./software.js";
|
|
4
|
+
export { CreatureView } from "./webgl.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AACxF,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,MAAM,EACN,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,SAAS,EAAE,KAAK,KAAK,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Draws GenoCode creatures: in the browser with three.js (CreatureView), or into an image without
|
|
2
|
+
// a browser (rasterize), with the same shapes, camera and lights.
|
|
3
|
+
export { creatureBounds, shapeGeometry } from "./geometry.js";
|
|
4
|
+
export { backgroundRamp, DEFAULT_BACKGROUND, FIELD_OF_VIEW, frameCamera, LIGHTS, } from "./look.js";
|
|
5
|
+
export { rasterize } from "./software.js";
|
|
6
|
+
export { CreatureView } from "./webgl.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,kEAAkE;AAElE,OAAO,EAAE,cAAc,EAAE,aAAa,EAA4B,MAAM,eAAe,CAAC;AACxF,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,MAAM,GAEP,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,SAAS,EAAkC,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/look.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type Colour, type Value } from "@genocode/core";
|
|
2
|
+
import type { Bounds } from "./geometry.js";
|
|
3
|
+
export declare const FIELD_OF_VIEW = 40;
|
|
4
|
+
export interface CameraPlacement {
|
|
5
|
+
position: [number, number, number];
|
|
6
|
+
target: [number, number, number];
|
|
7
|
+
near: number;
|
|
8
|
+
far: number;
|
|
9
|
+
}
|
|
10
|
+
/** Looks at the creature's face (the turtle starts facing +z, towards the viewer), from a little above. */
|
|
11
|
+
export declare function frameCamera(bounds: Bounds, aspect: number): CameraPlacement;
|
|
12
|
+
/** Directions point towards the light, in world space. */
|
|
13
|
+
export declare const LIGHTS: {
|
|
14
|
+
ambient: number;
|
|
15
|
+
key: {
|
|
16
|
+
direction: [number, number, number];
|
|
17
|
+
strength: number;
|
|
18
|
+
};
|
|
19
|
+
fill: {
|
|
20
|
+
direction: [number, number, number];
|
|
21
|
+
strength: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/** Shininess (the specular exponent) for a shape's sharpness, 0–1. */
|
|
25
|
+
export declare function shininess(sharpness: number): number;
|
|
26
|
+
export type Rgb = [number, number, number];
|
|
27
|
+
/** The background when a creature has none: a dark blue, lighter towards the top. */
|
|
28
|
+
export declare const DEFAULT_BACKGROUND: {
|
|
29
|
+
bottom: Rgb;
|
|
30
|
+
top: Rgb;
|
|
31
|
+
};
|
|
32
|
+
export declare function colourRgb(c: Colour): Rgb;
|
|
33
|
+
/**
|
|
34
|
+
* Turns a background's fill into a vertical ramp of colours, sampled at `rows` points from the
|
|
35
|
+
* bottom (0) to the top (1). Patterns aren't drawn yet (roadmap phase 7), so they fall back to the
|
|
36
|
+
* default background tinted with their hue.
|
|
37
|
+
*/
|
|
38
|
+
export declare function backgroundRamp(fill: Value | undefined, rows: number): Rgb[];
|
|
39
|
+
//# sourceMappingURL=look.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"look.d.ts","sourceRoot":"","sources":["../src/look.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2GAA2G;AAC3G,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,CAY3E;AAED,0DAA0D;AAC1D,eAAO,MAAM,MAAM;IACjB,OAAO;IACP,GAAG;QAAI,SAAS;QAAwB,QAAQ;;IAChD,IAAI;QAAI,SAAS;QAA4B,QAAQ;;CACtD,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAOD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE3C,qFAAqF;AACrF,eAAO,MAAM,kBAAkB,EAAE;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,GAAG,EAAE,GAAG,CAAA;CAGvD,CAAC;AAEF,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAExC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,KAAK,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE,CAO3E"}
|
package/dist/look.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// What both renderers share, so a creature looks the same in the browser and in `genie render`:
|
|
2
|
+
// camera framing, lights, and how backgrounds are drawn.
|
|
3
|
+
import { sampleGradient, toRgb } from "@genocode/core";
|
|
4
|
+
export const FIELD_OF_VIEW = 40;
|
|
5
|
+
/** Looks at the creature's face (the turtle starts facing +z, towards the viewer), from a little above. */
|
|
6
|
+
export function frameCamera(bounds, aspect) {
|
|
7
|
+
const half = (FIELD_OF_VIEW * Math.PI) / 360;
|
|
8
|
+
// The narrower of the two directions decides how far back the camera goes.
|
|
9
|
+
const fit = Math.min(Math.sin(half), Math.sin(Math.atan(Math.tan(half) * aspect)));
|
|
10
|
+
const distance = (bounds.radius / fit) * 1.1;
|
|
11
|
+
const [x, y, z] = bounds.centre;
|
|
12
|
+
return {
|
|
13
|
+
position: [x, y + bounds.radius * 0.3, z + distance],
|
|
14
|
+
target: [x, y, z],
|
|
15
|
+
near: Math.max(distance - bounds.radius * 2, distance / 1000),
|
|
16
|
+
far: distance + bounds.radius * 4,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Directions point towards the light, in world space. */
|
|
20
|
+
export const LIGHTS = {
|
|
21
|
+
ambient: 0.35,
|
|
22
|
+
key: { direction: normalise([1, 2, 3]), strength: 0.85 },
|
|
23
|
+
fill: { direction: normalise([-2, -0.5, 1]), strength: 0.3 },
|
|
24
|
+
};
|
|
25
|
+
/** Shininess (the specular exponent) for a shape's sharpness, 0–1. */
|
|
26
|
+
export function shininess(sharpness) {
|
|
27
|
+
return 4 + sharpness * 124;
|
|
28
|
+
}
|
|
29
|
+
function normalise(v) {
|
|
30
|
+
const l = Math.hypot(...v);
|
|
31
|
+
return [v[0] / l, v[1] / l, v[2] / l];
|
|
32
|
+
}
|
|
33
|
+
/** The background when a creature has none: a dark blue, lighter towards the top. */
|
|
34
|
+
export const DEFAULT_BACKGROUND = {
|
|
35
|
+
bottom: [0.03, 0.04, 0.08],
|
|
36
|
+
top: [0.13, 0.16, 0.26],
|
|
37
|
+
};
|
|
38
|
+
export function colourRgb(c) {
|
|
39
|
+
return toRgb(c);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Turns a background's fill into a vertical ramp of colours, sampled at `rows` points from the
|
|
43
|
+
* bottom (0) to the top (1). Patterns aren't drawn yet (roadmap phase 7), so they fall back to the
|
|
44
|
+
* default background tinted with their hue.
|
|
45
|
+
*/
|
|
46
|
+
export function backgroundRamp(fill, rows) {
|
|
47
|
+
const out = [];
|
|
48
|
+
for (let i = 0; i < rows; i++) {
|
|
49
|
+
const t = rows === 1 ? 0 : i / (rows - 1);
|
|
50
|
+
out.push(backgroundAt(fill, t));
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
function mixRgb(a, b, t) {
|
|
55
|
+
return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t];
|
|
56
|
+
}
|
|
57
|
+
function backgroundAt(fill, t) {
|
|
58
|
+
const fallback = mixRgb(DEFAULT_BACKGROUND.bottom, DEFAULT_BACKGROUND.top, t);
|
|
59
|
+
if (fill === undefined || typeof fill !== "object")
|
|
60
|
+
return fallback;
|
|
61
|
+
switch (fill.type) {
|
|
62
|
+
case "colour":
|
|
63
|
+
return colourRgb(fill);
|
|
64
|
+
case "gradient":
|
|
65
|
+
// Blended in HSV, the short way round the hue circle, as the language defines.
|
|
66
|
+
return colourRgb(sampleGradient(fill, t));
|
|
67
|
+
case "pattern": {
|
|
68
|
+
if (fill.kind === null)
|
|
69
|
+
return fallback;
|
|
70
|
+
const tint = toRgb({ type: "colour", h: fill.hue, s: 0.6, v: 0.35, a: 1 });
|
|
71
|
+
return mixRgb(fallback, tint, 0.5 + 0.3 * t);
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
return fallback;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=look.js.map
|
package/dist/look.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"look.js","sourceRoot":"","sources":["../src/look.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type LaidShape, type Value } from "@genocode/core";
|
|
2
|
+
export interface RasterOptions {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
/** The background's fill (a colour, gradient or pattern); the default background if left out. */
|
|
6
|
+
background?: Value | undefined;
|
|
7
|
+
/** Samples per pixel along each side, for smoother edges. Default 2. */
|
|
8
|
+
supersample?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface Image {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
/** RGBA, 8 bits per channel, rows from the top. */
|
|
14
|
+
data: Uint8ClampedArray;
|
|
15
|
+
}
|
|
16
|
+
export declare function rasterize(shapes: readonly LaidShape[], options: RasterOptions): Image;
|
|
17
|
+
//# sourceMappingURL=software.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"software.d.ts","sourceRoot":"","sources":["../src/software.ts"],"names":[],"mappings":"AAGA,OAAO,EAAS,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAInE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,UAAU,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC/B,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,IAAI,EAAE,iBAAiB,CAAC;CACzB;AA2CD,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,KAAK,CAyIrF"}
|
package/dist/software.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// A small software renderer: draws a creature into an RGBA image without a browser, for
|
|
2
|
+
// `genie render`, thumbnails and tests. It uses the same shapes, camera and lights as the WebGL view.
|
|
3
|
+
import { toRgb } from "@genocode/core";
|
|
4
|
+
import { creatureBounds, shapeGeometry } from "./geometry.js";
|
|
5
|
+
import { backgroundRamp, FIELD_OF_VIEW, frameCamera, LIGHTS, shininess } from "./look.js";
|
|
6
|
+
function sub(a, b) {
|
|
7
|
+
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
8
|
+
}
|
|
9
|
+
function dot(a, b) {
|
|
10
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
11
|
+
}
|
|
12
|
+
function cross(a, b) {
|
|
13
|
+
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
14
|
+
}
|
|
15
|
+
function normalise(a) {
|
|
16
|
+
const l = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
17
|
+
return [a[0] / l, a[1] / l, a[2] / l];
|
|
18
|
+
}
|
|
19
|
+
/** The inverse transpose of a placement's 3×3 part, which carries normals. Row-major result. */
|
|
20
|
+
function normalMatrix(m) {
|
|
21
|
+
// Columns of the 3×3 part.
|
|
22
|
+
const a = [m[0], m[1], m[2]];
|
|
23
|
+
const b = [m[4], m[5], m[6]];
|
|
24
|
+
const c = [m[8], m[9], m[10]];
|
|
25
|
+
const bc = cross(b, c);
|
|
26
|
+
const ca = cross(c, a);
|
|
27
|
+
const ab = cross(a, b);
|
|
28
|
+
const det = dot(a, bc);
|
|
29
|
+
if (det === 0 || !Number.isFinite(det))
|
|
30
|
+
return undefined;
|
|
31
|
+
// The inverse's rows are bc, ca, ab over det; its transpose's columns are those, i.e. rows of N.
|
|
32
|
+
return [
|
|
33
|
+
bc[0] / det,
|
|
34
|
+
ca[0] / det,
|
|
35
|
+
ab[0] / det,
|
|
36
|
+
bc[1] / det,
|
|
37
|
+
ca[1] / det,
|
|
38
|
+
ab[1] / det,
|
|
39
|
+
bc[2] / det,
|
|
40
|
+
ca[2] / det,
|
|
41
|
+
ab[2] / det,
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
export function rasterize(shapes, options) {
|
|
45
|
+
const ss = Math.max(1, Math.round(options.supersample ?? 2));
|
|
46
|
+
const W = options.width * ss;
|
|
47
|
+
const H = options.height * ss;
|
|
48
|
+
const colour = new Float32Array(W * H * 3);
|
|
49
|
+
const depth = new Float32Array(W * H); // 1 / distance; bigger is nearer, 0 is empty
|
|
50
|
+
const ramp = backgroundRamp(options.background, H);
|
|
51
|
+
for (let y = 0; y < H; y++) {
|
|
52
|
+
const c = ramp[H - 1 - y];
|
|
53
|
+
for (let x = 0; x < W; x++)
|
|
54
|
+
colour.set(c, (y * W + x) * 3);
|
|
55
|
+
}
|
|
56
|
+
const cam = frameCamera(creatureBounds(shapes), options.width / options.height);
|
|
57
|
+
const eye = cam.position;
|
|
58
|
+
const forward = normalise(sub(cam.target, eye));
|
|
59
|
+
const right = normalise(cross(forward, [0, 1, 0]));
|
|
60
|
+
const up = cross(right, forward);
|
|
61
|
+
const focal = H / 2 / Math.tan((FIELD_OF_VIEW * Math.PI) / 360);
|
|
62
|
+
const lights = [LIGHTS.key, LIGHTS.fill];
|
|
63
|
+
const opaque = shapes.filter((s) => s.colour.a >= 0.999);
|
|
64
|
+
const seeThrough = shapes
|
|
65
|
+
.filter((s) => s.colour.a < 0.999 && s.colour.a > 0)
|
|
66
|
+
.map((s) => ({ s, d: dot(sub([s.matrix[12], s.matrix[13], s.matrix[14]], eye), forward) }))
|
|
67
|
+
.sort((p, q) => q.d - p.d)
|
|
68
|
+
.map((p) => p.s);
|
|
69
|
+
for (const shape of [...opaque, ...seeThrough]) {
|
|
70
|
+
const m = shape.matrix;
|
|
71
|
+
const nm = normalMatrix(m);
|
|
72
|
+
if (!nm)
|
|
73
|
+
continue;
|
|
74
|
+
const geometry = shapeGeometry(shape.shape, false, "low");
|
|
75
|
+
const pos = geometry.getAttribute("position").array;
|
|
76
|
+
const nor = geometry.getAttribute("normal").array;
|
|
77
|
+
const index = geometry.getIndex()?.array;
|
|
78
|
+
const count = pos.length / 3;
|
|
79
|
+
const base = toRgb(shape.colour);
|
|
80
|
+
const alpha = shape.colour.a;
|
|
81
|
+
const exponent = shininess(shape.sharpness);
|
|
82
|
+
// Per corner: screen x, screen y, 1/distance, and lit colour.
|
|
83
|
+
const sx = new Float32Array(count);
|
|
84
|
+
const sy = new Float32Array(count);
|
|
85
|
+
const iz = new Float32Array(count);
|
|
86
|
+
const lit = new Float32Array(count * 3);
|
|
87
|
+
for (let v = 0; v < count; v++) {
|
|
88
|
+
const px = pos[v * 3];
|
|
89
|
+
const py = pos[v * 3 + 1];
|
|
90
|
+
const pz = pos[v * 3 + 2];
|
|
91
|
+
const world = [
|
|
92
|
+
m[0] * px + m[4] * py + m[8] * pz + m[12],
|
|
93
|
+
m[1] * px + m[5] * py + m[9] * pz + m[13],
|
|
94
|
+
m[2] * px + m[6] * py + m[10] * pz + m[14],
|
|
95
|
+
];
|
|
96
|
+
const nx = nor[v * 3];
|
|
97
|
+
const ny = nor[v * 3 + 1];
|
|
98
|
+
const nz = nor[v * 3 + 2];
|
|
99
|
+
const n = normalise([
|
|
100
|
+
nm[0] * nx + nm[1] * ny + nm[2] * nz,
|
|
101
|
+
nm[3] * nx + nm[4] * ny + nm[5] * nz,
|
|
102
|
+
nm[6] * nx + nm[7] * ny + nm[8] * nz,
|
|
103
|
+
]);
|
|
104
|
+
const rel = sub(world, eye);
|
|
105
|
+
const dist = dot(rel, forward);
|
|
106
|
+
iz[v] = dist > cam.near * 0.5 ? 1 / dist : 0;
|
|
107
|
+
sx[v] = W / 2 + (dot(rel, right) / dist) * focal;
|
|
108
|
+
sy[v] = H / 2 - (dot(rel, up) / dist) * focal;
|
|
109
|
+
const toEye = normalise(sub(eye, world));
|
|
110
|
+
let diffuse = LIGHTS.ambient;
|
|
111
|
+
let specular = 0;
|
|
112
|
+
for (const l of lights) {
|
|
113
|
+
diffuse += l.strength * Math.max(0, dot(n, l.direction));
|
|
114
|
+
if (shape.shine > 0) {
|
|
115
|
+
const half = normalise([
|
|
116
|
+
l.direction[0] + toEye[0],
|
|
117
|
+
l.direction[1] + toEye[1],
|
|
118
|
+
l.direction[2] + toEye[2],
|
|
119
|
+
]);
|
|
120
|
+
specular += l.strength * shape.shine * Math.pow(Math.max(0, dot(n, half)), exponent);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (let k = 0; k < 3; k++)
|
|
124
|
+
lit[v * 3 + k] = base[k] * diffuse + specular;
|
|
125
|
+
}
|
|
126
|
+
const triangles = index ? index.length / 3 : count / 3;
|
|
127
|
+
for (let t = 0; t < triangles; t++) {
|
|
128
|
+
const a = index ? index[t * 3] : t * 3;
|
|
129
|
+
const b = index ? index[t * 3 + 1] : t * 3 + 1;
|
|
130
|
+
const c = index ? index[t * 3 + 2] : t * 3 + 2;
|
|
131
|
+
if (iz[a] === 0 || iz[b] === 0 || iz[c] === 0)
|
|
132
|
+
continue; // behind the camera
|
|
133
|
+
const area = (sx[b] - sx[a]) * (sy[c] - sy[a]) - (sy[b] - sy[a]) * (sx[c] - sx[a]);
|
|
134
|
+
if (area === 0 || !Number.isFinite(area))
|
|
135
|
+
continue;
|
|
136
|
+
const x0 = Math.max(0, Math.floor(Math.min(sx[a], sx[b], sx[c])));
|
|
137
|
+
const x1 = Math.min(W - 1, Math.ceil(Math.max(sx[a], sx[b], sx[c])));
|
|
138
|
+
const y0 = Math.max(0, Math.floor(Math.min(sy[a], sy[b], sy[c])));
|
|
139
|
+
const y1 = Math.min(H - 1, Math.ceil(Math.max(sy[a], sy[b], sy[c])));
|
|
140
|
+
for (let y = y0; y <= y1; y++) {
|
|
141
|
+
const py = y + 0.5;
|
|
142
|
+
for (let x = x0; x <= x1; x++) {
|
|
143
|
+
const px = x + 0.5;
|
|
144
|
+
const wa = ((sx[b] - px) * (sy[c] - py) - (sy[b] - py) * (sx[c] - px)) / area;
|
|
145
|
+
const wb = ((sx[c] - px) * (sy[a] - py) - (sy[c] - py) * (sx[a] - px)) / area;
|
|
146
|
+
const wc = 1 - wa - wb;
|
|
147
|
+
if (wa < 0 || wb < 0 || wc < 0)
|
|
148
|
+
continue;
|
|
149
|
+
const z = wa * iz[a] + wb * iz[b] + wc * iz[c];
|
|
150
|
+
const at = y * W + x;
|
|
151
|
+
if (z <= depth[at])
|
|
152
|
+
continue;
|
|
153
|
+
const ka = (wa * iz[a]) / z;
|
|
154
|
+
const kb = (wb * iz[b]) / z;
|
|
155
|
+
const kc = (wc * iz[c]) / z;
|
|
156
|
+
for (let k = 0; k < 3; k++) {
|
|
157
|
+
const value = ka * lit[a * 3 + k] + kb * lit[b * 3 + k] + kc * lit[c * 3 + k];
|
|
158
|
+
colour[at * 3 + k] =
|
|
159
|
+
alpha >= 0.999 ? value : colour[at * 3 + k] * (1 - alpha) + value * alpha;
|
|
160
|
+
}
|
|
161
|
+
if (alpha >= 0.999)
|
|
162
|
+
depth[at] = z;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const data = new Uint8ClampedArray(options.width * options.height * 4);
|
|
168
|
+
for (let y = 0; y < options.height; y++) {
|
|
169
|
+
for (let x = 0; x < options.width; x++) {
|
|
170
|
+
const out = (y * options.width + x) * 4;
|
|
171
|
+
for (let k = 0; k < 3; k++) {
|
|
172
|
+
let sum = 0;
|
|
173
|
+
for (let dy = 0; dy < ss; dy++) {
|
|
174
|
+
for (let dx = 0; dx < ss; dx++)
|
|
175
|
+
sum += colour[((y * ss + dy) * W + x * ss + dx) * 3 + k];
|
|
176
|
+
}
|
|
177
|
+
data[out + k] = Math.round(Math.min(1, Math.max(0, sum / (ss * ss))) * 255);
|
|
178
|
+
}
|
|
179
|
+
data[out + 3] = 255;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return { width: options.width, height: options.height, data };
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=software.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"software.js","sourceRoot":"","sources":["../src/software.ts"],"names":[],"mappings":"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"}
|
package/dist/webgl.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type LaidShape, type Value } from "@genocode/core";
|
|
2
|
+
import { PerspectiveCamera, WebGLRenderer } from "three";
|
|
3
|
+
export declare class CreatureView {
|
|
4
|
+
private readonly canvas;
|
|
5
|
+
readonly renderer: WebGLRenderer;
|
|
6
|
+
readonly camera: PerspectiveCamera;
|
|
7
|
+
private readonly scene;
|
|
8
|
+
private readonly creature;
|
|
9
|
+
private readonly controls;
|
|
10
|
+
private readonly opaque;
|
|
11
|
+
private readonly seeThrough;
|
|
12
|
+
private readonly resizeObserver;
|
|
13
|
+
private shapes;
|
|
14
|
+
private frameRequested;
|
|
15
|
+
constructor(canvas: HTMLCanvasElement);
|
|
16
|
+
/** Replaces the creature on show. With `keepView`, the camera stays where the viewer left it. */
|
|
17
|
+
setCreature(shapes: readonly LaidShape[], keepView?: boolean): void;
|
|
18
|
+
/** Shows a background's fill: a colour, a gradient, or (until patterns exist) a tinted default. */
|
|
19
|
+
setBackground(fill: Value | undefined): void;
|
|
20
|
+
/** Frames the whole creature, seen from the front and a little above. */
|
|
21
|
+
resetView(): void;
|
|
22
|
+
private resize;
|
|
23
|
+
private requestFrame;
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=webgl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../src/webgl.ts"],"names":[],"mappings":"AAGA,OAAO,EAAS,KAAK,SAAS,EAAkB,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAUL,iBAAiB,EAIjB,aAAa,EAEd,MAAM,OAAO,CAAC;AA2Cf,qBAAa,YAAY;IAYX,OAAO,CAAC,QAAQ,CAAC,MAAM;IAXnC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,MAAM,oBAAsD;IACrE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,cAAc,CAAS;IAE/B,YAA6B,MAAM,EAAE,iBAAiB,EAiBrD;IAED,iGAAiG;IACjG,WAAW,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,QAAQ,UAAQ,GAAG,IAAI,CAyChE;IAED,mGAAmG;IACnG,aAAa,CAAC,IAAI,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAmB3C;IAED,yEAAyE;IACzE,SAAS,IAAI,IAAI,CAahB;IAED,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,YAAY;IAWpB,OAAO,IAAI,IAAI,CAOd;CACF"}
|
package/dist/webgl.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// Shows a creature in the browser with three.js: one instanced mesh per kind of shape, with each
|
|
2
|
+
// shape's colour, alpha, shine and sharpness carried per instance.
|
|
3
|
+
import { toRgb } from "@genocode/core";
|
|
4
|
+
import { AmbientLight, CanvasTexture, Color, DirectionalLight, Group, InstancedBufferAttribute, InstancedMesh, Matrix4, MeshPhongMaterial, PerspectiveCamera, Scene, SRGBColorSpace, Vector3, WebGLRenderer, } from "three";
|
|
5
|
+
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
6
|
+
import { creatureBounds, shapeGeometry } from "./geometry.js";
|
|
7
|
+
import { backgroundRamp, FIELD_OF_VIEW, frameCamera, LIGHTS } from "./look.js";
|
|
8
|
+
/** Adds per-instance shine (x), sharpness (y) and alpha (z) to the Phong material. */
|
|
9
|
+
function addInstanceLook(shader) {
|
|
10
|
+
shader.vertexShader = shader.vertexShader
|
|
11
|
+
.replace("#include <common>", "#include <common>\nattribute vec3 instanceLook;\nvarying vec3 vLook;")
|
|
12
|
+
.replace("#include <begin_vertex>", "#include <begin_vertex>\nvLook = instanceLook;");
|
|
13
|
+
shader.fragmentShader = shader.fragmentShader
|
|
14
|
+
.replace("#include <common>", "#include <common>\nvarying vec3 vLook;")
|
|
15
|
+
.replace("#include <color_fragment>", "#include <color_fragment>\ndiffuseColor.a *= vLook.z;")
|
|
16
|
+
.replace("#include <lights_phong_fragment>", [
|
|
17
|
+
"BlinnPhongMaterial material;",
|
|
18
|
+
"material.diffuseColor = diffuseColor.rgb;",
|
|
19
|
+
"material.specularColor = vec3( vLook.x );",
|
|
20
|
+
"material.specularShininess = 4.0 + vLook.y * 124.0;",
|
|
21
|
+
"material.specularStrength = 1.0;",
|
|
22
|
+
].join("\n"));
|
|
23
|
+
}
|
|
24
|
+
function makeMaterial(transparent) {
|
|
25
|
+
const material = new MeshPhongMaterial({
|
|
26
|
+
color: 0xffffff,
|
|
27
|
+
transparent,
|
|
28
|
+
depthWrite: !transparent,
|
|
29
|
+
});
|
|
30
|
+
material.onBeforeCompile = addInstanceLook;
|
|
31
|
+
// Keeps three from sharing the compiled program with plain Phong materials.
|
|
32
|
+
material.customProgramCacheKey = () => "genocode-instance-look";
|
|
33
|
+
return material;
|
|
34
|
+
}
|
|
35
|
+
/** Light strengths in three are scaled by π compared with the software renderer's. */
|
|
36
|
+
const LIGHT_SCALE = Math.PI;
|
|
37
|
+
export class CreatureView {
|
|
38
|
+
canvas;
|
|
39
|
+
renderer;
|
|
40
|
+
camera = new PerspectiveCamera(FIELD_OF_VIEW, 1, 0.1, 1000);
|
|
41
|
+
scene = new Scene();
|
|
42
|
+
creature = new Group();
|
|
43
|
+
controls;
|
|
44
|
+
opaque = makeMaterial(false);
|
|
45
|
+
seeThrough = makeMaterial(true);
|
|
46
|
+
resizeObserver;
|
|
47
|
+
shapes = [];
|
|
48
|
+
frameRequested = false;
|
|
49
|
+
constructor(canvas) {
|
|
50
|
+
this.canvas = canvas;
|
|
51
|
+
this.renderer = new WebGLRenderer({ canvas, antialias: true, preserveDrawingBuffer: true });
|
|
52
|
+
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
53
|
+
this.scene.add(this.creature);
|
|
54
|
+
this.scene.add(new AmbientLight(0xffffff, LIGHTS.ambient * LIGHT_SCALE));
|
|
55
|
+
for (const l of [LIGHTS.key, LIGHTS.fill]) {
|
|
56
|
+
const light = new DirectionalLight(0xffffff, l.strength * LIGHT_SCALE);
|
|
57
|
+
light.position.set(...l.direction);
|
|
58
|
+
this.scene.add(light);
|
|
59
|
+
}
|
|
60
|
+
this.controls = new OrbitControls(this.camera, canvas);
|
|
61
|
+
this.controls.enableDamping = true;
|
|
62
|
+
this.controls.addEventListener("change", () => this.requestFrame());
|
|
63
|
+
this.resizeObserver = new ResizeObserver(() => this.resize());
|
|
64
|
+
this.resizeObserver.observe(canvas);
|
|
65
|
+
this.setBackground(undefined);
|
|
66
|
+
this.resize();
|
|
67
|
+
}
|
|
68
|
+
/** Replaces the creature on show. With `keepView`, the camera stays where the viewer left it. */
|
|
69
|
+
setCreature(shapes, keepView = false) {
|
|
70
|
+
for (const child of [...this.creature.children]) {
|
|
71
|
+
this.creature.remove(child);
|
|
72
|
+
const mesh = child;
|
|
73
|
+
mesh.geometry.dispose(); // each mesh has its own copy, carrying its instance attributes
|
|
74
|
+
mesh.dispose();
|
|
75
|
+
}
|
|
76
|
+
this.shapes = shapes;
|
|
77
|
+
const groups = new Map();
|
|
78
|
+
for (const s of shapes) {
|
|
79
|
+
if (s.colour.a <= 0)
|
|
80
|
+
continue;
|
|
81
|
+
const key = `${s.shape}/${s.mirrored}/${s.colour.a < 0.999}`;
|
|
82
|
+
if (!groups.has(key))
|
|
83
|
+
groups.set(key, []);
|
|
84
|
+
groups.get(key).push(s);
|
|
85
|
+
}
|
|
86
|
+
const matrix = new Matrix4();
|
|
87
|
+
const colour = new Color();
|
|
88
|
+
for (const [key, members] of groups) {
|
|
89
|
+
const [shape, mirrored, transparent] = key.split("/");
|
|
90
|
+
const mesh = new InstancedMesh(shapeGeometry(shape, mirrored === "true"), transparent === "true" ? this.seeThrough : this.opaque, members.length);
|
|
91
|
+
const look = new Float32Array(members.length * 3);
|
|
92
|
+
members.forEach((s, i) => {
|
|
93
|
+
matrix.fromArray(s.matrix);
|
|
94
|
+
mesh.setMatrixAt(i, matrix);
|
|
95
|
+
const [r, g, b] = toRgb(s.colour);
|
|
96
|
+
mesh.setColorAt(i, colour.setRGB(r, g, b, SRGBColorSpace));
|
|
97
|
+
look[i * 3] = s.shine;
|
|
98
|
+
look[i * 3 + 1] = s.sharpness;
|
|
99
|
+
look[i * 3 + 2] = s.colour.a;
|
|
100
|
+
});
|
|
101
|
+
mesh.geometry = mesh.geometry.clone();
|
|
102
|
+
mesh.geometry.setAttribute("instanceLook", new InstancedBufferAttribute(look, 3));
|
|
103
|
+
mesh.computeBoundingSphere();
|
|
104
|
+
this.creature.add(mesh);
|
|
105
|
+
}
|
|
106
|
+
if (!keepView)
|
|
107
|
+
this.resetView();
|
|
108
|
+
this.requestFrame();
|
|
109
|
+
}
|
|
110
|
+
/** Shows a background's fill: a colour, a gradient, or (until patterns exist) a tinted default. */
|
|
111
|
+
setBackground(fill) {
|
|
112
|
+
const rows = 256;
|
|
113
|
+
const ramp = backgroundRamp(fill, rows);
|
|
114
|
+
const canvas = document.createElement("canvas");
|
|
115
|
+
canvas.width = 1;
|
|
116
|
+
canvas.height = rows;
|
|
117
|
+
const ctx = canvas.getContext("2d");
|
|
118
|
+
const image = ctx.createImageData(1, rows);
|
|
119
|
+
ramp.forEach((c, i) => {
|
|
120
|
+
const row = rows - 1 - i;
|
|
121
|
+
image.data.set([c[0] * 255, c[1] * 255, c[2] * 255, 255], row * 4);
|
|
122
|
+
});
|
|
123
|
+
ctx.putImageData(image, 0, 0);
|
|
124
|
+
const texture = new CanvasTexture(canvas);
|
|
125
|
+
texture.colorSpace = SRGBColorSpace;
|
|
126
|
+
const old = this.scene.background;
|
|
127
|
+
this.scene.background = texture;
|
|
128
|
+
if (old && "dispose" in old)
|
|
129
|
+
old.dispose();
|
|
130
|
+
this.requestFrame();
|
|
131
|
+
}
|
|
132
|
+
/** Frames the whole creature, seen from the front and a little above. */
|
|
133
|
+
resetView() {
|
|
134
|
+
const aspect = this.canvas.clientWidth / Math.max(1, this.canvas.clientHeight);
|
|
135
|
+
const placement = frameCamera(creatureBounds(this.shapes), aspect);
|
|
136
|
+
this.camera.position.set(...placement.position);
|
|
137
|
+
this.camera.near = placement.near / 4;
|
|
138
|
+
this.camera.far = placement.far * 4;
|
|
139
|
+
this.camera.updateProjectionMatrix();
|
|
140
|
+
this.controls.target.set(...placement.target);
|
|
141
|
+
this.controls.minDistance = 0;
|
|
142
|
+
this.controls.maxDistance =
|
|
143
|
+
new Vector3(...placement.position).distanceTo(this.controls.target) * 8;
|
|
144
|
+
this.controls.update();
|
|
145
|
+
this.requestFrame();
|
|
146
|
+
}
|
|
147
|
+
resize() {
|
|
148
|
+
const w = this.canvas.clientWidth;
|
|
149
|
+
const h = this.canvas.clientHeight;
|
|
150
|
+
if (w === 0 || h === 0)
|
|
151
|
+
return;
|
|
152
|
+
this.renderer.setSize(w, h, false);
|
|
153
|
+
this.camera.aspect = w / h;
|
|
154
|
+
this.camera.updateProjectionMatrix();
|
|
155
|
+
this.requestFrame();
|
|
156
|
+
}
|
|
157
|
+
requestFrame() {
|
|
158
|
+
if (this.frameRequested)
|
|
159
|
+
return;
|
|
160
|
+
this.frameRequested = true;
|
|
161
|
+
requestAnimationFrame(() => {
|
|
162
|
+
this.frameRequested = false;
|
|
163
|
+
// Damping keeps the view moving for a moment after the mouse lets go.
|
|
164
|
+
if (this.controls.update())
|
|
165
|
+
this.requestFrame();
|
|
166
|
+
this.renderer.render(this.scene, this.camera);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
dispose() {
|
|
170
|
+
this.resizeObserver.disconnect();
|
|
171
|
+
this.controls.dispose();
|
|
172
|
+
for (const child of this.creature.children)
|
|
173
|
+
child.dispose();
|
|
174
|
+
this.opaque.dispose();
|
|
175
|
+
this.seeThrough.dispose();
|
|
176
|
+
this.renderer.dispose();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=webgl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl.js","sourceRoot":"","sources":["../src/webgl.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genocode/render",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Draws GenoCode creatures, textures and backgrounds with three.js.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/genocode-org/GenoCode.git",
|
|
9
|
+
"directory": "packages/render"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/genocode-org/GenoCode#readme",
|
|
12
|
+
"bugs": "https://github.com/genocode-org/GenoCode/issues",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@genocode/core": "0.1.0",
|
|
29
|
+
"three": "0.160.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/three": "0.160.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
}
|
|
37
|
+
}
|