ferritin_structure_mesh/
structure.rs1use super::ColorScheme;
7use bevy::prelude::*;
8use bon::Builder;
9use ferritin_core::AtomCollection;
10
11#[derive(Clone)]
13pub enum RenderOptions {
14 Wireframe,
15 Cartoon,
16 BallAndStick,
17 Solid,
18 Putty,
19}
20
21#[derive(Builder, Clone)]
23pub struct Structure {
24 pdb: AtomCollection,
25 #[builder(default = RenderOptions::Solid)]
26 rendertype: RenderOptions,
27 #[builder(default = ColorScheme::ByAtomType)]
28 color_scheme: ColorScheme,
29 #[builder(default = StandardMaterial::default())]
30 material: StandardMaterial,
31}
32
33impl Structure {
35 }
37
38impl Structure {
39 pub fn to_mesh(&self) -> Mesh {
41 match self.rendertype {
42 RenderOptions::Wireframe => self.render_wireframe(),
43 RenderOptions::Cartoon => self.render_cartoon(),
44 RenderOptions::BallAndStick => self.render_ballandstick(),
45 RenderOptions::Solid => self.render_spheres(),
46 RenderOptions::Putty => self.render_putty(),
47 }
48 }
49
50 pub fn get_material(&self) -> StandardMaterial {
52 self.material.clone()
53 }
54
55 fn render_wireframe(&self) -> Mesh {
57 self.create_sphere_mesh(0.5)
58 }
59
60 fn render_cartoon(&self) -> Mesh {
61 self.create_sphere_mesh(1.0)
62 }
63
64 fn render_ballandstick(&self) -> Mesh {
65 self.create_sphere_mesh(0.3)
66 }
67
68 fn render_spheres(&self) -> Mesh {
69 self.create_sphere_mesh(1.5)
70 }
71
72 fn render_putty(&self) -> Mesh {
73 self.create_sphere_mesh(2.0)
74 }
75
76 fn create_sphere_mesh(&self, radius: f32) -> Mesh {
78 let mut positions = Vec::new();
79 let mut normals = Vec::new();
80 let mut uvs = Vec::new();
81 let mut indices = Vec::new();
82
83 let subdivisions = 8;
84
85 for idx in 0..self.pdb.get_size() {
86 let coord = self.pdb.get_coord(idx);
87 let center = Vec3::new(coord[0], coord[1], coord[2]);
88 let base_index = positions.len() as u32;
89
90 for lat in 0..=subdivisions {
92 let theta = lat as f32 * std::f32::consts::PI / subdivisions as f32;
93 let sin_theta = theta.sin();
94 let cos_theta = theta.cos();
95
96 for lon in 0..=subdivisions {
97 let phi = lon as f32 * 2.0 * std::f32::consts::PI / subdivisions as f32;
98 let sin_phi = phi.sin();
99 let cos_phi = phi.cos();
100
101 let x = sin_theta * cos_phi;
102 let y = cos_theta;
103 let z = sin_theta * sin_phi;
104
105 let normal = Vec3::new(x, y, z);
106 let pos = center + normal * radius;
107
108 positions.push([pos.x, pos.y, pos.z]);
109 normals.push([normal.x, normal.y, normal.z]);
110 uvs.push([
111 lon as f32 / subdivisions as f32,
112 lat as f32 / subdivisions as f32,
113 ]);
114 }
115 }
116
117 for lat in 0..subdivisions {
119 for lon in 0..subdivisions {
120 let first = base_index + lat * (subdivisions + 1) + lon;
121 let second = first + subdivisions + 1;
122
123 indices.push(first);
124 indices.push(second);
125 indices.push(first + 1);
126
127 indices.push(second);
128 indices.push(second + 1);
129 indices.push(first + 1);
130 }
131 }
132 }
133
134 let mut mesh = Mesh::new(
136 bevy::mesh::PrimitiveTopology::TriangleList,
137 bevy::asset::RenderAssetUsages::default(),
138 );
139
140 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
141 mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
142 mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
143 mesh.insert_indices(bevy::mesh::Indices::U32(indices));
144
145 mesh
146 }
147}