Add node input type support for f32 to enable usage on GPU (#3095)

* update Cargo.lock

* f32: switch to f32 params

* f32: more f32 params, remove f32 casts

* f32: property support for f32

* f32: fix test `stable_node_id_generation`

* Fix f32 properties

* Fix f32 frontend data types

* Rename TaggedValue::Vec2 to ::FVec2 and ::Affine2 to ::FAffine2

---------

Co-authored-by: hypercube <0hypercube@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Firestar99
2025-08-27 20:08:45 -07:00
committed by GitHub
co-authored by hypercube Keavon Chambers
parent a199a5fd64
commit 82784b46a0
9 changed files with 206 additions and 131 deletions
@@ -4,6 +4,7 @@ use crate::messages::portfolio::document::data_panel::DataPanelMessage;
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
use crate::messages::prelude::*;
use crate::messages::tool::tool_messages::tool_prelude::*;
use glam::{Affine2, Vec2};
use graph_craft::document::NodeId;
use graphene_std::Color;
use graphene_std::Context;
@@ -594,6 +595,19 @@ impl TableRowLayout for DVec2 {
}
}
impl TableRowLayout for Vec2 {
fn type_name() -> &'static str {
"Vec2"
}
fn identifier(&self) -> String {
"Vec2".to_string()
}
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
let widgets = vec![TextLabel::new(format!("({}, {})", self.x, self.y)).widget_holder()];
vec![LayoutGroup::Row { widgets }]
}
}
impl TableRowLayout for DAffine2 {
fn type_name() -> &'static str {
"Transform"
@@ -607,6 +621,20 @@ impl TableRowLayout for DAffine2 {
}
}
impl TableRowLayout for Affine2 {
fn type_name() -> &'static str {
"Transform"
}
fn identifier(&self) -> String {
"Transform".to_string()
}
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
let matrix = DAffine2::from_cols_array(&self.to_cols_array().map(|x| x as f64));
let widgets = vec![TextLabel::new(format_transform_matrix(&matrix)).widget_holder()];
vec![LayoutGroup::Row { widgets }]
}
}
fn format_transform_matrix(transform: &DAffine2) -> String {
let (scale, angle, translation) = transform.to_scale_angle_translation();
let rotation = if angle == -0. { 0. } else { angle.to_degrees() };
@@ -147,9 +147,9 @@ pub(crate) fn property_from_type(
Type::Concrete(concrete_type) => {
match concrete_type.alias.as_ref().map(|x| x.as_ref()) {
// Aliased types (ambiguous values)
Some("Percentage") => number_widget(default_info, number_input.percentage().min(min(0.)).max(max(100.))).into(),
Some("SignedPercentage") => number_widget(default_info, number_input.percentage().min(min(-100.)).max(max(100.))).into(),
Some("Angle") => number_widget(default_info, number_input.mode_range().min(min(-180.)).max(max(180.)).unit(unit.unwrap_or("°"))).into(),
Some("Percentage") | Some("PercentageF32") => number_widget(default_info, number_input.percentage().min(min(0.)).max(max(100.))).into(),
Some("SignedPercentage") | Some("SignedPercentageF32") => number_widget(default_info, number_input.percentage().min(min(-100.)).max(max(100.))).into(),
Some("Angle") | Some("AngleF32") => number_widget(default_info, number_input.mode_range().min(min(-180.)).max(max(180.)).unit(unit.unwrap_or("°"))).into(),
Some("Multiplier") => number_widget(default_info, number_input.unit(unit.unwrap_or("x"))).into(),
Some("PixelLength") => number_widget(default_info, number_input.min(min(0.)).unit(unit.unwrap_or(" px"))).into(),
Some("Length") => number_widget(default_info, number_input.min(min(0.))).into(),
@@ -166,7 +166,7 @@ pub(crate) fn property_from_type(
// ===============
// PRIMITIVE TYPES
// ===============
Some(x) if x == TypeId::of::<f64>() => number_widget(default_info, number_input.min(min(f64::NEG_INFINITY)).max(max(f64::INFINITY))).into(),
Some(x) if x == TypeId::of::<f64>() || x == TypeId::of::<f32>() => number_widget(default_info, number_input.min(min(f64::NEG_INFINITY)).max(max(f64::INFINITY))).into(),
Some(x) if x == TypeId::of::<u32>() => number_widget(default_info, number_input.int().min(min(0.)).max(max(f64::from(u32::MAX)))).into(),
Some(x) if x == TypeId::of::<u64>() => number_widget(default_info, number_input.int().min(min(0.))).into(),
Some(x) if x == TypeId::of::<bool>() => bool_widget(default_info, CheckboxInput::default()).into(),
@@ -805,6 +805,14 @@ pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props:
.on_commit(commit_value)
.widget_holder(),
]),
Some(&TaggedValue::F32(x)) => widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
number_props
.value(Some(x as f64))
.on_update(update_value(move |x: &NumberInput| TaggedValue::F32(x.value.unwrap() as f32), node_id, index))
.on_commit(commit_value)
.widget_holder(),
]),
Some(&TaggedValue::U32(x)) => widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
number_props
@@ -851,6 +859,15 @@ pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props:
.on_commit(commit_value)
.widget_holder(),
]),
Some(&TaggedValue::FVec2(vec2)) => widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
number_props
// We use an arbitrary `y` instead of an arbitrary `x` here because the "Grid" node's "Spacing" value's height should be used from rectangular mode when transferred to "Y Spacing" in isometric mode
.value(Some(vec2.y as f64))
.on_update(update_value(move |x: &NumberInput| TaggedValue::F32(x.value.unwrap() as f32), node_id, index))
.on_commit(commit_value)
.widget_holder(),
]),
_ => {}
}
@@ -23,6 +23,7 @@ impl FrontendGraphDataType {
match TaggedValue::from_type_or_none(input) {
TaggedValue::U32(_)
| TaggedValue::U64(_)
| TaggedValue::F32(_)
| TaggedValue::F64(_)
| TaggedValue::DVec2(_)
| TaggedValue::F64Array4(_)