From e00d4b2217024d2c6f89b9c583fd642c5c7f70d9 Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Sun, 17 Apr 2022 17:20:22 -0600 Subject: [PATCH 01/10] dev work --- docs/shaders.md | 19 +- examples/math/exponential.html | 85 +++++ examples/math/fieldlines.html | 359 ++++++++++++++++++++++ examples/math/helitorus.html | 184 +++++++++++ examples/math/hyperbolic.html | 155 ++++++++++ examples/sci/solarsystem.html | 31 +- examples/test/closed-line.html | 191 ++++++++++++ examples/test/closed-surface.html | 112 +++++++ examples/test/disc.html | 69 +++++ examples/test/partial-data.html | 121 ++++++++ examples/test/scatter.html | 62 ++++ src/context.js | 1 + src/docs/traits.js | 16 + src/index.js | 3 +- src/primitives/types/classes.js | 14 +- src/primitives/types/data/area.js | 7 + src/primitives/types/data/array.js | 5 +- src/primitives/types/data/buffer.js | 12 +- src/primitives/types/data/interval.js | 7 + src/primitives/types/data/latch.js | 48 +++ src/primitives/types/data/matrix.js | 8 +- src/primitives/types/data/scale.js | 1 + src/primitives/types/data/volume.js | 8 + src/primitives/types/data/voxel.js | 12 +- src/primitives/types/draw/axis.js | 8 +- src/primitives/types/draw/grid.js | 1 + src/primitives/types/draw/line.js | 5 +- src/primitives/types/draw/surface.js | 13 +- src/primitives/types/draw/vector.js | 5 +- src/primitives/types/helpers.js | 5 + src/primitives/types/operator/memo.js | 7 +- src/primitives/types/operator/operator.js | 4 +- src/primitives/types/operator/reverse.js | 64 ++++ src/primitives/types/present/track.js | 28 +- src/primitives/types/shader/shader.js | 14 +- src/primitives/types/traits.ts | 14 + src/primitives/types/transform/layer.js | 9 +- src/render/buffer/itembuffer.js | 3 + src/render/buffer/matrixbuffer.js | 1 + src/render/buffer/voxelbuffer.js | 2 + src/render/geometry/arrowgeometry.js | 9 +- src/util/pretty.js | 4 +- 42 files changed, 1665 insertions(+), 61 deletions(-) create mode 100644 examples/math/exponential.html create mode 100644 examples/math/fieldlines.html create mode 100644 examples/math/helitorus.html create mode 100644 examples/math/hyperbolic.html create mode 100644 examples/test/closed-line.html create mode 100644 examples/test/closed-surface.html create mode 100644 examples/test/disc.html create mode 100644 examples/test/partial-data.html create mode 100644 examples/test/scatter.html create mode 100644 src/primitives/types/data/latch.js create mode 100644 src/primitives/types/operator/reverse.js diff --git a/docs/shaders.md b/docs/shaders.md index e0d0d3ad..fcb80607 100644 --- a/docs/shaders.md +++ b/docs/shaders.md @@ -3,7 +3,7 @@ MathBox offloads most of its computations onto the GPU. As it assembles shaders on the fly, you can easily insert your own pieces of shader code. This is either as part of the usual vertex/fragment shader, or as a (re)sampler, which processes pure data, whether it's values, colors, sprites, weights, and so on. The `` node lets you add a GLSL shader you have written into Mathbox. The specific form of the shader will depend on the operator that uses the shader (``, ``, ``, `` or ``). By default, they will link up with a preceding ``, but you can select any shader node using the `shader` prop. - + The shader snippet it references will look something like this: -This samples both arrays and combines it with the third (implied) source. The order of the function definitions is matched with the array, their names are ignored. Note that external sources always have the signature `vec4 function(vec4)`, unlike implied sources, which depend on use (see below). +This samples both arrays and combines it with the third (implied) source. The +order of the function definitions is matched with the array, their names are +ignored. + +The callback signature depends on both indices and channels, mapping to +float/vec2/vec3/vec4. Indices specifies the type of the argument, channels the +return type. The example above is the default `{indices: 4, channels: 4}`: ## Resample @@ -58,7 +64,7 @@ The callback signature depends on both indices and channels, mapping to float/ve uniform vec3 dataSize; // dimensions uniform vec3 targetResolution; // uniform vec3 targetSize; // - + vec4 getSample(vec3 xyz); // indices 3, channels 4 vec4 getFramesSample(vec3 xyz) { // return getSample(xyz); // @@ -66,7 +72,7 @@ The callback signature depends on both indices and channels, mapping to float/ve Used e.g. as - + mathbox .matrix({ ... }) .shader({ @@ -103,7 +109,7 @@ Now you can take your array of source data, `#colors`, and retext your strings t + + + + + + + + diff --git a/examples/math/fieldlines.html b/examples/math/fieldlines.html new file mode 100644 index 00000000..6cad1edf --- /dev/null +++ b/examples/math/fieldlines.html @@ -0,0 +1,359 @@ + + + + + MathBox - Field Lines + + + + + + + + + diff --git a/examples/math/helitorus.html b/examples/math/helitorus.html new file mode 100644 index 00000000..e6043df4 --- /dev/null +++ b/examples/math/helitorus.html @@ -0,0 +1,184 @@ + + + + + MathBox - Helitoroidal Surface + + + + + + + + + diff --git a/examples/math/hyperbolic.html b/examples/math/hyperbolic.html new file mode 100644 index 00000000..3882c49c --- /dev/null +++ b/examples/math/hyperbolic.html @@ -0,0 +1,155 @@ + + + + + MathBox - Hyperbolic Curvature + + + + + + + + + diff --git a/examples/sci/solarsystem.html b/examples/sci/solarsystem.html index dc4c3a17..000579e7 100644 --- a/examples/sci/solarsystem.html +++ b/examples/sci/solarsystem.html @@ -11,6 +11,8 @@ type="text/javascript" src="https://cdn.jsdelivr.net/npm/three@0.137.0/examples/js/controls/OrbitControls.js" > + + - diff --git a/examples/test/closed-line.html b/examples/test/closed-line.html new file mode 100644 index 00000000..ef6c0e06 --- /dev/null +++ b/examples/test/closed-line.html @@ -0,0 +1,191 @@ + + + + + MathBox - Closed Line + + + + + + + + diff --git a/examples/test/closed-surface.html b/examples/test/closed-surface.html new file mode 100644 index 00000000..39c1628e --- /dev/null +++ b/examples/test/closed-surface.html @@ -0,0 +1,112 @@ + + + + + MathBox - Closed Surface + + + + + + + + diff --git a/examples/test/disc.html b/examples/test/disc.html new file mode 100644 index 00000000..d82a4e66 --- /dev/null +++ b/examples/test/disc.html @@ -0,0 +1,69 @@ + + + + + MathBox - Discs + + + + + + + + diff --git a/examples/test/partial-data.html b/examples/test/partial-data.html new file mode 100644 index 00000000..b860277d --- /dev/null +++ b/examples/test/partial-data.html @@ -0,0 +1,121 @@ + + + + + MathBox - Partially Filled Data + + + + + + + + diff --git a/examples/test/scatter.html b/examples/test/scatter.html new file mode 100644 index 00000000..a450cc3e --- /dev/null +++ b/examples/test/scatter.html @@ -0,0 +1,62 @@ + + + + + MathBox - Scatter + + + + + + + + diff --git a/src/context.js b/src/context.js index 66706653..d832b80b 100644 --- a/src/context.js +++ b/src/context.js @@ -31,6 +31,7 @@ export class Context { Util, DOM: Util.VDOM, }; + this.Version = "2.1.4"; } //------------------------------------------------------------------- diff --git a/src/docs/traits.js b/src/docs/traits.js index cb79f6cd..a25772d3 100644 --- a/src/docs/traits.js +++ b/src/docs/traits.js @@ -12,6 +12,11 @@ export default { visible: ["Visibility for rendering", "bool", "true"], }, + latch: { + data: ["Data to monitor for changes", "nullable object", null], + deep: ["Do deep value comparison", "boolean", true], + }, + unit: { scale: [ "(Vertical) Reference scale of viewport in pixels", @@ -31,6 +36,7 @@ export default { span: { range: ["Range on axis", "vec2", "[-1, 1]"], }, + view: { range: [ "4D range in view", @@ -233,6 +239,7 @@ export default { mesh: { fill: ["Fill mesh", "bool", true], shaded: ["Shade mesh", "bool", false], + normals: ["Normals data source", "nullable select", "null", "#normals"], map: ["Texture map source", "nullable select", "null", '"#map"'], lineBias: ["Z-Bias for lines on fill", "number", 5], }, @@ -318,6 +325,8 @@ export default { "null", '["#pressure", "#divergence"]', ], + indices: ["Source indices", "number", 4], + channels: ["Source channels", "number", 4], language: ["Shader language", "string", '"glsl"'], code: ["Shader code", "string", '""'], uniforms: [ @@ -379,6 +388,13 @@ export default { height: ["Repeat height", "number", "1"], depth: ["Repeat depth", "number", "1"], }, + reverse: { + items: ["Reverse items", "boolean", "false"], + width: ["Reverse width", "boolean", "false"], + height: ["Reverse height", "boolean", "false"], + depth: ["Reverse depth", "boolean", "false"], + }, + slice: { items: [ "Slice from, to items (excluding to)", diff --git a/src/index.js b/src/index.js index 1715d4fc..167f4c15 100644 --- a/src/index.js +++ b/src/index.js @@ -23,13 +23,12 @@ import * as util from "./util"; import { Bootstrap } from "threestrap/src/bootstrap.js"; import { Context as ctx } from "./context.js"; -export const version = "2.1.4"; - // Just because export const π = Math.PI; export const τ = π * 2; export const e = Math.E; export const Context = ctx; +export const version = ctx.version; export const Model = model; export const Overlay = overlay; export const Primitives = primitives; diff --git a/src/primitives/types/classes.js b/src/primitives/types/classes.js index 4adee031..89cddd82 100644 --- a/src/primitives/types/classes.js +++ b/src/primitives/types/classes.js @@ -1,7 +1,16 @@ /* eslint-disable sort-imports */ import { Group, Inherit, Root, Unit } from "./base"; import { Camera } from "./camera"; -import { Area, Array_, Interval, Matrix, Scale, Volume, Voxel } from "./data"; +import { + Area, + Array_, + Interval, + Latch, + Matrix, + Scale, + Volume, + Voxel, +} from "./data"; import { Axis, Face, @@ -33,6 +42,7 @@ import { Readback, Repeat, Resample, + Reverse, Slice, Split, Spread, @@ -87,6 +97,7 @@ export const Classes = { voxel: Voxel, volume: Volume, scale: Scale, + latch: Latch, html: HTML, dom: DOM, @@ -104,6 +115,7 @@ export const Classes = { readback: Readback, resample: Resample, repeat: Repeat, + reverse: Reverse, swizzle: Swizzle, spread: Spread, split: Split, diff --git a/src/primitives/types/data/area.js b/src/primitives/types/data/area.js index 5e5f9da8..e9738895 100644 --- a/src/primitives/types/data/area.js +++ b/src/primitives/types/data/area.js @@ -107,5 +107,12 @@ export class Area extends Matrix { super.unmake(); return this._helpers.span.unmake(); } + + change(changed, touched, init) { + super.change(changed, touched, init); + if (touched["x"] || touched["y"]) { + this.updateSpan(); + } + } } Area.initClass(); diff --git a/src/primitives/types/data/array.js b/src/primitives/types/data/array.js index fde09928..c07e597f 100644 --- a/src/primitives/types/data/array.js +++ b/src/primitives/types/data/array.js @@ -151,6 +151,8 @@ export class Array_ extends Buffer { if (changed["array.width"]) { const { width, bufferWidth } = this.props; + this.spec.width = width; + if (width > bufferWidth) { return this.rebuild(); } @@ -183,6 +185,7 @@ export class Array_ extends Buffer { } const { data } = this.props; + let { width } = this.width; const { space, used } = this; const l = used.width; @@ -206,7 +209,7 @@ export class Array_ extends Buffer { } return this.buffer.update(); } else { - let width = this.spec.width || 1; + width = this.spec.width || 1; this.buffer.setActive(width); diff --git a/src/primitives/types/data/buffer.js b/src/primitives/types/data/buffer.js index 70b4537d..f4416be4 100644 --- a/src/primitives/types/data/buffer.js +++ b/src/primitives/types/data/buffer.js @@ -39,7 +39,7 @@ export class Buffer extends Data { make() { super.make(); - return (this.clockParent = this._inherit("clock")); + return (this.clockParent = this._inherit("latch")); } unmake() { @@ -71,7 +71,10 @@ export class Buffer extends Data { const { live, fps, hurry, limit, realtime, observe } = this.props; const filled = this.buffer.getFilled(); - if (!!filled && !live) { + if (filled && !live) { + return; + } + if (this.latchParent && !this.latchParent.isDirty) { return; } @@ -84,6 +87,11 @@ export class Buffer extends Data { const frame = 1 / fps; step = realtime && observe ? speed * frame : frame; + if (Math.abs(time.time - this.bufferTime) > time.step * limit) { + this.bufferTime = time.time; + this.bufferClock = time.clock; + } + this.bufferSlack = Math.min(limit / fps, slack + delta); this.bufferDelta = delta; this.bufferStep = step; diff --git a/src/primitives/types/data/interval.js b/src/primitives/types/data/interval.js index 0e55e5c4..c648143e 100644 --- a/src/primitives/types/data/interval.js +++ b/src/primitives/types/data/interval.js @@ -83,5 +83,12 @@ export class Interval extends Array_ { super.unmake(); return this._helpers.span.unmake(); } + + change(changed, touched, init) { + super.change(changed, touched, init); + if (touched["span"]) { + this.updateSpan(); + } + } } Interval.initClass(); diff --git a/src/primitives/types/data/latch.js b/src/primitives/types/data/latch.js new file mode 100644 index 00000000..d1a4ca71 --- /dev/null +++ b/src/primitives/types/data/latch.js @@ -0,0 +1,48 @@ +import { Parent } from "../base/parent.js"; + +function clone(x) { + return x && JSON.parse(JSON.stringify(x)); +} + +function deepEq(a, b) { + return JSON.stringify(a) == JSON.stringify(b); +} + +class Latch extends Parent { + static initClass() { + this.traits = ["node", "entity", "active", "latch"]; + } + + init() { + this.data = undefined; + this.isDirty = true; + } + + make() { + this._helpers.active.make(); + + this._listen("root", "root.update", function () { + if (this.isActive) { + this.update(); + } + }); + } + + unmake() { + this._helpers.active.unmake(); + this.data = undefined; + } + + swap() { + let { deep, data } = this.props; + const dirty = deep ? !deepEq(data, this.data) : data != this.data; + if (dirty) { + this.data = deep ? clone(data) : data; + } + } + + update() { + this.isDirty = this.swap(); + } +} +Latch.initClass(); diff --git a/src/primitives/types/data/matrix.js b/src/primitives/types/data/matrix.js index ad74cedd..6fb58d40 100644 --- a/src/primitives/types/data/matrix.js +++ b/src/primitives/types/data/matrix.js @@ -160,6 +160,8 @@ export class Matrix extends Buffer { if (changed["matrix.width"]) { const { width, bufferWidth } = this.props; + this.spec.width = width; + if (width > bufferWidth) { return this.rebuild(); } @@ -167,6 +169,8 @@ export class Matrix extends Buffer { if (changed["matrix.height"]) { const { height, bufferHeight } = this.props; + this.spec.height = height; + if (height > bufferHeight) { return this.rebuild(); } @@ -233,9 +237,9 @@ export class Matrix extends Buffer { const length = this.buffer.update(); used.width = _w = width; - used.height = Math.ceil(length / _w); + used.height = Math.min(height, Math.ceil(length / _w)); if (used.height === 1) { - return (used.width = length); + used.width = Math.min(width, length); } } }); diff --git a/src/primitives/types/data/scale.js b/src/primitives/types/data/scale.js index b201a148..6cbf67b3 100644 --- a/src/primitives/types/data/scale.js +++ b/src/primitives/types/data/scale.js @@ -107,6 +107,7 @@ export class Scale extends Source { touched["interval"] || touched["span"] || touched["scale"] || + touched["origin"] || init ) { return this.updateRanges(); diff --git a/src/primitives/types/data/volume.js b/src/primitives/types/data/volume.js index 2d1d6dca..c7256e94 100644 --- a/src/primitives/types/data/volume.js +++ b/src/primitives/types/data/volume.js @@ -136,5 +136,13 @@ export class Volume extends Voxel { super.unmake(); return this._helpers.span.unmake(); } + + change(changed, touched, init) { + super.change(changed, touched, init); + + if (touched["x"] || touched["y"] || touched["z"]) { + this.updateSpan(); + } + } } Volume.initClass(); diff --git a/src/primitives/types/data/voxel.js b/src/primitives/types/data/voxel.js index 26b43852..c9b53e95 100644 --- a/src/primitives/types/data/voxel.js +++ b/src/primitives/types/data/voxel.js @@ -153,6 +153,8 @@ export class Voxel extends Buffer { if (changed["voxel.width"]) { const { width, bufferWidth } = this.props; + this.spec.width = width; + if (width > bufferWidth) { return this.rebuild(); } @@ -160,6 +162,8 @@ export class Voxel extends Buffer { if (changed["voxel.height"]) { const { height, bufferHeight } = this.props; + this.spec.height = height; + if (height > bufferHeight) { return this.rebuild(); } @@ -167,6 +171,8 @@ export class Voxel extends Buffer { if (changed["voxel.depth"]) { const { depth, bufferDepth } = this.props; + this.spec.depth = depth; + if (depth > bufferDepth) { return this.rebuild(); } @@ -241,12 +247,12 @@ export class Voxel extends Buffer { used.width = _w = width; used.height = _h = height; - used.depth = Math.ceil(length / _w / _h); + used.depth = Math.min(depth, Math.ceil(length / _w / _h)); if (used.depth === 1) { - used.height = Math.ceil(length / _w); + used.height = Math.min(height, Math.ceil(length / _w)); if (used.height === 1) { - return (used.width = length); + used.width = Math.min(width, length); } } } diff --git a/src/primitives/types/draw/axis.js b/src/primitives/types/draw/axis.js index f9b90f46..6395c3bc 100644 --- a/src/primitives/types/draw/axis.js +++ b/src/primitives/types/draw/axis.js @@ -161,7 +161,13 @@ export class Axis extends Primitive { return this.rebuild(); } - if (touched["interval"] || touched["span"] || touched["view"] || init) { + if ( + touched["interval"] || + touched["span"] || + touched["view"] || + touched["origin"] || + init + ) { return this.updateRanges(); } } diff --git a/src/primitives/types/draw/grid.js b/src/primitives/types/draw/grid.js index 0d66d51d..f956a80d 100644 --- a/src/primitives/types/draw/grid.js +++ b/src/primitives/types/draw/grid.js @@ -180,6 +180,7 @@ export class Grid extends Primitive { touched["area"] || touched["grid"] || touched["view"] || + touched["origin"] || init ) { return this.updateRanges(); diff --git a/src/primitives/types/draw/line.js b/src/primitives/types/draw/line.js index 4f9da9c0..69c29d11 100644 --- a/src/primitives/types/draw/line.js +++ b/src/primitives/types/draw/line.js @@ -82,7 +82,7 @@ export class Line extends Primitive { const { start, end } = this.props; // Stroke style - const { stroke, join, proximity } = this.props; + const { stroke, join, proximity, closed } = this.props; this.proximity = proximity; // Fetch geometry dimensions @@ -123,6 +123,7 @@ export class Line extends Primitive { stroke, join, proximity, + closed, mask, material, }); @@ -140,6 +141,7 @@ export class Line extends Primitive { layers, position, color, + closed, mask, material, }) @@ -156,6 +158,7 @@ export class Line extends Primitive { layers, position, color, + closed, mask, material, }) diff --git a/src/primitives/types/draw/surface.js b/src/primitives/types/draw/surface.js index 04f8dfde..fa718151 100644 --- a/src/primitives/types/draw/surface.js +++ b/src/primitives/types/draw/surface.js @@ -73,10 +73,11 @@ export class Surface extends Primitive { make() { // Bind to attached data sources - let color; + let color, normal; this._helpers.bind.make([ { to: "geometry.points", trait: "source" }, { to: "geometry.colors", trait: "source" }, + { to: "mesh.normals", trait: "source" }, { to: "mesh.map", trait: "source" }, ]); @@ -126,8 +127,15 @@ export class Surface extends Primitive { const objects = []; this.proximity = proximity; + // Fetch normals + if (this.bind.normals != null) { + normal = this._shaders.shader(); + this.bind.normals.sourceShader(normal); + this._helpers.shade.normal(normal); + } + // Build color lookup - if (this.bind.colors) { + if (this.bind.colors != null) { color = this._shaders.shader(); this.bind.colors.sourceShader(color); } @@ -165,6 +173,7 @@ export class Surface extends Primitive { layers: items, position, color, + normal, zUnits: -zUnits, stroke, join, diff --git a/src/primitives/types/draw/vector.js b/src/primitives/types/draw/vector.js index 1a9c1560..a5c64b6f 100644 --- a/src/primitives/types/draw/vector.js +++ b/src/primitives/types/draw/vector.js @@ -82,7 +82,7 @@ export class Vector extends Primitive { const { start, end } = this.props; // Stroke style - const { stroke, join, proximity } = this.props; + const { stroke, join, proximity, closed } = this.props; this.proximity = proximity; // Fetch geometry dimensions @@ -130,6 +130,7 @@ export class Vector extends Primitive { stroke, join, proximity, + closed, mask, material, }); @@ -147,6 +148,7 @@ export class Vector extends Primitive { layers, position, color, + closed, mask, material, }) @@ -163,6 +165,7 @@ export class Vector extends Primitive { layers, position, color, + closed, mask, material, }) diff --git a/src/primitives/types/helpers.js b/src/primitives/types/helpers.js index a889dd1f..739fff36 100644 --- a/src/primitives/types/helpers.js +++ b/src/primitives/types/helpers.js @@ -255,6 +255,11 @@ const helpers = { return shader; }, + normal(shader) { + shader.pipe(UGLSL.swizzleVec4("xyz")); + return shader; + }, + map(shader) { if (!shader) { return shader; diff --git a/src/primitives/types/operator/memo.js b/src/primitives/types/operator/memo.js index f2f13343..78808b7e 100644 --- a/src/primitives/types/operator/memo.js +++ b/src/primitives/types/operator/memo.js @@ -78,15 +78,14 @@ export class Memo extends Operator { } unmake() { - super.unmake(); + this._helpers.active.unmake(); if (this.bind.source != null) { - this._helpers.active.unmake(); - this.memo.unadopt(this.compose); this.memo.dispose(); + this.memo = this.compose = null; - return (this.memo = this.compose = null); + super.unmake(); } } diff --git a/src/primitives/types/operator/operator.js b/src/primitives/types/operator/operator.js index ce862490..4cd53d69 100644 --- a/src/primitives/types/operator/operator.js +++ b/src/primitives/types/operator/operator.js @@ -39,7 +39,9 @@ export class Operator extends Source { } init() { - return (this.sourceSpec = [{ to: "operator.source", trait: "source" }]); + return (this.sourceSpec = [ + { to: "operator.source", trait: "source", optional: true }, + ]); } make() { diff --git a/src/primitives/types/operator/reverse.js b/src/primitives/types/operator/reverse.js new file mode 100644 index 00000000..581f7149 --- /dev/null +++ b/src/primitives/types/operator/reverse.js @@ -0,0 +1,64 @@ +// Operator = require './operator' +// Util = require '../../../util' + +// class Reverse extends Operator +// @traits = ['node', 'bind', 'operator', 'source', 'index', 'reverse'] + +// getDimensions: () -> @bind.source.getDimensions() +// getActiveDimensions: () -> @bind.source.getActiveDimensions() +// getFutureDimensions: () -> @bind.source.getFutureDimensions() +// getIndexDimensions: () -> @bind.source.getIndexDimensions() + +// sourceShader: (shader) -> +// shader.pipe 'reverse.position', @uniforms +// @bind.source.sourceShader shader + +// _resolveScale: (key, dims) -> +// range = @props[key] +// dim = dims[key] +// if range then -1 else 1 + +// _resolveOffset: (key, dims) -> +// range = @props[key] +// dim = dims[key] +// if range then dim - 1 else 0 + +// make: () -> +// super +// return unless @bind.source? + +// @uniforms = +// reverseScale: @_attributes.make @_types.vec4() +// reverseOffset: @_attributes.make @_types.vec4() + +// unmake: () -> +// super + +// resize: () -> +// return unless @bind.source? + +// dims = @bind.source.getActiveDimensions() + +// @uniforms.reverseScale.value.set( +// @_resolveScale('width', dims), +// @_resolveScale('height', dims), +// @_resolveScale('depth', dims), +// @_resolveScale('items', dims), +// ) + +// @uniforms.reverseOffset.value.set( +// @_resolveOffset('width', dims), +// @_resolveOffset('height', dims), +// @_resolveOffset('depth', dims), +// @_resolveOffset('items', dims), +// ) + +// super + +// change: (changed, touched, init) -> +// return @rebuild() if touched['operator'] + +// if touched['reverse'] +// @resize() + +// module.exports = Reverse diff --git a/src/primitives/types/present/track.js b/src/primitives/types/present/track.js index 352d6a5b..0c614bc7 100644 --- a/src/primitives/types/present/track.js +++ b/src/primitives/types/present/track.js @@ -132,14 +132,14 @@ export class Track extends Primitive { } if (step instanceof Array) { - // [props, expr] array + // [props, bind] array step = { key: +key, props: step[0] != null ? deepCopy(step[0]) : {}, - expr: step[1] != null ? deepCopy(step[1]) : {}, + bind: step[1] != null ? deepCopy(step[1]) : {}, }; } else { - if (step.key == null && !step.props && !step.expr) { + if (step.key == null && !step.props && !step.bind) { // Direct props object (iffy, but people will do this anyhow) step = { props: deepCopy(step) }; } else { @@ -152,8 +152,8 @@ export class Track extends Primitive { if (step.props == null) { step.props = {}; } - if (step.expr == null) { - step.expr = {}; + if (step.bind == null) { + step.bind = {}; } } @@ -195,8 +195,8 @@ export class Track extends Primitive { } for (key in script) { step = script[key]; - for (k in step.expr) { - v = step.expr[k]; + for (k in step.bind) { + v = step.bind[k]; props[k] = true; } } @@ -227,10 +227,10 @@ export class Track extends Primitive { v = object.validate(k, step.props[k] != null ? step.props[k] : v); props[k] = step.props[k] = v; - if (step.expr[k] != null && typeof step.expr[k] !== "function") { + if (step.bind[k] != null && typeof step.bind[k] !== "function") { console.warn(this.node.toMarkup()); - message = `${this.node.toString()} - Expression \`${ - step.expr[k] + message = `${this.node.toString()} - Bind expression \`${ + step.bind[k] }\` on property \`${k}\` is not a function`; throw new Error(message); } @@ -317,8 +317,8 @@ export class Track extends Primitive { // Create prop expression interpolator const live = (key) => { - const fromE = from.expr[key]; - const toE = to.expr[key]; + const fromE = from.bind[key]; + const toE = to.bind[key]; const fromP = from.props[key]; const toP = to.props[key]; @@ -412,12 +412,12 @@ export class Track extends Primitive { // Handle expr / props on both ends const expr = {}; - for (k in from.expr) { + for (k in from.bind) { if (expr[k] == null) { expr[k] = live(k); } } - for (k in to.expr) { + for (k in to.bind) { if (expr[k] == null) { expr[k] = live(k); } diff --git a/src/primitives/types/shader/shader.js b/src/primitives/types/shader/shader.js index c3fa5113..63e3cfe8 100644 --- a/src/primitives/types/shader/shader.js +++ b/src/primitives/types/shader/shader.js @@ -8,6 +8,8 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ + +import * as UGLSL from "../../../util/glsl.js"; import { Primitive } from "../../primitive.js"; export class Shader extends Primitive { @@ -104,7 +106,7 @@ export class Shader extends Primitive { if (uniforms == null) { uniforms = {}; } - const { code } = this.props; + const { code, indices, channels } = this.props; // Merge in prop attributes as uniforms for (k in this.node.attributes) { @@ -130,7 +132,15 @@ export class Shader extends Primitive { // Require sources if (this.bind.sources != null) { for (const source of Array.from(this.bind.sources)) { - s.require(source.sourceShader(this._shaders.shader())); + s.callback(); + if (indices != 4) { + s.pipe(UGLSL.extendVec(indices, 4)); + } + s.pipe(source.sourceShader(this._shaders.shader())); + if (channels != 4) { + s.pipe(UGLSL.truncateVec(4, channels)); + } + s.join(); } } diff --git a/src/primitives/types/traits.ts b/src/primitives/types/traits.ts index 155f6ab5..5fea6fc1 100644 --- a/src/primitives/types/traits.ts +++ b/src/primitives/types/traits.ts @@ -16,6 +16,11 @@ export const Traits = { visible: Types.bool(true), }, + latch: { + data: Types.nullable(Types.object()), + deep: Types.nullable(Types.bool(true)), + }, + unit: { scale: Types.nullable(Types.number()), fov: Types.nullable(Types.number()), @@ -209,6 +214,7 @@ export const Traits = { mesh: { fill: Types.bool(true), shaded: Types.bool(false), + normals: Types.nullable(Types.select()), map: Types.nullable(Types.select()), lineBias: Types.number(5), }, @@ -279,6 +285,8 @@ export const Traits = { shader: { sources: Types.nullable(Types.select()), + indices: Types.number(4), + channels: Types.number(4), language: Types.string("glsl"), code: Types.string(), uniforms: Types.nullable(Types.object()), @@ -337,6 +345,12 @@ export const Traits = { height: Types.nullable(Types.vec2()), depth: Types.nullable(Types.vec2()), }, + reverse: { + items: Types.bool(false), + width: Types.bool(false), + height: Types.bool(false), + depth: Types.bool(false), + }, lerp: { size: Types.mapping("absolute"), items: Types.nullable(Types.number()), diff --git a/src/primitives/types/transform/layer.js b/src/primitives/types/transform/layer.js index 8df1ad1b..32e78e7d 100644 --- a/src/primitives/types/transform/layer.js +++ b/src/primitives/types/transform/layer.js @@ -49,10 +49,15 @@ export class Layer extends Transform { // Fit x/y switch (fit) { case _enum.x: - this.uniforms.layerScale.value.set(pitch * aspect, pitch * aspect); + this.uniforms.layerScale.value.set( + pitch * aspect, + pitch * aspect, + 1, + 1 + ); break; case _enum.y: - this.uniforms.layerScale.value.set(pitch, pitch); + this.uniforms.layerScale.value.set(pitch, pitch, 1, 1); break; } diff --git a/src/render/buffer/itembuffer.js b/src/render/buffer/itembuffer.js index dd6dd9ca..ab1f1afc 100644 --- a/src/render/buffer/itembuffer.js +++ b/src/render/buffer/itembuffer.js @@ -63,12 +63,15 @@ export class ItemBuffer extends DataBuffer { repeat = callback(emit, i, j, k, l); if (++l === p - padW) { skip(padW); + m += padW; l = 0; if (++i === n - padX) { skip(p * padX); + m += p * padX; i = 0; if (++j === m - padY) { skip(p * n * padY); + m += p * n * padY; j = 0; k++; } diff --git a/src/render/buffer/matrixbuffer.js b/src/render/buffer/matrixbuffer.js index 77d23dfe..be723c79 100644 --- a/src/render/buffer/matrixbuffer.js +++ b/src/render/buffer/matrixbuffer.js @@ -77,6 +77,7 @@ export class MatrixBuffer extends DataBuffer { repeat = callback(emit, i, j); if (++i === n - pad) { skip(pad); + k += pad; i = 0; j++; } diff --git a/src/render/buffer/voxelbuffer.js b/src/render/buffer/voxelbuffer.js index 6f3ee15d..5365c009 100644 --- a/src/render/buffer/voxelbuffer.js +++ b/src/render/buffer/voxelbuffer.js @@ -58,9 +58,11 @@ export class VoxelBuffer extends DataBuffer { repeat = callback(emit, i, j, k); if (++i === n - padX) { skip(padX); + l += padX; i = 0; if (++j === m - padY) { skip(n * padY); + l += n * padY; j = 0; k++; } diff --git a/src/render/geometry/arrowgeometry.js b/src/render/geometry/arrowgeometry.js index 708ead42..a03241f3 100644 --- a/src/render/geometry/arrowgeometry.js +++ b/src/render/geometry/arrowgeometry.js @@ -23,7 +23,7 @@ Cones to attach as arrowheads on line strips export class ArrowGeometry extends ClipGeometry { constructor(options) { - let anchor, flip, k, layers, ribbons, samples, sides, strips; + let anchor, flip, closed, k, layers, ribbons, samples, sides, strips; let asc, end; super(options); @@ -35,8 +35,13 @@ export class ArrowGeometry extends ClipGeometry { this.ribbons = ribbons = +options.ribbons || 1; this.layers = layers = +options.layers || 1; this.flip = flip = options.flip != null ? options.flip : false; + this.closed = closed = options.closed != null ? options.closed : false; this.anchor = anchor = - options.anchor != null ? options.anchor : flip ? 0 : samples - 1; + options.anchor != null + ? options.anchor + : flip || closed + ? 0 + : samples - 1; const arrows = strips * ribbons * layers; const points = (sides + 2) * arrows; diff --git a/src/util/pretty.js b/src/util/pretty.js index ae35e86f..617a86fd 100644 --- a/src/util/pretty.js +++ b/src/util/pretty.js @@ -262,9 +262,9 @@ const prettyJSXPair = (function () { } else { `${v}`; } - v = v.replace(/^function (\([^)]+\))/, "$1 =>"); + v = v.replace(/^function (\([^)]*\))/, "$1 =>"); return (v = v.replace( - /^(\([^)]+\)) =>\s*{\s*return\s*([^}]+)\s*;\s*}/, + /^(\([^)]*\)) =>\s*{\s*return\s*([^}]+)\s*;\s*}/, "$1 => $2" )); case "number": From 459dfc674a3a9010639e62c5bccc5916fe907a7f Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 05:38:39 -0600 Subject: [PATCH 02/10] final code changes --- src/primitives/types/data/latch.js | 2 +- src/render/geometry/arrowgeometry.js | 7 +- src/render/geometry/linegeometry.js | 49 ++++--------- src/render/geometry/surfacegeometry.js | 46 ++---------- src/render/meshes/arrow.js | 8 +- src/render/meshes/base.js | 32 +++++++- src/render/meshes/line.js | 4 + src/render/meshes/sprite.js | 2 +- src/render/meshes/surface.js | 33 ++++++--- src/shaders/glsl/arrow.position.js | 33 +++++---- src/shaders/glsl/layer.position.js | 2 + src/shaders/glsl/line.position.js | 71 ++++++++++++------ src/shaders/glsl/mesh.fragment.color.js | 1 + src/shaders/glsl/point.position.js | 16 +++- src/shaders/glsl/project.position.js | 12 ++- src/shaders/glsl/reverse.position.js | 6 ++ src/shaders/glsl/surface.position.js | 8 ++ src/shaders/glsl/surface.position.normal.js | 50 +++---------- src/shaders/glsl/surface.position.shaded.js | 81 +++++++++++++++++++++ 19 files changed, 286 insertions(+), 177 deletions(-) create mode 100644 src/shaders/glsl/reverse.position.js create mode 100644 src/shaders/glsl/surface.position.shaded.js diff --git a/src/primitives/types/data/latch.js b/src/primitives/types/data/latch.js index d1a4ca71..6281b067 100644 --- a/src/primitives/types/data/latch.js +++ b/src/primitives/types/data/latch.js @@ -34,7 +34,7 @@ class Latch extends Parent { } swap() { - let { deep, data } = this.props; + const { deep, data } = this.props; const dirty = deep ? !deepEq(data, this.data) : data != this.data; if (dirty) { this.data = deep ? clone(data) : data; diff --git a/src/render/geometry/arrowgeometry.js b/src/render/geometry/arrowgeometry.js index a03241f3..07015a70 100644 --- a/src/render/geometry/arrowgeometry.js +++ b/src/render/geometry/arrowgeometry.js @@ -107,9 +107,8 @@ export class ArrowGeometry extends ClipGeometry { base += sides + 1; } - const step = flip ? 1 : -1; - const far = flip ? samples - 1 : 0; - const near = anchor + step; + const near = flip ? 1 : closed ? samples - 1 : -1; + const far = flip && !closed ? samples - 1 : 0; const x = anchor; for ( @@ -172,7 +171,7 @@ export class ArrowGeometry extends ClipGeometry { this._clipGeometry(samples, strips, ribbons, layers); - if (samples > this.anchor) { + if (samples > 0) { const dims = [layers, ribbons, strips]; const maxs = [this.layers, this.ribbons, this.strips]; quads = this.sides * this._reduce(dims, maxs); diff --git a/src/render/geometry/linegeometry.js b/src/render/geometry/linegeometry.js index 71bf03d6..c2735be4 100644 --- a/src/render/geometry/linegeometry.js +++ b/src/render/geometry/linegeometry.js @@ -52,10 +52,9 @@ export class LineGeometry extends ClipGeometry { const lines = samples - 1; this.joints = joints = detail - 1; - this.vertices = vertices = (lines - 1) * joints + samples; - this.segments = segments = (lines - 1) * joints + lines; + this.vertices = vertices = (lines - (closed ? 0 : 1)) * joints + samples; + this.segments = segments = (lines - (closed ? 0 : 1)) * joints + lines; - const wrap = samples - (closed ? 1 : 0); const points = vertices * strips * ribbons * layers * 2; const quads = segments * strips * ribbons * layers; const triangles = quads * 2; @@ -68,11 +67,7 @@ export class LineGeometry extends ClipGeometry { ); this.setAttribute( "line", - new BufferAttribute(new Float32Array(points * 2), 2) - ); - this.setAttribute( - "strip", - new BufferAttribute(new Float32Array(points * 2), 2) + new BufferAttribute(new Float32Array(points * 1), 1) ); if (detail > 1) { this.setAttribute( @@ -84,7 +79,6 @@ export class LineGeometry extends ClipGeometry { const index = this._emitter("index"); const position = this._emitter("position4"); const line = this._emitter("line"); - const strip = this._emitter("strip"); if (detail > 1) { joint = this._emitter("joint"); } @@ -157,20 +151,14 @@ export class LineGeometry extends ClipGeometry { asc6 ? i1 < end6 : i1 > end6; asc6 ? i1++ : i1--, x = i1 ) { - if (closed) { - x = x % wrap; - } edge = edger(x); if (edge !== 0) { position(x, y, z, l); position(x, y, z, l); - line(edge, 1); - line(edge, -1); - - strip(0, segments); - strip(0, segments); + line(1); + line(-1); joint(0.5); joint(0.5); @@ -183,11 +171,8 @@ export class LineGeometry extends ClipGeometry { position(x, y, z, l); position(x, y, z, l); - line(edge, 1); - line(edge, -1); - - strip(0, segments); - strip(0, segments); + line(1); + line(-1); joint(m / joints); joint(m / joints); @@ -222,19 +207,11 @@ export class LineGeometry extends ClipGeometry { asc11 ? j1 < end11 : j1 > end11; asc11 ? j1++ : j1--, x = j1 ) { - if (closed) { - x = x % wrap; - } - edge = edger(x); - position(x, y, z, l); position(x, y, z, l); - line(edge, 1); - line(edge, -1); - - strip(0, segments); - strip(0, segments); + line(1); + line(-1); } } } @@ -258,12 +235,12 @@ export class LineGeometry extends ClipGeometry { if (layers == null) { ({ layers } = this); } - let segments = Math.max(0, samples - (this.closed ? 0 : 1)); - const vertices = samples + (samples - 2) * this.joints; - segments = vertices - 1; + const vertices = samples + (samples - (this.closed ? 0 : 2)) * this.joints; + const segments = vertices - (this.closed ? 0 : 1); + samples += this.closed; - this._clipGeometry(vertices, strips, ribbons, layers); + this._clipGeometry(samples, strips, ribbons, layers); return this._clipOffsets( 6, segments, diff --git a/src/render/geometry/surfacegeometry.js b/src/render/geometry/surfacegeometry.js index 60017908..c98ea04c 100644 --- a/src/render/geometry/surfacegeometry.js +++ b/src/render/geometry/surfacegeometry.js @@ -51,9 +51,6 @@ export class SurfaceGeometry extends ClipGeometry { this.surfaces = surfaces = +options.surfaces || 1; this.layers = layers = +options.layers || 1; - const wrapX = width - (closedX ? 1 : 0); - const wrapY = height - (closedY ? 1 : 0); - this.segmentsX = segmentsX = Math.max(0, width - 1); this.segmentsY = segmentsY = Math.max(0, height - 1); @@ -107,30 +104,6 @@ export class SurfaceGeometry extends ClipGeometry { base += width; } - const edgerX = closedX - ? () => 0 - : function (x) { - if (x === 0) { - return -1; - } else if (x === segmentsX) { - return 1; - } else { - return 0; - } - }; - - const edgerY = closedY - ? () => 0 - : function (y) { - if (y === 0) { - return -1; - } else if (y === segmentsY) { - return 1; - } else { - return 0; - } - }; - for ( let l = 0, end3 = layers, asc3 = 0 <= end3; asc3 ? l < end3 : l > end3; @@ -146,24 +119,12 @@ export class SurfaceGeometry extends ClipGeometry { asc5 ? i1 < end5 : i1 > end5; asc5 ? i1++ : i1--, y = i1 ) { - if (closedY) { - y = y % wrapY; - } - const edgeY = edgerY(y); - for ( let j1 = 0, x = j1, end6 = width, asc6 = 0 <= end6; asc6 ? j1 < end6 : j1 > end6; asc6 ? j1++ : j1--, x = j1 ) { - if (closedX) { - x = x % wrapX; - } - const edgeX = edgerX(x); - position(x, y, z, l); - - surface(edgeX, edgeY); } } } @@ -175,10 +136,10 @@ export class SurfaceGeometry extends ClipGeometry { clip(width, height, surfaces, layers) { if (width == null) { - ({ width } = this); + width = this.width - this.closedX; } if (height == null) { - ({ height } = this); + height = this.height - this.closedY; } if (surfaces == null) { ({ surfaces } = this); @@ -186,6 +147,9 @@ export class SurfaceGeometry extends ClipGeometry { if (layers == null) { ({ layers } = this); } + width += this.closedX; + height += this.closedY; + const segmentsX = Math.max(0, width - 1); const segmentsY = Math.max(0, height - 1); diff --git a/src/render/meshes/arrow.js b/src/render/meshes/arrow.js index 5cbb2cb3..2809b786 100644 --- a/src/render/meshes/arrow.js +++ b/src/render/meshes/arrow.js @@ -35,11 +35,17 @@ export class Arrow extends Base { layers: options.layers, anchor: options.anchor, flip: options.flip, + closed: options.closed, }); this._adopt(uniforms); this._adopt(this.geometry.uniforms); + const defs = {}; + if (closed) { + defs["ARROW_CLOSED"] = ""; + } + const factory = shaders.material(); const v = factory.vertex; @@ -47,7 +53,7 @@ export class Arrow extends Base { v.pipe(this._vertexColor(color, mask)); v.require(this._vertexPosition(position, material, map, 1, stpq)); - v.pipe("arrow.position", this.uniforms); + v.pipe("arrow.position", this.uniforms, defs); v.pipe("project.position", this.uniforms); factory.fragment = f = this._fragmentColor( diff --git a/src/render/meshes/base.js b/src/render/meshes/base.js index 7d68e79d..3a5ccb74 100644 --- a/src/render/meshes/base.js +++ b/src/render/meshes/base.js @@ -53,6 +53,28 @@ export class Base extends Renderable { return null; } + _injectPreamble(preamble, code) { + const program = preamble + "\n" + code; + if (code.match(/#extension/)) { + return this._hoist(program); + } else { + return program; + } + } + + _hoist(code) { + const lines = code.split("\n"); + const out = []; + for (const line of Array.from(lines)) { + if (line.match(/^\s*#extension/)) { + out.unshift(line); + } else { + out.push(line); + } + } + return out.join("\n"); + } + _material(options) { const precision = this.renderer.capabilities.precision; @@ -88,9 +110,13 @@ uniform vec3 cameraPosition;\ (key) => (material[key] = options[key]) ); - material.vertexShader = [vertexPrefix, material.vertexShader].join("\n"); - material.fragmentShader = [fragmentPrefix, material.fragmentShader].join( - "\n" + material.vertexShader = this._injectPreamble( + vertexPrefix, + material.vertexShader + ); + material.fragmentShader = this._injectPreamble( + fragmentPrefix, + material.fragmentShader ); return material; } diff --git a/src/render/meshes/line.js b/src/render/meshes/line.js index 73865fb5..3ecff30c 100644 --- a/src/render/meshes/line.js +++ b/src/render/meshes/line.js @@ -31,6 +31,7 @@ export class Line extends Base { linear, clip, proximity, + closed, } = options; if (uniforms == null) { @@ -74,6 +75,9 @@ export class Line extends Base { if (detail > 1) { defs["LINE_JOIN_DETAIL"] = detail; } + if (closed) { + defs["LINE_CLOSED"] = ""; + } const v = factory.vertex; diff --git a/src/render/meshes/sprite.js b/src/render/meshes/sprite.js index 3e0cd498..98d58574 100644 --- a/src/render/meshes/sprite.js +++ b/src/render/meshes/sprite.js @@ -112,7 +112,7 @@ export class Sprite extends Base { this.geometry.dispose(); this.edgeMaterial.dispose(); this.fillMaterial.dispose(); - this.nreders = + this.renders = this.geometry = this.edgeMaterial = this.fillMaterial = diff --git a/src/render/meshes/surface.js b/src/render/meshes/surface.js index add200c3..ac52ccbe 100644 --- a/src/render/meshes/surface.js +++ b/src/render/meshes/surface.js @@ -14,12 +14,12 @@ import { SurfaceGeometry } from "../geometry/surfacegeometry.js"; export class Surface extends Base { constructor(renderer, shaders, options) { - let defs, f; + let f; super(renderer, shaders, options); let { uniforms, material } = options; - const { position, color, mask, map, combine, linear, stpq, intUV } = + const { position, color, normal, mask, map, combine, linear, stpq, intUV } = options; if (uniforms == null) { @@ -43,22 +43,35 @@ export class Surface extends Base { this._adopt(uniforms); this._adopt(this.geometry.uniforms); + const defs = {}; + if (options.closedX) { + defs.SURFACE_CLOSED_X = ""; + } + if (options.closedY) { + defs.SURFACE_CLOSED_Y = ""; + } + if (intUV) { + defs.POSITION_UV_INT = ""; + } + const factory = shaders.material(); const v = factory.vertex; - if (intUV) { - defs = { POSITION_UV_INT: "" }; - } - v.pipe(this._vertexColor(color, mask)); v.require(this._vertexPosition(position, material, map, 2, stpq)); - if (!material) { - v.pipe("surface.position", this.uniforms, defs); - } - if (material) { + + if (normal) { + v.require(normal); v.pipe("surface.position.normal", this.uniforms, defs); + } else { + if (!material) { + v.pipe("surface.position", this.uniforms, defs); + } + if (material) { + v.pipe("surface.position.shaded", this.uniforms, defs); + } } v.pipe("project.position", this.uniforms); diff --git a/src/shaders/glsl/arrow.position.js b/src/shaders/glsl/arrow.position.js index 49a2e3c1..f904ab24 100644 --- a/src/shaders/glsl/arrow.position.js +++ b/src/shaders/glsl/arrow.position.js @@ -14,13 +14,14 @@ attribute vec2 attach; // External vec3 getPosition(vec4 xyzw, float canonical); -void getArrowGeometry(vec4 xyzw, float near, float far, out vec3 left, out vec3 right, out vec3 start) { - right = getPosition(xyzw, 1.0); - left = getPosition(vec4(near, xyzw.yzw), 0.0); - start = getPosition(vec4(far, xyzw.yzw), 0.0); +void getArrowGeometry(vec4 xyzw, float near, float mid, float far, out vec3 left, out vec3 right, out vec3 middle, out vec3 start) { + right = getPosition(xyzw, 1.0); + left = getPosition(vec4(near, xyzw.yzw), 0.0); + middle = getPosition(vec4(mid, xyzw.yzw), 0.0); + start = getPosition(vec4(far, xyzw.yzw), 0.0); } -mat4 getArrowMatrix(vec3 left, vec3 right, vec3 start) { +mat4 getArrowMatrix(vec3 left, vec3 right, vec3 middle, vec3 start) { float depth = focusDepth; if (lineDepth < 1.0) { @@ -28,7 +29,7 @@ mat4 getArrowMatrix(vec3 left, vec3 right, vec3 start) { float z = max(0.00001, -right.z); depth = mix(z, focusDepth, lineDepth); } - + vec3 diff = left - right; float l = length(diff); if (l == 0.0) { @@ -42,16 +43,15 @@ mat4 getArrowMatrix(vec3 left, vec3 right, vec3 start) { vec3 t = normalize(diff); vec3 n = normalize(cross(t, t.yzx + vec3(.1, .2, .3))); vec3 b = cross(n, t); - + // Shrink arrows when vector gets too small // Approach linear scaling with cubic ease the smaller we get float size = arrowSize * lineWidth * worldUnit * depth * 1.25; - diff = right - start; - l = length(diff) * arrowSpace; + l = max(length(right - middle), length(middle - start)) * 2.0 * arrowSpace; float mini = clamp(1.0 - l / size * .333, 0.0, 1.0); float scale = 1.0 - mini * mini * mini; float range = size * scale; - + // Size to 2.5:1 ratio float rangeNB = range / 2.5; @@ -63,12 +63,15 @@ mat4 getArrowMatrix(vec3 left, vec3 right, vec3 start) { } vec3 getArrowPosition() { - vec3 left, right, start; - + vec3 left, right, middle, start; + + // Clip arrow position and attachment anchors to data vec4 p = min(geometryClip, position4); - - getArrowGeometry(p, attach.x, attach.y, left, right, start); - mat4 matrix = getArrowMatrix(left, right, start); + vec3 a = vec3(min(geometryClip.x, p.x + attach.x), geometryClip.x / 2.0, min(geometryClip.x, attach.y)); + + getArrowGeometry(p, a.x, a.y, a.z, left, right, middle, start); + mat4 matrix = getArrowMatrix(left, right, middle, start); + return (matrix * vec4(arrow.xyz, 1.0)).xyz; } diff --git a/src/shaders/glsl/layer.position.js b/src/shaders/glsl/layer.position.js index 00d894df..462817c8 100644 --- a/src/shaders/glsl/layer.position.js +++ b/src/shaders/glsl/layer.position.js @@ -1,6 +1,8 @@ export default /* glsl */ `uniform vec4 layerScale; uniform vec4 layerBias; +#define PROJECT_ORTHOGONAL + vec4 layerPosition(vec4 position, inout vec4 stpq) { return layerScale * position + layerBias; } diff --git a/src/shaders/glsl/line.position.js b/src/shaders/glsl/line.position.js index 6e5f12c8..b26263b4 100644 --- a/src/shaders/glsl/line.position.js +++ b/src/shaders/glsl/line.position.js @@ -8,8 +8,8 @@ uniform float focusDepth; uniform vec4 geometryClip; attribute vec4 position4; -// (Start/mid/end -1/0/1, top/bottom -1,1) -attribute vec2 line; +// (Top/bottom -1,1) +attribute float line; // 0...1 for round or bevel joins #ifdef LINE_JOIN_DETAIL @@ -48,21 +48,33 @@ varying vec2 vClipEnds; void clipEnds(vec4 xyzw, vec3 center, vec3 pos) { - // Sample end of line strip - vec4 xyzwE = vec4(strip.y, xyzw.yzw); - vec3 end = getPosition(xyzwE, 0.0); - // Sample start of line strip - vec4 xyzwS = vec4(strip.x, xyzw.yzw); + vec4 xyzwS = vec4(0.0, xyzw.yzw); vec3 start = getPosition(xyzwS, 0.0); + // Sample middle of line strip + vec4 xyzwM = vec4(geometryClip.x / 2.0, xyzw.yzw); + vec3 middle = getPosition(xyzwM, 0.0); + +#ifdef LINE_CLOSED + vec3 end = start; +#else + // Sample other end of line strip + vec4 xyzwE = vec4(geometryClip.x, xyzw.yzw); + vec3 end = getPosition(xyzwE, 0.0); +#endif + // Measure length - vec3 diff = end - start; - float l = length(diff) * clipSpace; + float l = max(length(end - middle), length(middle - start)) * clipSpace * 2.0; // Arrow length (=2.5x radius) float arrowSize = 1.25 * clipRange * lineWidth * worldUnit; +#ifdef LINE_CLOSED + // Clip around start/end + end = start; +#endif + vClipEnds = vec2(1.0); if (clipStyle.y > 0.0) { @@ -83,7 +95,7 @@ void clipEnds(vec4 xyzw, vec3 center, vec3 pos) { float invrange = 1.0 / (size * scale); // Clip end - diff = end - center; + vec3 diff = end - center; if(diff == vec3(0.0)) vClipEnds.x = -1.0; else { @@ -111,7 +123,7 @@ void clipEnds(vec4 xyzw, vec3 center, vec3 pos) { float invrange = 1.0 / (size * scale); // Clip start - diff = center - start; + vec3 diff = center - start; if(diff == vec3(0.0)) vClipEnds.y = -1.0; else { @@ -120,8 +132,6 @@ void clipEnds(vec4 xyzw, vec3 center, vec3 pos) { vClipEnds.y = d * invrange - 1.0; } } - - } #endif @@ -154,13 +164,22 @@ void fixCenter(inout vec3 left, inout vec3 center, inout vec3 right) { } } +vec4 wrapAround(vec4 xyzw) { +#ifdef LINE_CLOSED + float gx = geometryClip.x; + if (xyzw.x < 0.0) xyzw.x += gx; + if (xyzw.x >= gx) xyzw.x -= gx; +#endif + return xyzw; +} + // Sample the source data in an edge-aware manner void getLineGeometry(vec4 xyzw, float edge, out vec3 left, out vec3 center, out vec3 right) { vec4 delta = vec4(1.0, 0.0, 0.0, 0.0); - center = getPosition(xyzw, 1.0); - left = (edge > -0.5) ? getPosition(xyzw - delta, 0.0) : center; - right = (edge < 0.5) ? getPosition(xyzw + delta, 0.0) : center; + center = getPosition(xyzw, 1.0); + left = (edge > -0.5) ? getPosition(wrapAround(xyzw - delta), 0.0) : center; + right = (edge < 0.5) ? getPosition(wrapAround(xyzw + delta), 0.0) : center; } // Calculate the position for a vertex along the line, including joins @@ -301,14 +320,20 @@ vec3 getLineJoin(float edge, bool odd, vec3 left, vec3 center, vec3 right, float vec3 getLinePosition() { vec3 left, center, right, join; - // left/center/right - float edge = line.x; - // up/down - float offset = line.y; + // Up/down along segment + float offset = line; // Clip data vec4 p = min(geometryClip, position4); - edge += max(0.0, position4.x - geometryClip.x); + + // Left/center/right + float edge = 0.0; +#ifdef LINE_CLOSED + if (p.x == geometryClip.x) p.x = 0.0; +#else + if (p.x == geometryClip.x) edge = 1.0; + if (p.x == 0.0) edge = -1.0; +#endif // Get position + adjacent neighbours getLineGeometry(p, edge, left, center, right); @@ -337,7 +362,11 @@ vec3 getLinePosition() { width *= worldUnit; // Calculate line join +#ifdef LINE_CLOSED + join = getLineJoin(0.0, odd, left, center, right, width, offset, joint); +#else join = getLineJoin(edge, odd, left, center, right, width, offset, joint); +#endif vec3 pos = center + join * offset * width; #ifdef LINE_STROKE diff --git a/src/shaders/glsl/mesh.fragment.color.js b/src/shaders/glsl/mesh.fragment.color.js index 37eba14a..16d3858a 100644 --- a/src/shaders/glsl/mesh.fragment.color.js +++ b/src/shaders/glsl/mesh.fragment.color.js @@ -1,6 +1,7 @@ export default /* glsl */ `varying vec4 vColor; vec4 getColor() { + if (vColor.a <= 0.0) discard; return vColor; } `; diff --git a/src/shaders/glsl/point.position.js b/src/shaders/glsl/point.position.js index 9d2d8390..c9feebd9 100644 --- a/src/shaders/glsl/point.position.js +++ b/src/shaders/glsl/point.position.js @@ -19,7 +19,15 @@ float getPointSize(vec4 xyzw); vec3 getPosition(vec4 xyzw, float canonical); vec3 getPointPosition() { - vec4 p = min(geometryClip, position4); + // Discard out-of-range points by generating degenerate face + if ( + position4.x > geometryClip.x || + position4.y > geometryClip.y || + position4.z > geometryClip.z || + position4.w > geometryClip.w + ) return vec3(0.0, 0.0, 0.0); + vec4 p = position4; + vec3 center = getPosition(p, 1.0); // Depth blending @@ -27,13 +35,13 @@ vec3 getPointPosition() { // Workaround: set depth = 0 float z = -center.z; float depth = mix(z, focusDepth, pointDepth); - - // Match device/unit mapping + + // Match device/unit mapping // Sprite goes from -1..1, width = 2. float pointSize = getPointSize(p); float size = pointScale * pointSize * pixelUnit * .5; float depthSize = depth * size; - + // Pad sprite by half a pixel to make the anti-aliasing straddle the pixel edge // Note: pixelsize measures radius float pixelSize = .5 * (pointDepth > 0.0 ? depthSize / z : size); diff --git a/src/shaders/glsl/project.position.js b/src/shaders/glsl/project.position.js index 02bd830c..ee609d6b 100644 --- a/src/shaders/glsl/project.position.js +++ b/src/shaders/glsl/project.position.js @@ -2,17 +2,25 @@ export default /* glsl */ `uniform float styleZBias; uniform float styleZIndex; void setPosition(vec3 position) { + + #ifdef PROJECT_ORTHOGONAL + // Orthogonal projection with depth preservation around z = 1 + vec4 pos = projectionMatrix * vec4(position, 1.0); + pos.xy *= -position.z; + #else + // Normal perspective projection vec4 pos = projectionMatrix * vec4(position, 1.0); + #endif // Apply relative Z bias float bias = (1.0 - styleZBias / 32768.0); pos.z *= bias; - + // Apply large scale Z index changes if (styleZIndex > 0.0) { float z = pos.z / pos.w; pos.z = ((z + 1.0) / (styleZIndex + 1.0) - 1.0) * pos.w; } - + gl_Position = pos; }`; diff --git a/src/shaders/glsl/reverse.position.js b/src/shaders/glsl/reverse.position.js new file mode 100644 index 00000000..5ff69b07 --- /dev/null +++ b/src/shaders/glsl/reverse.position.js @@ -0,0 +1,6 @@ +export default /* glsl */ `uniform vec4 reverseScale; +uniform vec4 reverseOffset; + +vec4 getReverseOffset(vec4 xyzw) { + return xyzw * reverseScale + reverseOffset; +}`; diff --git a/src/shaders/glsl/surface.position.js b/src/shaders/glsl/surface.position.js index f873b45d..b8a1f4b1 100644 --- a/src/shaders/glsl/surface.position.js +++ b/src/shaders/glsl/surface.position.js @@ -9,6 +9,14 @@ vec3 getPosition(vec4 xyzw, float canonical); vec3 getSurfacePosition() { vec4 p = min(geometryClip, position4); + +#ifdef SURFACE_CLOSED_X + if (p.x == geometryClip.x) p.x = 0.0; +#endif +#ifdef SURFACE_CLOSED_Y + if (p.y == geometryClip.y) p.y = 0.0; +#endif + vec3 xyz = getPosition(p, 1.0); // Overwrite UVs diff --git a/src/shaders/glsl/surface.position.normal.js b/src/shaders/glsl/surface.position.normal.js index 12a08fcf..c7d41e31 100644 --- a/src/shaders/glsl/surface.position.normal.js +++ b/src/shaders/glsl/surface.position.normal.js @@ -2,55 +2,29 @@ export default /* glsl */ `uniform vec4 mapSize; uniform vec4 geometryResolution; uniform vec4 geometryClip; attribute vec4 position4; -attribute vec2 surface; // External vec3 getPosition(vec4 xyzw, float canonical); - -void getSurfaceGeometry(vec4 xyzw, float edgeX, float edgeY, out vec3 left, out vec3 center, out vec3 right, out vec3 up, out vec3 down) { - vec4 deltaX = vec4(1.0, 0.0, 0.0, 0.0); - vec4 deltaY = vec4(0.0, 1.0, 0.0, 0.0); - - /* - // high quality, 5 tap - center = getPosition(xyzw, 1.0); - left = (edgeX > -0.5) ? getPosition(xyzw - deltaX, 0.0) : center; - right = (edgeX < 0.5) ? getPosition(xyzw + deltaX, 0.0) : center; - down = (edgeY > -0.5) ? getPosition(xyzw - deltaY, 0.0) : center; - up = (edgeY < 0.5) ? getPosition(xyzw + deltaY, 0.0) : center; - */ - - // low quality, 3 tap - center = getPosition(xyzw, 1.0); - left = center; - down = center; - right = (edgeX < 0.5) ? getPosition(xyzw + deltaX, 0.0) : (2.0 * center - getPosition(xyzw - deltaX, 0.0)); - up = (edgeY < 0.5) ? getPosition(xyzw + deltaY, 0.0) : (2.0 * center - getPosition(xyzw - deltaY, 0.0)); -} - -vec3 getSurfaceNormal(vec3 left, vec3 center, vec3 right, vec3 up, vec3 down) { - vec3 dx = right - left; - vec3 dy = up - down; - vec3 n = cross(dy, dx); - if (length(n) > 0.0) { - return normalize(n); - } - return vec3(0.0, 1.0, 0.0); -} +vec3 getNormal(vec4 xyzw); varying vec3 vNormal; varying vec3 vLight; varying vec3 vPosition; vec3 getSurfacePositionNormal() { - vec3 left, center, right, up, down; vec4 p = min(geometryClip, position4); +#ifdef SURFACE_CLOSED_X + if (p.x == geometryClip.x) p.x = 0.0; +#endif +#ifdef SURFACE_CLOSED_Y + if (p.y == geometryClip.y) p.y = 0.0; +#endif - getSurfaceGeometry(p, surface.x, surface.y, left, center, right, up, down); - vNormal = getSurfaceNormal(left, center, right, up, down); - vLight = normalize((viewMatrix * vec4(1.0, 2.0, 2.0, 0.0)).xyz); // hardcoded directional light - vPosition = -center; + vec3 center = getPosition(p, 1.0); + vNormal = normalMatrix * normalize(getNormal(p)); + vLight = normalize((viewMatrix * vec4(1.0, 2.0, 2.0, 0.0)).xyz); // hardcoded directional light + vPosition = -center; #ifdef POSITION_UV #ifdef POSITION_UV_INT @@ -59,7 +33,7 @@ vec3 getSurfacePositionNormal() { vUV = position4.xy * geometryResolution.xy; #endif #endif - + return center; } `; diff --git a/src/shaders/glsl/surface.position.shaded.js b/src/shaders/glsl/surface.position.shaded.js new file mode 100644 index 00000000..8ee59388 --- /dev/null +++ b/src/shaders/glsl/surface.position.shaded.js @@ -0,0 +1,81 @@ +export default /* glsl */ `uniform vec4 mapSize; +uniform vec4 geometryResolution; +uniform vec4 geometryClip; +attribute vec4 position4; + +// External +vec3 getPosition(vec4 xyzw, float canonical); + +vec4 wrapAround(vec4 xyzw) { +#ifdef SURFACE_CLOSED_X + float gx = geometryClip.x; + if (xyzw.x < 0.0) xyzw.x += gx; + if (xyzw.x >= gx) xyzw.x -= gx; +#endif +#ifdef SURFACE_CLOSED_Y + float gy = geometryClip.y; + if (xyzw.y < 0.0) xyzw.y += gy; + if (xyzw.y >= gy) xyzw.y -= gy; +#endif + return xyzw; +} + +void getSurfaceGeometry(vec4 xyzw, float edgeX, float edgeY, out vec3 left, out vec3 center, out vec3 right, out vec3 up, out vec3 down) { + vec4 deltaX = vec4(1.0, 0.0, 0.0, 0.0); + vec4 deltaY = vec4(0.0, 1.0, 0.0, 0.0); + + center = getPosition(xyzw, 1.0); + left = center; + down = center; + right = (edgeX < 0.5) ? getPosition(wrapAround(xyzw + deltaX), 0.0) : (2.0 * center - getPosition(xyzw - deltaX, 0.0)); + up = (edgeY < 0.5) ? getPosition(wrapAround(xyzw + deltaY), 0.0) : (2.0 * center - getPosition(xyzw - deltaY, 0.0)); +} + +vec3 getSurfaceNormal(vec3 left, vec3 center, vec3 right, vec3 up, vec3 down) { + vec3 dx = right - left; + vec3 dy = up - down; + vec3 n = cross(dy, dx); + if (length(n) > 0.0) { + return normalize(n); + } + return vec3(0.0, 1.0, 0.0); +} + +varying vec3 vNormal; +varying vec3 vLight; +varying vec3 vPosition; + +vec3 getSurfacePositionShaded() { + vec3 left, center, right, up, down; + + vec4 p = min(geometryClip, position4); + vec2 surface = vec2(0.0); +#ifdef SURFACE_CLOSED_X + if (p.x == geometryClip.x) p.x = 0.0; +#else + if (p.x == geometryClip.x) surface.x = 1.0; + //if (p.x == 0.0) surface.x = -1.0; +#endif +#ifdef SURFACE_CLOSED_Y + if (p.y == geometryClip.y) p.y = 0.0; +#else + if (p.y == geometryClip.y) surface.y = 1.0; + //if (p.y == 0.0) surface.y = -1.0; +#endif + + getSurfaceGeometry(p, surface.x, surface.y, left, center, right, up, down); + vNormal = getSurfaceNormal(left, center, right, up, down); + vLight = normalize((viewMatrix * vec4(1.0, 2.0, 2.0, 0.0)).xyz); // hardcoded directional light + vPosition = -center; + +#ifdef POSITION_UV +#ifdef POSITION_UV_INT + vUV = -.5 + (position4.xy * geometryResolution.xy) * mapSize.xy; +#else + vUV = position4.xy * geometryResolution.xy; +#endif +#endif + + return center; +} +`; From 19c80b3209650063a85969daf16d46f0fc0024c5 Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 05:44:48 -0600 Subject: [PATCH 03/10] down to reverse --- src/primitives/types/data/array.js | 2 +- src/primitives/types/data/index.js | 1 + src/primitives/types/operator/index.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/primitives/types/data/array.js b/src/primitives/types/data/array.js index c07e597f..05f7ddf3 100644 --- a/src/primitives/types/data/array.js +++ b/src/primitives/types/data/array.js @@ -185,7 +185,7 @@ export class Array_ extends Buffer { } const { data } = this.props; - let { width } = this.width; + let { width } = this.props; const { space, used } = this; const l = used.width; diff --git a/src/primitives/types/data/index.js b/src/primitives/types/data/index.js index f1fcfe7c..05fb5a7d 100644 --- a/src/primitives/types/data/index.js +++ b/src/primitives/types/data/index.js @@ -1,5 +1,6 @@ export * from "./array.js"; export * from "./interval.js"; +export * from "./latch.js"; export * from "./matrix.js"; export * from "./area.js"; export * from "./voxel.js"; diff --git a/src/primitives/types/operator/index.js b/src/primitives/types/operator/index.js index ec7b1cd5..5aa5e2a2 100644 --- a/src/primitives/types/operator/index.js +++ b/src/primitives/types/operator/index.js @@ -6,6 +6,7 @@ export * from "./memo.js"; export * from "./readback.js"; export * from "./resample.js"; export * from "./repeat.js"; +export * from "./reverse.js"; export * from "./swizzle.js"; export * from "./spread.js"; export * from "./split.js"; From 198273cbfb8f4c3aa8a86d89a42afc74739906e8 Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 06:18:02 -0600 Subject: [PATCH 04/10] fix src --- src/index.js | 2 +- src/primitives/types/data/buffer.js | 3 +- src/primitives/types/operator/reverse.js | 156 +++++++++++++---------- src/shaders/index.js | 4 + 4 files changed, 99 insertions(+), 66 deletions(-) diff --git a/src/index.js b/src/index.js index 167f4c15..402c727f 100644 --- a/src/index.js +++ b/src/index.js @@ -28,7 +28,7 @@ export const π = Math.PI; export const τ = π * 2; export const e = Math.E; export const Context = ctx; -export const version = ctx.version; +export const version = ctx.Version; export const Model = model; export const Overlay = overlay; export const Primitives = primitives; diff --git a/src/primitives/types/data/buffer.js b/src/primitives/types/data/buffer.js index f4416be4..11b0ce08 100644 --- a/src/primitives/types/data/buffer.js +++ b/src/primitives/types/data/buffer.js @@ -39,7 +39,8 @@ export class Buffer extends Data { make() { super.make(); - return (this.clockParent = this._inherit("latch")); + this.clockParent = this._inherit("clock"); + this.latchParent = this._inherit("latch"); } unmake() { diff --git a/src/primitives/types/operator/reverse.js b/src/primitives/types/operator/reverse.js index 581f7149..470ab4e6 100644 --- a/src/primitives/types/operator/reverse.js +++ b/src/primitives/types/operator/reverse.js @@ -1,64 +1,92 @@ -// Operator = require './operator' -// Util = require '../../../util' - -// class Reverse extends Operator -// @traits = ['node', 'bind', 'operator', 'source', 'index', 'reverse'] - -// getDimensions: () -> @bind.source.getDimensions() -// getActiveDimensions: () -> @bind.source.getActiveDimensions() -// getFutureDimensions: () -> @bind.source.getFutureDimensions() -// getIndexDimensions: () -> @bind.source.getIndexDimensions() - -// sourceShader: (shader) -> -// shader.pipe 'reverse.position', @uniforms -// @bind.source.sourceShader shader - -// _resolveScale: (key, dims) -> -// range = @props[key] -// dim = dims[key] -// if range then -1 else 1 - -// _resolveOffset: (key, dims) -> -// range = @props[key] -// dim = dims[key] -// if range then dim - 1 else 0 - -// make: () -> -// super -// return unless @bind.source? - -// @uniforms = -// reverseScale: @_attributes.make @_types.vec4() -// reverseOffset: @_attributes.make @_types.vec4() - -// unmake: () -> -// super - -// resize: () -> -// return unless @bind.source? - -// dims = @bind.source.getActiveDimensions() - -// @uniforms.reverseScale.value.set( -// @_resolveScale('width', dims), -// @_resolveScale('height', dims), -// @_resolveScale('depth', dims), -// @_resolveScale('items', dims), -// ) - -// @uniforms.reverseOffset.value.set( -// @_resolveOffset('width', dims), -// @_resolveOffset('height', dims), -// @_resolveOffset('depth', dims), -// @_resolveOffset('items', dims), -// ) - -// super - -// change: (changed, touched, init) -> -// return @rebuild() if touched['operator'] - -// if touched['reverse'] -// @resize() - -// module.exports = Reverse +import { Operator } from "./operator.js"; + +export class Reverse extends Operator { + static initClass() { + this.traits = ["node", "bind", "operator", "source", "index", "reverse"]; + } + + getDimensions() { + return this.bind.source.getDimensions(); + } + getActiveDimensions() { + return this.bind.source.getActiveDimensions(); + } + getFutureDimensions() { + return this.bind.source.getFutureDimensions(); + } + getIndexDimensions() { + return this.bind.source.getIndexDimensions(); + } + + sourceShader(shader) { + shader.pipe("reverse.position", this.uniforms); + return this.bind.source.sourceShader(shader); + } + + _resolveScale(key, dims) { + const range = this.props[key]; + const dim = dims[key]; + return range ? -1 : 1; + } + + _resolveOffset(key, dims) { + const range = this.props[key]; + const dim = dims[key]; + if (range) { + return dim - 1; + } else { + return 0; + } + } + + make() { + super.make(...arguments); + if (this.bind.source == null) { + return; + } + + return (this.uniforms = { + reverseScale: this._attributes.make(this._types.vec4()), + reverseOffset: this._attributes.make(this._types.vec4()), + }); + } + + unmake() { + return super.unmake(...arguments); + } + + resize() { + if (this.bind.source == null) { + return; + } + + const dims = this.bind.source.getActiveDimensions(); + + this.uniforms.reverseScale.value.set( + this._resolveScale("width", dims), + this._resolveScale("height", dims), + this._resolveScale("depth", dims), + this._resolveScale("items", dims) + ); + + this.uniforms.reverseOffset.value.set( + this._resolveOffset("width", dims), + this._resolveOffset("height", dims), + this._resolveOffset("depth", dims), + this._resolveOffset("items", dims) + ); + + return super.resize(...arguments); + } + + change(changed, touched, init) { + if (touched["operator"]) { + return this.rebuild(); + } + + if (touched["reverse"]) { + return this.resize(); + } + } +} +Reverse.initClass(); diff --git a/src/shaders/index.js b/src/shaders/index.js index c1882c60..c229443f 100644 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -73,6 +73,7 @@ import repeatposition from "./glsl/repeat.position"; import resamplepadding from "./glsl/resample.padding"; import resamplerelative from "./glsl/resample.relative"; import revealmask from "./glsl/reveal.mask"; +import reverseposition from "./glsl/reverse.position"; import rootposition from "./glsl/root.position"; import sample2d from "./glsl/sample.2d"; import scaleposition from "./glsl/scale.position"; @@ -104,6 +105,7 @@ import subdividewidthlerp from "./glsl/subdivide.width.lerp"; import surfacemaskhollow from "./glsl/surface.mask.hollow"; import surfaceposition from "./glsl/surface.position"; import surfacepositionnormal from "./glsl/surface.position.normal"; +import surfacepositionshaded from "./glsl/surface.position.shaded"; import ticksposition from "./glsl/ticks.position"; import transform3position from "./glsl/transform3.position"; import transform4position from "./glsl/transform4.position"; @@ -185,6 +187,7 @@ export const Snippets = { "resample.padding": resamplepadding, "resample.relative": resamplerelative, "reveal.mask": revealmask, + "reverse.position": reverseposition, "root.position": rootposition, "sample.2d": sample2d, "scale.position": scaleposition, @@ -216,6 +219,7 @@ export const Snippets = { "surface.mask.hollow": surfacemaskhollow, "surface.position": surfaceposition, "surface.position.normal": surfacepositionnormal, + "surface.position.shaded": surfacepositionshaded, "ticks.position": ticksposition, "transform3.position": transform3position, "transform4.position": transform4position, From 9788e562b0c6fd1c8ff8c14ee47a025e4acbb69a Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 06:59:34 -0600 Subject: [PATCH 05/10] new examples --- examples/math/exponential.html | 178 ++++++------ examples/math/fieldlines.html | 443 ++++++++++++++++-------------- examples/math/helitorus.html | 333 +++++++++++----------- examples/math/hyperbolic.html | 218 ++++++++------- examples/sci/solarsystem.html | 7 +- examples/test/closed-line.html | 368 +++++++++++++------------ examples/test/closed-surface.html | 142 +++++----- examples/test/disc.html | 143 ++++++---- examples/test/partial-data.html | 251 +++++++++-------- examples/test/scatter.html | 124 +++++---- 10 files changed, 1194 insertions(+), 1013 deletions(-) diff --git a/examples/math/exponential.html b/examples/math/exponential.html index 5ed11ac8..e498d8a7 100644 --- a/examples/math/exponential.html +++ b/examples/math/exponential.html @@ -1,85 +1,109 @@ - - - MathBox - Complex Exponential - - - - - - - + + + + + + + + + - + + view + .area({ + rangeX: [-3, 1], + rangeY: [-2 * MathBox.π, 2 * MathBox.π], + width: 129, + height: 65, + expr: function (emit, x, y, i, j) { + var r = Math.exp(x); + + emit(Math.cos(y) * r, Math.sin(y) * r, x, y); + }, + channels: 4, + }) + .surface({ + color: white, + zBias: -0.25, + }) + .line({ + color: blue, + width: 4, + }) + .transpose({ + order: "yxzw", + }) + .line({ + color: blue, + width: 4, + }); + + diff --git a/examples/math/fieldlines.html b/examples/math/fieldlines.html index 6cad1edf..b8c9dac3 100644 --- a/examples/math/fieldlines.html +++ b/examples/math/fieldlines.html @@ -1,158 +1,188 @@ - - - MathBox - Field Lines - - - - - - - + + + + + + + + + - + }, + { + visible: function () { + return props.field2; + }, + } + ); + + diff --git a/examples/math/helitorus.html b/examples/math/helitorus.html index e6043df4..425496e3 100644 --- a/examples/math/helitorus.html +++ b/examples/math/helitorus.html @@ -1,157 +1,180 @@ - - - MathBox - Helitoroidal Surface - - - - - - - + + + + + + + + + - + + var curves1 = view + .resample({ + height: 5, + }) + .line({ + color: 0xffffff, + width: 2, + }); + + diff --git a/examples/math/hyperbolic.html b/examples/math/hyperbolic.html index 3882c49c..bf717ad3 100644 --- a/examples/math/hyperbolic.html +++ b/examples/math/hyperbolic.html @@ -1,155 +1,167 @@ - - - MathBox - Hyperbolic Curvature - - - - - - - + + + + + + + + + - + + diff --git a/examples/sci/solarsystem.html b/examples/sci/solarsystem.html index 000579e7..d1971211 100644 --- a/examples/sci/solarsystem.html +++ b/examples/sci/solarsystem.html @@ -11,11 +11,10 @@ type="text/javascript" src="https://cdn.jsdelivr.net/npm/three@0.137.0/examples/js/controls/OrbitControls.js" > - - + - - - - - + + + + + + + + - + view + .transform({ + position: [0, -1, 0], + }) + .line({ + color: 0xbf2060, + width: 15, + join: "bevel", + start: true, + end: true, + }); + + diff --git a/examples/test/closed-surface.html b/examples/test/closed-surface.html index 39c1628e..709823bb 100644 --- a/examples/test/closed-surface.html +++ b/examples/test/closed-surface.html @@ -1,57 +1,75 @@ - - - MathBox - Closed Surface - - - - - - + + + + + + + + - + + diff --git a/examples/test/disc.html b/examples/test/disc.html index d82a4e66..c2238d52 100644 --- a/examples/test/disc.html +++ b/examples/test/disc.html @@ -1,69 +1,92 @@ - - - MathBox - Discs - - - - - - + + + + + + + + - + view.array({ + data: [ + [1, 0, 1], + [-1, 0, 1], + [-1, 0, -1], + [1, 0, -1], + ], + channels: 3, + }); + view.point({ + depth: 0, + size: 100, + color: 0xb0c7ff, + }); + + diff --git a/examples/test/partial-data.html b/examples/test/partial-data.html index b860277d..2dfe18ea 100644 --- a/examples/test/partial-data.html +++ b/examples/test/partial-data.html @@ -1,121 +1,148 @@ - - - MathBox - Partially Filled Data - - - - - - + + + + + + + + - + view + .voxel( + { + // Reserve space ahead of time + bufferWidth: 6, + bufferHeight: 6, + bufferDepth: 6, + width: 4, + height: 3, + depth: 2, + channels: 3, + expr: (emit, i, j, k) => { + emit(i / 5, k / 10, 0.6 + j / 10); + }, + }, + { + // Change size at runtime + width: (t) => Math.floor(4 + ramp(t * 1.1) * 2), + height: (t) => Math.floor(3 + ramp(t * 0.8) * 3), + depth: (t) => Math.floor(2 + ramp(t * 0.6) * 3), + } + ) + .point({ + color: 0xff00ff, + size: 10, + opacity: 0.5, + zWrite: false, + }); + + diff --git a/examples/test/scatter.html b/examples/test/scatter.html index a450cc3e..a3d36798 100644 --- a/examples/test/scatter.html +++ b/examples/test/scatter.html @@ -1,62 +1,82 @@ - - - MathBox - Scatter - - - - - - + + + - three.camera.position.set(2.5, 1, -1.3); - three.renderer.setClearColor(new THREE.Color(0x000000), 1.0); + + + + + - + view.array({ + data: positions, + channels: 3, + }); + view.array({ + data: colors, + channels: 4, + }); + view.point({ + size: 10, + points: "<<", + colors: "<", + }); + + From d1065ea9ba7d6f35f694d4f3e68f0be74ec8dabf Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 07:10:28 -0600 Subject: [PATCH 06/10] appease linter --- src/primitives/types/operator/reverse.js | 5 ++--- src/render/geometry/surfacegeometry.js | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/primitives/types/operator/reverse.js b/src/primitives/types/operator/reverse.js index 470ab4e6..66664006 100644 --- a/src/primitives/types/operator/reverse.js +++ b/src/primitives/types/operator/reverse.js @@ -23,9 +23,8 @@ export class Reverse extends Operator { return this.bind.source.sourceShader(shader); } - _resolveScale(key, dims) { + _resolveScale(key, _dims) { const range = this.props[key]; - const dim = dims[key]; return range ? -1 : 1; } @@ -79,7 +78,7 @@ export class Reverse extends Operator { return super.resize(...arguments); } - change(changed, touched, init) { + change(_changed, touched, _init) { if (touched["operator"]) { return this.rebuild(); } diff --git a/src/render/geometry/surfacegeometry.js b/src/render/geometry/surfacegeometry.js index c98ea04c..413c8cf9 100644 --- a/src/render/geometry/surfacegeometry.js +++ b/src/render/geometry/surfacegeometry.js @@ -71,7 +71,6 @@ export class SurfaceGeometry extends ClipGeometry { const index = this._emitter("index"); const position = this._emitter("position4"); - const surface = this._emitter("surface"); let base = 0; for ( From fff0e0f75571dcb49e492107d1c1d43d186c194c Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 09:15:55 -0600 Subject: [PATCH 07/10] use lodash --- src/primitives/types/data/latch.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/primitives/types/data/latch.js b/src/primitives/types/data/latch.js index 6281b067..3cb3ae2a 100644 --- a/src/primitives/types/data/latch.js +++ b/src/primitives/types/data/latch.js @@ -1,12 +1,6 @@ import { Parent } from "../base/parent.js"; - -function clone(x) { - return x && JSON.parse(JSON.stringify(x)); -} - -function deepEq(a, b) { - return JSON.stringify(a) == JSON.stringify(b); -} +import isEqual from "lodash/eqDeep"; +import cloneDeep from "lodash/cloneDeep"; class Latch extends Parent { static initClass() { @@ -35,9 +29,9 @@ class Latch extends Parent { swap() { const { deep, data } = this.props; - const dirty = deep ? !deepEq(data, this.data) : data != this.data; + const dirty = deep ? !isEqual(data, this.data) : data != this.data; if (dirty) { - this.data = deep ? clone(data) : data; + this.data = deep ? cloneDeep(data) : data; } } From 3a606de44b5caf9e54ed54cd04e00cc71410ee42 Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 09:22:07 -0600 Subject: [PATCH 08/10] sort imports --- src/primitives/types/data/latch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/types/data/latch.js b/src/primitives/types/data/latch.js index 3cb3ae2a..ebfb8200 100644 --- a/src/primitives/types/data/latch.js +++ b/src/primitives/types/data/latch.js @@ -1,6 +1,6 @@ import { Parent } from "../base/parent.js"; -import isEqual from "lodash/eqDeep"; import cloneDeep from "lodash/cloneDeep"; +import isEqual from "lodash/eqDeep"; class Latch extends Parent { static initClass() { From 55cb1eecd232420673a9484f3001195930e7539f Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Mon, 18 Apr 2022 09:28:32 -0600 Subject: [PATCH 09/10] fix isequal --- package-lock.json | 12 +++++------- package.json | 1 + src/primitives/types/data/latch.js | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec6d74ce..827bb4ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "mathbox", - "version": "2.1.3", + "version": "2.1.4", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "mathbox", - "version": "2.1.3", + "version": "2.1.4", "license": "MIT", "dependencies": { "css-select": "^4.2.1", + "lodash": "^4.17.21", "shadergraph": "^2.1.3", "threestrap": "^0.4.1" }, @@ -4735,8 +4735,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -12129,8 +12128,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.merge": { "version": "4.6.2", diff --git a/package.json b/package.json index 9b651025..ad53515a 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "prettier": {}, "dependencies": { "css-select": "^4.2.1", + "lodash": "^4.17.21", "shadergraph": "^2.1.3", "threestrap": "^0.4.1" }, diff --git a/src/primitives/types/data/latch.js b/src/primitives/types/data/latch.js index ebfb8200..e3bc20f6 100644 --- a/src/primitives/types/data/latch.js +++ b/src/primitives/types/data/latch.js @@ -1,8 +1,8 @@ import { Parent } from "../base/parent.js"; import cloneDeep from "lodash/cloneDeep"; -import isEqual from "lodash/eqDeep"; +import isEqual from "lodash/isEqual"; -class Latch extends Parent { +export class Latch extends Parent { static initClass() { this.traits = ["node", "entity", "active", "latch"]; } From 9df35fe0d281cb3ac133e7d4f845cb381ef1de6e Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Tue, 19 Apr 2022 00:01:58 -0600 Subject: [PATCH 10/10] address review --- examples/test/scatter.html | 1 + src/primitives/types/operator/reverse.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/test/scatter.html b/examples/test/scatter.html index a3d36798..2756da8f 100644 --- a/examples/test/scatter.html +++ b/examples/test/scatter.html @@ -76,6 +76,7 @@ size: 10, points: "<<", colors: "<", + color: 0xffffff, }); diff --git a/src/primitives/types/operator/reverse.js b/src/primitives/types/operator/reverse.js index 66664006..59fec7ac 100644 --- a/src/primitives/types/operator/reverse.js +++ b/src/primitives/types/operator/reverse.js @@ -39,7 +39,7 @@ export class Reverse extends Operator { } make() { - super.make(...arguments); + super.make(); if (this.bind.source == null) { return; } @@ -51,7 +51,7 @@ export class Reverse extends Operator { } unmake() { - return super.unmake(...arguments); + return super.unmake(); } resize() { @@ -75,7 +75,7 @@ export class Reverse extends Operator { this._resolveOffset("items", dims) ); - return super.resize(...arguments); + return super.resize(); } change(_changed, touched, _init) {