1pub mod render;
2use fission_core::op::Color;
3use fission_core::ui::{Container, CustomNode, Node};
4use fission_core::{BuildCtx, View, Widget};
5use fission_ir::op::{EmbedKind, LayoutOp};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Point3D {
10 pub x: f32,
11 pub y: f32,
12 pub z: f32,
13}
14
15impl Point3D {
16 pub fn new(x: f32, y: f32, z: f32) -> Self {
17 Self { x, y, z }
18 }
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub enum Primitive3D {
23 Cube {
24 center: Point3D,
25 size: f32,
26 color: Color,
27 },
28 Sphere {
29 center: Point3D,
30 radius: f32,
31 color: Color,
32 },
33 Mesh {
34 vertices: Vec<Point3D>,
35 indices: Vec<u32>,
36 color: Color,
37 },
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct Scene3D {
42 pub width: Option<f32>,
43 pub height: Option<f32>,
44 pub primitives: Vec<Primitive3D>,
45}
46
47impl Scene3D {
48 pub fn new() -> Self {
49 Self {
50 width: None,
51 height: None,
52 primitives: Vec::new(),
53 }
54 }
55
56 pub fn width(mut self, w: f32) -> Self {
57 self.width = Some(w);
58 self
59 }
60
61 pub fn height(mut self, h: f32) -> Self {
62 self.height = Some(h);
63 self
64 }
65
66 pub fn add_primitive(mut self, primitive: Primitive3D) -> Self {
67 self.primitives.push(primitive);
68 self
69 }
70}
71
72impl<S: fission_core::AppState> Widget<S> for Scene3D {
73 fn build(&self, _ctx: &mut BuildCtx<S>, _view: &View<S>) -> Node {
74 let mut container = Container::new(Node::Custom(CustomNode {
75 debug_tag: "fission_3d::Scene3D".into(),
76 lowerer: Some(std::sync::Arc::new(Scene3DLowerer {
77 scene: self.clone(),
78 })),
79 render_object: None,
80 }));
81 if let Some(w) = self.width {
82 container = container.width(w);
83 } else {
84 container = container.flex_grow(1.0);
85 }
86 if let Some(h) = self.height {
87 container = container.height(h);
88 } else {
89 if self.width.is_none() {
90 container = container.flex_grow(1.0);
91 }
92 }
93 container.into_node()
94 }
95}
96
97#[derive(Debug)]
98pub struct Scene3DLowerer {
99 pub scene: Scene3D,
100}
101
102impl fission_core::ui::traits::LowerDyn for Scene3DLowerer {
103 fn lower_dyn(&self, cx: &mut fission_core::lowering::LoweringContext) -> fission_ir::NodeId {
104 let node_id = cx.next_node_id();
105
106 let w = self
107 .scene
108 .width
109 .unwrap_or_else(|| (cx.env.viewport_size.width - 264.0).max(400.0));
110 let h = self
111 .scene
112 .height
113 .unwrap_or_else(|| (cx.env.viewport_size.height - 200.0).max(300.0));
114
115 let payload = bincode::serialize(&self.scene.primitives).unwrap_or_default();
120 let op = fission_ir::Op::Layout(LayoutOp::Embed {
121 kind: EmbedKind::Custom(payload),
122 widget_id: fission_ir::WidgetNodeId::explicit("fission_3d_scene"),
123 width: Some(w),
124 height: Some(h),
125 });
126
127 cx.insert_node(node_id, op, vec![])
128 }
129}