355 lines
19 KiB
Markdown
355 lines
19 KiB
Markdown
# Class Diagram Overview
|
|
|
|
Compact class diagram showing key classes and their relationships.
|
|
|
|
```
|
|
┌─────────────────────────────────────┐
|
|
│ Application │
|
|
│ (Base application lifecycle) │
|
|
├─────────────────────────────────────┤
|
|
│ +OnStart() │
|
|
│ +OnStop() │
|
|
│ +OnFrame(deltaTime) │
|
|
│ +TakeScreenshot() │
|
|
└──────────────┬──────────────────────┘
|
|
│ extends
|
|
▼
|
|
┌─────────────────────────────────────┐
|
|
│ App │
|
|
│ (Main application class) │
|
|
├─────────────────────────────────────┤
|
|
│ -m_Nodes: vector<Node> │
|
|
│ -m_Links: vector<Link> │
|
|
│ -m_RootContainers: vector<...> │
|
|
│ -m_ActiveRootContainer: RootContainer│
|
|
│ +GetNextId(): int │
|
|
│ +FindNode(id): Node* │
|
|
│ +FindLink(id): Link* │
|
|
│ +FindPin(id): Pin* │
|
|
│ +SpawnBlockNode(type): Node* │
|
|
│ +SpawnParameterNode(type): Node* │
|
|
│ +SaveGraph() │
|
|
│ +LoadGraph() │
|
|
│ +ExecuteRuntimeStep() │
|
|
│ +RenderNodes() │
|
|
│ +RenderLinks() │
|
|
└─┬────────────┬───────────────┬──────┘
|
|
│ │ │
|
|
│ manages │ owns │ uses
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌──────────────────────┐ ┌─────────┐ ┌──────────────┐
|
|
│ RootContainer │ │ Node │ │ BlockRegistry│
|
|
│ (File-based graph) │ │ │ │ (Factory) │
|
|
├──────────────────────┤ └────┬────┘ ├──────────────┤
|
|
│ -m_Filename: string │ │ │ +CreateBlock()│
|
|
│ -m_IsDirty: bool │ │ has │ +Register() │
|
|
│ +GetFilename() │ ▼ └──────────────┘
|
|
│ +SetDirty() │ ┌─────────┐
|
|
└──────────┬───────────┘ │ Block │◄───┐
|
|
│ extends │ │ │
|
|
▼ ├─────────┤ │
|
|
┌──────────────────────┐ │ +Build() │ │ extends
|
|
│ Container │ │ +Render()│ │
|
|
│ (Hierarchical group) │ │ +Run() │ │
|
|
├──────────────────────┤ │ +Activate│ │
|
|
│ -m_NodeIds: vector │ │ Output()│ │
|
|
│ -m_LinkIds: vector │ │ +Activate│ │
|
|
│ -m_Children: vector │ │ Input() │ │
|
|
│ +GetNextId(): int │ └────┬────┘ │
|
|
│ +AddNode() │ │ │
|
|
│ +RemoveNode() │ │ │
|
|
│ +GetNodes(): vector │ │ │
|
|
│ +GetLinks(): vector │ │ │
|
|
│ +Run() │ │ │
|
|
│ +Render() │ │ │
|
|
└──────────────────────┘ │ │
|
|
│ │
|
|
│ │
|
|
┌────────────┴──┐ │
|
|
│ │ │
|
|
▼ ▼ │
|
|
┌──────────────────┐ ┌──────────────────┐
|
|
│ ParameterizedBlock│ │ ParameterNode │
|
|
│ (Block + params) │ │ (Value nodes) │
|
|
├──────────────────┤ ├──────────────────┤
|
|
│ -m_InputParams │ │ -m_ID: int │
|
|
│ -m_OutputParams │ │ -m_Name: string │
|
|
│ -m_Inputs │ │ -m_Type: PinType │
|
|
│ -m_Outputs │ │ -m_BoolValue │
|
|
│ +AddInputParam() │ │ -m_IntValue │
|
|
│ +AddOutputParam() │ │ -m_FloatValue │
|
|
│ +AddInput() │ │ +GetBool() │
|
|
│ +AddOutput() │ │ +SetBool() │
|
|
└──────────────────┘ │ +Run() │
|
|
│ +Render() │
|
|
│ +Build() │
|
|
└──────────────────┘
|
|
▲
|
|
│ creates
|
|
│
|
|
┌──────────────────┐
|
|
│ParameterRegistry │
|
|
│ (Factory) │
|
|
├──────────────────┤
|
|
│ +CreateParameter()│
|
|
└──────────────────┘
|
|
|
|
|
|
┌──────────────────────────────────────┐
|
|
│ EditorContext │
|
|
│ (Core editor & rendering) │
|
|
├──────────────────────────────────────┤
|
|
│ -m_Links: vector<Link*> │
|
|
│ -m_Nodes: vector<Node*> │
|
|
│ -m_GuidedLinks: map<LinkId, ...> │
|
|
│ +CreateLink(id): Link* │
|
|
│ +DrawNodes() │
|
|
│ +DrawLinks() │
|
|
│ +HandleControlPointDragging() │
|
|
│ +HandleGuidedLinkInteractions() │
|
|
│ +ExecuteRuntime() │
|
|
└───────┬────────────┬──────────────────┘
|
|
│ manages │ manages
|
|
│ │
|
|
▼ ▼
|
|
┌─────────┐ ┌──────────────────┐
|
|
│ Link │ │ GuidedLink │
|
|
│ │ │ (Waypoint routing)│
|
|
└─────────┘ ├──────────────────┤
|
|
│ +ID: LinkId │
|
|
│ +Mode: LinkMode │
|
|
│ +ControlPoints │
|
|
│ +AddControlPoint() │
|
|
│ +RemoveControlP()│
|
|
│ +GetCurveSegm() │
|
|
└────┬─────────────┘
|
|
│ contains
|
|
▼
|
|
┌──────────────────┐
|
|
│ ControlPoint │
|
|
│ (Waypoint) │
|
|
├──────────────────┤
|
|
│ +Position: ImVec2│
|
|
│ +IsManual: bool │
|
|
└──────────────────┘
|
|
▲
|
|
│ persists
|
|
│
|
|
┌──────────────────┐
|
|
│ LinkSettings │
|
|
│ (Persistence) │
|
|
├──────────────────┤
|
|
│ +m_ID: LinkId │
|
|
│ +m_Mode: LinkMode│
|
|
│ +m_ControlPoints │
|
|
│ +Serialize(): json│
|
|
└──────────────────┘
|
|
|
|
|
|
Relationship Legend:
|
|
───► = manages/owns (composition)
|
|
──..► = uses/creates (dependency)
|
|
──┬── = extends (inheritance)
|
|
──o── = has (aggregation)
|
|
```
|
|
|
|
## Key Components
|
|
|
|
### Application Layer
|
|
- **[App](examples/blueprints-example/app.h)**: Main application class managing nodes, links, containers, and runtime execution
|
|
- Extends **[Application](examples/application/include/application.h)** base class for windowing and rendering
|
|
|
|
### Block System
|
|
- **[Block](examples/blueprints-example/blocks/block.h)**: Abstract base class for executable nodes
|
|
- **[ParameterizedBlock](examples/blueprints-example/blocks/block.h)**: Block with input/output parameters and flow control
|
|
- **[BlockRegistry](examples/blueprints-example/blocks/block.h)**: Factory pattern for creating block instances
|
|
|
|
### Parameter System
|
|
- **[ParameterNode](examples/blueprints-example/blocks/parameter_node.h)**: Standalone value nodes (Bool/Int/Float/String)
|
|
- **[ParameterRegistry](examples/blueprints-example/blocks/parameter_node.h)**: Factory for creating parameter nodes
|
|
|
|
### Container System
|
|
- **[Container](examples/blueprints-example/containers/container.h)**: Hierarchical node/link grouping with ID management
|
|
- **[RootContainer](examples/blueprints-example/containers/root_container.h)**: Top-level container tied to a graph file
|
|
|
|
### Editor System
|
|
- **[EditorContext](imgui_node_editor_internal.h)**: Core editor managing rendering and interactions
|
|
- **[GuidedLink](links-guided.h)**: User-controllable waypoints for link routing
|
|
- **[ControlPoint](links-guided.h)**: Individual waypoint on a guided link
|
|
- **[LinkSettings](links-guided.h)**: Persistence for guided link configuration
|
|
|
|
## Source Files Reference
|
|
|
|
| Class | Description | Header File | Implementation Files |
|
|
|-------|-------------|-------------|---------------------|
|
|
| [Application](examples/application/include/application.h) | Base application class for windowing, rendering, and lifecycle management | `examples/application/include/application.h` | - |
|
|
| [App](examples/blueprints-example/app.h) | Main application class managing nodes, links, containers, graph persistence, and runtime execution | `examples/blueprints-example/app.h` | `app-logic.cpp`, `app-render.cpp`, `app-runtime.cpp` |
|
|
| [Block](examples/blueprints-example/blocks/block.h) | Abstract base class for executable nodes with Build/Render/Run interface and activation API | `examples/blueprints-example/blocks/block.h` | `blocks/*.cpp` |
|
|
| [ParameterizedBlock](examples/blueprints-example/blocks/block.h) | Block with input/output parameters and flow control pins | `examples/blueprints-example/blocks/block.h` | `blocks/*.cpp` |
|
|
| [BlockRegistry](examples/blueprints-example/blocks/block.h) | Factory pattern registry for creating block instances by type name | `examples/blueprints-example/blocks/block.h` | - |
|
|
| [ParameterNode](examples/blueprints-example/blocks/parameter_node.h) | Standalone value nodes (Bool/Int/Float/String) with editable display modes | `examples/blueprints-example/blocks/parameter_node.h` | `blocks/parameter_node.cpp` |
|
|
| [ParameterRegistry](examples/blueprints-example/blocks/parameter_node.h) | Factory for creating parameter nodes by type | `examples/blueprints-example/blocks/parameter_node.h` | - |
|
|
| [Container](examples/blueprints-example/containers/container.h) | Hierarchical container for grouping nodes/links with ID management and safe pointer resolution | `examples/blueprints-example/containers/container.h` | `containers/container.cpp` |
|
|
| [RootContainer](examples/blueprints-example/containers/root_container.h) | Top-level container tied to a graph file, manages root-level nodes and links | `examples/blueprints-example/containers/root_container.h` | `containers/root_container.cpp` |
|
|
| [EditorContext](imgui_node_editor_internal.h) | Core editor managing rendering, interactions, link management, and guided link editing | `imgui_node_editor_internal.h` | `imgui_node_editor_render.cpp`, `imgui_node_editor_links.cpp` |
|
|
| [GuidedLink](links-guided.h) | User-controllable waypoints for custom link routing with control point management | `links-guided.h` | `imgui_node_editor_links.cpp` |
|
|
| [ControlPoint](links-guided.h) | Individual waypoint on a guided link with manual/auto placement flags | `links-guided.h` | - |
|
|
| [LinkSettings](links-guided.h) | Persistence structure for guided link configuration (mode, control points, snap settings) | `links-guided.h` | - |
|
|
|
|
## Key Methods
|
|
|
|
### App Core Operations
|
|
- `SaveGraph()` / `LoadGraph()`: Graph persistence
|
|
- `ExecuteRuntimeStep()`: Process activated blocks
|
|
- `RenderNodes()` / `RenderLinks()`: Visual rendering
|
|
- `FindNode()` / `FindLink()` / `FindPin()`: ID-based lookups
|
|
|
|
### Block Execution
|
|
- `Block::Run()`: Execute block logic
|
|
- `Block::ActivateOutput()` / `ActivateInput()`: Flow control
|
|
- `Block::Build()`: Create node structure with pins
|
|
- `Block::Render()`: Custom rendering per block
|
|
|
|
### Container Management
|
|
- `Container::GetNodes()` / `GetLinks()`: Safe ID-to-pointer resolution
|
|
- `Container::GetNextId()`: Unique ID generation
|
|
- `Container::Run()`: Execute container contents
|
|
|
|
### Editor Rendering
|
|
- `EditorContext::DrawNodes()` / `DrawLinks()`: Core rendering
|
|
- `EditorContext::HandleGuidedLinkInteractions()`: Waypoint editing
|
|
- `EditorContext::ExecuteRuntime()`: Runtime integration point
|
|
|
|
## Simplification Suggestions
|
|
|
|
### Core API Requirements
|
|
The `imgui_node_editor.h` API only requires:
|
|
- **NodeId, LinkId, PinId**: Type-safe IDs (already used correctly)
|
|
- **BeginNode()/EndNode()**: Node creation blocks
|
|
- **BeginPin()/EndPin()**: Pin creation blocks
|
|
- **Link()**: Create link between two PinIds
|
|
- **QueryNewLink/QueryNewNode**: Creation callbacks
|
|
- **QueryDeletedNode/QueryDeletedLink**: Deletion callbacks
|
|
- **GetNodePosition/SetNodePosition**: Position management
|
|
|
|
The editor **does NOT require**:
|
|
- ❌ Container/grouping hierarchy
|
|
- ❌ Complex inheritance chains
|
|
- ❌ Registry/factory patterns
|
|
- ❌ Duplicate storage systems
|
|
|
|
### 🗑️ Candidates for Removal/Simplification
|
|
|
|
#### 1. **Container System Redundancy** ⚠️ HIGH IMPACT
|
|
**Problem**: `App` stores nodes/links in both `m_Nodes`/`m_Links` AND `RootContainer::m_NodeIds`/`m_LinkIds`
|
|
- Core API works with IDs directly - doesn't need containers
|
|
- Double storage = sync complexity + pointer invalidation risks
|
|
- `GetNodes()/GetLinks()` converts IDs→pointers unnecessarily
|
|
|
|
**Suggestion**:
|
|
- **Remove `Container`/`RootContainer` entirely** OR
|
|
- **Make Container just a grouping/visual feature** (nodes still in App's flat list)
|
|
- Use `std::map<NodeId, Node*>` for O(1) lookups instead of ID vectors
|
|
|
|
**Files affected**: `containers/container.h`, `containers/root_container.h`, `app-logic.cpp` (GetNodes/GetLinks calls)
|
|
|
|
---
|
|
|
|
#### 2. **Registry Pattern Overhead** ⚠️ MEDIUM IMPACT
|
|
**Problem**: `BlockRegistry` and `ParameterRegistry` are singleton factories that just map strings to constructors
|
|
- Adds indirection for simple "create by type name" operations
|
|
- Could be simple function tables or even switch statements
|
|
|
|
**Suggestion**:
|
|
- Replace with `std::function<Block*(int)>` map directly in `App`
|
|
- OR use simple `switch(typeName)` if block types are finite
|
|
- Keep factories only if you need dynamic plugin loading
|
|
|
|
**Files affected**: `blocks/block.h` (registry), `app-logic.cpp` (CreateBlock calls)
|
|
|
|
---
|
|
|
|
#### 3. **Block vs ParameterizedBlock Inheritance** ⚠️ MEDIUM IMPACT
|
|
**Problem**: Two-level inheritance when most/all blocks need parameters anyway
|
|
- Base `Block` is abstract but has minimal functionality
|
|
- `ParameterizedBlock` adds params, but could just be the base class
|
|
|
|
**Suggestion**:
|
|
- Merge `Block` and `ParameterizedBlock` into single `Block` class
|
|
- OR make `ParameterizedBlock` the base, drop abstract `Block` if unused
|
|
- Check if any blocks actually use base `Block` without parameters
|
|
|
|
**Files affected**: `blocks/block.h`, all block implementations
|
|
|
|
---
|
|
|
|
#### 4. **LinkSettings vs GuidedLink Duplication** ⚠️ LOW IMPACT
|
|
**Problem**: `LinkSettings` (for persistence) and `GuidedLink` (for runtime) store same data
|
|
- Two structures for same concept = sync complexity
|
|
|
|
**Suggestion**:
|
|
- Merge into single structure with `Serialize()` method
|
|
- OR make `GuidedLink` contain `LinkSettings` directly
|
|
- Eliminates conversion between formats
|
|
|
|
**Files affected**: `links-guided.h`, save/load code
|
|
|
|
---
|
|
|
|
#### 5. **Node Instance Union Pattern** ⚠️ LOW IMPACT
|
|
**Problem**: `Node` stores either `BlockInstance*` OR `ParameterInstance*` (mutually exclusive)
|
|
- Requires runtime type checking (`IsBlockBased()`, `GetBlockInstance()`, etc.)
|
|
- Could use `std::variant<Block*, ParameterNode*>` or simpler approach
|
|
|
|
**Suggestion**:
|
|
- Use `std::variant` for type safety OR
|
|
- Separate `BlockNode` and `ParameterNode` completely (no shared base)
|
|
- Current pattern works but adds complexity
|
|
|
|
**Files affected**: `types.h` (Node struct), rendering/runtime code
|
|
|
|
---
|
|
|
|
#### 6. **GetNodes()/GetLinks() ID→Pointer Conversion** ⚠️ MEDIUM IMPACT
|
|
**Problem**: Container stores IDs in vectors, then converts to pointers via `App::FindNode()`
|
|
- Adds indirection layer, performance overhead (though minimal)
|
|
- Pointer invalidation risks when vectors resize
|
|
|
|
**Suggestion**:
|
|
- Store pointers directly if Container system is kept
|
|
- OR use `std::unordered_map<NodeId, Node*>` for O(1) lookup
|
|
- Current ID-based storage is safer but adds complexity
|
|
|
|
**Files affected**: `containers/container.cpp` (GetNodes/GetLinks implementations)
|
|
|
|
---
|
|
|
|
### ✅ What to Keep
|
|
|
|
- **Block abstraction**: Good separation of concerns (Build/Render/Run)
|
|
- **Activation API**: Useful for flow control in runtime
|
|
- **Guided Links**: Core feature, keep but simplify persistence
|
|
- **ID-based lookups**: Type safety is valuable, but consider maps vs vectors
|
|
|
|
### 📊 Impact Summary
|
|
|
|
| Simplification | Impact | Effort | Priority |
|
|
|---------------|--------|--------|----------|
|
|
| Remove Container system | HIGH | HIGH | ⭐⭐⭐ |
|
|
| Simplify Registry | MEDIUM | LOW | ⭐⭐ |
|
|
| Merge Block inheritance | MEDIUM | MEDIUM | ⭐⭐ |
|
|
| Merge LinkSettings | LOW | LOW | ⭐ |
|
|
| Simplify Node instances | LOW | MEDIUM | ⭐ |
|
|
|
|
### 🔍 Recommended Investigation
|
|
|
|
Before removing anything, verify:
|
|
1. Are containers used for anything beyond tracking node/link ownership? (groups? nesting?)
|
|
2. Do any blocks actually inherit from `Block` directly without parameters?
|
|
3. Can we prove Container system adds value beyond App's flat storage?
|
|
4. What percentage of code deals with Container vs direct Node/Link access?
|
|
|
|
**Core Insight**: The editor API works with IDs. Your abstractions should minimize conversion between IDs ↔ pointers ↔ containers.
|
|
|