Skip to content

Commit

Permalink
Implement transparency, blend mode, layer order
Browse files Browse the repository at this point in the history
  • Loading branch information
spaaaacccee committed Dec 5, 2023
1 parent 143fbc5 commit 6798a95
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 55 deletions.
4 changes: 2 additions & 2 deletions client/src/components/inspector/TraceRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ export function TraceRenderer({
) : (
<>
<Box ref={ref}>
{layers.map((l) => (
<RenderLayer key={l.key} layer={l} />
{layers.map((l, i) => (
<RenderLayer index={i} key={l.key} layer={l} />
))}
</Box>
</>
Expand Down
43 changes: 39 additions & 4 deletions client/src/components/layer-editor/LayerEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,35 @@ import {
import { Layer } from "slices/layers";
import { inferLayerName, layerHandlers } from "../../layers/Layer";

const compositeOperations = [
"color",
"color-burn",
"color-dodge",
"copy",
"darken",
"destination-atop",
"destination-in",
"destination-out",
"destination-over",
"difference",
"exclusion",
"hard-light",
"hue",
"lighten",
"lighter",
"luminosity",
"multiply",
"overlay",
"saturation",
"screen",
"soft-light",
"source-atop",
"source-in",
"source-out",
"source-over",
"xor",
];

type LayerEditorProps = {
value: Layer;
onValueChange?: (v: Layer) => void;
Expand Down Expand Up @@ -126,21 +155,27 @@ function Component(
"Transparency",
<FeaturePicker
label="Transparency"
items={["25", "50", "75", "100"].map((c) => ({
items={["0", "25", "50", "75"].map((c) => ({
id: c,
name: `${c}%`,
}))}
value="100"
value={draft.transparency ?? "0"}
showArrow
onChange={(e) =>
setDraft?.(produce(draft, (d) => set(d, "transparency", e)))
}
/>
)}
{renderOption(
"Display Mode",
<FeaturePicker
label="Display Mode"
value="normal"
items={options(["normal", "difference"])}
value={draft.displayMode ?? "source-over"}
items={options(compositeOperations)}
showArrow
onChange={(e) =>
setDraft?.(produce(draft, (d) => set(d, "displayMode", e)))
}
/>
)}
{renderHeading("Source Options")}
Expand Down
9 changes: 4 additions & 5 deletions client/src/hooks/useBreakpoints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useMemo } from "react";
import { UploadedTrace } from "slices/UIState";
import { useLayer } from "slices/layers";


export type Comparator = {
key: string;
apply: (value: number, reference: number) => boolean;
Expand All @@ -30,7 +29,8 @@ export type DebugLayerData = {
};
export function useBreakpoints(key?: string) {
const { layer } = useLayer<DebugLayerData>(key);
const {monotonicF, monotonicG,breakpoints ,code,trace} = layer?.source??{}
const { monotonicF, monotonicG, breakpoints, code, trace } =
layer?.source ?? {};
// TODO:
return useMemo(() => {
const memo = keyBy(trace?.content?.events, "id");
Expand All @@ -53,7 +53,7 @@ export function useBreakpoints(key?: string) {
type,
property = "",
reference = 0,
} of breakpoints??[]) {
} of breakpoints ?? []) {
const isType = !type || type === event.type;
const match = condition?.apply?.(get(event, property), reference);
if (active && isType && match) {
Expand All @@ -69,7 +69,7 @@ export function useBreakpoints(key?: string) {
call(code ?? "", "shouldBreak", [
step,
event,
trace?.content?.events?? [],
trace?.content?.events ?? [],
])
) {
return { result: "Script editor" };
Expand All @@ -81,5 +81,4 @@ export function useBreakpoints(key?: string) {
return { result: "" };
});
}, [code, trace?.content, breakpoints, monotonicF, monotonicG]);

}
11 changes: 9 additions & 2 deletions client/src/layers/Layer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type SelectionInfoProvider = FC<{
export type LayerController<K extends string, T> = {
key: K;
editor: FC<EditorSetterProps<Layer<T>>>;
renderer: FC<{ layer?: Layer<T> }>;
renderer: FC<{ layer?: Layer<T>; index?: number }>;
service?: FC<EditorSetterProps<Layer<T>>>;
inferName: (layer: Layer<T>) => string;
steps: FC<{
Expand All @@ -28,12 +28,19 @@ export type LayerController<K extends string, T> = {
getSelectionInfo?: SelectionInfoProvider;
};

export function RenderLayer({ layer }: { layer?: Layer }) {
export function RenderLayer({
layer,
index,
}: {
layer?: Layer;
index?: number;
}) {
return (
<>
{layer &&
createElement(layerHandlers[layer?.source?.type ?? ""]?.renderer, {
layer,
index,
})}
</>
);
Expand Down
19 changes: 16 additions & 3 deletions client/src/layers/map/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useEffectWhen } from "hooks/useEffectWhen";
import { useMapContent } from "hooks/useMapContent";
import { useParsedMap } from "hooks/useParsedMap";
import { LayerController, inferLayerName } from "layers";
import { isUndefined, round, set, startCase } from "lodash";
import { isUndefined, map, round, set, startCase } from "lodash";
import { withProduce } from "produce";
import { useMemo } from "react";
import { Map } from "slices/UIState";
Expand Down Expand Up @@ -41,9 +41,22 @@ export const controller = {
</>
);
}),
renderer: ({ layer }) => {
renderer: ({ layer, index }) => {
const { nodes } = layer?.source?.parsedMap ?? {};
const nodes2 = useMemo(() => [nodes ?? []], [nodes]);
const nodes2 = useMemo(
() => [
map(nodes, (n) => ({
...n,
meta: {
...n.meta,
sourceLayerIndex: index,
sourceLayerAlpha: 1 - 0.01 * +(layer?.transparency ?? 0),
sourceLayerDisplayMode: layer?.displayMode ?? "source-over",
},
})),
],
[nodes, index, layer?.transparency, layer?.displayMode]
);
return <NodeList nodes={nodes2} />;
},
steps: ({ children }) => <>{children?.([])}</>,
Expand Down
55 changes: 43 additions & 12 deletions client/src/layers/trace/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export type TraceLayerData = {
trace?: UploadedTrace;
parsedTrace?: ParseTraceWorkerReturnType;
onion?: "off" | "transparent" | "solid";
} & PlaybackLayerData & DebugLayerData;
} & PlaybackLayerData &
DebugLayerData;

export type TraceLayer = Layer<TraceLayerData>;

Expand Down Expand Up @@ -178,24 +179,54 @@ export const controller = {
</>
);
}),
renderer: ({ layer }) => {
renderer: ({ layer, index }) => {
const parsedTrace = layer?.source?.parsedTrace;
const step = useThrottle(layer?.source?.step ?? 0, 1000 / 60);

const path = use2DPath(layer, step);
const path = use2DPath(layer, index, step);
const steps = useMemo(
() =>
map(parsedTrace?.stepsPersistent, (c) =>
map(c, (d) => merge(d, { meta: { sourceLayer: layer?.key } }))
map(c, (d) =>
merge(d, {
meta: {
sourceLayer: layer?.key,
sourceLayerIndex: index,
sourceLayerAlpha: 1 - 0.01 * +(layer?.transparency ?? 0),
sourceLayerDisplayMode: layer?.displayMode ?? "source-over",
},
})
)
),
[parsedTrace?.stepsPersistent, layer?.key]
[
parsedTrace?.stepsPersistent,
layer?.key,
layer?.transparency,
layer?.displayMode,
index,
]
);
const steps1 = useMemo(
() =>
map(parsedTrace?.stepsTransient, (c) =>
map(c, (d) => merge(d, { meta: { sourceLayer: layer?.key } }))
map(c, (d) =>
merge(d, {
meta: {
sourceLayer: layer?.key,
sourceLayerIndex: index,
sourceLayerAlpha: 1 - 0.01 * +(layer?.transparency ?? 0),
sourceLayerDisplayMode: layer?.displayMode ?? "source-over",
},
})
)
),
[parsedTrace?.stepsTransient, layer?.key]
[
parsedTrace?.stepsTransient,
layer?.key,
layer?.transparency,
layer?.displayMode,
index,
]
);
const steps2 = useMemo(() => [steps1[step] ?? []], [steps1, step]);
return (
Expand All @@ -217,11 +248,11 @@ export const controller = {
.filter((c) => c.meta?.sourceLayer === layer?.key)
.map((c) => c.meta?.step)
.filter(negate(isUndefined))
.sort((a, b) => a - b)
.sort((a, b) => a! - b!)
.value() as number[];
const info = chain(event?.info?.components)
.filter((c) => c.meta?.sourceLayer === layer?.key)
.filter((c) => c.meta.info)
.filter((c) => c.meta?.info)
.value() as any[];
if (steps.length && layer) {
const step = last(steps)!;
Expand Down Expand Up @@ -271,7 +302,7 @@ export const controller = {
},
} satisfies LayerController<"trace", TraceLayerData>;

function use2DPath(layer?: TraceLayer, step: number = 0) {
function use2DPath(layer?: TraceLayer, index: number = 0, step: number = 0) {
const { palette } = useTheme();
const { getPath } = useMemo(
() =>
Expand Down Expand Up @@ -336,14 +367,14 @@ function use2DPath(layer?: TraceLayer, step: number = 0) {
nodes={[
map(primitive, (c) => ({
component: c,
meta: { source: "path" },
meta: { source: "path", sourceLayerIndex: -99999 + index },
})),
]}
/>
);
}
}
return <></>;
}, [layer, step, palette, getPath]);
}, [layer, index, step, palette, getPath]);
return element;
}
28 changes: 20 additions & 8 deletions client/src/pages/StepsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@ import { Placeholder } from "components/inspector/Placeholder";
import { useViewTreeContext } from "components/inspector/ViewTree";
import { usePlaybackState } from "hooks/usePlaybackState";
import { inferLayerName, layerHandlers } from "layers/Layer";
import { defer, map } from "lodash";
import { defer, map, throttle } from "lodash";
import { Page } from "pages/Page";
import { TraceEvent } from "protocol";
import { cloneElement, createElement, useEffect, useMemo, useRef } from "react";
import {
cloneElement,
createElement,
useCallback,
useEffect,
useMemo,
useRef,
} from "react";
import { useLayer } from "slices/layers";

const divider = <Divider orientation="vertical" flexItem sx={{ m: 1 }} />;
Expand All @@ -40,18 +47,23 @@ export function StepsPage() {
}
}, [layer]);

useEffect(() => {
defer(
() =>
const f = useCallback(
throttle(
(step: number) =>
ref?.current?.scrollToIndex?.({
index: step,
align: "start",
behavior: "smooth",
offset: -pxToInt(spacing(6 + 2)),
}),
0
);
}, [step, playing, spacing]);
1000 / 30
),
[ref]
);

useEffect(() => {
defer(() => f(step));
}, [f, step]);

return (
<Page onChange={onChange} stack={state}>
Expand Down
4 changes: 2 additions & 2 deletions client/src/public-dev/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"short_name": "Visualiser",
"name": "Visualiser",
"version": "1.0.5",
"version": "dev",
"description": "Visualise pathfinding search and more",
"version_name": "1.0.5; mid October 2023",
"version_name": "dev",
"repository": "https://github.com/path-visualiser/app",
"docs": "https://github.com/path-visualiser/app/blob/master/docs",
"icons": [
Expand Down
4 changes: 2 additions & 2 deletions client/src/public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"short_name": "Visualiser",
"name": "Visualiser",
"version": "1.1.0",
"version": "1.1.1",
"description": "Visualise pathfinding search and more",
"version_name": "1.1.0; mid November 2023",
"version_name": "1.1.1; early December 2023",
"repository": "https://github.com/path-visualiser/app",
"docs": "https://github.com/path-visualiser/app/blob/master/docs",
"icons": [
Expand Down
1 change: 1 addition & 0 deletions client/src/slices/layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type Layer<T = Record<string, any>> = {
name?: string;
source?: { type: string } & T;
transparency?: "25" | "50" | "75" | "100";
displayMode?: GlobalCompositeOperation;
};

export type Layers = {
Expand Down
4 changes: 1 addition & 3 deletions internal-renderers/src/d2-renderer/D2Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,14 @@ class D2Renderer

add(components: ComponentEntry<CompiledD2IntrinsicComponent>[]) {
const id = nanoid();
map(this.#workers, (w) => w.call("add", [components, id]));
const bodies = map(components, ({ component, meta }) => ({
...primitives[component.$].test(component),
component,
meta,
index: this.#next(),
}));
this.#system.load(bodies);
map(this.#workers, (w) =>
w.call("add", [map(components, "component"), id])
);
return () =>
defer(() => {
for (const c of bodies) this.#system.remove(c);
Expand Down
Loading

0 comments on commit 6798a95

Please sign in to comment.