1use std::collections::HashMap;
5use std::fmt;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub struct NodeId(pub u64);
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub struct SocketId {
18 pub node_id: NodeId,
19 pub index: usize,
20 pub direction: SocketDirection,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub enum SocketDirection {
26 Input,
27 Output,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum DataType {
33 Float,
34 Vec2,
35 Vec3,
36 Vec4,
37 Mat3,
38 Mat4,
39 Sampler2D,
40 Bool,
41 Int,
42}
43
44impl fmt::Display for DataType {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 match self {
47 DataType::Float => write!(f, "float"),
48 DataType::Vec2 => write!(f, "vec2"),
49 DataType::Vec3 => write!(f, "vec3"),
50 DataType::Vec4 => write!(f, "vec4"),
51 DataType::Mat3 => write!(f, "mat3"),
52 DataType::Mat4 => write!(f, "mat4"),
53 DataType::Sampler2D => write!(f, "sampler2D"),
54 DataType::Bool => write!(f, "bool"),
55 DataType::Int => write!(f, "int"),
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
66pub struct Socket {
67 pub name: String,
68 pub data_type: DataType,
69 pub direction: SocketDirection,
70 pub default_value: Option<ParamValue>,
71}
72
73impl Socket {
74 pub fn input(name: &str, dt: DataType) -> Self {
75 Self { name: name.to_string(), data_type: dt, direction: SocketDirection::Input, default_value: None }
76 }
77
78 pub fn input_default(name: &str, dt: DataType, val: ParamValue) -> Self {
79 Self { name: name.to_string(), data_type: dt, direction: SocketDirection::Input, default_value: Some(val) }
80 }
81
82 pub fn output(name: &str, dt: DataType) -> Self {
83 Self { name: name.to_string(), data_type: dt, direction: SocketDirection::Output, default_value: None }
84 }
85}
86
87#[derive(Debug, Clone, PartialEq)]
93pub enum ParamValue {
94 Float(f32),
95 Vec2([f32; 2]),
96 Vec3([f32; 3]),
97 Vec4([f32; 4]),
98 Int(i32),
99 Bool(bool),
100 String(String),
101}
102
103impl ParamValue {
104 pub fn as_float(&self) -> Option<f32> {
105 match self { ParamValue::Float(v) => Some(*v), _ => None }
106 }
107 pub fn as_vec2(&self) -> Option<[f32; 2]> {
108 match self { ParamValue::Vec2(v) => Some(*v), _ => None }
109 }
110 pub fn as_vec3(&self) -> Option<[f32; 3]> {
111 match self { ParamValue::Vec3(v) => Some(*v), _ => None }
112 }
113 pub fn as_vec4(&self) -> Option<[f32; 4]> {
114 match self { ParamValue::Vec4(v) => Some(*v), _ => None }
115 }
116 pub fn as_int(&self) -> Option<i32> {
117 match self { ParamValue::Int(v) => Some(*v), _ => None }
118 }
119 pub fn as_bool(&self) -> Option<bool> {
120 match self { ParamValue::Bool(v) => Some(*v), _ => None }
121 }
122 pub fn as_string(&self) -> Option<&str> {
123 match self { ParamValue::String(v) => Some(v.as_str()), _ => None }
124 }
125
126 pub fn to_glsl(&self) -> String {
128 match self {
129 ParamValue::Float(v) => format_float(*v),
130 ParamValue::Vec2(v) => format!("vec2({}, {})", format_float(v[0]), format_float(v[1])),
131 ParamValue::Vec3(v) => format!("vec3({}, {}, {})", format_float(v[0]), format_float(v[1]), format_float(v[2])),
132 ParamValue::Vec4(v) => format!("vec4({}, {}, {}, {})", format_float(v[0]), format_float(v[1]), format_float(v[2]), format_float(v[3])),
133 ParamValue::Int(v) => format!("{}", v),
134 ParamValue::Bool(v) => if *v { "true".to_string() } else { "false".to_string() },
135 ParamValue::String(v) => v.clone(),
136 }
137 }
138
139 pub fn data_type(&self) -> DataType {
141 match self {
142 ParamValue::Float(_) => DataType::Float,
143 ParamValue::Vec2(_) => DataType::Vec2,
144 ParamValue::Vec3(_) => DataType::Vec3,
145 ParamValue::Vec4(_) => DataType::Vec4,
146 ParamValue::Int(_) => DataType::Int,
147 ParamValue::Bool(_) => DataType::Bool,
148 ParamValue::String(_) => DataType::Float, }
150 }
151}
152
153fn format_float(v: f32) -> String {
154 if v == v.floor() && v.abs() < 1e9 {
155 format!("{:.1}", v)
156 } else {
157 format!("{}", v)
158 }
159}
160
161#[derive(Debug, Clone, PartialEq)]
167pub enum NodeType {
168 Color,
170 Texture,
171 VertexPosition,
172 VertexNormal,
173 Time,
174 CameraPos,
175 GameStateVar,
176
177 Translate,
179 Rotate,
180 Scale,
181 WorldToLocal,
182 LocalToWorld,
183
184 Add,
186 Sub,
187 Mul,
188 Div,
189 Dot,
190 Cross,
191 Normalize,
192 Length,
193 Abs,
194 Floor,
195 Ceil,
196 Fract,
197 Mod,
198 Pow,
199 Sqrt,
200 Sin,
201 Cos,
202 Tan,
203 Atan2,
204 Lerp,
205 Clamp,
206 Smoothstep,
207 Remap,
208 Step,
209
210 Fresnel,
212 Dissolve,
213 Distortion,
214 Blur,
215 Sharpen,
216 EdgeDetect,
217 Outline,
218 Bloom,
219 ChromaticAberration,
220
221 HSVToRGB,
223 RGBToHSV,
224 Contrast,
225 Saturation,
226 Hue,
227 Invert,
228 Posterize,
229 GradientMap,
230
231 Perlin,
233 Simplex,
234 Voronoi,
235 FBM,
236 Turbulence,
237
238 MainColor,
240 EmissionBuffer,
241 BloomBuffer,
242 NormalOutput,
243}
244
245impl NodeType {
246 pub fn display_name(&self) -> &'static str {
248 match self {
249 NodeType::Color => "Color",
250 NodeType::Texture => "Texture Sample",
251 NodeType::VertexPosition => "Vertex Position",
252 NodeType::VertexNormal => "Vertex Normal",
253 NodeType::Time => "Time",
254 NodeType::CameraPos => "Camera Position",
255 NodeType::GameStateVar => "Game State Variable",
256 NodeType::Translate => "Translate",
257 NodeType::Rotate => "Rotate",
258 NodeType::Scale => "Scale",
259 NodeType::WorldToLocal => "World To Local",
260 NodeType::LocalToWorld => "Local To World",
261 NodeType::Add => "Add",
262 NodeType::Sub => "Subtract",
263 NodeType::Mul => "Multiply",
264 NodeType::Div => "Divide",
265 NodeType::Dot => "Dot Product",
266 NodeType::Cross => "Cross Product",
267 NodeType::Normalize => "Normalize",
268 NodeType::Length => "Length",
269 NodeType::Abs => "Absolute",
270 NodeType::Floor => "Floor",
271 NodeType::Ceil => "Ceil",
272 NodeType::Fract => "Fract",
273 NodeType::Mod => "Modulo",
274 NodeType::Pow => "Power",
275 NodeType::Sqrt => "Square Root",
276 NodeType::Sin => "Sine",
277 NodeType::Cos => "Cosine",
278 NodeType::Tan => "Tangent",
279 NodeType::Atan2 => "Atan2",
280 NodeType::Lerp => "Lerp",
281 NodeType::Clamp => "Clamp",
282 NodeType::Smoothstep => "Smoothstep",
283 NodeType::Remap => "Remap",
284 NodeType::Step => "Step",
285 NodeType::Fresnel => "Fresnel",
286 NodeType::Dissolve => "Dissolve",
287 NodeType::Distortion => "Distortion",
288 NodeType::Blur => "Blur",
289 NodeType::Sharpen => "Sharpen",
290 NodeType::EdgeDetect => "Edge Detect",
291 NodeType::Outline => "Outline",
292 NodeType::Bloom => "Bloom",
293 NodeType::ChromaticAberration => "Chromatic Aberration",
294 NodeType::HSVToRGB => "HSV to RGB",
295 NodeType::RGBToHSV => "RGB to HSV",
296 NodeType::Contrast => "Contrast",
297 NodeType::Saturation => "Saturation",
298 NodeType::Hue => "Hue Shift",
299 NodeType::Invert => "Invert",
300 NodeType::Posterize => "Posterize",
301 NodeType::GradientMap => "Gradient Map",
302 NodeType::Perlin => "Perlin Noise",
303 NodeType::Simplex => "Simplex Noise",
304 NodeType::Voronoi => "Voronoi",
305 NodeType::FBM => "FBM",
306 NodeType::Turbulence => "Turbulence",
307 NodeType::MainColor => "Main Color Output",
308 NodeType::EmissionBuffer => "Emission Buffer",
309 NodeType::BloomBuffer => "Bloom Buffer",
310 NodeType::NormalOutput => "Normal Output",
311 }
312 }
313
314 pub fn category(&self) -> &'static str {
316 match self {
317 NodeType::Color | NodeType::Texture | NodeType::VertexPosition
318 | NodeType::VertexNormal | NodeType::Time | NodeType::CameraPos
319 | NodeType::GameStateVar => "Source",
320
321 NodeType::Translate | NodeType::Rotate | NodeType::Scale
322 | NodeType::WorldToLocal | NodeType::LocalToWorld => "Transform",
323
324 NodeType::Add | NodeType::Sub | NodeType::Mul | NodeType::Div
325 | NodeType::Dot | NodeType::Cross | NodeType::Normalize | NodeType::Length
326 | NodeType::Abs | NodeType::Floor | NodeType::Ceil | NodeType::Fract
327 | NodeType::Mod | NodeType::Pow | NodeType::Sqrt | NodeType::Sin
328 | NodeType::Cos | NodeType::Tan | NodeType::Atan2 | NodeType::Lerp
329 | NodeType::Clamp | NodeType::Smoothstep | NodeType::Remap
330 | NodeType::Step => "Math",
331
332 NodeType::Fresnel | NodeType::Dissolve | NodeType::Distortion
333 | NodeType::Blur | NodeType::Sharpen | NodeType::EdgeDetect
334 | NodeType::Outline | NodeType::Bloom
335 | NodeType::ChromaticAberration => "Effect",
336
337 NodeType::HSVToRGB | NodeType::RGBToHSV | NodeType::Contrast
338 | NodeType::Saturation | NodeType::Hue | NodeType::Invert
339 | NodeType::Posterize | NodeType::GradientMap => "Color",
340
341 NodeType::Perlin | NodeType::Simplex | NodeType::Voronoi
342 | NodeType::FBM | NodeType::Turbulence => "Noise",
343
344 NodeType::MainColor | NodeType::EmissionBuffer | NodeType::BloomBuffer
345 | NodeType::NormalOutput => "Output",
346 }
347 }
348
349 pub fn is_output(&self) -> bool {
351 matches!(self, NodeType::MainColor | NodeType::EmissionBuffer | NodeType::BloomBuffer | NodeType::NormalOutput)
352 }
353
354 pub fn is_pure_math(&self) -> bool {
356 matches!(self,
357 NodeType::Add | NodeType::Sub | NodeType::Mul | NodeType::Div
358 | NodeType::Dot | NodeType::Cross | NodeType::Normalize | NodeType::Length
359 | NodeType::Abs | NodeType::Floor | NodeType::Ceil | NodeType::Fract
360 | NodeType::Mod | NodeType::Pow | NodeType::Sqrt | NodeType::Sin
361 | NodeType::Cos | NodeType::Tan | NodeType::Atan2 | NodeType::Lerp
362 | NodeType::Clamp | NodeType::Smoothstep | NodeType::Remap | NodeType::Step
363 | NodeType::HSVToRGB | NodeType::RGBToHSV | NodeType::Contrast
364 | NodeType::Saturation | NodeType::Hue | NodeType::Invert
365 | NodeType::Posterize
366 )
367 }
368
369 pub fn is_source(&self) -> bool {
371 matches!(self,
372 NodeType::Color | NodeType::Texture | NodeType::VertexPosition
373 | NodeType::VertexNormal | NodeType::Time | NodeType::CameraPos
374 | NodeType::GameStateVar
375 )
376 }
377
378 pub fn instruction_cost(&self) -> u32 {
380 match self {
381 NodeType::Color => 0,
383 NodeType::VertexPosition | NodeType::VertexNormal | NodeType::CameraPos => 1,
384 NodeType::Time => 0,
385 NodeType::GameStateVar => 1,
386 NodeType::Texture => 4,
387
388 NodeType::Translate | NodeType::Scale => 3,
390 NodeType::Rotate => 8,
391 NodeType::WorldToLocal | NodeType::LocalToWorld => 16,
392
393 NodeType::Add | NodeType::Sub => 1,
395 NodeType::Mul => 1,
396 NodeType::Div => 2,
397 NodeType::Dot => 3,
398 NodeType::Cross => 6,
399 NodeType::Normalize => 4,
400 NodeType::Length => 3,
401 NodeType::Abs | NodeType::Floor | NodeType::Ceil | NodeType::Fract => 1,
402 NodeType::Mod => 2,
403 NodeType::Pow => 4,
404 NodeType::Sqrt => 2,
405 NodeType::Sin | NodeType::Cos | NodeType::Tan => 4,
406 NodeType::Atan2 => 6,
407 NodeType::Lerp => 3,
408 NodeType::Clamp => 2,
409 NodeType::Smoothstep => 5,
410 NodeType::Remap => 6,
411 NodeType::Step => 1,
412
413 NodeType::Fresnel => 8,
415 NodeType::Dissolve => 12,
416 NodeType::Distortion => 10,
417 NodeType::Blur => 32,
418 NodeType::Sharpen => 20,
419 NodeType::EdgeDetect => 24,
420 NodeType::Outline => 16,
421 NodeType::Bloom => 28,
422 NodeType::ChromaticAberration => 18,
423
424 NodeType::HSVToRGB | NodeType::RGBToHSV => 10,
426 NodeType::Contrast | NodeType::Saturation | NodeType::Hue => 6,
427 NodeType::Invert => 1,
428 NodeType::Posterize => 4,
429 NodeType::GradientMap => 8,
430
431 NodeType::Perlin => 20,
433 NodeType::Simplex => 24,
434 NodeType::Voronoi => 30,
435 NodeType::FBM => 60,
436 NodeType::Turbulence => 50,
437
438 NodeType::MainColor | NodeType::EmissionBuffer
440 | NodeType::BloomBuffer | NodeType::NormalOutput => 1,
441 }
442 }
443
444 pub fn default_inputs(&self) -> Vec<Socket> {
446 match self {
447 NodeType::Color => vec![
449 Socket::input_default("color", DataType::Vec4, ParamValue::Vec4([1.0, 1.0, 1.0, 1.0])),
450 ],
451 NodeType::Texture => vec![
452 Socket::input("uv", DataType::Vec2),
453 Socket::input_default("sampler", DataType::Sampler2D, ParamValue::Int(0)),
454 ],
455 NodeType::VertexPosition => vec![],
456 NodeType::VertexNormal => vec![],
457 NodeType::Time => vec![
458 Socket::input_default("speed", DataType::Float, ParamValue::Float(1.0)),
459 ],
460 NodeType::CameraPos => vec![],
461 NodeType::GameStateVar => vec![
462 Socket::input_default("var_name", DataType::Float, ParamValue::String("game_var_0".to_string())),
463 ],
464
465 NodeType::Translate => vec![
467 Socket::input("position", DataType::Vec3),
468 Socket::input_default("offset", DataType::Vec3, ParamValue::Vec3([0.0, 0.0, 0.0])),
469 ],
470 NodeType::Rotate => vec![
471 Socket::input("position", DataType::Vec3),
472 Socket::input_default("axis", DataType::Vec3, ParamValue::Vec3([0.0, 1.0, 0.0])),
473 Socket::input_default("angle", DataType::Float, ParamValue::Float(0.0)),
474 ],
475 NodeType::Scale => vec![
476 Socket::input("position", DataType::Vec3),
477 Socket::input_default("factor", DataType::Vec3, ParamValue::Vec3([1.0, 1.0, 1.0])),
478 ],
479 NodeType::WorldToLocal => vec![
480 Socket::input("position", DataType::Vec3),
481 Socket::input("matrix", DataType::Mat4),
482 ],
483 NodeType::LocalToWorld => vec![
484 Socket::input("position", DataType::Vec3),
485 Socket::input("matrix", DataType::Mat4),
486 ],
487
488 NodeType::Add => vec![
490 Socket::input_default("a", DataType::Float, ParamValue::Float(0.0)),
491 Socket::input_default("b", DataType::Float, ParamValue::Float(0.0)),
492 ],
493 NodeType::Sub => vec![
494 Socket::input_default("a", DataType::Float, ParamValue::Float(0.0)),
495 Socket::input_default("b", DataType::Float, ParamValue::Float(0.0)),
496 ],
497 NodeType::Mul => vec![
498 Socket::input_default("a", DataType::Float, ParamValue::Float(1.0)),
499 Socket::input_default("b", DataType::Float, ParamValue::Float(1.0)),
500 ],
501 NodeType::Div => vec![
502 Socket::input_default("a", DataType::Float, ParamValue::Float(1.0)),
503 Socket::input_default("b", DataType::Float, ParamValue::Float(1.0)),
504 ],
505 NodeType::Dot => vec![
506 Socket::input("a", DataType::Vec3),
507 Socket::input("b", DataType::Vec3),
508 ],
509 NodeType::Cross => vec![
510 Socket::input("a", DataType::Vec3),
511 Socket::input("b", DataType::Vec3),
512 ],
513 NodeType::Normalize => vec![
514 Socket::input("v", DataType::Vec3),
515 ],
516 NodeType::Length => vec![
517 Socket::input("v", DataType::Vec3),
518 ],
519 NodeType::Abs => vec![
520 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
521 ],
522 NodeType::Floor => vec![
523 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
524 ],
525 NodeType::Ceil => vec![
526 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
527 ],
528 NodeType::Fract => vec![
529 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
530 ],
531 NodeType::Mod => vec![
532 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
533 Socket::input_default("y", DataType::Float, ParamValue::Float(1.0)),
534 ],
535 NodeType::Pow => vec![
536 Socket::input_default("base", DataType::Float, ParamValue::Float(1.0)),
537 Socket::input_default("exp", DataType::Float, ParamValue::Float(1.0)),
538 ],
539 NodeType::Sqrt => vec![
540 Socket::input_default("x", DataType::Float, ParamValue::Float(1.0)),
541 ],
542 NodeType::Sin => vec![
543 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
544 ],
545 NodeType::Cos => vec![
546 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
547 ],
548 NodeType::Tan => vec![
549 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
550 ],
551 NodeType::Atan2 => vec![
552 Socket::input_default("y", DataType::Float, ParamValue::Float(0.0)),
553 Socket::input_default("x", DataType::Float, ParamValue::Float(1.0)),
554 ],
555 NodeType::Lerp => vec![
556 Socket::input_default("a", DataType::Float, ParamValue::Float(0.0)),
557 Socket::input_default("b", DataType::Float, ParamValue::Float(1.0)),
558 Socket::input_default("t", DataType::Float, ParamValue::Float(0.5)),
559 ],
560 NodeType::Clamp => vec![
561 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
562 Socket::input_default("min_val", DataType::Float, ParamValue::Float(0.0)),
563 Socket::input_default("max_val", DataType::Float, ParamValue::Float(1.0)),
564 ],
565 NodeType::Smoothstep => vec![
566 Socket::input_default("edge0", DataType::Float, ParamValue::Float(0.0)),
567 Socket::input_default("edge1", DataType::Float, ParamValue::Float(1.0)),
568 Socket::input_default("x", DataType::Float, ParamValue::Float(0.5)),
569 ],
570 NodeType::Remap => vec![
571 Socket::input_default("x", DataType::Float, ParamValue::Float(0.5)),
572 Socket::input_default("in_min", DataType::Float, ParamValue::Float(0.0)),
573 Socket::input_default("in_max", DataType::Float, ParamValue::Float(1.0)),
574 Socket::input_default("out_min", DataType::Float, ParamValue::Float(0.0)),
575 Socket::input_default("out_max", DataType::Float, ParamValue::Float(1.0)),
576 ],
577 NodeType::Step => vec![
578 Socket::input_default("edge", DataType::Float, ParamValue::Float(0.5)),
579 Socket::input_default("x", DataType::Float, ParamValue::Float(0.0)),
580 ],
581
582 NodeType::Fresnel => vec![
584 Socket::input("normal", DataType::Vec3),
585 Socket::input("view_dir", DataType::Vec3),
586 Socket::input_default("power", DataType::Float, ParamValue::Float(2.0)),
587 Socket::input_default("bias", DataType::Float, ParamValue::Float(0.0)),
588 ],
589 NodeType::Dissolve => vec![
590 Socket::input("color", DataType::Vec4),
591 Socket::input_default("noise", DataType::Float, ParamValue::Float(0.5)),
592 Socket::input_default("threshold", DataType::Float, ParamValue::Float(0.5)),
593 Socket::input_default("edge_width", DataType::Float, ParamValue::Float(0.05)),
594 Socket::input_default("edge_color", DataType::Vec4, ParamValue::Vec4([1.0, 0.5, 0.0, 1.0])),
595 ],
596 NodeType::Distortion => vec![
597 Socket::input("uv", DataType::Vec2),
598 Socket::input_default("strength", DataType::Float, ParamValue::Float(0.1)),
599 Socket::input_default("direction", DataType::Vec2, ParamValue::Vec2([1.0, 0.0])),
600 Socket::input_default("noise", DataType::Float, ParamValue::Float(0.0)),
601 ],
602 NodeType::Blur => vec![
603 Socket::input("uv", DataType::Vec2),
604 Socket::input_default("radius", DataType::Float, ParamValue::Float(2.0)),
605 Socket::input_default("samples", DataType::Int, ParamValue::Int(8)),
606 Socket::input("sampler", DataType::Sampler2D),
607 ],
608 NodeType::Sharpen => vec![
609 Socket::input("uv", DataType::Vec2),
610 Socket::input_default("strength", DataType::Float, ParamValue::Float(1.0)),
611 Socket::input("sampler", DataType::Sampler2D),
612 ],
613 NodeType::EdgeDetect => vec![
614 Socket::input("uv", DataType::Vec2),
615 Socket::input_default("threshold", DataType::Float, ParamValue::Float(0.1)),
616 Socket::input("sampler", DataType::Sampler2D),
617 ],
618 NodeType::Outline => vec![
619 Socket::input("color", DataType::Vec4),
620 Socket::input("depth", DataType::Float),
621 Socket::input("normal", DataType::Vec3),
622 Socket::input_default("width", DataType::Float, ParamValue::Float(1.0)),
623 Socket::input_default("outline_color", DataType::Vec4, ParamValue::Vec4([0.0, 0.0, 0.0, 1.0])),
624 ],
625 NodeType::Bloom => vec![
626 Socket::input("color", DataType::Vec4),
627 Socket::input_default("threshold", DataType::Float, ParamValue::Float(0.8)),
628 Socket::input_default("intensity", DataType::Float, ParamValue::Float(1.5)),
629 Socket::input_default("radius", DataType::Float, ParamValue::Float(4.0)),
630 ],
631 NodeType::ChromaticAberration => vec![
632 Socket::input("uv", DataType::Vec2),
633 Socket::input_default("offset", DataType::Float, ParamValue::Float(0.005)),
634 Socket::input("sampler", DataType::Sampler2D),
635 ],
636
637 NodeType::HSVToRGB => vec![
639 Socket::input_default("h", DataType::Float, ParamValue::Float(0.0)),
640 Socket::input_default("s", DataType::Float, ParamValue::Float(1.0)),
641 Socket::input_default("v", DataType::Float, ParamValue::Float(1.0)),
642 ],
643 NodeType::RGBToHSV => vec![
644 Socket::input("rgb", DataType::Vec3),
645 ],
646 NodeType::Contrast => vec![
647 Socket::input("color", DataType::Vec3),
648 Socket::input_default("amount", DataType::Float, ParamValue::Float(1.0)),
649 ],
650 NodeType::Saturation => vec![
651 Socket::input("color", DataType::Vec3),
652 Socket::input_default("amount", DataType::Float, ParamValue::Float(1.0)),
653 ],
654 NodeType::Hue => vec![
655 Socket::input("color", DataType::Vec3),
656 Socket::input_default("shift", DataType::Float, ParamValue::Float(0.0)),
657 ],
658 NodeType::Invert => vec![
659 Socket::input("color", DataType::Vec3),
660 ],
661 NodeType::Posterize => vec![
662 Socket::input("color", DataType::Vec3),
663 Socket::input_default("levels", DataType::Float, ParamValue::Float(4.0)),
664 ],
665 NodeType::GradientMap => vec![
666 Socket::input_default("t", DataType::Float, ParamValue::Float(0.5)),
667 Socket::input_default("color_a", DataType::Vec3, ParamValue::Vec3([0.0, 0.0, 0.0])),
668 Socket::input_default("color_b", DataType::Vec3, ParamValue::Vec3([1.0, 1.0, 1.0])),
669 ],
670
671 NodeType::Perlin => vec![
673 Socket::input("position", DataType::Vec3),
674 Socket::input_default("scale", DataType::Float, ParamValue::Float(1.0)),
675 Socket::input_default("seed", DataType::Float, ParamValue::Float(0.0)),
676 ],
677 NodeType::Simplex => vec![
678 Socket::input("position", DataType::Vec3),
679 Socket::input_default("scale", DataType::Float, ParamValue::Float(1.0)),
680 Socket::input_default("seed", DataType::Float, ParamValue::Float(0.0)),
681 ],
682 NodeType::Voronoi => vec![
683 Socket::input("position", DataType::Vec3),
684 Socket::input_default("scale", DataType::Float, ParamValue::Float(1.0)),
685 Socket::input_default("jitter", DataType::Float, ParamValue::Float(1.0)),
686 ],
687 NodeType::FBM => vec![
688 Socket::input("position", DataType::Vec3),
689 Socket::input_default("scale", DataType::Float, ParamValue::Float(1.0)),
690 Socket::input_default("octaves", DataType::Int, ParamValue::Int(4)),
691 Socket::input_default("lacunarity", DataType::Float, ParamValue::Float(2.0)),
692 Socket::input_default("gain", DataType::Float, ParamValue::Float(0.5)),
693 ],
694 NodeType::Turbulence => vec![
695 Socket::input("position", DataType::Vec3),
696 Socket::input_default("scale", DataType::Float, ParamValue::Float(1.0)),
697 Socket::input_default("octaves", DataType::Int, ParamValue::Int(4)),
698 Socket::input_default("lacunarity", DataType::Float, ParamValue::Float(2.0)),
699 Socket::input_default("gain", DataType::Float, ParamValue::Float(0.5)),
700 ],
701
702 NodeType::MainColor => vec![
704 Socket::input("color", DataType::Vec4),
705 ],
706 NodeType::EmissionBuffer => vec![
707 Socket::input("emission", DataType::Vec4),
708 ],
709 NodeType::BloomBuffer => vec![
710 Socket::input("bloom", DataType::Vec4),
711 ],
712 NodeType::NormalOutput => vec![
713 Socket::input("normal", DataType::Vec3),
714 ],
715 }
716 }
717
718 pub fn default_outputs(&self) -> Vec<Socket> {
720 match self {
721 NodeType::Color => vec![Socket::output("color", DataType::Vec4)],
723 NodeType::Texture => vec![
724 Socket::output("color", DataType::Vec4),
725 Socket::output("r", DataType::Float),
726 Socket::output("g", DataType::Float),
727 Socket::output("b", DataType::Float),
728 Socket::output("a", DataType::Float),
729 ],
730 NodeType::VertexPosition => vec![Socket::output("position", DataType::Vec3)],
731 NodeType::VertexNormal => vec![Socket::output("normal", DataType::Vec3)],
732 NodeType::Time => vec![
733 Socket::output("time", DataType::Float),
734 Socket::output("sin_time", DataType::Float),
735 Socket::output("cos_time", DataType::Float),
736 Socket::output("fract_time", DataType::Float),
737 ],
738 NodeType::CameraPos => vec![Socket::output("position", DataType::Vec3)],
739 NodeType::GameStateVar => vec![Socket::output("value", DataType::Float)],
740
741 NodeType::Translate | NodeType::Rotate | NodeType::Scale
743 | NodeType::WorldToLocal | NodeType::LocalToWorld => {
744 vec![Socket::output("result", DataType::Vec3)]
745 }
746
747 NodeType::Add | NodeType::Sub | NodeType::Mul | NodeType::Div => {
749 vec![Socket::output("result", DataType::Float)]
750 }
751 NodeType::Dot => vec![Socket::output("result", DataType::Float)],
752 NodeType::Cross => vec![Socket::output("result", DataType::Vec3)],
753 NodeType::Normalize => vec![Socket::output("result", DataType::Vec3)],
754 NodeType::Length => vec![Socket::output("result", DataType::Float)],
755 NodeType::Abs | NodeType::Floor | NodeType::Ceil | NodeType::Fract
756 | NodeType::Mod | NodeType::Pow | NodeType::Sqrt => {
757 vec![Socket::output("result", DataType::Float)]
758 }
759 NodeType::Sin | NodeType::Cos | NodeType::Tan | NodeType::Atan2 => {
760 vec![Socket::output("result", DataType::Float)]
761 }
762 NodeType::Lerp | NodeType::Clamp | NodeType::Smoothstep
763 | NodeType::Remap | NodeType::Step => {
764 vec![Socket::output("result", DataType::Float)]
765 }
766
767 NodeType::Fresnel => vec![Socket::output("factor", DataType::Float)],
769 NodeType::Dissolve => vec![
770 Socket::output("color", DataType::Vec4),
771 Socket::output("mask", DataType::Float),
772 ],
773 NodeType::Distortion => vec![Socket::output("uv", DataType::Vec2)],
774 NodeType::Blur => vec![Socket::output("color", DataType::Vec4)],
775 NodeType::Sharpen => vec![Socket::output("color", DataType::Vec4)],
776 NodeType::EdgeDetect => vec![Socket::output("edges", DataType::Float)],
777 NodeType::Outline => vec![Socket::output("color", DataType::Vec4)],
778 NodeType::Bloom => vec![
779 Socket::output("color", DataType::Vec4),
780 Socket::output("bloom_mask", DataType::Float),
781 ],
782 NodeType::ChromaticAberration => vec![Socket::output("color", DataType::Vec4)],
783
784 NodeType::HSVToRGB => vec![Socket::output("rgb", DataType::Vec3)],
786 NodeType::RGBToHSV => vec![
787 Socket::output("h", DataType::Float),
788 Socket::output("s", DataType::Float),
789 Socket::output("v", DataType::Float),
790 ],
791 NodeType::Contrast | NodeType::Saturation | NodeType::Hue
792 | NodeType::Invert | NodeType::Posterize => {
793 vec![Socket::output("color", DataType::Vec3)]
794 }
795 NodeType::GradientMap => vec![Socket::output("color", DataType::Vec3)],
796
797 NodeType::Perlin | NodeType::Simplex => vec![
799 Socket::output("value", DataType::Float),
800 Socket::output("gradient", DataType::Vec3),
801 ],
802 NodeType::Voronoi => vec![
803 Socket::output("distance", DataType::Float),
804 Socket::output("cell_id", DataType::Float),
805 Socket::output("cell_pos", DataType::Vec3),
806 ],
807 NodeType::FBM | NodeType::Turbulence => vec![
808 Socket::output("value", DataType::Float),
809 ],
810
811 NodeType::MainColor | NodeType::EmissionBuffer
813 | NodeType::BloomBuffer | NodeType::NormalOutput => vec![],
814 }
815 }
816
817 pub fn generate_glsl(&self, var_prefix: &str, input_vars: &[String]) -> GlslSnippet {
824 let mut lines = Vec::new();
825 let mut outputs: Vec<String> = Vec::new();
826
827 match self {
828 NodeType::Color => {
830 let inp = input_or_default(input_vars, 0, "vec4(1.0, 1.0, 1.0, 1.0)");
831 let out = format!("{}_color", var_prefix);
832 lines.push(format!("vec4 {} = {};", out, inp));
833 outputs.push(out);
834 }
835 NodeType::Texture => {
836 let uv = input_or_default(input_vars, 0, "v_uv");
837 let sampler = input_or_default(input_vars, 1, "u_texture0");
838 let out = format!("{}_tex", var_prefix);
839 lines.push(format!("vec4 {} = texture2D({}, {});", out, sampler, uv));
840 outputs.push(format!("{}", out));
841 outputs.push(format!("{}.r", out));
842 outputs.push(format!("{}.g", out));
843 outputs.push(format!("{}.b", out));
844 outputs.push(format!("{}.a", out));
845 }
846 NodeType::VertexPosition => {
847 let out = format!("{}_vpos", var_prefix);
848 lines.push(format!("vec3 {} = v_position;", out));
849 outputs.push(out);
850 }
851 NodeType::VertexNormal => {
852 let out = format!("{}_vnorm", var_prefix);
853 lines.push(format!("vec3 {} = v_normal;", out));
854 outputs.push(out);
855 }
856 NodeType::Time => {
857 let speed = input_or_default(input_vars, 0, "1.0");
858 let t = format!("{}_t", var_prefix);
859 lines.push(format!("float {} = u_time * {};", t, speed));
860 outputs.push(t.clone());
861 outputs.push(format!("sin({})", t));
862 outputs.push(format!("cos({})", t));
863 outputs.push(format!("fract({})", t));
864 }
865 NodeType::CameraPos => {
866 let out = format!("{}_campos", var_prefix);
867 lines.push(format!("vec3 {} = u_camera_pos;", out));
868 outputs.push(out);
869 }
870 NodeType::GameStateVar => {
871 let var_name = input_or_default(input_vars, 0, "game_var_0");
872 let out = format!("{}_gsv", var_prefix);
873 let uniform_name = if var_name.starts_with("u_gs_") {
875 var_name.clone()
876 } else {
877 format!("u_gs_{}", var_name.trim_matches('"'))
878 };
879 lines.push(format!("float {} = {};", out, uniform_name));
880 outputs.push(out);
881 }
882
883 NodeType::Translate => {
885 let pos = input_or_default(input_vars, 0, "vec3(0.0)");
886 let offset = input_or_default(input_vars, 1, "vec3(0.0)");
887 let out = format!("{}_trans", var_prefix);
888 lines.push(format!("vec3 {} = {} + {};", out, pos, offset));
889 outputs.push(out);
890 }
891 NodeType::Rotate => {
892 let pos = input_or_default(input_vars, 0, "vec3(0.0)");
893 let axis = input_or_default(input_vars, 1, "vec3(0.0, 1.0, 0.0)");
894 let angle = input_or_default(input_vars, 2, "0.0");
895 let out = format!("{}_rot", var_prefix);
896 lines.push(format!("vec3 {out}_k = normalize({axis});"));
898 lines.push(format!("float {out}_c = cos({angle});"));
899 lines.push(format!("float {out}_s = sin({angle});"));
900 lines.push(format!(
901 "vec3 {out} = {pos} * {out}_c + cross({out}_k, {pos}) * {out}_s + {out}_k * dot({out}_k, {pos}) * (1.0 - {out}_c);",
902 ));
903 outputs.push(out);
904 }
905 NodeType::Scale => {
906 let pos = input_or_default(input_vars, 0, "vec3(0.0)");
907 let factor = input_or_default(input_vars, 1, "vec3(1.0)");
908 let out = format!("{}_scl", var_prefix);
909 lines.push(format!("vec3 {} = {} * {};", out, pos, factor));
910 outputs.push(out);
911 }
912 NodeType::WorldToLocal => {
913 let pos = input_or_default(input_vars, 0, "vec3(0.0)");
914 let mat = input_or_default(input_vars, 1, "u_inv_model");
915 let out = format!("{}_w2l", var_prefix);
916 lines.push(format!("vec3 {} = ({} * vec4({}, 1.0)).xyz;", out, mat, pos));
917 outputs.push(out);
918 }
919 NodeType::LocalToWorld => {
920 let pos = input_or_default(input_vars, 0, "vec3(0.0)");
921 let mat = input_or_default(input_vars, 1, "u_model");
922 let out = format!("{}_l2w", var_prefix);
923 lines.push(format!("vec3 {} = ({} * vec4({}, 1.0)).xyz;", out, mat, pos));
924 outputs.push(out);
925 }
926
927 NodeType::Add => {
929 let a = input_or_default(input_vars, 0, "0.0");
930 let b = input_or_default(input_vars, 1, "0.0");
931 let out = format!("{}_add", var_prefix);
932 lines.push(format!("float {} = {} + {};", out, a, b));
933 outputs.push(out);
934 }
935 NodeType::Sub => {
936 let a = input_or_default(input_vars, 0, "0.0");
937 let b = input_or_default(input_vars, 1, "0.0");
938 let out = format!("{}_sub", var_prefix);
939 lines.push(format!("float {} = {} - {};", out, a, b));
940 outputs.push(out);
941 }
942 NodeType::Mul => {
943 let a = input_or_default(input_vars, 0, "1.0");
944 let b = input_or_default(input_vars, 1, "1.0");
945 let out = format!("{}_mul", var_prefix);
946 lines.push(format!("float {} = {} * {};", out, a, b));
947 outputs.push(out);
948 }
949 NodeType::Div => {
950 let a = input_or_default(input_vars, 0, "1.0");
951 let b = input_or_default(input_vars, 1, "1.0");
952 let out = format!("{}_div", var_prefix);
953 lines.push(format!("float {} = {} / max({}, 0.0001);", out, a, b));
954 outputs.push(out);
955 }
956 NodeType::Dot => {
957 let a = input_or_default(input_vars, 0, "vec3(0.0)");
958 let b = input_or_default(input_vars, 1, "vec3(0.0)");
959 let out = format!("{}_dot", var_prefix);
960 lines.push(format!("float {} = dot({}, {});", out, a, b));
961 outputs.push(out);
962 }
963 NodeType::Cross => {
964 let a = input_or_default(input_vars, 0, "vec3(0.0)");
965 let b = input_or_default(input_vars, 1, "vec3(0.0)");
966 let out = format!("{}_cross", var_prefix);
967 lines.push(format!("vec3 {} = cross({}, {});", out, a, b));
968 outputs.push(out);
969 }
970 NodeType::Normalize => {
971 let v = input_or_default(input_vars, 0, "vec3(0.0, 1.0, 0.0)");
972 let out = format!("{}_norm", var_prefix);
973 lines.push(format!("vec3 {} = normalize({});", out, v));
974 outputs.push(out);
975 }
976 NodeType::Length => {
977 let v = input_or_default(input_vars, 0, "vec3(0.0)");
978 let out = format!("{}_len", var_prefix);
979 lines.push(format!("float {} = length({});", out, v));
980 outputs.push(out);
981 }
982 NodeType::Abs => {
983 let x = input_or_default(input_vars, 0, "0.0");
984 let out = format!("{}_abs", var_prefix);
985 lines.push(format!("float {} = abs({});", out, x));
986 outputs.push(out);
987 }
988 NodeType::Floor => {
989 let x = input_or_default(input_vars, 0, "0.0");
990 let out = format!("{}_floor", var_prefix);
991 lines.push(format!("float {} = floor({});", out, x));
992 outputs.push(out);
993 }
994 NodeType::Ceil => {
995 let x = input_or_default(input_vars, 0, "0.0");
996 let out = format!("{}_ceil", var_prefix);
997 lines.push(format!("float {} = ceil({});", out, x));
998 outputs.push(out);
999 }
1000 NodeType::Fract => {
1001 let x = input_or_default(input_vars, 0, "0.0");
1002 let out = format!("{}_fract", var_prefix);
1003 lines.push(format!("float {} = fract({});", out, x));
1004 outputs.push(out);
1005 }
1006 NodeType::Mod => {
1007 let x = input_or_default(input_vars, 0, "0.0");
1008 let y = input_or_default(input_vars, 1, "1.0");
1009 let out = format!("{}_mod", var_prefix);
1010 lines.push(format!("float {} = mod({}, {});", out, x, y));
1011 outputs.push(out);
1012 }
1013 NodeType::Pow => {
1014 let base = input_or_default(input_vars, 0, "1.0");
1015 let exp = input_or_default(input_vars, 1, "1.0");
1016 let out = format!("{}_pow", var_prefix);
1017 lines.push(format!("float {} = pow(max({}, 0.0), {});", out, base, exp));
1018 outputs.push(out);
1019 }
1020 NodeType::Sqrt => {
1021 let x = input_or_default(input_vars, 0, "1.0");
1022 let out = format!("{}_sqrt", var_prefix);
1023 lines.push(format!("float {} = sqrt(max({}, 0.0));", out, x));
1024 outputs.push(out);
1025 }
1026 NodeType::Sin => {
1027 let x = input_or_default(input_vars, 0, "0.0");
1028 let out = format!("{}_sin", var_prefix);
1029 lines.push(format!("float {} = sin({});", out, x));
1030 outputs.push(out);
1031 }
1032 NodeType::Cos => {
1033 let x = input_or_default(input_vars, 0, "0.0");
1034 let out = format!("{}_cos", var_prefix);
1035 lines.push(format!("float {} = cos({});", out, x));
1036 outputs.push(out);
1037 }
1038 NodeType::Tan => {
1039 let x = input_or_default(input_vars, 0, "0.0");
1040 let out = format!("{}_tan", var_prefix);
1041 lines.push(format!("float {} = tan({});", out, x));
1042 outputs.push(out);
1043 }
1044 NodeType::Atan2 => {
1045 let y = input_or_default(input_vars, 0, "0.0");
1046 let x = input_or_default(input_vars, 1, "1.0");
1047 let out = format!("{}_atan2", var_prefix);
1048 lines.push(format!("float {} = atan({}, {});", out, y, x));
1049 outputs.push(out);
1050 }
1051 NodeType::Lerp => {
1052 let a = input_or_default(input_vars, 0, "0.0");
1053 let b = input_or_default(input_vars, 1, "1.0");
1054 let t = input_or_default(input_vars, 2, "0.5");
1055 let out = format!("{}_lerp", var_prefix);
1056 lines.push(format!("float {} = mix({}, {}, {});", out, a, b, t));
1057 outputs.push(out);
1058 }
1059 NodeType::Clamp => {
1060 let x = input_or_default(input_vars, 0, "0.0");
1061 let lo = input_or_default(input_vars, 1, "0.0");
1062 let hi = input_or_default(input_vars, 2, "1.0");
1063 let out = format!("{}_clamp", var_prefix);
1064 lines.push(format!("float {} = clamp({}, {}, {});", out, x, lo, hi));
1065 outputs.push(out);
1066 }
1067 NodeType::Smoothstep => {
1068 let e0 = input_or_default(input_vars, 0, "0.0");
1069 let e1 = input_or_default(input_vars, 1, "1.0");
1070 let x = input_or_default(input_vars, 2, "0.5");
1071 let out = format!("{}_ss", var_prefix);
1072 lines.push(format!("float {} = smoothstep({}, {}, {});", out, e0, e1, x));
1073 outputs.push(out);
1074 }
1075 NodeType::Remap => {
1076 let x = input_or_default(input_vars, 0, "0.5");
1077 let in_min = input_or_default(input_vars, 1, "0.0");
1078 let in_max = input_or_default(input_vars, 2, "1.0");
1079 let out_min = input_or_default(input_vars, 3, "0.0");
1080 let out_max = input_or_default(input_vars, 4, "1.0");
1081 let out = format!("{}_remap", var_prefix);
1082 lines.push(format!(
1083 "float {} = {} + ({} - {}) * (({}) - {}) / max(({}) - {}, 0.0001);",
1084 out, out_min, out_max, out_min, x, in_min, in_max, in_min
1085 ));
1086 outputs.push(out);
1087 }
1088 NodeType::Step => {
1089 let edge = input_or_default(input_vars, 0, "0.5");
1090 let x = input_or_default(input_vars, 1, "0.0");
1091 let out = format!("{}_step", var_prefix);
1092 lines.push(format!("float {} = step({}, {});", out, edge, x));
1093 outputs.push(out);
1094 }
1095
1096 NodeType::Fresnel => {
1098 let normal = input_or_default(input_vars, 0, "v_normal");
1099 let view = input_or_default(input_vars, 1, "normalize(u_camera_pos - v_position)");
1100 let power = input_or_default(input_vars, 2, "2.0");
1101 let bias = input_or_default(input_vars, 3, "0.0");
1102 let out = format!("{}_fresnel", var_prefix);
1103 lines.push(format!(
1104 "float {} = {} + (1.0 - {}) * pow(1.0 - max(dot({}, {}), 0.0), {});",
1105 out, bias, bias, normal, view, power
1106 ));
1107 outputs.push(out);
1108 }
1109 NodeType::Dissolve => {
1110 let color = input_or_default(input_vars, 0, "vec4(1.0)");
1111 let noise = input_or_default(input_vars, 1, "0.5");
1112 let thresh = input_or_default(input_vars, 2, "0.5");
1113 let edge_w = input_or_default(input_vars, 3, "0.05");
1114 let edge_c = input_or_default(input_vars, 4, "vec4(1.0, 0.5, 0.0, 1.0)");
1115 let out = format!("{}_diss", var_prefix);
1116 lines.push(format!("float {out}_mask = step({thresh}, {noise});"));
1117 lines.push(format!(
1118 "float {out}_edge = smoothstep({thresh} - {edge_w}, {thresh}, {noise}) - {out}_mask;"
1119 ));
1120 lines.push(format!(
1121 "vec4 {out} = mix({edge_c}, {color}, {out}_mask) * ({out}_mask + {out}_edge);"
1122 ));
1123 outputs.push(out.clone());
1124 outputs.push(format!("{}_mask", out));
1125 }
1126 NodeType::Distortion => {
1127 let uv = input_or_default(input_vars, 0, "v_uv");
1128 let strength = input_or_default(input_vars, 1, "0.1");
1129 let dir = input_or_default(input_vars, 2, "vec2(1.0, 0.0)");
1130 let noise = input_or_default(input_vars, 3, "0.0");
1131 let out = format!("{}_dist", var_prefix);
1132 lines.push(format!(
1133 "vec2 {} = {} + {} * {} * (1.0 + {});",
1134 out, uv, dir, strength, noise
1135 ));
1136 outputs.push(out);
1137 }
1138 NodeType::Blur => {
1139 let uv = input_or_default(input_vars, 0, "v_uv");
1140 let radius = input_or_default(input_vars, 1, "2.0");
1141 let _samples = input_or_default(input_vars, 2, "8");
1142 let sampler = input_or_default(input_vars, 3, "u_texture0");
1143 let out = format!("{}_blur", var_prefix);
1144 lines.push(format!("vec4 {out} = vec4(0.0);"));
1145 lines.push(format!("float {out}_total = 0.0;"));
1146 lines.push(format!("for (int i = -4; i <= 4; i++) {{"));
1148 lines.push(format!(" for (int j = -4; j <= 4; j++) {{"));
1149 lines.push(format!(" vec2 {out}_off = vec2(float(i), float(j)) * {radius} / 512.0;"));
1150 lines.push(format!(" float {out}_w = exp(-float(i*i + j*j) / (2.0 * {radius} * {radius}));"));
1151 lines.push(format!(" {out} += texture2D({sampler}, {uv} + {out}_off) * {out}_w;"));
1152 lines.push(format!(" {out}_total += {out}_w;"));
1153 lines.push(format!(" }}"));
1154 lines.push(format!("}}"));
1155 lines.push(format!("{out} /= max({out}_total, 0.001);"));
1156 outputs.push(out);
1157 }
1158 NodeType::Sharpen => {
1159 let uv = input_or_default(input_vars, 0, "v_uv");
1160 let strength = input_or_default(input_vars, 1, "1.0");
1161 let sampler = input_or_default(input_vars, 2, "u_texture0");
1162 let out = format!("{}_sharp", var_prefix);
1163 lines.push(format!("vec2 {out}_px = vec2(1.0/512.0, 1.0/512.0);"));
1164 lines.push(format!("vec4 {out}_c = texture2D({sampler}, {uv});"));
1165 lines.push(format!("vec4 {out}_n = texture2D({sampler}, {uv} + vec2(0.0, {out}_px.y));"));
1166 lines.push(format!("vec4 {out}_s = texture2D({sampler}, {uv} - vec2(0.0, {out}_px.y));"));
1167 lines.push(format!("vec4 {out}_e = texture2D({sampler}, {uv} + vec2({out}_px.x, 0.0));"));
1168 lines.push(format!("vec4 {out}_w = texture2D({sampler}, {uv} - vec2({out}_px.x, 0.0));"));
1169 lines.push(format!(
1170 "vec4 {out} = {out}_c + ({out}_c * 4.0 - {out}_n - {out}_s - {out}_e - {out}_w) * {strength};"
1171 ));
1172 outputs.push(out);
1173 }
1174 NodeType::EdgeDetect => {
1175 let uv = input_or_default(input_vars, 0, "v_uv");
1176 let threshold = input_or_default(input_vars, 1, "0.1");
1177 let sampler = input_or_default(input_vars, 2, "u_texture0");
1178 let out = format!("{}_edge", var_prefix);
1179 lines.push(format!("vec2 {out}_px = vec2(1.0/512.0);"));
1180 lines.push(format!("float {out}_tl = dot(texture2D({sampler}, {uv} + vec2(-1.0, 1.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1181 lines.push(format!("float {out}_t = dot(texture2D({sampler}, {uv} + vec2( 0.0, 1.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1182 lines.push(format!("float {out}_tr = dot(texture2D({sampler}, {uv} + vec2( 1.0, 1.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1183 lines.push(format!("float {out}_l = dot(texture2D({sampler}, {uv} + vec2(-1.0, 0.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1184 lines.push(format!("float {out}_r = dot(texture2D({sampler}, {uv} + vec2( 1.0, 0.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1185 lines.push(format!("float {out}_bl = dot(texture2D({sampler}, {uv} + vec2(-1.0,-1.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1186 lines.push(format!("float {out}_b = dot(texture2D({sampler}, {uv} + vec2( 0.0,-1.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1187 lines.push(format!("float {out}_br = dot(texture2D({sampler}, {uv} + vec2( 1.0,-1.0)*{out}_px).rgb, vec3(0.299, 0.587, 0.114));"));
1188 lines.push(format!("float {out}_gx = -1.0*{out}_tl + 1.0*{out}_tr - 2.0*{out}_l + 2.0*{out}_r - 1.0*{out}_bl + 1.0*{out}_br;"));
1189 lines.push(format!("float {out}_gy = -1.0*{out}_tl - 2.0*{out}_t - 1.0*{out}_tr + 1.0*{out}_bl + 2.0*{out}_b + 1.0*{out}_br;"));
1190 lines.push(format!("float {out} = step({threshold}, sqrt({out}_gx*{out}_gx + {out}_gy*{out}_gy));"));
1191 outputs.push(out);
1192 }
1193 NodeType::Outline => {
1194 let color = input_or_default(input_vars, 0, "vec4(1.0)");
1195 let _depth = input_or_default(input_vars, 1, "0.0");
1196 let normal = input_or_default(input_vars, 2, "v_normal");
1197 let width = input_or_default(input_vars, 3, "1.0");
1198 let outline_c = input_or_default(input_vars, 4, "vec4(0.0, 0.0, 0.0, 1.0)");
1199 let out = format!("{}_outline", var_prefix);
1200 lines.push(format!(
1201 "float {out}_rim = 1.0 - abs(dot(normalize({normal}), normalize(u_camera_pos - v_position)));"
1202 ));
1203 lines.push(format!("float {out}_factor = smoothstep(1.0 - {width} * 0.1, 1.0, {out}_rim);"));
1204 lines.push(format!("vec4 {out} = mix({color}, {outline_c}, {out}_factor);"));
1205 outputs.push(out);
1206 }
1207 NodeType::Bloom => {
1208 let color = input_or_default(input_vars, 0, "vec4(1.0)");
1209 let threshold = input_or_default(input_vars, 1, "0.8");
1210 let intensity = input_or_default(input_vars, 2, "1.5");
1211 let _radius = input_or_default(input_vars, 3, "4.0");
1212 let out = format!("{}_bloom", var_prefix);
1213 lines.push(format!(
1214 "float {out}_lum = dot({color}.rgb, vec3(0.299, 0.587, 0.114));"
1215 ));
1216 lines.push(format!(
1217 "float {out}_mask = max(0.0, {out}_lum - {threshold}) / max(1.0 - {threshold}, 0.001);"
1218 ));
1219 lines.push(format!("vec4 {out} = {color} + {color} * {out}_mask * {intensity};"));
1220 outputs.push(out.clone());
1221 outputs.push(format!("{}_mask", out));
1222 }
1223 NodeType::ChromaticAberration => {
1224 let uv = input_or_default(input_vars, 0, "v_uv");
1225 let offset = input_or_default(input_vars, 1, "0.005");
1226 let sampler = input_or_default(input_vars, 2, "u_texture0");
1227 let out = format!("{}_ca", var_prefix);
1228 lines.push(format!("vec2 {out}_dir = normalize({uv} - vec2(0.5));"));
1229 lines.push(format!("float {out}_r = texture2D({sampler}, {uv} + {out}_dir * {offset}).r;"));
1230 lines.push(format!("float {out}_g = texture2D({sampler}, {uv}).g;"));
1231 lines.push(format!("float {out}_b = texture2D({sampler}, {uv} - {out}_dir * {offset}).b;"));
1232 lines.push(format!("float {out}_a = texture2D({sampler}, {uv}).a;"));
1233 lines.push(format!("vec4 {out} = vec4({out}_r, {out}_g, {out}_b, {out}_a);"));
1234 outputs.push(out);
1235 }
1236
1237 NodeType::HSVToRGB => {
1239 let h = input_or_default(input_vars, 0, "0.0");
1240 let s = input_or_default(input_vars, 1, "1.0");
1241 let v = input_or_default(input_vars, 2, "1.0");
1242 let out = format!("{}_h2r", var_prefix);
1243 lines.push(format!("vec3 {out}_k = vec3(1.0, 2.0/3.0, 1.0/3.0);"));
1244 lines.push(format!("vec3 {out}_p = abs(fract(vec3({h}) + {out}_k) * 6.0 - 3.0);"));
1245 lines.push(format!("vec3 {out} = {v} * mix(vec3(1.0), clamp({out}_p - 1.0, 0.0, 1.0), {s});"));
1246 outputs.push(out);
1247 }
1248 NodeType::RGBToHSV => {
1249 let rgb = input_or_default(input_vars, 0, "vec3(1.0)");
1250 let out = format!("{}_r2h", var_prefix);
1251 lines.push(format!("vec4 {out}_K = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);"));
1252 lines.push(format!("vec4 {out}_p = mix(vec4({rgb}.bg, {out}_K.wz), vec4({rgb}.gb, {out}_K.xy), step({rgb}.b, {rgb}.g));"));
1253 lines.push(format!("vec4 {out}_q = mix(vec4({out}_p.xyw, {rgb}.r), vec4({rgb}.r, {out}_p.yzx), step({out}_p.x, {rgb}.r));"));
1254 lines.push(format!("float {out}_d = {out}_q.x - min({out}_q.w, {out}_q.y);"));
1255 lines.push(format!("float {out}_e = 1.0e-10;"));
1256 lines.push(format!("float {out}_h = abs({out}_q.z + ({out}_q.w - {out}_q.y) / (6.0 * {out}_d + {out}_e));"));
1257 lines.push(format!("float {out}_s = {out}_d / ({out}_q.x + {out}_e);"));
1258 lines.push(format!("float {out}_v = {out}_q.x;"));
1259 outputs.push(format!("{}_h", out));
1260 outputs.push(format!("{}_s", out));
1261 outputs.push(format!("{}_v", out));
1262 }
1263 NodeType::Contrast => {
1264 let color = input_or_default(input_vars, 0, "vec3(0.5)");
1265 let amount = input_or_default(input_vars, 1, "1.0");
1266 let out = format!("{}_contrast", var_prefix);
1267 lines.push(format!("vec3 {out} = (({color} - 0.5) * {amount}) + 0.5;"));
1268 outputs.push(out);
1269 }
1270 NodeType::Saturation => {
1271 let color = input_or_default(input_vars, 0, "vec3(0.5)");
1272 let amount = input_or_default(input_vars, 1, "1.0");
1273 let out = format!("{}_sat", var_prefix);
1274 lines.push(format!("float {out}_lum = dot({color}, vec3(0.299, 0.587, 0.114));"));
1275 lines.push(format!("vec3 {out} = mix(vec3({out}_lum), {color}, {amount});"));
1276 outputs.push(out);
1277 }
1278 NodeType::Hue => {
1279 let color = input_or_default(input_vars, 0, "vec3(0.5)");
1280 let shift = input_or_default(input_vars, 1, "0.0");
1281 let out = format!("{}_hue", var_prefix);
1282 lines.push(format!("float {out}_angle = {shift} * 6.28318;"));
1284 lines.push(format!("float {out}_cs = cos({out}_angle);"));
1285 lines.push(format!("float {out}_sn = sin({out}_angle);"));
1286 lines.push(format!("vec3 {out}_w = vec3(0.299, 0.587, 0.114);"));
1287 lines.push(format!("vec3 {out} = vec3("));
1288 lines.push(format!(" dot({color}, {out}_w + vec3(1.0-0.299, -0.587, -0.114)*{out}_cs + vec3(0.0, 0.0, 1.0)*{out}_sn*0.5),"));
1289 lines.push(format!(" dot({color}, {out}_w + vec3(-0.299, 1.0-0.587, -0.114)*{out}_cs + vec3(0.0, 0.0, -0.5)*{out}_sn),"));
1290 lines.push(format!(" dot({color}, {out}_w + vec3(-0.299, -0.587, 1.0-0.114)*{out}_cs + vec3(0.0, 1.0, 0.0)*{out}_sn*0.5)"));
1291 lines.push(format!(");"));
1292 outputs.push(out);
1293 }
1294 NodeType::Invert => {
1295 let color = input_or_default(input_vars, 0, "vec3(0.5)");
1296 let out = format!("{}_inv", var_prefix);
1297 lines.push(format!("vec3 {out} = 1.0 - {color};"));
1298 outputs.push(out);
1299 }
1300 NodeType::Posterize => {
1301 let color = input_or_default(input_vars, 0, "vec3(0.5)");
1302 let levels = input_or_default(input_vars, 1, "4.0");
1303 let out = format!("{}_poster", var_prefix);
1304 lines.push(format!("vec3 {out} = floor({color} * {levels}) / {levels};"));
1305 outputs.push(out);
1306 }
1307 NodeType::GradientMap => {
1308 let t = input_or_default(input_vars, 0, "0.5");
1309 let color_a = input_or_default(input_vars, 1, "vec3(0.0)");
1310 let color_b = input_or_default(input_vars, 2, "vec3(1.0)");
1311 let out = format!("{}_gmap", var_prefix);
1312 lines.push(format!("vec3 {out} = mix({color_a}, {color_b}, clamp({t}, 0.0, 1.0));"));
1313 outputs.push(out);
1314 }
1315
1316 NodeType::Perlin => {
1318 let pos = input_or_default(input_vars, 0, "v_position");
1319 let scale = input_or_default(input_vars, 1, "1.0");
1320 let seed = input_or_default(input_vars, 2, "0.0");
1321 let out = format!("{}_perlin", var_prefix);
1322 lines.push(format!("vec3 {out}_p = {pos} * {scale} + vec3({seed});"));
1324 lines.push(format!("vec3 {out}_i = floor({out}_p);"));
1325 lines.push(format!("vec3 {out}_f = fract({out}_p);"));
1326 lines.push(format!("vec3 {out}_u = {out}_f * {out}_f * (3.0 - 2.0 * {out}_f);"));
1327 lines.push(format!("float {out}_h000 = fract(sin(dot({out}_i, vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1329 lines.push(format!("float {out}_h100 = fract(sin(dot({out}_i + vec3(1.0,0.0,0.0), vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1330 lines.push(format!("float {out}_h010 = fract(sin(dot({out}_i + vec3(0.0,1.0,0.0), vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1331 lines.push(format!("float {out}_h110 = fract(sin(dot({out}_i + vec3(1.0,1.0,0.0), vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1332 lines.push(format!("float {out}_h001 = fract(sin(dot({out}_i + vec3(0.0,0.0,1.0), vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1333 lines.push(format!("float {out}_h101 = fract(sin(dot({out}_i + vec3(1.0,0.0,1.0), vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1334 lines.push(format!("float {out}_h011 = fract(sin(dot({out}_i + vec3(0.0,1.0,1.0), vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1335 lines.push(format!("float {out}_h111 = fract(sin(dot({out}_i + vec3(1.0,1.0,1.0), vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1336 lines.push(format!("float {out}_x0 = mix(mix({out}_h000, {out}_h100, {out}_u.x), mix({out}_h010, {out}_h110, {out}_u.x), {out}_u.y);"));
1337 lines.push(format!("float {out}_x1 = mix(mix({out}_h001, {out}_h101, {out}_u.x), mix({out}_h011, {out}_h111, {out}_u.x), {out}_u.y);"));
1338 lines.push(format!("float {out}_val = mix({out}_x0, {out}_x1, {out}_u.z);"));
1339 lines.push(format!("vec3 {out}_grad = normalize(vec3({out}_h100 - {out}_h000, {out}_h010 - {out}_h000, {out}_h001 - {out}_h000));"));
1340 outputs.push(format!("{out}_val"));
1341 outputs.push(format!("{out}_grad"));
1342 }
1343 NodeType::Simplex => {
1344 let pos = input_or_default(input_vars, 0, "v_position");
1345 let scale = input_or_default(input_vars, 1, "1.0");
1346 let seed = input_or_default(input_vars, 2, "0.0");
1347 let out = format!("{}_simplex", var_prefix);
1348 lines.push(format!("vec3 {out}_p = {pos} * {scale} + vec3({seed});"));
1350 lines.push(format!("float {out}_F3 = 1.0/3.0;"));
1351 lines.push(format!("float {out}_s = ({out}_p.x + {out}_p.y + {out}_p.z) * {out}_F3;"));
1352 lines.push(format!("vec3 {out}_i = floor({out}_p + vec3({out}_s));"));
1353 lines.push(format!("float {out}_G3 = 1.0/6.0;"));
1354 lines.push(format!("float {out}_t = ({out}_i.x + {out}_i.y + {out}_i.z) * {out}_G3;"));
1355 lines.push(format!("vec3 {out}_x0 = {out}_p - ({out}_i - vec3({out}_t));"));
1356 lines.push(format!("float {out}_val = fract(sin(dot({out}_i, vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1358 lines.push(format!("float {out}_val2 = fract(sin(dot({out}_i + 1.0, vec3(127.1, 311.7, 74.7))) * 43758.5453);"));
1359 lines.push(format!("float {out}_result = mix({out}_val, {out}_val2, fract({out}_s)) * 2.0 - 1.0;"));
1360 lines.push(format!("vec3 {out}_grad = normalize(vec3({out}_val, {out}_val2, {out}_result));"));
1361 outputs.push(format!("{out}_result"));
1362 outputs.push(format!("{out}_grad"));
1363 }
1364 NodeType::Voronoi => {
1365 let pos = input_or_default(input_vars, 0, "v_position");
1366 let scale = input_or_default(input_vars, 1, "1.0");
1367 let jitter = input_or_default(input_vars, 2, "1.0");
1368 let out = format!("{}_voronoi", var_prefix);
1369 lines.push(format!("vec3 {out}_p = {pos} * {scale};"));
1370 lines.push(format!("vec3 {out}_n = floor({out}_p);"));
1371 lines.push(format!("vec3 {out}_f = fract({out}_p);"));
1372 lines.push(format!("float {out}_md = 8.0;"));
1373 lines.push(format!("float {out}_id = 0.0;"));
1374 lines.push(format!("vec3 {out}_mr = vec3(0.0);"));
1375 lines.push(format!("for (int k = -1; k <= 1; k++) {{"));
1376 lines.push(format!(" for (int j = -1; j <= 1; j++) {{"));
1377 lines.push(format!(" for (int i = -1; i <= 1; i++) {{"));
1378 lines.push(format!(" vec3 {out}_g = vec3(float(i), float(j), float(k));"));
1379 lines.push(format!(" vec3 {out}_cell = {out}_n + {out}_g;"));
1380 lines.push(format!(" vec3 {out}_o = fract(sin(vec3(dot({out}_cell, vec3(127.1,311.7,74.7)), dot({out}_cell, vec3(269.5,183.3,246.1)), dot({out}_cell, vec3(113.5,271.9,124.6)))) * 43758.5453) * {jitter};"));
1381 lines.push(format!(" vec3 {out}_r = {out}_g + {out}_o - {out}_f;"));
1382 lines.push(format!(" float {out}_d = dot({out}_r, {out}_r);"));
1383 lines.push(format!(" if ({out}_d < {out}_md) {{"));
1384 lines.push(format!(" {out}_md = {out}_d;"));
1385 lines.push(format!(" {out}_id = dot({out}_cell, vec3(7.0, 157.0, 113.0));"));
1386 lines.push(format!(" {out}_mr = {out}_r;"));
1387 lines.push(format!(" }}"));
1388 lines.push(format!(" }}"));
1389 lines.push(format!(" }}"));
1390 lines.push(format!("}}"));
1391 outputs.push(format!("sqrt({out}_md)"));
1392 outputs.push(format!("fract({out}_id)"));
1393 outputs.push(format!("{out}_mr"));
1394 }
1395 NodeType::FBM => {
1396 let pos = input_or_default(input_vars, 0, "v_position");
1397 let scale = input_or_default(input_vars, 1, "1.0");
1398 let _octaves = input_or_default(input_vars, 2, "4");
1399 let lacunarity = input_or_default(input_vars, 3, "2.0");
1400 let gain = input_or_default(input_vars, 4, "0.5");
1401 let out = format!("{}_fbm", var_prefix);
1402 lines.push(format!("float {out} = 0.0;"));
1403 lines.push(format!("float {out}_amp = 1.0;"));
1404 lines.push(format!("vec3 {out}_p = {pos} * {scale};"));
1405 lines.push(format!("for (int {out}_i = 0; {out}_i < 4; {out}_i++) {{"));
1406 lines.push(format!(" vec3 {out}_fi = floor({out}_p);"));
1407 lines.push(format!(" vec3 {out}_ff = fract({out}_p);"));
1408 lines.push(format!(" vec3 {out}_fu = {out}_ff*{out}_ff*(3.0-2.0*{out}_ff);"));
1409 lines.push(format!(" float {out}_a = fract(sin(dot({out}_fi, vec3(127.1,311.7,74.7)))*43758.5453);"));
1410 lines.push(format!(" float {out}_b = fract(sin(dot({out}_fi+vec3(1,0,0), vec3(127.1,311.7,74.7)))*43758.5453);"));
1411 lines.push(format!(" float {out}_c = fract(sin(dot({out}_fi+vec3(0,1,0), vec3(127.1,311.7,74.7)))*43758.5453);"));
1412 lines.push(format!(" float {out}_d = fract(sin(dot({out}_fi+vec3(1,1,0), vec3(127.1,311.7,74.7)))*43758.5453);"));
1413 lines.push(format!(" float {out}_v = mix(mix({out}_a,{out}_b,{out}_fu.x), mix({out}_c,{out}_d,{out}_fu.x), {out}_fu.y);"));
1414 lines.push(format!(" {out} += {out}_amp * {out}_v;"));
1415 lines.push(format!(" {out}_amp *= {gain};"));
1416 lines.push(format!(" {out}_p *= {lacunarity};"));
1417 lines.push(format!("}}"));
1418 outputs.push(out);
1419 }
1420 NodeType::Turbulence => {
1421 let pos = input_or_default(input_vars, 0, "v_position");
1422 let scale = input_or_default(input_vars, 1, "1.0");
1423 let _octaves = input_or_default(input_vars, 2, "4");
1424 let lacunarity = input_or_default(input_vars, 3, "2.0");
1425 let gain = input_or_default(input_vars, 4, "0.5");
1426 let out = format!("{}_turb", var_prefix);
1427 lines.push(format!("float {out} = 0.0;"));
1428 lines.push(format!("float {out}_amp = 1.0;"));
1429 lines.push(format!("vec3 {out}_p = {pos} * {scale};"));
1430 lines.push(format!("for (int {out}_i = 0; {out}_i < 4; {out}_i++) {{"));
1431 lines.push(format!(" vec3 {out}_fi = floor({out}_p);"));
1432 lines.push(format!(" vec3 {out}_ff = fract({out}_p);"));
1433 lines.push(format!(" vec3 {out}_fu = {out}_ff*{out}_ff*(3.0-2.0*{out}_ff);"));
1434 lines.push(format!(" float {out}_a = fract(sin(dot({out}_fi, vec3(127.1,311.7,74.7)))*43758.5453);"));
1435 lines.push(format!(" float {out}_b = fract(sin(dot({out}_fi+vec3(1,0,0), vec3(127.1,311.7,74.7)))*43758.5453);"));
1436 lines.push(format!(" float {out}_c = fract(sin(dot({out}_fi+vec3(0,1,0), vec3(127.1,311.7,74.7)))*43758.5453);"));
1437 lines.push(format!(" float {out}_d = fract(sin(dot({out}_fi+vec3(1,1,0), vec3(127.1,311.7,74.7)))*43758.5453);"));
1438 lines.push(format!(" float {out}_v = mix(mix({out}_a,{out}_b,{out}_fu.x), mix({out}_c,{out}_d,{out}_fu.x), {out}_fu.y);"));
1439 lines.push(format!(" {out} += {out}_amp * abs({out}_v * 2.0 - 1.0);"));
1440 lines.push(format!(" {out}_amp *= {gain};"));
1441 lines.push(format!(" {out}_p *= {lacunarity};"));
1442 lines.push(format!("}}"));
1443 outputs.push(out);
1444 }
1445
1446 NodeType::MainColor => {
1448 let color = input_or_default(input_vars, 0, "vec4(1.0)");
1449 lines.push(format!("gl_FragColor = {};", color));
1450 }
1451 NodeType::EmissionBuffer => {
1452 let emission = input_or_default(input_vars, 0, "vec4(0.0)");
1453 lines.push(format!("gl_FragData[1] = {};", emission));
1454 }
1455 NodeType::BloomBuffer => {
1456 let bloom = input_or_default(input_vars, 0, "vec4(0.0)");
1457 lines.push(format!("gl_FragData[2] = {};", bloom));
1458 }
1459 NodeType::NormalOutput => {
1460 let normal = input_or_default(input_vars, 0, "v_normal");
1461 lines.push(format!("gl_FragData[3] = vec4({} * 0.5 + 0.5, 1.0);", normal));
1462 }
1463 }
1464
1465 GlslSnippet { lines, output_vars: outputs }
1466 }
1467}
1468
1469fn input_or_default(input_vars: &[String], index: usize, default: &str) -> String {
1470 if index < input_vars.len() && !input_vars[index].is_empty() {
1471 input_vars[index].clone()
1472 } else {
1473 default.to_string()
1474 }
1475}
1476
1477#[derive(Debug, Clone)]
1483pub struct GlslSnippet {
1484 pub lines: Vec<String>,
1486 pub output_vars: Vec<String>,
1488}
1489
1490#[derive(Debug, Clone)]
1496pub struct ShaderNode {
1497 pub id: NodeId,
1498 pub node_type: NodeType,
1499 pub label: String,
1500 pub inputs: Vec<Socket>,
1501 pub outputs: Vec<Socket>,
1502 pub properties: HashMap<String, ParamValue>,
1504 pub editor_x: f32,
1506 pub editor_y: f32,
1507 pub enabled: bool,
1509 pub conditional_var: Option<String>,
1512 pub conditional_threshold: f32,
1513}
1514
1515impl ShaderNode {
1516 pub fn new(id: NodeId, node_type: NodeType) -> Self {
1518 let inputs = node_type.default_inputs();
1519 let outputs = node_type.default_outputs();
1520 let label = node_type.display_name().to_string();
1521 Self {
1522 id,
1523 node_type,
1524 label,
1525 inputs,
1526 outputs,
1527 properties: HashMap::new(),
1528 editor_x: 0.0,
1529 editor_y: 0.0,
1530 enabled: true,
1531 conditional_var: None,
1532 conditional_threshold: 0.0,
1533 }
1534 }
1535
1536 pub fn at(mut self, x: f32, y: f32) -> Self {
1538 self.editor_x = x;
1539 self.editor_y = y;
1540 self
1541 }
1542
1543 pub fn with_property(mut self, key: &str, value: ParamValue) -> Self {
1545 self.properties.insert(key.to_string(), value);
1546 self
1547 }
1548
1549 pub fn with_input_default(mut self, socket_name: &str, value: ParamValue) -> Self {
1551 for s in &mut self.inputs {
1552 if s.name == socket_name {
1553 s.default_value = Some(value.clone());
1554 }
1555 }
1556 self
1557 }
1558
1559 pub fn with_condition(mut self, var_name: &str, threshold: f32) -> Self {
1561 self.conditional_var = Some(var_name.to_string());
1562 self.conditional_threshold = threshold;
1563 self
1564 }
1565
1566 pub fn output_type(&self, index: usize) -> Option<DataType> {
1568 self.outputs.get(index).map(|s| s.data_type)
1569 }
1570
1571 pub fn input_type(&self, index: usize) -> Option<DataType> {
1573 self.inputs.get(index).map(|s| s.data_type)
1574 }
1575
1576 pub fn input_default(&self, index: usize) -> Option<&ParamValue> {
1578 self.inputs.get(index).and_then(|s| s.default_value.as_ref())
1579 }
1580
1581 pub fn var_prefix(&self) -> String {
1583 format!("n{}", self.id.0)
1584 }
1585
1586 pub fn estimated_cost(&self) -> u32 {
1588 self.node_type.instruction_cost()
1589 }
1590}
1591
1592#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1598pub struct Connection {
1599 pub from_node: NodeId,
1600 pub from_socket: usize,
1601 pub to_node: NodeId,
1602 pub to_socket: usize,
1603}
1604
1605impl Connection {
1606 pub fn new(from_node: NodeId, from_socket: usize, to_node: NodeId, to_socket: usize) -> Self {
1607 Self { from_node, from_socket, to_node, to_socket }
1608 }
1609}
1610
1611#[derive(Debug, Clone)]
1617pub struct ShaderGraph {
1618 pub name: String,
1619 nodes: HashMap<NodeId, ShaderNode>,
1620 connections: Vec<Connection>,
1621 next_id: u64,
1622}
1623
1624impl ShaderGraph {
1625 pub fn new(name: &str) -> Self {
1627 Self {
1628 name: name.to_string(),
1629 nodes: HashMap::new(),
1630 connections: Vec::new(),
1631 next_id: 1,
1632 }
1633 }
1634
1635 pub fn alloc_id(&mut self) -> NodeId {
1637 let id = NodeId(self.next_id);
1638 self.next_id += 1;
1639 id
1640 }
1641
1642 pub fn add_node(&mut self, node_type: NodeType) -> NodeId {
1644 let id = self.alloc_id();
1645 let node = ShaderNode::new(id, node_type);
1646 self.nodes.insert(id, node);
1647 id
1648 }
1649
1650 pub fn add_node_with(&mut self, mut node: ShaderNode) -> NodeId {
1652 let id = self.alloc_id();
1653 node.id = id;
1654 self.nodes.insert(id, node);
1655 id
1656 }
1657
1658 pub fn insert_node(&mut self, node: ShaderNode) -> NodeId {
1660 let id = node.id;
1661 if id.0 >= self.next_id {
1662 self.next_id = id.0 + 1;
1663 }
1664 self.nodes.insert(id, node);
1665 id
1666 }
1667
1668 pub fn connect(&mut self, from_node: NodeId, from_socket: usize, to_node: NodeId, to_socket: usize) {
1670 self.connections.retain(|c| !(c.to_node == to_node && c.to_socket == to_socket));
1672 self.connections.push(Connection::new(from_node, from_socket, to_node, to_socket));
1673 }
1674
1675 pub fn disconnect_node(&mut self, node_id: NodeId) {
1677 self.connections.retain(|c| c.from_node != node_id && c.to_node != node_id);
1678 }
1679
1680 pub fn disconnect(&mut self, from_node: NodeId, from_socket: usize, to_node: NodeId, to_socket: usize) {
1682 self.connections.retain(|c| {
1683 !(c.from_node == from_node && c.from_socket == from_socket
1684 && c.to_node == to_node && c.to_socket == to_socket)
1685 });
1686 }
1687
1688 pub fn remove_node(&mut self, node_id: NodeId) {
1690 self.disconnect_node(node_id);
1691 self.nodes.remove(&node_id);
1692 }
1693
1694 pub fn node(&self, id: impl std::borrow::Borrow<NodeId>) -> Option<&ShaderNode> {
1696 self.nodes.get(id.borrow())
1697 }
1698
1699 pub fn node_mut(&mut self, id: NodeId) -> Option<&mut ShaderNode> {
1701 self.nodes.get_mut(&id)
1702 }
1703
1704 pub fn nodes(&self) -> impl Iterator<Item = &ShaderNode> {
1706 self.nodes.values()
1707 }
1708
1709 pub fn node_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
1711 self.nodes.keys().copied()
1712 }
1713
1714 pub fn node_count(&self) -> usize {
1716 self.nodes.len()
1717 }
1718
1719 pub fn connections(&self) -> &[Connection] {
1721 &self.connections
1722 }
1723
1724 pub fn incoming_connections(&self, node_id: NodeId) -> Vec<&Connection> {
1726 self.connections.iter().filter(|c| c.to_node == node_id).collect()
1727 }
1728
1729 pub fn outgoing_connections(&self, node_id: NodeId) -> Vec<&Connection> {
1731 self.connections.iter().filter(|c| c.from_node == node_id).collect()
1732 }
1733
1734 pub fn output_nodes(&self) -> Vec<NodeId> {
1736 self.nodes.values()
1737 .filter(|n| n.node_type.is_output())
1738 .map(|n| n.id)
1739 .collect()
1740 }
1741
1742 pub fn source_nodes(&self) -> Vec<NodeId> {
1744 self.nodes.values()
1745 .filter(|n| n.node_type.is_source())
1746 .map(|n| n.id)
1747 .collect()
1748 }
1749
1750 pub fn estimated_cost(&self) -> u32 {
1752 self.nodes.values().map(|n| n.estimated_cost()).sum()
1753 }
1754
1755 pub fn validate(&self) -> Vec<String> {
1758 let mut errors = Vec::new();
1759 for conn in &self.connections {
1760 if !self.nodes.contains_key(&conn.from_node) {
1761 errors.push(format!("Connection references missing source node {}", conn.from_node.0));
1762 }
1763 if !self.nodes.contains_key(&conn.to_node) {
1764 errors.push(format!("Connection references missing target node {}", conn.to_node.0));
1765 }
1766 if conn.from_node == conn.to_node {
1767 errors.push(format!("Self-loop on node {}", conn.from_node.0));
1768 }
1769 if let Some(src) = self.nodes.get(&conn.from_node) {
1770 if conn.from_socket >= src.outputs.len() {
1771 errors.push(format!(
1772 "Node {} output socket {} out of range (has {})",
1773 conn.from_node.0, conn.from_socket, src.outputs.len()
1774 ));
1775 }
1776 }
1777 if let Some(dst) = self.nodes.get(&conn.to_node) {
1778 if conn.to_socket >= dst.inputs.len() {
1779 errors.push(format!(
1780 "Node {} input socket {} out of range (has {})",
1781 conn.to_node.0, conn.to_socket, dst.inputs.len()
1782 ));
1783 }
1784 }
1785 }
1786 let mut seen_inputs: HashMap<(u64, usize), u64> = HashMap::new();
1788 for conn in &self.connections {
1789 let key = (conn.to_node.0, conn.to_socket);
1790 if let Some(prev) = seen_inputs.insert(key, conn.from_node.0) {
1791 errors.push(format!(
1792 "Duplicate connection to node {} socket {}: from {} and {}",
1793 conn.to_node.0, conn.to_socket, prev, conn.from_node.0
1794 ));
1795 }
1796 }
1797 errors
1798 }
1799
1800 pub fn topology_hash(&self) -> u64 {
1802 let mut hash: u64 = 0xcbf29ce484222325; let prime: u64 = 0x100000001b3;
1804
1805 let mut node_ids: Vec<u64> = self.nodes.keys().map(|k| k.0).collect();
1807 node_ids.sort();
1808
1809 for nid in &node_ids {
1810 hash ^= *nid;
1811 hash = hash.wrapping_mul(prime);
1812 if let Some(node) = self.nodes.get(&NodeId(*nid)) {
1813 for b in node.node_type.display_name().bytes() {
1815 hash ^= b as u64;
1816 hash = hash.wrapping_mul(prime);
1817 }
1818 }
1819 }
1820
1821 let mut conns: Vec<(u64, usize, u64, usize)> = self.connections.iter()
1823 .map(|c| (c.from_node.0, c.from_socket, c.to_node.0, c.to_socket))
1824 .collect();
1825 conns.sort();
1826 for (a, b, c, d) in conns {
1827 hash ^= a;
1828 hash = hash.wrapping_mul(prime);
1829 hash ^= b as u64;
1830 hash = hash.wrapping_mul(prime);
1831 hash ^= c;
1832 hash = hash.wrapping_mul(prime);
1833 hash ^= d as u64;
1834 hash = hash.wrapping_mul(prime);
1835 }
1836
1837 hash
1838 }
1839
1840 pub fn nodes_map(&self) -> &HashMap<NodeId, ShaderNode> {
1842 &self.nodes
1843 }
1844
1845 pub fn next_id_counter(&self) -> u64 {
1847 self.next_id
1848 }
1849
1850 pub fn set_next_id(&mut self, val: u64) {
1852 self.next_id = val;
1853 }
1854
1855 pub fn add_connection_raw(&mut self, conn: Connection) {
1857 self.connections.push(conn);
1858 }
1859}
1860
1861impl Default for ShaderGraph {
1862 fn default() -> Self {
1863 Self::new("untitled")
1864 }
1865}