Skip to content

Commit 974e47d

Browse files
committed
Add voronoi mode
1 parent 0ade766 commit 974e47d

File tree

4 files changed

+329
-428
lines changed

4 files changed

+329
-428
lines changed

Nodes/Nodes.hpp

Lines changed: 0 additions & 324 deletions
Original file line numberDiff line numberDiff line change
@@ -2,327 +2,3 @@
22

33
#include "NodesModel.hpp"
44
#include "NodesUi.hpp"
5-
6-
#if 0
7-
#pragma once
8-
9-
#include <ossia/network/value/value.hpp>
10-
11-
#include <halp/controls.hpp>
12-
#include <halp/custom_widgets.hpp>
13-
#include <halp/layout.hpp>
14-
#include <halp/meta.hpp>
15-
#include <halp/sample_accurate_controls.hpp>
16-
#include <halp/value_types.hpp>
17-
18-
#include <cmath>
19-
20-
#include <vector>
21-
22-
namespace spat
23-
{
24-
25-
struct Node
26-
{
27-
halp::xy_type<float> position{0.5f, 0.5f};
28-
float radius{0.1f};
29-
};
30-
31-
struct NodesWidget
32-
{
33-
static constexpr double width() { return 400.; }
34-
static constexpr double height() { return 400.; }
35-
36-
std::vector<Node> nodes;
37-
halp::xy_type<float> inputPoint{0.5f, 0.5f};
38-
int selectedNode{-1};
39-
bool editingRadius{false};
40-
41-
void paint(auto ctx)
42-
{
43-
// Draw background
44-
ctx.set_fill_color({20, 20, 20, 255});
45-
ctx.begin_path();
46-
ctx.draw_rect(0., 0., width(), height());
47-
ctx.fill();
48-
49-
// Draw nodes
50-
int i = 0;
51-
for (const auto& node : nodes)
52-
{
53-
const double centerX = node.position.x * width();
54-
const double centerY = node.position.y * height();
55-
const double radius = node.radius * std::min(width(), height());
56-
57-
// Draw node circle
58-
if (i == selectedNode && editingRadius)
59-
{
60-
ctx.set_stroke_color({255, 100, 100, 255});
61-
ctx.set_stroke_width(3.);
62-
ctx.set_fill_color({100, 50, 50, 100});
63-
}
64-
else if (i == selectedNode)
65-
{
66-
ctx.set_stroke_color({200, 200, 200, 255});
67-
ctx.set_stroke_width(2.);
68-
ctx.set_fill_color({80, 80, 80, 100});
69-
}
70-
else
71-
{
72-
ctx.set_stroke_color({150, 150, 150, 255});
73-
ctx.set_stroke_width(1.);
74-
ctx.set_fill_color({60, 60, 60, 100});
75-
}
76-
77-
ctx.begin_path();
78-
ctx.draw_circle(centerX, centerY, radius);
79-
ctx.fill();
80-
ctx.stroke();
81-
82-
// Draw node number
83-
ctx.set_fill_color({255, 255, 255, 255});
84-
ctx.begin_path();
85-
ctx.draw_text(centerX - 10, centerY + 5, std::to_string(i));
86-
ctx.fill();
87-
88-
i++;
89-
}
90-
91-
// Draw input point
92-
ctx.set_fill_color({100, 200, 255, 255});
93-
ctx.begin_path();
94-
ctx.draw_circle(inputPoint.x * width(), inputPoint.y * height(), 5);
95-
ctx.fill();
96-
}
97-
98-
float distance(const halp::xy_type<float>& p1, const halp::xy_type<float>& p2) const
99-
{
100-
float dx = p2.x - p1.x;
101-
float dy = p2.y - p1.y;
102-
return std::sqrt(dx * dx + dy * dy);
103-
}
104-
105-
int findNodeAt(double x, double y) const
106-
{
107-
halp::xy_type<float> pos{
108-
static_cast<float>(x / width()),
109-
static_cast<float>(y / height())
110-
};
111-
112-
for (int i = 0; i < std::ssize(nodes); ++i)
113-
{
114-
if (distance(pos, nodes[i].position) < 0.03f)
115-
{
116-
return i;
117-
}
118-
}
119-
return -1;
120-
}
121-
122-
bool mouse_press(double x, double y)
123-
{
124-
int nodeIndex = findNodeAt(x, y);
125-
126-
if (nodeIndex >= 0)
127-
{
128-
selectedNode = nodeIndex;
129-
editingRadius = false; // For now, simple mode
130-
}
131-
else
132-
{
133-
// Create new node
134-
nodes.push_back(Node{
135-
halp::xy_type<float>{
136-
static_cast<float>(x / width()),
137-
static_cast<float>(y / height())
138-
},
139-
0.1f
140-
});
141-
selectedNode = std::ssize(nodes) - 1;
142-
}
143-
144-
update();
145-
return true;
146-
}
147-
148-
void mouse_move(double x, double y)
149-
{
150-
if (selectedNode >= 0 && selectedNode < std::ssize(nodes))
151-
{
152-
nodes[selectedNode].position = halp::xy_type<float>{
153-
static_cast<float>(std::clamp(x / width(), 0.0, 1.0)),
154-
static_cast<float>(std::clamp(y / height(), 0.0, 1.0))
155-
};
156-
update();
157-
}
158-
}
159-
160-
void mouse_release(double x, double y)
161-
{
162-
selectedNode = -1;
163-
update();
164-
}
165-
166-
bool mouse_double_click(double x, double y)
167-
{
168-
// Delete node on double click
169-
int nodeIndex = findNodeAt(x, y);
170-
if (nodeIndex >= 0)
171-
{
172-
nodes.erase(nodes.begin() + nodeIndex);
173-
selectedNode = -1;
174-
update();
175-
}
176-
return true;
177-
}
178-
179-
void wheel(double x, double y, double delta)
180-
{
181-
int nodeIndex = findNodeAt(x, y);
182-
if (nodeIndex >= 0)
183-
{
184-
// Adjust radius with wheel
185-
nodes[nodeIndex].radius += delta * 0.001f;
186-
nodes[nodeIndex].radius = std::clamp(nodes[nodeIndex].radius, 0.01f, 0.5f);
187-
update();
188-
}
189-
}
190-
191-
std::function<void()> update;
192-
};
193-
194-
class Nodes
195-
{
196-
public:
197-
halp_meta(name, "Nodes")
198-
halp_meta(category, "Control/Spatialization")
199-
halp_meta(c_name, "Nodes")
200-
halp_meta(uuid, "9e7f5d2a-b3c4-4e8a-9f1d-6a2b3c4d5e6f")
201-
halp_meta(author, "ossia score")
202-
halp_meta(description, "Node-based distance weighting for preset interpolation")
203-
halp_meta(manual_url, "https://ossia.io/score-docs/processes/nodes.html")
204-
205-
struct ins
206-
{
207-
halp::xy_spinboxes_f32<"Input Point", halp::range{.min = 0., .max = 1., .init = 0.5}> inputPoint;
208-
halp::val_port<"Nodes", std::vector<ossia::value>> nodes;
209-
} inputs;
210-
211-
struct outs
212-
{
213-
halp::val_port<"Weights", std::vector<ossia::value>> weights;
214-
} outputs;
215-
216-
void operator()()
217-
{
218-
// Compute weights based on input point and nodes
219-
outputs.weights.value.clear();
220-
221-
if (inputs.nodes.value.empty())
222-
return;
223-
224-
float totalWeight = 0.0f;
225-
std::vector<float> weights;
226-
weights.reserve(inputs.nodes.value.size());
227-
228-
// Calculate weights for each node
229-
for (const auto& node_val : inputs.nodes.value)
230-
{
231-
auto vec = ossia::convert<ossia::vec3f>(node_val);
232-
halp::xy_type<float> nodePos{vec[0], vec[1]};
233-
float nodeRadius = vec[2];
234-
235-
float dx = inputs.inputPoint.value.x - nodePos.x;
236-
float dy = inputs.inputPoint.value.y - nodePos.y;
237-
float dist = std::sqrt(dx * dx + dy * dy);
238-
239-
float weight = 0.0f;
240-
if (dist < nodeRadius)
241-
{
242-
// Linear falloff within radius
243-
weight = 1.0f - (dist / nodeRadius);
244-
weight = std::max(0.0f, std::min(1.0f, weight));
245-
}
246-
247-
weights.push_back(weight);
248-
totalWeight += weight;
249-
}
250-
251-
// Normalize weights if total > 1
252-
if (totalWeight > 1.0f && totalWeight > 0.0f)
253-
{
254-
for (auto& w : weights)
255-
{
256-
w /= totalWeight;
257-
}
258-
}
259-
260-
// Convert to ossia values
261-
for (auto w : weights)
262-
{
263-
outputs.weights.value.push_back(ossia::value{w});
264-
}
265-
}
266-
267-
struct ui
268-
{
269-
halp_meta(name, "Main")
270-
halp_meta(layout, halp::layouts::vbox)
271-
halp_meta(background, halp::colors::dark)
272-
273-
halp::control<&ins::inputPoint> inputControl;
274-
halp::custom_actions_item<NodesWidget> nodesDisplay;
275-
276-
struct bus
277-
{
278-
struct nodes_message
279-
{
280-
halp_flag(relocatable);
281-
std::vector<Node> nodes;
282-
};
283-
284-
struct input_message
285-
{
286-
halp_flag(relocatable);
287-
halp::xy_type<float> point;
288-
};
289-
290-
void init(ui& ui)
291-
{
292-
// Connect the input point control to the widget
293-
ui.nodesDisplay.inputPoint = ui.inputControl.value;
294-
295-
// Set up update callback
296-
ui.nodesDisplay.update = [&ui, this] {
297-
// Send nodes data to processing thread
298-
std::vector<ossia::value> node_values;
299-
for (const auto& node : ui.nodesDisplay.nodes)
300-
{
301-
node_values.push_back(ossia::vec3f{node.position.x, node.position.y, node.radius});
302-
}
303-
304-
// This would need proper message passing in real implementation
305-
// For now, we'll just update the display
306-
};
307-
}
308-
309-
static void process_message(ui& self, nodes_message&& msg)
310-
{
311-
self.nodesDisplay.nodes = std::move(msg.nodes);
312-
if (self.nodesDisplay.update)
313-
self.nodesDisplay.update();
314-
}
315-
316-
static void process_message(ui& self, input_message&& msg)
317-
{
318-
self.nodesDisplay.inputPoint = msg.point;
319-
if (self.nodesDisplay.update)
320-
self.nodesDisplay.update();
321-
}
322-
};
323-
};
324-
};
325-
326-
}
327-
328-
#endif

0 commit comments

Comments
 (0)