Skip to main content

ferritin_bevy/
plugin.rs

1//! Module for loading PDBs into Bevy via the Plugin system
2//!
3//! Over time this would be a good candidate for factoring out
4//!
5use super::{ColorScheme, RenderOptions, Structure};
6use bevy::prelude::*;
7use ferritin_core::load_model;
8use std::path::Path;
9use std::path::PathBuf;
10
11#[derive(Clone)]
12pub struct StructureSettings {
13    pub render_type: RenderOptions,
14    pub color_scheme: ColorScheme,
15    pub material: StandardMaterial,
16}
17impl Default for StructureSettings {
18    fn default() -> Self {
19        Self {
20            render_type: RenderOptions::Solid,
21            color_scheme: ColorScheme::Solid(Color::WHITE),
22            material: StandardMaterial::default(),
23        }
24    }
25}
26
27// adding this for integration with Bevy
28pub struct StructurePlugin {
29    initial_files: Vec<(PathBuf, StructureSettings)>,
30}
31
32impl Default for StructurePlugin {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl StructurePlugin {
39    pub fn new() -> Self {
40        Self {
41            initial_files: Vec::new(),
42        }
43    }
44    pub fn with_file<P: Into<PathBuf>>(
45        mut self,
46        path: P,
47        settings: Option<StructureSettings>,
48    ) -> Self {
49        self.initial_files
50            .push((path.into(), settings.unwrap_or_default()));
51        self
52    }
53}
54
55// adding this for integration with Bevy
56impl Plugin for StructurePlugin {
57    fn build(&self, app: &mut App) {
58        app.insert_resource(StructureFiles(self.initial_files.clone()))
59            .add_systems(Startup, load_initial_proteins)
60            .add_message::<LoadProteinEvent>();
61    }
62}
63
64#[derive(Resource)]
65struct StructureFiles(Vec<(PathBuf, StructureSettings)>);
66
67#[derive(Message)]
68pub struct LoadProteinEvent(pub PathBuf);
69
70fn load_initial_proteins(
71    structure_files: Res<StructureFiles>,
72    mut commands: Commands,
73    mut meshes: ResMut<Assets<Mesh>>,
74    mut materials: ResMut<Assets<StandardMaterial>>,
75) {
76    for (file_path, settings) in &structure_files.0 {
77        // check valid filepath
78        if !Path::new(file_path).exists() {
79            eprintln!("Error: File not found: {:?}", file_path);
80            continue;
81        }
82
83        let model = load_model(file_path).unwrap();
84
85        let structure = Structure::builder()
86            .pdb(model)
87            .rendertype(settings.render_type.clone())
88            .color_scheme(settings.color_scheme.clone())
89            .material(settings.material.clone())
90            .build();
91
92        let mesh = structure.to_mesh();
93        let material = structure.get_material();
94
95        commands.spawn((
96            Mesh3d(meshes.add(mesh)),
97            MeshMaterial3d(materials.add(material)),
98        ));
99    }
100}