Skip to content

Commit a30d1fe

Browse files
authored
Refactor simulation engine and renderer architecture (#58)
* refactor simulation * <WIP> renderer * update * 8 bit adder
1 parent 3a642d4 commit a30d1fe

29 files changed

Lines changed: 1276 additions & 978 deletions

File tree

src/common/vector2.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export type Vector2 = { x: number; y: number };
22

33
export const vector2 = {
44
zero: { x: 0, y: 0 },
5+
create: (x: number, y: number): Vector2 => ({ x, y }),
56
add: (a: Vector2, b: Vector2): Vector2 => ({
67
x: a.x + b.x,
78
y: a.y + b.y,

src/pages/edit/Editor/components/NodePinPropertyEditor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { rect } from "../../../../common/rect";
77
import { IntrinsicComponentDefinition } from "../../../../store/intrinsics/base";
88
import { CCNodePinStore } from "../../../../store/nodePin";
99
import { useStore } from "../../../../store/react";
10-
import getCCComponentEditorRendererNodeGeometry from "../renderer/Node.geometry";
10+
import getCCComponentEditorRendererNodeGeometry from "../renderer/Node/geometry";
1111
import { useComponentEditorStore } from "../store";
1212

1313
export function CCComponentEditorNodePinPropertyEditor() {

src/pages/edit/Editor/renderer/Background.tsx renamed to src/pages/edit/Editor/renderer/Background/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { vector2 } from "../../../../common/vector2";
2-
import { useComponentEditorStore } from "../store";
1+
import { vector2 } from "../../../../../common/vector2";
2+
import { useComponentEditorStore } from "../../store";
33

44
export default function CCComponentEditorRendererBackground() {
55
const componentEditorState = useComponentEditorStore()();

src/pages/edit/Editor/renderer/InputValue.tsx renamed to src/pages/edit/Editor/renderer/ComponentPin/index.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import nullthrows from "nullthrows";
2-
import { theme } from "../../../../common/theme";
3-
import type { CCNodePinId } from "../../../../store/nodePin";
4-
import { useStore } from "../../../../store/react";
5-
import { useComponentEditorStore } from "../store";
6-
import {
7-
stringifySimulationValue,
8-
wrappingIncrementSimulationValue,
9-
} from "../store/slices/core";
10-
import getCCComponentEditorRendererNodeGeometry from "./Node.geometry";
11-
export type CCComponentEditorRendererInputValueProps = {
2+
import { theme } from "../../../../../common/theme";
3+
import type { CCNodePinId } from "../../../../../store/nodePin";
4+
import { useStore } from "../../../../../store/react";
5+
import { wrappingIncrementSimulationValue } from "../../../../../store/simulation";
6+
import { useComponentEditorStore } from "../../store";
7+
import { stringifySimulationValue } from "../../store/slices/core";
8+
import getCCComponentEditorRendererNodeGeometry from "./../Node/geometry";
9+
export type CCComponentEditorRendererComponentPinProps = {
1210
nodePinId: CCNodePinId;
1311
};
14-
// TODO: Change name to CCComponentEditorRendererComponentPin
15-
export default function CCComponentEditorRendererInputValue({
12+
export default function CCComponentEditorRendererComponentPin({
1613
nodePinId,
17-
}: CCComponentEditorRendererInputValueProps) {
14+
}: CCComponentEditorRendererComponentPinProps) {
1815
const { store } = useStore();
1916
const componentEditorState = useComponentEditorStore()();
2017
const nodePin = nullthrows(store.nodePins.get(nodePinId));

src/pages/edit/Editor/renderer/Connection.tsx renamed to src/pages/edit/Editor/renderer/Connection/index.tsx

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,41 @@
11
import nullthrows from "nullthrows";
22
import { useState } from "react";
3-
import { theme } from "../../../../common/theme";
4-
import type { CCConnectionId } from "../../../../store/connection";
5-
import { useStore } from "../../../../store/react";
6-
import ensureStoreItem from "../../../../store/react/error";
7-
import { useNode } from "../../../../store/react/selectors";
8-
import { useComponentEditorStore } from "../store";
9-
import { stringifySimulationValue } from "../store/slices/core/index";
10-
import getCCComponentEditorRendererNodeGeometry from "./Node.geometry";
3+
import { theme } from "../../../../../common/theme";
4+
import type { Vector2 } from "../../../../../common/vector2";
5+
import type { CCComponentPinType } from "../../../../../store/componentPin";
6+
import type { CCConnectionId } from "../../../../../store/connection";
7+
import { useStore } from "../../../../../store/react";
8+
import ensureStoreItem from "../../../../../store/react/error";
9+
import { useNode } from "../../../../../store/react/selectors";
10+
import { useComponentEditorStore } from "../../store";
11+
import { stringifySimulationValue } from "../../store/slices/core/index";
12+
import getCCComponentEditorRendererNodeGeometry from "../Node/geometry";
13+
14+
export type CCComponentEditorRendererConnectionEndpoint = {
15+
direction: CCComponentPinType;
16+
position: Vector2;
17+
};
1118

1219
export type CCComponentEditorRendererConnectionCoreProps = {
13-
from: { x: number; y: number };
14-
to: { x: number; y: number };
20+
from: CCComponentEditorRendererConnectionEndpoint;
21+
to: CCComponentEditorRendererConnectionEndpoint;
1522
connectionId?: CCConnectionId;
1623
onMouseEnter?: React.MouseEventHandler<SVGPathElement>;
1724
onMouseLeave?: React.MouseEventHandler<SVGPathElement>;
1825
};
1926

27+
const straightGap = 10;
28+
const polarity: Record<CCComponentPinType, number> = {
29+
input: -1,
30+
output: 1,
31+
};
2032
export function CCComponentEditorRendererConnectionCore({
2133
from,
2234
to,
2335
connectionId,
2436
onMouseEnter,
2537
onMouseLeave,
2638
}: CCComponentEditorRendererConnectionCoreProps) {
27-
const straightGap = 10;
28-
const direction = from.x < to.x ? 1 : -1;
29-
3039
const componentEditorState = useComponentEditorStore()();
3140

3241
const handleClick = (e: React.MouseEvent) => {
@@ -40,17 +49,17 @@ export function CCComponentEditorRendererConnectionCore({
4049
// biome-ignore lint/a11y/noStaticElementInteractions: SVG
4150
<path
4251
d={[
43-
`M ${from.x} ${from.y}`,
44-
`h ${straightGap * direction}`,
52+
`M ${from.position.x} ${from.position.y}`,
53+
`h ${straightGap * polarity[from.direction]}`,
4554
`C ${[
46-
from.x + 4 * straightGap * direction,
47-
from.y,
48-
to.x - 4 * straightGap * direction,
49-
to.y,
50-
to.x - straightGap * direction,
51-
to.y,
55+
from.position.x + 4 * straightGap * polarity[from.direction],
56+
from.position.y,
57+
to.position.x + 4 * straightGap * polarity[to.direction],
58+
to.position.y,
59+
to.position.x + straightGap * polarity[to.direction],
60+
to.position.y,
5261
].join(" ")}`,
53-
`h ${straightGap * direction}`,
62+
`h ${straightGap * polarity[from.direction]}`,
5463
].join(" ")}
5564
stroke={
5665
connectionId &&
@@ -87,7 +96,13 @@ const CCComponentEditorRendererConnection = ensureStoreItem(
8796
const componentEditorState = useComponentEditorStore()();
8897
const connection = nullthrows(store.connections.get(connectionId));
8998
const fromNodePin = nullthrows(store.nodePins.get(connection.from));
99+
const fromComponentPin = nullthrows(
100+
store.componentPins.get(fromNodePin.componentPinId),
101+
);
90102
const toNodePin = nullthrows(store.nodePins.get(connection.to));
103+
const toComponentPin = nullthrows(
104+
store.componentPins.get(toNodePin.componentPinId),
105+
);
91106
const fromNode = useNode(fromNodePin.nodeId);
92107
const toNode = useNode(toNodePin.nodeId);
93108
const fromNodeGeometry = getCCComponentEditorRendererNodeGeometry(
@@ -110,8 +125,11 @@ const CCComponentEditorRendererConnection = ensureStoreItem(
110125
return (
111126
<>
112127
<CCComponentEditorRendererConnectionCore
113-
from={fromNodePinPosition}
114-
to={toNodePinPosition}
128+
from={{
129+
direction: fromComponentPin.type,
130+
position: fromNodePinPosition,
131+
}}
132+
to={{ direction: toComponentPin.type, position: toNodePinPosition }}
115133
connectionId={connectionId}
116134
onMouseEnter={() => {
117135
setIsHovered(true);

src/pages/edit/Editor/renderer/Node.geometry.ts

Lines changed: 0 additions & 62 deletions
This file was deleted.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { type Vector2, vector2 } from "../../../../../../../common/vector2";
2+
import type { CCNodePinId } from "../../../../../../../store/nodePin";
3+
import type {
4+
CCComponentEditorRendererNodeGeometryCalculator,
5+
CCComponentEditorRendererNodeGeometrySource,
6+
} from "../../types";
7+
8+
const width = 100;
9+
const gapY = 20;
10+
const paddingY = 15;
11+
12+
export const ccComponentRendererNodeDefaultGeometryCalculator: CCComponentEditorRendererNodeGeometryCalculator =
13+
(source: CCComponentEditorRendererNodeGeometrySource) => {
14+
const size: Vector2 = {
15+
x: width,
16+
y:
17+
gapY *
18+
Math.max(
19+
source.inputNodePinIds.length,
20+
source.outputNodePinIds.length,
21+
) +
22+
paddingY * 2,
23+
};
24+
25+
const nodePinPositionById = new Map<CCNodePinId, Vector2>();
26+
for (const [index, nodePinId] of source.inputNodePinIds.entries()) {
27+
nodePinPositionById.set(nodePinId, {
28+
x: source.position.x - size.x / 2,
29+
y:
30+
source.position.y +
31+
gapY * (index - source.inputNodePinIds.length / 2 + 0.5),
32+
});
33+
}
34+
for (const [index, nodePinId] of source.outputNodePinIds.entries()) {
35+
nodePinPositionById.set(nodePinId, {
36+
x: source.position.x + size.x / 2,
37+
y:
38+
source.position.y +
39+
gapY * (index - source.outputNodePinIds.length / 2 + 0.5),
40+
});
41+
}
42+
43+
return {
44+
rect: {
45+
position: vector2.sub(source.position, vector2.div(size, 2)),
46+
size,
47+
},
48+
nodePinPositionById,
49+
};
50+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { theme } from "../../../../../../../common/theme";
2+
import type { CCComponentEditorRendererNodeRendererProps } from "../../types";
3+
4+
export function CCComponentEditorRendererNodeDefaultRenderer(
5+
props: CCComponentEditorRendererNodeRendererProps,
6+
) {
7+
return (
8+
<>
9+
<text
10+
fill={theme.palette.textPrimary}
11+
x={props.geometry.rect.position.x}
12+
y={props.geometry.rect.position.y - 5}
13+
textAnchor="start"
14+
fontSize={12}
15+
>
16+
{props.component.name}
17+
</text>
18+
<rect
19+
x={props.geometry.rect.position.x}
20+
y={props.geometry.rect.position.y}
21+
width={props.geometry.rect.size.x}
22+
height={props.geometry.rect.size.y}
23+
fill={theme.palette.white}
24+
stroke={
25+
props.nodeState.isSelected
26+
? theme.palette.primary
27+
: theme.palette.textPrimary
28+
}
29+
strokeWidth={2}
30+
rx={2}
31+
/>
32+
</>
33+
);
34+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { type Vector2, vector2 } from "../../../../../../../common/vector2";
2+
import type { CCNodePinId } from "../../../../../../../store/nodePin";
3+
import type {
4+
CCComponentEditorRendererNodeGeometryCalculator,
5+
CCComponentEditorRendererNodeGeometrySource,
6+
} from "../../types";
7+
8+
const width = 320;
9+
const height = 200;
10+
11+
export const ccComponentRendererNodeDisplayGeometryCalculator: CCComponentEditorRendererNodeGeometryCalculator =
12+
(source: CCComponentEditorRendererNodeGeometrySource) => {
13+
const size: Vector2 = {
14+
x: width,
15+
y: height,
16+
};
17+
18+
return {
19+
rect: {
20+
position: vector2.sub(source.position, vector2.div(size, 2)),
21+
size,
22+
},
23+
nodePinPositionById: new Map<CCNodePinId, Vector2>(
24+
source.inputNodePinIds.map(
25+
(id) =>
26+
[
27+
id,
28+
vector2.create(source.position.x - size.x / 2, source.position.y),
29+
] as const,
30+
),
31+
),
32+
};
33+
};

0 commit comments

Comments
 (0)