Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
AIEditorClipboard.cpp
Go to the documentation of this file.
1/**
2 * @file AIEditorClipboard.cpp
3 * @brief Implementation of AI Editor clipboard system
4 * @author Olympe Engine
5 * @date 2026-02-19
6 */
7
8#include "AIEditorClipboard.h"
9#include "../../system/system_utils.h"
10#include <cfloat>
11#include <algorithm>
12
13namespace Olympe {
14namespace AI {
15
16// ============================================================================
17// Singleton Access
18// ============================================================================
19
25
26// ============================================================================
27// Copy
28// ============================================================================
29
31 const std::vector<NodeGraph::NodeId>& nodeIds,
33{
34 Clear();
35
36 if (nodeIds.empty() || doc == nullptr) {
37 return;
38 }
39
40 // Build set of node IDs for fast lookup
41 std::map<uint32_t, bool> nodeIdSet;
42 for (size_t i = 0; i < nodeIds.size(); ++i) {
43 nodeIdSet[nodeIds[i].value] = true;
44 }
45
46 // Find reference position (top-left corner)
48 for (auto it = nodeIdSet.begin(); it != nodeIdSet.end(); ++it) {
49 NodeGraph::NodeId nodeId;
50 nodeId.value = it->first;
51
52 const NodeGraph::NodeData* nodeData = doc->GetNode(nodeId);
53 if (nodeData != nullptr) {
54 if (nodeData->position.x < refPos.x) {
55 refPos.x = nodeData->position.x;
56 }
57 if (nodeData->position.y < refPos.y) {
58 refPos.y = nodeData->position.y;
59 }
60 }
61 }
62
63 // Copy nodes
64 for (auto it = nodeIdSet.begin(); it != nodeIdSet.end(); ++it) {
65 NodeGraph::NodeId nodeId;
66 nodeId.value = it->first;
67
68 const NodeGraph::NodeData* nodeData = doc->GetNode(nodeId);
69 if (nodeData == nullptr) {
70 continue;
71 }
72
74 cn.type = nodeData->type;
75 cn.name = nodeData->name;
76 cn.position = Vector(
77 nodeData->position.x - refPos.x,
78 nodeData->position.y - refPos.y
79 );
80 cn.parameters = nodeData->parameters;
81 cn.originalId = it->first;
82
83 m_nodes.push_back(cn);
84 }
85
86 // Copy links (only between copied nodes)
87 const std::vector<NodeGraph::LinkData>& allLinks = doc->GetLinks();
88 for (size_t i = 0; i < allLinks.size(); ++i) {
90
91 // Get source and target node IDs from pins
92 // Pin ID convention: nodeId * PIN_ID_MULTIPLIER + offset
95
96 // Check if both nodes are in the copied set
97 auto fromIt = nodeIdSet.find(fromNodeId);
98 auto toIt = nodeIdSet.find(toNodeId);
99
100 if (fromIt != nodeIdSet.end() && toIt != nodeIdSet.end()) {
103 clipLink.childOriginalId = toNodeId;
104 m_links.push_back(clipLink);
105 }
106 }
107
108 SYSTEM_LOG << "[Clipboard] Copied " << m_nodes.size() << " nodes, "
109 << m_links.size() << " links" << std::endl;
110}
111
112// ============================================================================
113// Cut
114// ============================================================================
115
117 const std::vector<NodeGraph::NodeId>& nodeIds,
119{
120 if (doc == nullptr) {
121 return;
122 }
123
124 // Copy first
125 Copy(nodeIds, doc);
126
127 // Delete selected nodes
128 for (size_t i = 0; i < nodeIds.size(); ++i) {
129 doc->DeleteNode(nodeIds[i]);
130 }
131
132 SYSTEM_LOG << "[Clipboard] Cut " << nodeIds.size() << " nodes" << std::endl;
133}
134
135// ============================================================================
136// Paste
137// ============================================================================
138
139std::vector<NodeGraph::NodeId> AIEditorClipboard::Paste(
142{
143 std::vector<NodeGraph::NodeId> newNodeIds;
144
145 if (IsEmpty() || doc == nullptr) {
146 return newNodeIds;
147 }
148
149 // Map: originalId -> new NodeId
150 std::map<uint32_t, NodeGraph::NodeId> idMap;
151
152 // Create nodes
153 for (size_t i = 0; i < m_nodes.size(); ++i)
154 {
155 Vector pos ( m_nodes[i].position.x + pasteOffset.x, m_nodes[i].position.y + pasteOffset.y);
156
157
158 NodeGraph::NodeId newId = doc->CreateNode(m_nodes[i].type, pos);
159
160 // Set name and parameters
161 const NodeGraph::NodeData* nodeData = doc->GetNode(newId);
162 if (nodeData != nullptr) {
164 updatedData.name = m_nodes[i].name;
165 updatedData.parameters = m_nodes[i].parameters;
166 doc->UpdateNode(newId, updatedData);
167 }
168
169 idMap[m_nodes[i].originalId] = newId;
170 newNodeIds.push_back(newId);
171 }
172
173 // Recreate links
174 for (size_t i = 0; i < m_links.size(); ++i) {
175 auto parentIt = idMap.find(m_links[i].parentOriginalId);
176 auto childIt = idMap.find(m_links[i].childOriginalId);
177
178 if (parentIt != idMap.end() && childIt != idMap.end()) {
179 // Create pins from node IDs using the pin ID convention
180 // Output pin: nodeId * PIN_ID_MULTIPLIER + PIN_ID_OUTPUT_OFFSET
181 // Input pin: nodeId * PIN_ID_MULTIPLIER + PIN_ID_INPUT_OFFSET
182 NodeGraph::PinId fromPin;
183 fromPin.value = parentIt->second.value * PIN_ID_MULTIPLIER + PIN_ID_OUTPUT_OFFSET;
184
185 NodeGraph::PinId toPin;
186 toPin.value = childIt->second.value * PIN_ID_MULTIPLIER + PIN_ID_INPUT_OFFSET;
187
188 doc->ConnectPins(fromPin, toPin);
189 }
190 }
191
192 SYSTEM_LOG << "[Clipboard] Pasted " << newNodeIds.size() << " nodes" << std::endl;
193
194 return newNodeIds;
195}
196
197// ============================================================================
198// Utility Methods
199// ============================================================================
200
202{
203 return m_nodes.empty();
204}
205
207{
208 m_nodes.clear();
209 m_links.clear();
210}
211
212} // namespace AI
213} // namespace Olympe
Clipboard system for AI Editor (Cut/Copy/Paste)
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
Singleton clipboard manager for AI Editor.
void Cut(const std::vector< NodeGraph::NodeId > &nodeIds, NodeGraph::GraphDocument *doc)
Cut selected nodes (copy + delete)
static AIEditorClipboard & Get()
Get singleton instance.
void Copy(const std::vector< NodeGraph::NodeId > &nodeIds, NodeGraph::GraphDocument *doc)
Copy selected nodes to clipboard.
std::vector< NodeGraph::NodeId > Paste(NodeGraph::GraphDocument *doc, Vector pasteOffset)
Paste clipboard nodes into active graph.
bool IsEmpty() const
Check if clipboard has data.
std::vector< ClipboardNode > m_nodes
Copied nodes.
std::vector< ClipboardLink > m_links
Copied links.
Main document class for a node graph.
constexpr uint32_t PIN_ID_INPUT_OFFSET
Offset for input pin: nodeId * 1000 + 0.
constexpr uint32_t PIN_ID_OUTPUT_OFFSET
Offset for output pin: nodeId * 1000 + 1.
constexpr uint32_t PIN_ID_MULTIPLIER
Multiplier for pin IDs from node IDs.
< Provides AssetID and INVALID_ASSET_ID
@ Vector
3-component vector (Vector from vector.h)
Represents a node in the clipboard.
std::string type
Node type (e.g., "BT_Selector")
std::map< std::string, std::string > parameters
#define SYSTEM_LOG