Skip to content

Commit f28b4c1

Browse files
committed
Fix simulation issues
1 parent 0953598 commit f28b4c1

File tree

10 files changed

+202
-174
lines changed

10 files changed

+202
-174
lines changed

src/common/vector2.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export const vector2 = {
1818
x: a.x / b,
1919
y: a.y / b,
2020
}),
21+
size: (a: Vector2): number => Math.hypot(a.x, a.y),
22+
distance: (a: Vector2, b: Vector2): number => vector2.size(vector2.sub(a, b)),
2123
fromDomEvent: (e: { offsetX: number; offsetY: number }): Vector2 => ({
2224
x: e.offsetX,
2325
y: e.offsetY,

src/hooks/drag.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { type PointerEvent, useRef } from "react";
2+
import { vector2, type Vector2 } from "../common/vector2";
3+
4+
const DRAG_THRESHOLD = 5;
5+
6+
export type UseDraggableProps = {
7+
onClick?(e: PointerEvent): void;
8+
onDragStart?(e: PointerEvent): void;
9+
onDrag?(e: PointerEvent): void;
10+
onDragEnd?(e: PointerEvent): void;
11+
};
12+
13+
export function useDraggable(props: UseDraggableProps) {
14+
const { onClick, onDragStart, onDrag, onDragEnd } = props;
15+
16+
const dragStateRef = useRef<{
17+
pointerId: number;
18+
initialPosition: Vector2;
19+
isDragging: boolean;
20+
} | null>(null);
21+
22+
return {
23+
onPointerDown: (e: PointerEvent) => {
24+
if (!(e.buttons & 1)) return;
25+
dragStateRef.current = {
26+
pointerId: e.pointerId,
27+
initialPosition: vector2.fromDomEvent(e.nativeEvent),
28+
isDragging: false,
29+
};
30+
onDragStart?.(e);
31+
e.currentTarget.setPointerCapture(e.pointerId);
32+
},
33+
onPointerMove: (e: PointerEvent) => {
34+
if (!dragStateRef.current) return;
35+
if (dragStateRef.current.pointerId !== e.pointerId) return;
36+
if (dragStateRef.current.isDragging) {
37+
onDrag?.(e);
38+
return;
39+
}
40+
41+
const currentPosition = vector2.fromDomEvent(e.nativeEvent);
42+
const distance = vector2.distance(
43+
dragStateRef.current.initialPosition,
44+
currentPosition,
45+
);
46+
if (distance > DRAG_THRESHOLD) {
47+
dragStateRef.current.isDragging = true;
48+
onDragStart?.(e);
49+
onDrag?.(e);
50+
}
51+
},
52+
onPointerUp: (e: PointerEvent) => {
53+
if (!dragStateRef.current) return;
54+
if (dragStateRef.current.pointerId !== e.pointerId) return;
55+
e.currentTarget.releasePointerCapture(e.pointerId);
56+
},
57+
onLostPointerCapture: (e: PointerEvent) => {
58+
if (!dragStateRef.current) return;
59+
if (dragStateRef.current.isDragging) onDragEnd?.(e);
60+
else onClick?.(e);
61+
dragStateRef.current = null;
62+
},
63+
};
64+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export function CCComponentEditorNodePinPropertyEditor() {
2+
}

src/pages/edit/Editor/hooks/drag.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/pages/edit/Editor/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function CCComponentEditorContent({
6262
);
6363
}
6464

65-
export default function CCComponentEditor(props: CCComponentEditorProps) {
65+
export default function CCComponentEditor(props: CCComponentEditorProps) {
6666
const { componentId } = props;
6767
return (
6868
<ComponentEditorStoreProvider componentId={componentId}>

src/pages/edit/Editor/renderer/NodePin.tsx

Lines changed: 56 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useComponentEditorStore } from "../store";
1010
import type { SimulationValue } from "../store/slices/core";
1111
import { CCComponentEditorRendererConnectionCore } from "./Connection";
1212
import getCCComponentEditorRendererNodeGeometry from "./Node.geometry";
13+
import { useDraggable } from "../../../../hooks/drag";
1314

1415
const NODE_PIN_POSITION_SENSITIVITY = 10;
1516

@@ -33,40 +34,6 @@ export default function CCComponentEditorRendererNodePin({
3334
cursorPosition: Vector2;
3435
nodePinPositionKDTree: KDTree<CCNodePinId>;
3536
} | null>(null);
36-
const onDrag = (e: PointerEvent) => {
37-
let nodePinPositionKDTree = draggingState?.nodePinPositionKDTree;
38-
if (!nodePinPositionKDTree) {
39-
const nodes = store.nodes.getManyByParentComponentId(
40-
node.parentComponentId,
41-
);
42-
nodePinPositionKDTree = KDTree.from(
43-
nodes
44-
.filter((yourNode) => yourNode.id !== node.id)
45-
.flatMap((yourNode) => [
46-
...getCCComponentEditorRendererNodeGeometry(store, yourNode.id)
47-
.nodePinPositionById,
48-
])
49-
.flatMap(([yourNodePinId, yourNodePinPosition]) => {
50-
const yourNodePin = nullthrows(store.nodePins.get(yourNodePinId));
51-
const yourComponentPin = nullthrows(
52-
store.componentPins.get(yourNodePin.componentPinId),
53-
);
54-
if (yourComponentPin.type === componentPin.type) return [];
55-
return [
56-
[yourNodePinId, [yourNodePinPosition.x, yourNodePinPosition.y]],
57-
] as const;
58-
}),
59-
2,
60-
);
61-
}
62-
setDraggingState({
63-
cursorPosition: componentEditorState.fromCanvasToStage(
64-
vector2.fromDomEvent(e.nativeEvent),
65-
),
66-
nodePinPositionKDTree,
67-
});
68-
};
69-
7037
let draggingView: ReactNode = null;
7138
let nodePinIdToConnect: CCNodePinId | null = null;
7239
if (draggingState) {
@@ -100,6 +67,57 @@ export default function CCComponentEditorRendererNodePin({
10067
/>
10168
);
10269
}
70+
const draggableProps = useDraggable({
71+
onDrag: (e: PointerEvent) => {
72+
let nodePinPositionKDTree = draggingState?.nodePinPositionKDTree;
73+
if (!nodePinPositionKDTree) {
74+
const nodes = store.nodes.getManyByParentComponentId(
75+
node.parentComponentId,
76+
);
77+
nodePinPositionKDTree = KDTree.from(
78+
nodes
79+
.filter((yourNode) => yourNode.id !== node.id)
80+
.flatMap((yourNode) => [
81+
...getCCComponentEditorRendererNodeGeometry(store, yourNode.id)
82+
.nodePinPositionById,
83+
])
84+
.flatMap(([yourNodePinId, yourNodePinPosition]) => {
85+
const yourNodePin = nullthrows(store.nodePins.get(yourNodePinId));
86+
const yourComponentPin = nullthrows(
87+
store.componentPins.get(yourNodePin.componentPinId),
88+
);
89+
if (yourComponentPin.type === componentPin.type) return [];
90+
return [
91+
[yourNodePinId, [yourNodePinPosition.x, yourNodePinPosition.y]],
92+
] as const;
93+
}),
94+
2,
95+
);
96+
}
97+
setDraggingState({
98+
cursorPosition: componentEditorState.fromCanvasToStage(
99+
vector2.fromDomEvent(e.nativeEvent),
100+
),
101+
nodePinPositionKDTree,
102+
});
103+
},
104+
onDragEnd: () => {
105+
if (nodePinIdToConnect) {
106+
const route = {
107+
input: { from: nodePinIdToConnect, to: nodePin.id },
108+
output: { from: nodePin.id, to: nodePinIdToConnect },
109+
}[componentPin.type];
110+
store.connections.register(
111+
CCConnectionStore.create({
112+
parentComponentId: node.parentComponentId,
113+
...route,
114+
bentPortion: 0.5,
115+
}),
116+
);
117+
}
118+
setDraggingState(null);
119+
},
120+
});
103121

104122
const isSimulationMode = useComponentEditorStore()(
105123
(s) => s.editorMode === "play",
@@ -119,7 +137,7 @@ export default function CCComponentEditorRendererNodePin({
119137
let nodePinValue: SimulationValue;
120138
let nodePinValueAsString: string | null = null;
121139
if (isSimulationMode && hasNoConnection) {
122-
if (implementationComponentPin) {
140+
if (implementationComponentPin && implementationComponentPin.type === "input") {
123141
nodePinValue = nullthrows(
124142
componentEditorState.getInputValue(implementationComponentPin.id),
125143
);
@@ -131,11 +149,11 @@ export default function CCComponentEditorRendererNodePin({
131149
nodePinValueAsString = simulationValueToString(nodePinValue);
132150
}
133151
const updateInputValue = () => {
134-
if (!implementationComponentPin) return;
152+
if (!implementationComponentPin || implementationComponentPin.type !== "input") return;
135153
const updatedPinValue = [...nodePinValue];
136154
updatedPinValue[0] = !updatedPinValue[0];
137155
componentEditorState.setInputValue(
138-
implementationComponentPin.id,
156+
implementationComponentPin?.id,
139157
updatedPinValue,
140158
);
141159
};
@@ -152,30 +170,7 @@ export default function CCComponentEditorRendererNodePin({
152170
{nodePinValueAsString}
153171
</text>
154172
)}
155-
<g
156-
onPointerDown={(e) => {
157-
e.currentTarget.setPointerCapture(e.pointerId);
158-
onDrag(e);
159-
}}
160-
onPointerMove={draggingState ? onDrag : undefined}
161-
onPointerUp={() => {
162-
if (!nodePinIdToConnect) return;
163-
const route = {
164-
input: { from: nodePinIdToConnect, to: nodePin.id },
165-
output: { from: nodePin.id, to: nodePinIdToConnect },
166-
}[componentPin.type];
167-
store.connections.register(
168-
CCConnectionStore.create({
169-
parentComponentId: node.parentComponentId,
170-
...route,
171-
bentPortion: 0.5,
172-
}),
173-
);
174-
}}
175-
onLostPointerCapture={() => {
176-
setDraggingState(null);
177-
}}
178-
>
173+
<g {...draggableProps} style={{ cursor: "pointer" }}>
179174
<rect
180175
x={position.x - 5}
181176
y={position.y - 5}

src/store/componentEvaluator.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import type { CCNodeId } from "./node";
1212
import type { CCNodePin, CCNodePinId } from "./nodePin";
1313

1414
function createInput(
15+
store: CCStore,
1516
nodePins: CCNodePin[],
1617
inputPin: Record<string, CCComponentPin>,
17-
inputValues: Map<CCNodePinId, SimulationValue>,
18+
inputValues: Map<CCNodePinId, SimulationValue> | null,
1819
): Record<string, SimulationValue[]> {
1920
const input: Partial<Record<string, SimulationValue[]>> = {};
2021
for (const key in inputPin) {
@@ -23,9 +24,15 @@ function createInput(
2324
(nodePin: CCNodePin) => componentPin.id === nodePin.componentPinId,
2425
);
2526
targetNodePins.sort((a, b) => a.order - b.order);
26-
const values = targetNodePins.map((nodePin: CCNodePin) =>
27+
const values = inputValues ? targetNodePins.map((nodePin: CCNodePin) =>
2728
nullthrows(inputValues.get(nodePin.id)),
28-
);
29+
) : targetNodePins.map((nodePin: CCNodePin) => {
30+
const multiplexability = store.nodePins.getNodePinMultiplexability(
31+
nodePin.id,
32+
);
33+
const bitWidth = multiplexability.isMultiplexable ? 1 : multiplexability.multiplicity;
34+
return Array<boolean>(bitWidth).fill(false);
35+
});
2936
input[key] = values;
3037
}
3138
return input as Record<string, SimulationValue[]>;
@@ -66,18 +73,20 @@ function simulateIntrinsic(
6673
invariant(componentDefinition);
6774
const inputPin = componentDefinition.inputPin;
6875
const outputPin = componentDefinition.outputPin;
69-
const _input = createInput(nodePins, inputPin, inputValues);
76+
const _input = createInput(store, nodePins, inputPin, inputValues);
7077
const outputShape = createOutputShape(store, nodePins, outputPin);
71-
const previousInputValues = new Map<CCNodePinId, SimulationValue>();
72-
for (const nodePin of nodePins) {
73-
const previousValue = parentPreviousFrame?.nodes
74-
.get(nodeId)
75-
?.pins.get(nodePin.id);
76-
if (previousValue) {
77-
previousInputValues.set(nodePin.id, previousValue);
78+
const previousInputValues = parentPreviousFrame ? new Map<CCNodePinId, SimulationValue>() : null;
79+
if (previousInputValues) {
80+
for (const nodePin of nodePins) {
81+
const previousValue = parentPreviousFrame?.nodes
82+
.get(nodeId)
83+
?.pins.get(nodePin.id);
84+
if (previousValue) {
85+
previousInputValues.set(nodePin.id, previousValue);
86+
}
7887
}
7988
}
80-
const previousInput = createInput(nodePins, inputPin, previousInputValues);
89+
const previousInput = createInput(store, nodePins, inputPin, previousInputValues);
8190
const output = componentDefinition.evaluate(
8291
_input,
8392
outputShape,

0 commit comments

Comments
 (0)